Arcane  4.2.3.0
User 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_LLONG);
992 H5Tset_precision(type_id, 8 * sizeof(long long));
993 H5Tset_order(type_id, H5T_ORDER_LE);
994 m_llong_id.setId(type_id);
995 }
996 {
997 hid_t type_id = H5Tcopy(H5T_NATIVE_USHORT);
998 H5Tset_precision(type_id, 8 * sizeof(unsigned short));
999 H5Tset_order(type_id, H5T_ORDER_LE);
1000 m_ushort_id.setId(type_id);
1001 }
1002 {
1003 hid_t type_id = H5Tcopy(H5T_NATIVE_UINT);
1004 H5Tset_precision(type_id, 8 * sizeof(unsigned int));
1005 H5Tset_order(type_id, H5T_ORDER_LE);
1006 m_uint_id.setId(type_id);
1007 }
1008 {
1009 hid_t type_id = H5Tcopy(H5T_NATIVE_ULONG);
1010 H5Tset_precision(type_id, 8 * sizeof(unsigned long));
1011 H5Tset_order(type_id, H5T_ORDER_LE);
1012 m_ulong_id.setId(type_id);
1013 }
1014 {
1015 hid_t type_id = H5Tcopy(H5T_NATIVE_ULLONG);
1016 H5Tset_precision(type_id, 8 * sizeof(unsigned long long));
1017 H5Tset_order(type_id, H5T_ORDER_LE);
1018 m_ullong_id.setId(type_id);
1019 }
1020 {
1021 hid_t type_id = H5Tcopy(H5T_NATIVE_FLOAT);
1022 H5Tset_precision(type_id, 8 * sizeof(float));
1023 H5Tset_order(type_id, H5T_ORDER_LE);
1024 m_float32_id.setId(type_id);
1025 }
1026 {
1027 hid_t type_id = H5Tcopy(H5T_NATIVE_DOUBLE);
1028 H5Tset_precision(type_id, 8 * sizeof(double));
1029 H5Tset_order(type_id, H5T_ORDER_LE);
1030 m_real_id.setId(type_id);
1031 }
1032 {
1033 hid_t type_id = H5Tcreate(H5T_COMPOUND, sizeof(Real2POD));
1034 _H5Tinsert(type_id, "X", HOFFSET(Real2POD, x), H5T_NATIVE_DOUBLE);
1035 _H5Tinsert(type_id, "Y", HOFFSET(Real2POD, y), H5T_NATIVE_DOUBLE);
1036 m_real2_id.setId(type_id);
1037 }
1038 {
1039 hid_t type_id = H5Tcreate(H5T_COMPOUND, sizeof(Real3POD));
1040 _H5Tinsert(type_id, "X", HOFFSET(Real3POD, x), H5T_NATIVE_DOUBLE);
1041 _H5Tinsert(type_id, "Y", HOFFSET(Real3POD, y), H5T_NATIVE_DOUBLE);
1042 _H5Tinsert(type_id, "Z", HOFFSET(Real3POD, z), H5T_NATIVE_DOUBLE);
1043 m_real3_id.setId(type_id);
1044 }
1045 {
1046 hid_t type_id = H5Tcreate(H5T_COMPOUND, sizeof(Real2x2POD));
1047 _H5Tinsert(type_id, "XX", HOFFSET(Real2x2POD, x.x), H5T_NATIVE_DOUBLE);
1048 _H5Tinsert(type_id, "XY", HOFFSET(Real2x2POD, x.y), H5T_NATIVE_DOUBLE);
1049 _H5Tinsert(type_id, "YX", HOFFSET(Real2x2POD, y.x), H5T_NATIVE_DOUBLE);
1050 _H5Tinsert(type_id, "YY", HOFFSET(Real2x2POD, y.y), H5T_NATIVE_DOUBLE);
1051 m_real2x2_id.setId(type_id);
1052 }
1053 {
1054 hid_t type_id = H5Tcreate(H5T_COMPOUND, sizeof(Real3x3POD));
1055 _H5Tinsert(type_id, "XX", HOFFSET(Real3x3POD, x.x), H5T_NATIVE_DOUBLE);
1056 _H5Tinsert(type_id, "XY", HOFFSET(Real3x3POD, x.y), H5T_NATIVE_DOUBLE);
1057 _H5Tinsert(type_id, "XZ", HOFFSET(Real3x3POD, x.z), H5T_NATIVE_DOUBLE);
1058 _H5Tinsert(type_id, "YX", HOFFSET(Real3x3POD, y.x), H5T_NATIVE_DOUBLE);
1059 _H5Tinsert(type_id, "YY", HOFFSET(Real3x3POD, y.y), H5T_NATIVE_DOUBLE);
1060 _H5Tinsert(type_id, "YZ", HOFFSET(Real3x3POD, y.z), H5T_NATIVE_DOUBLE);
1061 _H5Tinsert(type_id, "ZX", HOFFSET(Real3x3POD, z.x), H5T_NATIVE_DOUBLE);
1062 _H5Tinsert(type_id, "ZY", HOFFSET(Real3x3POD, z.y), H5T_NATIVE_DOUBLE);
1063 _H5Tinsert(type_id, "ZZ", HOFFSET(Real3x3POD, z.z), H5T_NATIVE_DOUBLE);
1064 m_real3x3_id.setId(type_id);
1065 }
1066
1067 // HDF5 1.10 and 1.12 do not yet support 'BFloat16' and 'Float16' types.
1068 // When that is the case, we will be able to use the type provided by HDF5.
1069 // (NOTE: HDF5 1.14.4 supports Float16)
1070
1071 // Add opaque type for BFloat16.
1072 {
1073 hid_t type_id = H5Tcopy(H5T_NATIVE_B16);
1074 m_bfloat16_id.setId(type_id);
1075 }
1076 // Add opaque type for Float16.
1077 {
1078 hid_t type_id = H5Tcopy(H5T_NATIVE_B16);
1079 m_float16_id.setId(type_id);
1080 }
1081}
1082
1083/*---------------------------------------------------------------------------*/
1084/*---------------------------------------------------------------------------*/
1085
1086StandardTypes::
1087~StandardTypes()
1088{
1089}
1090
1091/*---------------------------------------------------------------------------*/
1092/*---------------------------------------------------------------------------*/
1093
1094void StandardTypes::
1095_H5Tinsert(hid_t type, const char* name, Integer offset, hid_t field_id)
1096{
1097 // Mutex managed by initialize.
1098 herr_t herr = H5Tinsert(type, name, offset, field_id);
1099 if (herr < 0) {
1100 ARCANE_FATAL("Can not insert type");
1101 }
1102}
1103
1104/*---------------------------------------------------------------------------*/
1105/*---------------------------------------------------------------------------*/
1106
1107#ifdef ARCANE_REAL_NOT_BUILTIN
1108hid_t StandardTypes::
1109nativeType(Real) const
1110{
1111 ARCANE_FATAL("Real is a complex type");
1112}
1113#endif
1114
1115hid_t StandardTypes::
1116saveType(eDataType sd) const
1117{
1118 switch (sd) {
1119 case DT_Byte:
1120 return saveType(Byte());
1121 case DT_Real:
1122 return saveType(Real());
1123 case DT_Real2:
1124 return saveType(Real2());
1125 case DT_Real2x2:
1126 return saveType(Real2x2());
1127 case DT_Real3:
1128 return saveType(Real3());
1129 case DT_Real3x3:
1130 return saveType(Real3x3());
1131 case DT_Int8:
1132 return saveType(Int8());
1133 case DT_Int16:
1134 return saveType(Int16());
1135 case DT_Int32:
1136 return saveType(Int32());
1137 case DT_Int64:
1138 return saveType(Int64());
1139 case DT_Float32:
1140 return saveType(Float32());
1141 case DT_Float16:
1142 return saveType(Float16());
1143 case DT_BFloat16:
1144 return saveType(BFloat16());
1145 default:
1146 throw ArgumentException(String::format("Bad type '{0}'", sd));
1147 }
1148}
1149
1150/*---------------------------------------------------------------------------*/
1151/*---------------------------------------------------------------------------*/
1152
1153hid_t StandardTypes::
1154nativeType(eDataType sd) const
1155{
1156 switch (sd) {
1157 case DT_Byte:
1158 return nativeType(Byte());
1159 case DT_Real:
1160 return nativeType(Real());
1161 case DT_Real2:
1162 return nativeType(Real2());
1163 case DT_Real2x2:
1164 return nativeType(Real2x2());
1165 case DT_Real3:
1166 return nativeType(Real3());
1167 case DT_Real3x3:
1168 return nativeType(Real3x3());
1169 case DT_Int8:
1170 return nativeType(Int8());
1171 case DT_Int16:
1172 return nativeType(Int16());
1173 case DT_Int32:
1174 return nativeType(Int32());
1175 case DT_Int64:
1176 return nativeType(Int64());
1177 case DT_Float32:
1178 return nativeType(Float32());
1179 case DT_Float16:
1180 return nativeType(Float16());
1181 case DT_BFloat16:
1182 return nativeType(BFloat16());
1183 default:
1184 throw ArgumentException(String::format("Bad type '{0}'", sd));
1185 }
1186}
1187
1188/*---------------------------------------------------------------------------*/
1189/*---------------------------------------------------------------------------*/
1190
1191/*---------------------------------------------------------------------------*/
1192/*---------------------------------------------------------------------------*/
1193
1194StandardArray::
1195StandardArray(hid_t hfile, const String& hpath)
1196: m_hfile(hfile)
1197, m_hpath(hpath)
1198, m_ids_hpath(hpath + "_Ids")
1199, m_is_init(false)
1200{
1201}
1202
1203/*---------------------------------------------------------------------------*/
1204/*---------------------------------------------------------------------------*/
1205
1206void StandardArray::
1207readDim()
1208{
1209 if (m_is_init)
1210 return;
1211 m_is_init = true;
1212 m_hdataset.open(m_hfile, m_hpath);
1213 HSpace hspace(m_hdataset.getSpace());
1214 {
1215 const int max_dim = 256; // Maximum number of dimensions for HDF arrays
1216 hsize_t hdf_dims[max_dim];
1217 hsize_t max_dims[max_dim];
1218 int nb_dim = -1;
1219 {
1220 ARCANE_HDF5_MUTEX;
1221 nb_dim = H5Sget_simple_extent_ndims(hspace.id());
1222 H5Sget_simple_extent_dims(hspace.id(), hdf_dims, max_dims);
1223 }
1224 for (Integer i = 0; i < nb_dim; ++i) {
1225 //cerr << "** DIM i=" << i << " hdim=" << hdf_dims[i]
1226 // << " max=" << max_dims[i] << '\n';
1227 m_dimensions.add((Int64)hdf_dims[i]);
1228 }
1229 }
1230 // Checks if a variable suffixed '_Ids' exists containing the unique numbers
1231 // of the entities
1232 m_ids_dataset.openIfExists(m_hfile, m_ids_hpath);
1233 //cout << "TRY OPEN ID DATASET path=" << m_ids_hpath << " r=" << m_ids_dataset.id()>0 << '\n';
1234}
1235
1236/*---------------------------------------------------------------------------*/
1237/*---------------------------------------------------------------------------*/
1238
1240setIdsPath(const String& ids_path)
1241{
1242 m_ids_hpath = ids_path;
1243}
1244
1245/*---------------------------------------------------------------------------*/
1246/*---------------------------------------------------------------------------*/
1247
1248void StandardArray::
1249_write(const void* buffer, Integer nb_element, hid_t save_type, hid_t native_type)
1250{
1251 if (!m_is_init) {
1252 hsize_t dims[1];
1253 dims[0] = nb_element;
1254
1255 HSpace hspace;
1256 hspace.createSimple(1, dims);
1257 if (hspace.isBad())
1258 ARCANE_THROW(IOException, "Can not create space");
1259
1260 m_dimensions.clear();
1261 m_dimensions.add(nb_element);
1262
1263 m_hdataset.recursiveCreate(m_hfile, m_hpath, save_type, hspace, H5P_DEFAULT);
1264 if (m_hdataset.isBad())
1265 ARCANE_THROW(IOException, "Can not create dataset");
1266
1267 m_is_init = true;
1268 }
1269
1270 m_hdataset.write(native_type, buffer);
1271}
1272
1273/*---------------------------------------------------------------------------*/
1274/*---------------------------------------------------------------------------*/
1275
1276bool StandardArray::
1277exists() const
1278{
1279 HDataset dataset;
1280 dataset.openIfExists(m_hfile, m_hpath);
1281 return dataset.id() > 0;
1282}
1283
1284/*---------------------------------------------------------------------------*/
1285/*---------------------------------------------------------------------------*/
1286
1287template <typename DataType> StandardArrayT<DataType>::
1288StandardArrayT(hid_t hfile, const String& hpath)
1289: StandardArray(hfile, hpath)
1290{
1291}
1292
1293/*---------------------------------------------------------------------------*/
1294/*---------------------------------------------------------------------------*/
1295
1296template <typename DataType> void StandardArrayT<DataType>::
1298{
1299 m_hdataset.readWithException(st.nativeType(DataType()), buffer.data());
1300}
1301
1302/*---------------------------------------------------------------------------*/
1303/*---------------------------------------------------------------------------*/
1304
1305template <typename DataType> void StandardArrayT<DataType>::
1307{
1308 readDim();
1309 buffer.resize(m_dimensions[0]);
1310 read(st, buffer);
1311}
1312
1313/*---------------------------------------------------------------------------*/
1314/*---------------------------------------------------------------------------*/
1315
1316template <typename DataType> void StandardArrayT<DataType>::
1318{
1319 bool is_master = pm->isMasterIO();
1320 Integer master_rank = pm->masterIORank();
1321 bool has_ids = false;
1322 if (is_master) {
1323 read(st, buffer);
1324 Integer buf_size = buffer.size();
1325 if (m_ids_dataset.id() > 0) {
1326 has_ids = true;
1327 m_ids_dataset.read(st.nativeType(Int64()), unique_ids.data());
1328 }
1329 Integer infos[2];
1330 infos[0] = buf_size;
1331 infos[1] = has_ids ? 1 : 0;
1332 IntegerArrayView iav(2, infos);
1333 pm->broadcast(iav, master_rank);
1334 pm->broadcast(buffer, master_rank);
1335 pm->broadcast(unique_ids, master_rank);
1336 }
1337 else {
1338 Integer infos[2];
1339 IntegerArrayView iav(2, infos);
1340 pm->broadcast(iav, master_rank);
1341 Integer buf_size = infos[0];
1342 has_ids = infos[1] != 0;
1343 buffer.resize(buf_size);
1344 unique_ids.resize(buf_size);
1345 pm->broadcast(buffer, master_rank);
1346 pm->broadcast(unique_ids, master_rank);
1347 }
1348 if (!has_ids) {
1349 for (Integer i = 0, is = unique_ids.size(); i < is; ++i)
1350 unique_ids[i] = i;
1351 }
1352}
1353
1354/*---------------------------------------------------------------------------*/
1355/*---------------------------------------------------------------------------*/
1356
1357template <typename DataType> void StandardArrayT<DataType>::
1358write(StandardTypes& st, ConstArrayView<DataType> buffer)
1359{
1360 Integer nb_element = buffer.size();
1361 _write(buffer.data(), nb_element, st.saveType(DataType()), st.nativeType(DataType()));
1362}
1363
1364/*---------------------------------------------------------------------------*/
1365/*---------------------------------------------------------------------------*/
1366
1367template <typename DataType> void StandardArrayT<DataType>::
1368_writeSortedValues(ITraceMng* tm, StandardTypes& st,
1369 ConstArrayView<DataType> buffer,
1370 Int64ConstArrayView unique_ids)
1371{
1372 ARCANE_UNUSED(tm);
1373
1374 Integer total_size = buffer.size();
1375 Integer nb_element = unique_ids.size();
1376 Integer dim2_size = 1;
1377 if (nb_element != total_size) {
1378 if (nb_element == 0)
1379 ARCANE_THROW(ArgumentException, "unique_ids size is zero but not buffer size ({0})",
1380 total_size);
1381 dim2_size = total_size / nb_element;
1382 if (dim2_size * nb_element != total_size)
1383 ARCANE_THROW(ArgumentException, "buffer size ({0}) is not a multiple of unique_ids size ({1})",
1384 total_size, nb_element);
1385 }
1386
1387 UniqueArray<ValueWithUid> values_to_sort(nb_element);
1388 UniqueArray<DataType> out_buffer(total_size);
1389 //tm->info() << " WRITE total_size=" << total_size
1390 //<< " uid_size=" << unique_ids.size();
1391 for (Integer i = 0; i < nb_element; ++i) {
1392 values_to_sort[i].m_uid = unique_ids[i];
1393 values_to_sort[i].m_index = i;
1394 //values_to_sort[i].m_value = buffer[i];
1395 //tm->info() << "BEFORE SORT i=" << i << " uid=" << unique_ids[i];
1396 }
1397 std::sort(std::begin(values_to_sort), std::end(values_to_sort));
1398 for (Integer i = 0; i < nb_element; ++i) {
1399 Integer old_index = values_to_sort[i].m_index;
1400 for (Integer j = 0; j < dim2_size; ++j) {
1401 Integer pos = (i * dim2_size) + j;
1402 out_buffer[pos] = buffer[(old_index * dim2_size) + j];
1403 //tm->info() << "AFTER SORT i=" << i << " uid=" << values_to_sort[i].m_uid
1404 // << " j=" << j << " pos=" << pos
1405 // << " value=" << out_buffer[pos];
1406 }
1407 }
1408 write(st, out_buffer);
1409}
1410
1411/*---------------------------------------------------------------------------*/
1412/*---------------------------------------------------------------------------*/
1413
1414template <typename DataType> void StandardArrayT<DataType>::
1415parallelWrite(IParallelMng* pm, StandardTypes& st,
1416 ConstArrayView<DataType> buffer, Int64ConstArrayView unique_ids)
1417{
1418 //TODO:
1419 // For now, only the master process writes.
1420 // It retrieves all values, sorts them by increasing uniqueId
1421 // and writes them.
1422 // It is important that everything is sorted in ascending order because
1423 // this allows maintaining the same writing order even when mesh partitioning
1424 // occurs. The read operation assumes this constraint is met and only reads the
1425 // uniqueId information at the start of the case.
1426 bool is_parallel = pm->isParallel();
1427 ITraceMng* tm = pm->traceMng();
1428
1429 if (!is_parallel) {
1430 _writeSortedValues(tm, st, buffer, unique_ids);
1431 return;
1432 }
1433
1434 bool is_master = pm->isMasterIO();
1435 Integer master_rank = pm->masterIORank();
1436 Integer nb_rank = pm->commSize();
1437 Integer buf_size = buffer.size();
1438 Integer unique_id_size = unique_ids.size();
1439 IntegerUniqueArray rank_sizes(2 * nb_rank);
1440 // The master subdomain retrieves information from all others.
1441 // If a subdomain has no elements to send, it does nothing
1442 // (it does not send empty buffers)
1443 if (is_master) {
1444 Integer buf[2];
1445 buf[0] = buf_size;
1446 buf[1] = unique_id_size;
1447 IntegerArrayView iav(2, buf);
1448 pm->allGather(iav, rank_sizes);
1449
1450 Integer buffer_total_size = 0;
1451 Integer unique_id_total_size = 0;
1452 IntegerUniqueArray buffer_rank_index(nb_rank);
1453 IntegerUniqueArray unique_id_rank_index(nb_rank);
1454
1455 for (Integer i = 0; i < nb_rank; ++i) {
1456 buffer_rank_index[i] = buffer_total_size;
1457 buffer_total_size += rank_sizes[(i * 2)];
1458 unique_id_rank_index[i] = unique_id_total_size;
1459 unique_id_total_size += rank_sizes[(i * 2) + 1];
1460 }
1461
1462 UniqueArray<DataType> full_buffer(buffer_total_size);
1463 Int64UniqueArray full_unique_ids(unique_id_total_size);
1464
1465 for (Integer i = 0; i < nb_rank; ++i) {
1466 // Ne recoit pas de valeurs des processus n'ayant pas de valeurs
1467 if (rank_sizes[(i * 2)] == 0)
1468 continue;
1469 ArrayView<DataType> local_buf(rank_sizes[(i * 2)], &full_buffer[buffer_rank_index[i]]);
1470 Int64ArrayView local_unique_ids(rank_sizes[(i * 2) + 1], &full_unique_ids[unique_id_rank_index[i]]);
1471 if (i == master_rank) {
1472 local_buf.copy(buffer);
1473 local_unique_ids.copy(unique_ids);
1474 }
1475 else {
1476 pm->recv(local_buf, i);
1477 pm->recv(local_unique_ids, i);
1478 }
1479 }
1480 tm->info(5) << "PARALLEL WRITE path=" << m_hpath << " total_size=" << full_buffer.size();
1481 _writeSortedValues(tm, st, full_buffer, full_unique_ids);
1482 }
1483 else {
1484 Integer buf[2];
1485 buf[0] = buf_size;
1486 buf[1] = unique_id_size;
1487 IntegerArrayView iav(2, buf);
1488 pm->allGather(iav, rank_sizes);
1489 // No need to send empty buffers
1490 if (buffer.size() > 0) {
1491 pm->send(buffer, master_rank);
1492 pm->send(unique_ids, master_rank);
1493 }
1494 }
1495}
1496
1497/*---------------------------------------------------------------------------*/
1498/*---------------------------------------------------------------------------*/
1499
1500template class StandardArrayT<Real>;
1501template class StandardArrayT<Real3>;
1502template class StandardArrayT<Real3x3>;
1503template class StandardArrayT<Real2>;
1504template class StandardArrayT<Real2x2>;
1505template class StandardArrayT<Int16>;
1506template class StandardArrayT<Int32>;
1507template class StandardArrayT<Int64>;
1508template class StandardArrayT<Byte>;
1509template class StandardArrayT<Int8>;
1510template class StandardArrayT<Float32>;
1511// NOTE: these types cannot yet be instantiated because they require
1512// the ability to perform send/receive via IParallelMng, which is not
1513// yet implemented.
1514//template class StandardArrayT<Float16>;
1515//template class StandardArrayT<BFloat16>;
1516
1517/*---------------------------------------------------------------------------*/
1518/*---------------------------------------------------------------------------*/
1519
1520template <typename DataType> DataType
1523{
1524 Hdf5Utils::HDataset m_hdataset;
1525 m_hdataset.open(m_hfile, m_hpath);
1526 Hdf5Utils::HSpace hspace(m_hdataset.getSpace());
1527 {
1528 const int max_dim = 256; // Maximum number of HDF array dimensions
1529 hsize_t hdf_dims[max_dim];
1530 hsize_t max_dims[max_dim];
1531 int nb_dim = -1;
1532 {
1533 ARCANE_HDF5_MUTEX;
1534 nb_dim = H5Sget_simple_extent_ndims(hspace.id());
1535 H5Sget_simple_extent_dims(hspace.id(), hdf_dims, max_dims);
1536 }
1537 if (nb_dim != 1 || hdf_dims[0] != 1)
1538 ARCANE_THROW(IOException, "Cannot read non scalar");
1539 }
1540
1541 DataType dummy;
1542 m_hdataset.read(st.nativeType(DataType()), &dummy);
1543 return dummy;
1544}
1545
1546/*---------------------------------------------------------------------------*/
1547
1548template <> String
1551{
1552 ByteUniqueArray utf8_bytes;
1553
1554 Hdf5Utils::HDataset m_hdataset;
1555 m_hdataset.open(m_hfile, m_hpath);
1556 Hdf5Utils::HSpace hspace(m_hdataset.getSpace());
1557 {
1558 const int max_dim = 256; // Maximum number of HDF array dimensions
1559 hsize_t hdf_dims[max_dim];
1560 hsize_t max_dims[max_dim];
1561 int nb_dim = -1;
1562 {
1563 ARCANE_HDF5_MUTEX;
1564 nb_dim = H5Sget_simple_extent_ndims(hspace.id());
1565 H5Sget_simple_extent_dims(hspace.id(), hdf_dims, max_dims);
1566 }
1567
1568 if (nb_dim != 1)
1569 ARCANE_THROW(IOException, "Cannot read multidim string");
1570 utf8_bytes.resize(hdf_dims[0]);
1571 }
1572
1573 m_hdataset.read(st.nativeType(Byte()), utf8_bytes.data());
1574 return String(utf8_bytes);
1575}
1576
1577/*---------------------------------------------------------------------------*/
1578
1579template <typename DataType> void
1581write(Hdf5Utils::StandardTypes& st, const DataType& t)
1582{
1583 hsize_t dims[1] = { 1 };
1584 Hdf5Utils::HSpace hspace;
1585 hspace.createSimple(1, dims);
1586 if (hspace.isBad())
1587 ARCANE_THROW(IOException, "Can not create space");
1588
1589 Hdf5Utils::HDataset m_hdataset;
1590 m_hdataset.recursiveCreate(m_hfile, m_hpath, st.saveType(DataType()), hspace, H5P_DEFAULT);
1591 if (m_hdataset.isBad())
1592 ARCANE_THROW(IOException, "Can not create dataset");
1593
1594 herr_t herr = m_hdataset.write(st.nativeType(DataType()), &t);
1595 if (herr < 0)
1596 ARCANE_THROW(IOException, "Cannot write data");
1597}
1598
1599/*---------------------------------------------------------------------------*/
1600
1601template <> void
1604{
1605 ByteConstArrayView utf8_bytes = s.utf8();
1606
1607 hsize_t dims[1];
1608 dims[0] = utf8_bytes.size() + 1;
1609
1610 Hdf5Utils::HSpace hspace;
1611 hspace.createSimple(1, dims);
1612 if (hspace.isBad())
1613 ARCANE_THROW(IOException, "Can not create space");
1614
1615 Hdf5Utils::HDataset m_hdataset;
1616 m_hdataset.recursiveCreate(m_hfile, m_hpath, st.saveType(Byte()), hspace, H5P_DEFAULT);
1617 if (m_hdataset.isBad())
1618 ARCANE_THROW(IOException, "Can not create dataset");
1619
1620 herr_t herr = m_hdataset.write(st.nativeType(Byte()), utf8_bytes.data());
1621 if (herr < 0)
1622 ARCANE_THROW(IOException, "Cannot write data");
1623}
1624
1625/*---------------------------------------------------------------------------*/
1626
1627template class StandardScalarT<String>;
1628template class StandardScalarT<Real>;
1629template class StandardScalarT<Real3>;
1630template class StandardScalarT<Real3x3>;
1631template class StandardScalarT<Real2>;
1632template class StandardScalarT<Real2x2>;
1633template class StandardScalarT<Int16>;
1634template class StandardScalarT<Int32>;
1635template class StandardScalarT<Int64>;
1636template class StandardScalarT<Byte>;
1637template class StandardScalarT<Int8>;
1638template class StandardScalarT<Float16>;
1639template class StandardScalarT<BFloat16>;
1640template class StandardScalarT<Float32>;
1641
1642/*---------------------------------------------------------------------------*/
1643/*---------------------------------------------------------------------------*/
1644
1645} // namespace Arcane::Hdf5Utils
1646
1647/*---------------------------------------------------------------------------*/
1648/*---------------------------------------------------------------------------*/
#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.
Definition Hdf5Utils.h:448
Helper class for searching a group.
Definition Hdf5Utils.h:321
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*).
Definition Hdf5Utils.h:190
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.
Definition Hdf5Utils.h:405
Encapsulates a hid_t.
Definition Hdf5Utils.h:151
Encapsulates a simple dataset from an HDF5 file that represents an array.
Definition Hdf5Utils.h:823
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.
Definition Hdf5Utils.h:780
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).
Definition Hdf5Utils.h:879
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.
Definition Hdf5Utils.h:593
HType m_bfloat16_id
HDF identifier for BFloat16.
Definition Hdf5Utils.h:765
HType m_real2x2_id
HDF identifier for Real2x2.
Definition Hdf5Utils.h:762
HType m_llong_id
HDF identifier for signed long longs.
Definition Hdf5Utils.h:755
StandardTypes()
Creates an instance by initializing the types.
Definition Hdf5Utils.cc:938
HType m_long_id
HDF identifier for signed longs.
Definition Hdf5Utils.h:754
HType m_ullong_id
HDF identifier for unsigned long longs.
Definition Hdf5Utils.h:758
HType m_int_id
HDF identifier for signed integers.
Definition Hdf5Utils.h:753
HType m_short_id
HDF identifier for signed shorts.
Definition Hdf5Utils.h:751
HType m_real3x3_id
HDF identifier for Real3x3.
Definition Hdf5Utils.h:763
HType m_real_id
HDF identifier for reals.
Definition Hdf5Utils.h:759
HType m_ushort_id
HDF identifier for unsigned shorts.
Definition Hdf5Utils.h:752
HType m_ulong_id
HDF identifier for unsigned longs.
Definition Hdf5Utils.h:757
HType m_schar_id
HDF identifier for signed characters.
Definition Hdf5Utils.h:750
HType m_uchar_id
HDF identifier for unsigned characters.
Definition Hdf5Utils.h:749
HType m_real2_id
HDF identifier for Real2.
Definition Hdf5Utils.h:760
HType m_float32_id
HDF identifier for Float32.
Definition Hdf5Utils.h:766
HType m_float16_id
HDF identifier for Float16.
Definition Hdf5Utils.h:764
HType m_char_id
HDF identifier for characters.
Definition Hdf5Utils.h:748
void initialize()
Initializes the types.
Definition Hdf5Utils.cc:957
HType m_uint_id
HDF identifier for unsigned integers.
Definition Hdf5Utils.h:756
HType m_real3_id
HDF identifier for Real3.
Definition Hdf5Utils.h:761
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'.