@@ -6,17 +6,21 @@ module h5mpi
6
6
use mpi, only : MPI_COMM_WORLD, MPI_INFO_NULL, mpi_comm_rank
7
7
use hdf5, only : &
8
8
HID_T, HSIZE_T, SIZE_T, &
9
+ H5I_FILE_F, &
9
10
H5T_INTEGER_F, H5T_FLOAT_F, H5T_STRING_F, &
10
11
H5T_NATIVE_CHARACTER, H5T_NATIVE_INTEGER, H5T_NATIVE_REAL, H5T_NATIVE_DOUBLE, H5T_STD_I64LE, &
11
12
H5F_ACC_RDONLY_F, H5F_ACC_TRUNC_F, H5F_ACC_RDWR_F, H5F_SCOPE_GLOBAL_F, &
13
+ H5F_OBJ_FILE_F, H5F_OBJ_GROUP_F, H5F_OBJ_DATASET_F, H5F_OBJ_DATATYPE_F, H5F_OBJ_ALL_F, &
12
14
H5FD_MPIO_COLLECTIVE_F, &
13
15
H5P_DEFAULT_F, H5P_FILE_ACCESS_F, H5P_DATASET_CREATE_F, H5P_DATASET_XFER_F, &
14
16
H5S_ALL_F, H5S_SELECT_SET_F, &
15
17
H5D_CHUNKED_F, H5D_CONTIGUOUS_F, H5D_COMPACT_F, &
16
18
h5dcreate_f, h5dopen_f, h5dclose_f, h5dget_space_f, h5dget_create_plist_f, &
17
19
h5fopen_f, h5fclose_f, h5fcreate_f, h5fget_filesize_f, h5fflush_f, h5fis_hdf5_f, &
20
+ h5fget_obj_count_f, h5fget_obj_ids_f, h5fget_name_f, &
21
+ h5iis_valid_f, h5iget_type_f, h5iget_name_f, &
18
22
h5pcreate_f, h5pclose_f, h5pset_chunk_f, h5pset_dxpl_mpio_f, h5pset_fapl_mpio_f, h5pall_filters_avail_f, &
19
- h5sselect_hyperslab_f, h5screate_simple_f, h5sclose_f, &
23
+ h5sselect_hyperslab_f, h5sselect_none_f, h5screate_simple_f, h5sclose_f, &
20
24
h5get_libversion_f, &
21
25
h5open_f, h5close_f
22
26
@@ -30,8 +34,10 @@ module h5mpi
30
34
31
35
character (:), allocatable :: filename
32
36
integer (HID_T) :: file_id
33
- logical :: is_open = .false.
37
+
34
38
logical :: use_mpi = .false.
39
+ integer :: mpi_id = - 1
40
+
35
41
logical :: debug = .false.
36
42
logical :: parallel_compression = .false.
37
43
logical :: fletcher32 = .false.
@@ -49,7 +55,8 @@ module h5mpi
49
55
class = > get_class, dtype = > get_native_dtype, &
50
56
deflate = > get_deflate, &
51
57
layout = > hdf_get_layout, chunks = > hdf_get_chunk, &
52
- is_contig = > hdf_is_contig, is_chunked = > hdf_is_chunked, is_compact = > hdf_is_compact
58
+ is_contig = > hdf_is_contig, is_chunked = > hdf_is_chunked, is_compact = > hdf_is_compact, &
59
+ is_open
53
60
! ! procedures without mapping
54
61
55
62
generic, public :: write = > h5write_scalar,ph5write_1d, ph5write_2d, ph5write_3d, ph5write_4d, ph5write_5d, ph5write_6d, ph5write_7d
@@ -62,6 +69,9 @@ module h5mpi
62
69
procedure , private :: h5read_scalar, ph5read_1d, ph5read_2d, ph5read_3d, ph5read_4d, ph5read_5d, ph5read_6d, ph5read_7d
63
70
! ! mapped procedures must be declared again like this
64
71
72
+ ! > flush file to disk and close file if user forgets to do so.
73
+ final :: destructor
74
+
65
75
end type hdf5_file
66
76
67
77
@@ -73,7 +83,7 @@ module h5mpi
73
83
74
84
private
75
85
public :: mpi_h5comm, hdf5_file, mpi_tags, has_parallel_compression, is_hdf5, &
76
- check, hdf_wrapup, hdf_rank_check, hdf_shape_check, mpi_collective, mpi_hyperslab, &
86
+ check, hdf_rank_check, hdf_shape_check, mpi_collective, mpi_hyperslab, &
77
87
hdf5version, HSIZE_T
78
88
79
89
interface ! < write.f90
@@ -84,7 +94,7 @@ module subroutine hdf_create(self, dname, dtype, mem_dims, dset_dims, filespace,
84
94
character (* ), intent (in ) :: dname
85
95
integer (HID_T), intent (in ) :: dtype
86
96
integer (HSIZE_T), dimension (:), intent (in ) :: mem_dims, dset_dims
87
- integer (HID_T), intent (out ), optional :: filespace, memspace, dset_id
97
+ integer (HID_T), intent (out ) :: filespace, memspace, dset_id
88
98
integer (HSIZE_T), dimension (:), intent (in ), optional :: istart, iend
89
99
integer , dimension (:), intent (in ), optional :: chunk_size
90
100
logical , intent (in ), optional :: compact
@@ -324,6 +334,11 @@ subroutine ph5open(self, filename, action, mpi, comp_lvl, shuffle, fletcher32, d
324
334
325
335
if (present (mpi)) self% use_mpi = mpi
326
336
337
+ if (self% use_mpi) then
338
+ call mpi_comm_rank(MPI_COMM_WORLD, self% mpi_id, ierr)
339
+ if (ierr /= 0 ) error stop " ERROR:h5fortran:open: could not get MPI ID"
340
+ endif
341
+
327
342
if (present (debug)) self% debug = debug
328
343
329
344
call get_hdf5_config(self% parallel_compression)
@@ -394,7 +409,6 @@ subroutine ph5open(self, filename, action, mpi, comp_lvl, shuffle, fletcher32, d
394
409
endif
395
410
396
411
self% filename = filename
397
- self% is_open = .true.
398
412
399
413
end subroutine ph5open
400
414
@@ -411,41 +425,106 @@ subroutine ph5close(self, close_hdf5_interface)
411
425
412
426
class(hdf5_file), intent (inout ) :: self
413
427
logical , intent (in ), optional :: close_hdf5_interface
414
- integer :: ier, ierr, mpi_id
415
428
416
- if (.not. self% is_open) then
429
+ integer :: ierr, i
430
+ integer (SIZE_T) :: Ngroup, Ndset, Ndtype, Nfile, Lf_name, Lds_name
431
+ integer (HID_T), allocatable :: obj_ids(:)
432
+ integer (SIZE_T), parameter :: L = 2048 ! < arbitrary length
433
+ character (L) :: file_name, dset_name
434
+
435
+ if (.not. self% is_open()) then
417
436
write (stderr,* ) ' WARNING:h5fortran:file_close: file handle is already closed: ' // self% filename
418
437
return
419
438
endif
420
439
440
+ ! > ref count for better error messages, as this is more of a problem with HDF5-MPI programs
441
+ call h5fget_obj_count_f(self% file_id, H5F_OBJ_GROUP_F, Ngroup, ierr)
442
+ if (ierr /= 0 ) error stop " ERROR:h5fortran:close:h5fget_obj_count: could not count open groups: " // self% filename
443
+ if (Ngroup > 0 ) write (stderr,' (a,i0,a)' ) " ERROR:h5fortran:close: there are " , Ngroup, " groups open: " // self% filename
444
+
445
+
446
+ call h5fget_obj_count_f(self% file_id, H5F_OBJ_DATASET_F, Ndset, ierr)
447
+ if (ierr /= 0 ) error stop " ERROR:h5fortran:close:h5fget_obj_count: could not count open datasets: " // self% filename
448
+ if (Ndset > 0 ) then
449
+ write (stderr,' (a,i0,a)' ) " ERROR:h5fortran:close: there are " , Ndset, " datasets open: " // self% filename
450
+
451
+ allocate (obj_ids(Ndset))
452
+ call h5fget_obj_ids_f(self% file_id, H5F_OBJ_DATASET_F, Ndset, obj_ids, ierr)
453
+ if (ierr /= 0 ) error stop " ERROR:h5fortran:close:h5fget_obj_ids: could not get open dataset ids: " // self% filename
454
+
455
+ do i = 1 , int (Ndset)
456
+ call h5fget_name_f(obj_ids(i), file_name, Lf_name, ierr)
457
+ if (ierr /= 0 ) error stop " ERROR:h5fortran:close:h5fget_name: could not get filename of open dataset: " // self% filename
458
+
459
+ call h5iget_name_f(obj_ids(i), dset_name, L, Lds_name, ierr)
460
+
461
+ write (stderr,* ) " h5fortran:close: open dataset: " // dset_name(:Lds_name) // " in file: " // file_name(:Lf_name)
462
+ end do
463
+ endif
464
+
465
+ call h5fget_obj_count_f(self% file_id, H5F_OBJ_DATATYPE_F, Ndtype, ierr)
466
+ if (ierr /= 0 ) error stop " ERROR:h5fortran:close:h5fget_obj_count: could not count open datatypes: " // self% filename
467
+ if (Ndtype > 0 ) write (stderr,' (a,i0,a)' ) " ERROR:h5fortran:close: there are " , Ndtype, " datatypes open: " // self% filename
468
+
469
+ call h5fget_obj_count_f(self% file_id, H5F_OBJ_FILE_F, Nfile, ierr)
470
+ if (ierr /= 0 ) error stop " ERROR:h5fortran:close:h5fget_obj_count: could not count open files: " // self% filename
471
+ if (Nfile < 1 ) write (stderr,' (a,i0,a)' ) " ERROR:h5fortran:close: there are " , Nfile, " files open: " // self% filename
472
+
473
+ if (Ngroup > 0 .or. Ndset > 0 .or. Ndtype > 0 ) error stop " ERROR:h5fortran:close: hanging HID handles open: " // self% filename
474
+
421
475
422
476
! > close hdf5 file
423
- call h5fclose_f(self% file_id, ier)
424
- if (ier/= 0 ) then
425
- call mpi_comm_rank(MPI_COMM_WORLD, mpi_id, ierr)
426
- write (stderr,' (a,i0)' ) ' ERROR:h5fortran:h5fclose: HDF5 file close: ' // self% filename // ' mpi_id: ' , mpi_id
477
+ call h5fclose_f(self% file_id, ierr)
478
+ if (ierr /= 0 ) then
479
+ write (stderr,' (a,i0)' ) ' ERROR:h5fortran:h5fclose: HDF5 file close: ' // self% filename // ' mpi_id: ' , self% mpi_id
427
480
error stop
428
481
endif
429
482
430
483
if (present (close_hdf5_interface)) then
431
484
if (close_hdf5_interface) then
432
- call h5close_f(ier )
433
- if (ier /= 0 ) error stop ' ERROR: HDF5 library close'
485
+ call h5close_f(ierr )
486
+ if (ierr /= 0 ) error stop ' ERROR:h5fortran:h5close : HDF5 library close'
434
487
endif
435
488
endif
436
489
437
- ! > sentinel file_id
438
- self% file_id = 0
490
+ end subroutine ph5close
439
491
440
- self% is_open = .false.
441
492
442
- end subroutine ph5close
493
+ logical function is_open (self )
494
+ ! ! check if file handle is open
495
+
496
+ class(hdf5_file), intent (in ) :: self
497
+
498
+ ! integer :: hid_type
499
+ integer :: ierr
500
+
501
+ call h5iis_valid_f(self% file_id, is_open, ierr)
502
+ if (ierr /= 0 ) error stop " h5fortran:is_open:h5iis_valid: " // self% filename
503
+
504
+ ! call h5iget_type_f(self%file_id, hid_type, ierr)
505
+ ! if(ierr /= 0 .or. hid_type /= H5I_FILE_F) is_open = .false.
506
+
507
+ end function is_open
508
+
443
509
444
510
logical function has_parallel_compression ()
445
511
call get_hdf5_config(has_parallel_compression)
446
512
end function has_parallel_compression
447
513
448
514
515
+ subroutine destructor (self )
516
+ ! ! Close file and handle if user forgets to do so
517
+
518
+ type (hdf5_file), intent (inout ) :: self
519
+
520
+ if (.not. self% is_open()) return
521
+
522
+ print ' (a)' , " auto-closing " // self% filename
523
+ call self% close ()
524
+
525
+ end subroutine destructor
526
+
527
+
449
528
logical function hdf_is_contig (self , dname )
450
529
class(hdf5_file), intent (in ) :: self
451
530
character (* ), intent (in ) :: dname
@@ -638,38 +717,15 @@ logical function hdf_exist(self, dname) result(exists)
638
717
639
718
integer :: ierr
640
719
641
- if (.not. self% is_open) error stop ' h5fortran:exist: file handle is not open'
720
+ if (.not. self% is_open()) error stop ' h5fortran:exist: file handle is not open: ' // self % filename
642
721
643
722
call h5ltpath_valid_f(self% file_id, dname, .true. , exists, ierr)
644
723
! ! h5lexists_f can false error with groups--just use h5ltpath_valid
645
-
646
724
if (ierr/= 0 ) error stop ' h5fortran:check_exist: could not determine status of ' // dname // ' in ' // self% filename
647
725
648
-
649
726
end function hdf_exist
650
727
651
728
652
- subroutine hdf_wrapup (filespace , memspace , dset_id , plist_id )
653
-
654
- integer (HID_T), intent (in ) :: filespace, memspace, dset_id, plist_id
655
-
656
- integer :: ierr
657
-
658
- call h5dclose_f(dset_id, ierr)
659
- if (ierr/= 0 ) error stop " ERROR: closing dataset"
660
-
661
- if (memspace /= H5S_ALL_F) call h5sclose_f(memspace, ierr)
662
- if (ierr/= 0 ) error stop " ERROR: closing memory dataspace"
663
-
664
- if (filespace /= H5S_ALL_F) call h5sclose_f(filespace, ierr)
665
- if (ierr/= 0 ) error stop " ERROR: closing file dataspace"
666
-
667
- call h5pclose_f(plist_id, ierr)
668
- if (ierr/= 0 ) error stop " ERROR: closing property"
669
-
670
- end subroutine hdf_wrapup
671
-
672
-
673
729
subroutine hdf_rank_check (self , dname , mrank , vector_scalar )
674
730
675
731
class(hdf5_file), intent (in ) :: self
@@ -683,9 +739,9 @@ subroutine hdf_rank_check(self, dname, mrank, vector_scalar)
683
739
684
740
if (present (vector_scalar)) vector_scalar = .false.
685
741
686
- if (.not. self% is_open) error stop ' h5fortran:rank_check: file handle is not open'
742
+ if (.not. self% is_open()) error stop ' ERROR: h5fortran:rank_check: file handle is not open: ' // self % filename
687
743
688
- if (.not. self% exist (dname)) error stop ' ERROR: ' // dname // ' does not exist in ' // self% filename
744
+ if (.not. self% exist (dname)) error stop ' ERROR::h5fortran:rank_check: ' // dname // ' does not exist in ' // self% filename
689
745
690
746
! > check for matching rank, else bad reads can occur--doesn't always crash without this check
691
747
call h5ltget_dataset_ndims_f(self% file_id, dname, drank, ierr)
@@ -726,14 +782,14 @@ subroutine hdf_shape_check(self, dname, dims, dset_dims)
726
782
727
783
call h5ltget_dataset_info_f(self% file_id, dname, dims= dsdims, &
728
784
type_class= type_class, type_size= type_size, errcode= ierr)
729
- if (ierr/= 0 ) error stop ' h5fortran:shape_check: get_dataset_info ' // dname // ' read ' // self% filename
785
+ if (ierr/= 0 ) error stop ' ERROR: h5fortran:shape_check: get_dataset_info ' // dname // ' read ' // self% filename
730
786
731
787
if (present (dset_dims)) dset_dims = dsdims
732
788
733
789
if (self% use_mpi) return
734
790
735
791
if (any (int (dims, int64) /= dsdims)) then
736
- write (stderr,* ) ' h5fortran:shape_check: shape mismatch ' // dname // ' = ' , dsdims, ' variable shape =' , dims
792
+ write (stderr,* ) ' ERROR: h5fortran:shape_check: shape mismatch ' // dname // ' = ' , dsdims, ' variable shape =' , dims
737
793
error stop
738
794
endif
739
795
@@ -748,14 +804,12 @@ integer(HSIZE_T) function hdf_filesize(self)
748
804
749
805
logical :: close_self
750
806
751
- close_self = .false.
807
+ close_self = .not. self% is_open()
808
+
809
+ if (close_self) call self% open (self% filename, action= " r" , mpi= .false. )
752
810
753
- if (.not. self% is_open) then
754
- close_self = .true.
755
- call self% open (self% filename, action= " r" , mpi= .false. )
756
- endif
757
811
call h5fget_filesize_f(self% file_id, hdf_filesize, ierr)
758
- if (ierr/= 0 ) error stop " could not get file size " // self% filename
812
+ if (ierr/= 0 ) error stop " ERROR:h5fortran: could not get file size " // self% filename
759
813
760
814
if (close_self) call self% close ()
761
815
0 commit comments