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