Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
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/* Post-processing in VTK HDF format. */
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// This format is described on the following webpage:
38//
39// https://kitware.github.io/vtk-examples/site/VTKFileFormats/#hdf-file-formats
40
41/*---------------------------------------------------------------------------*/
42/*---------------------------------------------------------------------------*/
43
44// TODO: Look into saving uniqueId() (via vtkOriginalCellIds)
45// TODO: Look into how to avoid saving the mesh in every iteration if it
46// doesn't change. With the concept of HDF5 linking, it should be possible
47// to store this information elsewhere and only save the mesh
48// if it evolves.
49// TODO: Look into compression
50
51/*
52 NOTE on parallel implementation
53
54 The current implementation is very basic.
55 Only the master rank (rank 0 generally) performs the outputs. For
56 each dataset, this rank performs a gather to retrieve the information. This
57 therefore assumes that everyone has the same variables and in the same order
58 (normally this is always the case because it is sorted by the VariableMng).
59
60 This implementation therefore works regardless of the message exchange mode
61 used (full MPI, shared memory, or hybrid).
62
63 TODO: Decouple the writing from variable management to be able to use
64 HDF5 collective operations (if compiled with MPI). In this case, it
65 is still necessary to manually manage the message exchange mode in shared memory
66 or hybrid.
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
104
107
110
113
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() << "The 'VtkHdf' format implementation is experimental";
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: protect concurrent HDF5 calls
200 // It is possible to use HDF5 collective mode via MPI-IO in the following cases:
201 // - Hdf5 was compiled with MPI
202 // - we are in pure MPI mode (neither shared memory mode nor hybrid mode)
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 // For connectivities, the array size is equal
250 // to the number of cells 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 // Save the uniqueIds, types, and coordinates of the nodes.
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 // Save the uniqueId of each node in the "GlobalNodeId" dataset.
326 _writeDataSet1DCollective<Int64>(m_node_data_group, "GlobalNodeId", nodes_uid);
327
328 // Save the information about the node type (real or ghost).
329 _writeDataSet1DCollective<unsigned char>(m_node_data_group, "vtkGhostType", nodes_ghost_type);
330
331 // Save the coordinates of the nodes.
332 _writeDataSet2DCollective<Real>(top_group, "Points", points);
333 }
334
335 // Save the information about the cell type (real or ghost)
336 _writeDataSet1DCollective<Int64>(m_cell_data_group, "GlobalCellId", cells_uid);
337
338 // Save the uniqueId of each cell in the "GlobalCellId" dataset.
339 // The use of the "vtkOriginalCellIds" dataset does not work in 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
434template <typename DataType> void VtkHdfDataWriter::
435_writeDataSet2DCollectiveWithCollectiveIO(HGroup& group, const String& name, Span2<const DataType> values)
436{
437 IParallelMng* pm = m_mesh->parallelMng();
438 Int64 dim1_size = values.dim1Size();
439 Int64 dim2_size = values.dim2Size();
440 Int32 nb_rank = pm->commSize();
441 Int32 my_rank = pm->commRank();
442 UniqueArray<Int64> all_sizes(nb_rank);
443 pm->allGather(ConstArrayView<Int64>(1, &dim1_size), all_sizes);
444
445 Int64 total_size = 0;
446 for (Integer i = 0; i < nb_rank; ++i)
447 total_size += all_sizes[i];
448 Int64 my_index = 0;
449 for (Integer i = 0; i < my_rank; ++i)
450 my_index += all_sizes[i];
451 //m_variables_offset.insert(std::make_pair(v->fullName(), VarOffset(my_index, total_size, all_sizes)));
452 //info() << " ADD OFFSET v=" << v->fullName() << " offset=" << my_index
453 // << " total_size=" << total_size;
454
455 hsize_t offset[2];
456 hsize_t count[2];
457 offset[0] = my_index;
458 offset[1] = 0;
459 count[0] = dim1_size;
460 count[1] = dim2_size;
461
462 hsize_t dims[2];
463 dims[0] = total_size;
464 dims[1] = dim2_size;
465 HSpace filespace_id;
466 filespace_id.createSimple(2, dims);
467 HSpace memspace_id;
468 memspace_id.createSimple(2, count);
469
470 HDataset dataset_id;
471 const hid_t hdf_type = HDFTraits<DataType>::hdfType();
472
473 dataset_id.create(group, name.localstr(), hdf_type, filespace_id, H5P_DEFAULT);
474
475 H5Sselect_hyperslab(filespace_id.id(), H5S_SELECT_SET, offset, NULL, count, NULL);
476
477 HProperty write_plist_id;
478 write_plist_id.createDatasetTransfertCollectiveMPIIO();
479
480 herr_t herr = dataset_id.write(hdf_type, values.data(), memspace_id, filespace_id, write_plist_id);
481
482 if (herr < 0)
483 ARCANE_THROW(IOException, "Can not write dataset '{0}'", name);
484}
485
486/*---------------------------------------------------------------------------*/
487/*---------------------------------------------------------------------------*/
488
489template <typename DataType> void VtkHdfDataWriter::
490_writeDataSet1D(HGroup& group, const String& name, Span<const DataType> values)
491{
492 hsize_t dims[1];
493 dims[0] = values.size();
494 HSpace hspace;
495 hspace.createSimple(1, dims);
496 HDataset dataset;
497 const hid_t hdf_type = HDFTraits<DataType>::hdfType();
498 dataset.create(group, name.localstr(), hdf_type, hspace, H5P_DEFAULT);
499 dataset.write(hdf_type, values.data());
500 if (dataset.isBad())
501 ARCANE_THROW(IOException, "Can not write dataset '{0}'", name);
502}
503
504/*---------------------------------------------------------------------------*/
505/*---------------------------------------------------------------------------*/
506
507template <typename DataType> void VtkHdfDataWriter::
508_writeDataSet1DCollective(HGroup& group, const String& name, Span<const DataType> values)
509{
510 if (!m_is_parallel) {
511 _writeDataSet1D(group, name, values);
512 return;
513 }
514 if (m_is_collective_io) {
515 _writeDataSet1DCollectiveWithCollectiveIO(group, name, values);
516 return;
517 }
518 UniqueArray<DataType> all_values;
519 IParallelMng* pm = m_mesh->parallelMng();
520 pm->gatherVariable(values.smallView(), all_values, pm->masterIORank());
521 if (m_is_master_io)
522 _writeDataSet1D<DataType>(group, name, all_values);
523}
524
525/*---------------------------------------------------------------------------*/
526/*---------------------------------------------------------------------------*/
527
528template <typename DataType> void VtkHdfDataWriter::
529_writeDataSet2D(HGroup& group, const String& name, Span2<const DataType> values)
530{
531 hsize_t dims[2];
532 dims[0] = values.dim1Size();
533 dims[1] = values.dim2Size();
534 HSpace hspace;
535 hspace.createSimple(2, dims);
536 HDataset dataset;
537 const hid_t hdf_type = HDFTraits<DataType>::hdfType();
538 dataset.create(group, name.localstr(), hdf_type, hspace, H5P_DEFAULT);
539 dataset.write(hdf_type, values.data());
540 if (dataset.isBad())
541 ARCANE_THROW(IOException, "Can not write dataset '{0}'", name);
542}
543
544/*---------------------------------------------------------------------------*/
545/*---------------------------------------------------------------------------*/
546
547template <typename DataType> void VtkHdfDataWriter::
548_writeDataSet2DCollective(HGroup& group, const String& name, Span2<const DataType> values)
549{
550 Int64 dim2_size = values.dim2Size();
551
552 if (!m_is_parallel) {
553 _writeDataSet2D(group, name, values);
554 return;
555 }
556
557 if (m_is_collective_io) {
558 _writeDataSet2DCollectiveWithCollectiveIO(group, name, values);
559 return;
560 }
561
562 UniqueArray<DataType> all_values;
563 IParallelMng* pm = m_mesh->parallelMng();
564 Span<const DataType> values_1d(values.data(), values.totalNbElement());
565 pm->gatherVariable(values_1d.smallView(), all_values, pm->masterIORank());
566 if (m_is_master_io) {
567 Int64 dim1_size = all_values.size();
568 if (dim2_size != 0)
569 dim1_size = dim1_size / dim2_size;
570 Span2<const DataType> span2(all_values.data(), dim1_size, dim2_size);
571 _writeDataSet2D<DataType>(group, name, span2);
572 }
573}
574
575/*---------------------------------------------------------------------------*/
576/*---------------------------------------------------------------------------*/
577
578void VtkHdfDataWriter::
579_addInt64ArrayAttribute(Hid& hid, const char* name, Span<const Int64> values)
580{
581 hsize_t len = values.size();
582 hid_t aid = H5Screate_simple(1, &len, 0);
583 hid_t attr = H5Acreate2(hid.id(), name, H5T_NATIVE_INT64, aid, H5P_DEFAULT, H5P_DEFAULT);
584 if (attr < 0)
585 ARCANE_FATAL("Can not create attribute '{0}'", name);
586 int ret = H5Awrite(attr, H5T_NATIVE_INT64, values.data());
587 if (ret < 0)
588 ARCANE_FATAL("Can not write attribute '{0}'", name);
589 H5Aclose(attr);
590 H5Sclose(aid);
591}
592
593/*---------------------------------------------------------------------------*/
594/*---------------------------------------------------------------------------*/
595
596void VtkHdfDataWriter::
597_addStringAttribute(Hid& hid, const char* name, const String& value)
598{
599 hid_t aid = H5Screate(H5S_SCALAR);
600 hid_t attr_type = H5Tcopy(H5T_C_S1);
601 H5Tset_size(attr_type, value.length());
602 hid_t attr = H5Acreate2(hid.id(), name, attr_type, aid, H5P_DEFAULT, H5P_DEFAULT);
603 if (attr < 0)
604 ARCANE_FATAL("Can not create attribute {0}", name);
605 int ret = H5Awrite(attr, attr_type, value.localstr());
606 ret = H5Tclose(attr_type);
607 if (ret < 0)
608 ARCANE_FATAL("Can not write attribute '{0}'", name);
609 H5Aclose(attr);
610 H5Sclose(aid);
611}
612
613/*---------------------------------------------------------------------------*/
614/*---------------------------------------------------------------------------*/
615
616void VtkHdfDataWriter::
617endWrite()
618{
619 m_cell_data_group.close();
620 m_node_data_group.close();
621 //top_group.close();
622 m_file_id.close();
623
624 // Writes the file containing the times (starting from ParaView version 5.5)
625 // https://www.paraview.org/Wiki/ParaView_Release_Notes#JSON_based_new_meta_file_format_for_series_added
626 //
627 // Example:
628 // {
629 // "file-series-version" : "1.0",
630 // "files" : [
631 // { "name" : "foo1.vtk", "time" : 0 },
632 // { "name" : "foo2.vtk", "time" : 5.5 },
633 // { "name" : "foo3.vtk", "time" : 11.2 }
634 // ]
635 // }
636
637 if (!m_is_master_io)
638 return;
639
640 JSONWriter writer(JSONWriter::FormatFlags::None);
641 {
642 JSONWriter::Object o(writer);
643 writer.write("file-series-version", "1.0");
644 writer.writeKey("files");
645 writer.beginArray();
646 {
647 Integer file_index = 1;
648 for (Real v : m_times) {
649 JSONWriter::Object o(writer);
650 String filename = _getFileNameForTimeIndex(file_index);
651 writer.write("name", filename);
652 writer.write("time", v);
653 ++file_index;
654 }
655 writer.endArray();
656 }
657 }
658 Directory dir(m_directory_name);
659 String fname = dir.file(_getFileNameForTimeIndex(-1) + ".series");
660 std::ofstream ofile(fname.localstr());
661 StringView buf = writer.getBuffer();
662 ofile.write(reinterpret_cast<const char*>(buf.bytes().data()), buf.length());
663}
664
665/*---------------------------------------------------------------------------*/
666/*---------------------------------------------------------------------------*/
667
669setMetaData(const String& meta_data)
670{
671 ARCANE_UNUSED(meta_data);
672}
673
674/*---------------------------------------------------------------------------*/
675/*---------------------------------------------------------------------------*/
676
678write(IVariable* var, IData* data)
679{
680 info(4) << "Write VtkHdf var=" << var->name();
681
682 eItemKind item_kind = var->itemKind();
683
684 if (var->dimension() != 1)
685 ARCANE_FATAL("Only export of scalar item variable is implemented (name={0})", var->name());
686
687 HGroup* group = nullptr;
688 switch (item_kind) {
689 case IK_Cell:
690 group = &m_cell_data_group;
691 break;
692 case IK_Node:
693 group = &m_node_data_group;
694 break;
695 default:
696 ARCANE_FATAL("Only export of 'Cell' or 'Node' variable is implemented (name={0})", var->name());
697 }
699
700 eDataType data_type = var->dataType();
701 switch (data_type) {
702 case DT_Real:
703 _writeBasicTypeDataset<Real>(*group, var, data);
704 break;
705 case DT_Int64:
706 _writeBasicTypeDataset<Int64>(*group, var, data);
707 break;
708 case DT_Int32:
709 _writeBasicTypeDataset<Int32>(*group, var, data);
710 break;
711 case DT_Real3:
712 _writeReal3Dataset(*group, var, data);
713 break;
714 case DT_Real2:
715 _writeReal2Dataset(*group, var, data);
716 break;
717 default:
718 warning() << String::format("Export for datatype '{0}' is not supported (var_name={1})", data_type, var->name());
719 }
720}
721
722/*---------------------------------------------------------------------------*/
723/*---------------------------------------------------------------------------*/
724
725template <typename DataType> void VtkHdfDataWriter::
726_writeBasicTypeDataset(HGroup& group, IVariable* var, IData* data)
727{
728 auto* true_data = dynamic_cast<IArrayDataT<DataType>*>(data);
729 ARCANE_CHECK_POINTER(true_data);
730 _writeDataSet1DCollective(group, var->name(), Span<const DataType>(true_data->view()));
731}
732
733/*---------------------------------------------------------------------------*/
734/*---------------------------------------------------------------------------*/
735
736void VtkHdfDataWriter::
737_writeReal3Dataset(HGroup& group, IVariable* var, IData* data)
738{
739 auto* true_data = dynamic_cast<IArrayDataT<Real3>*>(data);
740 ARCANE_CHECK_POINTER(true_data);
741 SmallSpan<const Real3> values(true_data->view());
742 Int32 nb_value = values.size();
743 // TODO: optimize this without passing through a temporary array
744 UniqueArray2<Real> scalar_values;
745 scalar_values.resize(nb_value, 3);
746 for (Int32 i = 0; i < nb_value; ++i) {
747 Real3 v = values[i];
748 scalar_values[i][0] = v.x;
749 scalar_values[i][1] = v.y;
750 scalar_values[i][2] = v.z;
751 }
752 _writeDataSet2DCollective<Real>(group, var->name(), scalar_values);
753}
754
755/*---------------------------------------------------------------------------*/
756/*---------------------------------------------------------------------------*/
757
758void VtkHdfDataWriter::
759_writeReal2Dataset(HGroup& group, IVariable* var, IData* data)
760{
761 // Convert to an array of 3 components where the last one will be 0.
762 auto* true_data = dynamic_cast<IArrayDataT<Real2>*>(data);
763 ARCANE_CHECK_POINTER(true_data);
764 SmallSpan<const Real2> values(true_data->view());
765 Int32 nb_value = values.size();
766 UniqueArray2<Real> scalar_values;
767 scalar_values.resize(nb_value, 3);
768 for (Int32 i = 0; i < nb_value; ++i) {
769 Real2 v = values[i];
770 scalar_values[i][0] = v.x;
771 scalar_values[i][1] = v.y;
772 scalar_values[i][2] = 0.0;
773 }
774 _writeDataSet2DCollective<Real>(group, var->name(), scalar_values);
775}
776
777/*---------------------------------------------------------------------------*/
778/*---------------------------------------------------------------------------*/
779
780/*---------------------------------------------------------------------------*/
781/*---------------------------------------------------------------------------*/
785class VtkHdfPostProcessor
787{
788 public:
789
790 explicit VtkHdfPostProcessor(const ServiceBuildInfo& sbi)
792 {
793 }
794
795 IDataWriter* dataWriter() override { return m_writer.get(); }
796 void notifyBeginWrite() override
797 {
798 auto w = std::make_unique<VtkHdfDataWriter>(mesh(), groups());
799 w->setTimes(times());
801 w->setDirectoryName(dir.file("vtkhdf"));
802 m_writer = std::move(w);
803 }
804 void notifyEndWrite() override
805 {
806 m_writer = nullptr;
807 }
808 void close() override {}
809
810 private:
811
812 std::unique_ptr<IDataWriter> m_writer;
813};
814
815/*---------------------------------------------------------------------------*/
816/*---------------------------------------------------------------------------*/
817
818ARCANE_REGISTER_SERVICE_VTKHDFPOSTPROCESSOR(VtkHdfPostProcessor,
819 VtkHdfPostProcessor);
820
821/*---------------------------------------------------------------------------*/
822/*---------------------------------------------------------------------------*/
823
824} // namespace Arcane
825
826/*---------------------------------------------------------------------------*/
827/*---------------------------------------------------------------------------*/
#define ARCANE_CHECK_POINTER(ptr)
Macro returning the pointer ptr if it is not null or throwing an exception if it is null.
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ENUMERATE_CELL(name, group)
Generic enumerator for a cell group.
#define ENUMERATE_NODE(name, group)
Generic enumerator for a node group.
ArcaneVtkHdfPostProcessorObject(const Arcane::ServiceBuildInfo &sbi)
Constructeur.
Class managing a directory.
Definition Directory.h:36
String file(const String &file_name) const override
Returns the full path of the file file_name in the directory.
Definition Directory.cc:120
Encapsulates a hid_t for a file.
Encapsulates a hid_t for a group.
static void useMutex(bool is_active, IParallelMng *pm)
Function allowing activation or deactivation of locks on each HDF5 call.
Definition Hdf5Utils.cc:89
static constexpr bool hasParallelHdf5()
True HDF5 is compiled with MPI support.
Encapsulates a hid_t.
Interface of a 1D array data item of type T.
Definition IData.h:300
Interface for writing variable data.
Definition IDataWriter.h:45
Interface of a data item.
Definition IData.h:34
Interface of a variable.
Definition IVariable.h:40
virtual eDataType dataType() const =0
Data type managed by the variable (Real, Integer, ...).
virtual eItemKind itemKind() const =0
Kind of mesh entities on which the variable is based.
virtual Integer dimension() const =0
Dimension of the variable.
virtual String name() const =0
Variable name.
Integer size() const
Number of elements in the group.
Definition ItemGroup.h:93
ItemGroupCollection groups() override
List of groups to save.
ConstArrayView< Real > times() override
List of saved times.
const String & baseDirectoryName() override
Name of the output directory for files.
Structure containing the information to create a service.
View for a 2D array whose size is an 'Int64'.
Definition Span2.h:324
View of an array of elements of type T.
Definition Span.h:635
Unicode character string constructor.
TraceAccessor(ITraceMng *m)
Constructs an accessor via the trace manager m.
TraceMessage info() const
Flow for an information message.
TraceMessage warning() const
Flow for a warning message.
TraceMessage pwarning() const
1D data vector with value semantics (STL style).
String m_directory_name
Output directory.
ItemGroupCollection m_groups
List of groups to save.
void setMetaData(const String &meta_data) override
Sets the metadata information.
UniqueArray< Real > m_times
List of times.
HFile m_file_id
HDF file identifier.
String m_full_filename
Current HDF file name.
void write(IVariable *var, IData *data) override
Writes the data data of the variable var.
void close() override
Closes the writer. After closing, it can no longer be used.
IDataWriter * dataWriter() override
Returns the writer associated with this post-processor.
void notifyEndWrite() override
Notifies that an output has just been performed.
void notifyBeginWrite() override
Notifies that an output is going to be performed with the current parameters.
ItemGroupT< Cell > CellGroup
Group of cells.
Definition ItemTypes.h:184
ItemGroupT< Node > NodeGroup
Group of nodes.
Definition ItemTypes.h:168
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Coordinate type quantity at node.
Integer len(const char *s)
Returns the length of the string s.
Utility functions for Hdf5.
Definition Hdf5Utils.cc:34
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Collection< ItemGroup > ItemGroupCollection
Collection of mesh item groups.
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
eItemKind
Mesh entity type.
@ IK_Node
Node mesh entity.
@ IK_Cell
Cell mesh entity.
double Real
Type representing a real number.
unsigned char Byte
Type of a byte.
Definition BaseTypes.h:43
eDataType
Data type.
Definition DataTypes.h:41
@ DT_Int32
32-bit integer data type
Definition DataTypes.h:45
@ DT_Real3
Vector 3 data type.
Definition DataTypes.h:49
@ DT_Int64
64-bit integer data type
Definition DataTypes.h:46
@ DT_Real2
Vector 2 data type.
Definition DataTypes.h:48
@ DT_Real
Real data type.
Definition DataTypes.h:43
@ Cell
The mesh is AMR by cell.
Definition MeshKind.h:53
std::int32_t Int32
Signed integer type of 32 bits.
ConstArrayView< Real > RealConstArrayView
C equivalent of a 1D array of reals.
Definition UtilsTypes.h:488