Arcane  4.2.3.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/MeshKind.h"
29#include "arcane/core/VariableCollection.h"
30#include "arcane/core/IParallelMng.h"
31#include "arcane/core/IMesh.h"
32#include "arcane/core/internal/IParallelMngInternal.h"
33#include "arcane/core/internal/VtkCellTypes.h"
34#include "arcane/core/internal/GatherGroup.h"
35
36#include "arcane/core/materials/IMeshMaterialMng.h"
37#include "arcane/core/materials/IMeshEnvironment.h"
38
39#include "arcane/hdf5/Hdf5Utils.h"
40#include "arcane/hdf5/VtkHdfV2PostProcessor_axl.h"
41
42#include <map>
43
44// Ce format est décrit sur la page web suivante :
45//
46// https://kitware.github.io/vtk-examples/site/VTKFileFormats/#hdf-file-formats
47//
48// Le format 2.0 avec le support intégré de l'évolution temporelle n'est
49// disponible que dans la branche master de VTK à partir d'avril 2023.
50
51/*---------------------------------------------------------------------------*/
52/*---------------------------------------------------------------------------*/
53
54// TODO: Ajouter test de vérifcation des valeurs sauvegardées
55
56// TODO: Regarder la sauvegarde des uniqueId() (via vtkOriginalCellIds)
57
58// TODO: Regarder comment éviter de sauver le maillage à chaque itération s'il
59// ne change pas.
60
61// TODO: Regarder la compression
62
63// TODO: gérer les variables 2D
64
65// TODO: hors HDF5, faire un mécanisme qui regroupe plusieurs parties
66// du maillage en une seule. Cela permettra de réduire le nombre de mailles
67// fantômes et d'utiliser MPI/IO en mode hybride.
68
69/*---------------------------------------------------------------------------*/
70/*---------------------------------------------------------------------------*/
71
72namespace Arcane
73{
74using namespace Hdf5Utils;
75using namespace Materials;
76
77namespace
78{
79 template <typename T> Span<const T>
80 asConstSpan(const T* v)
81 {
82 return Span<const T>(v, 1);
83 }
84} // namespace
85
86/*---------------------------------------------------------------------------*/
87/*---------------------------------------------------------------------------*/
88
89class VtkHdfV2DataWriter
90: public TraceAccessor
91, public IDataWriter
92{
93 public:
94
101 struct DatasetGroupAndName
102 {
103 public:
104
105 DatasetGroupAndName(HGroup& group_, const String& name_)
106 : group(group_)
107 , name(name_)
108 {}
109
110 public:
111
112 HGroup& group;
113 String name;
114 };
115
127 struct DatasetInfo
128 {
129 DatasetInfo() = default;
130 explicit DatasetInfo(const String& name)
131 : m_name(name)
132 {}
133 DatasetInfo(HGroup& _group, const String& name)
134 : m_group(&_group)
135 , m_name(name)
136 {}
137 bool isNull() const { return m_name.null(); }
138
139 HGroup* group() const { return m_group; }
140 const String& name() const { return m_name; }
142 Int64 offset() const { return m_offset; }
143 void setOffset(Int64 v) { m_offset = v; }
144 friend bool operator<(const DatasetInfo& s1, const DatasetInfo& s2)
145 {
146 return (s1.m_name < s2.m_name);
147 }
148
149 private:
150
151 HGroup* m_group = nullptr;
152 String m_name;
153 Int64 m_offset = -1;
154 };
155
158 {
159 public:
160
161 void setTotalSize(Int64 v) { m_total_size = v; }
162 void setSize(Int64 v) { m_size = v; }
163 void setOffset(Int64 v) { m_offset = v; }
164
165 Int64 totalSize() const { return m_total_size; }
166 Int64 size() const { return m_size; }
167 Int64 offset() const { return m_offset; }
168
169 private:
170
177 };
178
180 struct ItemGroupCollectiveInfo
181 {
182 public:
183
184 explicit ItemGroupCollectiveInfo(const ItemGroup& g)
185 : m_item_group(g)
186 {}
187
188 public:
189
190 void setWritePartInfo(const WritePartInfo& part_info) { m_write_part_info = part_info; }
191 const WritePartInfo& writePartInfo() const { return m_write_part_info; }
192
193 public:
194
199 };
200
204 struct DataInfo
205 {
206 public:
207
208 DataInfo(const DatasetGroupAndName& dname, const DatasetInfo& dataset_info)
209 : dataset(dname)
210 , m_dataset_info(dataset_info)
211 {
212 }
213 DataInfo(const DatasetGroupAndName& dname, const DatasetInfo& dataset_info,
214 ItemGroupCollectiveInfo* group_info)
215 : dataset(dname)
216 , m_dataset_info(dataset_info)
217 , m_group_info(group_info)
218 {
219 }
220 DataInfo(HGroup& dataset_group, const String& dataset_name, const DatasetInfo& dataset_info)
221 : dataset(dataset_group, dataset_name)
222 , m_dataset_info(dataset_info)
223 {
224 }
225 DataInfo(HGroup& dataset_group, const String& dataset_name, const DatasetInfo& dataset_info,
226 ItemGroupCollectiveInfo* group_info)
227 : dataset(dataset_group, dataset_name)
228 , m_dataset_info(dataset_info)
229 , m_group_info(group_info)
230 {
231 }
232
233 public:
234
235 DatasetInfo datasetInfo() const { return m_dataset_info; }
236
237 public:
238
239 DatasetGroupAndName dataset;
240 DatasetInfo m_dataset_info;
241 ItemGroupCollectiveInfo* m_group_info = nullptr;
242 };
243
244 public:
245
246 VtkHdfV2DataWriter(IMesh* mesh, const ItemGroupCollection& groups, bool is_collective_io);
247
248 public:
249
250 void beginWrite(const VariableCollection& vars) override;
251 void endWrite() override;
252 void setMetaData(const String& meta_data) override;
253 void write(IVariable* var, IData* data) override;
254
255 public:
256
257 void setTimes(RealConstArrayView times) { m_times = times; }
258 void setDirectoryName(const String& dir_name) { m_directory_name = dir_name; }
259 void setMaxWriteSize(Int64 v) { m_max_write_size = v; }
260
261 private:
262
264 IMesh* m_mesh = nullptr;
265
268
271
274
277
280
283
284 HGroup m_top_group;
285 HGroup m_cell_data_group;
286 HGroup m_node_data_group;
287
288 HGroup m_steps_group;
289 HGroup m_point_data_offsets_group;
290 HGroup m_cell_data_offsets_group;
291 HGroup m_field_data_offsets_group;
292
293 bool m_is_parallel = false;
294 bool m_is_collective_io = false;
295 bool m_is_first_call = false;
296 bool m_is_writer = false;
297
307
308 Int32 m_writer = 0;
309
310 DatasetInfo m_cell_offset_info;
311 DatasetInfo m_point_offset_info;
312 DatasetInfo m_connectivity_offset_info;
313 DatasetInfo m_face_connectivity_offset_info;
314 DatasetInfo m_polyhedron_to_face_offset_info;
315 DatasetInfo m_face_offsets_offset_info;
316 DatasetInfo m_offset_for_cell_offset_info;
317 DatasetInfo m_offset_for_face_offset_info;
318 DatasetInfo m_offset_for_polyhedron_offset_info;
319 DatasetInfo m_part_offset_info;
320 DatasetInfo m_time_offset_info;
321 std::map<DatasetInfo, Int64> m_offset_info_list;
322
323 StandardTypes m_standard_types{ false };
324
325 ItemGroupCollectiveInfo m_all_cells_info;
326 ItemGroupCollectiveInfo m_all_nodes_info;
328
329 GatherGroupInfo m_all_cells_gather_group_info;
330 GatherGroupInfo m_all_nodes_gather_group_info;
331 UniqueArray<Ref<GatherGroupInfo>> m_gather_info_materials_groups;
332
340
341 private:
342
343 void _addInt64ArrayAttribute(Hid& hid, const char* name, Span<const Int64> values);
344 void _addStringAttribute(Hid& hid, const char* name, const String& value);
345
346 template <typename DataType> void
347 _writeDataSet1D(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values);
348 template <typename DataType> void
349 _writeDataSet1DUsingCollectiveIO(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values);
350 template <typename DataType> void
351 _writeDataSet1DCollective(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values);
352 template <typename DataType> void
353 _writeDataSet2D(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values);
354 template <typename DataType> void
355 _writeDataSet2DUsingCollectiveIO(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values);
356 template <typename DataType> void
357 _writeDataSet2DCollective(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values);
358 template <typename DataType> void
359 _writeBasicTypeDataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data);
360 void _writeReal3Dataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data);
361 void _writeReal2Dataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data);
362
363 String _getFileName()
364 {
365 StringBuilder sb(m_mesh->name());
366 sb += ".hdf";
367 return sb.toString();
368 }
369 template <typename DataType> void
370 _writeDataSetGeneric(const DataInfo& data_info, GatherGroupInfo* gather_info, Int32 nb_dim,
371 Int64 dim1_size, Int64 dim2_size, const DataType* values_data,
372 bool is_collective);
373 void _writeDataSetGeneric(const DataInfo& data_info, GatherGroupInfo* gather_info, Int32 nb_dim,
374 Int64 dim1_size, Int64 dim2_size, ConstMemoryView values_data,
375 const hid_t hdf_datatype_type, bool is_collective);
376 void _addInt64Attribute(Hid& hid, const char* name, Int64 value);
377 Int64 _readInt64Attribute(Hid& hid, const char* name);
378 void _openOrCreateGroups();
379 void _closeGroups();
380 void _readAndSetOffset(DatasetInfo& offset_info, Int32 wanted_step);
381 void _initializeOffsets();
382 void _initializeItemGroupCollectiveInfos(ItemGroupCollectiveInfo& group_info, GatherGroupInfo& gather_info);
383 WritePartInfo _computeWritePartInfo(Int64 local_size);
384 void _writeConstituentsGroups();
385};
386
387/*---------------------------------------------------------------------------*/
388/*---------------------------------------------------------------------------*/
389
390VtkHdfV2DataWriter::
391VtkHdfV2DataWriter(IMesh* mesh, const ItemGroupCollection& groups, bool is_collective_io)
392: TraceAccessor(mesh->traceMng())
393, m_mesh(mesh)
394, m_groups(groups)
395, m_is_collective_io(is_collective_io)
396, m_all_cells_info(mesh->allCells())
397, m_all_nodes_info(mesh->allNodes())
398, m_all_cells_gather_group_info(mesh->parallelMng(), is_collective_io)
399, m_all_nodes_gather_group_info(mesh->parallelMng(), is_collective_io)
400{
401}
402
403/*---------------------------------------------------------------------------*/
404/*---------------------------------------------------------------------------*/
405
406void VtkHdfV2DataWriter::
407beginWrite(const VariableCollection& vars)
408{
409 ARCANE_UNUSED(vars);
410
411 // Récupère le gestionnaire de matériaux s'il existe
413
414 IParallelMng* pm = m_mesh->parallelMng();
415 const Int32 nb_rank = pm->commSize();
416 m_is_parallel = nb_rank > 1;
417
418 Int32 time_index = m_times.size();
419 const bool is_first_call = (time_index < 2);
420 m_is_first_call = is_first_call;
421 if (is_first_call)
422 info() << "WARNING: L'implémentation au format 'VtkHdfV2' est expérimentale";
423
424 String filename = _getFileName();
425
426 Directory dir(m_directory_name);
427
428 m_full_filename = dir.file(filename);
429 info(4) << "VtkHdfV2DataWriter::beginWrite() file=" << m_full_filename;
430
431 HInit();
432 HInit::useMutex(pm->isThreadImplementation(), pm);
433
434 // Il est possible d'utiliser le mode collectif de HDF5 via MPI-IO dans les cas suivants :
435 // * Hdf5 a été compilé avec MPI,
436 // * on est en mode MPI pure (ni mode mémoire partagé, ni mode hybride).
437 m_is_collective_io = m_is_collective_io && (pm->isParallel() && HInit::hasParallelHdf5());
438 if (pm->isThreadImplementation() && !pm->isHybridImplementation())
439 m_is_collective_io = false;
440
441 if (is_first_call) {
442 info() << "VtkHdfV2DataWriter: using collective MPI/IO ?=" << m_is_collective_io;
443 info() << "VtkHdfV2DataWriter: max_write_size (kB) =" << m_max_write_size;
444 info() << "VtkHdfV2DataWriter: has_material?=" << (m_material_mng != nullptr);
445 }
446
447 bool is_master_io = pm->isMasterIO();
448
449 // Vrai si on doit participer aux écritures
450 // Si on utilise MPI/IO avec HDF5, il faut tout de même que tous
451 // les rangs fassent toutes les opérations d'écriture pour garantir
452 // la cohérence des méta-données.
453 if (m_is_collective_io) {
454 m_writer = pm->_internalApi()->masterParallelIORank();
455 m_is_writer = (m_writer == pm->commRank());
456 }
457 else {
458 m_writer = pm->masterIORank();
459 m_is_writer = is_master_io;
460 }
461
462 // Indique qu'on utilise MPI/IO si demandé
463 HProperty plist_id;
464 if (m_is_collective_io && m_is_writer)
465 plist_id.createFilePropertyMPIIO(pm);
466
467 // Même avec MPI-IO, un seul proc doit créer le dossier.
468 if (is_first_call && is_master_io)
469 dir.createDirectory();
470
471 if (m_is_collective_io)
472 pm->barrier();
473
474 if (m_is_writer) {
475 m_standard_types.initialize();
476
477 if (is_first_call)
478 m_file_id.openTruncate(m_full_filename, plist_id.id());
479 else
480 m_file_id.openAppend(m_full_filename, plist_id.id());
481
482 _openOrCreateGroups();
483
484 if (is_first_call) {
485 std::array<Int64, 2> version = { 2, 5 };
486 _addInt64ArrayAttribute(m_top_group, "Version", version);
487 _addStringAttribute(m_top_group, "Type", "UnstructuredGrid");
488 }
489 }
490
491 // Initialise les informations collectives sur les groupes de mailles et noeuds
492 _initializeItemGroupCollectiveInfos(m_all_cells_info, m_all_cells_gather_group_info);
493 _initializeItemGroupCollectiveInfos(m_all_nodes_info, m_all_nodes_gather_group_info);
494
495 CellGroup all_cells = m_mesh->allCells();
496 NodeGroup all_nodes = m_mesh->allNodes();
497
498 const Int32 nb_cell = all_cells.size();
499 const Int32 nb_node = all_nodes.size();
500
501 Int64 total_nb_connected_node = 0;
502 ENUMERATE_ (Cell, icell, all_cells) {
503 Cell cell = *icell;
504 total_nb_connected_node += cell.nodeIds().size();
505 }
506
507 // Pour les offsets, la taille du tableau est égal
508 // au nombre de mailles plus 1.
509 UniqueArray<Int64> cells_connectivity(total_nb_connected_node);
510 UniqueArray<Int64> cells_offset(nb_cell + 1);
511 UniqueArray<unsigned char> cells_ghost_type(nb_cell);
512 UniqueArray<unsigned char> cells_type(nb_cell);
513 UniqueArray<Int64> cells_uid(nb_cell);
514
515 // Tableaux pour les mailles polyèdres.
516 //
517 // Le tableau 'faces_connectivity' contient la liste des noeuds de chaque face
518 // de chaque maille polyèdre et 'faces_offset' contient l'offset de chaque
519 // face dans 'faces_connectivity' (sa taille est égale au nombre de faces
520 // plus 1). Chaque maille polyèdre a sa propre liste de faces (une face partagée
521 // par deux mailles est sauvegardée deux fois car VTK demande que les noeuds d'une
522 // face soient ordonnés de sorte que la normale à la face pointe vers l'extérieur
523 // de la maille).
524 //
525 // Le tableau 'polyhedron_to_faces' contient pour chaque maille la liste de ses
526 // faces (cette liste est vide pour les mailles qui ne sont pas des polyèdres) et
527 // 'polyhedron_offset' contient l'offset de chaque maille dans
528 // 'polyhedron_to_faces' (sa taille est égale au nombre de mailles plus 1).
529 UniqueArray<Int64> faces_connectivity;
530 UniqueArray<Int64> faces_offset;
531 UniqueArray<Int64> polyhedron_to_faces;
532 UniqueArray<Int64> polyhedron_offset(nb_cell + 1);
533 faces_offset.add(0);
534 polyhedron_offset[0] = 0;
535 Int64 nb_face = 0;
536
537 // Dans un maillage polyédrique, toutes les mailles ayant au moins une face sont
538 // considérées comme des mailles polyèdres. Pour les autres maillages, seules les
539 // mailles de type polyèdre sont considérées comme des mailles polyèdres.
540 const bool mesh_is_polyhedral = (m_mesh->meshKind().meshStructure() == eMeshStructure::Polyhedral);
541
542 cells_offset[0] = 0;
543 {
544 Int32 connected_node_index = 0;
545 ENUMERATE_CELL (icell, all_cells) {
546 Int32 index = icell.index();
547 Cell cell = *icell;
548
549 cells_uid[index] = cell.uniqueId();
550
551 Byte ghost_type = 0;
552 bool is_ghost = !cell.isOwn();
553 if (is_ghost)
554 ghost_type = VtkUtils::CellGhostTypes::DUPLICATECELL;
555 cells_ghost_type[index] = ghost_type;
556
557 const bool is_polyhedron = cell.typeInfo()->isPolyhedron() || (mesh_is_polyhedral && cell.nbFace() > 0);
558 unsigned char vtk_type = VtkUtils::VTK_POLYHEDRON;
559 if (!is_polyhedron)
560 vtk_type = VtkUtils::arcaneToVtkCellType(cell.type());
561 cells_type[index] = vtk_type;
562 for (NodeLocalId node : cell.nodeIds()) {
563 cells_connectivity[connected_node_index] = node;
564 ++connected_node_index;
565 }
566 cells_offset[index + 1] = connected_node_index;
567
568 if (is_polyhedron) {
569 for (Face face : cell.faces()) {
570 // VTK demande que les noeuds d'une face d'un polyèdre soient ordonnés
571 // de sorte que la normale à cette face pointe vers l'extérieur de la
572 // maille. Dans Arcane, l'orientation stockée d'une face est vers
573 // l'extérieur pour sa maille arrière. Pour la maille avant, l'ordre des
574 // noeuds doit donc être inversé.
575 Int32 face_nb_node = face.nbNode();
576 bool is_back_cell = (face.backCellId().localId() == cell.localId());
577 if (is_back_cell) {
578 for (NodeLocalId node : face.nodeIds())
579 faces_connectivity.add(node);
580 }
581 else {
582 NodeLocalIdView node_ids = face.nodeIds();
583 for (Int32 i = face_nb_node - 1; i >= 0; --i)
584 faces_connectivity.add(node_ids[i]);
585 }
586 faces_offset.add(faces_connectivity.size());
587 polyhedron_to_faces.add(nb_face);
588 ++nb_face;
589 }
590 }
591 polyhedron_offset[index + 1] = polyhedron_to_faces.size();
592 }
593 }
594
595 // Détermine si les datasets liés aux mailles polyèdres doivent
596 // être écrits. C'est le cas soit quand le maillage contient au moins une
597 // maille polyèdre, soit quand ces datasets ont déjà été créés pour un
598 // pas de temps précédent (leur contenu doit alors être mis à jour à chaque
599 // pas de temps pour garder cohérents les offsets temporels du fichier).
600 {
601 Int32 local_has_polyhedron = (nb_face > 0) ? 1 : 0;
602 Int32 global_has_polyhedron = pm->reduce(MessagePassing::ReduceMax, local_has_polyhedron);
603 Int32 global_has_polyhedron_datasets = 0;
604 if (!m_is_first_call) {
605 Int32 local_has_polyhedron_datasets = 0;
606 if (m_is_writer) {
607 HDataset polyhedron_dataset;
608 polyhedron_dataset.openIfExists(m_top_group, "FaceConnectivity");
609 local_has_polyhedron_datasets = (polyhedron_dataset.id() > 0) ? 1 : 0;
610 }
611 global_has_polyhedron_datasets = pm->reduce(MessagePassing::ReduceMax, local_has_polyhedron_datasets);
612 }
613 if (global_has_polyhedron != 0 && global_has_polyhedron_datasets == 0 && !m_is_first_call)
614 ARCANE_FATAL("The mesh contains polyhedron cells but the associated datasets "
615 "do not exist in the file '{0}'. Polyhedron cells must be present "
616 "from the first output",
618 m_write_polyhedron_datasets = (global_has_polyhedron != 0) || (global_has_polyhedron_datasets != 0);
619 }
620
621 _initializeOffsets();
622
623 // ggi est un GatherGroupInfo pour les tableaux qui ne sont pas de taille nb_cell ou nb_node.
624 Ref<GatherGroupInfo> ggi_ref = createRef<GatherGroupInfo>(m_mesh->parallelMng(), m_is_collective_io);
625 GatherGroupInfo* ggi = ggi_ref.get();
626
627 // TODO: faire un offset pour cet objet (ou regarder comment le calculer automatiquement
628 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "Offsets", m_offset_for_cell_offset_info),
629 ggi, cells_offset);
630
632 // Sauve l'offset des faces de chaque maille dans 'PolyhedronToFaces'.
633 // Ce dataset a la même structure que 'Offsets' ((nb_cell + 1) valeurs
634 // par partie) et est donc écrit avec les mêmes informations de gather.
635 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "PolyhedronOffsets", m_offset_for_polyhedron_offset_info),
636 ggi, polyhedron_offset);
637 }
638 ggi->setNeedRecompute();
639
640 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "Connectivity", m_connectivity_offset_info),
641 ggi, cells_connectivity);
642 ggi->setNeedRecompute();
643
645 // Sauve les noeuds des faces des mailles polyèdres.
646 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "FaceConnectivity", m_face_connectivity_offset_info),
647 ggi, faces_connectivity);
648 ggi->setNeedRecompute();
649
650 // Sauve les faces de chaque maille. Les mailles qui ne sont pas des polyèdres
651 // ont une liste de faces vide.
652 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "PolyhedronToFaces", m_polyhedron_to_face_offset_info),
653 ggi, polyhedron_to_faces);
654 ggi->setNeedRecompute();
655
656 // Sauve les offsets des faces dans 'FaceConnectivity'. La taille du tableau
657 // est égale au nombre de faces plus 1.
658 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "FaceOffsets", m_offset_for_face_offset_info),
659 ggi, faces_offset);
660 ggi->setNeedRecompute();
661 }
662
663 _writeDataSet1DCollective<unsigned char>(DataInfo(m_top_group, "Types", m_cell_offset_info),
664 &m_all_cells_gather_group_info, cells_type);
665
666 {
667 Int64 nb_cell_int64 = nb_cell;
668 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "NumberOfCells", m_part_offset_info),
669 ggi, asConstSpan(&nb_cell_int64));
670
671 Int64 nb_node_int64 = nb_node;
672 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "NumberOfPoints", m_part_offset_info),
673 ggi, asConstSpan(&nb_node_int64));
674
675 Int64 number_of_connectivity_ids = cells_connectivity.size();
676 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "NumberOfConnectivityIds", m_part_offset_info),
677 ggi, asConstSpan(&number_of_connectivity_ids));
678
680 Int64 nb_face_int64 = nb_face;
681 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "NumberOfFaces", m_part_offset_info),
682 ggi, asConstSpan(&nb_face_int64));
683
684 Int64 number_of_face_connectivity_ids = faces_connectivity.size();
685 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "NumberOfFaceConnectivityIds", m_part_offset_info),
686 ggi, asConstSpan(&number_of_face_connectivity_ids));
687
688 Int64 number_of_polyhedron_to_face_ids = polyhedron_to_faces.size();
689 _writeDataSet1DCollective<Int64>(DataInfo(m_top_group, "NumberOfPolyhedronToFaceIds", m_part_offset_info),
690 ggi, asConstSpan(&number_of_polyhedron_to_face_ids));
691 }
692 }
693 ggi->setNeedRecompute();
694
695 // Sauve les uniqueIds, les types et les coordonnées des noeuds.
696 {
697 UniqueArray<Int64> nodes_uid(nb_node);
698 UniqueArray<unsigned char> nodes_ghost_type(nb_node);
699 VariableNodeReal3& nodes_coordinates(m_mesh->nodesCoordinates());
700 UniqueArray2<Real> points;
701 points.resize(nb_node, 3);
702 ENUMERATE_ (Node, inode, all_nodes) {
703 Int32 index = inode.index();
704 Node node = *inode;
705
706 nodes_uid[index] = node.uniqueId();
707
708 Byte ghost_type = 0;
709 bool is_ghost = !node.isOwn();
710 if (is_ghost)
711 ghost_type = VtkUtils::PointGhostTypes::DUPLICATEPOINT;
712 nodes_ghost_type[index] = ghost_type;
713
714 Real3 pos = nodes_coordinates[inode];
715 points[index][0] = pos.x;
716 points[index][1] = pos.y;
717 points[index][2] = pos.z;
718 }
719
720 // Sauve l'uniqueId de chaque nœud dans le dataset "GlobalNodeId".
721 _writeDataSet1DCollective<Int64>(DataInfo(DatasetGroupAndName(m_node_data_group, "GlobalIds"), m_cell_offset_info),
722 &m_all_nodes_gather_group_info, nodes_uid);
723
724 // Sauve les informations sur le type de nœud (réel ou fantôme).
725 _writeDataSet1DCollective<unsigned char>(DataInfo(DatasetGroupAndName(m_node_data_group, "vtkGhostType"), m_cell_offset_info),
726 &m_all_nodes_gather_group_info, nodes_ghost_type);
727
728 // Sauve les coordonnées des noeuds.
729 _writeDataSet2DCollective<Real>(DataInfo(DatasetGroupAndName(m_top_group, "Points"), m_point_offset_info),
730 ggi, points);
731 ggi->setNeedRecompute();
732 }
733
734 // Sauve les informations sur le type de maille (réel ou fantôme)
735 _writeDataSet1DCollective<unsigned char>(DataInfo(DatasetGroupAndName(m_cell_data_group, "vtkGhostType"), m_cell_offset_info),
736 &m_all_cells_gather_group_info, cells_ghost_type);
737
738 // Sauve l'uniqueId de chaque maille dans le dataset "GlobalCellId".
739 // L'utilisation du dataset "vtkOriginalCellIds" ne fonctionne pas dans Paraview.
740 _writeDataSet1DCollective<Int64>(DataInfo(DatasetGroupAndName(m_cell_data_group, "GlobalIds"), m_cell_offset_info),
741 &m_all_cells_gather_group_info, cells_uid);
742
743 if (m_is_writer) {
744 // Liste des temps.
745 Real current_time = m_times[time_index - 1];
746 // TODO : Remplacer ggi par nullptr en non-collective ?
747 _writeDataSet1D<Real>(DataInfo(DatasetGroupAndName(m_steps_group, "Values"), m_time_offset_info),
748 ggi, asConstSpan(&current_time));
749
750 // Offset de la partie.
751 Int64 comm_size = pm->commSize();
752 Int64 part_offset = (time_index - 1) * comm_size;
753 _writeDataSet1D<Int64>(DataInfo(DatasetGroupAndName(m_steps_group, "PartOffsets"), m_time_offset_info),
754 ggi, asConstSpan(&part_offset));
755
757 // Offset du dataset 'FaceOffsets' pour le pas de temps courant. Cette
758 // valeur est le nombre de faces sauvées avant le pas de temps courant. Elle
759 // se déduit de l'offset d'écriture du dataset 'FaceOffsets' (qui contient
760 // lui aussi une valeur d'offset par partie et par pas de temps) en
761 // retirant le nombre de ces valeurs d'offset.
762 auto face_offsets_write_offset = m_offset_info_list.find(m_offset_for_face_offset_info);
763 if (face_offsets_write_offset == m_offset_info_list.end())
764 ARCANE_FATAL("The dataset 'FaceOffsets' has not been written");
765 Int64 nb_offset_value = (time_index - 1) * comm_size;
766 Int64 face_offsets_offset = face_offsets_write_offset->second - nb_offset_value;
767 _writeDataSet1D<Int64>({ { m_steps_group, "FaceOffsetsOffsets" }, m_time_offset_info }, ggi,
768 asConstSpan(&face_offsets_offset));
769 }
770
771 // Nombre de temps
772 _addInt64Attribute(m_steps_group, "NSteps", time_index);
773 }
774 //ggi->needRecompute();
775
776 _writeConstituentsGroups();
777}
778
779/*---------------------------------------------------------------------------*/
780/*---------------------------------------------------------------------------*/
781
782void VtkHdfV2DataWriter::
783_writeConstituentsGroups()
784{
785 if (!m_material_mng)
786 return;
787
788 // Remplit les informations des groupes liés aux constituents
789 // NOTE : Pour l'instant, on ne traite que les milieux.
790 for (IMeshEnvironment* env : m_material_mng->environments()) {
791 CellGroup cells = env->cells();
792
793 Ref<ItemGroupCollectiveInfo> group_info_ref = createRef<ItemGroupCollectiveInfo>(cells);
794 m_materials_groups.add(group_info_ref);
795
796 Ref<GatherGroupInfo> gather_info_ref = createRef<GatherGroupInfo>(m_material_mng->mesh()->parallelMng(), m_is_collective_io);
797 m_gather_info_materials_groups.add(gather_info_ref);
798
799 ItemGroupCollectiveInfo& group_info = *group_info_ref.get();
800 GatherGroupInfo& gather_info = *gather_info_ref.get();
801 _initializeItemGroupCollectiveInfos(group_info, gather_info);
802
803 ConstArrayView<Int32> groups_ids = cells.view().localIds();
804 DatasetGroupAndName dataset_group_name(m_top_group, String("Constituent_") + cells.name());
805 if (m_is_first_call)
806 info() << "Writing infos for group '" << cells.name() << "'";
807 _writeDataSet1DCollective<Int32>({ dataset_group_name, m_cell_offset_info, group_info_ref.get() }, gather_info_ref.get(), groups_ids);
808 }
809}
810
811/*---------------------------------------------------------------------------*/
812/*---------------------------------------------------------------------------*/
818{
819 // TODO: regarder pour utiliser un scan.
820 IParallelMng* pm = m_mesh->parallelMng();
821 Int32 nb_rank = pm->commSize();
822 Int32 my_rank = pm->commRank();
823
824 UniqueArray<Int64> ranks_size(nb_rank);
825 ArrayView<Int64> all_sizes(ranks_size);
826 Int64 dim1_size = local_size;
827 pm->allGather(ConstArrayView<Int64>(1, &dim1_size), all_sizes);
828
829 Int64 total_size = 0;
830 for (Integer i = 0; i < nb_rank; ++i)
831 total_size += all_sizes[i];
832
833 Int64 my_index = 0;
834 for (Integer i = 0; i < my_rank; ++i)
835 my_index += all_sizes[i];
836
837 WritePartInfo part_info;
838 part_info.setTotalSize(total_size);
839 part_info.setSize(local_size);
840 part_info.setOffset(my_index);
841 return part_info;
842}
843
844/*---------------------------------------------------------------------------*/
845/*---------------------------------------------------------------------------*/
846
847void VtkHdfV2DataWriter::
848_initializeItemGroupCollectiveInfos(ItemGroupCollectiveInfo& group_info, GatherGroupInfo& gather_info)
849{
850 Int32 dim1_size = group_info.m_item_group.size();
851
852 gather_info.setCollectiveIO(m_is_collective_io);
853 gather_info.computeSize(dim1_size);
854
855 Int32 computed_nb_elem = gather_info.nbElemOutput();
856
857 group_info.setWritePartInfo(_computeWritePartInfo(computed_nb_elem));
858}
859
860namespace
861{
862 std::pair<Int64, Int64> _getInterval(Int64 index, Int64 nb_interval, Int64 total_size)
863 {
864 Int64 n = total_size;
865 Int64 isize = n / nb_interval;
866 Int64 ibegin = index * isize;
867 // Pour le dernier interval, prend les elements restants
868 if ((index + 1) == nb_interval)
869 isize = n - ibegin;
870 return { ibegin, isize };
871 }
872} // namespace
873
874/*---------------------------------------------------------------------------*/
875/*---------------------------------------------------------------------------*/
882void VtkHdfV2DataWriter::
883_writeDataSetGeneric(const DataInfo& data_info, GatherGroupInfo* gather_info, Int32 nb_dim,
884 Int64 dim1_size, Int64 dim2_size,
885 ConstMemoryView values_data,
886 const hid_t hdf_type, bool is_collective)
887{
888 ARCANE_CHECK_POINTER(gather_info);
889 if (nb_dim == 1)
890 dim2_size = 1;
891
892 HGroup& group = data_info.dataset.group;
893 const String& name = data_info.dataset.name;
894
895 // Si positif ou nul, indique l'offset d'écriture.
896 // Sinon, on écrit à la fin du dataset actuel.
897 Int64 wanted_offset = data_info.datasetInfo().offset();
898
899 static constexpr int MAX_DIM = 2;
900 HDataset dataset;
901
902 // En cas d'opération collective, local_dims et global_dims sont
903 // différents sur la première dimension. La deuxième dimension est toujours
904 // identique pour local_dims et global_dims et ne doit pas être modifiée durant
905 // tout le calcul.
906
907 // Dimensions du dataset que le rang courant va écrire.
909 local_dims[0] = dim1_size;
910 local_dims[1] = dim2_size;
911
912 // Dimensions cumulées de tous les rangs pour l'écriture.
914
915 // Dimensions maximales du DataSet
916 // Pour la deuxième dimension, on suppose qu'elle est constante au cours du temps.
918 max_dims[0] = H5S_UNLIMITED;
919 max_dims[1] = dim2_size;
920
921 herr_t herror = 0;
922 Int64 write_offset = 0;
923
924 Int64 my_index = 0;
925 Int64 global_dim1_size = dim1_size;
926 Int32 nb_participating_rank = 1;
927
928 if (is_collective) {
929 nb_participating_rank = gather_info->nbWriterGlobal();
930 WritePartInfo part_info;
931 if (data_info.m_group_info) {
932 // Si la donnée est associée à un groupe, alors les informations
933 // sur l'offset ont déjà été calculées
934 part_info = data_info.m_group_info->writePartInfo();
935 }
936 else {
937 part_info = _computeWritePartInfo(dim1_size);
938 }
939 global_dim1_size = part_info.totalSize();
940 my_index = part_info.offset();
941 }
942
943 // La seule opération collective était _computeWritePartInfo().
944 if (!m_is_writer) {
945 return;
946 }
947
948 HProperty write_plist_id;
949 if constexpr (HInit::hasParallelHdf5()) {
950 if (is_collective)
952 else
954 }
955
956 HSpace file_space;
957 FixedArray<hsize_t, MAX_DIM> hyperslab_offsets;
958
959 if (m_is_first_call) {
960 // TODO: regarder comment mieux calculer le chunk
962 global_dims[0] = global_dim1_size;
963 global_dims[1] = dim2_size;
964 // Il est important que tout le monde ait la même taille de chunk.
965 Int64 chunk_size = global_dim1_size / nb_participating_rank;
966 if (chunk_size < 1024)
967 chunk_size = 1024;
968 const Int64 max_chunk_size = 1024 * 1024 * 10;
969 chunk_size = math::min(chunk_size, max_chunk_size);
970 chunk_dims[0] = chunk_size;
971 chunk_dims[1] = dim2_size;
972 info() << "CHUNK nb_dim=" << nb_dim
973 << " global_dim1_size=" << global_dim1_size
974 << " chunk0=" << chunk_dims[0]
975 << " chunk1=" << chunk_dims[1]
976 << " name=" << name;
977 file_space.createSimple(nb_dim, global_dims.data(), max_dims.data());
978 HProperty plist_id;
979 plist_id.create(H5P_DATASET_CREATE);
980 H5Pset_chunk(plist_id.id(), nb_dim, chunk_dims.data());
981 dataset.create(group, name.localstr(), hdf_type, file_space, HProperty{}, plist_id, HProperty{});
982
983 if (is_collective) {
984 hyperslab_offsets[0] = my_index;
985 hyperslab_offsets[1] = 0;
986 }
987 }
988 else {
989 // Agrandit la première dimension du dataset.
990 // On va ajouter 'global_dim1_size' à cette dimension.
991 dataset.open(group, name.localstr());
992 file_space = dataset.getSpace();
993 int nb_dimension = file_space.nbDimension();
994 if (nb_dimension != nb_dim)
995 ARCANE_THROW(IOException, "Bad dimension '{0}' for dataset '{1}' (should be 1)",
996 nb_dimension, name);
997 // TODO: Vérifier que la deuxième dimension est la même que celle sauvée.
998 FixedArray<hsize_t, MAX_DIM> original_dims;
999 file_space.getDimensions(original_dims.data(), nullptr);
1000 hsize_t offset0 = original_dims[0];
1001 // Si on a un offset positif issu de DatasetInfo alors on le prend.
1002 // Cela signifie qu'on a fait un retour arrière.
1003 if (wanted_offset >= 0) {
1004 offset0 = wanted_offset;
1005 info() << "Forcing offset to " << wanted_offset;
1006 }
1007 global_dims[0] = offset0 + global_dim1_size;
1008 global_dims[1] = dim2_size;
1009 write_offset = offset0;
1010 // Agrandit le dataset.
1011 // ATTENTION cela invalide file_space. Il faut donc le relire juste après.
1012 if ((herror = dataset.setExtent(global_dims.data())) < 0)
1013 ARCANE_THROW(IOException, "Can not extent dataset '{0}' (err={1})", name, herror);
1014 file_space = dataset.getSpace();
1015
1016 hyperslab_offsets[0] = offset0 + my_index;
1017 hyperslab_offsets[1] = 0;
1018 info(4) << "APPEND nb_dim=" << nb_dim
1019 << " dim0=" << global_dims[0]
1020 << " count0=" << local_dims[0]
1021 << " offsets0=" << hyperslab_offsets[0] << " name=" << name;
1022 }
1023
1024 Int64 nb_write_byte = global_dim1_size * dim2_size * values_data.datatypeSize();
1025
1026 // Effectue l'écriture en plusieurs parties si demandé.
1027 // Cela n'est possible que pour l'écriture collective.
1028 Int64 nb_interval = 1;
1029 if (is_collective && m_max_write_size > 0) {
1030 nb_interval = 1 + nb_write_byte / (m_max_write_size * 1024);
1031 }
1032 info(4) << "WRITE global_size=" << nb_write_byte << " max_size=" << m_max_write_size << " nb_interval=" << nb_interval;
1033
1034 for (Int64 i = 0; i < nb_interval; ++i) {
1035 auto [index, nb_element] = _getInterval(i, nb_interval, dim1_size);
1036 // Sélectionne la partie de la donnée à écrire
1038 dims[0] = nb_element;
1039 dims[1] = dim2_size;
1040 FixedArray<hsize_t, 2> offsets;
1041 offsets[0] = hyperslab_offsets[0] + index;
1042 offsets[1] = 0;
1043 if ((herror = H5Sselect_hyperslab(file_space.id(), H5S_SELECT_SET, offsets.data(), nullptr, dims.data(), nullptr)) < 0)
1044 ARCANE_THROW(IOException, "Can not select hyperslab '{0}' (err={1})", name, herror);
1045
1046 HSpace memory_space;
1047 memory_space.createSimple(nb_dim, dims.data());
1048 Int64 data_offset = index * values_data.datatypeSize() * dim2_size;
1049 // Effectue l'écriture
1050 if ((herror = dataset.write(hdf_type, values_data.data() + data_offset, memory_space, file_space, write_plist_id)) < 0)
1051 ARCANE_THROW(IOException, "Can not write dataset '{0}' (err={1})", name, herror);
1052
1053 if (dataset.isBad())
1054 ARCANE_THROW(IOException, "Can not write dataset '{0}'", name);
1055 }
1056
1057 if (!data_info.datasetInfo().isNull())
1058 m_offset_info_list.insert(std::make_pair(data_info.datasetInfo(), write_offset));
1059}
1060
1061/*---------------------------------------------------------------------------*/
1062/*---------------------------------------------------------------------------*/
1063
1064template <typename DataType> void VtkHdfV2DataWriter::
1065_writeDataSetGeneric(const DataInfo& data_info, GatherGroupInfo* gather_info, Int32 nb_dim,
1066 Int64 dim1_size, Int64 dim2_size, const DataType* values_data,
1067 bool is_collective)
1068{
1069 const hid_t hdf_type = m_standard_types.nativeType(DataType{});
1070 ConstMemoryView mem_view = makeConstMemoryView(values_data, sizeof(DataType), dim1_size * dim2_size);
1071 _writeDataSetGeneric(data_info, gather_info, nb_dim, dim1_size, dim2_size, mem_view, hdf_type, is_collective);
1072}
1073
1074/*---------------------------------------------------------------------------*/
1075/*---------------------------------------------------------------------------*/
1076
1077template <typename DataType> void VtkHdfV2DataWriter::
1078_writeDataSet1D(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
1079{
1080 _writeDataSetGeneric(data_info, gather_info, 1, values.size(), 1, values.data(), false);
1081}
1082
1083/*---------------------------------------------------------------------------*/
1084/*---------------------------------------------------------------------------*/
1085
1086template <typename DataType> void VtkHdfV2DataWriter::
1087_writeDataSet1DUsingCollectiveIO(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
1088{
1089 _writeDataSetGeneric(data_info, gather_info, 1, values.size(), 1, values.data(), true);
1090}
1091
1092/*---------------------------------------------------------------------------*/
1093/*---------------------------------------------------------------------------*/
1094
1095template <typename DataType> void VtkHdfV2DataWriter::
1096_writeDataSet1DCollective(const DataInfo& data_info, GatherGroupInfo* gather_info, Span<const DataType> values)
1097{
1098 ARCANE_CHECK_POINTER(gather_info);
1099
1100 GatherGroup gg;
1101
1102 gather_info->computeSizeT(values);
1103 gg.setGatherGroupInfo(gather_info);
1104
1105 if (gg.isNeedGather()) {
1106 UniqueArray<DataType> all_values;
1107 gg.gatherToMasterIOT(values, all_values);
1108
1109 if (m_is_collective_io)
1110 _writeDataSet1DUsingCollectiveIO(data_info, gather_info, all_values.constSpan());
1111 else
1112 _writeDataSet1D(data_info, gather_info, all_values.constSpan());
1113 }
1114 else {
1115 if (m_is_collective_io)
1116 _writeDataSet1DUsingCollectiveIO(data_info, gather_info, values);
1117 else
1118 _writeDataSet1D(data_info, gather_info, values);
1119 }
1120}
1121
1122/*---------------------------------------------------------------------------*/
1123/*---------------------------------------------------------------------------*/
1124
1125template <typename DataType> void VtkHdfV2DataWriter::
1126_writeDataSet2D(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
1127{
1128 _writeDataSetGeneric(data_info, gather_info, 2, values.dim1Size(), values.dim2Size(), values.data(), false);
1129}
1130
1131/*---------------------------------------------------------------------------*/
1132/*---------------------------------------------------------------------------*/
1133
1134template <typename DataType> void VtkHdfV2DataWriter::
1135_writeDataSet2DUsingCollectiveIO(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
1136{
1137 _writeDataSetGeneric(data_info, gather_info, 2, values.dim1Size(), values.dim2Size(), values.data(), true);
1138}
1139
1140/*---------------------------------------------------------------------------*/
1141/*---------------------------------------------------------------------------*/
1142
1143template <typename DataType> void VtkHdfV2DataWriter::
1144_writeDataSet2DCollective(const DataInfo& data_info, GatherGroupInfo* gather_info, Span2<const DataType> values)
1145{
1146 ARCANE_CHECK_POINTER(gather_info);
1147
1148 GatherGroup gg;
1149
1150 gather_info->computeSizeT(values);
1151 gg.setGatherGroupInfo(gather_info);
1152
1153 if (gg.isNeedGather()) {
1154 UniqueArray2<DataType> all_values;
1155 gg.gatherToMasterIOT(values, all_values);
1156
1157 if (m_is_collective_io)
1158 _writeDataSet2DUsingCollectiveIO(data_info, gather_info, all_values.constSpan());
1159 else
1160 _writeDataSet2D(data_info, gather_info, all_values.constSpan());
1161 }
1162 else {
1163 if (m_is_collective_io)
1164 _writeDataSet2DUsingCollectiveIO(data_info, gather_info, values);
1165 else
1166 _writeDataSet2D(data_info, gather_info, values);
1167 }
1168}
1169
1170/*---------------------------------------------------------------------------*/
1171/*---------------------------------------------------------------------------*/
1172
1173void VtkHdfV2DataWriter::
1174_addInt64ArrayAttribute(Hid& hid, const char* name, Span<const Int64> values)
1175{
1176 hsize_t len = values.size();
1177 hid_t aid = H5Screate_simple(1, &len, nullptr);
1178 hid_t attr = H5Acreate2(hid.id(), name, H5T_NATIVE_INT64, aid, H5P_DEFAULT, H5P_DEFAULT);
1179 if (attr < 0)
1180 ARCANE_FATAL("Can not create attribute '{0}'", name);
1181 int ret = H5Awrite(attr, H5T_NATIVE_INT64, values.data());
1182 if (ret < 0)
1183 ARCANE_FATAL("Can not write attribute '{0}'", name);
1184 H5Aclose(attr);
1185 H5Sclose(aid);
1186}
1187
1188/*---------------------------------------------------------------------------*/
1189/*---------------------------------------------------------------------------*/
1190
1191void VtkHdfV2DataWriter::
1192_addInt64Attribute(Hid& hid, const char* name, Int64 value)
1193{
1194 HSpace aid(H5Screate(H5S_SCALAR));
1195 HAttribute attr;
1196 if (m_is_first_call)
1197 attr.create(hid, name, H5T_NATIVE_INT64, aid);
1198 else
1199 attr.open(hid, name);
1200 if (attr.isBad())
1201 ARCANE_FATAL("Can not create attribute '{0}'", name);
1202 herr_t ret = attr.write(H5T_NATIVE_INT64, &value);
1203 if (ret < 0)
1204 ARCANE_FATAL("Can not write attribute '{0}'", name);
1205}
1206
1207/*---------------------------------------------------------------------------*/
1208/*---------------------------------------------------------------------------*/
1209
1210Int64 VtkHdfV2DataWriter::
1211_readInt64Attribute(Hid& hid, const char* name)
1212{
1213 HAttribute attr;
1214 attr.open(hid, name);
1215 if (attr.isBad())
1216 ARCANE_FATAL("Can not open attribute '{0}'", name);
1217 Int64 value;
1218 herr_t ret = attr.read(H5T_NATIVE_INT64, &value);
1219 if (ret < 0)
1220 ARCANE_FATAL("Can not read attribute '{0}'", name);
1221 return value;
1222}
1223
1224/*---------------------------------------------------------------------------*/
1225/*---------------------------------------------------------------------------*/
1226
1227void VtkHdfV2DataWriter::
1228_addStringAttribute(Hid& hid, const char* name, const String& value)
1229{
1230 hid_t aid = H5Screate(H5S_SCALAR);
1231 hid_t attr_type = H5Tcopy(H5T_C_S1);
1232 H5Tset_size(attr_type, value.length());
1233 hid_t attr = H5Acreate2(hid.id(), name, attr_type, aid, H5P_DEFAULT, H5P_DEFAULT);
1234 if (attr < 0)
1235 ARCANE_FATAL("Can not create attribute {0}", name);
1236 int ret = H5Awrite(attr, attr_type, value.localstr());
1237 ret = H5Tclose(attr_type);
1238 if (ret < 0)
1239 ARCANE_FATAL("Can not write attribute '{0}'", name);
1240 H5Aclose(attr);
1241 H5Sclose(aid);
1242}
1243
1244/*---------------------------------------------------------------------------*/
1245/*---------------------------------------------------------------------------*/
1246
1247void VtkHdfV2DataWriter::
1248endWrite()
1249{
1250 // Sauvegarde les offsets enregistrés
1251
1252 if (m_is_writer) {
1253 for (const auto& i : m_offset_info_list) {
1254 Int64 offset = i.second;
1255 const DatasetInfo& offset_info = i.first;
1256 HGroup* hdf_group = offset_info.group();
1257 //info() << "OFFSET_INFO name=" << offset_info.name() << " offset=" << offset;
1258 if (hdf_group) {
1259 Ref<GatherGroupInfo> ggi = createRef<GatherGroupInfo>(m_mesh->parallelMng(), m_is_collective_io);
1260 _writeDataSet1D<Int64>({ { *hdf_group, offset_info.name() }, m_time_offset_info }, ggi.get(), asConstSpan(&offset));
1261 }
1262 }
1263 }
1264 _closeGroups();
1265 m_file_id.close();
1266}
1267
1268/*---------------------------------------------------------------------------*/
1269/*---------------------------------------------------------------------------*/
1270
1271void VtkHdfV2DataWriter::
1272_openOrCreateGroups()
1273{
1274 // Tout groupe ouvert ici doit être fermé dans closeGroups().
1275 m_top_group.openOrCreate(m_file_id, "VTKHDF");
1276 m_cell_data_group.openOrCreate(m_top_group, "CellData");
1277 m_node_data_group.openOrCreate(m_top_group, "PointData");
1278 m_steps_group.openOrCreate(m_top_group, "Steps");
1279 m_point_data_offsets_group.openOrCreate(m_steps_group, "PointDataOffsets");
1280 m_cell_data_offsets_group.openOrCreate(m_steps_group, "CellDataOffsets");
1281 m_field_data_offsets_group.openOrCreate(m_steps_group, "FieldDataOffsets");
1282}
1283
1284/*---------------------------------------------------------------------------*/
1285/*---------------------------------------------------------------------------*/
1286
1287void VtkHdfV2DataWriter::
1288_closeGroups()
1289{
1290 m_cell_data_group.close();
1291 m_node_data_group.close();
1292 m_point_data_offsets_group.close();
1293 m_cell_data_offsets_group.close();
1294 m_field_data_offsets_group.close();
1295 m_steps_group.close();
1296 m_top_group.close();
1297}
1298
1299/*---------------------------------------------------------------------------*/
1300/*---------------------------------------------------------------------------*/
1301
1303setMetaData(const String& meta_data)
1304{
1305 ARCANE_UNUSED(meta_data);
1306}
1307
1308/*---------------------------------------------------------------------------*/
1309/*---------------------------------------------------------------------------*/
1310
1312write(IVariable* var, IData* data)
1313{
1314 info(4) << "Write VtkHdfV2 var=" << var->name();
1315
1316 eItemKind item_kind = var->itemKind();
1317
1318 if (var->dimension() != 1)
1319 ARCANE_FATAL("Only export of scalar item variable is implemented (name={0})", var->name());
1320 if (var->isPartial())
1321 ARCANE_FATAL("Export of partial variable is not implemented");
1322
1323 HGroup* group = nullptr;
1324 DatasetInfo offset_info;
1325 ItemGroupCollectiveInfo* group_info = nullptr;
1326 GatherGroupInfo* gather_info = nullptr;
1327 switch (item_kind) {
1328 case IK_Cell:
1329 group = &m_cell_data_group;
1330 offset_info = m_cell_offset_info;
1331 group_info = &m_all_cells_info;
1332 gather_info = &m_all_cells_gather_group_info;
1333 break;
1334 case IK_Node:
1335 group = &m_node_data_group;
1336 offset_info = m_point_offset_info;
1337 group_info = &m_all_nodes_info;
1338 gather_info = &m_all_nodes_gather_group_info;
1339 break;
1340 default:
1341 ARCANE_FATAL("Only export of 'Cell' or 'Node' variable is implemented (name={0})", var->name());
1342 }
1343
1344 ARCANE_CHECK_POINTER(group);
1345
1346 DataInfo data_info(DatasetGroupAndName{ *group, var->name() }, offset_info, group_info);
1347 eDataType data_type = var->dataType();
1348 switch (data_type) {
1349 case DT_Real:
1350 _writeBasicTypeDataset<Real>(data_info, gather_info, data);
1351 break;
1352 case DT_Int64:
1353 _writeBasicTypeDataset<Int64>(data_info, gather_info, data);
1354 break;
1355 case DT_Int32:
1356 _writeBasicTypeDataset<Int32>(data_info, gather_info, data);
1357 break;
1358 case DT_Real3:
1359 _writeReal3Dataset(data_info, gather_info, data);
1360 break;
1361 case DT_Real2:
1362 _writeReal2Dataset(data_info, gather_info, data);
1363 break;
1364 default:
1365 warning() << String::format("Export for datatype '{0}' is not supported (var_name={1})", data_type, var->name());
1366 }
1367}
1368
1369/*---------------------------------------------------------------------------*/
1370/*---------------------------------------------------------------------------*/
1371
1372template <typename DataType> void VtkHdfV2DataWriter::
1373_writeBasicTypeDataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data)
1374{
1375 auto* true_data = dynamic_cast<IArrayDataT<DataType>*>(data);
1376 ARCANE_CHECK_POINTER(true_data);
1377 _writeDataSet1DCollective(data_info, gather_info, Span<const DataType>(true_data->view()));
1378}
1379
1380/*---------------------------------------------------------------------------*/
1381/*---------------------------------------------------------------------------*/
1382
1383void VtkHdfV2DataWriter::
1384_writeReal3Dataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data)
1385{
1386 auto* true_data = dynamic_cast<IArrayDataT<Real3>*>(data);
1387 ARCANE_CHECK_POINTER(true_data);
1388 SmallSpan<const Real3> values(true_data->view());
1389 Int32 nb_value = values.size();
1390 // TODO: optimiser cela sans passer par un tableau temporaire
1391 UniqueArray2<Real> scalar_values;
1392 scalar_values.resize(nb_value, 3);
1393 for (Int32 i = 0; i < nb_value; ++i) {
1394 Real3 v = values[i];
1395 scalar_values[i][0] = v.x;
1396 scalar_values[i][1] = v.y;
1397 scalar_values[i][2] = v.z;
1398 }
1399 _writeDataSet2DCollective<Real>(data_info, gather_info, scalar_values);
1400}
1401
1402/*---------------------------------------------------------------------------*/
1403/*---------------------------------------------------------------------------*/
1404
1405void VtkHdfV2DataWriter::
1406_writeReal2Dataset(const DataInfo& data_info, GatherGroupInfo* gather_info, IData* data)
1407{
1408 // Converti en un tableau de 3 composantes dont la dernière vaudra 0.
1409 auto* true_data = dynamic_cast<IArrayDataT<Real2>*>(data);
1410 ARCANE_CHECK_POINTER(true_data);
1411 SmallSpan<const Real2> values(true_data->view());
1412 Int32 nb_value = values.size();
1413 UniqueArray2<Real> scalar_values;
1414 scalar_values.resize(nb_value, 3);
1415 for (Int32 i = 0; i < nb_value; ++i) {
1416 Real2 v = values[i];
1417 scalar_values[i][0] = v.x;
1418 scalar_values[i][1] = v.y;
1419 scalar_values[i][2] = 0.0;
1420 }
1421 _writeDataSet2DCollective<Real>(data_info, gather_info, scalar_values);
1422}
1423
1424/*---------------------------------------------------------------------------*/
1425/*---------------------------------------------------------------------------*/
1426
1427void VtkHdfV2DataWriter::
1428_readAndSetOffset(DatasetInfo& offset_info, Int32 wanted_step)
1429{
1430 HGroup* hgroup = offset_info.group();
1431 ARCANE_CHECK_POINTER(hgroup);
1432 StandardArrayT<Int64> a(hgroup->id(), offset_info.name());
1433 UniqueArray<Int64> values;
1434 a.directRead(m_standard_types, values);
1435 Int64 offset_value = values[wanted_step];
1436 offset_info.setOffset(offset_value);
1437 info() << "VALUES name=" << offset_info.name() << " values=" << values
1438 << " wanted_step=" << wanted_step << " v=" << offset_value;
1439}
1440
1441/*---------------------------------------------------------------------------*/
1442/*---------------------------------------------------------------------------*/
1443
1444void VtkHdfV2DataWriter::
1445_initializeOffsets()
1446{
1447 // Il y a 5 valeurs d'offset utilisées :
1448 //
1449 // - offset sur le nombre de mailles (CellOffsets). Cet offset a pour nombre d'éléments
1450 // le nombre de temps sauvés et est augmenté à chaque sortie du nombre de mailles. Cet offset
1451 // est aussi utilisé pour les variables aux mailles
1452 // - offset sur le nombre de noeuds (PointOffsets). Il est équivalent à 'CellOffsets' mais
1453 // pour les noeuds.
1454 // - offset pour "NumberOfCells", "NumberOfPoints" et "NumberOfConnectivityIds". Pour chacun
1455 // de ces champs il y a NbPart valeurs par temps, avec 'NbPart' le nombre de parties (donc
1456 // le nombre de sous-domaines si on ne fait pas de regroupement). Il y a ainsi au total
1457 // NbPart * NbTimeStep dans ce champ d'offset.
1458 // - offset pour le champ "Connectivity" qui s'appelle "ConnectivityIdOffsets".
1459 // Cet offset a pour nombre d'éléments le nombre de temps sauvés.
1460 // - offset pour le champ "Offsets". "Offset" contient pour chaque maille l'offset dans
1461 // "Connectivity" de la connectivité des noeuds de la maille. Cet offset n'est pas sauvés,
1462 // mais comme ce champ à un nombre de valeurs égal au nombre de mailles plus un il est possible
1463 // de le déduire de "CellOffsets" (il vaut "CellOffsets" plus l'index du temps courant).
1464 //
1465 // Quand le maillage contient des mailles polyèdres, 4 valeurs d'offset supplémentaires
1466 // sont utilisées :
1467 //
1468 // - offset pour le champ "FaceConnectivity" qui s'appelle "FaceConnectivityOffsets".
1469 // Il est équivalent à "ConnectivityIdOffsets" mais pour les faces des mailles polyèdres.
1470 // - offset pour le champ "PolyhedronToFaces" qui s'appelle "PolyhedronToFaceIdOffsets".
1471 // Il est équivalent à "ConnectivityIdOffsets" mais pour la liste des faces de chaque maille.
1472 // - offset pour le champ "FaceOffsets" qui s'appelle "FaceOffsetsOffsets". Il contient
1473 // le nombre de faces sauvées avant le temps courant. Comme pour "Offsets", l'offset
1474 // d'écriture du dataset "FaceOffsets" peut en être déduit (il vaut "FaceOffsetsOffsets"
1475 // plus le nombre de parties sauvegardées avant le temps courant).
1476 // - offset pour le champ "PolyhedronOffsets". Cet offset n'est pas sauvegardé mais, comme
1477 // ce champ a la même structure que "Offsets", son offset d'écriture est égal à celui
1478 // de "Offsets".
1479
1480 m_cell_offset_info = DatasetInfo(m_steps_group, "CellOffsets");
1481 m_point_offset_info = DatasetInfo(m_steps_group, "PointOffsets");
1482 m_connectivity_offset_info = DatasetInfo(m_steps_group, "ConnectivityIdOffsets");
1483 m_face_connectivity_offset_info = DatasetInfo(m_steps_group, "FaceConnectivityOffsets");
1484 m_polyhedron_to_face_offset_info = DatasetInfo(m_steps_group, "PolyhedronToFaceIdOffsets");
1485 m_face_offsets_offset_info = DatasetInfo(m_steps_group, "FaceOffsetsOffsets");
1486 // Ces cinq offsets ne sont pas sauvegardés dans le format VTK
1487 m_offset_for_cell_offset_info = DatasetInfo("_OffsetForCellOffsetInfo");
1488 m_offset_for_face_offset_info = DatasetInfo("_OffsetForFaceOffsetInfo");
1489 m_offset_for_polyhedron_offset_info = DatasetInfo("_OffsetForPolyhedronOffsetInfo");
1490 m_part_offset_info = DatasetInfo("_PartOffsetInfo");
1491 m_time_offset_info = DatasetInfo("_TimeOffsetInfo");
1492
1493 // Regarde si on n'a pas fait de retour-arrière.
1494 // C'est le cas si le nombre de temps sauvés est supérieur au nombre
1495 // de valeurs de \a m_times.
1496 if (m_is_writer && !m_is_first_call) {
1497 IParallelMng* pm = m_mesh->parallelMng();
1498 const Int32 nb_rank = pm->commSize();
1499 Int64 nb_current_step = _readInt64Attribute(m_steps_group, "NSteps");
1500 Int32 time_index = m_times.size();
1501 info(4) << "NB_STEP=" << nb_current_step << " time_index=" << time_index
1502 << " current_time=" << m_times.back();
1503 const bool debug_times = false;
1504 if (debug_times) {
1505 StandardArrayT<Real> a1(m_steps_group.id(), "Values");
1506 UniqueArray<Real> times;
1507 a1.directRead(m_standard_types, times);
1508 info() << "TIMES=" << times;
1509 }
1510 if ((nb_current_step + 1) != time_index) {
1511 info() << "[VtkHdf] go_backward detected";
1512 Int32 wanted_step = time_index - 1;
1513 // Signifie qu'on a fait un retour arrière.
1514 // Dans ce cas, il faut relire les offsets
1515 _readAndSetOffset(m_cell_offset_info, wanted_step);
1516 _readAndSetOffset(m_point_offset_info, wanted_step);
1517 _readAndSetOffset(m_connectivity_offset_info, wanted_step);
1519 _readAndSetOffset(m_face_connectivity_offset_info, wanted_step);
1520 _readAndSetOffset(m_polyhedron_to_face_offset_info, wanted_step);
1521 _readAndSetOffset(m_face_offsets_offset_info, wanted_step);
1522 // Le dataset 'FaceOffsets' contient (nb_face + 1) valeurs par partie :
1523 // son offset d'écriture se déduit de 'FaceOffsetsOffsets'.
1524 m_offset_for_face_offset_info.setOffset(m_face_offsets_offset_info.offset() + wanted_step * nb_rank);
1525 // Le dataset 'PolyhedronOffsets' a la même structure que 'Offsets' :
1526 // son offset d'écriture est donc le même.
1527 m_offset_for_polyhedron_offset_info.setOffset(m_offset_for_cell_offset_info.offset());
1528 }
1529 m_part_offset_info.setOffset(wanted_step * nb_rank);
1530 m_time_offset_info.setOffset(wanted_step);
1531 m_offset_for_cell_offset_info.setOffset(m_cell_offset_info.offset() + wanted_step * nb_rank);
1532 }
1533 }
1534}
1535
1536/*---------------------------------------------------------------------------*/
1537/*---------------------------------------------------------------------------*/
1538
1539/*---------------------------------------------------------------------------*/
1540/*---------------------------------------------------------------------------*/
1544class VtkHdfV2PostProcessor
1546{
1547 public:
1548
1549 explicit VtkHdfV2PostProcessor(const ServiceBuildInfo& sbi)
1551 {
1552 }
1553
1554 IDataWriter* dataWriter() override { return m_writer.get(); }
1555 void notifyBeginWrite() override
1556 {
1557 bool use_collective_io = true;
1558 Int64 max_write_size = 0;
1559 if (options()) {
1560 use_collective_io = options()->useCollectiveWrite();
1561 max_write_size = options()->maxWriteSize();
1562 }
1563 auto w = std::make_unique<VtkHdfV2DataWriter>(mesh(), groups(), use_collective_io);
1564 w->setMaxWriteSize(max_write_size);
1565 w->setTimes(times());
1567 w->setDirectoryName(dir.file("vtkhdfv2"));
1568 m_writer = std::move(w);
1569 }
1570 void notifyEndWrite() override
1571 {
1572 m_writer = nullptr;
1573 }
1574 void close() override {}
1575
1576 private:
1577
1578 std::unique_ptr<IDataWriter> m_writer;
1579};
1580
1581/*---------------------------------------------------------------------------*/
1582/*---------------------------------------------------------------------------*/
1583
1584ARCANE_REGISTER_SERVICE_VTKHDFV2POSTPROCESSOR(VtkHdfV2PostProcessor,
1585 VtkHdfV2PostProcessor);
1586
1587/*---------------------------------------------------------------------------*/
1588/*---------------------------------------------------------------------------*/
1589
1590} // namespace Arcane
1591
1592/*---------------------------------------------------------------------------*/
1593/*---------------------------------------------------------------------------*/
#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.
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:91
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:321
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.
bool m_write_polyhedron_datasets
Vrai si les datasets liés aux mailles polyèdres doivent être écrits pour le pas de temps courant.
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:346
ItemLocalIdListViewT< Node > NodeLocalIdView
Vue sur les localId() d'une liste de noeuds.
Definition ItemTypes.h:407
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:35
Active toujours les traces dans les parties Arcane concernant les matériaux.
@ ReduceMax
Maximum des valeurs.
-- 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.
@ Polyhedral
Maillage polyedrique.
Definition MeshKind.h:37
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:42
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:486
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.