Skip to content

Commit ff0e81b

Browse files
committed
add %softlink create, h5exist() fcn and tests
1 parent 4f3e6d2 commit ff0e81b

File tree

5 files changed

+175
-2
lines changed

5 files changed

+175
-2
lines changed

src/interface.f90

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ module h5mpi
5454
create => hdf_create, filesize => hdf_filesize, &
5555
class => get_class, dtype => get_native_dtype, &
5656
deflate => get_deflate, &
57+
softlink => create_softlink, &
5758
layout => hdf_get_layout, chunks => hdf_get_chunk, &
5859
is_contig => hdf_is_contig, is_chunked => hdf_is_chunked, is_compact => hdf_is_compact, &
5960
is_open
@@ -84,7 +85,7 @@ module h5mpi
8485
private
8586
public :: mpi_h5comm, hdf5_file, mpi_tags, has_parallel_compression, is_hdf5, &
8687
check, hdf_rank_check, hdf_shape_check, mpi_collective, mpi_hyperslab, &
87-
hdf5version, &
88+
hdf5version, h5exist, &
8889
HSIZE_T, &
8990
H5T_INTEGER_F, H5T_FLOAT_F, H5T_STRING_F, &
9091
H5T_NATIVE_REAL, H5T_NATIVE_DOUBLE, H5T_NATIVE_INTEGER, H5T_NATIVE_CHARACTER, H5T_STD_I64LE
@@ -102,6 +103,13 @@ module subroutine hdf_create(self, dname, dtype, mem_dims, dset_dims, filespace,
102103
integer, dimension(:), intent(in), optional :: chunk_size
103104
logical, intent(in), optional :: compact
104105
end subroutine hdf_create
106+
107+
module subroutine create_softlink(self, tgt, link)
108+
class(hdf5_file), intent(inout) :: self
109+
character(*), intent(in) :: tgt, & !< target path to link
110+
link !< soft link path to create
111+
end subroutine create_softlink
112+
105113
end interface
106114

107115
interface !< hdf5_config.f90
@@ -249,6 +257,12 @@ end subroutine hdf_get_chunk
249257
!! the read "value" are intent(inout) because:
250258
!! * arrays: to work correctly when actual argument is allocatable
251259
!! * scalar: to work correctly with character type
260+
261+
module logical function h5exist(filename, dname, mpi)
262+
character(*), intent(in) :: filename, dname
263+
logical, intent(in) :: mpi
264+
end function h5exist
265+
252266
module subroutine h5read_scalar(self, dname, value)
253267
class(hdf5_file), intent(in) :: self
254268
character(*), intent(in) :: dname

src/read/reader.in.f90

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@
55
contains
66

77

8+
module procedure h5exist
9+
10+
type(hdf5_file) :: h
11+
12+
call h%open(filename, action='r', mpi=mpi)
13+
h5exist = h%exist(dname)
14+
call h%close()
15+
16+
end procedure h5exist
17+
18+
819
module procedure h5read_scalar
920

1021
integer(HSIZE_T) :: dims(0)

src/tests/unit/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ max_gcd(${MPI_MAX} ${MPIEXEC_MAX_NUMPROCS} Nmpi)
55

66
message(STATUS "Unit tests using ${Nmpi} processes")
77

8-
set(test_names cast deflate_write deflate_props deflate_read destructor layout shape string)
8+
set(test_names cast deflate_write deflate_props deflate_read destructor exist layout shape string)
99

1010
foreach(t IN LISTS test_names)
1111

src/tests/unit/test_exist.f90

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
program exist_tests
2+
!! test "exist" variable
3+
4+
use, intrinsic :: iso_fortran_env, only : stderr=>error_unit
5+
6+
use mpi, only : mpi_init, MPI_COMM_WORLD, mpi_comm_rank
7+
8+
use h5mpi, only: hdf5_file, h5exist, is_hdf5
9+
10+
11+
implicit none (type, external)
12+
13+
external :: mpi_finalize
14+
15+
integer :: ierr, mpi_id
16+
character(*), parameter :: fn = "test_destruct.h5"
17+
18+
19+
call mpi_init(ierr)
20+
if (ierr /= 0) error stop "mpi_init"
21+
22+
call mpi_comm_rank(MPI_COMM_WORLD, mpi_id, ierr)
23+
if(ierr /= 0) error stop "mpi_comm_rank"
24+
25+
call test_is_hdf5()
26+
if(mpi_id == 0) print *, 'OK: is_hdf5'
27+
28+
call test_exist('exist.h5')
29+
if(mpi_id == 0) print *, 'OK: exist'
30+
31+
call test_softlink('soft.h5')
32+
if(mpi_id == 0) print *, "OK: softlink"
33+
34+
call test_multifiles()
35+
if(mpi_id == 0) print *, 'OK: multiple files open at once'
36+
37+
call mpi_finalize(ierr)
38+
if (ierr /= 0) error stop "mpi_finalize"
39+
40+
41+
contains
42+
43+
44+
subroutine test_is_hdf5()
45+
integer :: i
46+
47+
if(is_hdf5('apidfjpj-8j9ejfpq984jfp89q39SHf.h5')) error stop 'test_exist: non-existent file declared hdf5'
48+
49+
open(newunit=i, file='not_hdf5.h5', action='write')
50+
write(i,*) 'I am not an HDF5 file.'
51+
close(i)
52+
53+
if(is_hdf5('not_hdf5.h5')) error stop 'text files are not hdf5'
54+
55+
end subroutine test_is_hdf5
56+
57+
58+
subroutine test_exist(fn)
59+
60+
type(hdf5_file) :: h
61+
62+
character(*), intent(in) :: fn
63+
64+
call h%open(fn, "w", mpi=.true.)
65+
call h%write('/x', 42)
66+
call h%close()
67+
68+
if(.not.is_hdf5(fn)) error stop fn // ' does not exist'
69+
70+
call h%open(fn, "r", mpi=.true.)
71+
if (.not. h%exist('/x')) error stop fn // ' /x exists'
72+
73+
if (h%exist('/A')) error stop 'variable /A should not exist in ' // fn
74+
75+
call h%close()
76+
77+
if(h%is_open()) error stop 'file is closed'
78+
79+
if (.not. h5exist(fn, '/x', mpi=.true.)) error stop 'x exists'
80+
if (h5exist(fn, '/A', mpi=.true.)) error stop 'A not exist'
81+
82+
end subroutine test_exist
83+
84+
85+
subroutine test_softlink(fn)
86+
87+
type(hdf5_file) :: h
88+
character(*), intent(in) :: fn
89+
90+
integer :: y
91+
92+
call h%open(fn, action='w', mpi=.true.)
93+
94+
call h%write("/actual", 142)
95+
call h%softlink("/actual", "/additional")
96+
call h%read("/additional", y)
97+
98+
if (.not.h%exist("/additional")) error stop "softlink not present"
99+
100+
if (y /= 142) error stop "did not read softlink correctly"
101+
102+
!> test dangling link
103+
104+
call h%softlink("/not_here", "/not_yet")
105+
if (h%exist("/not_yet")) error stop "dangling softlink"
106+
107+
call h%write("/not_here", 36)
108+
call h%read("/not_yet", y)
109+
if (y /= 36) error stop "finalizing dangling link failed"
110+
111+
call h%close()
112+
113+
end subroutine test_softlink
114+
115+
116+
subroutine test_multifiles()
117+
118+
type(hdf5_file) :: f,g,h
119+
120+
call f%open(filename='A.h5', action='w', mpi=.true.)
121+
call g%open(filename='B.h5', action='w', mpi=.true.)
122+
if (h%is_open()) error stop 'is_open not isolated at constructor'
123+
call h%open(filename='C.h5', action='w', mpi=.true.)
124+
125+
call f%flush()
126+
127+
call f%close()
128+
if (.not.g%is_open() .or. .not. h%is_open()) error stop 'is_open not isolated at destructor'
129+
call g%close()
130+
call h%close()
131+
132+
end subroutine test_multifiles
133+
134+
end program

src/write/write.f90

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use hdf5, only : h5pset_deflate_f, h5pset_fletcher32_f, h5pset_shuffle_f, h5pset_layout_f, &
44
h5dwrite_f, &
5+
h5lcreate_soft_f, &
56
h5screate_f, &
67
H5S_SCALAR_F
78

@@ -98,6 +99,19 @@
9899
end procedure hdf_create
99100

100101

102+
module procedure create_softlink
103+
!! HDF5 soft link -- to variables in same file
104+
!! target need not exist (dangling link)
105+
!! linking to external files requires an external link (different function required)
106+
107+
integer :: ierr
108+
109+
call H5Lcreate_soft_f(tgt, self%file_id, link, ierr)
110+
if (ierr /= 0) error stop 'ERROR:h5fortran:create_softlink: ' // link // ' in ' // self%filename
111+
112+
end procedure create_softlink
113+
114+
101115
subroutine set_deflate(self, dims, dcpl, chunk_size)
102116
class(hdf5_file), intent(in) :: self
103117
integer(HSIZE_T), intent(in) :: dims(:)

0 commit comments

Comments
 (0)