Arcane  4.2.1.0
Developer documentation
Loading...
Searching...
No Matches
Hdf5Utils.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/* Hdf5Utils.cc (C) 2000-2026 */
9/* */
10/* HDF5 Utilities. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/Iostream.h"
15#include "arcane/utils/Array.h"
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/NotSupportedException.h"
18#include "arcane/utils/ArgumentException.h"
19#include "arcane/utils/ITraceMng.h"
20#include "arcane/utils/TraceInfo.h"
21#include "arcane/utils/IOException.h"
22#include "arcane/utils/Convert.h"
23
24#include "arcane/core/ArcaneException.h"
25#include "arcane/core/IParallelMng.h"
26
27#include "arcane/hdf5/Hdf5Utils.h"
28
29#include <algorithm>
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
33
35{
36
37/*---------------------------------------------------------------------------*/
38/*---------------------------------------------------------------------------*/
39
40namespace
41{
42 std::once_flag h5open_once_flag;
43
44#if (defined(H5_HAVE_THREADSAFE) || defined(H5_HAVE_CONCURRENCY))
45 bool global_hdf5_mutex_is_active = false;
46#else
47 bool global_hdf5_mutex_is_active = true;
48#endif
49
50 std::mutex global_hdf5_mutex;
51 Hdf5Mutex hdf5_mutex(global_hdf5_mutex, global_hdf5_mutex_is_active);
52
53#if (defined(H5_HAVE_THREADSAFE) || defined(H5_HAVE_CONCURRENCY))
54#define ARCANE_HDF5_MUTEX
55#else
56 struct ScopedMutex
57 {
58 ScopedMutex()
59 {
60 hdf5_mutex.lock();
61 }
62 ~ScopedMutex()
63 {
64 hdf5_mutex.unlock();
65 }
66 };
67#define ARCANE_HDF5_MUTEX ScopedMutex scoped_mutex
68#endif
69} // namespace
70
71Hdf5Mutex& _ArcaneHdf5UtilsMutex()
72{
73 return hdf5_mutex;
74}
75
76/*---------------------------------------------------------------------------*/
77/*---------------------------------------------------------------------------*/
78
79HInit::
80HInit()
81{
82 // Ensure this is called only once and protects against concurrent calls.
83 std::call_once(h5open_once_flag, []() { H5open(); });
84}
85
86/*---------------------------------------------------------------------------*/
87/*---------------------------------------------------------------------------*/
88
90useMutex([[maybe_unused]] bool is_active, [[maybe_unused]] IParallelMng* pm)
91{
92#if (defined(H5_HAVE_THREADSAFE) || defined(H5_HAVE_CONCURRENCY))
93 pm->traceMng()->info(4) << "HDF5 -- Is HDF5 threadsafe: 1 -- Is Mutex enabled: " << global_hdf5_mutex_is_active;
94#else
95 bool env_is_enable = true;
96 if (const auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_HDF5_DISABLE_MUTEX", true)) {
97 env_is_enable = (v.value() == 0);
98 }
99 pm->barrier();
100 global_hdf5_mutex.lock();
101 global_hdf5_mutex_is_active = env_is_enable && is_active;
102 global_hdf5_mutex.unlock();
103 pm->barrier();
104 pm->traceMng()->info(4) << "HDF5 -- Is HDF5 threadsafe: 0 -- Is Mutex enabled: " << global_hdf5_mutex_is_active;
105#endif
106}
107
108/*---------------------------------------------------------------------------*/
109/*---------------------------------------------------------------------------*/
110
111namespace
112{
113
114 hid_t _H5Gopen(hid_t loc_id, const char* name)
115 {
116 return H5Gopen2(loc_id, name, H5P_DEFAULT);
117 }
118
119 hid_t _H5Gcreate(hid_t loc_id, const char* name)
120 {
121 return H5Gcreate2(loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
122 }
123
124} // namespace
125/*---------------------------------------------------------------------------*/
126/*---------------------------------------------------------------------------*/
127
128extern "C" ARCANE_HDF5_EXPORT herr_t
129_ArcaneHdf5UtilsGroupIterateMe(hid_t g, const char* mn, void* ptr)
130{
131 ARCANE_UNUSED(g);
132 HGroupSearch* rw = reinterpret_cast<HGroupSearch*>(ptr);
133 return rw->iterateMe(mn);
134}
135
136/*---------------------------------------------------------------------------*/
137/*---------------------------------------------------------------------------*/
138
139void splitString(const String& str, Array<String>& str_array, char c)
140{
141 const char* str_str = str.localstr();
142 Int64 offset = 0;
143 Int64 len = str.length();
144 for (Int64 i = 0; i < len; ++i) {
145 if (str_str[i] == c && i != offset) {
146 str_array.add(std::string_view(str_str + offset, i - offset));
147 offset = i + 1;
148 }
149 }
150 if (len != offset)
151 str_array.add(std::string_view(str_str + offset, len - offset));
152}
153
154/*---------------------------------------------------------------------------*/
155/*---------------------------------------------------------------------------*/
156
157void HFile::
158openTruncate(const String& var)
159{
160 close();
161 {
162 ARCANE_HDF5_MUTEX;
163 _setId(H5Fcreate(var.localstr(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT));
164 }
165 if (isBad())
166 ARCANE_THROW(ReaderWriterException, "Can not open file '{0}'", var);
167}
168
169void HFile::
170openAppend(const String& var)
171{
172 close();
173 {
174 ARCANE_HDF5_MUTEX;
175 _setId(H5Fopen(var.localstr(), H5F_ACC_RDWR, H5P_DEFAULT));
176 }
177 if (isBad())
178 ARCANE_THROW(ReaderWriterException, "Can not open file '{0}'", var);
179}
180
181void HFile::
182openRead(const String& var)
183{
184 close();
185 {
186 ARCANE_HDF5_MUTEX;
187 _setId(H5Fopen(var.localstr(), H5F_ACC_RDONLY, H5P_DEFAULT));
188 }
189 if (isBad())
190 ARCANE_THROW(ReaderWriterException, "Can not open file '{0}'", var);
191}
192
193void HFile::
194openTruncate(const String& var, hid_t plist_id)
195{
196 close();
197 {
198 ARCANE_HDF5_MUTEX;
199 _setId(H5Fcreate(var.localstr(), H5F_ACC_TRUNC, H5P_DEFAULT, plist_id));
200 }
201 if (isBad())
202 ARCANE_THROW(ReaderWriterException, "Can not open file '{0}'", var);
203}
204
205void HFile::
206openAppend(const String& var, hid_t plist_id)
207{
208 close();
209 {
210 ARCANE_HDF5_MUTEX;
211 _setId(H5Fopen(var.localstr(), H5F_ACC_RDWR, plist_id));
212 }
213 if (isBad())
214 ARCANE_THROW(ReaderWriterException, "Can not open file '{0}'", var);
215}
216
217void HFile::
218openRead(const String& var, hid_t plist_id)
219{
220 close();
221 {
222 ARCANE_HDF5_MUTEX;
223 _setId(H5Fopen(var.localstr(), H5F_ACC_RDONLY, plist_id));
224 }
225 if (isBad())
226 ARCANE_THROW(ReaderWriterException, "Can not open file '{0}'", var);
227}
228
229/*---------------------------------------------------------------------------*/
230/*---------------------------------------------------------------------------*/
231
232herr_t HFile::
233_close()
234{
235 herr_t e = 0;
236 if (id() > 0) {
237 ARCANE_HDF5_MUTEX;
238 e = H5Fclose(id());
239 _setNullId();
240 }
241 return e;
242}
243
244/*---------------------------------------------------------------------------*/
245/*---------------------------------------------------------------------------*/
246
247void HFile::
248close()
249{
250 herr_t e = _close();
251 if (e < 0)
252 ARCANE_THROW(ReaderWriterException, "Can not close file");
253}
254
255/*---------------------------------------------------------------------------*/
256/*---------------------------------------------------------------------------*/
257
258void HGroup::
259recursiveCreate(const Hid& loc_id, const String& var)
260{
261 UniqueArray<String> bufs;
262 splitString(var, bufs, '/');
263 recursiveCreate(loc_id, bufs);
264}
265
266void HGroup::
267recursiveCreate(const Hid& loc_id, const Array<String>& bufs)
268{
269 close();
270 hid_t last_hid = loc_id.id();
271 Integer nb_create = bufs.size();
272 UniqueArray<hid_t> ref_ids(nb_create);
273 for (Integer i = 0; i < nb_create; ++i) {
274 last_hid = _checkOrCreate(last_hid, bufs[i]);
275 ref_ids[i] = last_hid;
276 }
277 // Release all intermediate created groups
278 ARCANE_HDF5_MUTEX;
279 for (Integer i = 0; i < nb_create - 1; ++i) {
280 H5Gclose(ref_ids[i]);
281 }
282 _setId(last_hid);
283}
284
285/*---------------------------------------------------------------------------*/
286/*---------------------------------------------------------------------------*/
287
288void HGroup::
289checkDelete(const Hid& loc_id, const String& var)
290{
291 UniqueArray<String> bufs;
292 splitString(var, bufs, '/');
293 hid_t last_hid = loc_id.id();
294 hid_t parent_hid = last_hid;
295 Integer i = 0;
296 Integer size = bufs.size();
297 for (; i < size; ++i) {
298 parent_hid = last_hid;
299 last_hid = _checkExist(last_hid, bufs[i]);
300 if (last_hid == 0)
301 break;
302 }
303 // Group found, we delete it.
304 if (last_hid > 0 && parent_hid > 0 && i == size) {
305 //cerr << "** DELETE <" << bufs[size-1] << "\n";
306 ARCANE_HDF5_MUTEX;
307 H5Gunlink(parent_hid, bufs[size - 1].localstr());
308 }
309}
310
311/*---------------------------------------------------------------------------*/
312/*---------------------------------------------------------------------------*/
313
314void HGroup::
315recursiveOpen(const Hid& loc_id, const String& var)
316{
317 close();
318 UniqueArray<String> bufs;
319 splitString(var, bufs, '/');
320 hid_t last_hid = loc_id.id();
321 Integer nb_open = bufs.size();
322 UniqueArray<hid_t> ref_ids(nb_open);
323 ARCANE_HDF5_MUTEX;
324 for (Integer i = 0; i < nb_open; ++i) {
325 last_hid = _H5Gopen(last_hid, bufs[i].localstr());
326 ref_ids[i] = last_hid;
327 }
328 // Release all intermediate opened groups
329 for (Integer i = 0; i < nb_open - 1; ++i) {
330 H5Gclose(ref_ids[i]);
331 }
332 _setId(last_hid);
333}
334
335/*---------------------------------------------------------------------------*/
336/*---------------------------------------------------------------------------*/
337
338void HGroup::
339openIfExists(const Hid& loc_id, const Array<String>& paths)
340{
341 close();
342 hid_t last_hid = loc_id.id();
343 bool is_valid = true;
344 Integer nb_open = paths.size();
345 UniqueArray<hid_t> ref_ids;
346 ref_ids.reserve(nb_open);
347 for (Integer i = 0; i < nb_open; ++i) {
348 if (HGroup::hasChildren(last_hid, paths[i].localstr())) {
349 ARCANE_HDF5_MUTEX;
350 last_hid = _H5Gopen(last_hid, paths[i].localstr());
351 ref_ids.add(last_hid);
352 }
353 else {
354 is_valid = false;
355 break;
356 }
357 }
358 if (is_valid)
359 _setId(last_hid);
360 // Close all intermediate groups
361 ARCANE_HDF5_MUTEX;
362 for (Integer i = 0; i < ref_ids.size(); ++i) {
363 if (ref_ids[i] != last_hid) {
364 H5Gclose(ref_ids[i]);
365 }
366 }
367}
368
369/*---------------------------------------------------------------------------*/
370/*---------------------------------------------------------------------------*/
371
372bool HGroup::
373hasChildren(const String& var)
374{
375 return hasChildren(id(), var);
376}
377
378/*---------------------------------------------------------------------------*/
379/*---------------------------------------------------------------------------*/
380
381bool HGroup::
382hasChildren(hid_t loc_id, const String& var)
383{
384 HGroupSearch gs(var);
385 ARCANE_HDF5_MUTEX;
386 herr_t v = H5Giterate(loc_id, ".", 0, _ArcaneHdf5UtilsGroupIterateMe, &gs);
387 bool has_children = v > 0;
388 //cout << "** HAS CHILDREN " << var << " v=" << has_children << '\n';
389 return has_children;
390}
391
392/*---------------------------------------------------------------------------*/
393/*---------------------------------------------------------------------------*/
394
395hid_t HGroup::
396_checkOrCreate(hid_t loc_id, const String& group_name)
397{
398 // To check if a group already exists, since there is no
399 // worthy function in HDF5, we use the iteration mechanism
400 // to store all child groups of this group, and then search
401 // if the desired group exists
402 HGroupSearch gs(group_name);
403 //cerr << "** CHECK CREATE <" << group_name.str() << ">\n";
404 ARCANE_HDF5_MUTEX;
405 herr_t v = H5Giterate(loc_id, ".", 0, _ArcaneHdf5UtilsGroupIterateMe, &gs);
406
407 // Check if the group already exists
408 //herr_t he = H5Gget_objinfo(loc_id,group_name.str(),true,0);
409 //cerr << "** CHECK CREATE <" << group_name.str() << "> " << v << "\n";
410 //cerr << "** CHECK CREATE <" << group_name.str() << "> " << v << ' ' << he << "\n";
411 if (v > 0) {
412 return _H5Gopen(loc_id, group_name.localstr());
413 }
414 hid_t new_id = _H5Gcreate(loc_id, group_name.localstr());
415 //cerr << "** TRY TO CREATE <" << group_name.str() << "> " << new_id << "\n";
416 return new_id;
417}
418
419/*---------------------------------------------------------------------------*/
420/*---------------------------------------------------------------------------*/
421
422void HGroup::
423create(const Hid& loc_id, const String& group_name)
424{
425 ARCANE_HDF5_MUTEX;
426 _setId(H5Gcreate2(loc_id.id(), group_name.localstr(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT));
427}
428
429/*---------------------------------------------------------------------------*/
430/*---------------------------------------------------------------------------*/
431
432void HGroup::
433openOrCreate(const Hid& loc_id, const String& group_name)
434{
435 hid_t id = _checkOrCreate(loc_id.id(), group_name);
436 if (id < 0)
437 ARCANE_THROW(ReaderWriterException, "Can not open or create group named '{0}'", group_name);
438 _setId(id);
439}
440
441/*---------------------------------------------------------------------------*/
442/*---------------------------------------------------------------------------*/
443
444void HGroup::
445open(const Hid& loc_id, const String& var)
446{
447 hid_t id = -1;
448 {
449 ARCANE_HDF5_MUTEX;
450 id = _H5Gopen(loc_id.id(), var.localstr());
451 }
452 if (id < 0)
453 ARCANE_THROW(ReaderWriterException, "Can not find group named '{0}'", var);
454 _setId(id);
455}
456
457/*---------------------------------------------------------------------------*/
458/*---------------------------------------------------------------------------*/
459
460void HGroup::
461close()
462{
463 if (id() > 0) {
464 ARCANE_HDF5_MUTEX;
465 H5Gclose(id());
466 _setNullId();
467 }
468}
469
470/*---------------------------------------------------------------------------*/
471/*---------------------------------------------------------------------------*/
472
473hid_t HGroup::
474_checkExist(hid_t loc_id, const String& group_name)
475{
476 // To check if a group already exists, since there is no
477 // proper function in HDF5, we use the iteration mechanism
478 // to store all child groups of this group, and then search
479 // if the desired group exists
480 HGroupSearch gs(group_name);
481 //cerr << "** CHECK CREATE <" << group_name.str() << ">\n";
482 ARCANE_HDF5_MUTEX;
483 herr_t v = H5Giterate(loc_id, ".", 0, _ArcaneHdf5UtilsGroupIterateMe, &gs);
484
485 // Check if the group already exists
486 //herr_t he = H5Gget_objinfo(loc_id,group_name.str(),true,0);
487 //cerr << "** CHECK CREATE <" << group_name.str() << "> " << v << "\n";
488 //cerr << "** CHECK CREATE <" << group_name.str() << "> " << v << ' ' << he << "\n";
489 if (v > 0) {
490 return _H5Gopen(loc_id, group_name.localstr());
491 }
492 //hid_t new_id = H5Gcreate(loc_id,group_name.localstr(),0);
493 //cerr << "** TRY TO CREATE <" << group_name.str() << "> " << new_id << "\n";
494 return 0;
495}
496
497/*---------------------------------------------------------------------------*/
498/*---------------------------------------------------------------------------*/
499
500/*---------------------------------------------------------------------------*/
501/*---------------------------------------------------------------------------*/
502
503HSpace::
504~HSpace()
505{
506 if (id() > 0) {
507 ARCANE_HDF5_MUTEX;
508 H5Sclose(id());
509 }
510}
511
512/*---------------------------------------------------------------------------*/
513/*---------------------------------------------------------------------------*/
514
515void HSpace::
516createSimple(int nb, hsize_t dims[])
517{
518 ARCANE_HDF5_MUTEX;
519 _setId(H5Screate_simple(nb, dims, nullptr));
520}
521
522/*---------------------------------------------------------------------------*/
523/*---------------------------------------------------------------------------*/
524
525void HSpace::
526createSimple(int nb, hsize_t dims[], hsize_t max_dims[])
527{
528 ARCANE_HDF5_MUTEX;
529 _setId(H5Screate_simple(nb, dims, max_dims));
530}
531
532/*---------------------------------------------------------------------------*/
533/*---------------------------------------------------------------------------*/
534
535int HSpace::
536nbDimension()
537{
538 ARCANE_HDF5_MUTEX;
539 return H5Sget_simple_extent_ndims(id());
540}
541
542/*---------------------------------------------------------------------------*/
543/*---------------------------------------------------------------------------*/
544
545herr_t HSpace::
546getDimensions(hsize_t dims[], hsize_t max_dims[])
547{
548 ARCANE_HDF5_MUTEX;
549 return H5Sget_simple_extent_dims(id(), dims, max_dims);
550}
551
552/*---------------------------------------------------------------------------*/
553/*---------------------------------------------------------------------------*/
554
555/*---------------------------------------------------------------------------*/
556/*---------------------------------------------------------------------------*/
557
558void HDataset::
559close()
560{
561 if (id() > 0) {
562 ARCANE_HDF5_MUTEX;
563 H5Dclose(id());
564 }
565 _setNullId();
566}
567
568/*---------------------------------------------------------------------------*/
569/*---------------------------------------------------------------------------*/
570
571void HDataset::
572create(const Hid& loc_id, const String& var, hid_t save_type,
573 const HSpace& space_id, hid_t plist)
574{
575 ARCANE_HDF5_MUTEX;
576 hid_t hid = H5Dcreate2(loc_id.id(), var.localstr(), save_type, space_id.id(),
577 plist, H5P_DEFAULT, H5P_DEFAULT);
578 //cerr << "** CREATE ID=" << hid << '\n';
579 _setId(hid);
580}
581
582/*---------------------------------------------------------------------------*/
583/*---------------------------------------------------------------------------*/
584
585void HDataset::
586create(const Hid& loc_id, const String& var, hid_t save_type,
587 const HSpace& space_id, const HProperty& link_plist,
588 const HProperty& creation_plist, const HProperty& access_plist)
589{
590 ARCANE_HDF5_MUTEX;
591 hid_t hid = H5Dcreate2(loc_id.id(), var.localstr(), save_type, space_id.id(),
592 link_plist.id(), creation_plist.id(), access_plist.id());
593 //cerr << "** CREATE ID=" << hid << '\n';
594 _setId(hid);
595}
596
597/*---------------------------------------------------------------------------*/
598/*---------------------------------------------------------------------------*/
599
600herr_t HDataset::
601write(hid_t native_type, const void* array)
602{
603 //cerr << "** WRITE ID=" << id() << '\n';
604 ARCANE_HDF5_MUTEX;
605 return H5Dwrite(id(), native_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, array);
606}
607
608/*---------------------------------------------------------------------------*/
609/*---------------------------------------------------------------------------*/
610
611herr_t HDataset::
612write(hid_t native_type, const void* array, const HSpace& memspace_id,
613 const HSpace& filespace_id, hid_t plist)
614{
615 //cerr << "** WRITE ID=" << id() << '\n';
616 ARCANE_HDF5_MUTEX;
617 return H5Dwrite(id(), native_type, memspace_id.id(), filespace_id.id(), plist, array);
618}
619
620/*---------------------------------------------------------------------------*/
621/*---------------------------------------------------------------------------*/
622
623herr_t HDataset::
624write(hid_t native_type, const void* array, const HSpace& memspace_id,
625 const HSpace& filespace_id, const HProperty& plist)
626{
627 //cerr << "** WRITE ID=" << id() << '\n';
628 ARCANE_HDF5_MUTEX;
629 return H5Dwrite(id(), native_type, memspace_id.id(), filespace_id.id(), plist.id(), array);
630}
631
632/*---------------------------------------------------------------------------*/
633/*---------------------------------------------------------------------------*/
634
635herr_t HDataset::
636read(hid_t native_type, void* array)
637{
638 ARCANE_HDF5_MUTEX;
639 return H5Dread(id(), native_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, array);
640}
641
642/*---------------------------------------------------------------------------*/
643/*---------------------------------------------------------------------------*/
644
645void HDataset::
646readWithException(hid_t native_type, void* array)
647{
648 herr_t err = -1;
649 {
650 ARCANE_HDF5_MUTEX;
651 err = H5Dread(id(), native_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, array);
652 }
653 if (err != 0)
654 ARCANE_THROW(IOException, "Can not read dataset");
655}
656
657/*---------------------------------------------------------------------------*/
658/*---------------------------------------------------------------------------*/
659
660HSpace HDataset::
661getSpace()
662{
663 ARCANE_HDF5_MUTEX;
664 return HSpace(H5Dget_space(id()));
665}
666
667/*---------------------------------------------------------------------------*/
668/*---------------------------------------------------------------------------*/
669
670herr_t HDataset::
671setExtent(const hsize_t new_dims[])
672{
673 ARCANE_HDF5_MUTEX;
674 return H5Dset_extent(id(), new_dims);
675}
676
677/*---------------------------------------------------------------------------*/
678/*---------------------------------------------------------------------------*/
679
680void HDataset::
681recursiveCreate(const Hid& loc_id, const String& var, hid_t save_type,
682 const HSpace& space_id, hid_t plist)
683{
684 // If the dataset already exists, it must be removed
685 // otherwise it is not always possible to modify the space_id
686 UniqueArray<String> paths;
687 splitString(var, paths, '/');
688 Integer nb_path = paths.size();
689 if (nb_path == 1) {
690 if (HGroup::hasChildren(loc_id.id(), var)) {
691 _remove(loc_id.id(), var);
692 }
693 create(loc_id, var, save_type, space_id, plist);
694 return;
695 }
696 String last_name = paths[nb_path - 1];
697 paths.resize(nb_path - 1);
698 HGroup group;
699 group.recursiveCreate(loc_id, paths);
700 if (group.hasChildren(last_name)) {
701 _remove(group.id(), last_name);
702 }
703 create(group.id(), last_name, save_type, space_id, plist);
704}
705
706/*---------------------------------------------------------------------------*/
707/*---------------------------------------------------------------------------*/
708
709void HDataset::
710_remove(hid_t hid, const String& var)
711{
712 ARCANE_HDF5_MUTEX;
713 H5Gunlink(hid, var.localstr());
714}
715
716/*---------------------------------------------------------------------------*/
717/*---------------------------------------------------------------------------*/
718
719HAttribute::
720~HAttribute()
721{
722 if (id() > 0) {
723 ARCANE_HDF5_MUTEX;
724 H5Aclose(id());
725 }
726}
727
728/*---------------------------------------------------------------------------*/
729/*---------------------------------------------------------------------------*/
730
731void HAttribute::
732remove(const Hid& loc_id, const String& var)
733{
734 ARCANE_HDF5_MUTEX;
735 _setId(H5Adelete(loc_id.id(), var.localstr()));
736}
737
738/*---------------------------------------------------------------------------*/
739/*---------------------------------------------------------------------------*/
740
741void HAttribute::
742create(const Hid& loc_id, const String& var, hid_t save_type, const HSpace& space_id)
743{
744 ARCANE_HDF5_MUTEX;
745 _setId(H5Acreate2(loc_id.id(), var.localstr(), save_type, space_id.id(), H5P_DEFAULT, H5P_DEFAULT));
746}
747
748/*---------------------------------------------------------------------------*/
749/*---------------------------------------------------------------------------*/
750
751void HAttribute::
752open(const Hid& loc_id, const String& var)
753{
754 ARCANE_HDF5_MUTEX;
755 _setId(H5Aopen_name(loc_id.id(), var.localstr()));
756}
757
758/*---------------------------------------------------------------------------*/
759/*---------------------------------------------------------------------------*/
760
761herr_t HAttribute::
762write(hid_t native_type, void* array)
763{
764 ARCANE_HDF5_MUTEX;
765 return H5Awrite(id(), native_type, array);
766}
767
768/*---------------------------------------------------------------------------*/
769/*---------------------------------------------------------------------------*/
770
771herr_t HAttribute::
772read(hid_t native_type, void* array)
773{
774 ARCANE_HDF5_MUTEX;
775 return H5Aread(id(), native_type, array);
776}
777
778/*---------------------------------------------------------------------------*/
779/*---------------------------------------------------------------------------*/
780
781HSpace HAttribute::
782getSpace()
783{
784 ARCANE_HDF5_MUTEX;
785 return HSpace(H5Aget_space(id()));
786}
787
788/*---------------------------------------------------------------------------*/
789/*---------------------------------------------------------------------------*/
790
791/*---------------------------------------------------------------------------*/
792/*---------------------------------------------------------------------------*/
793
794HType::
795~HType()
796{
797 if (id() > 0) {
798 ARCANE_HDF5_MUTEX;
799 H5Tclose(id());
800 }
801}
802
803/*---------------------------------------------------------------------------*/
804/*---------------------------------------------------------------------------*/
805
806/*---------------------------------------------------------------------------*/
807/*---------------------------------------------------------------------------*/
808
809void HDataset::
810open(const Hid& loc_id, const String& var)
811{
812 {
813 ARCANE_HDF5_MUTEX;
814 _setId(H5Dopen2(loc_id.id(), var.localstr(), H5P_DEFAULT));
815 }
816 if (isBad())
817 ARCANE_THROW(IOException, "Can not open dataset '{0}'", var);
818}
819
820/*---------------------------------------------------------------------------*/
821/*---------------------------------------------------------------------------*/
822
823void HDataset::
824openIfExists(const Hid& loc_id, const String& var)
825{
826 UniqueArray<String> paths;
827 splitString(var, paths, '/');
828 Integer nb_path = paths.size();
829 HGroup parent_group;
830 String last_name = var;
831 if (nb_path > 1) {
832 last_name = paths[nb_path - 1];
833 paths.resize(nb_path - 1);
834 parent_group.openIfExists(loc_id, paths);
835 }
836 else {
837 parent_group.open(loc_id, ".");
838 }
839 if (parent_group.isBad())
840 return;
841 if (parent_group.hasChildren(last_name))
842 open(loc_id.id(), var.localstr());
843}
844
845/*---------------------------------------------------------------------------*/
846/*---------------------------------------------------------------------------*/
847
848/*---------------------------------------------------------------------------*/
849/*---------------------------------------------------------------------------*/
850
851void HProperty::
852close()
853{
854 if (id() > 0) {
855 ARCANE_HDF5_MUTEX;
856 H5Pclose(id());
857 _setNullId();
858 }
859}
860
861/*---------------------------------------------------------------------------*/
862/*---------------------------------------------------------------------------*/
863
864void HProperty::
865create(hid_t cls_id)
866{
867 close();
868 ARCANE_HDF5_MUTEX;
869 _setId(H5Pcreate(cls_id));
870}
871
872/*---------------------------------------------------------------------------*/
873/*---------------------------------------------------------------------------*/
874
877{
878#ifdef H5_HAVE_PARALLEL
879 void* arcane_comm = pm->getMPICommunicator();
880 if (!arcane_comm)
881 ARCANE_FATAL("No MPI environment available");
882 MPI_Comm mpi_comm = *((MPI_Comm*)arcane_comm);
883 MPI_Info mpi_info = MPI_INFO_NULL;
884
885 create(H5P_FILE_ACCESS);
886 H5Pset_fapl_mpio(id(), mpi_comm, mpi_info);
887#else
888 ARCANE_UNUSED(pm);
889 ARCANE_THROW(NotSupportedException, "HDF5 is not compiled with MPI support");
890#endif
891}
892
893/*---------------------------------------------------------------------------*/
894/*---------------------------------------------------------------------------*/
895
898{
899#ifdef H5_HAVE_PARALLEL
900 create(H5P_DATASET_XFER);
901 H5Pset_dxpl_mpio(id(), H5FD_MPIO_COLLECTIVE);
902
903#if (H5_VERS_MAJOR >= 2 || H5_VERS_MINOR >= 14)
904 H5Pset_selection_io(id(), H5D_SELECTION_IO_MODE_OFF);
905#endif
906
907#else
908 ARCANE_THROW(NotSupportedException, "HDF5 is not compiled with MPI support");
909#endif
910}
911
912/*---------------------------------------------------------------------------*/
913/*---------------------------------------------------------------------------*/
914
917{
918#ifdef H5_HAVE_PARALLEL
919 create(H5P_DATASET_XFER);
920 H5Pset_dxpl_mpio(id(), H5FD_MPIO_INDEPENDENT);
921
922#if (H5_VERS_MAJOR >= 2 || H5_VERS_MINOR >= 14)
923 H5Pset_selection_io(id(), H5D_SELECTION_IO_MODE_OFF);
924#endif
925
926#else
927 ARCANE_THROW(NotSupportedException, "HDF5 is not compiled with MPI support");
928#endif
929}
930
931/*---------------------------------------------------------------------------*/
932/*---------------------------------------------------------------------------*/
933
934/*---------------------------------------------------------------------------*/
935/*---------------------------------------------------------------------------*/
936
942
943/*---------------------------------------------------------------------------*/
944/*---------------------------------------------------------------------------*/
945
947StandardTypes(bool do_init)
948{
949 if (do_init)
950 initialize();
951}
952
953/*---------------------------------------------------------------------------*/
954/*---------------------------------------------------------------------------*/
955
958{
959 ARCANE_HDF5_MUTEX;
960 {
961 hid_t type_id = H5Tcopy(H5T_NATIVE_CHAR);
962 m_char_id.setId(type_id);
963 }
964 {
965 hid_t type_id = H5Tcopy(H5T_NATIVE_UCHAR);
966 m_uchar_id.setId(type_id);
967 }
968 {
969 hid_t type_id = H5Tcopy(H5T_NATIVE_SCHAR);
970 m_schar_id.setId(type_id);
971 }
972 {
973 hid_t type_id = H5Tcopy(H5T_NATIVE_SHORT);
974 H5Tset_precision(type_id, 8 * sizeof(short));
975 H5Tset_order(type_id, H5T_ORDER_LE);
976 m_short_id.setId(type_id);
977 }
978 {
979 hid_t type_id = H5Tcopy(H5T_NATIVE_INT);
980 H5Tset_precision(type_id, 8 * sizeof(int));
981 H5Tset_order(type_id, H5T_ORDER_LE);
982 m_int_id.setId(type_id);
983 }
984 {
985 hid_t type_id = H5Tcopy(H5T_NATIVE_LONG);
986 H5Tset_precision(type_id, 8 * sizeof(long));
987 H5Tset_order(type_id, H5T_ORDER_LE);
988 m_long_id.setId(type_id);
989 }
990 {
991 hid_t type_id = H5Tcopy(H5T_NATIVE_USHORT);
992 H5Tset_precision(type_id, 8 * sizeof(unsigned short));
993 H5Tset_order(type_id, H5T_ORDER_LE);
994 m_ushort_id.setId(type_id);
995 }
996 {
997 hid_t type_id = H5Tcopy(H5T_NATIVE_UINT);
998 H5Tset_precision(type_id, 8 * sizeof(unsigned int));
999 H5Tset_order(type_id, H5T_ORDER_LE);
1000 m_uint_id.setId(type_id);
1001 }
1002 {
1003 hid_t type_id = H5Tcopy(H5T_NATIVE_ULONG);
1004 H5Tset_precision(type_id, 8 * sizeof(unsigned long));
1005 H5Tset_order(type_id, H5T_ORDER_LE);
1006 m_ulong_id.setId(type_id);
1007 }
1008 {
1009 hid_t type_id = H5Tcopy(H5T_NATIVE_FLOAT);
1010 H5Tset_precision(type_id, 8 * sizeof(float));
1011 H5Tset_order(type_id, H5T_ORDER_LE);
1012 m_float32_id.setId(type_id);
1013 }
1014 {
1015 hid_t type_id = H5Tcopy(H5T_NATIVE_DOUBLE);
1016 H5Tset_precision(type_id, 8 * sizeof(double));
1017 H5Tset_order(type_id, H5T_ORDER_LE);
1018 m_real_id.setId(type_id);
1019 }
1020 {
1021 hid_t type_id = H5Tcreate(H5T_COMPOUND, sizeof(Real2POD));
1022 _H5Tinsert(type_id, "X", HOFFSET(Real2POD, x), H5T_NATIVE_DOUBLE);
1023 _H5Tinsert(type_id, "Y", HOFFSET(Real2POD, y), H5T_NATIVE_DOUBLE);
1024 m_real2_id.setId(type_id);
1025 }
1026 {
1027 hid_t type_id = H5Tcreate(H5T_COMPOUND, sizeof(Real3POD));
1028 _H5Tinsert(type_id, "X", HOFFSET(Real3POD, x), H5T_NATIVE_DOUBLE);
1029 _H5Tinsert(type_id, "Y", HOFFSET(Real3POD, y), H5T_NATIVE_DOUBLE);
1030 _H5Tinsert(type_id, "Z", HOFFSET(Real3POD, z), H5T_NATIVE_DOUBLE);
1031 m_real3_id.setId(type_id);
1032 }
1033 {
1034 hid_t type_id = H5Tcreate(H5T_COMPOUND, sizeof(Real2x2POD));
1035 _H5Tinsert(type_id, "XX", HOFFSET(Real2x2POD, x.x), H5T_NATIVE_DOUBLE);
1036 _H5Tinsert(type_id, "XY", HOFFSET(Real2x2POD, x.y), H5T_NATIVE_DOUBLE);
1037 _H5Tinsert(type_id, "YX", HOFFSET(Real2x2POD, y.x), H5T_NATIVE_DOUBLE);
1038 _H5Tinsert(type_id, "YY", HOFFSET(Real2x2POD, y.y), H5T_NATIVE_DOUBLE);
1039 m_real2x2_id.setId(type_id);
1040 }
1041 {
1042 hid_t type_id = H5Tcreate(H5T_COMPOUND, sizeof(Real3x3POD));
1043 _H5Tinsert(type_id, "XX", HOFFSET(Real3x3POD, x.x), H5T_NATIVE_DOUBLE);
1044 _H5Tinsert(type_id, "XY", HOFFSET(Real3x3POD, x.y), H5T_NATIVE_DOUBLE);
1045 _H5Tinsert(type_id, "XZ", HOFFSET(Real3x3POD, x.z), H5T_NATIVE_DOUBLE);
1046 _H5Tinsert(type_id, "YX", HOFFSET(Real3x3POD, y.x), H5T_NATIVE_DOUBLE);
1047 _H5Tinsert(type_id, "YY", HOFFSET(Real3x3POD, y.y), H5T_NATIVE_DOUBLE);
1048 _H5Tinsert(type_id, "YZ", HOFFSET(Real3x3POD, y.z), H5T_NATIVE_DOUBLE);
1049 _H5Tinsert(type_id, "ZX", HOFFSET(Real3x3POD, z.x), H5T_NATIVE_DOUBLE);
1050 _H5Tinsert(type_id, "ZY", HOFFSET(Real3x3POD, z.y), H5T_NATIVE_DOUBLE);
1051 _H5Tinsert(type_id, "ZZ", HOFFSET(Real3x3POD, z.z), H5T_NATIVE_DOUBLE);
1052 m_real3x3_id.setId(type_id);
1053 }
1054
1055 // HDF5 1.10 and 1.12 do not yet support 'BFloat16' and 'Float16' types.
1056 // When that is the case, we will be able to use the type provided by HDF5.
1057 // (NOTE: HDF5 1.14.4 supports Float16)
1058
1059 // Add opaque type for BFloat16.
1060 {
1061 hid_t type_id = H5Tcopy(H5T_NATIVE_B16);
1062 m_bfloat16_id.setId(type_id);
1063 }
1064 // Add opaque type for Float16.
1065 {
1066 hid_t type_id = H5Tcopy(H5T_NATIVE_B16);
1067 m_float16_id.setId(type_id);
1068 }
1069}
1070
1071/*---------------------------------------------------------------------------*/
1072/*---------------------------------------------------------------------------*/
1073
1074StandardTypes::
1075~StandardTypes()
1076{
1077}
1078
1079/*---------------------------------------------------------------------------*/
1080/*---------------------------------------------------------------------------*/
1081
1082void StandardTypes::
1083_H5Tinsert(hid_t type, const char* name, Integer offset, hid_t field_id)
1084{
1085 // Mutex managed by initialize.
1086 herr_t herr = H5Tinsert(type, name, offset, field_id);
1087 if (herr < 0) {
1088 ARCANE_FATAL("Can not insert type");
1089 }
1090}
1091
1092/*---------------------------------------------------------------------------*/
1093/*---------------------------------------------------------------------------*/
1094
1095#ifdef ARCANE_REAL_NOT_BUILTIN
1096hid_t StandardTypes::
1097nativeType(Real) const
1098{
1099 ARCANE_FATAL("Real is a complex type");
1100}
1101#endif
1102
1103hid_t StandardTypes::
1104saveType(eDataType sd) const
1105{
1106 switch (sd) {
1107 case DT_Byte:
1108 return saveType(Byte());
1109 case DT_Real:
1110 return saveType(Real());
1111 case DT_Real2:
1112 return saveType(Real2());
1113 case DT_Real2x2:
1114 return saveType(Real2x2());
1115 case DT_Real3:
1116 return saveType(Real3());
1117 case DT_Real3x3:
1118 return saveType(Real3x3());
1119 case DT_Int8:
1120 return saveType(Int8());
1121 case DT_Int16:
1122 return saveType(Int16());
1123 case DT_Int32:
1124 return saveType(Int32());
1125 case DT_Int64:
1126 return saveType(Int64());
1127 case DT_Float32:
1128 return saveType(Float32());
1129 case DT_Float16:
1130 return saveType(Float16());
1131 case DT_BFloat16:
1132 return saveType(BFloat16());
1133 default:
1134 throw ArgumentException(String::format("Bad type '{0}'", sd));
1135 }
1136}
1137
1138/*---------------------------------------------------------------------------*/
1139/*---------------------------------------------------------------------------*/
1140
1141hid_t StandardTypes::
1142nativeType(eDataType sd) const
1143{
1144 switch (sd) {
1145 case DT_Byte:
1146 return nativeType(Byte());
1147 case DT_Real:
1148 return nativeType(Real());
1149 case DT_Real2:
1150 return nativeType(Real2());
1151 case DT_Real2x2:
1152 return nativeType(Real2x2());
1153 case DT_Real3:
1154 return nativeType(Real3());
1155 case DT_Real3x3:
1156 return nativeType(Real3x3());
1157 case DT_Int8:
1158 return nativeType(Int8());
1159 case DT_Int16:
1160 return nativeType(Int16());
1161 case DT_Int32:
1162 return nativeType(Int32());
1163 case DT_Int64:
1164 return nativeType(Int64());
1165 case DT_Float32:
1166 return nativeType(Float32());
1167 case DT_Float16:
1168 return nativeType(Float16());
1169 case DT_BFloat16:
1170 return nativeType(BFloat16());
1171 default:
1172 throw ArgumentException(String::format("Bad type '{0}'", sd));
1173 }
1174}
1175
1176/*---------------------------------------------------------------------------*/
1177/*---------------------------------------------------------------------------*/
1178
1179/*---------------------------------------------------------------------------*/
1180/*---------------------------------------------------------------------------*/
1181
1182StandardArray::
1183StandardArray(hid_t hfile, const String& hpath)
1184: m_hfile(hfile)
1185, m_hpath(hpath)
1186, m_ids_hpath(hpath + "_Ids")
1187, m_is_init(false)
1188{
1189}
1190
1191/*---------------------------------------------------------------------------*/
1192/*---------------------------------------------------------------------------*/
1193
1194void StandardArray::
1195readDim()
1196{
1197 if (m_is_init)
1198 return;
1199 m_is_init = true;
1200 m_hdataset.open(m_hfile, m_hpath);
1201 HSpace hspace(m_hdataset.getSpace());
1202 {
1203 const int max_dim = 256; // Maximum number of dimensions for HDF arrays
1204 hsize_t hdf_dims[max_dim];
1205 hsize_t max_dims[max_dim];
1206 int nb_dim = -1;
1207 {
1208 ARCANE_HDF5_MUTEX;
1209 nb_dim = H5Sget_simple_extent_ndims(hspace.id());
1210 H5Sget_simple_extent_dims(hspace.id(), hdf_dims, max_dims);
1211 }
1212 for (Integer i = 0; i < nb_dim; ++i) {
1213 //cerr << "** DIM i=" << i << " hdim=" << hdf_dims[i]
1214 // << " max=" << max_dims[i] << '\n';
1215 m_dimensions.add((Int64)hdf_dims[i]);
1216 }
1217 }
1218 // Checks if a variable suffixed '_Ids' exists containing the unique numbers
1219 // of the entities
1220 m_ids_dataset.openIfExists(m_hfile, m_ids_hpath);
1221 //cout << "TRY OPEN ID DATASET path=" << m_ids_hpath << " r=" << m_ids_dataset.id()>0 << '\n';
1222}
1223
1224/*---------------------------------------------------------------------------*/
1225/*---------------------------------------------------------------------------*/
1226
1228setIdsPath(const String& ids_path)
1229{
1230 m_ids_hpath = ids_path;
1231}
1232
1233/*---------------------------------------------------------------------------*/
1234/*---------------------------------------------------------------------------*/
1235
1236void StandardArray::
1237_write(const void* buffer, Integer nb_element, hid_t save_type, hid_t native_type)
1238{
1239 if (!m_is_init) {
1240 hsize_t dims[1];
1241 dims[0] = nb_element;
1242
1243 HSpace hspace;
1244 hspace.createSimple(1, dims);
1245 if (hspace.isBad())
1246 ARCANE_THROW(IOException, "Can not create space");
1247
1248 m_dimensions.clear();
1249 m_dimensions.add(nb_element);
1250
1251 m_hdataset.recursiveCreate(m_hfile, m_hpath, save_type, hspace, H5P_DEFAULT);
1252 if (m_hdataset.isBad())
1253 ARCANE_THROW(IOException, "Can not create dataset");
1254
1255 m_is_init = true;
1256 }
1257
1258 m_hdataset.write(native_type, buffer);
1259}
1260
1261/*---------------------------------------------------------------------------*/
1262/*---------------------------------------------------------------------------*/
1263
1264bool StandardArray::
1265exists() const
1266{
1267 HDataset dataset;
1268 dataset.openIfExists(m_hfile, m_hpath);
1269 return dataset.id() > 0;
1270}
1271
1272/*---------------------------------------------------------------------------*/
1273/*---------------------------------------------------------------------------*/
1274
1275template <typename DataType> StandardArrayT<DataType>::
1276StandardArrayT(hid_t hfile, const String& hpath)
1277: StandardArray(hfile, hpath)
1278{
1279}
1280
1281/*---------------------------------------------------------------------------*/
1282/*---------------------------------------------------------------------------*/
1283
1284template <typename DataType> void StandardArrayT<DataType>::
1286{
1287 m_hdataset.readWithException(st.nativeType(DataType()), buffer.data());
1288}
1289
1290/*---------------------------------------------------------------------------*/
1291/*---------------------------------------------------------------------------*/
1292
1293template <typename DataType> void StandardArrayT<DataType>::
1295{
1296 readDim();
1297 buffer.resize(m_dimensions[0]);
1298 read(st, buffer);
1299}
1300
1301/*---------------------------------------------------------------------------*/
1302/*---------------------------------------------------------------------------*/
1303
1304template <typename DataType> void StandardArrayT<DataType>::
1306{
1307 bool is_master = pm->isMasterIO();
1308 Integer master_rank = pm->masterIORank();
1309 bool has_ids = false;
1310 if (is_master) {
1311 read(st, buffer);
1312 Integer buf_size = buffer.size();
1313 if (m_ids_dataset.id() > 0) {
1314 has_ids = true;
1315 m_ids_dataset.read(st.nativeType(Int64()), unique_ids.data());
1316 }
1317 Integer infos[2];
1318 infos[0] = buf_size;
1319 infos[1] = has_ids ? 1 : 0;
1320 IntegerArrayView iav(2, infos);
1321 pm->broadcast(iav, master_rank);
1322 pm->broadcast(buffer, master_rank);
1323 pm->broadcast(unique_ids, master_rank);
1324 }
1325 else {
1326 Integer infos[2];
1327 IntegerArrayView iav(2, infos);
1328 pm->broadcast(iav, master_rank);
1329 Integer buf_size = infos[0];
1330 has_ids = infos[1] != 0;
1331 buffer.resize(buf_size);
1332 unique_ids.resize(buf_size);
1333 pm->broadcast(buffer, master_rank);
1334 pm->broadcast(unique_ids, master_rank);
1335 }
1336 if (!has_ids) {
1337 for (Integer i = 0, is = unique_ids.size(); i < is; ++i)
1338 unique_ids[i] = i;
1339 }
1340}
1341
1342/*---------------------------------------------------------------------------*/
1343/*---------------------------------------------------------------------------*/
1344
1345template <typename DataType> void StandardArrayT<DataType>::
1346write(StandardTypes& st, ConstArrayView<DataType> buffer)
1347{
1348 Integer nb_element = buffer.size();
1349 _write(buffer.data(), nb_element, st.saveType(DataType()), st.nativeType(DataType()));
1350}
1351
1352/*---------------------------------------------------------------------------*/
1353/*---------------------------------------------------------------------------*/
1354
1355template <typename DataType> void StandardArrayT<DataType>::
1356_writeSortedValues(ITraceMng* tm, StandardTypes& st,
1357 ConstArrayView<DataType> buffer,
1358 Int64ConstArrayView unique_ids)
1359{
1360 ARCANE_UNUSED(tm);
1361
1362 Integer total_size = buffer.size();
1363 Integer nb_element = unique_ids.size();
1364 Integer dim2_size = 1;
1365 if (nb_element != total_size) {
1366 if (nb_element == 0)
1367 ARCANE_THROW(ArgumentException, "unique_ids size is zero but not buffer size ({0})",
1368 total_size);
1369 dim2_size = total_size / nb_element;
1370 if (dim2_size * nb_element != total_size)
1371 ARCANE_THROW(ArgumentException, "buffer size ({0}) is not a multiple of unique_ids size ({1})",
1372 total_size, nb_element);
1373 }
1374
1375 UniqueArray<ValueWithUid> values_to_sort(nb_element);
1376 UniqueArray<DataType> out_buffer(total_size);
1377 //tm->info() << " WRITE total_size=" << total_size
1378 //<< " uid_size=" << unique_ids.size();
1379 for (Integer i = 0; i < nb_element; ++i) {
1380 values_to_sort[i].m_uid = unique_ids[i];
1381 values_to_sort[i].m_index = i;
1382 //values_to_sort[i].m_value = buffer[i];
1383 //tm->info() << "BEFORE SORT i=" << i << " uid=" << unique_ids[i];
1384 }
1385 std::sort(std::begin(values_to_sort), std::end(values_to_sort));
1386 for (Integer i = 0; i < nb_element; ++i) {
1387 Integer old_index = values_to_sort[i].m_index;
1388 for (Integer j = 0; j < dim2_size; ++j) {
1389 Integer pos = (i * dim2_size) + j;
1390 out_buffer[pos] = buffer[(old_index * dim2_size) + j];
1391 //tm->info() << "AFTER SORT i=" << i << " uid=" << values_to_sort[i].m_uid
1392 // << " j=" << j << " pos=" << pos
1393 // << " value=" << out_buffer[pos];
1394 }
1395 }
1396 write(st, out_buffer);
1397}
1398
1399/*---------------------------------------------------------------------------*/
1400/*---------------------------------------------------------------------------*/
1401
1402template <typename DataType> void StandardArrayT<DataType>::
1403parallelWrite(IParallelMng* pm, StandardTypes& st,
1404 ConstArrayView<DataType> buffer, Int64ConstArrayView unique_ids)
1405{
1406 //TODO:
1407 // For now, only the master process writes.
1408 // It retrieves all values, sorts them by increasing uniqueId
1409 // and writes them.
1410 // It is important that everything is sorted in ascending order because
1411 // this allows maintaining the same writing order even when mesh partitioning
1412 // occurs. The read operation assumes this constraint is met and only reads the
1413 // uniqueId information at the start of the case.
1414 bool is_parallel = pm->isParallel();
1415 ITraceMng* tm = pm->traceMng();
1416
1417 if (!is_parallel) {
1418 _writeSortedValues(tm, st, buffer, unique_ids);
1419 return;
1420 }
1421
1422 bool is_master = pm->isMasterIO();
1423 Integer master_rank = pm->masterIORank();
1424 Integer nb_rank = pm->commSize();
1425 Integer buf_size = buffer.size();
1426 Integer unique_id_size = unique_ids.size();
1427 IntegerUniqueArray rank_sizes(2 * nb_rank);
1428 // The master subdomain retrieves information from all others.
1429 // If a subdomain has no elements to send, it does nothing
1430 // (it does not send empty buffers)
1431 if (is_master) {
1432 Integer buf[2];
1433 buf[0] = buf_size;
1434 buf[1] = unique_id_size;
1435 IntegerArrayView iav(2, buf);
1436 pm->allGather(iav, rank_sizes);
1437
1438 Integer buffer_total_size = 0;
1439 Integer unique_id_total_size = 0;
1440 IntegerUniqueArray buffer_rank_index(nb_rank);
1441 IntegerUniqueArray unique_id_rank_index(nb_rank);
1442
1443 for (Integer i = 0; i < nb_rank; ++i) {
1444 buffer_rank_index[i] = buffer_total_size;
1445 buffer_total_size += rank_sizes[(i * 2)];
1446 unique_id_rank_index[i] = unique_id_total_size;
1447 unique_id_total_size += rank_sizes[(i * 2) + 1];
1448 }
1449
1450 UniqueArray<DataType> full_buffer(buffer_total_size);
1451 Int64UniqueArray full_unique_ids(unique_id_total_size);
1452
1453 for (Integer i = 0; i < nb_rank; ++i) {
1454 // Ne recoit pas de valeurs des processus n'ayant pas de valeurs
1455 if (rank_sizes[(i * 2)] == 0)
1456 continue;
1457 ArrayView<DataType> local_buf(rank_sizes[(i * 2)], &full_buffer[buffer_rank_index[i]]);
1458 Int64ArrayView local_unique_ids(rank_sizes[(i * 2) + 1], &full_unique_ids[unique_id_rank_index[i]]);
1459 if (i == master_rank) {
1460 local_buf.copy(buffer);
1461 local_unique_ids.copy(unique_ids);
1462 }
1463 else {
1464 pm->recv(local_buf, i);
1465 pm->recv(local_unique_ids, i);
1466 }
1467 }
1468 tm->info(5) << "PARALLEL WRITE path=" << m_hpath << " total_size=" << full_buffer.size();
1469 _writeSortedValues(tm, st, full_buffer, full_unique_ids);
1470 }
1471 else {
1472 Integer buf[2];
1473 buf[0] = buf_size;
1474 buf[1] = unique_id_size;
1475 IntegerArrayView iav(2, buf);
1476 pm->allGather(iav, rank_sizes);
1477 // No need to send empty buffers
1478 if (buffer.size() > 0) {
1479 pm->send(buffer, master_rank);
1480 pm->send(unique_ids, master_rank);
1481 }
1482 }
1483}
1484
1485/*---------------------------------------------------------------------------*/
1486/*---------------------------------------------------------------------------*/
1487
1488template class StandardArrayT<Real>;
1489template class StandardArrayT<Real3>;
1490template class StandardArrayT<Real3x3>;
1491template class StandardArrayT<Real2>;
1492template class StandardArrayT<Real2x2>;
1493template class StandardArrayT<Int16>;
1494template class StandardArrayT<Int32>;
1495template class StandardArrayT<Int64>;
1496template class StandardArrayT<Byte>;
1497template class StandardArrayT<Int8>;
1498template class StandardArrayT<Float32>;
1499// NOTE: these types cannot yet be instantiated because they require
1500// the ability to perform send/receive via IParallelMng, which is not
1501// yet implemented.
1502//template class StandardArrayT<Float16>;
1503//template class StandardArrayT<BFloat16>;
1504
1505/*---------------------------------------------------------------------------*/
1506/*---------------------------------------------------------------------------*/
1507
1508template <typename DataType> DataType
1511{
1512 Hdf5Utils::HDataset m_hdataset;
1513 m_hdataset.open(m_hfile, m_hpath);
1514 Hdf5Utils::HSpace hspace(m_hdataset.getSpace());
1515 {
1516 const int max_dim = 256; // Maximum number of HDF array dimensions
1517 hsize_t hdf_dims[max_dim];
1518 hsize_t max_dims[max_dim];
1519 int nb_dim = -1;
1520 {
1521 ARCANE_HDF5_MUTEX;
1522 nb_dim = H5Sget_simple_extent_ndims(hspace.id());
1523 H5Sget_simple_extent_dims(hspace.id(), hdf_dims, max_dims);
1524 }
1525 if (nb_dim != 1 || hdf_dims[0] != 1)
1526 ARCANE_THROW(IOException, "Cannot read non scalar");
1527 }
1528
1529 DataType dummy;
1530 m_hdataset.read(st.nativeType(DataType()), &dummy);
1531 return dummy;
1532}
1533
1534/*---------------------------------------------------------------------------*/
1535
1536template <> String
1539{
1540 ByteUniqueArray utf8_bytes;
1541
1542 Hdf5Utils::HDataset m_hdataset;
1543 m_hdataset.open(m_hfile, m_hpath);
1544 Hdf5Utils::HSpace hspace(m_hdataset.getSpace());
1545 {
1546 const int max_dim = 256; // Maximum number of HDF array dimensions
1547 hsize_t hdf_dims[max_dim];
1548 hsize_t max_dims[max_dim];
1549 int nb_dim = -1;
1550 {
1551 ARCANE_HDF5_MUTEX;
1552 nb_dim = H5Sget_simple_extent_ndims(hspace.id());
1553 H5Sget_simple_extent_dims(hspace.id(), hdf_dims, max_dims);
1554 }
1555
1556 if (nb_dim != 1)
1557 ARCANE_THROW(IOException, "Cannot read multidim string");
1558 utf8_bytes.resize(hdf_dims[0]);
1559 }
1560
1561 m_hdataset.read(st.nativeType(Byte()), utf8_bytes.data());
1562 return String(utf8_bytes);
1563}
1564
1565/*---------------------------------------------------------------------------*/
1566
1567template <typename DataType> void
1569write(Hdf5Utils::StandardTypes& st, const DataType& t)
1570{
1571 hsize_t dims[1] = { 1 };
1572 Hdf5Utils::HSpace hspace;
1573 hspace.createSimple(1, dims);
1574 if (hspace.isBad())
1575 ARCANE_THROW(IOException, "Can not create space");
1576
1577 Hdf5Utils::HDataset m_hdataset;
1578 m_hdataset.recursiveCreate(m_hfile, m_hpath, st.saveType(DataType()), hspace, H5P_DEFAULT);
1579 if (m_hdataset.isBad())
1580 ARCANE_THROW(IOException, "Can not create dataset");
1581
1582 herr_t herr = m_hdataset.write(st.nativeType(DataType()), &t);
1583 if (herr < 0)
1584 ARCANE_THROW(IOException, "Cannot write data");
1585}
1586
1587/*---------------------------------------------------------------------------*/
1588
1589template <> void
1592{
1593 ByteConstArrayView utf8_bytes = s.utf8();
1594
1595 hsize_t dims[1];
1596 dims[0] = utf8_bytes.size() + 1;
1597
1598 Hdf5Utils::HSpace hspace;
1599 hspace.createSimple(1, dims);
1600 if (hspace.isBad())
1601 ARCANE_THROW(IOException, "Can not create space");
1602
1603 Hdf5Utils::HDataset m_hdataset;
1604 m_hdataset.recursiveCreate(m_hfile, m_hpath, st.saveType(Byte()), hspace, H5P_DEFAULT);
1605 if (m_hdataset.isBad())
1606 ARCANE_THROW(IOException, "Can not create dataset");
1607
1608 herr_t herr = m_hdataset.write(st.nativeType(Byte()), utf8_bytes.data());
1609 if (herr < 0)
1610 ARCANE_THROW(IOException, "Cannot write data");
1611}
1612
1613/*---------------------------------------------------------------------------*/
1614
1615template class StandardScalarT<String>;
1616template class StandardScalarT<Real>;
1617template class StandardScalarT<Real3>;
1618template class StandardScalarT<Real3x3>;
1619template class StandardScalarT<Real2>;
1620template class StandardScalarT<Real2x2>;
1621template class StandardScalarT<Int16>;
1622template class StandardScalarT<Int32>;
1623template class StandardScalarT<Int64>;
1624template class StandardScalarT<Byte>;
1625template class StandardScalarT<Int8>;
1626template class StandardScalarT<Float16>;
1627template class StandardScalarT<BFloat16>;
1628template class StandardScalarT<Float32>;
1629
1630/*---------------------------------------------------------------------------*/
1631/*---------------------------------------------------------------------------*/
1632
1633} // namespace Arcane::Hdf5Utils
1634
1635/*---------------------------------------------------------------------------*/
1636/*---------------------------------------------------------------------------*/
#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.
Modifiable view of an array of type T.
constexpr const_pointer data() const noexcept
Pointer to the start of the view.
Base class for 1D data vectors.
void resize(Int64 s)
Changes the number of elements in the array to s.
void clear()
Removes the elements from the array.
void add(ConstReferenceType val)
Adds element val to the end of the array.
const T * data() const
Access to the root of the array without any protection.
constexpr const_pointer data() const noexcept
Pointer to the allocated memory.
constexpr Integer size() const noexcept
Number of elements in the array.
Template class for converting a type.
Encapsulates a hid_t for a dataset.
Helper class for searching a group.
static void useMutex(bool is_active, IParallelMng *pm)
Function allowing activation or deactivation of locks on each HDF5 call.
Definition Hdf5Utils.cc:90
Encapsulates a hid_t for a property (H5P*).
void createDatasetTransfertCollectiveMPIIO()
Creates a dataset property for MPIIO.
Definition Hdf5Utils.cc:897
void createFilePropertyMPIIO(IParallelMng *pm)
Creates a file property for MPIIO.
Definition Hdf5Utils.cc:876
void createDatasetTransfertIndependentMPIIO()
Creates a dataset property for MPIIO.
Definition Hdf5Utils.cc:916
Encapsulates a hid_t for a dataspace.
Encapsulates a hid_t.
Encapsulates a simple dataset from an HDF5 file that represents an array.
void read(StandardTypes &st, ArrayView< DataType > buffer)
Reads the dataset of a 1D array. This operation is only valid after calling readDim()....
void directRead(StandardTypes &st, Array< DataType > &buffer)
Reads the dataset of a 1D array.
Encapsulates a simple dataset from an HDF5 file that represents an array.
void setIdsPath(const String &ids_path)
When reading, positions the path in hfile to the dataset containing the unique_ids.
Encapsulates a simple dataset from an HDF5 file that represents a scalar (possibly String).
DataType read(Hdf5Utils::StandardTypes &st)
Reads a data item.
void write(Hdf5Utils::StandardTypes &st, const DataType &t)
Writes a data item.
Definition of standard Arcane types for hdf5.
HType m_bfloat16_id
HDF identifier for BFloat16.
HType m_real2x2_id
HDF identifier for Real2x2.
StandardTypes()
Creates an instance by initializing the types.
Definition Hdf5Utils.cc:938
HType m_long_id
HDF identifier for signed longs.
HType m_int_id
HDF identifier for signed integers.
HType m_short_id
HDF identifier for signed shorts.
HType m_real3x3_id
HDF identifier for Real3x3.
HType m_real_id
HDF identifier for reals.
HType m_ushort_id
HDF identifier for unsigned shorts.
HType m_ulong_id
HDF identifier for unsigned longs.
HType m_schar_id
HDF identifier for signed characters.
HType m_uchar_id
HDF identifier for unsigned characters.
HType m_real2_id
HDF identifier for Real2.
HType m_float32_id
HDF identifier for Float32.
HType m_float16_id
HDF identifier for Float16.
HType m_char_id
HDF identifier for characters.
void initialize()
Initializes the types.
Definition Hdf5Utils.cc:957
HType m_uint_id
HDF identifier for unsigned integers.
HType m_real3_id
HDF identifier for Real3.
Exception when an input/output error is detected.
Definition IOException.h:34
Interface of the parallelism manager for a subdomain.
virtual bool isMasterIO() const =0
true if the instance is a master I/O manager.
virtual Integer masterIORank() const =0
Rank of the instance managing I/O (for which isMasterIO() is true).
virtual void * getMPICommunicator()=0
Address of the MPI communicator associated with this manager.
ByteConstArrayView utf8() const
Returns the conversion of the instance into UTF-8 encoding.
Definition String.cc:277
Integer len(const char *s)
Returns the length of the string s.
Utility functions for Hdf5.
Definition Hdf5Utils.cc:35
std::int8_t Int8
Signed integer type of 8 bits.
Array< Int64 > Int64Array
Dynamic one-dimensional array of 64-bit integers.
Definition UtilsTypes.h:119
ArrayView< Int64 > Int64ArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:445
UniqueArray< Int64 > Int64UniqueArray
Dynamic 1D array of 64-bit integers.
Definition UtilsTypes.h:333
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
ArrayView< Integer > IntegerArrayView
C equivalent of a 1D array of integers.
Definition UtilsTypes.h:451
ConstArrayView< Int64 > Int64ConstArrayView
C equivalent of a 1D array of 64-bit integers.
Definition UtilsTypes.h:474
UniqueArray< Byte > ByteUniqueArray
Dynamic 1D array of characters.
Definition UtilsTypes.h:329
std::int16_t Int16
Signed integer type of 16 bits.
double Real
Type representing a real number.
ConstArrayView< Byte > ByteConstArrayView
C equivalent of a 1D array of characters.
Definition UtilsTypes.h:470
unsigned char Byte
Type of a byte.
Definition BaseTypes.h:42
float Float32
IEEE-753 single-precision floating-point type.
eDataType
Data type.
Definition DataTypes.h:41
@ DT_Float32
'Float32' data type
Definition DataTypes.h:54
@ DT_Real2x2
2x2 tensor data type
Definition DataTypes.h:50
@ DT_Int16
16-bit integer data type
Definition DataTypes.h:44
@ DT_Int8
8-bit integer data type
Definition DataTypes.h:55
@ DT_Real3x3
3x3 tensor data type
Definition DataTypes.h:51
@ DT_Int32
32-bit integer data type
Definition DataTypes.h:45
@ DT_Real3
Vector 3 data type.
Definition DataTypes.h:49
@ DT_Float16
'Float16' data type
Definition DataTypes.h:53
@ DT_Int64
64-bit integer data type
Definition DataTypes.h:46
@ DT_BFloat16
'BFloat16' data type
Definition DataTypes.h:52
@ DT_Real2
Vector 2 data type.
Definition DataTypes.h:48
@ DT_Real
Real data type.
Definition DataTypes.h:43
@ DT_Byte
Byte data type.
Definition DataTypes.h:42
UniqueArray< Integer > IntegerUniqueArray
Dynamic 1D array of integers.
Definition UtilsTypes.h:341
std::int32_t Int32
Signed integer type of 32 bits.
Arcane::BFloat16 BFloat16
Type 'Brain Float16'.