Arcane  4.2.3.0
Documentation utilisateur
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
95 /*!
96 * \brief Classe pour conserver un couple (hdf_group,nom_du_dataset).
97 *
98 * Les instances de cette classe utilisent une référence sur un groupe HDF5
99 * et ce dernier doit donc vivre plus longtemps que l'instance.
100 */
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
116 /*!
117 * \brief Classe pour conserver les information d'un offset.
118 *
119 * Il s'agit d'un couple (hdf_group,nom_du_dataset).
120 *
121 * Le groupe peut être nul auquel cas il s'agit d'un offset qui est
122 * uniquement calculé et qui ne sera pas sauvegardé.
123 *
124 * Les instances de cette classe utilisent une référence sur un groupe HDF5
125 * et ce dernier doit donc vivre plus longtemps que l'instance.
126 */
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; }
141 //! Valeur de l'offset. (-1) si on écrit à la fin du tableau
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
156 //! Informations sur l'offset de la partie à écrire associée à un rang
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
171 //! Nombre d'éléments sur tous les rangs
172 Int64 m_total_size = 0;
173 //! Nombre d'éléments de mon rang
174 Int64 m_size = 0;
175 //! Offset de mon rang
176 Int64 m_offset = -1;
177 };
178
179 //! Informations collectives sur un ItemGroup;
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
195 //! Groupe associé
197 //! Informations sur l'écriture.
199 };
200
201 /*!
202 * \brief Conserve les infos sur les données à sauver et l'offset associé.
203 */
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
263 //! Maillage associé
264 IMesh* m_mesh = nullptr;
265
266 //! Gestionnaire de matériaux associé (peut-être nul)
267 IMeshMaterialMng* m_material_mng = nullptr;
268
269 //! Liste des groupes à sauver
270 ItemGroupCollection m_groups;
271
272 //! Liste des temps
273 UniqueArray<Real> m_times;
274
275 //! Nom du fichier HDF courant
276 String m_full_filename;
277
278 //! Répertoire de sortie.
279 String m_directory_name;
280
281 //! Identifiant HDF du fichier
282 HFile m_file_id;
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
298 /*!
299 * \brief Vrai si les datasets liés aux mailles polyèdres
300 * doivent être écrits pour le pas de temps courant.
301 *
302 * C'est le cas soit quand le maillage contient au moins une maille
303 * polyèdre, soit quand ces datasets ont déjà été créés pour un pas
304 * de temps précédent.
305 */
306 bool m_write_polyhedron_datasets = false;
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;
327 UniqueArray<Ref<ItemGroupCollectiveInfo>> m_materials_groups;
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
333 /*!
334 * \brief Taille maximale (en kilo-octet) pour une écriture.
335 *
336 * Si l'écriture dépasse cette taille, elle est scindée en plusieurs écriture.
337 * Cela peut être nécessaire avec MPI-IO pour les gros volumes.
338 */
339 Int64 m_max_write_size = 0;
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
412 m_material_mng = IMeshMaterialMng::getReference(m_mesh, false);
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",
617 m_full_filename);
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
631 if (m_write_polyhedron_datasets) {
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
644 if (m_write_polyhedron_datasets) {
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
679 if (m_write_polyhedron_datasets) {
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
756 if (m_write_polyhedron_datasets) {
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/*---------------------------------------------------------------------------*/
813/*!
814 * \brief Calcule l'offset de notre partie et le nombre total d'éléments.
815 */
816VtkHdfV2DataWriter::WritePartInfo VtkHdfV2DataWriter::
817_computeWritePartInfo(Int64 local_size)
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/*---------------------------------------------------------------------------*/
876/*!
877 * \brief Écrit une donnée 1D ou 2D.
878 *
879 * Pour chaque temps ajouté, la donnée est écrite à la fin des valeurs précédentes
880 * sauf en cas de retour arrière où l'offset est dans data_info.
881 */
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.
908 FixedArray<hsize_t, MAX_DIM> local_dims;
909 local_dims[0] = dim1_size;
910 local_dims[1] = dim2_size;
911
912 // Dimensions cumulées de tous les rangs pour l'écriture.
913 FixedArray<hsize_t, MAX_DIM> global_dims;
914
915 // Dimensions maximales du DataSet
916 // Pour la deuxième dimension, on suppose qu'elle est constante au cours du temps.
917 FixedArray<hsize_t, MAX_DIM> max_dims;
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)
951 write_plist_id.createDatasetTransfertCollectiveMPIIO();
952 else
953 write_plist_id.createDatasetTransfertIndependentMPIIO();
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
961 FixedArray<hsize_t, MAX_DIM> chunk_dims;
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
1037 FixedArray<hsize_t, 2> dims;
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);
1518 if (m_write_polyhedron_datasets) {
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/*---------------------------------------------------------------------------*/
1541/*!
1542 * \brief Post-traitement au format VtkHdf V2.
1543 */
1544class VtkHdfV2PostProcessor
1545: public ArcaneVtkHdfV2PostProcessorObject
1546{
1547 public:
1548
1549 explicit VtkHdfV2PostProcessor(const ServiceBuildInfo& sbi)
1550 : ArcaneVtkHdfV2PostProcessorObject(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());
1566 Directory dir(baseDirectoryName());
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,
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.
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
Encapsule un hid_t pour un groupe.
Definition Hdf5Utils.h:349
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.
Definition Hdf5Utils.h:122
Interface d'écriture des données d'une variable.
Definition IDataWriter.h:44
Interface d'une donnée.
Definition IData.h:33
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
Integer size() const
Nombre d'éléments du groupe.
Definition ItemGroup.h:88
static IMeshMaterialMng * getReference(const MeshHandleOrMesh &mesh_handle, bool create=true)
Récupère ou créé la référence associée à mesh.
Structure contenant les informations pour créer un service.
Vue d'un tableau d'éléments de type T.
Definition Span.h:633
Chaîne de caractères unicode.
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.
Collection de variables.
void write(IVariable *var, IData *data) override
Ecrit les données data de la variable var.
void setMetaData(const String &meta_data) override
Positionne les infos des méta-données.
Post-traitement au format VtkHdf V2.
__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.