Arcane  v4.1.10.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 (is_collective)
774
775 HSpace file_space;
776 FixedArray<hsize_t, MAX_DIM> hyperslab_offsets;
777
778 if (m_is_first_call) {
779 // TODO: regarder comment mieux calculer le chunk
781 global_dims[0] = global_dim1_size;
782 global_dims[1] = dim2_size;
783 // Il est important que tout le monde ait la même taille de chunk.
784 Int64 chunk_size = global_dim1_size / nb_participating_rank;
785 if (chunk_size < 1024)
786 chunk_size = 1024;
787 const Int64 max_chunk_size = 1024 * 1024 * 10;
788 chunk_size = math::min(chunk_size, max_chunk_size);
789 chunk_dims[0] = chunk_size;
790 chunk_dims[1] = dim2_size;
791 info() << "CHUNK nb_dim=" << nb_dim
792 << " global_dim1_size=" << global_dim1_size
793 << " chunk0=" << chunk_dims[0]
794 << " chunk1=" << chunk_dims[1]
795 << " name=" << name;
796 file_space.createSimple(nb_dim, global_dims.data(), max_dims.data());
797 HProperty plist_id;
798 plist_id.create(H5P_DATASET_CREATE);
799 H5Pset_chunk(plist_id.id(), nb_dim, chunk_dims.data());
800 dataset.create(group, name.localstr(), hdf_type, file_space, HProperty{}, plist_id, HProperty{});
801
802 if (is_collective) {
803 hyperslab_offsets[0] = my_index;
804 hyperslab_offsets[1] = 0;
805 }
806 }
807 else {
808 // Agrandit la première dimension du dataset.
809 // On va ajouter 'global_dim1_size' à cette dimension.
810 dataset.open(group, name.localstr());
811 file_space = dataset.getSpace();
812 int nb_dimension = file_space.nbDimension();
813 if (nb_dimension != nb_dim)
814 ARCANE_THROW(IOException, "Bad dimension '{0}' for dataset '{1}' (should be 1)",
815 nb_dimension, name);
816 // TODO: Vérifier que la deuxième dimension est la même que celle sauvée.
817 FixedArray<hsize_t, MAX_DIM> original_dims;
818 file_space.getDimensions(original_dims.data(), nullptr);
819 hsize_t offset0 = original_dims[0];
820 // Si on a un offset positif issu de DatasetInfo alors on le prend.
821 // Cela signifie qu'on a fait un retour arrière.
822 if (wanted_offset >= 0) {
823 offset0 = wanted_offset;
824 info() << "Forcing offset to " << wanted_offset;
825 }
826 global_dims[0] = offset0 + global_dim1_size;
827 global_dims[1] = dim2_size;
828 write_offset = offset0;
829 // Agrandit le dataset.
830 // ATTENTION cela invalide file_space. Il faut donc le relire juste après.
831 if ((herror = dataset.setExtent(global_dims.data())) < 0)
832 ARCANE_THROW(IOException, "Can not extent dataset '{0}' (err={1})", name, herror);
833 file_space = dataset.getSpace();
834
835 hyperslab_offsets[0] = offset0 + my_index;
836 hyperslab_offsets[1] = 0;
837 info(4) << "APPEND nb_dim=" << nb_dim
838 << " dim0=" << global_dims[0]
839 << " count0=" << local_dims[0]
840 << " offsets0=" << hyperslab_offsets[0] << " name=" << name;
841 }
842
843 Int64 nb_write_byte = global_dim1_size * dim2_size * values_data.datatypeSize();
844
845 // Effectue l'écriture en plusieurs parties si demandé.
846 // Cela n'est possible que pour l'écriture collective.
847 Int64 nb_interval = 1;
848 if (is_collective && m_max_write_size > 0) {
849 nb_interval = 1 + nb_write_byte / (m_max_write_size * 1024);
850 }
851 info(4) << "WRITE global_size=" << nb_write_byte << " max_size=" << m_max_write_size << " nb_interval=" << nb_interval;
852
853 for (Int64 i = 0; i < nb_interval; ++i) {
854 auto [index, nb_element] = _getInterval(i, nb_interval, dim1_size);
855 // Sélectionne la partie de la donnée à écrire
857 dims[0] = nb_element;
858 dims[1] = dim2_size;
860 offsets[0] = hyperslab_offsets[0] + index;
861 offsets[1] = 0;
862 if ((herror = H5Sselect_hyperslab(file_space.id(), H5S_SELECT_SET, offsets.data(), nullptr, dims.data(), nullptr)) < 0)
863 ARCANE_THROW(IOException, "Can not select hyperslab '{0}' (err={1})", name, herror);
864
865 HSpace memory_space;
866 memory_space.createSimple(nb_dim, dims.data());
867 Int64 data_offset = index * values_data.datatypeSize() * dim2_size;
868 // Effectue l'écriture
869 if ((herror = dataset.write(hdf_type, values_data.data() + data_offset, memory_space, file_space, write_plist_id)) < 0)
870 ARCANE_THROW(IOException, "Can not write dataset '{0}' (err={1})", name, herror);
871
872 if (dataset.isBad())
873 ARCANE_THROW(IOException, "Can not write dataset '{0}'", name);
874 }
875
876 if (!data_info.datasetInfo().isNull())
877 m_offset_info_list.insert(std::make_pair(data_info.datasetInfo(), write_offset));
878}
879
880/*---------------------------------------------------------------------------*/
881/*---------------------------------------------------------------------------*/
882
883template <typename DataType> void VtkHdfV2DataWriter::
884_writeDataSetGeneric(const DataInfo& data_info, GatherGroupInfo* gather_info, Int32 nb_dim,
885 Int64 dim1_size, Int64 dim2_size, const DataType* values_data,
886 bool is_collective)
887{
888 const hid_t hdf_type = m_standard_types.nativeType(DataType{});
889 ConstMemoryView mem_view = makeConstMemoryView(values_data, sizeof(DataType), dim1_size * dim2_size);
890 _writeDataSetGeneric(data_info, gather_info, nb_dim, dim1_size, dim2_size, mem_view, hdf_type, is_collective);
891}
892
893/*---------------------------------------------------------------------------*/
894/*---------------------------------------------------------------------------*/
895
896template <typename DataType> void VtkHdfV2DataWriter::
897_writeDataSet1D(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
898{
899 _writeDataSetGeneric(data_info, gather_info, 1, values.size(), 1, values.data(), false);
900}
901
902/*---------------------------------------------------------------------------*/
903/*---------------------------------------------------------------------------*/
904
905template <typename DataType> void VtkHdfV2DataWriter::
906_writeDataSet1DUsingCollectiveIO(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
907{
908 _writeDataSetGeneric(data_info, gather_info, 1, values.size(), 1, values.data(), true);
909}
910
911/*---------------------------------------------------------------------------*/
912/*---------------------------------------------------------------------------*/
913
914template <typename DataType> void VtkHdfV2DataWriter::
915_writeDataSet1DCollective(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
916{
917 ARCANE_CHECK_POINTER(gather_info);
918
919 GatherGroup gg;
920
921 gather_info->computeSizeT(values);
922 gg.setGatherGroupInfo(gather_info);
923
924 if (gg.isNeedGather()) {
925 UniqueArray<DataType> all_values;
926 gg.gatherToMasterIOT(values, all_values);
927
928 if (m_is_collective_io)
929 _writeDataSet1DUsingCollectiveIO(data_info, gather_info, all_values.constSpan());
930 else
931 _writeDataSet1D(data_info, gather_info, all_values.constSpan());
932 }
933 else {
934 if (m_is_collective_io)
935 _writeDataSet1DUsingCollectiveIO(data_info, gather_info, values);
936 else
937 _writeDataSet1D(data_info, gather_info, values);
938 }
939}
940
941/*---------------------------------------------------------------------------*/
942/*---------------------------------------------------------------------------*/
943
944template <typename DataType> void VtkHdfV2DataWriter::
945_writeDataSet2D(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
946{
947 _writeDataSetGeneric(data_info, gather_info, 2, values.dim1Size(), values.dim2Size(), values.data(), false);
948}
949
950/*---------------------------------------------------------------------------*/
951/*---------------------------------------------------------------------------*/
952
953template <typename DataType> void VtkHdfV2DataWriter::
954_writeDataSet2DUsingCollectiveIO(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
955{
956 _writeDataSetGeneric(data_info, gather_info, 2, values.dim1Size(), values.dim2Size(), values.data(), true);
957}
958
959/*---------------------------------------------------------------------------*/
960/*---------------------------------------------------------------------------*/
961
962template <typename DataType> void VtkHdfV2DataWriter::
963_writeDataSet2DCollective(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
964{
965 ARCANE_CHECK_POINTER(gather_info);
966
967 GatherGroup gg;
968
969 gather_info->computeSizeT(values);
970 gg.setGatherGroupInfo(gather_info);
971
972 if (gg.isNeedGather()) {
973 UniqueArray2<DataType> all_values;
974 gg.gatherToMasterIOT(values, all_values);
975
976 if (m_is_collective_io)
977 _writeDataSet2DUsingCollectiveIO(data_info, gather_info, all_values.constSpan());
978 else
979 _writeDataSet2D(data_info, gather_info, all_values.constSpan());
980 }
981 else {
982 if (m_is_collective_io)
983 _writeDataSet2DUsingCollectiveIO(data_info, gather_info, values);
984 else
985 _writeDataSet2D(data_info, gather_info, values);
986 }
987}
988
989/*---------------------------------------------------------------------------*/
990/*---------------------------------------------------------------------------*/
991
992void VtkHdfV2DataWriter::
993_addInt64ArrayAttribute(Hid& hid, const char* name, Span<const Int64> values)
994{
995 hsize_t len = values.size();
996 hid_t aid = H5Screate_simple(1, &len, nullptr);
997 hid_t attr = H5Acreate2(hid.id(), name, H5T_NATIVE_INT64, aid, H5P_DEFAULT, H5P_DEFAULT);
998 if (attr < 0)
999 ARCANE_FATAL("Can not create attribute '{0}'", name);
1000 int ret = H5Awrite(attr, H5T_NATIVE_INT64, values.data());
1001 if (ret < 0)
1002 ARCANE_FATAL("Can not write attribute '{0}'", name);
1003 H5Aclose(attr);
1004 H5Sclose(aid);
1005}
1006
1007/*---------------------------------------------------------------------------*/
1008/*---------------------------------------------------------------------------*/
1009
1010void VtkHdfV2DataWriter::
1011_addInt64Attribute(Hid& hid, const char* name, Int64 value)
1012{
1013 HSpace aid(H5Screate(H5S_SCALAR));
1014 HAttribute attr;
1015 if (m_is_first_call)
1016 attr.create(hid, name, H5T_NATIVE_INT64, aid);
1017 else
1018 attr.open(hid, name);
1019 if (attr.isBad())
1020 ARCANE_FATAL("Can not create attribute '{0}'", name);
1021 herr_t ret = attr.write(H5T_NATIVE_INT64, &value);
1022 if (ret < 0)
1023 ARCANE_FATAL("Can not write attribute '{0}'", name);
1024}
1025
1026/*---------------------------------------------------------------------------*/
1027/*---------------------------------------------------------------------------*/
1028
1029Int64 VtkHdfV2DataWriter::
1030_readInt64Attribute(Hid& hid, const char* name)
1031{
1032 HAttribute attr;
1033 attr.open(hid, name);
1034 if (attr.isBad())
1035 ARCANE_FATAL("Can not open attribute '{0}'", name);
1036 Int64 value;
1037 herr_t ret = attr.read(H5T_NATIVE_INT64, &value);
1038 if (ret < 0)
1039 ARCANE_FATAL("Can not read attribute '{0}'", name);
1040 return value;
1041}
1042
1043/*---------------------------------------------------------------------------*/
1044/*---------------------------------------------------------------------------*/
1045
1046void VtkHdfV2DataWriter::
1047_addStringAttribute(Hid& hid, const char* name, const String& value)
1048{
1049 hid_t aid = H5Screate(H5S_SCALAR);
1050 hid_t attr_type = H5Tcopy(H5T_C_S1);
1051 H5Tset_size(attr_type, value.length());
1052 hid_t attr = H5Acreate2(hid.id(), name, attr_type, aid, H5P_DEFAULT, H5P_DEFAULT);
1053 if (attr < 0)
1054 ARCANE_FATAL("Can not create attribute {0}", name);
1055 int ret = H5Awrite(attr, attr_type, value.localstr());
1056 ret = H5Tclose(attr_type);
1057 if (ret < 0)
1058 ARCANE_FATAL("Can not write attribute '{0}'", name);
1059 H5Aclose(attr);
1060 H5Sclose(aid);
1061}
1062
1063/*---------------------------------------------------------------------------*/
1064/*---------------------------------------------------------------------------*/
1065
1066void VtkHdfV2DataWriter::
1067endWrite()
1068{
1069 // Sauvegarde les offsets enregistrés
1070
1071 if (m_is_writer) {
1072 for (const auto& i : m_offset_info_list) {
1073 Int64 offset = i.second;
1074 const DatasetInfo& offset_info = i.first;
1075 HGroup* hdf_group = offset_info.group();
1076 //info() << "OFFSET_INFO name=" << offset_info.name() << " offset=" << offset;
1077 if (hdf_group) {
1078 Ref<GatherGroupInfo> ggi = createRef<GatherGroupInfo>(m_mesh->parallelMng(), m_is_collective_io);
1079 _writeDataSet1D<Int64>({ { *hdf_group, offset_info.name() }, m_time_offset_info }, ggi.get(), asConstSpan(&offset));
1080 }
1081 }
1082 }
1083 _closeGroups();
1084 m_file_id.close();
1085}
1086
1087/*---------------------------------------------------------------------------*/
1088/*---------------------------------------------------------------------------*/
1089
1090void VtkHdfV2DataWriter::
1091_openOrCreateGroups()
1092{
1093 // Tout groupe ouvert ici doit être fermé dans closeGroups().
1094 m_top_group.openOrCreate(m_file_id, "VTKHDF");
1095 m_cell_data_group.openOrCreate(m_top_group, "CellData");
1096 m_node_data_group.openOrCreate(m_top_group, "PointData");
1097 m_steps_group.openOrCreate(m_top_group, "Steps");
1098 m_point_data_offsets_group.openOrCreate(m_steps_group, "PointDataOffsets");
1099 m_cell_data_offsets_group.openOrCreate(m_steps_group, "CellDataOffsets");
1100 m_field_data_offsets_group.openOrCreate(m_steps_group, "FieldDataOffsets");
1101}
1102
1103/*---------------------------------------------------------------------------*/
1104/*---------------------------------------------------------------------------*/
1105
1106void VtkHdfV2DataWriter::
1107_closeGroups()
1108{
1109 m_cell_data_group.close();
1110 m_node_data_group.close();
1111 m_point_data_offsets_group.close();
1112 m_cell_data_offsets_group.close();
1113 m_field_data_offsets_group.close();
1114 m_steps_group.close();
1115 m_top_group.close();
1116}
1117
1118/*---------------------------------------------------------------------------*/
1119/*---------------------------------------------------------------------------*/
1120
1122setMetaData(const String& meta_data)
1123{
1124 ARCANE_UNUSED(meta_data);
1125}
1126
1127/*---------------------------------------------------------------------------*/
1128/*---------------------------------------------------------------------------*/
1129
1131write(IVariable* var, IData* data)
1132{
1133 info(4) << "Write VtkHdfV2 var=" << var->name();
1134
1135 eItemKind item_kind = var->itemKind();
1136
1137 if (var->dimension() != 1)
1138 ARCANE_FATAL("Only export of scalar item variable is implemented (name={0})", var->name());
1139 if (var->isPartial())
1140 ARCANE_FATAL("Export of partial variable is not implemented");
1141
1142 HGroup* group = nullptr;
1143 DatasetInfo offset_info;
1144 ItemGroupCollectiveInfo* group_info = nullptr;
1145 GatherGroupInfo* gather_info = nullptr;
1146 switch (item_kind) {
1147 case IK_Cell:
1148 group = &m_cell_data_group;
1149 offset_info = m_cell_offset_info;
1150 group_info = &m_all_cells_info;
1151 gather_info = &m_all_cells_gather_group_info;
1152 break;
1153 case IK_Node:
1154 group = &m_node_data_group;
1155 offset_info = m_point_offset_info;
1156 group_info = &m_all_nodes_info;
1157 gather_info = &m_all_nodes_gather_group_info;
1158 break;
1159 default:
1160 ARCANE_FATAL("Only export of 'Cell' or 'Node' variable is implemented (name={0})", var->name());
1161 }
1162
1163 ARCANE_CHECK_POINTER(group);
1164
1165 DataInfo data_info(DatasetGroupAndName{ *group, var->name() }, offset_info, group_info);
1166 eDataType data_type = var->dataType();
1167 switch (data_type) {
1168 case DT_Real:
1169 _writeBasicTypeDataset<Real>(data_info, gather_info, data);
1170 break;
1171 case DT_Int64:
1172 _writeBasicTypeDataset<Int64>(data_info, gather_info, data);
1173 break;
1174 case DT_Int32:
1175 _writeBasicTypeDataset<Int32>(data_info, gather_info, data);
1176 break;
1177 case DT_Real3:
1178 _writeReal3Dataset(data_info, gather_info, data);
1179 break;
1180 case DT_Real2:
1181 _writeReal2Dataset(data_info, gather_info, data);
1182 break;
1183 default:
1184 warning() << String::format("Export for datatype '{0}' is not supported (var_name={1})", data_type, var->name());
1185 }
1186}
1187
1188/*---------------------------------------------------------------------------*/
1189/*---------------------------------------------------------------------------*/
1190
1191template <typename DataType> void VtkHdfV2DataWriter::
1192_writeBasicTypeDataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data)
1193{
1194 auto* true_data = dynamic_cast<IArrayDataT<DataType>*>(data);
1195 ARCANE_CHECK_POINTER(true_data);
1196 _writeDataSet1DCollective(data_info, gather_info, Span<const DataType>(true_data->view()));
1197}
1198
1199/*---------------------------------------------------------------------------*/
1200/*---------------------------------------------------------------------------*/
1201
1202void VtkHdfV2DataWriter::
1203_writeReal3Dataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data)
1204{
1205 auto* true_data = dynamic_cast<IArrayDataT<Real3>*>(data);
1206 ARCANE_CHECK_POINTER(true_data);
1207 SmallSpan<const Real3> values(true_data->view());
1208 Int32 nb_value = values.size();
1209 // TODO: optimiser cela sans passer par un tableau temporaire
1210 UniqueArray2<Real> scalar_values;
1211 scalar_values.resize(nb_value, 3);
1212 for (Int32 i = 0; i < nb_value; ++i) {
1213 Real3 v = values[i];
1214 scalar_values[i][0] = v.x;
1215 scalar_values[i][1] = v.y;
1216 scalar_values[i][2] = v.z;
1217 }
1218 _writeDataSet2DCollective<Real>(data_info, gather_info, scalar_values);
1219}
1220
1221/*---------------------------------------------------------------------------*/
1222/*---------------------------------------------------------------------------*/
1223
1224void VtkHdfV2DataWriter::
1225_writeReal2Dataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data)
1226{
1227 // Converti en un tableau de 3 composantes dont la dernière vaudra 0.
1228 auto* true_data = dynamic_cast<IArrayDataT<Real2>*>(data);
1229 ARCANE_CHECK_POINTER(true_data);
1230 SmallSpan<const Real2> values(true_data->view());
1231 Int32 nb_value = values.size();
1232 UniqueArray2<Real> scalar_values;
1233 scalar_values.resize(nb_value, 3);
1234 for (Int32 i = 0; i < nb_value; ++i) {
1235 Real2 v = values[i];
1236 scalar_values[i][0] = v.x;
1237 scalar_values[i][1] = v.y;
1238 scalar_values[i][2] = 0.0;
1239 }
1240 _writeDataSet2DCollective<Real>(data_info, gather_info, scalar_values);
1241}
1242
1243/*---------------------------------------------------------------------------*/
1244/*---------------------------------------------------------------------------*/
1245
1246void VtkHdfV2DataWriter::
1247_readAndSetOffset(DatasetInfo& offset_info, Int32 wanted_step)
1248{
1249 HGroup* hgroup = offset_info.group();
1250 ARCANE_CHECK_POINTER(hgroup);
1251 StandardArrayT<Int64> a(hgroup->id(), offset_info.name());
1252 UniqueArray<Int64> values;
1253 a.directRead(m_standard_types, values);
1254 Int64 offset_value = values[wanted_step];
1255 offset_info.setOffset(offset_value);
1256 info() << "VALUES name=" << offset_info.name() << " values=" << values
1257 << " wanted_step=" << wanted_step << " v=" << offset_value;
1258}
1259
1260/*---------------------------------------------------------------------------*/
1261/*---------------------------------------------------------------------------*/
1262
1263void VtkHdfV2DataWriter::
1264_initializeOffsets()
1265{
1266 // Il y a 5 valeurs d'offset utilisées :
1267 //
1268 // - offset sur le nombre de mailles (CellOffsets). Cet offset a pour nombre d'éléments
1269 // le nombre de temps sauvés et est augmenté à chaque sortie du nombre de mailles. Cet offset
1270 // est aussi utilisé pour les variables aux mailles
1271 // - offset sur le nombre de noeuds (PointOffsets). Il est équivalent à 'CellOffsets' mais
1272 // pour les noeuds.
1273 // - offset pour "NumberOfCells", "NumberOfPoints" et "NumberOfConnectivityIds". Pour chacun
1274 // de ces champs il y a NbPart valeurs par temps, avec 'NbPart' le nombre de parties (donc
1275 // le nombre de sous-domaines si on ne fait pas de regroupement). Il y a ainsi au total
1276 // NbPart * NbTimeStep dans ce champ d'offset.
1277 // - offset pour le champ "Connectivity" qui s'appelle "ConnectivityIdOffsets".
1278 // Cet offset a pour nombre d'éléments le nombre de temps sauvés.
1279 // - offset pour le champ "Offsets". "Offset" contient pour chaque maille l'offset dans
1280 // "Connectivity" de la connectivité des noeuds de la maille. Cet offset n'est pas sauvés,
1281 // mais comme ce champ à un nombre de valeurs égal au nombre de mailles plus un il est possible
1282 // de le déduire de "CellOffsets" (il vaut "CellOffsets" plus l'index du temps courant).
1283
1284 m_cell_offset_info = DatasetInfo(m_steps_group, "CellOffsets");
1285 m_point_offset_info = DatasetInfo(m_steps_group, "PointOffsets");
1286 m_connectivity_offset_info = DatasetInfo(m_steps_group, "ConnectivityIdOffsets");
1287 // Ces trois offsets ne sont pas sauvegardés dans le format VTK
1288 m_offset_for_cell_offset_info = DatasetInfo("_OffsetForCellOffsetInfo");
1289 m_part_offset_info = DatasetInfo("_PartOffsetInfo");
1290 m_time_offset_info = DatasetInfo("_TimeOffsetInfo");
1291
1292 // Regarde si on n'a pas fait de retour-arrière.
1293 // C'est le cas si le nombre de temps sauvés est supérieur au nombre
1294 // de valeurs de \a m_times.
1295 if (m_is_writer && !m_is_first_call) {
1296 IParallelMng* pm = m_mesh->parallelMng();
1297 const Int32 nb_rank = pm->commSize();
1298 Int64 nb_current_step = _readInt64Attribute(m_steps_group, "NSteps");
1299 Int32 time_index = m_times.size();
1300 info(4) << "NB_STEP=" << nb_current_step << " time_index=" << time_index
1301 << " current_time=" << m_times.back();
1302 const bool debug_times = false;
1303 if (debug_times) {
1304 StandardArrayT<Real> a1(m_steps_group.id(), "Values");
1305 UniqueArray<Real> times;
1306 a1.directRead(m_standard_types, times);
1307 info() << "TIMES=" << times;
1308 }
1309 if ((nb_current_step + 1) != time_index) {
1310 info() << "[VtkHdf] go_backward detected";
1311 Int32 wanted_step = time_index - 1;
1312 // Signifie qu'on a fait un retour arrière.
1313 // Dans ce cas, il faut relire les offsets
1314 _readAndSetOffset(m_cell_offset_info, wanted_step);
1315 _readAndSetOffset(m_point_offset_info, wanted_step);
1316 _readAndSetOffset(m_connectivity_offset_info, wanted_step);
1317 m_part_offset_info.setOffset(wanted_step * nb_rank);
1318 m_time_offset_info.setOffset(wanted_step);
1319 m_offset_for_cell_offset_info.setOffset(m_cell_offset_info.offset() + wanted_step * nb_rank);
1320 }
1321 }
1322}
1323
1324/*---------------------------------------------------------------------------*/
1325/*---------------------------------------------------------------------------*/
1326
1327/*---------------------------------------------------------------------------*/
1328/*---------------------------------------------------------------------------*/
1332class VtkHdfV2PostProcessor
1334{
1335 public:
1336
1337 explicit VtkHdfV2PostProcessor(const ServiceBuildInfo& sbi)
1339 {
1340 }
1341
1342 IDataWriter* dataWriter() override { return m_writer.get(); }
1343 void notifyBeginWrite() override
1344 {
1345 bool use_collective_io = true;
1346 Int64 max_write_size = 0;
1347 if (options()) {
1348 use_collective_io = options()->useCollectiveWrite();
1349 max_write_size = options()->maxWriteSize();
1350 }
1351 auto w = std::make_unique<VtkHdfV2DataWriter>(mesh(), groups(), use_collective_io);
1352 w->setMaxWriteSize(max_write_size);
1353 w->setTimes(times());
1355 w->setDirectoryName(dir.file("vtkhdfv2"));
1356 m_writer = std::move(w);
1357 }
1358 void notifyEndWrite() override
1359 {
1360 m_writer = nullptr;
1361 }
1362 void close() override {}
1363
1364 private:
1365
1366 std::unique_ptr<IDataWriter> m_writer;
1367};
1368
1369/*---------------------------------------------------------------------------*/
1370/*---------------------------------------------------------------------------*/
1371
1372ARCANE_REGISTER_SERVICE_VTKHDFV2POSTPROCESSOR(VtkHdfV2PostProcessor,
1373 VtkHdfV2PostProcessor);
1374
1375/*---------------------------------------------------------------------------*/
1376/*---------------------------------------------------------------------------*/
1377
1378} // namespace Arcane
1379
1380/*---------------------------------------------------------------------------*/
1381/*---------------------------------------------------------------------------*/
#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:103
static bool hasParallelHdf5()
Vrai HDF5 est compilé avec le support de MPI.
Definition Hdf5Utils.cc:90
Encapsule un hid_t pour une propriété (H5P*).
void createDatasetTransfertCollectiveMPIIO()
Créé une propriété de dataset pour MPIIO.
Definition Hdf5Utils.cc:911
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.
ConstMemoryView makeConstMemoryView(const void *ptr, Int32 datatype_size, Int64 nb_element)
Créé une vue mémoire en lecture seule.
Definition MemoryView.cc:36
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
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.