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() <<
"L'implémentation au format 'VtkHdf' est expérimentale";
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);
435template <
typename DataType>
void VtkHdfDataWriter::
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);
446 Int64 total_size = 0;
447 for (
Integer i = 0; i < nb_rank; ++i)
448 total_size += all_sizes[i];
450 for (
Integer i = 0; i < my_rank; ++i)
451 my_index += all_sizes[i];
458 offset[0] = my_index;
460 count[0] = dim1_size;
461 count[1] = dim2_size;
464 dims[0] = total_size;
467 filespace_id.createSimple(2, dims);
469 memspace_id.createSimple(2, count);
472 const hid_t hdf_type = HDFTraits<DataType>::hdfType();
474 dataset_id.create(group, name.localstr(), hdf_type, filespace_id, H5P_DEFAULT);
476 H5Sselect_hyperslab(filespace_id.id(), H5S_SELECT_SET, offset, NULL, count, NULL);
478 HProperty write_plist_id;
479 write_plist_id.createDatasetTransfertCollectiveMPIIO();
481 herr_t herr = dataset_id.write(hdf_type, values.data(), memspace_id, filespace_id, write_plist_id);
484 ARCANE_THROW(IOException,
"Can not write dataset '{0}'", name);
490template <
typename DataType>
void VtkHdfDataWriter::
494 dims[0] = values.size();
496 hspace.createSimple(1, dims);
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());
502 ARCANE_THROW(IOException,
"Can not write dataset '{0}'", name);
508template <
typename DataType>
void VtkHdfDataWriter::
511 if (!m_is_parallel) {
512 _writeDataSet1D(group, name, values);
515 if (m_is_collective_io) {
516 _writeDataSet1DCollectiveWithCollectiveIO(group, name, values);
519 UniqueArray<DataType> all_values;
520 IParallelMng* pm = m_mesh->parallelMng();
521 pm->gatherVariable(values.smallView(), all_values, pm->masterIORank());
523 _writeDataSet1D<DataType>(group, name, all_values);
529template <
typename DataType>
void VtkHdfDataWriter::
533 dims[0] = values.dim1Size();
534 dims[1] = values.dim2Size();
536 hspace.createSimple(2, dims);
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());
542 ARCANE_THROW(IOException,
"Can not write dataset '{0}'", name);
548template <
typename DataType>
void VtkHdfDataWriter::
551 Int64 dim2_size = values.dim2Size();
553 if (!m_is_parallel) {
554 _writeDataSet2D(group, name, values);
558 if (m_is_collective_io) {
559 _writeDataSet2DCollectiveWithCollectiveIO(group, name, values);
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();
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);
579void VtkHdfDataWriter::
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);
587 int ret = H5Awrite(attr, H5T_NATIVE_INT64, values.data());
597void VtkHdfDataWriter::
598_addStringAttribute(
Hid& hid,
const char* name,
const String& value)
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);
606 int ret = H5Awrite(attr, attr_type, value.localstr());
607 ret = H5Tclose(attr_type);
617void VtkHdfDataWriter::
620 m_cell_data_group.close();
621 m_node_data_group.close();
641 JSONWriter writer(JSONWriter::FormatFlags::None);
643 JSONWriter::Object o(writer);
644 writer.write(
"file-series-version",
"1.0");
645 writer.writeKey(
"files");
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);
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());
672 ARCANE_UNUSED(meta_data);
681 info(4) <<
"Write VtkHdf var=" << var->
name();
686 ARCANE_FATAL(
"Only export of scalar item variable is implemented (name={0})", var->
name());
691 group = &m_cell_data_group;
694 group = &m_node_data_group;
697 ARCANE_FATAL(
"Only export of 'Cell' or 'Node' variable is implemented (name={0})", var->
name());
704 _writeBasicTypeDataset<Real>(*group, var, data);
707 _writeBasicTypeDataset<Int64>(*group, var, data);
710 _writeBasicTypeDataset<Int32>(*group, var, data);
713 _writeReal3Dataset(*group, var, data);
716 _writeReal2Dataset(*group, var, data);
719 warning() << String::format(
"Export for datatype '{0}' is not supported (var_name={1})", data_type, var->
name());
726template <
typename DataType>
void VtkHdfDataWriter::
737void VtkHdfDataWriter::
738_writeReal3Dataset(HGroup& group, IVariable* var, IData* data)
740 auto* true_data =
dynamic_cast<IArrayDataT<Real3>*
>(data);
742 SmallSpan<const Real3> values(true_data->view());
743 Int32 nb_value = values.size();
745 UniqueArray2<Real> scalar_values;
746 scalar_values.resize(nb_value, 3);
747 for (Int32 i = 0; i < nb_value; ++i) {
749 scalar_values[i][0] = v.x;
750 scalar_values[i][1] = v.y;
751 scalar_values[i][2] = v.z;
753 _writeDataSet2DCollective<Real>(group, var->name(), scalar_values);
759void VtkHdfDataWriter::
763 auto* true_data =
dynamic_cast<IArrayDataT<Real2>*
>(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) {
771 scalar_values[i][0] = v.x;
772 scalar_values[i][1] = v.y;
773 scalar_values[i][2] = 0.0;
775 _writeDataSet2DCollective<Real>(group, var->name(), scalar_values);
786class VtkHdfPostProcessor
787:
public ArcaneVtkHdfPostProcessorObject
792 : ArcaneVtkHdfPostProcessorObject(sbi)
796 IDataWriter* dataWriter()
override {
return m_writer.get(); }
797 void notifyBeginWrite()
override
799 auto w = std::make_unique<VtkHdfDataWriter>(mesh(), groups());
800 w->setTimes(times());
802 w->setDirectoryName(dir.
file(
"vtkhdf"));
803 m_writer = std::move(w);
805 void notifyEndWrite()
override
809 void close()
override {}
813 std::unique_ptr<IDataWriter> m_writer;
#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.
Integer size() const
Nombre d'éléments du vecteur.
Classe gérant un répertoire.
String file(const String &file_name) const override
Retourne le chemin complet du fichier file_name dans le répertoire.
Encapsule un hid_t pour un fichier.
Encapsule un hid_t pour un groupe.
static void useMutex(bool is_active, IParallelMng *pm)
Fonction permettant d'activer ou de désactiver les verrous à chaque appel à HDF5.
static bool hasParallelHdf5()
Vrai HDF5 est compilé avec le support de MPI.
Interface d'écriture des données d'une variable.
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
Interface d'une variable.
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.
Structure contenant les informations pour créer un service.
Vue pour un tableau 2D dont la taille est un 'Int64'.
Vue d'un tableau d'éléments de type T.
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.
Classe d'accès aux traces.
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).
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.
ItemGroupT< Node > NodeGroup
Groupe de noeuds.
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.
-*- 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.
eDataType
Type d'une donnée.
@ DT_Int32
Donnée de type entier 32 bits.
@ DT_Real3
Donnée de type vecteur 3.
@ DT_Int64
Donnée de type entier 64 bits.
@ DT_Real2
Donnée de type vecteur 2.
@ DT_Real
Donnée de type réel.
@ Cell
Le maillage est AMR par maille.
std::int32_t Int32
Type entier signé sur 32 bits.
ConstArrayView< Real > RealConstArrayView
Equivalent C d'un tableau à une dimension de réels.