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"
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"
34#include "arcane/hdf5/Hdf5Utils.h"
35#include "arcane/hdf5/VtkHdfPostProcessor_axl.h"
89 void endWrite()
override;
96 void setDirectoryName(
const String& dir_name) { m_directory_name = dir_name; }
119 bool m_is_parallel =
false;
120 bool m_is_master_io =
false;
121 bool m_is_collective_io =
false;
126 void _addStringAttribute(
Hid& hid,
const char* name,
const String& value);
128 template <
typename DataType>
void
130 template <
typename DataType>
void
132 template <
typename DataType>
void
134 template <
typename DataType>
void
136 template <
typename DataType>
void
141 template <
typename DataType>
void
143 template <
typename DataType>
void
172void VtkHdfDataWriter::
173beginWrite(
const VariableCollection& vars)
178 const Int32 nb_rank = pm->
commSize();
179 m_is_parallel = nb_rank > 1;
180 m_is_master_io = pm->isMasterIO();
182 Int32 time_index = m_times.
size();
183 const bool is_first_call = (time_index < 2);
185 pwarning() <<
"The 'VtkHdf' format implementation is experimental";
187 String filename = _getFileNameForTimeIndex(time_index);
189 Directory dir(m_directory_name);
191 m_full_filename = dir.file(filename);
192 info(4) <<
"VtkHdfDataWriter::beginWrite() file=" << m_full_filename;
204 if (pm->isHybridImplementation() || pm->isThreadImplementation())
205 m_is_collective_io =
false;
207 info() <<
"VtkHdfDataWriter: using collective MPI/IO ?=" << m_is_collective_io;
210 if (m_is_collective_io)
211 plist_id.createFilePropertyMPIIO(pm);
213 if (time_index <= 1) {
214 if (m_is_master_io) {
215 dir.createDirectory();
219 if (m_is_collective_io)
222 if (m_is_collective_io || m_is_master_io) {
223 m_file_id.openTruncate(m_full_filename, plist_id.id());
225 top_group.create(m_file_id,
"VTKHDF");
227 m_cell_data_group.create(top_group,
"CellData");
228 m_node_data_group.create(top_group,
"PointData");
230 std::array<Int64, 2> version = { 1, 0 };
231 _addInt64ArrayAttribute(top_group,
"Version", version);
232 _addStringAttribute(top_group,
"Type",
"UnstructuredGrid");
235 CellGroup all_cells = m_mesh->allCells();
236 NodeGroup all_nodes = m_mesh->allNodes();
239 const Int32 nb_node = all_nodes.size();
241 Int32 total_nb_connected_node = 0;
245 total_nb_connected_node += cell.nodeIds().size();
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);
258 Int32 connected_node_index = 0;
260 Int32 index = icell.index();
263 cells_uid[index] = icell->uniqueId();
266 bool is_ghost = !cell.isOwn();
268 ghost_type = VtkUtils::CellGhostTypes::DUPLICATECELL;
269 cells_ghost_type[index] = ghost_type;
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;
277 cells_offset[index + 1] = connected_node_index;
281 _writeDataSet1DCollective<Int64>(top_group,
"Offsets", cells_offset);
283 _writeDataSet1DCollective<Int64>(top_group,
"Connectivity", cells_connectivity);
284 _writeDataSet1DCollective<unsigned char>(top_group,
"Types", cells_type);
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);
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);
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);
302 UniqueArray<Int64> nodes_uid(nb_node);
303 UniqueArray<unsigned char> nodes_ghost_type(nb_node);
305 UniqueArray2<Real> points;
306 points.resize(nb_node, 3);
308 Int32 index = inode.index();
311 nodes_uid[index] = inode->uniqueId();
314 bool is_ghost = !node.isOwn();
316 ghost_type = VtkUtils::PointGhostTypes::DUPLICATEPOINT;
317 nodes_ghost_type[index] = ghost_type;
319 Real3 pos = nodes_coordinates[inode];
320 points[index][0] = pos.x;
321 points[index][1] = pos.y;
322 points[index][2] = pos.z;
326 _writeDataSet1DCollective<Int64>(m_node_data_group,
"GlobalNodeId", nodes_uid);
329 _writeDataSet1DCollective<unsigned char>(m_node_data_group,
"vtkGhostType", nodes_ghost_type);
332 _writeDataSet2DCollective<Real>(top_group,
"Points", points);
336 _writeDataSet1DCollective<Int64>(m_cell_data_group,
"GlobalCellId", cells_uid);
340 _writeDataSet1DCollective<unsigned char>(m_cell_data_group,
"vtkGhostType", cells_ghost_type);
348 template <
typename DataType>
class HDFTraits;
350 template <>
class HDFTraits<
Int64>
354 static hid_t hdfType() {
return H5T_NATIVE_INT64; }
357 template <>
class HDFTraits<
Int32>
361 static hid_t hdfType() {
return H5T_NATIVE_INT32; }
364 template <>
class HDFTraits<double>
368 static hid_t hdfType() {
return H5T_NATIVE_DOUBLE; }
371 template <>
class HDFTraits<unsigned char>
375 static hid_t hdfType() {
return H5T_NATIVE_UINT8; }
383template <
typename DataType>
void VtkHdfDataWriter::
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);
393 Int64 total_size = 0;
394 for (
Integer i = 0; i < nb_rank; ++i)
395 total_size += all_sizes[i];
397 for (
Integer i = 0; i < my_rank; ++i)
398 my_index += all_sizes[i];
405 offset[0] = my_index;
409 dims[0] = total_size;
411 filespace_id.createSimple(1, dims);
413 memspace_id.createSimple(1, count);
416 const hid_t hdf_type = HDFTraits<DataType>::hdfType();
418 dataset_id.create(group, name.localstr(), hdf_type, filespace_id, H5P_DEFAULT);
420 H5Sselect_hyperslab(filespace_id.id(), H5S_SELECT_SET, offset, NULL, count, NULL);
422 HProperty write_plist_id;
423 write_plist_id.createDatasetTransfertCollectiveMPIIO();
425 herr_t herr = dataset_id.write(hdf_type, values.data(), memspace_id, filespace_id, write_plist_id);
428 ARCANE_THROW(IOException,
"Can not write dataset '{0}'", name);
434template <
typename DataType>
void VtkHdfDataWriter::
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);
445 Int64 total_size = 0;
446 for (
Integer i = 0; i < nb_rank; ++i)
447 total_size += all_sizes[i];
449 for (
Integer i = 0; i < my_rank; ++i)
450 my_index += all_sizes[i];
457 offset[0] = my_index;
459 count[0] = dim1_size;
460 count[1] = dim2_size;
463 dims[0] = total_size;
466 filespace_id.createSimple(2, dims);
468 memspace_id.createSimple(2, count);
471 const hid_t hdf_type = HDFTraits<DataType>::hdfType();
473 dataset_id.create(group, name.localstr(), hdf_type, filespace_id, H5P_DEFAULT);
475 H5Sselect_hyperslab(filespace_id.id(), H5S_SELECT_SET, offset, NULL, count, NULL);
477 HProperty write_plist_id;
478 write_plist_id.createDatasetTransfertCollectiveMPIIO();
480 herr_t herr = dataset_id.write(hdf_type, values.data(), memspace_id, filespace_id, write_plist_id);
483 ARCANE_THROW(IOException,
"Can not write dataset '{0}'", name);
489template <
typename DataType>
void VtkHdfDataWriter::
493 dims[0] = values.size();
495 hspace.createSimple(1, dims);
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());
501 ARCANE_THROW(IOException,
"Can not write dataset '{0}'", name);
507template <
typename DataType>
void VtkHdfDataWriter::
510 if (!m_is_parallel) {
511 _writeDataSet1D(group, name, values);
514 if (m_is_collective_io) {
515 _writeDataSet1DCollectiveWithCollectiveIO(group, name, values);
518 UniqueArray<DataType> all_values;
519 IParallelMng* pm = m_mesh->parallelMng();
520 pm->gatherVariable(values.smallView(), all_values, pm->masterIORank());
522 _writeDataSet1D<DataType>(group, name, all_values);
528template <
typename DataType>
void VtkHdfDataWriter::
532 dims[0] = values.dim1Size();
533 dims[1] = values.dim2Size();
535 hspace.createSimple(2, dims);
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());
541 ARCANE_THROW(IOException,
"Can not write dataset '{0}'", name);
547template <
typename DataType>
void VtkHdfDataWriter::
550 Int64 dim2_size = values.dim2Size();
552 if (!m_is_parallel) {
553 _writeDataSet2D(group, name, values);
557 if (m_is_collective_io) {
558 _writeDataSet2DCollectiveWithCollectiveIO(group, name, values);
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();
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);
578void VtkHdfDataWriter::
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);
586 int ret = H5Awrite(attr, H5T_NATIVE_INT64, values.data());
596void VtkHdfDataWriter::
597_addStringAttribute(
Hid& hid,
const char* name,
const String& value)
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);
605 int ret = H5Awrite(attr, attr_type, value.localstr());
606 ret = H5Tclose(attr_type);
616void VtkHdfDataWriter::
619 m_cell_data_group.close();
620 m_node_data_group.close();
640 JSONWriter writer(JSONWriter::FormatFlags::None);
642 JSONWriter::Object o(writer);
643 writer.write(
"file-series-version",
"1.0");
644 writer.writeKey(
"files");
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);
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());
671 ARCANE_UNUSED(meta_data);
680 info(4) <<
"Write VtkHdf var=" << var->
name();
685 ARCANE_FATAL(
"Only export of scalar item variable is implemented (name={0})", var->
name());
690 group = &m_cell_data_group;
693 group = &m_node_data_group;
696 ARCANE_FATAL(
"Only export of 'Cell' or 'Node' variable is implemented (name={0})", var->
name());
703 _writeBasicTypeDataset<Real>(*group, var, data);
706 _writeBasicTypeDataset<Int64>(*group, var, data);
709 _writeBasicTypeDataset<Int32>(*group, var, data);
712 _writeReal3Dataset(*group, var, data);
715 _writeReal2Dataset(*group, var, data);
718 warning() << String::format(
"Export for datatype '{0}' is not supported (var_name={1})", data_type, var->
name());
725template <
typename DataType>
void VtkHdfDataWriter::
736void VtkHdfDataWriter::
737_writeReal3Dataset(HGroup& group, IVariable* var, IData* data)
739 auto* true_data =
dynamic_cast<IArrayDataT<Real3>*
>(data);
741 SmallSpan<const Real3> values(true_data->view());
742 Int32 nb_value = values.size();
744 UniqueArray2<Real> scalar_values;
745 scalar_values.resize(nb_value, 3);
746 for (Int32 i = 0; i < nb_value; ++i) {
748 scalar_values[i][0] = v.x;
749 scalar_values[i][1] = v.y;
750 scalar_values[i][2] = v.z;
752 _writeDataSet2DCollective<Real>(group, var->name(), scalar_values);
758void VtkHdfDataWriter::
762 auto* true_data =
dynamic_cast<IArrayDataT<Real2>*
>(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) {
770 scalar_values[i][0] = v.x;
771 scalar_values[i][1] = v.y;
772 scalar_values[i][2] = 0.0;
774 _writeDataSet2DCollective<Real>(group, var->name(), scalar_values);
785class VtkHdfPostProcessor
786:
public ArcaneVtkHdfPostProcessorObject
791 : ArcaneVtkHdfPostProcessorObject(sbi)
795 IDataWriter* dataWriter()
override {
return m_writer.get(); }
796 void notifyBeginWrite()
override
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);
804 void notifyEndWrite()
override
808 void close()
override {}
812 std::unique_ptr<IDataWriter> m_writer;
#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.
Integer size() const
Number of elements in the vector.
Class managing a directory.
String file(const String &file_name) const override
Returns the full path of the file file_name in the directory.
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.
static constexpr bool hasParallelHdf5()
True HDF5 is compiled with MPI support.
Interface for writing variable data.
Interface of a data item.
virtual IParallelMng * parallelMng()=0
Parallelism manager.
virtual Int32 commSize() const =0
Number of instances in the communicator.
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.
Structure containing the information to create a service.
View for a 2D array whose size is an 'Int64'.
View of an array of elements of type T.
Unicode character string constructor.
String toString() const
Returns the constructed character string.
Unicode character string.
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).
void setMetaData(const String &meta_data) override
Sets the metadata information.
void write(IVariable *var, IData *data) override
Writes the data data of the variable var.
Post-processing in Ensight Hdf format.
ItemGroupT< Cell > CellGroup
Group of cells.
ItemGroupT< Node > NodeGroup
Group of nodes.
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.
-- 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.
@ DT_Int32
32-bit integer data type
@ DT_Real3
Vector 3 data type.
@ DT_Int64
64-bit integer data type
@ DT_Real2
Vector 2 data type.
@ Cell
The mesh is AMR by cell.
std::int32_t Int32
Signed integer type of 32 bits.
ConstArrayView< Real > RealConstArrayView
C equivalent of a 1D array of reals.