Arcane  v3.14.10.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-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
32#include "arcane/std/Hdf5Utils.h"
33#include "arcane/std/VtkHdfV2PostProcessor_axl.h"
34#include "arcane/std/internal/VtkCellTypes.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
95 {
96 HGroup& group;
97 String name;
98 };
99
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; }
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
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
156 Int64 m_total_size = 0;
158 Int64 m_size = 0;
160 Int64 m_offset = -1;
161 };
162
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
183 };
184
188 struct DataInfo
189 {
190 public:
191
193 : dataset(dname)
194 , m_dataset_info(dataset_info)
195 {
196 }
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
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
239
242
245
248
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
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,
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());
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/*---------------------------------------------------------------------------*/
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
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
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/*---------------------------------------------------------------------------*/
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.
637 local_dims[0] = dim1_size;
638 local_dims[1] = dim2_size;
639
640 // Dimensions cumulées de tous les rangs pour l'écriture.
642
643 // Dimensions maximales du DataSet
644 // Pour la deuxième dimension, on suppose qu'elle est constante au cours du temps.
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();
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
672 if (is_collective)
673 write_plist_id.createDatasetTransfertCollectiveMPIIO();
674
677
678 if (m_is_first_call) {
679 // TODO: regarder comment mieux calculer le chunk
682 global_dims[1] = dim2_size;
683 // Il est important que tout le monde ait la même taille de chunk.
685 if (chunk_size < 1024)
686 chunk_size = 1024;
687 const Int64 max_chunk_size = 1024 * 1024 * 10;
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());
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) {
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.
718 file_space.getDimensions(original_dims.data(), nullptr);
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) {
724 info() << "Forcing offset to " << wanted_offset;
725 }
727 global_dims[1] = dim2_size;
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
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) {
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
757 dims[0] = nb_element;
758 dims[1] = dim2_size;
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
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
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;
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
1043 eDataType data_type = var->dataType();
1044 switch (data_type) {
1045 case DT_Real:
1047 break;
1048 case DT_Int64:
1050 break;
1051 case DT_Int32:
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);
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/*---------------------------------------------------------------------------*/
1210{
1211 public:
1212
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());
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,
1249 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.
Generation de la classe de base du Service.
CaseOptionsVtkHdfV2PostProcessor * options() const
Options du jeu de données du service.
Classe gérant un répertoire.
Definition Directory.h:33
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*).
Encapsule un hid_t pour un dataspace.
Encapsule un hid_t.
Définition des types standards Arcane pour hdf5.
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
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 void gatherVariable(ConstArrayView< char > send_buf, Array< char > &recv_buf, Int32 rank)=0
Effectue un regroupement sur tous les processeurs.
virtual bool isThreadImplementation() const =0
Indique si l'implémentation utilise les threads.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual bool isMasterIO() const =0
true si l'instance est un gestionnaire maître des entrées/sorties.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual bool isHybridImplementation() const =0
Indique si l'implémentation utilise le mode hybride.
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....
virtual Integer masterIORank() const =0
Rang de l'instance gérant les entrées/sorties (pour laquelle isMasterIO() est vrai)
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
virtual void barrier()=0
Effectue une barière.
Interface d'une variable.
Definition IVariable.h:54
Groupe d'entités de maillage.
Definition ItemGroup.h:49
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
virtual RealConstArrayView times()
Liste des temps sauvés.
virtual const String & baseDirectoryName()
Nom du répertoire de sortie des fichiers.
virtual ItemGroupCollection groups()
Liste des groupes à sauver.
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.
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.
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.
Post-traitement au format VtkHdf V2.
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.
Integer size() const
Nombre d'éléments du vecteur.
Vue constante d'un tableau de type T.
Constructeur de chaîne de caractère unicode.
Chaîne de caractères unicode.
bool null() const
Retourne true si la chaîne est nulle.
Definition String.cc:304
TraceMessage pwarning() const
TraceMessage warning() const
Flot pour un message d'avertissement.
TraceMessage info() const
Flot pour un message d'information.
ARCCORE_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:142
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
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.