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;
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
154 return sb.toString();
172void VtkHdfDataWriter::
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();
183 const bool is_first_call = (time_index < 2);
185 pwarning() <<
"The 'VtkHdf' format implementation is experimental";
187 String filename = _getFileNameForTimeIndex(time_index);
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) {
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");
649 JSONWriter::Object o(writer);
650 String filename = _getFileNameForTimeIndex(file_index);
651 writer.write(
"name", filename);
652 writer.write(
"time", v);
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
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);
812 std::unique_ptr<IDataWriter> m_writer;
818ARCANE_REGISTER_SERVICE_VTKHDFPOSTPROCESSOR(VtkHdfPostProcessor,
819 VtkHdfPostProcessor);
#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.
ArcaneVtkHdfPostProcessorObject(const Arcane::ServiceBuildInfo &sbi)
Constructeur.
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 of a 1D array data item of type T.
Interface for writing variable data.
Interface of a data item.
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.
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'.
View of an array of elements of type T.
Unicode character string constructor.
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).
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.
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.