Arcane  v4.1.7.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
VtkHdfPostProcessor.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* VtkHdfPostProcessor.cc (C) 2000-2026 */
9/* */
10/* Pos-traitement au format VTK HDF. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/Collection.h"
15#include "arcane/utils/Enumerator.h"
16#include "arcane/utils/Iostream.h"
17#include "arcane/utils/ScopedPtr.h"
18#include "arcane/utils/StringBuilder.h"
19#include "arcane/utils/CheckedConvert.h"
20#include "arcane/utils/JSONWriter.h"
21#include "arcane/utils/IOException.h"
22
23#include "arcane/core/PostProcessorWriterBase.h"
24#include "arcane/core/Directory.h"
25#include "arcane/core/FactoryService.h"
26#include "arcane/core/IDataWriter.h"
27#include "arcane/core/IData.h"
28#include "arcane/core/IItemFamily.h"
29#include "arcane/core/VariableCollection.h"
30#include "arcane/core/IParallelMng.h"
31#include "arcane/core/IMesh.h"
32#include "arcane/core/internal/VtkCellTypes.h"
33
34#include "arcane/hdf5/Hdf5Utils.h"
35#include "arcane/hdf5/VtkHdfPostProcessor_axl.h"
36
37// Ce format est décrit sur la page web suivante:
38//
39// https://kitware.github.io/vtk-examples/site/VTKFileFormats/#hdf-file-formats
40
41/*---------------------------------------------------------------------------*/
42/*---------------------------------------------------------------------------*/
43
44// TODO: Regarder la sauvegarde des uniqueId() (via vtkOriginalCellIds)
45// TODO: Regarder comment éviter de sauver le maillage à chaque itération s'il
46// ne change pas. Avec la notion de lien de HDF5, il doit être possible
47// de mettre cette information ailleurs et de ne sauver le maillage
48// que s'il évolue.
49// TODO: Regarder la compression
50
51/*
52 NOTE sur l'implémentation parallèle
53
54 L'implémentation actuelle est très basique.
55 Seul le rang maitre (le rang 0 en général) effectue les sorties. Pour
56 chaque dataset, ce rang fait un gather pour récupérer les informations. Cela
57 suppose donc que tout le monde a les mêmes variables et dans le même ordre
58 (normalement c'est toujours le cas car c'est trié par la VariableMng).
59
60 Cette implémentation fonctionne donc quel que soit le mode d'échange de
61 message utilisé (full MPI, mémoire partagé ou hybride).
62
63 TODO: Découpler l'écriture de la gestion des variables pour pouvoir utiliser
64 les opérations collectives de HDF5 (si compilé avec MPI). Dans ce cas il
65 faut quand même géré manuellement le mode échange de message en mémoire
66 partagée ou hybride.
67*/
68/*---------------------------------------------------------------------------*/
69/*---------------------------------------------------------------------------*/
70
71namespace Arcane
72{
73using namespace Hdf5Utils;
74
75/*---------------------------------------------------------------------------*/
76/*---------------------------------------------------------------------------*/
77
78class VtkHdfDataWriter
79: public TraceAccessor
80, public IDataWriter
81{
82 public:
83
84 VtkHdfDataWriter(IMesh* mesh, ItemGroupCollection groups);
85
86 public:
87
88 void beginWrite(const VariableCollection& vars) override;
89 void endWrite() override;
90 void setMetaData(const String& meta_data) override;
91 void write(IVariable* var, IData* data) override;
92
93 public:
94
95 void setTimes(RealConstArrayView times) { m_times = times; }
96 void setDirectoryName(const String& dir_name) { m_directory_name = dir_name; }
97
98 private:
99
100 IMesh* m_mesh;
101
102 //! Liste des groupes à sauver
103 ItemGroupCollection m_groups;
104
105 //! Liste des temps
106 UniqueArray<Real> m_times;
107
108 //! Nom du fichier HDF courant
109 String m_full_filename;
110
111 //! Répertoire de sortie.
112 String m_directory_name;
113
114 //! Identifiant HDF du fichier
115 HFile m_file_id;
116
117 HGroup m_cell_data_group;
118 HGroup m_node_data_group;
119 bool m_is_parallel = false;
120 bool m_is_master_io = false;
121 bool m_is_collective_io = false;
122
123 private:
124
125 void _addInt64ArrayAttribute(Hid& hid, const char* name, Span<const Int64> values);
126 void _addStringAttribute(Hid& hid, const char* name, const String& value);
127
128 template <typename DataType> void
129 _writeDataSet1D(HGroup& group, const String& name, Span<const DataType> values);
130 template <typename DataType> void
131 _writeDataSet1DCollective(HGroup& group, const String& name, Span<const DataType> values);
132 template <typename DataType> void
133 _writeDataSet2D(HGroup& group, const String& name, Span2<const DataType> values);
134 template <typename DataType> void
135 _writeDataSet2DCollective(HGroup& group, const String& name, Span2<const DataType> values);
136 template <typename DataType> void
137 _writeBasicTypeDataset(HGroup& group, IVariable* var, IData* data);
138 void _writeReal3Dataset(HGroup& group, IVariable* var, IData* data);
139 void _writeReal2Dataset(HGroup& group, IVariable* var, IData* data);
140
141 template <typename DataType> void
142 _writeDataSet1DCollectiveWithCollectiveIO(HGroup& group, const String& name, Span<const DataType> values);
143 template <typename DataType> void
144 _writeDataSet2DCollectiveWithCollectiveIO(HGroup& group, const String& name, Span2<const DataType> values);
145
146 String _getFileNameForTimeIndex(Int32 index)
147 {
148 StringBuilder sb(m_mesh->name());
149 if (index >= 0) {
150 sb += "_";
151 sb += index;
152 }
153 sb += ".hdf";
154 return sb.toString();
155 }
156};
157
158/*---------------------------------------------------------------------------*/
159/*---------------------------------------------------------------------------*/
160
161VtkHdfDataWriter::
162VtkHdfDataWriter(IMesh* mesh, ItemGroupCollection groups)
163: TraceAccessor(mesh->traceMng())
164, m_mesh(mesh)
165, m_groups(groups)
166{
167}
168
169/*---------------------------------------------------------------------------*/
170/*---------------------------------------------------------------------------*/
171
172void VtkHdfDataWriter::
173beginWrite(const VariableCollection& vars)
174{
175 ARCANE_UNUSED(vars);
176
177 IParallelMng* pm = m_mesh->parallelMng();
178 const Int32 nb_rank = pm->commSize();
179 m_is_parallel = nb_rank > 1;
180 m_is_master_io = pm->isMasterIO();
181
182 Int32 time_index = m_times.size();
183 const bool is_first_call = (time_index < 2);
184 if (is_first_call)
185 pwarning() << "L'implémentation au format 'VtkHdf' est expérimentale";
186
187 String filename = _getFileNameForTimeIndex(time_index);
188
189 Directory dir(m_directory_name);
190
191 m_full_filename = dir.file(filename);
192 info(4) << "VtkHdfDataWriter::beginWrite() file=" << m_full_filename;
193
194 HInit();
195 HInit::useMutex(pm->isThreadImplementation(), pm);
196
197 HGroup top_group;
198
199 // TODO: protéger appels concurrents HDF5
200 // Il est possible d'utiliser le mode collectif de HDF5 via MPI-IO dans les cas suivants:
201 // - Hdf5 a été compilé avec MPI
202 // - on est en mode MPI pure (ni mode mémoire partagé, ni mode hybride)
203 m_is_collective_io = pm->isParallel() && HInit::hasParallelHdf5();
204 if (pm->isHybridImplementation() || pm->isThreadImplementation())
205 m_is_collective_io = false;
206 if (is_first_call)
207 info() << "VtkHdfDataWriter: using collective MPI/IO ?=" << m_is_collective_io;
208
209 HProperty plist_id;
210 if (m_is_collective_io)
211 plist_id.createFilePropertyMPIIO(pm);
212
213 if (time_index <= 1) {
214 if (m_is_master_io) {
215 dir.createDirectory();
216 }
217 }
218
219 if (m_is_collective_io)
220 pm->barrier();
221
222 if (m_is_collective_io || m_is_master_io) {
223 m_file_id.openTruncate(m_full_filename, plist_id.id());
224
225 top_group.create(m_file_id, "VTKHDF");
226
227 m_cell_data_group.create(top_group, "CellData");
228 m_node_data_group.create(top_group, "PointData");
229
230 std::array<Int64, 2> version = { 1, 0 };
231 _addInt64ArrayAttribute(top_group, "Version", version);
232 _addStringAttribute(top_group, "Type", "UnstructuredGrid");
233 }
234
235 CellGroup all_cells = m_mesh->allCells();
236 NodeGroup all_nodes = m_mesh->allNodes();
237
238 const Int32 nb_cell = all_cells.size();
239 const Int32 nb_node = all_nodes.size();
240
241 Int32 total_nb_connected_node = 0;
242 {
243 ENUMERATE_CELL (icell, all_cells) {
244 Cell cell = *icell;
245 total_nb_connected_node += cell.nodeIds().size();
246 }
247 }
248
249 // Pour les connectivités, la taille du tableau est égal
250 // au nombre de mailles plus 1.
251 UniqueArray<Int64> cells_connectivity(total_nb_connected_node);
252 UniqueArray<Int64> cells_offset(nb_cell + 1);
253 UniqueArray<unsigned char> cells_ghost_type(nb_cell);
254 UniqueArray<unsigned char> cells_type(nb_cell);
255 UniqueArray<Int64> cells_uid(nb_cell);
256 cells_offset[0] = 0;
257 {
258 Int32 connected_node_index = 0;
259 ENUMERATE_CELL (icell, all_cells) {
260 Int32 index = icell.index();
261 Cell cell = *icell;
262
263 cells_uid[index] = icell->uniqueId();
264
265 Byte ghost_type = 0;
266 bool is_ghost = !cell.isOwn();
267 if (is_ghost)
268 ghost_type = VtkUtils::CellGhostTypes::DUPLICATECELL;
269 cells_ghost_type[index] = ghost_type;
270
271 unsigned char vtk_type = VtkUtils::arcaneToVtkCellType(cell.type());
272 cells_type[index] = vtk_type;
273 for (NodeLocalId node : cell.nodeIds()) {
274 cells_connectivity[connected_node_index] = node;
275 ++connected_node_index;
276 }
277 cells_offset[index + 1] = connected_node_index;
278 }
279 }
280
281 _writeDataSet1DCollective<Int64>(top_group, "Offsets", cells_offset);
282
283 _writeDataSet1DCollective<Int64>(top_group, "Connectivity", cells_connectivity);
284 _writeDataSet1DCollective<unsigned char>(top_group, "Types", cells_type);
285
286 {
287 UniqueArray<Int64> nb_cell_by_ranks(1);
288 nb_cell_by_ranks[0] = nb_cell;
289 _writeDataSet1DCollective<Int64>(top_group, "NumberOfCells", nb_cell_by_ranks);
290
291 UniqueArray<Int64> nb_node_by_ranks(1);
292 nb_node_by_ranks[0] = nb_node;
293 _writeDataSet1DCollective<Int64>(top_group, "NumberOfPoints", nb_node_by_ranks);
294
295 UniqueArray<Int64> number_of_connectivity_ids(1);
296 number_of_connectivity_ids[0] = cells_connectivity.size();
297 _writeDataSet1DCollective<Int64>(top_group, "NumberOfConnectivityIds", number_of_connectivity_ids);
298 }
299
300 // Sauve les uniqueIds, les types et les coordonnées des noeuds.
301 {
302 UniqueArray<Int64> nodes_uid(nb_node);
303 UniqueArray<unsigned char> nodes_ghost_type(nb_node);
304 VariableNodeReal3& nodes_coordinates(m_mesh->nodesCoordinates());
305 UniqueArray2<Real> points;
306 points.resize(nb_node, 3);
307 ENUMERATE_NODE (inode, all_nodes) {
308 Int32 index = inode.index();
309 Node node = *inode;
310
311 nodes_uid[index] = inode->uniqueId();
312
313 Byte ghost_type = 0;
314 bool is_ghost = !node.isOwn();
315 if (is_ghost)
316 ghost_type = VtkUtils::PointGhostTypes::DUPLICATEPOINT;
317 nodes_ghost_type[index] = ghost_type;
318
319 Real3 pos = nodes_coordinates[inode];
320 points[index][0] = pos.x;
321 points[index][1] = pos.y;
322 points[index][2] = pos.z;
323 }
324
325 // Sauve l'uniqueId de chaque noeud dans le dataset "GlobalNodeId".
326 _writeDataSet1DCollective<Int64>(m_node_data_group, "GlobalNodeId", nodes_uid);
327
328 // Sauve les informations sur le type de noeud (réel ou fantôme).
329 _writeDataSet1DCollective<unsigned char>(m_node_data_group, "vtkGhostType", nodes_ghost_type);
330
331 // Sauve les coordonnées des noeuds.
332 _writeDataSet2DCollective<Real>(top_group, "Points", points);
333 }
334
335 // Sauve les informations sur le type de maille (réel ou fantôme)
336 _writeDataSet1DCollective<Int64>(m_cell_data_group, "GlobalCellId", cells_uid);
337
338 // Sauve l'uniqueId de chaque maille dans le dataset "GlobalCellId".
339 // L'utilisation du dataset "vtkOriginalCellIds" ne fonctionne pas dans Paraview.
340 _writeDataSet1DCollective<unsigned char>(m_cell_data_group, "vtkGhostType", cells_ghost_type);
341}
342
343/*---------------------------------------------------------------------------*/
344/*---------------------------------------------------------------------------*/
345
346namespace
347{
348 template <typename DataType> class HDFTraits;
349
350 template <> class HDFTraits<Int64>
351 {
352 public:
353
354 static hid_t hdfType() { return H5T_NATIVE_INT64; }
355 };
356
357 template <> class HDFTraits<Int32>
358 {
359 public:
360
361 static hid_t hdfType() { return H5T_NATIVE_INT32; }
362 };
363
364 template <> class HDFTraits<double>
365 {
366 public:
367
368 static hid_t hdfType() { return H5T_NATIVE_DOUBLE; }
369 };
370
371 template <> class HDFTraits<unsigned char>
372 {
373 public:
374
375 static hid_t hdfType() { return H5T_NATIVE_UINT8; }
376 };
377
378} // namespace
379
380/*---------------------------------------------------------------------------*/
381/*---------------------------------------------------------------------------*/
382
383template <typename DataType> void VtkHdfDataWriter::
384_writeDataSet1DCollectiveWithCollectiveIO(HGroup& group, const String& name, Span<const DataType> values)
385{
386 IParallelMng* pm = m_mesh->parallelMng();
387 Int64 size = values.size();
388 Int32 nb_rank = pm->commSize();
389 Int32 my_rank = pm->commRank();
390 UniqueArray<Int64> all_sizes(nb_rank);
391 pm->allGather(ConstArrayView<Int64>(1, &size), all_sizes);
392
393 Int64 total_size = 0;
394 for (Integer i = 0; i < nb_rank; ++i)
395 total_size += all_sizes[i];
396 Int64 my_index = 0;
397 for (Integer i = 0; i < my_rank; ++i)
398 my_index += all_sizes[i];
399 //m_variables_offset.insert(std::make_pair(v->fullName(), VarOffset(my_index, total_size, all_sizes)));
400 //info() << " ADD OFFSET v=" << v->fullName() << " offset=" << my_index
401 // << " total_size=" << total_size;
402
403 hsize_t offset[1];
404 hsize_t count[1];
405 offset[0] = my_index;
406 count[0] = size;
407
408 hsize_t dims[1];
409 dims[0] = total_size;
410 HSpace filespace_id;
411 filespace_id.createSimple(1, dims);
412 HSpace memspace_id;
413 memspace_id.createSimple(1, count);
414
415 HDataset dataset_id;
416 const hid_t hdf_type = HDFTraits<DataType>::hdfType();
417
418 dataset_id.create(group, name.localstr(), hdf_type, filespace_id, H5P_DEFAULT);
419
420 H5Sselect_hyperslab(filespace_id.id(), H5S_SELECT_SET, offset, NULL, count, NULL);
421
422 HProperty write_plist_id;
423 write_plist_id.createDatasetTransfertCollectiveMPIIO();
424
425 herr_t herr = dataset_id.write(hdf_type, values.data(), memspace_id, filespace_id, write_plist_id);
426
427 if (herr < 0)
428 ARCANE_THROW(IOException, "Can not write dataset '{0}'", name);
429
430}
431
432/*---------------------------------------------------------------------------*/
433/*---------------------------------------------------------------------------*/
434
435template <typename DataType> void VtkHdfDataWriter::
436_writeDataSet2DCollectiveWithCollectiveIO(HGroup& group, const String& name, Span2<const DataType> values)
437{
438 IParallelMng* pm = m_mesh->parallelMng();
439 Int64 dim1_size = values.dim1Size();
440 Int64 dim2_size = values.dim2Size();
441 Int32 nb_rank = pm->commSize();
442 Int32 my_rank = pm->commRank();
443 UniqueArray<Int64> all_sizes(nb_rank);
444 pm->allGather(ConstArrayView<Int64>(1, &dim1_size), all_sizes);
445
446 Int64 total_size = 0;
447 for (Integer i = 0; i < nb_rank; ++i)
448 total_size += all_sizes[i];
449 Int64 my_index = 0;
450 for (Integer i = 0; i < my_rank; ++i)
451 my_index += all_sizes[i];
452 //m_variables_offset.insert(std::make_pair(v->fullName(), VarOffset(my_index, total_size, all_sizes)));
453 //info() << " ADD OFFSET v=" << v->fullName() << " offset=" << my_index
454 // << " total_size=" << total_size;
455
456 hsize_t offset[2];
457 hsize_t count[2];
458 offset[0] = my_index;
459 offset[1] = 0;
460 count[0] = dim1_size;
461 count[1] = dim2_size;
462
463 hsize_t dims[2];
464 dims[0] = total_size;
465 dims[1] = dim2_size;
466 HSpace filespace_id;
467 filespace_id.createSimple(2, dims);
468 HSpace memspace_id;
469 memspace_id.createSimple(2, count);
470
471 HDataset dataset_id;
472 const hid_t hdf_type = HDFTraits<DataType>::hdfType();
473
474 dataset_id.create(group, name.localstr(), hdf_type, filespace_id, H5P_DEFAULT);
475
476 H5Sselect_hyperslab(filespace_id.id(), H5S_SELECT_SET, offset, NULL, count, NULL);
477
478 HProperty write_plist_id;
479 write_plist_id.createDatasetTransfertCollectiveMPIIO();
480
481 herr_t herr = dataset_id.write(hdf_type, values.data(), memspace_id, filespace_id, write_plist_id);
482
483 if (herr < 0)
484 ARCANE_THROW(IOException, "Can not write dataset '{0}'", name);
485}
486
487/*---------------------------------------------------------------------------*/
488/*---------------------------------------------------------------------------*/
489
490template <typename DataType> void VtkHdfDataWriter::
491_writeDataSet1D(HGroup& group, const String& name, Span<const DataType> values)
492{
493 hsize_t dims[1];
494 dims[0] = values.size();
495 HSpace hspace;
496 hspace.createSimple(1, dims);
497 HDataset dataset;
498 const hid_t hdf_type = HDFTraits<DataType>::hdfType();
499 dataset.create(group, name.localstr(), hdf_type, hspace, H5P_DEFAULT);
500 dataset.write(hdf_type, values.data());
501 if (dataset.isBad())
502 ARCANE_THROW(IOException, "Can not write dataset '{0}'", name);
503}
504
505/*---------------------------------------------------------------------------*/
506/*---------------------------------------------------------------------------*/
507
508template <typename DataType> void VtkHdfDataWriter::
509_writeDataSet1DCollective(HGroup& group, const String& name, Span<const DataType> values)
510{
511 if (!m_is_parallel) {
512 _writeDataSet1D(group, name, values);
513 return;
514 }
515 if (m_is_collective_io) {
516 _writeDataSet1DCollectiveWithCollectiveIO(group, name, values);
517 return;
518 }
519 UniqueArray<DataType> all_values;
520 IParallelMng* pm = m_mesh->parallelMng();
521 pm->gatherVariable(values.smallView(), all_values, pm->masterIORank());
522 if (m_is_master_io)
523 _writeDataSet1D<DataType>(group, name, all_values);
524}
525
526/*---------------------------------------------------------------------------*/
527/*---------------------------------------------------------------------------*/
528
529template <typename DataType> void VtkHdfDataWriter::
530_writeDataSet2D(HGroup& group, const String& name, Span2<const DataType> values)
531{
532 hsize_t dims[2];
533 dims[0] = values.dim1Size();
534 dims[1] = values.dim2Size();
535 HSpace hspace;
536 hspace.createSimple(2, dims);
537 HDataset dataset;
538 const hid_t hdf_type = HDFTraits<DataType>::hdfType();
539 dataset.create(group, name.localstr(), hdf_type, hspace, H5P_DEFAULT);
540 dataset.write(hdf_type, values.data());
541 if (dataset.isBad())
542 ARCANE_THROW(IOException, "Can not write dataset '{0}'", name);
543}
544
545/*---------------------------------------------------------------------------*/
546/*---------------------------------------------------------------------------*/
547
548template <typename DataType> void VtkHdfDataWriter::
549_writeDataSet2DCollective(HGroup& group, const String& name, Span2<const DataType> values)
550{
551 Int64 dim2_size = values.dim2Size();
552
553 if (!m_is_parallel) {
554 _writeDataSet2D(group, name, values);
555 return;
556 }
557
558 if (m_is_collective_io) {
559 _writeDataSet2DCollectiveWithCollectiveIO(group, name, values);
560 return;
561 }
562
563 UniqueArray<DataType> all_values;
564 IParallelMng* pm = m_mesh->parallelMng();
565 Span<const DataType> values_1d(values.data(), values.totalNbElement());
566 pm->gatherVariable(values_1d.smallView(), all_values, pm->masterIORank());
567 if (m_is_master_io) {
568 Int64 dim1_size = all_values.size();
569 if (dim2_size != 0)
570 dim1_size = dim1_size / dim2_size;
571 Span2<const DataType> span2(all_values.data(), dim1_size, dim2_size);
572 _writeDataSet2D<DataType>(group, name, span2);
573 }
574}
575
576/*---------------------------------------------------------------------------*/
577/*---------------------------------------------------------------------------*/
578
579void VtkHdfDataWriter::
580_addInt64ArrayAttribute(Hid& hid, const char* name, Span<const Int64> values)
581{
582 hsize_t len = values.size();
583 hid_t aid = H5Screate_simple(1, &len, 0);
584 hid_t attr = H5Acreate2(hid.id(), name, H5T_NATIVE_INT64, aid, H5P_DEFAULT, H5P_DEFAULT);
585 if (attr < 0)
586 ARCANE_FATAL("Can not create attribute '{0}'", name);
587 int ret = H5Awrite(attr, H5T_NATIVE_INT64, values.data());
588 if (ret < 0)
589 ARCANE_FATAL("Can not write attribute '{0}'", name);
590 H5Aclose(attr);
591 H5Sclose(aid);
592}
593
594/*---------------------------------------------------------------------------*/
595/*---------------------------------------------------------------------------*/
596
597void VtkHdfDataWriter::
598_addStringAttribute(Hid& hid, const char* name, const String& value)
599{
600 hid_t aid = H5Screate(H5S_SCALAR);
601 hid_t attr_type = H5Tcopy(H5T_C_S1);
602 H5Tset_size(attr_type, value.length());
603 hid_t attr = H5Acreate2(hid.id(), name, attr_type, aid, H5P_DEFAULT, H5P_DEFAULT);
604 if (attr < 0)
605 ARCANE_FATAL("Can not create attribute {0}", name);
606 int ret = H5Awrite(attr, attr_type, value.localstr());
607 ret = H5Tclose(attr_type);
608 if (ret < 0)
609 ARCANE_FATAL("Can not write attribute '{0}'", name);
610 H5Aclose(attr);
611 H5Sclose(aid);
612}
613
614/*---------------------------------------------------------------------------*/
615/*---------------------------------------------------------------------------*/
616
617void VtkHdfDataWriter::
618endWrite()
619{
620 m_cell_data_group.close();
621 m_node_data_group.close();
622 //top_group.close();
623 m_file_id.close();
624
625 // Ecrit le fichier contenant les temps (à partir de la version 5.5 de paraview)
626 // https://www.paraview.org/Wiki/ParaView_Release_Notes#JSON_based_new_meta_file_format_for_series_added
627 //
628 // Exemple:
629 // {
630 // "file-series-version" : "1.0",
631 // "files" : [
632 // { "name" : "foo1.vtk", "time" : 0 },
633 // { "name" : "foo2.vtk", "time" : 5.5 },
634 // { "name" : "foo3.vtk", "time" : 11.2 }
635 // ]
636 // }
637
638 if (!m_is_master_io)
639 return;
640
641 JSONWriter writer(JSONWriter::FormatFlags::None);
642 {
643 JSONWriter::Object o(writer);
644 writer.write("file-series-version", "1.0");
645 writer.writeKey("files");
646 writer.beginArray();
647 {
648 Integer file_index = 1;
649 for (Real v : m_times) {
650 JSONWriter::Object o(writer);
651 String filename = _getFileNameForTimeIndex(file_index);
652 writer.write("name", filename);
653 writer.write("time", v);
654 ++file_index;
655 }
656 writer.endArray();
657 }
658 }
659 Directory dir(m_directory_name);
660 String fname = dir.file(_getFileNameForTimeIndex(-1) + ".series");
661 std::ofstream ofile(fname.localstr());
662 StringView buf = writer.getBuffer();
663 ofile.write(reinterpret_cast<const char*>(buf.bytes().data()), buf.length());
664}
665
666/*---------------------------------------------------------------------------*/
667/*---------------------------------------------------------------------------*/
668
670setMetaData(const String& meta_data)
671{
672 ARCANE_UNUSED(meta_data);
673}
674
675/*---------------------------------------------------------------------------*/
676/*---------------------------------------------------------------------------*/
677
679write(IVariable* var, IData* data)
680{
681 info(4) << "Write VtkHdf var=" << var->name();
682
683 eItemKind item_kind = var->itemKind();
684
685 if (var->dimension() != 1)
686 ARCANE_FATAL("Only export of scalar item variable is implemented (name={0})", var->name());
687
688 HGroup* group = nullptr;
689 switch (item_kind) {
690 case IK_Cell:
691 group = &m_cell_data_group;
692 break;
693 case IK_Node:
694 group = &m_node_data_group;
695 break;
696 default:
697 ARCANE_FATAL("Only export of 'Cell' or 'Node' variable is implemented (name={0})", var->name());
698 }
700
701 eDataType data_type = var->dataType();
702 switch (data_type) {
703 case DT_Real:
704 _writeBasicTypeDataset<Real>(*group, var, data);
705 break;
706 case DT_Int64:
707 _writeBasicTypeDataset<Int64>(*group, var, data);
708 break;
709 case DT_Int32:
710 _writeBasicTypeDataset<Int32>(*group, var, data);
711 break;
712 case DT_Real3:
713 _writeReal3Dataset(*group, var, data);
714 break;
715 case DT_Real2:
716 _writeReal2Dataset(*group, var, data);
717 break;
718 default:
719 warning() << String::format("Export for datatype '{0}' is not supported (var_name={1})", data_type, var->name());
720 }
721}
722
723/*---------------------------------------------------------------------------*/
724/*---------------------------------------------------------------------------*/
725
726template <typename DataType> void VtkHdfDataWriter::
727_writeBasicTypeDataset(HGroup& group, IVariable* var, IData* data)
728{
729 auto* true_data = dynamic_cast<IArrayDataT<DataType>*>(data);
730 ARCANE_CHECK_POINTER(true_data);
731 _writeDataSet1DCollective(group, var->name(), Span<const DataType>(true_data->view()));
732}
733
734/*---------------------------------------------------------------------------*/
735/*---------------------------------------------------------------------------*/
736
737void VtkHdfDataWriter::
738_writeReal3Dataset(HGroup& group, IVariable* var, IData* data)
739{
740 auto* true_data = dynamic_cast<IArrayDataT<Real3>*>(data);
741 ARCANE_CHECK_POINTER(true_data);
742 SmallSpan<const Real3> values(true_data->view());
743 Int32 nb_value = values.size();
744 // TODO: optimiser cela sans passer par un tableau temporaire
745 UniqueArray2<Real> scalar_values;
746 scalar_values.resize(nb_value, 3);
747 for (Int32 i = 0; i < nb_value; ++i) {
748 Real3 v = values[i];
749 scalar_values[i][0] = v.x;
750 scalar_values[i][1] = v.y;
751 scalar_values[i][2] = v.z;
752 }
753 _writeDataSet2DCollective<Real>(group, var->name(), scalar_values);
754}
755
756/*---------------------------------------------------------------------------*/
757/*---------------------------------------------------------------------------*/
758
759void VtkHdfDataWriter::
760_writeReal2Dataset(HGroup& group, IVariable* var, IData* data)
761{
762 // Converti en un tableau de 3 composantes dont la dernière vaudra 0.
763 auto* true_data = dynamic_cast<IArrayDataT<Real2>*>(data);
764 ARCANE_CHECK_POINTER(true_data);
765 SmallSpan<const Real2> values(true_data->view());
766 Int32 nb_value = values.size();
767 UniqueArray2<Real> scalar_values;
768 scalar_values.resize(nb_value, 3);
769 for (Int32 i = 0; i < nb_value; ++i) {
770 Real2 v = values[i];
771 scalar_values[i][0] = v.x;
772 scalar_values[i][1] = v.y;
773 scalar_values[i][2] = 0.0;
774 }
775 _writeDataSet2DCollective<Real>(group, var->name(), scalar_values);
776}
777
778/*---------------------------------------------------------------------------*/
779/*---------------------------------------------------------------------------*/
780
781/*---------------------------------------------------------------------------*/
782/*---------------------------------------------------------------------------*/
783/*!
784 * \brief Post-traitement au format Ensight Hdf.
785 */
786class VtkHdfPostProcessor
787: public ArcaneVtkHdfPostProcessorObject
788{
789 public:
790
791 explicit VtkHdfPostProcessor(const ServiceBuildInfo& sbi)
792 : ArcaneVtkHdfPostProcessorObject(sbi)
793 {
794 }
795
796 IDataWriter* dataWriter() override { return m_writer.get(); }
797 void notifyBeginWrite() override
798 {
799 auto w = std::make_unique<VtkHdfDataWriter>(mesh(), groups());
800 w->setTimes(times());
801 Directory dir(baseDirectoryName());
802 w->setDirectoryName(dir.file("vtkhdf"));
803 m_writer = std::move(w);
804 }
805 void notifyEndWrite() override
806 {
807 m_writer = nullptr;
808 }
809 void close() override {}
810
811 private:
812
813 std::unique_ptr<IDataWriter> m_writer;
814};
815
816/*---------------------------------------------------------------------------*/
817/*---------------------------------------------------------------------------*/
818
819ARCANE_REGISTER_SERVICE_VTKHDFPOSTPROCESSOR(VtkHdfPostProcessor,
821
822/*---------------------------------------------------------------------------*/
823/*---------------------------------------------------------------------------*/
824
825} // namespace Arcane
826
827/*---------------------------------------------------------------------------*/
828/*---------------------------------------------------------------------------*/
#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_CELL(name, group)
Enumérateur générique d'un groupe de mailles.
#define ENUMERATE_NODE(name, group)
Enumérateur générique d'un groupe de noeuds.
Integer size() const
Nombre d'éléments du vecteur.
Classe gérant un répertoire.
Definition Directory.h:35
String file(const String &file_name) const override
Retourne le chemin complet du fichier file_name dans le répertoire.
Definition Directory.cc:120
Encapsule un hid_t pour un fichier.
Definition Hdf5Utils.h:256
Encapsule un hid_t pour un groupe.
Definition Hdf5Utils.h:327
static void useMutex(bool is_active, IParallelMng *pm)
Fonction permettant d'activer ou de désactiver les verrous à chaque appel à HDF5.
Definition Hdf5Utils.cc:118
static bool hasParallelHdf5()
Vrai HDF5 est compilé avec le support de MPI.
Definition Hdf5Utils.cc:105
Encapsule un hid_t.
Definition Hdf5Utils.h:147
Interface d'écriture des données d'une variable.
Definition IDataWriter.h:44
Interface d'une donnée.
Definition IData.h:33
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
Interface d'une variable.
Definition IVariable.h:39
virtual eDataType dataType() const =0
Type de la donnée gérée par la variable (Real, Integer, ...)
virtual eItemKind itemKind() const =0
Genre des entités du maillage sur lequel repose la variable.
virtual Integer dimension() const =0
Dimension de la variable.
virtual String name() const =0
Nom de la variable.
Integer size() const
Nombre d'éléments du groupe.
Definition ItemGroup.h:88
Structure contenant les informations pour créer un service.
Vue pour un tableau 2D dont la taille est un 'Int64'.
Definition Span2.h:301
Vue d'un tableau d'éléments de type T.
Definition Span.h:633
Constructeur de chaîne de caractère unicode.
String toString() const
Retourne la chaîne de caractères construite.
Chaîne de caractères unicode.
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessage info() const
Flot pour un message d'information.
TraceMessage warning() const
Flot pour un message d'avertissement.
TraceMessage pwarning() const
Vecteur 1D de données avec sémantique par valeur (style STL).
Collection de variables.
void setMetaData(const String &meta_data) override
Positionne les infos des méta-données.
void write(IVariable *var, IData *data) override
Ecrit les données data de la variable var.
Post-traitement au format Ensight Hdf.
ItemGroupT< Cell > CellGroup
Groupe de mailles.
Definition ItemTypes.h:183
ItemGroupT< Node > NodeGroup
Groupe de noeuds.
Definition ItemTypes.h:167
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
Integer len(const char *s)
Retourne la longueur de la chaîne s.
Fonctions utilitaires pour Hdf5.
Definition Hdf5Utils.cc:37
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Collection< ItemGroup > ItemGroupCollection
Collection de groupes d'éléments du maillage.
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
eItemKind
Genre d'entité de maillage.
@ IK_Node
Entité de maillage de genre noeud.
@ IK_Cell
Entité de maillage de genre maille.
double Real
Type représentant un réel.
unsigned char Byte
Type d'un octet.
Definition BaseTypes.h:43
eDataType
Type d'une donnée.
Definition DataTypes.h:39
@ DT_Int32
Donnée de type entier 32 bits.
Definition DataTypes.h:43
@ DT_Real3
Donnée de type vecteur 3.
Definition DataTypes.h:47
@ DT_Int64
Donnée de type entier 64 bits.
Definition DataTypes.h:44
@ DT_Real2
Donnée de type vecteur 2.
Definition DataTypes.h:46
@ DT_Real
Donnée de type réel.
Definition DataTypes.h:41
@ Cell
Le maillage est AMR par maille.
Definition MeshKind.h:52
std::int32_t Int32
Type entier signé sur 32 bits.
ConstArrayView< Real > RealConstArrayView
Equivalent C d'un tableau à une dimension de réels.
Definition UtilsTypes.h:488