Arcane  4.1.11.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
VtkHdfV2PostProcessor.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* VtkHdfV2PostProcessor.cc (C) 2000-2026 */
9/* */
10/* Pos-traitement au format VTK HDF. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
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"
21
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/VariableCollection.h"
29#include "arcane/core/IParallelMng.h"
30#include "arcane/core/IMesh.h"
31#include "arcane/core/internal/IParallelMngInternal.h"
32#include "arcane/core/internal/VtkCellTypes.h"
33#include "arcane/core/internal/GatherGroup.h"
34
35#include "arcane/core/materials/IMeshMaterialMng.h"
36#include "arcane/core/materials/IMeshEnvironment.h"
37
38#include "arcane/hdf5/Hdf5Utils.h"
39#include "arcane/hdf5/VtkHdfV2PostProcessor_axl.h"
40
41#include <map>
42
43// Ce format est décrit sur la page web suivante :
44//
45// https://kitware.github.io/vtk-examples/site/VTKFileFormats/#hdf-file-formats
46//
47// Le format 2.0 avec le support intégré de l'évolution temporelle n'est
48// disponible que dans la branche master de VTK à partir d'avril 2023.
49
50/*---------------------------------------------------------------------------*/
51/*---------------------------------------------------------------------------*/
52
53// TODO: Ajouter test de vérifcation des valeurs sauvegardées
54
55// TODO: Regarder la sauvegarde des uniqueId() (via vtkOriginalCellIds)
56
57// TODO: Regarder comment éviter de sauver le maillage à chaque itération s'il
58// ne change pas.
59
60// TODO: Regarder la compression
61
62// TODO: gérer les variables 2D
63
64// TODO: hors HDF5, faire un mécanisme qui regroupe plusieurs parties
65// du maillage en une seule. Cela permettra de réduire le nombre de mailles
66// fantômes et d'utiliser MPI/IO en mode hybride.
67
68/*---------------------------------------------------------------------------*/
69/*---------------------------------------------------------------------------*/
70
71namespace Arcane
72{
73using namespace Hdf5Utils;
74using namespace Materials;
75
76namespace
77{
78 template <typename T> Span<const T>
79 asConstSpan(const T* v)
80 {
81 return Span<const T>(v, 1);
82 }
83} // namespace
84
85/*---------------------------------------------------------------------------*/
86/*---------------------------------------------------------------------------*/
87
88class VtkHdfV2DataWriter
89: public TraceAccessor
90, public IDataWriter
91{
92 public:
93
100 struct DatasetGroupAndName
101 {
102 public:
103
104 DatasetGroupAndName(HGroup& group_, const String& name_)
105 : group(group_)
106 , name(name_)
107 {}
108
109 public:
110
111 HGroup& group;
112 String name;
113 };
114
126 struct DatasetInfo
127 {
128 DatasetInfo() = default;
129 explicit DatasetInfo(const String& name)
130 : m_name(name)
131 {}
132 DatasetInfo(HGroup& _group, const String& name)
133 : m_group(&_group)
134 , m_name(name)
135 {}
136 bool isNull() const { return m_name.null(); }
137
138 HGroup* group() const { return m_group; }
139 const String& name() const { return m_name; }
141 Int64 offset() const { return m_offset; }
142 void setOffset(Int64 v) { m_offset = v; }
143 friend bool operator<(const DatasetInfo& s1, const DatasetInfo& s2)
144 {
145 return (s1.m_name < s2.m_name);
146 }
147
148 private:
149
150 HGroup* m_group = nullptr;
151 String m_name;
152 Int64 m_offset = -1;
153 };
154
157 {
158 public:
159
160 void setTotalSize(Int64 v) { m_total_size = v; }
161 void setSize(Int64 v) { m_size = v; }
162 void setOffset(Int64 v) { m_offset = v; }
163
164 Int64 totalSize() const { return m_total_size; }
165 Int64 size() const { return m_size; }
166 Int64 offset() const { return m_offset; }
167
168 private:
169
176 };
177
179 struct ItemGroupCollectiveInfo
180 {
181 public:
182
183 explicit ItemGroupCollectiveInfo(const ItemGroup& g)
184 : m_item_group(g)
185 {}
186
187 public:
188
189 void setWritePartInfo(const WritePartInfo& part_info) { m_write_part_info = part_info; }
190 const WritePartInfo& writePartInfo() const { return m_write_part_info; }
191
192 public:
193
198 };
199
203 struct DataInfo
204 {
205 public:
206
207 DataInfo(const DatasetGroupAndName& dname, const DatasetInfo& dataset_info)
208 : dataset(dname)
209 , m_dataset_info(dataset_info)
210 {
211 }
212 DataInfo(const DatasetGroupAndName& dname, const DatasetInfo& dataset_info,
213 ItemGroupCollectiveInfo* group_info)
214 : dataset(dname)
215 , m_dataset_info(dataset_info)
216 , m_group_info(group_info)
217 {
218 }
219
220 public:
221
222 DatasetInfo datasetInfo() const { return m_dataset_info; }
223
224 public:
225
226 DatasetGroupAndName dataset;
227 DatasetInfo m_dataset_info;
228 ItemGroupCollectiveInfo* m_group_info = nullptr;
229 };
230
231 public:
232
233 VtkHdfV2DataWriter(IMesh* mesh, const ItemGroupCollection& groups, bool is_collective_io);
234
235 public:
236
237 void beginWrite(const VariableCollection& vars) override;
238 void endWrite() override;
239 void setMetaData(const String& meta_data) override;
240 void write(IVariable* var, IData* data) override;
241
242 public:
243
244 void setTimes(RealConstArrayView times) { m_times = times; }
245 void setDirectoryName(const String& dir_name) { m_directory_name = dir_name; }
246 void setMaxWriteSize(Int64 v) { m_max_write_size = v; }
247
248 private:
249
251 IMesh* m_mesh = nullptr;
252
255
258
261
264
267
270
271 HGroup m_top_group;
272 HGroup m_cell_data_group;
273 HGroup m_node_data_group;
274
275 HGroup m_steps_group;
276 HGroup m_point_data_offsets_group;
277 HGroup m_cell_data_offsets_group;
278 HGroup m_field_data_offsets_group;
279
280 bool m_is_parallel = false;
281 bool m_is_collective_io = false;
282 bool m_is_first_call = false;
283 bool m_is_writer = false;
284 Int32 m_writer = 0;
285
286 DatasetInfo m_cell_offset_info;
287 DatasetInfo m_point_offset_info;
288 DatasetInfo m_connectivity_offset_info;
289 DatasetInfo m_offset_for_cell_offset_info;
290 DatasetInfo m_part_offset_info;
291 DatasetInfo m_time_offset_info;
292 std::map<DatasetInfo, Int64> m_offset_info_list;
293
294 StandardTypes m_standard_types{ false };
295
296 ItemGroupCollectiveInfo m_all_cells_info;
297 ItemGroupCollectiveInfo m_all_nodes_info;
299
300 GatherGroupInfo m_all_cells_gather_group_info;
301 GatherGroupInfo m_all_nodes_gather_group_info;
302 UniqueArray<Ref<GatherGroupInfo>> m_gather_info_materials_groups;
303
311
312 private:
313
314 void _addInt64ArrayAttribute(Hid& hid, const char* name, Span<const Int64> values);
315 void _addStringAttribute(Hid& hid, const char* name, const String& value);
316
317 template <typename DataType> void
318 _writeDataSet1D(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values);
319 template <typename DataType> void
320 _writeDataSet1DUsingCollectiveIO(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values);
321 template <typename DataType> void
322 _writeDataSet1DCollective(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values);
323 template <typename DataType> void
324 _writeDataSet2D(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values);
325 template <typename DataType> void
326 _writeDataSet2DUsingCollectiveIO(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values);
327 template <typename DataType> void
328 _writeDataSet2DCollective(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values);
329 template <typename DataType> void
330 _writeBasicTypeDataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data);
331 void _writeReal3Dataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data);
332 void _writeReal2Dataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data);
333
334 String _getFileName()
335 {
336 StringBuilder sb(m_mesh->name());
337 sb += ".hdf";
338 return sb.toString();
339 }
340 template <typename DataType> void
341 _writeDataSetGeneric(const DataInfo& data_info, GatherGroupInfo* gather_info, Int32 nb_dim,
342 Int64 dim1_size, Int64 dim2_size, const DataType* values_data,
343 bool is_collective);
344 void _writeDataSetGeneric(const DataInfo& data_info, GatherGroupInfo* gather_info, Int32 nb_dim,
345 Int64 dim1_size, Int64 dim2_size, ConstMemoryView values_data,
346 const hid_t hdf_datatype_type, bool is_collective);
347 void _addInt64Attribute(Hid& hid, const char* name, Int64 value);
348 Int64 _readInt64Attribute(Hid& hid, const char* name);
349 void _openOrCreateGroups();
350 void _closeGroups();
351 void _readAndSetOffset(DatasetInfo& offset_info, Int32 wanted_step);
352 void _initializeOffsets();
353 void _initializeItemGroupCollectiveInfos(ItemGroupCollectiveInfo& group_info, GatherGroupInfo& gather_info);
354 WritePartInfo _computeWritePartInfo(Int64 local_size);
355 void _writeConstituentsGroups();
356};
357
358/*---------------------------------------------------------------------------*/
359/*---------------------------------------------------------------------------*/
360
361VtkHdfV2DataWriter::
362VtkHdfV2DataWriter(IMesh* mesh, const ItemGroupCollection& groups, bool is_collective_io)
363: TraceAccessor(mesh->traceMng())
364, m_mesh(mesh)
365, m_groups(groups)
366, m_is_collective_io(is_collective_io)
367, m_all_cells_info(mesh->allCells())
368, m_all_nodes_info(mesh->allNodes())
369, m_all_cells_gather_group_info(mesh->parallelMng(), is_collective_io)
370, m_all_nodes_gather_group_info(mesh->parallelMng(), is_collective_io)
371{
372}
373
374/*---------------------------------------------------------------------------*/
375/*---------------------------------------------------------------------------*/
376
377void VtkHdfV2DataWriter::
378beginWrite(const VariableCollection& vars)
379{
380 ARCANE_UNUSED(vars);
381
382 // Récupère le gestionnaire de matériaux s'il existe
384
385 IParallelMng* pm = m_mesh->parallelMng();
386 const Int32 nb_rank = pm->commSize();
387 m_is_parallel = nb_rank > 1;
388
389 Int32 time_index = m_times.size();
390 const bool is_first_call = (time_index < 2);
391 m_is_first_call = is_first_call;
392 if (is_first_call)
393 info() << "WARNING: L'implémentation au format 'VtkHdfV2' est expérimentale";
394
395 String filename = _getFileName();
396
397 Directory dir(m_directory_name);
398
399 m_full_filename = dir.file(filename);
400 info(4) << "VtkHdfV2DataWriter::beginWrite() file=" << m_full_filename;
401
402 HInit();
403 HInit::useMutex(pm->isThreadImplementation(), pm);
404
405 // Il est possible d'utiliser le mode collectif de HDF5 via MPI-IO dans les cas suivants :
406 // * Hdf5 a été compilé avec MPI,
407 // * on est en mode MPI pure (ni mode mémoire partagé, ni mode hybride).
408 m_is_collective_io = m_is_collective_io && (pm->isParallel() && HInit::hasParallelHdf5());
409 if (pm->isThreadImplementation() && !pm->isHybridImplementation())
410 m_is_collective_io = false;
411
412 if (is_first_call) {
413 info() << "VtkHdfV2DataWriter: using collective MPI/IO ?=" << m_is_collective_io;
414 info() << "VtkHdfV2DataWriter: max_write_size (kB) =" << m_max_write_size;
415 info() << "VtkHdfV2DataWriter: has_material?=" << (m_material_mng != nullptr);
416 }
417
418 bool is_master_io = pm->isMasterIO();
419
420 // Vrai si on doit participer aux écritures
421 // Si on utilise MPI/IO avec HDF5, il faut tout de même que tous
422 // les rangs fassent toutes les opérations d'écriture pour garantir
423 // la cohérence des méta-données.
424 if (m_is_collective_io) {
425 m_writer = pm->_internalApi()->masterParallelIORank();
426 m_is_writer = (m_writer == pm->commRank());
427 }
428 else {
429 m_writer = pm->masterIORank();
430 m_is_writer = is_master_io;
431 }
432
433 // Indique qu'on utilise MPI/IO si demandé
434 HProperty plist_id;
435 if (m_is_collective_io && m_is_writer)
436 plist_id.createFilePropertyMPIIO(pm);
437
438 // Même avec MPI-IO, un seul proc doit créer le dossier.
439 if (is_first_call && is_master_io)
440 dir.createDirectory();
441
442 if (m_is_collective_io)
443 pm->barrier();
444
445 if (m_is_writer) {
446 m_standard_types.initialize();
447
448 if (is_first_call)
449 m_file_id.openTruncate(m_full_filename, plist_id.id());
450 else
451 m_file_id.openAppend(m_full_filename, plist_id.id());
452
453 _openOrCreateGroups();
454
455 if (is_first_call) {
456 std::array<Int64, 2> version = { 2, 0 };
457 _addInt64ArrayAttribute(m_top_group, "Version", version);
458 _addStringAttribute(m_top_group, "Type", "UnstructuredGrid");
459 }
460 }
461
462 // Initialise les informations collectives sur les groupes de mailles et noeuds
463 _initializeItemGroupCollectiveInfos(m_all_cells_info, m_all_cells_gather_group_info);
464 _initializeItemGroupCollectiveInfos(m_all_nodes_info, m_all_nodes_gather_group_info);
465
466 CellGroup all_cells = m_mesh->allCells();
467 NodeGroup all_nodes = m_mesh->allNodes();
468
469 const Int32 nb_cell = all_cells.size();
470 const Int32 nb_node = all_nodes.size();
471
472 Int32 total_nb_connected_node = 0;
473 ENUMERATE_ (Cell, icell, all_cells) {
474 Cell cell = *icell;
475 total_nb_connected_node += cell.nodeIds().size();
476 }
477
478 // Pour les offsets, la taille du tableau est égal
479 // au nombre de mailles plus 1.
480 UniqueArray<Int64> cells_connectivity(total_nb_connected_node);
481 UniqueArray<Int64> cells_offset(nb_cell + 1);
482 UniqueArray<unsigned char> cells_ghost_type(nb_cell);
483 UniqueArray<unsigned char> cells_type(nb_cell);
484 UniqueArray<Int64> cells_uid(nb_cell);
485 cells_offset[0] = 0;
486 {
487 Int32 connected_node_index = 0;
488 ENUMERATE_CELL (icell, all_cells) {
489 Int32 index = icell.index();
490 Cell cell = *icell;
491
492 cells_uid[index] = cell.uniqueId();
493
494 Byte ghost_type = 0;
495 bool is_ghost = !cell.isOwn();
496 if (is_ghost)
497 ghost_type = VtkUtils::CellGhostTypes::DUPLICATECELL;
498 cells_ghost_type[index] = ghost_type;
499
500 unsigned char vtk_type = VtkUtils::arcaneToVtkCellType(cell.type());
501 cells_type[index] = vtk_type;
502 for (NodeLocalId node : cell.nodeIds()) {
503 cells_connectivity[connected_node_index] = node;
504 ++connected_node_index;
505 }
506 cells_offset[index + 1] = connected_node_index;
507 }
508 }
509
510 _initializeOffsets();
511
512 // ggi est un GatherGroupInfo pour les tableaux qui ne sont pas de taille nb_cell ou nb_node.
513 Ref<GatherGroupInfo> ggi_ref = createRef<GatherGroupInfo>(m_mesh->parallelMng(), m_is_collective_io);
514 GatherGroupInfo* ggi = ggi_ref.get();
515
516 // TODO: faire un offset pour cet objet (ou regarder comment le calculer automatiquement
517 _writeDataSet1DCollective<Int64>({ { m_top_group, "Offsets" }, m_offset_for_cell_offset_info }, ggi, cells_offset);
518 ggi->setNeedRecompute();
519
520 _writeDataSet1DCollective<Int64>({ { m_top_group, "Connectivity" }, m_connectivity_offset_info }, ggi, cells_connectivity);
521 ggi->setNeedRecompute();
522
523 _writeDataSet1DCollective<unsigned char>({ { m_top_group, "Types" }, m_cell_offset_info }, &m_all_cells_gather_group_info, cells_type);
524
525 {
526 Int64 nb_cell_int64 = nb_cell;
527 _writeDataSet1DCollective<Int64>({ { m_top_group, "NumberOfCells" }, m_part_offset_info }, ggi,
528 asConstSpan(&nb_cell_int64));
529
530 Int64 nb_node_int64 = nb_node;
531 _writeDataSet1DCollective<Int64>({ { m_top_group, "NumberOfPoints" }, m_part_offset_info }, ggi,
532 asConstSpan(&nb_node_int64));
533
534 Int64 number_of_connectivity_ids = cells_connectivity.size();
535 _writeDataSet1DCollective<Int64>({ { m_top_group, "NumberOfConnectivityIds" }, m_part_offset_info }, ggi,
536 asConstSpan(&number_of_connectivity_ids));
537 }
538 ggi->setNeedRecompute();
539
540 // Sauve les uniqueIds, les types et les coordonnées des noeuds.
541 {
542 UniqueArray<Int64> nodes_uid(nb_node);
543 UniqueArray<unsigned char> nodes_ghost_type(nb_node);
544 VariableNodeReal3& nodes_coordinates(m_mesh->nodesCoordinates());
545 UniqueArray2<Real> points;
546 points.resize(nb_node, 3);
547 ENUMERATE_ (Node, inode, all_nodes) {
548 Int32 index = inode.index();
549 Node node = *inode;
550
551 nodes_uid[index] = node.uniqueId();
552
553 Byte ghost_type = 0;
554 bool is_ghost = !node.isOwn();
555 if (is_ghost)
556 ghost_type = VtkUtils::PointGhostTypes::DUPLICATEPOINT;
557 nodes_ghost_type[index] = ghost_type;
558
559 Real3 pos = nodes_coordinates[inode];
560 points[index][0] = pos.x;
561 points[index][1] = pos.y;
562 points[index][2] = pos.z;
563 }
564
565 // Sauve l'uniqueId de chaque nœud dans le dataset "GlobalNodeId".
566 _writeDataSet1DCollective<Int64>({ { m_node_data_group, "GlobalIds" }, m_cell_offset_info }, &m_all_nodes_gather_group_info, nodes_uid);
567
568 // Sauve les informations sur le type de nœud (réel ou fantôme).
569 _writeDataSet1DCollective<unsigned char>({ { m_node_data_group, "vtkGhostType" }, m_cell_offset_info }, &m_all_nodes_gather_group_info, nodes_ghost_type);
570
571 // Sauve les coordonnées des noeuds.
572 _writeDataSet2DCollective<Real>({ { m_top_group, "Points" }, m_point_offset_info }, ggi, points);
573 ggi->setNeedRecompute();
574 }
575
576 // Sauve les informations sur le type de maille (réel ou fantôme)
577 _writeDataSet1DCollective<unsigned char>({ { m_cell_data_group, "vtkGhostType" }, m_cell_offset_info }, &m_all_cells_gather_group_info, cells_ghost_type);
578
579 // Sauve l'uniqueId de chaque maille dans le dataset "GlobalCellId".
580 // L'utilisation du dataset "vtkOriginalCellIds" ne fonctionne pas dans Paraview.
581 _writeDataSet1DCollective<Int64>({ { m_cell_data_group, "GlobalIds" }, m_cell_offset_info }, &m_all_cells_gather_group_info, cells_uid);
582
583 if (m_is_writer) {
584 // Liste des temps.
585 Real current_time = m_times[time_index - 1];
586 // TODO : Remplacer ggi par nullptr en non-collective ?
587 _writeDataSet1D<Real>({ { m_steps_group, "Values" }, m_time_offset_info }, ggi, asConstSpan(&current_time));
588
589 // Offset de la partie.
590 Int64 comm_size = pm->commSize();
591 Int64 part_offset = (time_index - 1) * comm_size;
592 _writeDataSet1D<Int64>({ { m_steps_group, "PartOffsets" }, m_time_offset_info }, ggi, asConstSpan(&part_offset));
593
594 // Nombre de temps
595 _addInt64Attribute(m_steps_group, "NSteps", time_index);
596 }
597 //ggi->needRecompute();
598
599 _writeConstituentsGroups();
600}
601
602/*---------------------------------------------------------------------------*/
603/*---------------------------------------------------------------------------*/
604
605void VtkHdfV2DataWriter::
606_writeConstituentsGroups()
607{
608 if (!m_material_mng)
609 return;
610
611 // Remplit les informations des groupes liés aux constituents
612 // NOTE : Pour l'instant, on ne traite que les milieux.
613 for (IMeshEnvironment* env : m_material_mng->environments()) {
614 CellGroup cells = env->cells();
615
616 Ref<ItemGroupCollectiveInfo> group_info_ref = createRef<ItemGroupCollectiveInfo>(cells);
617 m_materials_groups.add(group_info_ref);
618
619 Ref<GatherGroupInfo> gather_info_ref = createRef<GatherGroupInfo>(m_material_mng->mesh()->parallelMng(), m_is_collective_io);
620 m_gather_info_materials_groups.add(gather_info_ref);
621
622 ItemGroupCollectiveInfo& group_info = *group_info_ref.get();
623 GatherGroupInfo& gather_info = *gather_info_ref.get();
624 _initializeItemGroupCollectiveInfos(group_info, gather_info);
625
626 ConstArrayView<Int32> groups_ids = cells.view().localIds();
627 DatasetGroupAndName dataset_group_name(m_top_group, String("Constituent_") + cells.name());
628 if (m_is_first_call)
629 info() << "Writing infos for group '" << cells.name() << "'";
630 _writeDataSet1DCollective<Int32>({ dataset_group_name, m_cell_offset_info, group_info_ref.get() }, gather_info_ref.get(), groups_ids);
631 }
632}
633
634/*---------------------------------------------------------------------------*/
635/*---------------------------------------------------------------------------*/
641{
642 // TODO: regarder pour utiliser un scan.
643 IParallelMng* pm = m_mesh->parallelMng();
644 Int32 nb_rank = pm->commSize();
645 Int32 my_rank = pm->commRank();
646
647 UniqueArray<Int64> ranks_size(nb_rank);
648 ArrayView<Int64> all_sizes(ranks_size);
649 Int64 dim1_size = local_size;
650 pm->allGather(ConstArrayView<Int64>(1, &dim1_size), all_sizes);
651
652 Int64 total_size = 0;
653 for (Integer i = 0; i < nb_rank; ++i)
654 total_size += all_sizes[i];
655
656 Int64 my_index = 0;
657 for (Integer i = 0; i < my_rank; ++i)
658 my_index += all_sizes[i];
659
660 WritePartInfo part_info;
661 part_info.setTotalSize(total_size);
662 part_info.setSize(local_size);
663 part_info.setOffset(my_index);
664 return part_info;
665}
666
667/*---------------------------------------------------------------------------*/
668/*---------------------------------------------------------------------------*/
669
670void VtkHdfV2DataWriter::
671_initializeItemGroupCollectiveInfos(ItemGroupCollectiveInfo& group_info, GatherGroupInfo& gather_info)
672{
673 Int32 dim1_size = group_info.m_item_group.size();
674
675 gather_info.setCollectiveIO(m_is_collective_io);
676 gather_info.computeSize(dim1_size);
677
678 Int32 computed_nb_elem = gather_info.nbElemOutput();
679
680 group_info.setWritePartInfo(_computeWritePartInfo(computed_nb_elem));
681}
682
683namespace
684{
685 std::pair<Int64, Int64> _getInterval(Int64 index, Int64 nb_interval, Int64 total_size)
686 {
687 Int64 n = total_size;
688 Int64 isize = n / nb_interval;
689 Int64 ibegin = index * isize;
690 // Pour le dernier interval, prend les elements restants
691 if ((index + 1) == nb_interval)
692 isize = n - ibegin;
693 return { ibegin, isize };
694 }
695} // namespace
696
697/*---------------------------------------------------------------------------*/
698/*---------------------------------------------------------------------------*/
705void VtkHdfV2DataWriter::
706_writeDataSetGeneric(const DataInfo& data_info, GatherGroupInfo* gather_info, Int32 nb_dim,
707 Int64 dim1_size, Int64 dim2_size,
708 ConstMemoryView values_data,
709 const hid_t hdf_type, bool is_collective)
710{
711 ARCANE_CHECK_POINTER(gather_info);
712 if (nb_dim == 1)
713 dim2_size = 1;
714
715 HGroup& group = data_info.dataset.group;
716 const String& name = data_info.dataset.name;
717
718 // Si positif ou nul, indique l'offset d'écriture.
719 // Sinon, on écrit à la fin du dataset actuel.
720 Int64 wanted_offset = data_info.datasetInfo().offset();
721
722 static constexpr int MAX_DIM = 2;
723 HDataset dataset;
724
725 // En cas d'opération collective, local_dims et global_dims sont
726 // différents sur la première dimension. La deuxième dimension est toujours
727 // identique pour local_dims et global_dims et ne doit pas être modifiée durant
728 // tout le calcul.
729
730 // Dimensions du dataset que le rang courant va écrire.
732 local_dims[0] = dim1_size;
733 local_dims[1] = dim2_size;
734
735 // Dimensions cumulées de tous les rangs pour l'écriture.
737
738 // Dimensions maximales du DataSet
739 // Pour la deuxième dimension, on suppose qu'elle est constante au cours du temps.
741 max_dims[0] = H5S_UNLIMITED;
742 max_dims[1] = dim2_size;
743
744 herr_t herror = 0;
745 Int64 write_offset = 0;
746
747 Int64 my_index = 0;
748 Int64 global_dim1_size = dim1_size;
749 Int32 nb_participating_rank = 1;
750
751 if (is_collective) {
752 nb_participating_rank = gather_info->nbWriterGlobal();
753 WritePartInfo part_info;
754 if (data_info.m_group_info) {
755 // Si la donnée est associée à un groupe, alors les informations
756 // sur l'offset ont déjà été calculées
757 part_info = data_info.m_group_info->writePartInfo();
758 }
759 else {
760 part_info = _computeWritePartInfo(dim1_size);
761 }
762 global_dim1_size = part_info.totalSize();
763 my_index = part_info.offset();
764 }
765
766 // La seule opération collective était _computeWritePartInfo().
767 if (!m_is_writer) {
768 return;
769 }
770
771 HProperty write_plist_id;
772 if constexpr (HInit::hasParallelHdf5()) {
773 if (is_collective)
775 else
777 }
778
779 HSpace file_space;
780 FixedArray<hsize_t, MAX_DIM> hyperslab_offsets;
781
782 if (m_is_first_call) {
783 // TODO: regarder comment mieux calculer le chunk
785 global_dims[0] = global_dim1_size;
786 global_dims[1] = dim2_size;
787 // Il est important que tout le monde ait la même taille de chunk.
788 Int64 chunk_size = global_dim1_size / nb_participating_rank;
789 if (chunk_size < 1024)
790 chunk_size = 1024;
791 const Int64 max_chunk_size = 1024 * 1024 * 10;
792 chunk_size = math::min(chunk_size, max_chunk_size);
793 chunk_dims[0] = chunk_size;
794 chunk_dims[1] = dim2_size;
795 info() << "CHUNK nb_dim=" << nb_dim
796 << " global_dim1_size=" << global_dim1_size
797 << " chunk0=" << chunk_dims[0]
798 << " chunk1=" << chunk_dims[1]
799 << " name=" << name;
800 file_space.createSimple(nb_dim, global_dims.data(), max_dims.data());
801 HProperty plist_id;
802 plist_id.create(H5P_DATASET_CREATE);
803 H5Pset_chunk(plist_id.id(), nb_dim, chunk_dims.data());
804 dataset.create(group, name.localstr(), hdf_type, file_space, HProperty{}, plist_id, HProperty{});
805
806 if (is_collective) {
807 hyperslab_offsets[0] = my_index;
808 hyperslab_offsets[1] = 0;
809 }
810 }
811 else {
812 // Agrandit la première dimension du dataset.
813 // On va ajouter 'global_dim1_size' à cette dimension.
814 dataset.open(group, name.localstr());
815 file_space = dataset.getSpace();
816 int nb_dimension = file_space.nbDimension();
817 if (nb_dimension != nb_dim)
818 ARCANE_THROW(IOException, "Bad dimension '{0}' for dataset '{1}' (should be 1)",
819 nb_dimension, name);
820 // TODO: Vérifier que la deuxième dimension est la même que celle sauvée.
821 FixedArray<hsize_t, MAX_DIM> original_dims;
822 file_space.getDimensions(original_dims.data(), nullptr);
823 hsize_t offset0 = original_dims[0];
824 // Si on a un offset positif issu de DatasetInfo alors on le prend.
825 // Cela signifie qu'on a fait un retour arrière.
826 if (wanted_offset >= 0) {
827 offset0 = wanted_offset;
828 info() << "Forcing offset to " << wanted_offset;
829 }
830 global_dims[0] = offset0 + global_dim1_size;
831 global_dims[1] = dim2_size;
832 write_offset = offset0;
833 // Agrandit le dataset.
834 // ATTENTION cela invalide file_space. Il faut donc le relire juste après.
835 if ((herror = dataset.setExtent(global_dims.data())) < 0)
836 ARCANE_THROW(IOException, "Can not extent dataset '{0}' (err={1})", name, herror);
837 file_space = dataset.getSpace();
838
839 hyperslab_offsets[0] = offset0 + my_index;
840 hyperslab_offsets[1] = 0;
841 info(4) << "APPEND nb_dim=" << nb_dim
842 << " dim0=" << global_dims[0]
843 << " count0=" << local_dims[0]
844 << " offsets0=" << hyperslab_offsets[0] << " name=" << name;
845 }
846
847 Int64 nb_write_byte = global_dim1_size * dim2_size * values_data.datatypeSize();
848
849 // Effectue l'écriture en plusieurs parties si demandé.
850 // Cela n'est possible que pour l'écriture collective.
851 Int64 nb_interval = 1;
852 if (is_collective && m_max_write_size > 0) {
853 nb_interval = 1 + nb_write_byte / (m_max_write_size * 1024);
854 }
855 info(4) << "WRITE global_size=" << nb_write_byte << " max_size=" << m_max_write_size << " nb_interval=" << nb_interval;
856
857 for (Int64 i = 0; i < nb_interval; ++i) {
858 auto [index, nb_element] = _getInterval(i, nb_interval, dim1_size);
859 // Sélectionne la partie de la donnée à écrire
861 dims[0] = nb_element;
862 dims[1] = dim2_size;
864 offsets[0] = hyperslab_offsets[0] + index;
865 offsets[1] = 0;
866 if ((herror = H5Sselect_hyperslab(file_space.id(), H5S_SELECT_SET, offsets.data(), nullptr, dims.data(), nullptr)) < 0)
867 ARCANE_THROW(IOException, "Can not select hyperslab '{0}' (err={1})", name, herror);
868
869 HSpace memory_space;
870 memory_space.createSimple(nb_dim, dims.data());
871 Int64 data_offset = index * values_data.datatypeSize() * dim2_size;
872 // Effectue l'écriture
873 if ((herror = dataset.write(hdf_type, values_data.data() + data_offset, memory_space, file_space, write_plist_id)) < 0)
874 ARCANE_THROW(IOException, "Can not write dataset '{0}' (err={1})", name, herror);
875
876 if (dataset.isBad())
877 ARCANE_THROW(IOException, "Can not write dataset '{0}'", name);
878 }
879
880 if (!data_info.datasetInfo().isNull())
881 m_offset_info_list.insert(std::make_pair(data_info.datasetInfo(), write_offset));
882}
883
884/*---------------------------------------------------------------------------*/
885/*---------------------------------------------------------------------------*/
886
887template <typename DataType> void VtkHdfV2DataWriter::
888_writeDataSetGeneric(const DataInfo& data_info, GatherGroupInfo* gather_info, Int32 nb_dim,
889 Int64 dim1_size, Int64 dim2_size, const DataType* values_data,
890 bool is_collective)
891{
892 const hid_t hdf_type = m_standard_types.nativeType(DataType{});
893 ConstMemoryView mem_view = makeConstMemoryView(values_data, sizeof(DataType), dim1_size * dim2_size);
894 _writeDataSetGeneric(data_info, gather_info, nb_dim, dim1_size, dim2_size, mem_view, hdf_type, is_collective);
895}
896
897/*---------------------------------------------------------------------------*/
898/*---------------------------------------------------------------------------*/
899
900template <typename DataType> void VtkHdfV2DataWriter::
901_writeDataSet1D(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
902{
903 _writeDataSetGeneric(data_info, gather_info, 1, values.size(), 1, values.data(), false);
904}
905
906/*---------------------------------------------------------------------------*/
907/*---------------------------------------------------------------------------*/
908
909template <typename DataType> void VtkHdfV2DataWriter::
910_writeDataSet1DUsingCollectiveIO(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
911{
912 _writeDataSetGeneric(data_info, gather_info, 1, values.size(), 1, values.data(), true);
913}
914
915/*---------------------------------------------------------------------------*/
916/*---------------------------------------------------------------------------*/
917
918template <typename DataType> void VtkHdfV2DataWriter::
919_writeDataSet1DCollective(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
920{
921 ARCANE_CHECK_POINTER(gather_info);
922
923 GatherGroup gg;
924
925 gather_info->computeSizeT(values);
926 gg.setGatherGroupInfo(gather_info);
927
928 if (gg.isNeedGather()) {
929 UniqueArray<DataType> all_values;
930 gg.gatherToMasterIOT(values, all_values);
931
932 if (m_is_collective_io)
933 _writeDataSet1DUsingCollectiveIO(data_info, gather_info, all_values.constSpan());
934 else
935 _writeDataSet1D(data_info, gather_info, all_values.constSpan());
936 }
937 else {
938 if (m_is_collective_io)
939 _writeDataSet1DUsingCollectiveIO(data_info, gather_info, values);
940 else
941 _writeDataSet1D(data_info, gather_info, values);
942 }
943}
944
945/*---------------------------------------------------------------------------*/
946/*---------------------------------------------------------------------------*/
947
948template <typename DataType> void VtkHdfV2DataWriter::
949_writeDataSet2D(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
950{
951 _writeDataSetGeneric(data_info, gather_info, 2, values.dim1Size(), values.dim2Size(), values.data(), false);
952}
953
954/*---------------------------------------------------------------------------*/
955/*---------------------------------------------------------------------------*/
956
957template <typename DataType> void VtkHdfV2DataWriter::
958_writeDataSet2DUsingCollectiveIO(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
959{
960 _writeDataSetGeneric(data_info, gather_info, 2, values.dim1Size(), values.dim2Size(), values.data(), true);
961}
962
963/*---------------------------------------------------------------------------*/
964/*---------------------------------------------------------------------------*/
965
966template <typename DataType> void VtkHdfV2DataWriter::
967_writeDataSet2DCollective(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
968{
969 ARCANE_CHECK_POINTER(gather_info);
970
971 GatherGroup gg;
972
973 gather_info->computeSizeT(values);
974 gg.setGatherGroupInfo(gather_info);
975
976 if (gg.isNeedGather()) {
977 UniqueArray2<DataType> all_values;
978 gg.gatherToMasterIOT(values, all_values);
979
980 if (m_is_collective_io)
981 _writeDataSet2DUsingCollectiveIO(data_info, gather_info, all_values.constSpan());
982 else
983 _writeDataSet2D(data_info, gather_info, all_values.constSpan());
984 }
985 else {
986 if (m_is_collective_io)
987 _writeDataSet2DUsingCollectiveIO(data_info, gather_info, values);
988 else
989 _writeDataSet2D(data_info, gather_info, values);
990 }
991}
992
993/*---------------------------------------------------------------------------*/
994/*---------------------------------------------------------------------------*/
995
996void VtkHdfV2DataWriter::
997_addInt64ArrayAttribute(Hid& hid, const char* name, Span<const Int64> values)
998{
999 hsize_t len = values.size();
1000 hid_t aid = H5Screate_simple(1, &len, nullptr);
1001 hid_t attr = H5Acreate2(hid.id(), name, H5T_NATIVE_INT64, aid, H5P_DEFAULT, H5P_DEFAULT);
1002 if (attr < 0)
1003 ARCANE_FATAL("Can not create attribute '{0}'", name);
1004 int ret = H5Awrite(attr, H5T_NATIVE_INT64, values.data());
1005 if (ret < 0)
1006 ARCANE_FATAL("Can not write attribute '{0}'", name);
1007 H5Aclose(attr);
1008 H5Sclose(aid);
1009}
1010
1011/*---------------------------------------------------------------------------*/
1012/*---------------------------------------------------------------------------*/
1013
1014void VtkHdfV2DataWriter::
1015_addInt64Attribute(Hid& hid, const char* name, Int64 value)
1016{
1017 HSpace aid(H5Screate(H5S_SCALAR));
1018 HAttribute attr;
1019 if (m_is_first_call)
1020 attr.create(hid, name, H5T_NATIVE_INT64, aid);
1021 else
1022 attr.open(hid, name);
1023 if (attr.isBad())
1024 ARCANE_FATAL("Can not create attribute '{0}'", name);
1025 herr_t ret = attr.write(H5T_NATIVE_INT64, &value);
1026 if (ret < 0)
1027 ARCANE_FATAL("Can not write attribute '{0}'", name);
1028}
1029
1030/*---------------------------------------------------------------------------*/
1031/*---------------------------------------------------------------------------*/
1032
1033Int64 VtkHdfV2DataWriter::
1034_readInt64Attribute(Hid& hid, const char* name)
1035{
1036 HAttribute attr;
1037 attr.open(hid, name);
1038 if (attr.isBad())
1039 ARCANE_FATAL("Can not open attribute '{0}'", name);
1040 Int64 value;
1041 herr_t ret = attr.read(H5T_NATIVE_INT64, &value);
1042 if (ret < 0)
1043 ARCANE_FATAL("Can not read attribute '{0}'", name);
1044 return value;
1045}
1046
1047/*---------------------------------------------------------------------------*/
1048/*---------------------------------------------------------------------------*/
1049
1050void VtkHdfV2DataWriter::
1051_addStringAttribute(Hid& hid, const char* name, const String& value)
1052{
1053 hid_t aid = H5Screate(H5S_SCALAR);
1054 hid_t attr_type = H5Tcopy(H5T_C_S1);
1055 H5Tset_size(attr_type, value.length());
1056 hid_t attr = H5Acreate2(hid.id(), name, attr_type, aid, H5P_DEFAULT, H5P_DEFAULT);
1057 if (attr < 0)
1058 ARCANE_FATAL("Can not create attribute {0}", name);
1059 int ret = H5Awrite(attr, attr_type, value.localstr());
1060 ret = H5Tclose(attr_type);
1061 if (ret < 0)
1062 ARCANE_FATAL("Can not write attribute '{0}'", name);
1063 H5Aclose(attr);
1064 H5Sclose(aid);
1065}
1066
1067/*---------------------------------------------------------------------------*/
1068/*---------------------------------------------------------------------------*/
1069
1070void VtkHdfV2DataWriter::
1071endWrite()
1072{
1073 // Sauvegarde les offsets enregistrés
1074
1075 if (m_is_writer) {
1076 for (const auto& i : m_offset_info_list) {
1077 Int64 offset = i.second;
1078 const DatasetInfo& offset_info = i.first;
1079 HGroup* hdf_group = offset_info.group();
1080 //info() << "OFFSET_INFO name=" << offset_info.name() << " offset=" << offset;
1081 if (hdf_group) {
1082 Ref<GatherGroupInfo> ggi = createRef<GatherGroupInfo>(m_mesh->parallelMng(), m_is_collective_io);
1083 _writeDataSet1D<Int64>({ { *hdf_group, offset_info.name() }, m_time_offset_info }, ggi.get(), asConstSpan(&offset));
1084 }
1085 }
1086 }
1087 _closeGroups();
1088 m_file_id.close();
1089}
1090
1091/*---------------------------------------------------------------------------*/
1092/*---------------------------------------------------------------------------*/
1093
1094void VtkHdfV2DataWriter::
1095_openOrCreateGroups()
1096{
1097 // Tout groupe ouvert ici doit être fermé dans closeGroups().
1098 m_top_group.openOrCreate(m_file_id, "VTKHDF");
1099 m_cell_data_group.openOrCreate(m_top_group, "CellData");
1100 m_node_data_group.openOrCreate(m_top_group, "PointData");
1101 m_steps_group.openOrCreate(m_top_group, "Steps");
1102 m_point_data_offsets_group.openOrCreate(m_steps_group, "PointDataOffsets");
1103 m_cell_data_offsets_group.openOrCreate(m_steps_group, "CellDataOffsets");
1104 m_field_data_offsets_group.openOrCreate(m_steps_group, "FieldDataOffsets");
1105}
1106
1107/*---------------------------------------------------------------------------*/
1108/*---------------------------------------------------------------------------*/
1109
1110void VtkHdfV2DataWriter::
1111_closeGroups()
1112{
1113 m_cell_data_group.close();
1114 m_node_data_group.close();
1115 m_point_data_offsets_group.close();
1116 m_cell_data_offsets_group.close();
1117 m_field_data_offsets_group.close();
1118 m_steps_group.close();
1119 m_top_group.close();
1120}
1121
1122/*---------------------------------------------------------------------------*/
1123/*---------------------------------------------------------------------------*/
1124
1126setMetaData(const String& meta_data)
1127{
1128 ARCANE_UNUSED(meta_data);
1129}
1130
1131/*---------------------------------------------------------------------------*/
1132/*---------------------------------------------------------------------------*/
1133
1135write(IVariable* var, IData* data)
1136{
1137 info(4) << "Write VtkHdfV2 var=" << var->name();
1138
1139 eItemKind item_kind = var->itemKind();
1140
1141 if (var->dimension() != 1)
1142 ARCANE_FATAL("Only export of scalar item variable is implemented (name={0})", var->name());
1143 if (var->isPartial())
1144 ARCANE_FATAL("Export of partial variable is not implemented");
1145
1146 HGroup* group = nullptr;
1147 DatasetInfo offset_info;
1148 ItemGroupCollectiveInfo* group_info = nullptr;
1149 GatherGroupInfo* gather_info = nullptr;
1150 switch (item_kind) {
1151 case IK_Cell:
1152 group = &m_cell_data_group;
1153 offset_info = m_cell_offset_info;
1154 group_info = &m_all_cells_info;
1155 gather_info = &m_all_cells_gather_group_info;
1156 break;
1157 case IK_Node:
1158 group = &m_node_data_group;
1159 offset_info = m_point_offset_info;
1160 group_info = &m_all_nodes_info;
1161 gather_info = &m_all_nodes_gather_group_info;
1162 break;
1163 default:
1164 ARCANE_FATAL("Only export of 'Cell' or 'Node' variable is implemented (name={0})", var->name());
1165 }
1166
1167 ARCANE_CHECK_POINTER(group);
1168
1169 DataInfo data_info(DatasetGroupAndName{ *group, var->name() }, offset_info, group_info);
1170 eDataType data_type = var->dataType();
1171 switch (data_type) {
1172 case DT_Real:
1173 _writeBasicTypeDataset<Real>(data_info, gather_info, data);
1174 break;
1175 case DT_Int64:
1176 _writeBasicTypeDataset<Int64>(data_info, gather_info, data);
1177 break;
1178 case DT_Int32:
1179 _writeBasicTypeDataset<Int32>(data_info, gather_info, data);
1180 break;
1181 case DT_Real3:
1182 _writeReal3Dataset(data_info, gather_info, data);
1183 break;
1184 case DT_Real2:
1185 _writeReal2Dataset(data_info, gather_info, data);
1186 break;
1187 default:
1188 warning() << String::format("Export for datatype '{0}' is not supported (var_name={1})", data_type, var->name());
1189 }
1190}
1191
1192/*---------------------------------------------------------------------------*/
1193/*---------------------------------------------------------------------------*/
1194
1195template <typename DataType> void VtkHdfV2DataWriter::
1196_writeBasicTypeDataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data)
1197{
1198 auto* true_data = dynamic_cast<IArrayDataT<DataType>*>(data);
1199 ARCANE_CHECK_POINTER(true_data);
1200 _writeDataSet1DCollective(data_info, gather_info, Span<const DataType>(true_data->view()));
1201}
1202
1203/*---------------------------------------------------------------------------*/
1204/*---------------------------------------------------------------------------*/
1205
1206void VtkHdfV2DataWriter::
1207_writeReal3Dataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data)
1208{
1209 auto* true_data = dynamic_cast<IArrayDataT<Real3>*>(data);
1210 ARCANE_CHECK_POINTER(true_data);
1211 SmallSpan<const Real3> values(true_data->view());
1212 Int32 nb_value = values.size();
1213 // TODO: optimiser cela sans passer par un tableau temporaire
1214 UniqueArray2<Real> scalar_values;
1215 scalar_values.resize(nb_value, 3);
1216 for (Int32 i = 0; i < nb_value; ++i) {
1217 Real3 v = values[i];
1218 scalar_values[i][0] = v.x;
1219 scalar_values[i][1] = v.y;
1220 scalar_values[i][2] = v.z;
1221 }
1222 _writeDataSet2DCollective<Real>(data_info, gather_info, scalar_values);
1223}
1224
1225/*---------------------------------------------------------------------------*/
1226/*---------------------------------------------------------------------------*/
1227
1228void VtkHdfV2DataWriter::
1229_writeReal2Dataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data)
1230{
1231 // Converti en un tableau de 3 composantes dont la dernière vaudra 0.
1232 auto* true_data = dynamic_cast<IArrayDataT<Real2>*>(data);
1233 ARCANE_CHECK_POINTER(true_data);
1234 SmallSpan<const Real2> values(true_data->view());
1235 Int32 nb_value = values.size();
1236 UniqueArray2<Real> scalar_values;
1237 scalar_values.resize(nb_value, 3);
1238 for (Int32 i = 0; i < nb_value; ++i) {
1239 Real2 v = values[i];
1240 scalar_values[i][0] = v.x;
1241 scalar_values[i][1] = v.y;
1242 scalar_values[i][2] = 0.0;
1243 }
1244 _writeDataSet2DCollective<Real>(data_info, gather_info, scalar_values);
1245}
1246
1247/*---------------------------------------------------------------------------*/
1248/*---------------------------------------------------------------------------*/
1249
1250void VtkHdfV2DataWriter::
1251_readAndSetOffset(DatasetInfo& offset_info, Int32 wanted_step)
1252{
1253 HGroup* hgroup = offset_info.group();
1254 ARCANE_CHECK_POINTER(hgroup);
1255 StandardArrayT<Int64> a(hgroup->id(), offset_info.name());
1256 UniqueArray<Int64> values;
1257 a.directRead(m_standard_types, values);
1258 Int64 offset_value = values[wanted_step];
1259 offset_info.setOffset(offset_value);
1260 info() << "VALUES name=" << offset_info.name() << " values=" << values
1261 << " wanted_step=" << wanted_step << " v=" << offset_value;
1262}
1263
1264/*---------------------------------------------------------------------------*/
1265/*---------------------------------------------------------------------------*/
1266
1267void VtkHdfV2DataWriter::
1268_initializeOffsets()
1269{
1270 // Il y a 5 valeurs d'offset utilisées :
1271 //
1272 // - offset sur le nombre de mailles (CellOffsets). Cet offset a pour nombre d'éléments
1273 // le nombre de temps sauvés et est augmenté à chaque sortie du nombre de mailles. Cet offset
1274 // est aussi utilisé pour les variables aux mailles
1275 // - offset sur le nombre de noeuds (PointOffsets). Il est équivalent à 'CellOffsets' mais
1276 // pour les noeuds.
1277 // - offset pour "NumberOfCells", "NumberOfPoints" et "NumberOfConnectivityIds". Pour chacun
1278 // de ces champs il y a NbPart valeurs par temps, avec 'NbPart' le nombre de parties (donc
1279 // le nombre de sous-domaines si on ne fait pas de regroupement). Il y a ainsi au total
1280 // NbPart * NbTimeStep dans ce champ d'offset.
1281 // - offset pour le champ "Connectivity" qui s'appelle "ConnectivityIdOffsets".
1282 // Cet offset a pour nombre d'éléments le nombre de temps sauvés.
1283 // - offset pour le champ "Offsets". "Offset" contient pour chaque maille l'offset dans
1284 // "Connectivity" de la connectivité des noeuds de la maille. Cet offset n'est pas sauvés,
1285 // mais comme ce champ à un nombre de valeurs égal au nombre de mailles plus un il est possible
1286 // de le déduire de "CellOffsets" (il vaut "CellOffsets" plus l'index du temps courant).
1287
1288 m_cell_offset_info = DatasetInfo(m_steps_group, "CellOffsets");
1289 m_point_offset_info = DatasetInfo(m_steps_group, "PointOffsets");
1290 m_connectivity_offset_info = DatasetInfo(m_steps_group, "ConnectivityIdOffsets");
1291 // Ces trois offsets ne sont pas sauvegardés dans le format VTK
1292 m_offset_for_cell_offset_info = DatasetInfo("_OffsetForCellOffsetInfo");
1293 m_part_offset_info = DatasetInfo("_PartOffsetInfo");
1294 m_time_offset_info = DatasetInfo("_TimeOffsetInfo");
1295
1296 // Regarde si on n'a pas fait de retour-arrière.
1297 // C'est le cas si le nombre de temps sauvés est supérieur au nombre
1298 // de valeurs de \a m_times.
1299 if (m_is_writer && !m_is_first_call) {
1300 IParallelMng* pm = m_mesh->parallelMng();
1301 const Int32 nb_rank = pm->commSize();
1302 Int64 nb_current_step = _readInt64Attribute(m_steps_group, "NSteps");
1303 Int32 time_index = m_times.size();
1304 info(4) << "NB_STEP=" << nb_current_step << " time_index=" << time_index
1305 << " current_time=" << m_times.back();
1306 const bool debug_times = false;
1307 if (debug_times) {
1308 StandardArrayT<Real> a1(m_steps_group.id(), "Values");
1309 UniqueArray<Real> times;
1310 a1.directRead(m_standard_types, times);
1311 info() << "TIMES=" << times;
1312 }
1313 if ((nb_current_step + 1) != time_index) {
1314 info() << "[VtkHdf] go_backward detected";
1315 Int32 wanted_step = time_index - 1;
1316 // Signifie qu'on a fait un retour arrière.
1317 // Dans ce cas, il faut relire les offsets
1318 _readAndSetOffset(m_cell_offset_info, wanted_step);
1319 _readAndSetOffset(m_point_offset_info, wanted_step);
1320 _readAndSetOffset(m_connectivity_offset_info, wanted_step);
1321 m_part_offset_info.setOffset(wanted_step * nb_rank);
1322 m_time_offset_info.setOffset(wanted_step);
1323 m_offset_for_cell_offset_info.setOffset(m_cell_offset_info.offset() + wanted_step * nb_rank);
1324 }
1325 }
1326}
1327
1328/*---------------------------------------------------------------------------*/
1329/*---------------------------------------------------------------------------*/
1330
1331/*---------------------------------------------------------------------------*/
1332/*---------------------------------------------------------------------------*/
1336class VtkHdfV2PostProcessor
1338{
1339 public:
1340
1341 explicit VtkHdfV2PostProcessor(const ServiceBuildInfo& sbi)
1343 {
1344 }
1345
1346 IDataWriter* dataWriter() override { return m_writer.get(); }
1347 void notifyBeginWrite() override
1348 {
1349 bool use_collective_io = true;
1350 Int64 max_write_size = 0;
1351 if (options()) {
1352 use_collective_io = options()->useCollectiveWrite();
1353 max_write_size = options()->maxWriteSize();
1354 }
1355 auto w = std::make_unique<VtkHdfV2DataWriter>(mesh(), groups(), use_collective_io);
1356 w->setMaxWriteSize(max_write_size);
1357 w->setTimes(times());
1359 w->setDirectoryName(dir.file("vtkhdfv2"));
1360 m_writer = std::move(w);
1361 }
1362 void notifyEndWrite() override
1363 {
1364 m_writer = nullptr;
1365 }
1366 void close() override {}
1367
1368 private:
1369
1370 std::unique_ptr<IDataWriter> m_writer;
1371};
1372
1373/*---------------------------------------------------------------------------*/
1374/*---------------------------------------------------------------------------*/
1375
1376ARCANE_REGISTER_SERVICE_VTKHDFV2POSTPROCESSOR(VtkHdfV2PostProcessor,
1377 VtkHdfV2PostProcessor);
1378
1379/*---------------------------------------------------------------------------*/
1380/*---------------------------------------------------------------------------*/
1381
1382} // namespace Arcane
1383
1384/*---------------------------------------------------------------------------*/
1385/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_(type, name, group)
Enumérateur générique d'un groupe d'entité
#define ENUMERATE_CELL(name, group)
Enumérateur générique d'un groupe de mailles.
CaseOptionsVtkHdfV2PostProcessor * options() const
Options du jeu de données du service.
ArcaneVtkHdfV2PostProcessorObject(const Arcane::ServiceBuildInfo &sbi)
Constructeur.
Vue modifiable d'un tableau d'un type T.
Vue constante d'un tableau de type T.
Vue constante sur une zone mémoire contigue contenant des éléments de taille fixe.
constexpr Int32 datatypeSize() const
Taille du type de donnée associé (1 par défaut)
constexpr const std::byte * data() const
Pointeur sur la zone mémoire.
Classe gérant un répertoire.
Definition Directory.h:35
String file(const String &file_name) const override
Retourne le chemin complet du fichier file_name dans le répertoire.
Definition Directory.cc:120
Classe permettant de calculer et de conserver les informations de regroupements.
void computeSize(Int32 nb_elem_in) override
Méthode permettant de calculer les informations de regroupements.
Int32 nbWriterGlobal() override
Méthode pemettant de connaitre le nombre de sous-domaines écrivains.
Int32 nbElemOutput() override
Méthode permettant de connaitre le nombre d'éléments que notre sous-domaine devra traiter après récep...
Encapsule un hid_t pour un dataset.
Encapsule un hid_t pour un fichier.
Encapsule un hid_t pour un groupe.
static void useMutex(bool is_active, IParallelMng *pm)
Fonction permettant d'activer ou de désactiver les verrous à chaque appel à HDF5.
Definition Hdf5Utils.cc:90
static constexpr bool hasParallelHdf5()
Vrai HDF5 est compilé avec le support de MPI.
Encapsule un hid_t pour une propriété (H5P*).
void createDatasetTransfertCollectiveMPIIO()
Créé une propriété de dataset pour MPIIO.
Definition Hdf5Utils.cc:898
void createDatasetTransfertIndependentMPIIO()
Créé une propriété de dataset pour MPIIO.
Definition Hdf5Utils.cc:917
Encapsule un hid_t pour un dataspace.
Encapsule un hid_t.
Définition des types standards Arcane pour hdf5.
Interface d'une donnée tableau d'un type T.
Definition IData.h:292
Interface d'écriture des données d'une variable.
Definition IDataWriter.h:44
Interface d'une donnée.
Definition IData.h:33
Exception lorsqu'une erreur d'entrée/sortie est détectée.
Definition IOException.h:32
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual void allGather(ConstArrayView< char > send_buf, ArrayView< char > recv_buf)=0
Effectue un regroupement sur tous les processeurs. Il s'agit d'une opération collective....
Interface d'une variable.
Definition IVariable.h:39
virtual eDataType dataType() const =0
Type de la donnée gérée par la variable (Real, Integer, ...)
virtual eItemKind itemKind() const =0
Genre des entités du maillage sur lequel repose la variable.
virtual bool isPartial() const =0
Indique si la variable est partielle.
virtual Integer dimension() const =0
Dimension de la variable.
virtual String name() const =0
Nom de la variable.
Groupe d'entités de maillage.
Definition ItemGroup.h:49
Interface du gestionnaire des matériaux et des milieux d'un maillage.
static IMeshMaterialMng * getReference(const MeshHandleOrMesh &mesh_handle, bool create=true)
Récupère ou créé la référence associée à mesh.
ItemGroupCollection groups() override
Liste des groupes à sauver.
ConstArrayView< Real > times() override
Liste des temps sauvés.
const String & baseDirectoryName() override
Nom du répertoire de sortie des fichiers.
Structure contenant les informations pour créer un service.
Vue pour un tableau 2D dont la taille est un 'Int64'.
Definition Span2.h:301
Vue d'un tableau d'éléments de type T.
Definition Span.h:633
Constructeur de chaîne de caractère unicode.
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:228
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage warning() const
Flot pour un message d'avertissement.
Vecteur 1D de données avec sémantique par valeur (style STL).
Collection de variables.
void write(IVariable *var, IData *data) override
Ecrit les données data de la variable var.
IMeshMaterialMng * m_material_mng
Gestionnaire de matériaux associé (peut-être nul)
Int64 m_max_write_size
Taille maximale (en kilo-octet) pour une écriture.
String m_directory_name
Répertoire de sortie.
WritePartInfo _computeWritePartInfo(Int64 local_size)
Calcule l'offset de notre partie et le nombre total d'éléments.
IMesh * m_mesh
Maillage associé
HFile m_file_id
Identifiant HDF du fichier.
ItemGroupCollection m_groups
Liste des groupes à sauver.
UniqueArray< Real > m_times
Liste des temps.
void setMetaData(const String &meta_data) override
Positionne les infos des méta-données.
String m_full_filename
Nom du fichier HDF courant.
IDataWriter * dataWriter() override
Retourne l'écrivain associé à ce post-processeur.
void close() override
Ferme l'écrivain. Après fermeture, il ne peut plus être utilisé
void notifyBeginWrite() override
Notifie qu'une sortie va être effectuée avec les paramètres courants.
void notifyEndWrite() override
Notifie qu'une sortie vient d'être effectuée.
__host__ __device__ Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
Definition MathUtils.h:336
ItemGroupT< Cell > CellGroup
Groupe de mailles.
Definition ItemTypes.h:183
ItemGroupT< Node > NodeGroup
Groupe de noeuds.
Definition ItemTypes.h:167
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
Integer len(const char *s)
Retourne la longueur de la chaîne s.
Fonctions utilitaires pour Hdf5.
Definition Hdf5Utils.cc:34
Active toujours les traces dans les parties Arcane concernant les matériaux.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Ref< TrueType > createRef(Args &&... args)
Créé une instance de type TrueType avec les arguments Args et retourne une référence dessus.
Collection< ItemGroup > ItemGroupCollection
Collection de groupes d'éléments du maillage.
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
bool operator<(const Item &item1, const Item &item2)
Compare deux entités.
Definition Item.h:551
ConstMemoryView makeConstMemoryView(const void *ptr, Int32 datatype_size, Int64 nb_element)
Créé une vue mémoire en lecture seule.
Definition MemoryView.cc:36
eItemKind
Genre d'entité de maillage.
@ IK_Node
Entité de maillage de genre noeud.
@ IK_Cell
Entité de maillage de genre maille.
double Real
Type représentant un réel.
unsigned char Byte
Type d'un octet.
Definition BaseTypes.h:43
eDataType
Type d'une donnée.
Definition DataTypes.h:39
@ DT_Int32
Donnée de type entier 32 bits.
Definition DataTypes.h:43
@ DT_Real3
Donnée de type vecteur 3.
Definition DataTypes.h:47
@ DT_Int64
Donnée de type entier 64 bits.
Definition DataTypes.h:44
@ DT_Real2
Donnée de type vecteur 2.
Definition DataTypes.h:46
@ DT_Real
Donnée de type réel.
Definition DataTypes.h:41
@ Cell
Le maillage est AMR par maille.
Definition MeshKind.h:52
std::int32_t Int32
Type entier signé sur 32 bits.
ConstArrayView< Real > RealConstArrayView
Equivalent C d'un tableau à une dimension de réels.
Definition UtilsTypes.h:488
Conserve les infos sur les données à sauver et l'offset associé.
Classe pour conserver un couple (hdf_group,nom_du_dataset).
Classe pour conserver les information d'un offset.
Int64 offset() const
Valeur de l'offset. (-1) si on écrit à la fin du tableau.
Informations collectives sur un ItemGroup;.
WritePartInfo m_write_part_info
Informations sur l'écriture.
Informations sur l'offset de la partie à écrire associée à un rang.
Int64 m_size
Nombre d'éléments de mon rang.
Int64 m_total_size
Nombre d'éléments sur tous les rangs.