14#include "arcane/utils/Collection.h"
15#include "arcane/utils/Enumerator.h"
16#include "arcane/utils/Iostream.h"
17#include "arcane/utils/StringBuilder.h"
18#include "arcane/utils/IOException.h"
19#include "arcane/utils/FixedArray.h"
20#include "arcane/utils/MemoryView.h"
22#include "arcane/core/PostProcessorWriterBase.h"
23#include "arcane/core/Directory.h"
24#include "arcane/core/FactoryService.h"
25#include "arcane/core/IDataWriter.h"
26#include "arcane/core/IData.h"
27#include "arcane/core/IItemFamily.h"
28#include "arcane/core/MeshKind.h"
29#include "arcane/core/VariableCollection.h"
30#include "arcane/core/IParallelMng.h"
31#include "arcane/core/IMesh.h"
32#include "arcane/core/internal/IParallelMngInternal.h"
33#include "arcane/core/internal/VtkCellTypes.h"
34#include "arcane/core/internal/GatherGroup.h"
36#include "arcane/core/materials/IMeshMaterialMng.h"
37#include "arcane/core/materials/IMeshEnvironment.h"
39#include "arcane/hdf5/Hdf5Utils.h"
40#include "arcane/hdf5/VtkHdfV2PostProcessor_axl.h"
80 asConstSpan(
const T* v)
89class VtkHdfV2DataWriter
101 struct DatasetGroupAndName
105 DatasetGroupAndName(
HGroup& group_,
const String& name_)
129 DatasetInfo() =
default;
130 explicit DatasetInfo(
const String& name)
137 bool isNull()
const {
return m_name.null(); }
139 HGroup* group()
const {
return m_group; }
140 const String& name()
const {
return m_name; }
143 void setOffset(
Int64 v) { m_offset = v; }
144 friend bool operator<(
const DatasetInfo& s1,
const DatasetInfo& s2)
146 return (s1.m_name < s2.m_name);
151 HGroup* m_group =
nullptr;
161 void setTotalSize(
Int64 v) { m_total_size = v; }
162 void setSize(
Int64 v) { m_size = v; }
163 void setOffset(
Int64 v) { m_offset = v; }
165 Int64 totalSize()
const {
return m_total_size; }
166 Int64 size()
const {
return m_size; }
167 Int64 offset()
const {
return m_offset; }
172 Int64 m_total_size = 0;
180 struct ItemGroupCollectiveInfo
184 explicit ItemGroupCollectiveInfo(
const ItemGroup& g)
210 , m_dataset_info(dataset_info)
216 , m_dataset_info(dataset_info)
217 , m_group_info(group_info)
221 : dataset(dataset_group, dataset_name)
222 , m_dataset_info(dataset_info)
227 : dataset(dataset_group, dataset_name)
228 , m_dataset_info(dataset_info)
229 , m_group_info(group_info)
235 DatasetInfo datasetInfo()
const {
return m_dataset_info; }
251 void endWrite()
override;
258 void setDirectoryName(
const String& dir_name) { m_directory_name = dir_name; }
259 void setMaxWriteSize(Int64 v) { m_max_write_size = v; }
264 IMesh* m_mesh =
nullptr;
267 IMeshMaterialMng* m_material_mng =
nullptr;
273 UniqueArray<Real> m_times;
276 String m_full_filename;
279 String m_directory_name;
285 HGroup m_cell_data_group;
286 HGroup m_node_data_group;
288 HGroup m_steps_group;
289 HGroup m_point_data_offsets_group;
290 HGroup m_cell_data_offsets_group;
291 HGroup m_field_data_offsets_group;
293 bool m_is_parallel =
false;
294 bool m_is_collective_io =
false;
295 bool m_is_first_call =
false;
296 bool m_is_writer =
false;
306 bool m_write_polyhedron_datasets =
false;
321 std::map<DatasetInfo, Int64> m_offset_info_list;
323 StandardTypes m_standard_types{
false };
327 UniqueArray<Ref<ItemGroupCollectiveInfo>> m_materials_groups;
329 GatherGroupInfo m_all_cells_gather_group_info;
330 GatherGroupInfo m_all_nodes_gather_group_info;
331 UniqueArray<Ref<GatherGroupInfo>> m_gather_info_materials_groups;
339 Int64 m_max_write_size = 0;
343 void _addInt64ArrayAttribute(Hid& hid,
const char* name, Span<const Int64> values);
344 void _addStringAttribute(Hid& hid,
const char* name,
const String& value);
346 template <
typename DataType>
void
347 _writeDataSet1D(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values);
348 template <
typename DataType>
void
349 _writeDataSet1DUsingCollectiveIO(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values);
350 template <
typename DataType>
void
351 _writeDataSet1DCollective(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values);
352 template <
typename DataType>
void
353 _writeDataSet2D(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values);
354 template <
typename DataType>
void
355 _writeDataSet2DUsingCollectiveIO(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values);
356 template <
typename DataType>
void
357 _writeDataSet2DCollective(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values);
358 template <
typename DataType>
void
359 _writeBasicTypeDataset(
const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data);
360 void _writeReal3Dataset(
const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data);
361 void _writeReal2Dataset(
const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data);
363 String _getFileName()
365 StringBuilder sb(m_mesh->name());
367 return sb.toString();
369 template <
typename DataType>
void
370 _writeDataSetGeneric(
const DataInfo& data_info, GatherGroupInfo* gather_info,
Int32 nb_dim,
371 Int64 dim1_size,
Int64 dim2_size,
const DataType* values_data,
373 void _writeDataSetGeneric(
const DataInfo& data_info, GatherGroupInfo* gather_info,
Int32 nb_dim,
374 Int64 dim1_size,
Int64 dim2_size, ConstMemoryView values_data,
375 const hid_t hdf_datatype_type,
bool is_collective);
376 void _addInt64Attribute(Hid& hid,
const char* name,
Int64 value);
377 Int64 _readInt64Attribute(Hid& hid,
const char* name);
378 void _openOrCreateGroups();
381 void _initializeOffsets();
384 void _writeConstituentsGroups();
395, m_is_collective_io(is_collective_io)
396, m_all_cells_info(mesh->allCells())
397, m_all_nodes_info(mesh->allNodes())
398, m_all_cells_gather_group_info(mesh->parallelMng(), is_collective_io)
399, m_all_nodes_gather_group_info(mesh->parallelMng(), is_collective_io)
406void VtkHdfV2DataWriter::
407beginWrite(
const VariableCollection& vars)
414 IParallelMng* pm = m_mesh->parallelMng();
415 const Int32 nb_rank = pm->commSize();
416 m_is_parallel = nb_rank > 1;
418 Int32 time_index = m_times.size();
419 const bool is_first_call = (time_index < 2);
420 m_is_first_call = is_first_call;
422 info() <<
"WARNING: The 'VtkHdfV2' implementation is experimental";
424 String filename = _getFileName();
426 Directory dir(m_directory_name);
428 m_full_filename = dir.file(filename);
429 info(4) <<
"VtkHdfV2DataWriter::beginWrite() file=" << m_full_filename;
438 if (pm->isThreadImplementation() && !pm->isHybridImplementation())
439 m_is_collective_io =
false;
442 info() <<
"VtkHdfV2DataWriter: using collective MPI/IO ?=" << m_is_collective_io;
443 info() <<
"VtkHdfV2DataWriter: max_write_size (kB) =" << m_max_write_size;
444 info() <<
"VtkHdfV2DataWriter: has_material?=" << (m_material_mng !=
nullptr);
447 bool is_master_io = pm->isMasterIO();
453 if (m_is_collective_io) {
454 m_writer = pm->_internalApi()->masterParallelIORank();
455 m_is_writer = (m_writer == pm->commRank());
458 m_writer = pm->masterIORank();
459 m_is_writer = is_master_io;
464 if (m_is_collective_io && m_is_writer)
465 plist_id.createFilePropertyMPIIO(pm);
468 if (is_first_call && is_master_io)
469 dir.createDirectory();
471 if (m_is_collective_io)
475 m_standard_types.initialize();
478 m_file_id.openTruncate(m_full_filename, plist_id.id());
480 m_file_id.openAppend(m_full_filename, plist_id.id());
482 _openOrCreateGroups();
485 std::array<Int64, 2> version = { 2, 5 };
486 _addInt64ArrayAttribute(m_top_group,
"Version", version);
487 _addStringAttribute(m_top_group,
"Type",
"UnstructuredGrid");
492 _initializeItemGroupCollectiveInfos(m_all_cells_info, m_all_cells_gather_group_info);
493 _initializeItemGroupCollectiveInfos(m_all_nodes_info, m_all_nodes_gather_group_info);
495 CellGroup all_cells = m_mesh->allCells();
496 NodeGroup all_nodes = m_mesh->allNodes();
499 const Int32 nb_node = all_nodes.size();
501 Int64 total_nb_connected_node = 0;
504 total_nb_connected_node += cell.nodeIds().size();
509 UniqueArray<Int64> cells_connectivity(total_nb_connected_node);
510 UniqueArray<Int64> cells_offset(nb_cell + 1);
511 UniqueArray<unsigned char> cells_ghost_type(nb_cell);
512 UniqueArray<unsigned char> cells_type(nb_cell);
513 UniqueArray<Int64> cells_uid(nb_cell);
528 UniqueArray<Int64> faces_connectivity;
529 UniqueArray<Int64> faces_offset;
530 UniqueArray<Int64> polyhedron_to_faces;
531 UniqueArray<Int64> polyhedron_offset(nb_cell + 1);
533 polyhedron_offset[0] = 0;
543 Int32 connected_node_index = 0;
545 Int32 index = icell.index();
548 cells_uid[index] = cell.uniqueId();
551 bool is_ghost = !cell.isOwn();
553 ghost_type = VtkUtils::CellGhostTypes::DUPLICATECELL;
554 cells_ghost_type[index] = ghost_type;
556 const bool is_polyhedron = cell.typeInfo()->isPolyhedron() || (mesh_is_polyhedral && cell.nbFace() > 0);
557 unsigned char vtk_type = VtkUtils::VTK_POLYHEDRON;
559 vtk_type = VtkUtils::arcaneToVtkCellType(cell.type());
560 cells_type[index] = vtk_type;
561 for (NodeLocalId node : cell.nodeIds()) {
562 cells_connectivity[connected_node_index] = node;
563 ++connected_node_index;
565 cells_offset[index + 1] = connected_node_index;
568 for (Face face : cell.faces()) {
574 Int32 face_nb_node = face.nbNode();
575 bool is_back_cell = (face.backCellId().localId() == cell.localId());
577 for (NodeLocalId node : face.nodeIds())
578 faces_connectivity.add(node);
582 for (
Int32 i = face_nb_node - 1; i >= 0; --i)
583 faces_connectivity.add(node_ids[i]);
585 faces_offset.add(faces_connectivity.size());
586 polyhedron_to_faces.add(nb_face);
590 polyhedron_offset[index + 1] = polyhedron_to_faces.size();
600 Int32 local_has_polyhedron = (nb_face > 0) ? 1 : 0;
602 Int32 global_has_polyhedron_datasets = 0;
603 if (!m_is_first_call) {
604 Int32 local_has_polyhedron_datasets = 0;
606 HDataset polyhedron_dataset;
607 polyhedron_dataset.openIfExists(m_top_group,
"FaceConnectivity");
608 local_has_polyhedron_datasets = (polyhedron_dataset.id() > 0) ? 1 : 0;
612 if (global_has_polyhedron != 0 && global_has_polyhedron_datasets == 0 && !m_is_first_call)
613 ARCANE_FATAL(
"The mesh contains polyhedron cells but the associated datasets "
614 "do not exist in the file '{0}'. Polyhedron cells must be present "
615 "from the first output",
617 m_write_polyhedron_datasets = (global_has_polyhedron != 0) || (global_has_polyhedron_datasets != 0);
620 _initializeOffsets();
624 GatherGroupInfo* ggi = ggi_ref.get();
627 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"Offsets", m_offset_for_cell_offset_info),
630 if (m_write_polyhedron_datasets) {
634 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"PolyhedronOffsets", m_offset_for_polyhedron_offset_info),
635 ggi, polyhedron_offset);
637 ggi->setNeedRecompute();
639 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"Connectivity", m_connectivity_offset_info),
640 ggi, cells_connectivity);
641 ggi->setNeedRecompute();
643 if (m_write_polyhedron_datasets) {
645 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"FaceConnectivity", m_face_connectivity_offset_info),
646 ggi, faces_connectivity);
647 ggi->setNeedRecompute();
651 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"PolyhedronToFaces", m_polyhedron_to_face_offset_info),
652 ggi, polyhedron_to_faces);
653 ggi->setNeedRecompute();
657 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"FaceOffsets", m_offset_for_face_offset_info),
659 ggi->setNeedRecompute();
662 _writeDataSet1DCollective<unsigned char>(
DataInfo(m_top_group,
"Types", m_cell_offset_info),
663 &m_all_cells_gather_group_info, cells_type);
666 Int64 nb_cell_int64 = nb_cell;
667 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"NumberOfCells", m_part_offset_info),
668 ggi, asConstSpan(&nb_cell_int64));
670 Int64 nb_node_int64 = nb_node;
671 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"NumberOfPoints", m_part_offset_info),
672 ggi, asConstSpan(&nb_node_int64));
674 Int64 number_of_connectivity_ids = cells_connectivity.size();
675 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"NumberOfConnectivityIds", m_part_offset_info),
676 ggi, asConstSpan(&number_of_connectivity_ids));
678 if (m_write_polyhedron_datasets) {
679 Int64 nb_face_int64 = nb_face;
680 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"NumberOfFaces", m_part_offset_info),
681 ggi, asConstSpan(&nb_face_int64));
683 Int64 number_of_face_connectivity_ids = faces_connectivity.size();
684 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"NumberOfFaceConnectivityIds", m_part_offset_info),
685 ggi, asConstSpan(&number_of_face_connectivity_ids));
687 Int64 number_of_polyhedron_to_face_ids = polyhedron_to_faces.size();
688 _writeDataSet1DCollective<Int64>(
DataInfo(m_top_group,
"NumberOfPolyhedronToFaceIds", m_part_offset_info),
689 ggi, asConstSpan(&number_of_polyhedron_to_face_ids));
692 ggi->setNeedRecompute();
696 UniqueArray<Int64> nodes_uid(nb_node);
697 UniqueArray<unsigned char> nodes_ghost_type(nb_node);
699 UniqueArray2<Real> points;
700 points.resize(nb_node, 3);
702 Int32 index = inode.index();
705 nodes_uid[index] = node.uniqueId();
708 bool is_ghost = !node.isOwn();
710 ghost_type = VtkUtils::PointGhostTypes::DUPLICATEPOINT;
711 nodes_ghost_type[index] = ghost_type;
713 Real3 pos = nodes_coordinates[inode];
714 points[index][0] = pos.x;
715 points[index][1] = pos.y;
716 points[index][2] = pos.z;
721 &m_all_nodes_gather_group_info, nodes_uid);
725 &m_all_nodes_gather_group_info, nodes_ghost_type);
730 ggi->setNeedRecompute();
735 &m_all_cells_gather_group_info, cells_ghost_type);
740 &m_all_cells_gather_group_info, cells_uid);
744 Real current_time = m_times[time_index - 1];
747 ggi, asConstSpan(¤t_time));
750 Int64 comm_size = pm->commSize();
751 Int64 part_offset = (time_index - 1) * comm_size;
753 ggi, asConstSpan(&part_offset));
755 if (m_write_polyhedron_datasets) {
761 auto face_offsets_write_offset = m_offset_info_list.find(m_offset_for_face_offset_info);
762 if (face_offsets_write_offset == m_offset_info_list.end())
763 ARCANE_FATAL(
"The dataset 'FaceOffsets' has not been written");
764 Int64 nb_offset_value = (time_index - 1) * comm_size;
765 Int64 face_offsets_offset = face_offsets_write_offset->second - nb_offset_value;
766 _writeDataSet1D<Int64>({ { m_steps_group,
"FaceOffsetsOffsets" }, m_time_offset_info }, ggi,
767 asConstSpan(&face_offsets_offset));
771 _addInt64Attribute(m_steps_group,
"NSteps", time_index);
775 _writeConstituentsGroups();
781void VtkHdfV2DataWriter::
782_writeConstituentsGroups()
789 for (IMeshEnvironment* env : m_material_mng->environments()) {
793 m_materials_groups.add(group_info_ref);
796 m_gather_info_materials_groups.add(gather_info_ref);
799 GatherGroupInfo& gather_info = *gather_info_ref.get();
800 _initializeItemGroupCollectiveInfos(group_info, gather_info);
802 ConstArrayView<Int32> groups_ids = cells.view().localIds();
803 DatasetGroupAndName dataset_group_name(m_top_group, String(
"Constituent_") + cells.name());
805 info() <<
"Writing infos for group '" << cells.name() <<
"'";
806 _writeDataSet1DCollective<Int32>({ dataset_group_name, m_cell_offset_info, group_info_ref.get() }, gather_info_ref.get(), groups_ids);
815VtkHdfV2DataWriter::WritePartInfo VtkHdfV2DataWriter::
816_computeWritePartInfo(
Int64 local_size)
819 IParallelMng* pm = m_mesh->parallelMng();
820 Int32 nb_rank = pm->commSize();
821 Int32 my_rank = pm->commRank();
823 UniqueArray<Int64> ranks_size(nb_rank);
824 ArrayView<Int64> all_sizes(ranks_size);
825 Int64 dim1_size = local_size;
826 pm->allGather(ConstArrayView<Int64>(1, &dim1_size), all_sizes);
828 Int64 total_size = 0;
829 for (
Integer i = 0; i < nb_rank; ++i)
830 total_size += all_sizes[i];
833 for (
Integer i = 0; i < my_rank; ++i)
834 my_index += all_sizes[i];
837 part_info.setTotalSize(total_size);
838 part_info.setSize(local_size);
839 part_info.setOffset(my_index);
846void VtkHdfV2DataWriter::
849 Int32 dim1_size = group_info.m_item_group.size();
851 gather_info.setCollectiveIO(m_is_collective_io);
852 gather_info.computeSize(dim1_size);
854 Int32 computed_nb_elem = gather_info.nbElemOutput();
856 group_info.setWritePartInfo(_computeWritePartInfo(computed_nb_elem));
861 std::pair<Int64, Int64> _getInterval(
Int64 index,
Int64 nb_interval,
Int64 total_size)
863 Int64 n = total_size;
864 Int64 isize = n / nb_interval;
865 Int64 ibegin = index * isize;
867 if ((index + 1) == nb_interval)
869 return { ibegin, isize };
881void VtkHdfV2DataWriter::
882_writeDataSetGeneric(
const DataInfo& data_info, GatherGroupInfo* gather_info,
Int32 nb_dim,
884 ConstMemoryView values_data,
885 const hid_t hdf_type,
bool is_collective)
891 HGroup& group = data_info.dataset.group;
892 const String& name = data_info.dataset.name;
896 Int64 wanted_offset = data_info.datasetInfo().offset();
898 static constexpr int MAX_DIM = 2;
907 FixedArray<hsize_t, MAX_DIM> local_dims;
908 local_dims[0] = dim1_size;
909 local_dims[1] = dim2_size;
912 FixedArray<hsize_t, MAX_DIM> global_dims;
916 FixedArray<hsize_t, MAX_DIM> max_dims;
917 max_dims[0] = H5S_UNLIMITED;
918 max_dims[1] = dim2_size;
921 Int64 write_offset = 0;
924 Int64 global_dim1_size = dim1_size;
925 Int32 nb_participating_rank = 1;
928 nb_participating_rank = gather_info->nbWriterGlobal();
930 if (data_info.m_group_info) {
933 part_info = data_info.m_group_info->writePartInfo();
936 part_info = _computeWritePartInfo(dim1_size);
938 global_dim1_size = part_info.totalSize();
939 my_index = part_info.offset();
947 HProperty write_plist_id;
950 write_plist_id.createDatasetTransfertCollectiveMPIIO();
952 write_plist_id.createDatasetTransfertIndependentMPIIO();
956 FixedArray<hsize_t, MAX_DIM> hyperslab_offsets;
958 if (m_is_first_call) {
960 FixedArray<hsize_t, MAX_DIM> chunk_dims;
961 global_dims[0] = global_dim1_size;
962 global_dims[1] = dim2_size;
964 Int64 chunk_size = global_dim1_size / nb_participating_rank;
965 if (chunk_size < 1024)
967 const Int64 max_chunk_size = 1024 * 1024 * 10;
968 chunk_size =
math::min(chunk_size, max_chunk_size);
969 chunk_dims[0] = chunk_size;
970 chunk_dims[1] = dim2_size;
971 info() <<
"CHUNK nb_dim=" << nb_dim
972 <<
" global_dim1_size=" << global_dim1_size
973 <<
" chunk0=" << chunk_dims[0]
974 <<
" chunk1=" << chunk_dims[1]
976 file_space.createSimple(nb_dim, global_dims.data(), max_dims.data());
978 plist_id.create(H5P_DATASET_CREATE);
979 H5Pset_chunk(plist_id.id(), nb_dim, chunk_dims.data());
980 dataset.create(group, name.localstr(), hdf_type, file_space, HProperty{}, plist_id, HProperty{});
983 hyperslab_offsets[0] = my_index;
984 hyperslab_offsets[1] = 0;
990 dataset.open(group, name.localstr());
991 file_space = dataset.getSpace();
992 int nb_dimension = file_space.nbDimension();
993 if (nb_dimension != nb_dim)
994 ARCANE_THROW(IOException,
"Bad dimension '{0}' for dataset '{1}' (should be 1)",
997 FixedArray<hsize_t, MAX_DIM> original_dims;
998 file_space.getDimensions(original_dims.data(),
nullptr);
999 hsize_t offset0 = original_dims[0];
1002 if (wanted_offset >= 0) {
1003 offset0 = wanted_offset;
1004 info() <<
"Forcing offset to " << wanted_offset;
1006 global_dims[0] = offset0 + global_dim1_size;
1007 global_dims[1] = dim2_size;
1008 write_offset = offset0;
1011 if ((herror = dataset.setExtent(global_dims.data())) < 0)
1012 ARCANE_THROW(IOException,
"Can not extent dataset '{0}' (err={1})", name, herror);
1013 file_space = dataset.getSpace();
1015 hyperslab_offsets[0] = offset0 + my_index;
1016 hyperslab_offsets[1] = 0;
1017 info(4) <<
"APPEND nb_dim=" << nb_dim
1018 <<
" dim0=" << global_dims[0]
1019 <<
" count0=" << local_dims[0]
1020 <<
" offsets0=" << hyperslab_offsets[0] <<
" name=" << name;
1023 Int64 nb_write_byte = global_dim1_size * dim2_size * values_data.datatypeSize();
1027 Int64 nb_interval = 1;
1028 if (is_collective && m_max_write_size > 0) {
1029 nb_interval = 1 + nb_write_byte / (m_max_write_size * 1024);
1031 info(4) <<
"WRITE global_size=" << nb_write_byte <<
" max_size=" << m_max_write_size <<
" nb_interval=" << nb_interval;
1033 for (
Int64 i = 0; i < nb_interval; ++i) {
1034 auto [index, nb_element] = _getInterval(i, nb_interval, dim1_size);
1036 FixedArray<hsize_t, 2> dims;
1037 dims[0] = nb_element;
1038 dims[1] = dim2_size;
1039 FixedArray<hsize_t, 2> offsets;
1040 offsets[0] = hyperslab_offsets[0] + index;
1042 if ((herror = H5Sselect_hyperslab(file_space.id(), H5S_SELECT_SET, offsets.data(),
nullptr, dims.data(),
nullptr)) < 0)
1043 ARCANE_THROW(IOException,
"Can not select hyperslab '{0}' (err={1})", name, herror);
1045 HSpace memory_space;
1046 memory_space.createSimple(nb_dim, dims.data());
1047 Int64 data_offset = index * values_data.datatypeSize() * dim2_size;
1049 if ((herror = dataset.write(hdf_type, values_data.data() + data_offset, memory_space, file_space, write_plist_id)) < 0)
1050 ARCANE_THROW(IOException,
"Can not write dataset '{0}' (err={1})", name, herror);
1052 if (dataset.isBad())
1053 ARCANE_THROW(IOException,
"Can not write dataset '{0}'", name);
1056 if (!data_info.datasetInfo().isNull())
1057 m_offset_info_list.insert(std::make_pair(data_info.datasetInfo(), write_offset));
1063template <
typename DataType>
void VtkHdfV2DataWriter::
1064_writeDataSetGeneric(
const DataInfo& data_info, GatherGroupInfo* gather_info,
Int32 nb_dim,
1065 Int64 dim1_size,
Int64 dim2_size,
const DataType* values_data,
1068 const hid_t hdf_type = m_standard_types.nativeType(DataType{});
1069 ConstMemoryView mem_view =
makeConstMemoryView(values_data,
sizeof(DataType), dim1_size * dim2_size);
1070 _writeDataSetGeneric(data_info, gather_info, nb_dim, dim1_size, dim2_size, mem_view, hdf_type, is_collective);
1076template <
typename DataType>
void VtkHdfV2DataWriter::
1077_writeDataSet1D(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
1079 _writeDataSetGeneric(data_info, gather_info, 1, values.size(), 1, values.data(),
false);
1085template <
typename DataType>
void VtkHdfV2DataWriter::
1086_writeDataSet1DUsingCollectiveIO(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
1088 _writeDataSetGeneric(data_info, gather_info, 1, values.size(), 1, values.data(),
true);
1094template <
typename DataType>
void VtkHdfV2DataWriter::
1095_writeDataSet1DCollective(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
1101 gather_info->computeSizeT(values);
1102 gg.setGatherGroupInfo(gather_info);
1104 if (gg.isNeedGather()) {
1105 UniqueArray<DataType> all_values;
1106 gg.gatherToMasterIOT(values, all_values);
1108 if (m_is_collective_io)
1109 _writeDataSet1DUsingCollectiveIO(data_info, gather_info, all_values.constSpan());
1111 _writeDataSet1D(data_info, gather_info, all_values.constSpan());
1114 if (m_is_collective_io)
1115 _writeDataSet1DUsingCollectiveIO(data_info, gather_info, values);
1117 _writeDataSet1D(data_info, gather_info, values);
1124template <
typename DataType>
void VtkHdfV2DataWriter::
1125_writeDataSet2D(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
1127 _writeDataSetGeneric(data_info, gather_info, 2, values.dim1Size(), values.dim2Size(), values.data(),
false);
1133template <
typename DataType>
void VtkHdfV2DataWriter::
1134_writeDataSet2DUsingCollectiveIO(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
1136 _writeDataSetGeneric(data_info, gather_info, 2, values.dim1Size(), values.dim2Size(), values.data(),
true);
1142template <
typename DataType>
void VtkHdfV2DataWriter::
1143_writeDataSet2DCollective(
const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
1149 gather_info->computeSizeT(values);
1150 gg.setGatherGroupInfo(gather_info);
1152 if (gg.isNeedGather()) {
1153 UniqueArray2<DataType> all_values;
1154 gg.gatherToMasterIOT(values, all_values);
1156 if (m_is_collective_io)
1157 _writeDataSet2DUsingCollectiveIO(data_info, gather_info, all_values.constSpan());
1159 _writeDataSet2D(data_info, gather_info, all_values.constSpan());
1162 if (m_is_collective_io)
1163 _writeDataSet2DUsingCollectiveIO(data_info, gather_info, values);
1165 _writeDataSet2D(data_info, gather_info, values);
1172void VtkHdfV2DataWriter::
1173_addInt64ArrayAttribute(Hid& hid,
const char* name, Span<const Int64> values)
1175 hsize_t
len = values.size();
1176 hid_t aid = H5Screate_simple(1, &len,
nullptr);
1177 hid_t attr = H5Acreate2(hid.id(), name, H5T_NATIVE_INT64, aid, H5P_DEFAULT, H5P_DEFAULT);
1180 int ret = H5Awrite(attr, H5T_NATIVE_INT64, values.data());
1190void VtkHdfV2DataWriter::
1191_addInt64Attribute(Hid& hid,
const char* name,
Int64 value)
1193 HSpace aid(H5Screate(H5S_SCALAR));
1195 if (m_is_first_call)
1196 attr.create(hid, name, H5T_NATIVE_INT64, aid);
1198 attr.open(hid, name);
1201 herr_t ret = attr.write(H5T_NATIVE_INT64, &value);
1209Int64 VtkHdfV2DataWriter::
1210_readInt64Attribute(Hid& hid,
const char* name)
1213 attr.open(hid, name);
1217 herr_t ret = attr.read(H5T_NATIVE_INT64, &value);
1226void VtkHdfV2DataWriter::
1227_addStringAttribute(Hid& hid,
const char* name,
const String& value)
1229 hid_t aid = H5Screate(H5S_SCALAR);
1230 hid_t attr_type = H5Tcopy(H5T_C_S1);
1231 H5Tset_size(attr_type, value.length());
1232 hid_t attr = H5Acreate2(hid.id(), name, attr_type, aid, H5P_DEFAULT, H5P_DEFAULT);
1235 int ret = H5Awrite(attr, attr_type, value.localstr());
1236 ret = H5Tclose(attr_type);
1246void VtkHdfV2DataWriter::
1252 for (
const auto& i : m_offset_info_list) {
1253 Int64 offset = i.second;
1255 HGroup* hdf_group = offset_info.group();
1259 _writeDataSet1D<Int64>({ { *hdf_group, offset_info.name() }, m_time_offset_info }, ggi.get(), asConstSpan(&offset));
1270void VtkHdfV2DataWriter::
1271_openOrCreateGroups()
1274 m_top_group.openOrCreate(m_file_id,
"VTKHDF");
1275 m_cell_data_group.openOrCreate(m_top_group,
"CellData");
1276 m_node_data_group.openOrCreate(m_top_group,
"PointData");
1277 m_steps_group.openOrCreate(m_top_group,
"Steps");
1278 m_point_data_offsets_group.openOrCreate(m_steps_group,
"PointDataOffsets");
1279 m_cell_data_offsets_group.openOrCreate(m_steps_group,
"CellDataOffsets");
1280 m_field_data_offsets_group.openOrCreate(m_steps_group,
"FieldDataOffsets");
1286void VtkHdfV2DataWriter::
1289 m_cell_data_group.close();
1290 m_node_data_group.close();
1291 m_point_data_offsets_group.close();
1292 m_cell_data_offsets_group.close();
1293 m_field_data_offsets_group.close();
1294 m_steps_group.close();
1295 m_top_group.close();
1304 ARCANE_UNUSED(meta_data);
1313 info(4) <<
"Write VtkHdfV2 var=" << var->
name();
1318 ARCANE_FATAL(
"Only export of scalar item variable is implemented (name={0})", var->
name());
1320 ARCANE_FATAL(
"Export of partial variable is not implemented");
1325 GatherGroupInfo* gather_info =
nullptr;
1326 switch (item_kind) {
1328 group = &m_cell_data_group;
1329 offset_info = m_cell_offset_info;
1330 group_info = &m_all_cells_info;
1331 gather_info = &m_all_cells_gather_group_info;
1334 group = &m_node_data_group;
1335 offset_info = m_point_offset_info;
1336 group_info = &m_all_nodes_info;
1337 gather_info = &m_all_nodes_gather_group_info;
1340 ARCANE_FATAL(
"Only export of 'Cell' or 'Node' variable is implemented (name={0})", var->
name());
1347 switch (data_type) {
1349 _writeBasicTypeDataset<Real>(data_info, gather_info, data);
1352 _writeBasicTypeDataset<Int64>(data_info, gather_info, data);
1355 _writeBasicTypeDataset<Int32>(data_info, gather_info, data);
1358 _writeReal3Dataset(data_info, gather_info, data);
1361 _writeReal2Dataset(data_info, gather_info, data);
1364 warning() << String::format(
"Export for datatype '{0}' is not supported (var_name={1})", data_type, var->
name());
1371template <
typename DataType>
void VtkHdfV2DataWriter::
1372_writeBasicTypeDataset(
const DataInfo& data_info, GatherGroupInfo* gather_info,
IData* data)
1382void VtkHdfV2DataWriter::
1383_writeReal3Dataset(
const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data)
1385 auto* true_data =
dynamic_cast<IArrayDataT<Real3>*
>(data);
1387 SmallSpan<const Real3> values(true_data->view());
1388 Int32 nb_value = values.size();
1390 UniqueArray2<Real> scalar_values;
1391 scalar_values.resize(nb_value, 3);
1392 for (Int32 i = 0; i < nb_value; ++i) {
1393 Real3 v = values[i];
1394 scalar_values[i][0] = v.x;
1395 scalar_values[i][1] = v.y;
1396 scalar_values[i][2] = v.z;
1398 _writeDataSet2DCollective<Real>(data_info, gather_info, scalar_values);
1404void VtkHdfV2DataWriter::
1405_writeReal2Dataset(
const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data)
1408 auto* true_data =
dynamic_cast<IArrayDataT<Real2>*
>(data);
1410 SmallSpan<const Real2> values(true_data->view());
1411 Int32 nb_value = values.size();
1412 UniqueArray2<Real> scalar_values;
1413 scalar_values.resize(nb_value, 3);
1414 for (
Int32 i = 0; i < nb_value; ++i) {
1415 Real2 v = values[i];
1416 scalar_values[i][0] = v.x;
1417 scalar_values[i][1] = v.y;
1418 scalar_values[i][2] = 0.0;
1420 _writeDataSet2DCollective<Real>(data_info, gather_info, scalar_values);
1426void VtkHdfV2DataWriter::
1429 HGroup* hgroup = offset_info.group();
1431 StandardArrayT<Int64> a(hgroup->id(), offset_info.name());
1432 UniqueArray<Int64> values;
1433 a.directRead(m_standard_types, values);
1434 Int64 offset_value = values[wanted_step];
1435 offset_info.setOffset(offset_value);
1436 info() <<
"VALUES name=" << offset_info.name() <<
" values=" << values
1437 <<
" wanted_step=" << wanted_step <<
" v=" << offset_value;
1443void VtkHdfV2DataWriter::
1477 m_cell_offset_info =
DatasetInfo(m_steps_group,
"CellOffsets");
1478 m_point_offset_info =
DatasetInfo(m_steps_group,
"PointOffsets");
1479 m_connectivity_offset_info =
DatasetInfo(m_steps_group,
"ConnectivityIdOffsets");
1480 m_face_connectivity_offset_info =
DatasetInfo(m_steps_group,
"FaceConnectivityOffsets");
1481 m_polyhedron_to_face_offset_info =
DatasetInfo(m_steps_group,
"PolyhedronToFaceIdOffsets");
1482 m_face_offsets_offset_info =
DatasetInfo(m_steps_group,
"FaceOffsetsOffsets");
1484 m_offset_for_cell_offset_info =
DatasetInfo(
"_OffsetForCellOffsetInfo");
1485 m_offset_for_face_offset_info =
DatasetInfo(
"_OffsetForFaceOffsetInfo");
1486 m_offset_for_polyhedron_offset_info =
DatasetInfo(
"_OffsetForPolyhedronOffsetInfo");
1487 m_part_offset_info =
DatasetInfo(
"_PartOffsetInfo");
1488 m_time_offset_info =
DatasetInfo(
"_TimeOffsetInfo");
1493 if (m_is_writer && !m_is_first_call) {
1494 IParallelMng* pm = m_mesh->parallelMng();
1495 const Int32 nb_rank = pm->commSize();
1496 Int64 nb_current_step = _readInt64Attribute(m_steps_group,
"NSteps");
1497 Int32 time_index = m_times.size();
1498 info(4) <<
"NB_STEP=" << nb_current_step <<
" time_index=" << time_index
1499 <<
" current_time=" << m_times.back();
1500 const bool debug_times =
false;
1502 StandardArrayT<Real> a1(m_steps_group.id(),
"Values");
1503 UniqueArray<Real> times;
1504 a1.directRead(m_standard_types, times);
1505 info() <<
"TIMES=" << times;
1507 if ((nb_current_step + 1) != time_index) {
1508 info() <<
"[VtkHdf] go_backward detected";
1509 Int32 wanted_step = time_index - 1;
1512 _readAndSetOffset(m_cell_offset_info, wanted_step);
1513 _readAndSetOffset(m_point_offset_info, wanted_step);
1514 _readAndSetOffset(m_connectivity_offset_info, wanted_step);
1515 if (m_write_polyhedron_datasets) {
1516 _readAndSetOffset(m_face_connectivity_offset_info, wanted_step);
1517 _readAndSetOffset(m_polyhedron_to_face_offset_info, wanted_step);
1518 _readAndSetOffset(m_face_offsets_offset_info, wanted_step);
1521 m_offset_for_face_offset_info.setOffset(m_face_offsets_offset_info.offset() + wanted_step * nb_rank);
1524 m_offset_for_polyhedron_offset_info.setOffset(m_offset_for_cell_offset_info.offset());
1526 m_part_offset_info.setOffset(wanted_step * nb_rank);
1527 m_time_offset_info.setOffset(wanted_step);
1528 m_offset_for_cell_offset_info.setOffset(m_cell_offset_info.offset() + wanted_step * nb_rank);
1541class VtkHdfV2PostProcessor
1542:
public ArcaneVtkHdfV2PostProcessorObject
1547 : ArcaneVtkHdfV2PostProcessorObject(sbi)
1551 IDataWriter* dataWriter()
override {
return m_writer.get(); }
1552 void notifyBeginWrite()
override
1554 bool use_collective_io =
true;
1555 Int64 max_write_size = 0;
1557 use_collective_io = options()->useCollectiveWrite();
1558 max_write_size = options()->maxWriteSize();
1560 auto w = std::make_unique<VtkHdfV2DataWriter>(mesh(), groups(), use_collective_io);
1561 w->setMaxWriteSize(max_write_size);
1562 w->setTimes(times());
1564 w->setDirectoryName(dir.
file(
"vtkhdfv2"));
1565 m_writer = std::move(w);
1567 void notifyEndWrite()
override
1571 void close()
override {}
1575 std::unique_ptr<IDataWriter> m_writer;
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Class managing a directory.
String file(const String &file_name) const override
Returns the full path of the file file_name in the directory.
Encapsulates a hid_t for a group.
static void useMutex(bool is_active, IParallelMng *pm)
Function allowing activation or deactivation of locks on each HDF5 call.
static constexpr bool hasParallelHdf5()
True HDF5 is compiled with MPI support.
Interface for writing variable data.
Interface of a data item.
virtual eDataType dataType() const =0
Data type managed by the variable (Real, Integer, ...).
virtual eItemKind itemKind() const =0
Kind of mesh entities on which the variable is based.
virtual bool isPartial() const =0
Indicates if the variable is partial.
virtual Integer dimension() const =0
Dimension of the variable.
virtual String name() const =0
Variable name.
Integer size() const
Number of elements in the group.
static IMeshMaterialMng * getReference(const MeshHandleOrMesh &mesh_handle, bool create=true)
Retrieves or creates the reference associated with mesh.
Structure containing the information to create a service.
View of an array of elements of type T.
Unicode character string.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage info() const
Flow for an information message.
TraceMessage warning() const
Flow for a warning message.
void write(IVariable *var, IData *data) override
Writes the data data of the variable var.
void setMetaData(const String &meta_data) override
Sets the metadata information.
Post-processing in VtkHdf V2 format.
__host__ __device__ Real2 min(Real2 a, Real2 b)
Returns the minimum of two Real2.
ItemLocalIdListViewT< Node > NodeLocalIdView
View over the localId() of a list of nodes.
ItemGroupT< Cell > CellGroup
Group of cells.
ItemGroupT< Node > NodeGroup
Group of nodes.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
Integer len(const char *s)
Returns the length of the string s.
Utility functions for Hdf5.
Always enables tracing in Arcane parts concerning materials.
@ ReduceMax
Maximum of values.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Ref< TrueType > createRef(Args &&... args)
Creates an instance of type TrueType with arguments Args and returns a reference to it.
Collection< ItemGroup > ItemGroupCollection
Collection of mesh item groups.
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
@ Polyhedral
Polyhedral mesh.
bool operator<(const Item &item1, const Item &item2)
Compare two entities.
ConstMemoryView makeConstMemoryView(const void *ptr, Int32 datatype_size, Int64 nb_element)
Creates a read-only memory view.
eItemKind
Mesh entity type.
@ IK_Node
Node mesh entity.
@ IK_Cell
Cell mesh entity.
double Real
Type representing a real number.
unsigned char Byte
Type of a byte.
@ DT_Int32
32-bit integer data type
@ DT_Real3
Vector 3 data type.
@ DT_Int64
64-bit integer data type
@ DT_Real2
Vector 2 data type.
@ Cell
The mesh is AMR by cell.
std::int32_t Int32
Signed integer type of 32 bits.
ConstArrayView< Real > RealConstArrayView
C equivalent of a 1D array of reals.
Stores info about the data to be saved and the associated offset.
Class to store a pair (hdf_group, dataset_name).
Class to store offset information.
Int64 offset() const
Offset value. (-1) if writing to the end of the array.
Collective information for an ItemGroup;.
WritePartInfo m_write_part_info
Writing information.
ItemGroup m_item_group
Associated group.
Offset information for the part to write associated with a rank.