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