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