Arcane  4.1.12.0
User documentation
Loading...
Searching...
No Matches
Hdf5ReaderWriter.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/* Hdf5ReaderWriter.cc (C) 2000-2026 */
9/* */
10/* Reading/Writing in HDF5 format. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/String.h"
15#include "arcane/utils/StringBuilder.h"
16#include "arcane/utils/OStringStream.h"
17#include "arcane/utils/ScopedPtr.h"
18#include "arcane/utils/List.h"
19#include "arcane/utils/ITraceMng.h"
20#include "arcane/utils/CheckedConvert.h"
21#include "arcane/utils/ArrayShape.h"
22
23#include "arcane/core/ISubDomain.h"
24#include "arcane/core/StdNum.h"
25#include "arcane/core/IVariable.h"
26#include "arcane/core/CheckpointService.h"
27#include "arcane/core/Directory.h"
28#include "arcane/core/IParallelMng.h"
29#include "arcane/core/IParallelReplication.h"
30#include "arcane/core/ArcaneException.h"
31#include "arcane/core/VerifierService.h"
32#include "arcane/core/IVariableMng.h"
33#include "arcane/core/FactoryService.h"
34#include "arcane/core/IData.h"
35#include "arcane/core/Timer.h"
36#include "arcane/core/ISerializedData.h"
37#include "arcane/core/IIOMng.h"
38#include "arcane/core/IXmlDocumentHolder.h"
39
40#include "arcane/datatype/DataTypeTraits.h"
41
42#include "arcane/core/SerializeBuffer.h"
43#include "arcane/core/ISerializeMessageList.h"
44#include "arcane/core/internal/SerializeMessage.h"
45
46#include "arcane/hdf5/Hdf5ReaderWriter.h"
47
48#include "arcane/hdf5/Hdf5ReaderWriter_axl.h"
49
50#include <array>
51//#define ARCANE_TEST_HDF5MPI
52
53/*---------------------------------------------------------------------------*/
54/*---------------------------------------------------------------------------*/
55
56namespace Arcane
57{
58
59/*---------------------------------------------------------------------------*/
60/*---------------------------------------------------------------------------*/
61
62using namespace Hdf5Utils;
63
64static herr_t _Hdf5ReaderWriterIterateMe(hid_t, const char*, void*);
65
66/*---------------------------------------------------------------------------*/
67/*---------------------------------------------------------------------------*/
68
69namespace
70{
71 constexpr Int32 VARIABLE_INFO_SIZE = 10 + ArrayShape::MAX_NB_DIMENSION;
72
73#if (defined(H5_HAVE_THREADSAFE) || defined(H5_HAVE_CONCURRENCY))
74#define ARCANE_HDF5_MUTEX
75#else
76 struct ScopedMutex
77 {
78 ScopedMutex()
79 {
80 _ArcaneHdf5UtilsMutex().lock();
81 }
82 ~ScopedMutex()
83 {
84 _ArcaneHdf5UtilsMutex().unlock();
85 }
86 };
87#define ARCANE_HDF5_MUTEX ScopedMutex scoped_mutex
88#endif
89} // namespace
90
91/*---------------------------------------------------------------------------*/
92/*---------------------------------------------------------------------------*/
93
94Hdf5ReaderWriter::
95Hdf5ReaderWriter(ISubDomain* sd, const String& filename,
96 const String& sub_group_name,
97 Integer fileset_size, Integer currentIndex, Integer index_modulo,
98 eOpenMode open_mode, [[maybe_unused]] bool do_verif)
99: TraceAccessor(sd->traceMng())
100, m_parallel_mng(sd->parallelMng())
101, m_open_mode(open_mode)
102, m_filename(filename)
103, m_sub_group_name(sub_group_name)
104, m_is_initialized(false)
105, m_io_timer(sd, "Hdf5Timer", Timer::TimerReal)
106, m_is_parallel(false)
107, m_my_rank(m_parallel_mng->commRank())
108, m_send_rank(m_my_rank)
109, m_last_recv_rank(m_my_rank)
110, m_fileset_size(fileset_size)
111, m_index_write(currentIndex)
112, m_index_modulo(index_modulo)
113{
114
115 if (m_fileset_size != 1 && m_parallel_mng->isParallel()) {
116 m_is_parallel = true;
117 Integer nb_rank = m_parallel_mng->commSize();
118 if (m_fileset_size == 0) {
119 m_send_rank = 0;
120 m_last_recv_rank = nb_rank;
121 }
122 else {
123 m_send_rank = (m_my_rank / m_fileset_size) * m_fileset_size;
124 m_last_recv_rank = m_send_rank + m_fileset_size;
125 if (m_last_recv_rank > nb_rank)
126 m_last_recv_rank = nb_rank;
127 --m_last_recv_rank;
128 }
129 }
130 sd->traceMng()->info() << " INFOS PARALLEL: my_rank=" << m_my_rank
131 << " send_rank=" << m_send_rank
132 << " last_recv_rank=" << m_last_recv_rank
133 << " filename=" << filename;
134}
135
136/*---------------------------------------------------------------------------*/
137/*---------------------------------------------------------------------------*/
138void Hdf5ReaderWriter::
139initialize()
140{
141 if (m_is_initialized)
142 return;
143 m_is_initialized = true;
144
145 HInit();
146 HInit::useMutex(m_parallel_mng->isThreadImplementation(), m_parallel_mng);
147
148 info() << "INIT HDF5 READER/WRITER";
149 {
150 unsigned vmajor = 0;
151 unsigned vminor = 0;
152 unsigned vrel = 0;
153 ARCANE_HDF5_MUTEX;
154 ::H5get_libversion(&vmajor, &vminor, &vrel);
155 info() << "HDF5 version = " << vmajor << '.' << vminor << '.' << vrel;
156 }
157 info() << "SubGroup is '" << m_sub_group_name << "'";
158 if (m_open_mode == OpenModeRead) {
159 m_file_id.openRead(m_filename);
160 m_sub_group_id.recursiveOpen(m_file_id, m_sub_group_name);
161 }
162 else {
163 // If I am not the one writing, do not open the file
164 if (m_send_rank != m_my_rank)
165 return;
166 if (m_open_mode == OpenModeTruncate) {
167 hid_t plist_id = -1;
168 {
169 ARCANE_HDF5_MUTEX;
170 plist_id = H5Pcreate(H5P_FILE_ACCESS);
171#ifdef ARCANE_TEST_HDF5MPI
172 void* arcane_comm = subDomain()->parallelMng()->getMPICommunicator();
173 if (!arcane_comm)
174 ARCANE_FATAL("No MPI environment available");
175 MPI_Comm mpi_comm = *((MPI_Comm*)arcane_comm);
176 MPI_Info mpi_info = MPI_INFO_NULL;
177 //H5Pset_fapl_mpiposix(plist_id, mpi_comm, MPI_INFO_NULL); //mpi_info);
178 H5Pset_fapl_mpio(plist_id, mpi_comm, MPI_INFO_NULL); //mpi_info);
179 H5Pset_fclose_degree(plist_id, H5F_CLOSE_STRONG);
180#endif
181 int mdc_nelmts;
182 size_t rdcc_nelmts;
183 size_t rdcc_nbytes;
184 double rdcc_w0;
185 herr_t r = H5Pget_cache(plist_id, &mdc_nelmts, &rdcc_nelmts, &rdcc_nbytes, &rdcc_w0);
186 info() << " CACHE SIZE r=" << r << " mdc=" << mdc_nelmts
187 << " rdcc=" << rdcc_nelmts << " rdcc_bytes=" << rdcc_nbytes << " w0=" << rdcc_w0;
188 mdc_nelmts *= 10;
189 rdcc_nelmts *= 10;
190 rdcc_nbytes = 10000000;
191 r = H5Pset_cache(plist_id, mdc_nelmts, rdcc_nelmts, rdcc_nbytes, rdcc_w0);
192 info() << " SET CACHE SIZE R1=" << r;
193 //r = H5Pset_fapl_stdio(plist_id);
194 //info() << " R2=" << r;
195 hsize_t sieve_buf = (1024 << 12);
196 r = H5Pset_sieve_buf_size(plist_id, sieve_buf);
197 info() << " SIEVE_BUF=" << sieve_buf << " r=" << r;
198 hsize_t small_block_size = 0;
199 r = H5Pget_small_data_block_size(plist_id, &small_block_size);
200 info() << " SMALL BLOCK SIZE=" << small_block_size;
201 small_block_size <<= 10;
202 r = H5Pset_small_data_block_size(plist_id, small_block_size);
203 info() << " SET SMALL BLOCK SIZE s=" << small_block_size << " r=" << r;
204 }
205
206 m_file_id.openTruncate(m_filename, plist_id);
207 }
208 else if (m_open_mode == OpenModeAppend) {
209 m_file_id.openAppend(m_filename);
210 }
211 if (m_sub_group_name != "/") {
212 m_sub_group_id.checkDelete(m_file_id, m_sub_group_name);
213 m_sub_group_id.recursiveCreate(m_file_id, m_sub_group_name);
214 }
215 else
216 m_sub_group_id.open(m_file_id, m_sub_group_name);
217 }
218 if (m_file_id.isBad())
219 ARCANE_THROW(ReaderWriterException, "Unable to open file '{0}'", m_filename);
220
221 if (m_sub_group_id.isBad())
222 ARCANE_THROW(ReaderWriterException, "HDF5 group '{0}' not found", m_sub_group_name);
223
224 if (m_open_mode == OpenModeRead) {
225 int index = 0;
226 ARCANE_HDF5_MUTEX;
227 //H5Giterate(m_sub_group_id.id(),"Variables",&index,_Hdf5ReaderWriterIterateMe,this);
228 H5Giterate(m_file_id.id(), m_sub_group_name.localstr(), &index, _Hdf5ReaderWriterIterateMe, this);
229 }
230}
231
232/*---------------------------------------------------------------------------*/
233/*---------------------------------------------------------------------------*/
234
235Hdf5ReaderWriter::
236~Hdf5ReaderWriter()
237{
238}
239
240/*---------------------------------------------------------------------------*/
241/*---------------------------------------------------------------------------*/
242
243void Hdf5ReaderWriter::
244_checkValid()
245{
246 if (m_is_initialized)
247 return;
248 fatal() << "Use of a Hdf5ReaderWriter instance not initialized";
249}
250
251/*---------------------------------------------------------------------------*/
252/*---------------------------------------------------------------------------*/
253
254String Hdf5ReaderWriter::
255_variableGroupName(IVariable* var)
256{
257 return var->fullName();
258}
259
260/*---------------------------------------------------------------------------*/
261/*---------------------------------------------------------------------------*/
262/*!
263 * \brief Parallel writing.
264 *
265 * \warning Under test, not usable.
266 */
267void Hdf5ReaderWriter::
268_writeValParallel(IVariable* v, const ISerializedData* sdata)
269{
270 SerializeBuffer sb;
271 sb.setMode(ISerializer::ModeReserve);
272 sb.reserve(DT_Int32, 1); // To indicate the end of sends
273 sb.reserve(v->fullName());
274 sb.reserve(m_sub_group_name); //!< Group name.
275 sb.reserve(DT_Int32, 1); // To indicate the rank the message comes from
276 sdata->serialize(&sb);
277 sb.allocateBuffer();
278 sb.setMode(ISerializer::ModePut);
279 sb.putInt32(1); // Indicates that it is a non-empty message
280 sb.put(v->fullName());
281 sb.put(m_sub_group_name); //!< Group name.
282 sb.put(m_my_rank);
283 sdata->serialize(&sb);
284 m_parallel_mng->sendSerializer(&sb, m_send_rank);
285}
286
287/*---------------------------------------------------------------------------*/
288/*---------------------------------------------------------------------------*/
289
290void Hdf5ReaderWriter::
291_directReadVal(IVariable* v, IData* data)
292{
293 _checkValid();
294 info(4) << "DIRECT READ VAL v=" << v->name();
295 _readVal(v, data);
296}
297
298/*---------------------------------------------------------------------------*/
299/*---------------------------------------------------------------------------*/
300
301void Hdf5ReaderWriter::
302_directWriteVal(IVariable* v, IData* data)
303{
304 _checkValid();
305 Ref<ISerializedData> sdata(data->createSerializedDataRef(false));
306 if (m_is_parallel && m_send_rank != m_my_rank) {
307 _writeValParallel(v, sdata.get());
308 }
309 else {
310 _writeVal(v->fullName(), m_sub_group_name, sdata.get());
311 }
312}
313
314/*---------------------------------------------------------------------------*/
315/*---------------------------------------------------------------------------*/
316
317static herr_t
318_Hdf5ReaderWriterIterateMe(hid_t g, const char* mn, void* ptr)
319{
320 Hdf5ReaderWriter* rw = reinterpret_cast<Hdf5ReaderWriter*>(ptr);
321 return rw->iterateMe(g, mn);
322}
323
324/*---------------------------------------------------------------------------*/
325/*---------------------------------------------------------------------------*/
326
327herr_t Hdf5ReaderWriter::
328iterateMe(hid_t group_id, const char* member_name)
329{
330 ARCANE_UNUSED(group_id);
331 m_variables_name.add(StringView(member_name));
332 return 0;
333}
334
335/*---------------------------------------------------------------------------*/
336/*---------------------------------------------------------------------------*/
337
338void Hdf5ReaderWriter::
339_writeVal(const String& var_group_name,
340 const String& sub_group_name,
341 const ISerializedData* sdata,
342 const Int32 from_rank)
343{
344 const bool hits_modulo = (m_index_modulo != 0) && (m_index_write != 0) && ((m_index_write % m_index_modulo) == 0);
345 Timer::Sentry ts(&m_io_timer);
346
347 info(4) << " SDATA name=" << var_group_name << " nb_element=" << sdata->nbElement()
348 << " dim=" << sdata->nbDimension() << " datatype=" << sdata->baseDataType()
349 << " nb_basic_element=" << sdata->nbBaseElement()
350 << " is_multi=" << sdata->isMultiSize()
351 << " dimensions_size=" << sdata->extents().size()
352 << " memory_size=" << sdata->memorySize()
353 << " bytes_size=" << sdata->constBytes().size()
354 << " shape=" << sdata->shape().dimensions();
355
356 Integer nb_dimension = sdata->nbDimension();
357 Int64ConstArrayView dimensions = sdata->extents();
358
359 hid_t save_typeid = m_types.saveType(sdata->baseDataType());
360 hid_t trueid = m_types.nativeType(sdata->baseDataType());
361 const void* ptr = sdata->constBytes().data();
362 Int64 nb_base_element = sdata->nbBaseElement();
363
364 HGroup var_base_group;
365 var_base_group.recursiveCreate(m_file_id, sub_group_name);
366
367 // Creation of the group containing the variable information
368 HGroup group_id;
369 group_id.recursiveCreate(var_base_group, var_group_name);
370 if (group_id.isBad())
371 ARCANE_THROW(ReaderWriterException, "HDF5 group '{0}' not found", var_group_name);
372
373 Int64 nb_element = sdata->nbElement();
374 bool is_multi_size = sdata->isMultiSize();
375 Int64 dim2_size = 0;
376 Int64 dim1_size = 0;
377 if (nb_dimension == 2 && !is_multi_size) {
378 dim1_size = dimensions[0];
379 dim2_size = dimensions[1];
380 }
381 Integer dimension_array_size = dimensions.size();
382
383 // Save the information concerning the variable sizes and dimensions
384 {
385 hsize_t att_dims[1];
386 att_dims[0] = VARIABLE_INFO_SIZE;
387 HSpace space_id;
388 space_id.createSimple(1, att_dims);
389 std::array<Int64, VARIABLE_INFO_SIZE> dim_val_buf;
390 SmallSpan<Int64> dim_val(dim_val_buf);
391 dim_val.fill(0);
392
393 dim_val[0] = nb_dimension;
394 dim_val[1] = dim1_size;
395 dim_val[2] = dim2_size;
396 dim_val[3] = nb_element;
397 dim_val[4] = nb_base_element;
398 dim_val[5] = dimension_array_size;
399 dim_val[6] = is_multi_size ? 1 : 0;
400 dim_val[7] = sdata->baseDataType();
401 dim_val[8] = sdata->memorySize();
402 {
403 ArrayShape shape = sdata->shape();
404 Int32 shape_nb_dim = shape.nbDimension();
405 auto shape_dims = shape.dimensions();
406 dim_val[9] = shape_nb_dim;
407 for (Integer i = 0; i < shape_nb_dim; ++i)
408 dim_val[10 + i] = shape_dims[i];
409 }
410 HAttribute att_id;
411 if (m_is_parallel && hits_modulo && (from_rank != 0))
412 att_id.remove(group_id, "Dims");
413 att_id.create(group_id, "Dims", m_types.saveType(dim1_size), space_id);
414 herr_t herr = att_id.write(m_types.nativeType(dim2_size), dim_val.data());
415 if (herr < 0)
416 ARCANE_THROW(ReaderWriterException, "Wrong dimensions written for variable '{0}'", var_group_name);
417 }
418
419 // If the variable is a two-dimensional array type, save the
420 // sizes of the second dimension per element.
421 if (dimension_array_size != 0) {
422 hsize_t att_dims[1];
423 att_dims[0] = dimension_array_size;
424 HSpace space_id;
425 HDataset array_id;
426 space_id.createSimple(1, att_dims);
427 array_id.recursiveCreate(group_id, "Dim2", m_types.saveType(dim1_size), space_id, H5P_DEFAULT);
428 herr_t herr = array_id.write(m_types.nativeType(dim1_size), dimensions.data());
429 if (herr < 0)
430 ARCANE_THROW(ReaderWriterException, "Wrong dimensions written for variable '{0}'", var_group_name);
431 }
432
433 // Now, save the values if necessary
434 if (nb_base_element != 0 && ptr != nullptr) {
435 debug(Trace::High) << "Variable " << var_group_name << " begin dumped (nb_base_element=" << nb_base_element << ").";
436 hsize_t dims[1];
437 dims[0] = nb_base_element;
438 HSpace space_id;
439 space_id.createSimple(1, dims);
440 if (space_id.isBad())
441 ARCANE_THROW(ReaderWriterException, "Wrong dataspace for variable '{0}'", var_group_name);
442
443 HDataset dataset_id;
444 hid_t plist_id = H5P_DEFAULT;
445
446#if 0
447 if (nb_element>=10000){
448 ARCANE_HDF5_MUTEX
449 plist_id = H5Pcreate(H5P_DATASET_CREATE);
450 hsize_t chunk_dim[1];
451 chunk_dim[0] = (4096 << 1);
452 herr_t r = H5Pset_chunk(plist_id,1,chunk_dim);
453 info() << " SET CHUNK FOR " << var_group_name << " s=" << nb_element;
454 }
455#endif
456 dataset_id.recursiveCreate(group_id, "Values", save_typeid, space_id, plist_id);
457 if (dataset_id.isBad())
458 ARCANE_THROW(ReaderWriterException, "Wrong dataset for variable '{0}'", var_group_name);
459
460 herr_t herr = dataset_id.write(trueid, ptr);
461 if (herr < 0)
462 ARCANE_THROW(ReaderWriterException, "Wrong dataset written for variable '{0}'", var_group_name);
463 }
464}
465
466/*---------------------------------------------------------------------------*/
467/*---------------------------------------------------------------------------*/
468
469Ref<ISerializedData> Hdf5ReaderWriter::
470_readDim2(IVariable* var)
471{
472 const int max_dim = 256; // Maximum number of dimensions for HDF arrays
473 String vname = _variableGroupName(var);
474 info(4) << " READ DIM name=" << vname;
475 Int64 dimension_array_size = 0;
476 Int64 nb_element = 0;
477 Integer nb_dimension = -1;
478 // Check if the corresponding name is in the list of variables.
479 // If it is not, it means the array was not saved and
480 // therefore its dimensions are null.
481 {
482 bool is_found = false;
483 for (StringList::Enumerator i(m_variables_name); ++i;)
484 if (*i == vname) {
485 is_found = true;
486 break;
487 }
488 if (!is_found)
489 ARCANE_THROW(ReaderWriterException, "No HDF5 group named '{0} exists", vname);
490 }
491
492 // Retrieve the group containing the variable information
493 HGroup group_id;
494 //group_id.open(m_variable_group_id,vname);
495 group_id.open(m_sub_group_id, vname);
496 if (group_id.isBad())
497 ARCANE_THROW(ReaderWriterException, "HDF5 group '{0}' not found", vname);
498
499 bool is_multi_size = false;
500 eDataType data_type = DT_Unknown;
501 Int64 memory_size = 0;
502 Int64 nb_base_element = 0;
503 Int64 dim1_size = 0;
504 Int64 dim2_size = 0;
505 UniqueArray<Int64> dims;
506 ArrayShape data_shape;
507
508 // Retrieve the information concerning the variable sizes and dimensions
509 {
510 HAttribute att_id;
511 att_id.open(group_id, "Dims");
512 HSpace space_id = att_id.getSpace();
513
514 // We expect a single dimension, and the number of elements of
515 // the attribute (hdf_dims[0]) must be equal to 1 or 2.
516 hsize_t hdf_dims[max_dim];
517 hsize_t max_dims[max_dim];
518 {
519 ARCANE_HDF5_MUTEX;
520 H5Sget_simple_extent_dims(space_id.id(), hdf_dims, max_dims);
521 }
522
523 if (hdf_dims[0] != VARIABLE_INFO_SIZE)
524 ARCANE_THROW(ReaderWriterException, "Wrong dimensions for variable '{0}' (found={1} expected={2})",
525 vname, hdf_dims[0], VARIABLE_INFO_SIZE);
526
527 std::array<Int64, VARIABLE_INFO_SIZE> dim_val_buf;
528 att_id.read(m_types.nativeType(Int64()), dim_val_buf.data());
529
530 SmallSpan<const Int64> dim_val(dim_val_buf);
531
532 nb_dimension = CheckedConvert::toInteger(dim_val[0]);
533 dim1_size = dim_val[1];
534 dim2_size = dim_val[2];
535 nb_element = dim_val[3];
536 nb_base_element = dim_val[4];
537 dimension_array_size = dim_val[5];
538 is_multi_size = dim_val[6] != 0;
539 data_type = (eDataType)dim_val[7];
540 memory_size = dim_val[8];
541 Int32 shape_nb_dim = CheckedConvert::toInt32(dim_val[9]);
542 data_shape.setNbDimension(shape_nb_dim);
543 for (Integer i = 0; i < shape_nb_dim; ++i)
544 data_shape.setDimension(i, CheckedConvert::toInt32(dim_val[10 + i]));
545 }
546
547 info(4) << " READ DIM name=" << vname
548 << " nb_dim=" << nb_dimension << " dim1_size=" << dim1_size
549 << " dim2_size=" << dim2_size << " nb_element=" << nb_element
550 << " dimension_size=" << dimension_array_size
551 << " is_multi_size=" << is_multi_size
552 << " data_type" << data_type
553 << " shape=" << data_shape.dimensions();
554
555 if (dimension_array_size > 0) {
556 HDataset array_id;
557 array_id.open(group_id, "Dim2");
558 if (array_id.isBad())
559 ARCANE_THROW(ReaderWriterException, "Wrong dataset for variable '{0}'", vname);
560
561 HSpace space_id = array_id.getSpace();
562 if (space_id.isBad())
563 ARCANE_THROW(ReaderWriterException, "Wrong dataspace for variable '{0}'", vname);
564
565 hsize_t hdf_dims[max_dim];
566 hsize_t max_dims[max_dim];
567 {
568 ARCANE_HDF5_MUTEX;
569 H5Sget_simple_extent_dims(space_id.id(), hdf_dims, max_dims);
570 }
571 // Verify that the number of elements in the dataset is equal to that
572 // expected.
573 if ((Int64)hdf_dims[0] != dimension_array_size) {
574 ARCANE_THROW(ReaderWriterException, "Wrong number of elements in 'Dim2' for variable '{0}' (found={1} expected={2})",
575 vname, hdf_dims[0], dimension_array_size);
576 }
577 dim2_size = 0;
578 dims.resize(dimension_array_size);
579 herr_t herr = array_id.read(m_types.nativeType(Int64()), dims.data());
580 if (herr < 0)
581 ARCANE_THROW(ReaderWriterException, "Wrong dataset read for variable '{0}'", vname);
582 }
583 Ref<ISerializedData> sdata = arcaneCreateSerializedDataRef(data_type, memory_size, nb_dimension, nb_element,
584 nb_base_element, is_multi_size, dims, data_shape);
585 return sdata;
586}
587
588/*---------------------------------------------------------------------------*/
589/*---------------------------------------------------------------------------*/
590
591/*---------------------------------------------------------------------------*/
592/*---------------------------------------------------------------------------*/
593
594void Hdf5ReaderWriter::
595write(IVariable* v, IData* data)
596{
597 _directWriteVal(v, data);
598}
599
600/*---------------------------------------------------------------------------*/
601/*---------------------------------------------------------------------------*/
602
603void Hdf5ReaderWriter::
604_readVal(IVariable* v, IData* data)
605{
606 String var_group_name = _variableGroupName(v);
607 info(4) << " TRY TO READ var_group=" << var_group_name;
608 Ref<ISerializedData> sd(_readDim2(v));
609 Int64 storage_size = sd->memorySize();
610 info(4) << " READ DATA n=" << storage_size;
611 data->allocateBufferForSerializedData(sd.get());
612 if (storage_size != 0) {
613 // Retrieve the group containing the variable information
614 HGroup group_id;
615 //group_id.open(m_variable_group_id,var_group_name);
616 group_id.open(m_sub_group_id, var_group_name);
617 if (group_id.isBad())
618 ARCANE_THROW(ReaderWriterException, "No HDF5 group with name '{0}' exists", var_group_name);
619 HDataset dataset_id;
620 dataset_id.open(group_id, "Values");
621 if (dataset_id.isBad())
622 ARCANE_THROW(ReaderWriterException, "Wrong dataset for variable '{0}'", var_group_name);
623 void* ptr = sd->writableBytes().data();
624 info() << "READ Variable " << var_group_name << " ptr=" << ptr;
625 ;
626 hid_t trueid = m_types.nativeType(sd->baseDataType());
627 dataset_id.read(trueid, ptr);
628 }
629 data->assignSerializedData(sd.get());
630}
631
632/*---------------------------------------------------------------------------*/
633/*---------------------------------------------------------------------------*/
634
635void Hdf5ReaderWriter::
636read(IVariable* var, IData* data)
637{
638 _directReadVal(var, data);
639}
640
641/*---------------------------------------------------------------------------*/
642/*---------------------------------------------------------------------------*/
643
644void Hdf5ReaderWriter::
645setMetaData(const String& meta_data)
646{
647 if (m_is_parallel) {
648 IParallelMng* pm = m_parallel_mng;
649 //Integer nb_rank = pm->commSize();
650 if (m_send_rank != m_my_rank) {
651 // Send the group and the meta data
653 sb.setMode(ISerializer::ModeReserve);
654 sb.reserve(m_sub_group_name);
655 sb.reserve(meta_data);
656 sb.allocateBuffer();
658 sb.put(m_sub_group_name);
659 sb.put(meta_data);
660 m_parallel_mng->sendSerializer(&sb, m_send_rank);
661 }
662 else {
663 _setMetaData(meta_data, m_sub_group_name);
664 for (Integer i = m_send_rank + 1; i <= m_last_recv_rank; ++i) {
666 pm->recvSerializer(&sb, i);
668 String remote_group_name;
669 String remote_meta_data;
670 sb.get(remote_group_name);
671 sb.get(remote_meta_data);
672 _setMetaData(remote_meta_data, remote_group_name);
673 }
674 }
675 }
676 else
677 _setMetaData(meta_data, m_sub_group_name);
678}
679
680/*---------------------------------------------------------------------------*/
681/*---------------------------------------------------------------------------*/
682
683void Hdf5ReaderWriter::
684_setMetaData(const String& meta_data, const String& sub_group_name)
685{
686 const bool hits_modulo = (m_index_modulo != 0) && (m_index_write != 0) && ((m_index_write % m_index_modulo) == 0);
687 HGroup base_group;
688 if (hits_modulo)
689 base_group.recursiveOpen(m_file_id, sub_group_name);
690 else
691 base_group.recursiveCreate(m_file_id, sub_group_name);
692
693 Span<const Byte> meta_data_bytes = meta_data.bytes();
694 const Byte* _meta_data = meta_data_bytes.data();
695 hsize_t dims[1];
696 dims[0] = meta_data_bytes.size();
697
698 HSpace space_id;
699 space_id.createSimple(1, dims);
700 if (space_id.isBad())
701 throw ReaderWriterException(A_FUNCINFO, "Wrong space for meta-data ('MetaData')");
702
703 HDataset dataset_id;
704 if (hits_modulo)
705 dataset_id.recursiveCreate(base_group, "MetaData", m_types.nativeType(Byte()), space_id, H5P_DEFAULT);
706 else
707 dataset_id.create(base_group, "MetaData", m_types.nativeType(Byte()), space_id, H5P_DEFAULT);
708 if (dataset_id.isBad())
709 throw ReaderWriterException(A_FUNCINFO, "Wrong dataset for meta-data ('MetaData')");
710
711 herr_t herr = dataset_id.write(m_types.nativeType(Byte()), _meta_data);
712 if (herr < 0)
713 throw ReaderWriterException(A_FUNCINFO, "Unable to write meta-data ('MetaData')");
714}
715
716/*---------------------------------------------------------------------------*/
717/*---------------------------------------------------------------------------*/
718
719String Hdf5ReaderWriter::
720metaData()
721{
722 HDataset dataset_id;
723 dataset_id.open(m_sub_group_id, "MetaData");
724 if (dataset_id.isBad()) {
725 throw ReaderWriterException(A_FUNCINFO, "Wrong dataset for meta-data ('MetaData')");
726 }
727 HSpace space_id = dataset_id.getSpace();
728 if (space_id.isBad()) {
729 throw ReaderWriterException(A_FUNCINFO, "Wrong space for meta-data ('MetaData')");
730 }
731 const int max_dim = 256;
732 hsize_t hdf_dims[max_dim];
733 hsize_t max_dims[max_dim];
734 {
735 ARCANE_HDF5_MUTEX;
736 H5Sget_simple_extent_dims(space_id.id(), hdf_dims, max_dims);
737 }
738 if (hdf_dims[0] <= 0)
739 throw ReaderWriterException(A_FUNCINFO, "Wrong number of elements for meta-data ('MetaData')");
740 Integer nb_byte = static_cast<Integer>(hdf_dims[0]);
741 ByteUniqueArray uchars(nb_byte);
742 dataset_id.read(m_types.nativeType(Byte()), uchars.data());
743 String s(uchars);
744 return s;
745}
746
747/*---------------------------------------------------------------------------*/
748/*---------------------------------------------------------------------------*/
749
750void Hdf5ReaderWriter::
751endWrite()
752{
753 if (m_is_parallel) {
754 if (m_my_rank == m_send_rank) {
755 _receiveRemoteVariables();
756 }
757 else {
758 // Sends an end message
759 SerializeBuffer sb;
760 sb.setMode(ISerializer::ModeReserve);
761 sb.reserve(DT_Int32, 1); // To indicate the end of sends
762 sb.allocateBuffer();
763 sb.setMode(ISerializer::ModePut);
764 sb.putInt32(0); // Indicates it is an end message
765 m_parallel_mng->sendSerializer(&sb, m_send_rank);
766 }
767 }
768 {
769 info() << " Hdf5Timer: nb_activated=" << m_io_timer.nbActivated()
770 << " time=" << m_io_timer.totalTime();
771 }
772}
773
774/*---------------------------------------------------------------------------*/
775/*---------------------------------------------------------------------------*/
776
777void Hdf5ReaderWriter::
778_receiveRemoteVariables()
779{
780 IParallelMng* pm = m_parallel_mng;
781 Integer nb_remaining = m_last_recv_rank - m_send_rank;
782 info() << "NB REMAINING = " << nb_remaining;
783 Ref<ISerializeMessageList> m_messages(pm->createSerializeMessageListRef());
784 while (nb_remaining > 0) {
785 ScopedPtrT<ISerializeMessage> sm(new SerializeMessage(m_my_rank, NULL_SUB_DOMAIN_ID, ISerializeMessage::MT_Recv));
786 m_messages->addMessage(sm.get());
787 m_messages->processPendingMessages();
788 m_messages->waitMessages(Parallel::WaitAll);
789 ISerializer* sb = sm->serializer();
790 sb->setMode(ISerializer::ModeGet);
791 Int32 id = sb->getInt32();
792 if (id == 0)
793 --nb_remaining;
794 else
795 _writeRemoteVariable(sb);
796 }
797}
798
799/*---------------------------------------------------------------------------*/
800/*---------------------------------------------------------------------------*/
801
802void Hdf5ReaderWriter::
803_writeRemoteVariable(ISerializer* sb)
804{
805 String var_name;
806 sb->get(var_name);
807 String group_name;
808 sb->get(group_name);
809 Int32 rank = sb->getInt32();
810 //warning()<<"[\33[46;30m_writeRemoteVariable\33[m] rank="<<rank;
811 Ref<ISerializedData> sdata = arcaneCreateEmptySerializedDataRef();
812 sb->setReadMode(ISerializer::ReadReplace);
813 sdata->serialize(sb);
814 _writeVal(var_name, group_name, sdata.get(), rank);
815}
816
817/*---------------------------------------------------------------------------*/
818/*---------------------------------------------------------------------------*/
819
820/*---------------------------------------------------------------------------*/
821/*---------------------------------------------------------------------------*/
822/*!
823 * \brief Protection/reprise au format ArcaneHdf5.
824 */
825class ArcaneHdf5CheckpointService2
826: public ArcaneHdf5ReaderWriterObject
827{
828 public:
829
830 ArcaneHdf5CheckpointService2(const ServiceBuildInfo& sbi)
831 : ArcaneHdf5ReaderWriterObject(sbi)
832 , m_write_index(0)
833 , m_writer(nullptr)
834 , m_reader(nullptr)
835 , m_fileset_size(1)
836 , m_index_modulo(0)
837 {}
838
839 virtual IDataWriter* dataWriter() { return m_writer; }
840 virtual IDataReader* dataReader() { return m_reader; }
841
842 virtual void notifyBeginWrite();
843 virtual void notifyEndWrite();
844 virtual void notifyBeginRead();
845 virtual void notifyEndRead();
846 virtual void close() {}
847 virtual String readerServiceName() const { return "ArcaneHdf5CheckpointReader2"; }
848
849 private:
850
851 Integer m_write_index;
852 Hdf5ReaderWriter* m_writer;
853 Hdf5ReaderWriter* m_reader;
854 Integer m_fileset_size;
855 Integer m_index_modulo;
856
857 private:
858
859 String _defaultFileName()
860 {
861 info() << "USE DEFAULT FILE NAME";
862 IParallelMng* pm = subDomain()->parallelMng();
863 Integer rank = pm->commRank();
864 StringBuilder buf;
865
866 // Ajoute si besoin le numero du processeur
867 if (pm->isParallel()) {
868 Integer file_id = rank;
869 if (m_fileset_size != 0)
870 file_id = (rank / m_fileset_size) * m_fileset_size;
871 buf = "arcanedump.";
872 buf += file_id;
873 }
874 else {
875 buf = "arcanedump";
876 }
877
878 // Ajoute si besoin le numero du replica
879 IParallelReplication* pr = subDomain()->parallelMng()->replication();
880 if (pr->hasReplication()) {
881 buf += "_r";
882 buf += pr->replicationRank();
883 }
884
885 buf += ".h5";
886 return buf.toString();
887 }
888
889 Directory _defaultDirectory()
890 {
891 return Directory(baseDirectoryName());
892 }
893 void _parseMetaData(String meta_data);
894};
895
896/*---------------------------------------------------------------------------*/
897/*---------------------------------------------------------------------------*/
898
899void ArcaneHdf5CheckpointService2::
900_parseMetaData(String meta_data)
901{
902 IIOMng* io_mng = subDomain()->ioMng();
903 ScopedPtrT<IXmlDocumentHolder> xml_doc(io_mng->parseXmlBuffer(meta_data.utf8(), "MetaData"));
904 XmlNode root = xml_doc->documentNode().documentElement();
905 Integer version = root.attr("version").valueAsInteger();
906 if (version != 1) {
907 throw ReaderWriterException(A_FUNCINFO, "Bad version (expected 1)");
908 }
909 {
910 Integer fileset_size = root.child("fileset-size").valueAsInteger();
911 if (fileset_size < 0)
912 fileset_size = 0;
913 m_fileset_size = fileset_size;
914 }
915 {
916 Integer index_modulo = root.child("index-modulo").valueAsInteger();
917 if (index_modulo < 0)
918 index_modulo = 0;
919 m_index_modulo = index_modulo;
920 }
921 info() << " FileSet size=" << m_fileset_size;
922 info() << " Index modulo=" << m_index_modulo;
923}
924
925/*---------------------------------------------------------------------------*/
926/*---------------------------------------------------------------------------*/
927
928void ArcaneHdf5CheckpointService2::
929notifyBeginRead()
930{
931 String meta_data = readerMetaData();
932 _parseMetaData(meta_data);
933
934 info() << " GET META DATA READER " << readerMetaData()
935 << " filename=" << fileName();
936
937 if (fileName().null()) {
938 Directory dump_dir(_defaultDirectory());
939 setFileName(dump_dir.file(_defaultFileName()));
940 }
941 info() << " READ CHECKPOINT FILENAME = " << fileName();
942 StringBuilder sub_group;
943 sub_group = "SubDomain";
944 sub_group += subDomain()->subDomainId();
945 sub_group += "/Index";
946
947 Integer index = currentIndex();
948 if (m_index_modulo != 0)
949 index %= m_index_modulo;
950 sub_group += index;
951
952 m_reader = new Hdf5ReaderWriter(subDomain(),
953 fileName(),
954 sub_group.toString(),
955 0,
956 currentIndex(),
957 m_index_modulo,
958 Hdf5ReaderWriter::OpenModeRead);
959 m_reader->initialize();
960}
961
962/*---------------------------------------------------------------------------*/
963/*---------------------------------------------------------------------------*/
964
965void ArcaneHdf5CheckpointService2::
966notifyEndRead()
967{
968 delete m_reader;
969 m_reader = 0;
970}
971
972/*---------------------------------------------------------------------------*/
973/*---------------------------------------------------------------------------*/
974
975void ArcaneHdf5CheckpointService2::
976notifyBeginWrite()
977{
978 if (options()) {
979 // Récupération du nombre de fichiers par groupe
980 m_fileset_size = options()->filesetSize();
981 // Récupération du nombre d'indexes au maximum par fichiers
982 m_index_modulo = options()->indexModulo();
983 }
984
985 if (fileName().null()) {
986 Directory dump_dir(_defaultDirectory());
987 setFileName(dump_dir.file(_defaultFileName()));
988 }
989 Hdf5ReaderWriter::eOpenMode open_mode = Hdf5ReaderWriter::OpenModeAppend;
990 Integer write_index = checkpointTimes().size();
991 --write_index;
992
993 if (write_index == 0)
994 open_mode = Hdf5ReaderWriter::OpenModeTruncate;
995
996 // Test de l'option m_index_modulo pour savoir la profondeur du modulo
997 if (m_index_modulo != 0)
998 write_index %= m_index_modulo;
999
1000 StringBuilder sub_group;
1001 sub_group = "SubDomain";
1002 sub_group += subDomain()->parallelMng()->commRank();
1003 sub_group += "/Index";
1004 sub_group += write_index;
1005
1006 m_writer = new Hdf5ReaderWriter(subDomain(),
1007 fileName(),
1008 sub_group,
1009 m_fileset_size,
1010 checkpointTimes().size() - 1,
1011 m_index_modulo,
1012 open_mode);
1013 m_writer->initialize();
1014}
1015
1016/*---------------------------------------------------------------------------*/
1017/*---------------------------------------------------------------------------*/
1018
1019void ArcaneHdf5CheckpointService2::
1020notifyEndWrite()
1021{
1022 OStringStream ostr;
1023 ostr() << "<infos version='1'>\n";
1024 ostr() << " <fileset-size>" << m_fileset_size << "</fileset-size>\n";
1025 ostr() << " <index-modulo>" << m_index_modulo << "</index-modulo>\n";
1026 ostr() << "</infos>\n";
1027 setReaderMetaData(ostr.str());
1028 ++m_write_index;
1029 delete m_writer;
1030 m_writer = 0;
1031}
1032
1033/*---------------------------------------------------------------------------*/
1034/*---------------------------------------------------------------------------*/
1035
1036ARCANE_REGISTER_SERVICE(ArcaneHdf5CheckpointService2,
1037 ServiceProperty("ArcaneHdf5CheckpointReader2", ST_SubDomain),
1038 ARCANE_SERVICE_INTERFACE(ICheckpointReader));
1039
1040ARCANE_REGISTER_SERVICE(ArcaneHdf5CheckpointService2,
1041 ServiceProperty("ArcaneHdf5CheckpointWriter2", ST_SubDomain),
1042 ARCANE_SERVICE_INTERFACE(ICheckpointWriter));
1043
1044ARCANE_REGISTER_SERVICE_HDF5READERWRITER(ArcaneHdf5Checkpoint2,
1045 ArcaneHdf5CheckpointService2);
1046
1047/*---------------------------------------------------------------------------*/
1048/*---------------------------------------------------------------------------*/
1049
1050} // End namespace Arcane
1051
1052/*---------------------------------------------------------------------------*/
1053/*---------------------------------------------------------------------------*/
#define ARCANE_THROW(exception_class,...)
Macro for throwing an exception with formatting.
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro to declare an interface when registering a service.
const T * data() const
Access to the root of the array without any protection.
void put(Span< const Real > values) override
Add the array values.
void reserve(eBasicDataType dt, Int64 n) override
Reserves memory for n objects of type dt.
void allocateBuffer() override
Allocates the serializer memory.
void get(ArrayView< Real > values) override
Retrieve the array values.
void setMode(eMode new_mode) override
Sets the current mode.
constexpr const_pointer data() const noexcept
Pointer to the allocated memory.
Class managing a directory.
Definition Directory.h:36
Reading/Writing in HDF5 format.
Encapsulates a hid_t for a dataset.
Definition Hdf5Utils.h:448
Encapsulates a hid_t for a group.
Definition Hdf5Utils.h:351
Encapsulates a hid_t for a dataspace.
Definition Hdf5Utils.h:405
Interface for reading variable data.
Definition IDataReader.h:35
Interface for writing variable data.
Definition IDataWriter.h:45
Interface of a data item.
Definition IData.h:34
virtual void allocateBufferForSerializedData(ISerializedData *sdata)=0
Allocate memory to read the serialized values sdata.
virtual void assignSerializedData(const ISerializedData *sdata)=0
Assign the serialized values sdata to the data.
Interface of the input/output manager.
Definition IIOMng.h:37
virtual IXmlDocumentHolder * parseXmlBuffer(Span< const Byte > buffer, const String &name)=0
Reads and parses the XML file contained in the buffer buffer.
Interface of the parallelism manager for a subdomain.
virtual Int32 commRank() const =0
Rank of this instance in the communicator.
virtual bool isParallel() const =0
Returns true if the execution is parallel.
Brief information on parallel subdomain replication.
virtual bool hasReplication() const =0
Indicates if replication is active.
virtual Int32 replicationRank() const =0
Rank in the replication (from 0 to nbReplication()-1).
Interface of the subdomain manager.
Definition ISubDomain.h:75
Interface of a variable.
Definition IVariable.h:40
Reference to an instance.
Encapsulation of an automatically destructing pointer.
Definition ScopedPtr.h:44
Structure containing the information to create a service.
constexpr __host__ __device__ pointer data() const noexcept
Pointer to the start of the view.
Definition Span.h:539
constexpr __host__ __device__ SizeType size() const noexcept
Returns the size of the array.
Definition Span.h:327
View of an array of elements of type T.
Definition Span.h:635
Unicode character string constructor.
String toString() const
Returns the constructed character string.
ByteConstArrayView utf8() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:277
Span< const Byte > bytes() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:293
Management of a timer.
Definition Timer.h:63
ITraceMng * traceMng() const
Trace manager.
Node of a DOM tree.
Definition XmlNode.h:51
XmlNode attr(const String &name, bool throw_exception=false) const
Returns the attribute of name name.
Definition XmlNode.cc:257
XmlNode documentElement() const
Returns the document element.
Definition XmlNode.cc:565
XmlNode child(const String &name) const
Child node of this node with name name.
Definition XmlNode.cc:73
Integer valueAsInteger(bool throw_exception=false) const
Node value converted to integer.
Definition XmlNode.cc:441
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro for registering a service.
Utility functions for Hdf5.
Definition Hdf5Utils.cc:34
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Ref< ISerializedData > arcaneCreateSerializedDataRef(eDataType data_type, Int64 memory_size, Integer nb_dim, Int64 nb_element, Int64 nb_base_element, bool is_multi_size, Int64ConstArrayView dimensions)
Creates serialized data.
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:480
UniqueArray< Byte > ByteUniqueArray
Dynamic 1D array of characters.
Definition UtilsTypes.h:335
Ref< ISerializedData > arcaneCreateEmptySerializedDataRef()
Creates serialized data.
unsigned char Byte
Type of a byte.
Definition BaseTypes.h:43
eDataType
Data type.
Definition DataTypes.h:41
@ DT_Unknown
Unknown or uninitialized data type.
Definition DataTypes.h:58
std::int32_t Int32
Signed integer type of 32 bits.