From 356b5f331221d0bf051ae11e5fe0e11a5a9ef4a5 Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Fri, 7 Feb 2025 16:34:26 -0300 Subject: [PATCH 01/13] In the next release, fpm will support a hdf5 metapackage. --- fpm.toml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/fpm.toml b/fpm.toml index 4f680c3..fcad046 100644 --- a/fpm.toml +++ b/fpm.toml @@ -8,12 +8,6 @@ auto-tests = false auto-examples = false external-modules = ["hdf5", "h5lt"] -# HDF5 >= 1.10.6 -# link = ["hdf5_hl_fortran", "hdf5_fortran", "hdf5_hl", "hdf5"] - -# HDF5 < 1.10.6, and distros that rename the old way such as Ubuntu 22.04 -link = ["hdf5hl_fortran", "hdf5_fortran", "hdf5_hl", "hdf5"] - [install] library = true @@ -80,3 +74,6 @@ main = "test_string.f90" [[test]] name = "version" main = "test_version.f90" + +[dependencies] +hdf5 = '*' From 19c24ffa205f890091fc1bdbaafd402cb2977adf Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Fri, 7 Feb 2025 16:35:56 -0300 Subject: [PATCH 02/13] (bugfix) fix #50 --- src/utils.f90 | 5 +++-- src/write.f90 | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/utils.f90 b/src/utils.f90 index b113145..484f5f8 100644 --- a/src/utils.f90 +++ b/src/utils.f90 @@ -311,8 +311,9 @@ write(stderr,*) "ERROR:h5fortran:get_slice: memory size /= dataset size: check variable slice (index). " // & " Dset_dims:", ddims, "C Mem_dims:", c_mem_dims, "mem_dims:", mem_dims, "rank(mem_dims):", rank(mem_dims) error stop "ERROR:h5fortran:get_slice " // dset_name -elseif(any(iend-1 > ddims)) then - write(stderr,*) "ERROR:h5fortran:get_slice: iend: ", iend, ' > dset_dims: ', ddims +elseif(any(iend-istart > ddims)) then + write(stderr,*) "ERROR:h5fortran:get_slice: slice bigger than dataset: check variable slice (index). " // & + " Dset_dims:", ddims, "C Mem_dims:", c_mem_dims, "mem_dims:", mem_dims, "rank(mem_dims):", rank(mem_dims) error stop "ERROR:h5fortran:get_slice " // dset_name endif diff --git a/src/write.f90 b/src/write.f90 index ab5a469..c614283 100644 --- a/src/write.f90 +++ b/src/write.f90 @@ -82,7 +82,7 @@ if (present(istart)) then if(any(istart < 1)) error stop 'ERROR:h5fortran:create: istart must be >= 1' - if(any(iend <= istart)) error stop 'ERROR:h5fortran:create: iend must be > istart' + if(any(iend < istart)) error stop 'ERROR:h5fortran:create: iend must be >= istart' call H5Sget_simple_extent_ndims_f(filespace_id, drank, ier) call estop(ier, "create:H5Sget_simple_extent_ndims", self%filename, dname) @@ -92,7 +92,7 @@ call H5Sget_simple_extent_dims_f(filespace_id, ddims, maxdims, ier) if (ier /= drank) error stop 'ERROR:h5fortran:create: H5Sget_simple_extent_dims: ' // dname // ' in ' // self%filename - if(any(iend > ddims)) error stop 'ERROR:h5fortran:create: iend > dset_dims' // dname // ' in ' // self%filename + if(any(iend - istart > ddims)) error stop 'ERROR:h5fortran:create: iend - istart > dset_dims' // dname // ' in ' // self%filename else if (size(mem_dims) == 0) then !! scalar From 89209e31764785d21cc16fbbb9b9d6c339e4696f Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Sun, 9 Feb 2025 00:58:12 -0300 Subject: [PATCH 03/13] (feature) implemented visit and iterate methods. --- API.md | 26 ++++++++++ fpm.toml | 8 ++++ src/CMakeLists.txt | 4 +- src/interface.f90 | 56 ++++++++++++++++++++++ src/iterate.f90 | 112 ++++++++++++++++++++++++++++++++++++++++++++ src/visit.f90 | 112 ++++++++++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 2 +- 7 files changed, 318 insertions(+), 2 deletions(-) create mode 100644 src/iterate.f90 create mode 100644 src/visit.f90 diff --git a/API.md b/API.md index 1dab671..8f4216b 100644 --- a/API.md +++ b/API.md @@ -265,6 +265,32 @@ class(*), intent(out) :: attrval(:) !< character, real, integer call h%delete_attr(dname, attr) ``` +## Iterate over all datasets in a group + +```fortran +call h%iterate(group, callback) + +character(*), intent(in) :: group +subroutine callback(group_name, object_name, object_type) + character(len=*), intent(in) :: group_name + character(len=*), intent(in) :: object_name + character(len=*), intent(in) :: object_type +end subroutine +``` + +## Visit recursively all datasets starting from a group + +```fortran +call h%visit(group, callback) + +character(*), intent(in) :: group +subroutine callback(group_name, object_name, object_type) + character(len=*), intent(in) :: group_name + character(len=*), intent(in) :: object_name + character(len=*), intent(in) :: object_type +end subroutine +``` + ## high level operations These are single-call operations that are slower than the object-oriented methods above. diff --git a/fpm.toml b/fpm.toml index fcad046..9f66d30 100644 --- a/fpm.toml +++ b/fpm.toml @@ -71,6 +71,14 @@ main = "test_shape.f90" name = "string" main = "test_string.f90" +[[test]] +name = "visit" +main = "test_visit.f90" + +[[test]] +name = "iterate" +main = "test_iterate.f90" + [[test]] name = "version" main = "test_version.f90" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b3cb555..a962552 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,12 +1,14 @@ set(s ${CMAKE_CURRENT_SOURCE_DIR}) target_sources(h5fortran PRIVATE +${s}/interface.f90 ${s}/utils.f90 ${s}/read.f90 ${s}/read_scalar.f90 ${s}/read_ascii.f90 ${s}/reader.f90 ${s}/write.f90 ${s}/write_scalar.f90 ${s}/writer.f90 ${s}/reader_lt.f90 ${s}/writer_lt.f90 -${s}/interface.f90 ${s}/attr.f90 ${s}/attr_read.f90 ${s}/attr_write.f90 +${s}/iterate.f90 +${s}/visit.f90 ) diff --git a/src/interface.f90 b/src/interface.f90 index 56137d3..81c4172 100644 --- a/src/interface.f90 +++ b/src/interface.f90 @@ -56,6 +56,8 @@ module h5fortran procedure, public :: is_open procedure, public :: delete_attr => attr_delete procedure, public :: exist_attr => attr_exist +procedure, public :: iterate => hdf_iterate +procedure, public :: visit => hdf_visit !! procedures without mapping !> below are procedure that need generic mapping (type or rank agnostic) @@ -638,6 +640,60 @@ module logical function attr_exist(self, obj_name, attr_name) character(*), intent(in) :: obj_name, attr_name end function +module subroutine hdf_iterate(self, group_name, callback) + !! Opens the HDF5 file and the specified group, then iterates over + !! all members of the group. For each member the user‐provided + !! callback is invoked with: + !! + !! self - the HDF5 file object + !! group_name - name of the group + !! object_name - name of the member object + !! object_type - a short string indicating type ("group", "dataset", + !! "datatype", or "other") + class(hdf5_file), intent(in) :: self + character(len=*), intent(in) :: group_name + interface + subroutine user_callback_interface(group_name, object_name, object_type) + character(len=*), intent(in) :: group_name + !! The name of the group being traversed. + character(len=*), intent(in) :: object_name + !! The name of the object encountered. + character(len=*), intent(in) :: object_type + !!A short description such as "group", "dataset", + !! "datatype", or "other" + end subroutine + end interface + + procedure(user_callback_interface) :: callback +end subroutine + +module subroutine hdf_visit(self, group_name, callback) + !! Opens the HDF5 file and the specified group, then visits recursively + !! all members of the group. For each member the user‐provided + !! callback is invoked with: + !! + !! self - the HDF5 file object + !! group_name - name of the group + !! object_name - name of the member object + !! object_type - a short string indicating type ("group", "dataset", + !! "datatype", or "other") + class(hdf5_file), intent(in) :: self + character(len=*), intent(in) :: group_name + interface + subroutine user_callback_interface(group_name, object_name, object_type) + character(len=*), intent(in) :: group_name + !! The name of the group being traversed. + character(len=*), intent(in) :: object_name + !! The name of the object encountered. + character(len=*), intent(in) :: object_type + !!A short description such as "group", "dataset", + !! "datatype", or "other" + end subroutine + end interface + + procedure(user_callback_interface) :: callback +end subroutine + end interface diff --git a/src/iterate.f90 b/src/iterate.f90 new file mode 100644 index 0000000..06c9fe1 --- /dev/null +++ b/src/iterate.f90 @@ -0,0 +1,112 @@ +submodule (h5fortran) iterate_smod + use h5fortran + use hdf5 + implicit none + + interface + subroutine user_callback_interface(group_name, object_name, object_type) + character(len=*), intent(in) :: group_name + !! The name of the group being traversed. + character(len=*), intent(in) :: object_name + !! The name of the object encountered. + character(len=*), intent(in) :: object_type + !!A short description such as "group", "dataset", + !! "datatype", or "other" + end subroutine + end interface + + type :: iterate_data_t + procedure(user_callback_interface), nopass, pointer :: callback => null() + end type iterate_data_t + +contains + + module procedure hdf_iterate + use, intrinsic :: iso_c_binding, only: c_funptr, C_NULL_PTR, c_int + implicit none + integer(hid_t) :: group_id + integer(c_int) :: status + integer(hsize_t) :: idx + type(c_funptr) :: funptr + type(c_ptr) :: op_data_ptr + integer(c_int) :: return_value + + type(iterate_data_t) :: data + + ! Fill the iteration data with the user’s group name and callback. + data % callback => callback + + ! Open the group. + call H5Gopen_f(self%file_id, trim(group_name), group_id, status) + call estop(status, "hdf_iterate:H5Gopen_f", self%filename, "Error opening group: " // trim(group_name)) + + idx = 0 + op_data_ptr = C_NULL_PTR + ! Get the C function pointer for our internal callback. + funptr = c_funloc(internal_iterate_callback) + + ! Call H5Literate_f to iterate over the group. + call H5Literate_f(group_id, H5_INDEX_NAME_F, H5_ITER_NATIVE_F, idx, & + funptr, op_data_ptr, return_value, status) + call estop(status, "hdf_iterate:H5Literate_f", self%filename, "Error during iteration of group: " // trim(group_name)) + + ! Close the group and file. + call H5Gclose_f(group_id, status) + + contains + + integer(c_int) function internal_iterate_callback(grp_id, name, info, op_data) bind(C) + !! internal_iterate_callback: + !! + !! This is the callback procedure that will be passed to H5Literate_f. + !! It matches HDF5’s expected signature (using bind(C)) and is called + !! for each object in the group. + !! + !! It extracts the object name from the provided character array, + !! calls H5Oget_info_by_name_f to determine the object type, and then + !! calls the user's callback with the high-level parameters. + use ISO_C_BINDING, only: c_int, c_ptr, c_null_char + implicit none + integer(c_long), value :: grp_id + character(kind=c_char, len=1) :: name(0:255) + type(h5l_info_t) :: info + type(c_ptr) :: op_data + + integer :: status, i, len + type(H5O_info_t) :: infobuf + character(len=256) :: name_string + character(:), allocatable :: object_type + + ! Build a Fortran string from the character array. + do i = 0, 255 + len = i + if (name(i) == c_null_char) exit + name_string(i+1:i+1) = name(i)(1:1) + end do + + ! Retrieve object info using the object name. + call H5Oget_info_by_name_f(grp_id, name_string(1:len), infobuf, status) + if (status /= 0) then + internal_iterate_callback = status + return + end if + + if(infobuf % type == H5O_TYPE_GROUP_F)then + object_type = "group" + else if(infobuf % type == H5O_TYPE_DATASET_F)then + object_type = "dataset" + else if(infobuf % type == H5O_TYPE_NAMED_DATATYPE_F)then + object_type = "datatype" + else + object_type = "other" + endif + + ! Call the user’s callback procedure. + call data % callback(group_name, name_string(1:len), object_type) + + internal_iterate_callback = 0 ! Indicate success. + end function internal_iterate_callback + + end procedure hdf_iterate + +end submodule diff --git a/src/visit.f90 b/src/visit.f90 new file mode 100644 index 0000000..dfa5fb1 --- /dev/null +++ b/src/visit.f90 @@ -0,0 +1,112 @@ +submodule (h5fortran) visit_smod + use h5fortran + use hdf5 + implicit none + + interface + subroutine user_callback_interface(group_name, object_name, object_type) + character(len=*), intent(in) :: group_name + !! The name of the group being traversed. + character(len=*), intent(in) :: object_name + !! The name of the object encountered. + character(len=*), intent(in) :: object_type + !!A short description such as "group", "dataset", + !! "datatype", or "other" + end subroutine + end interface + + type :: visit_data_t + procedure(user_callback_interface), nopass, pointer :: callback => null() + end type visit_data_t + +contains + + module procedure hdf_visit + use, intrinsic :: iso_c_binding, only: c_funptr, C_NULL_PTR, c_int + implicit none + integer(hid_t) :: group_id + integer(c_int) :: status + integer(hsize_t) :: idx + type(c_funptr) :: funptr + type(c_ptr) :: op_data_ptr + integer(c_int) :: return_value + + type(visit_data_t) :: data + + ! Fill the iteration data with the user’s group name and callback. + data % callback => callback + + ! Open the group. + call H5Gopen_f(self%file_id, trim(group_name), group_id, status) + call estop(status, "hdf_visit:H5Gopen_f", self%filename, "Error opening group: " // trim(group_name)) + + idx = 0 + op_data_ptr = C_NULL_PTR + ! Get the C function pointer for our internal callback. + funptr = c_funloc(internal_visit_callback) + + ! Call H5Lvisit_f to visit over the group. + call H5Ovisit_f(group_id, H5_INDEX_NAME_F, H5_ITER_NATIVE_F, & + funptr, op_data_ptr, return_value, status) + call estop(status, "hdf_visit:H5Lvisit_f", self%filename, "Error during iteration of group: " // trim(group_name)) + + ! Close the group and file. + call H5Gclose_f(group_id, status) + + contains + + integer(c_int) function internal_visit_callback(grp_id, name, info, op_data) bind(C) + !! internal_visit_callback: + !! + !! This is the callback procedure that will be passed to H5Lvisit_f. + !! It matches HDF5’s expected signature (using bind(C)) and is called + !! for each object in the group. + !! + !! It extracts the object name from the provided character array, + !! calls H5Oget_info_by_name_f to determine the object type, and then + !! calls the user's callback with the high-level parameters. + use ISO_C_BINDING, only: c_int, c_ptr, c_null_char + implicit none + integer(c_long), value :: grp_id + character(kind=c_char, len=1) :: name(0:255) + type(h5l_info_t) :: info + type(c_ptr) :: op_data + + integer :: status, i, len + type(H5O_info_t) :: infobuf + character(len=256) :: name_string + character(:), allocatable :: object_type + + ! Build a Fortran string from the character array. + do i = 0, 255 + len = i + if (name(i) == c_null_char) exit + name_string(i+1:i+1) = name(i)(1:1) + end do + + ! Retrieve object info using the object name. + call H5Oget_info_by_name_f(grp_id, name_string(1:len), infobuf, status) + if (status /= 0) then + internal_visit_callback = status + return + end if + + if(infobuf % type == H5O_TYPE_GROUP_F)then + object_type = "group" + else if(infobuf % type == H5O_TYPE_DATASET_F)then + object_type = "dataset" + else if(infobuf % type == H5O_TYPE_NAMED_DATATYPE_F)then + object_type = "datatype" + else + object_type = "other" + endif + + ! Call the user’s callback procedure. + call data % callback(group_name, name_string(1:len), object_type) + + internal_visit_callback = 0 ! Indicate success. + end function internal_visit_callback + + end procedure hdf_visit + +end submodule diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 20edc47..bcaa207 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -60,7 +60,7 @@ endfunction(setup_test) set(test_names array attributes attributes_read cast deflate_write deflate_read deflate_props destructor exist groups layout lt scalar shape string string_read version write -fail_read_size_mismatch fail_read_rank_mismatch fail_nonexist_variable) +fail_read_size_mismatch fail_read_rank_mismatch fail_nonexist_variable iterate visit) if(HAVE_IEEE_ARITH) list(APPEND test_names fill) endif() From 1bc7b53a53ed78cf93b8b7f4fca3191b28ea9ea5 Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Sun, 9 Feb 2025 00:58:24 -0300 Subject: [PATCH 04/13] fixed small typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c8dd2d..e3f0545 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ On HPC, we suggest using the HDF5 library provided by the HPC system for best pe * variable length dataset writing We didn't use `type(c_ptr)` and `c_loc()` internally for datasets as we observed problems when the actual argument is sliced on read/write. -The current h5fortran impementation (Fortran `select type` for H5Dwrite/H5Dread) does work with sliced actual arguments. +The current h5fortran implementation (Fortran `select type` for H5Dwrite/H5Dread) does work with sliced actual arguments. HDF5 Fortran 2003 [features](https://docs.hdfgroup.org/archive/support/HDF5/doc/fortran/NewFeatures_F2003.pdf) From 7d05b39b1aa1b81100d7b830ec5fd5430eb8fe13 Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Sun, 9 Feb 2025 02:51:56 -0300 Subject: [PATCH 05/13] Solves the line truncation issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit build/dependencies/h5fortran/src/write.f90:95:132: 95 | if(any(iend - istart > ddims)) error stop 'ERROR:h5fortran:create: iend - istart > dset_dims' // dname // ' in ' // self%filename | 1 Error: Line truncated at (1) [-Werror=line-truncation] build/dependencies/h5fortran/src/write.f90:95:132: 95 | if(any(iend - istart > ddims)) error stop 'ERROR:h5fortran:create: iend - istart > dset_dims' // dname // ' in ' // self%filename | 1 Error: ‘filena’ at (1) is not a member of the ‘hdf5_file’ structure; did you mean ‘filename’? compilation terminated due to -fmax-errors=1. f951: some warnings being treated as errors Compilation failed for object " build_dependencies_h5fortran_src_write.f90.o " stopping due to failed compilation STOP 1 --- src/write.f90 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/write.f90 b/src/write.f90 index c614283..e5a29b8 100644 --- a/src/write.f90 +++ b/src/write.f90 @@ -90,9 +90,11 @@ allocate(ddims(drank), maxdims(drank)) call H5Sget_simple_extent_dims_f(filespace_id, ddims, maxdims, ier) - if (ier /= drank) error stop 'ERROR:h5fortran:create: H5Sget_simple_extent_dims: ' // dname // ' in ' // self%filename + if (ier /= drank) & + error stop 'ERROR:h5fortran:create: H5Sget_simple_extent_dims: ' // dname // ' in ' // self%filename - if(any(iend - istart > ddims)) error stop 'ERROR:h5fortran:create: iend - istart > dset_dims' // dname // ' in ' // self%filename + if(any(iend - istart > ddims)) & + error stop 'ERROR:h5fortran:create: iend - istart > dset_dims' // dname // ' in ' // self%filename else if (size(mem_dims) == 0) then !! scalar From b62db308a98815c2555359ee0fc35d2c80b04ea7 Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Mon, 10 Feb 2025 07:27:49 -0300 Subject: [PATCH 06/13] (tests) I forgot to add the tests files --- test/test_iterate.f90 | 46 +++++++++++++++++++++++++++++++++++++++++++ test/test_visit.f90 | 46 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 test/test_iterate.f90 create mode 100644 test/test_visit.f90 diff --git a/test/test_iterate.f90 b/test/test_iterate.f90 new file mode 100644 index 0000000..92812c5 --- /dev/null +++ b/test/test_iterate.f90 @@ -0,0 +1,46 @@ +program test_iterate + use, intrinsic :: iso_fortran_env, only: real64 + use h5fortran + use hdf5 + implicit none + + type(hdf5_file) :: h + character(*), parameter :: filename='test_iterate.h5' + integer :: i + + ! Create a sample HDF5 file + call h%open(filename, "w") + + call h%create_group("/group1") + call h%create_group("/group1/group2") + call h%write("/dataset1", 1.0_real64) + call h%write("/group1/dataset2", 2.0_real64) + + call h%close() + + ! Reopen the file for testing + call h%open(filename, "r") + + ! iterate the root group + print*, "test_iterate: iterating root group" + call h%iterate("/", my_callback) + + print*, "test_iterate: iterating /group1" + ! iterate a subgroup + call h%iterate("/group1", my_callback) + + call h%close() + + print*, "test_iterate: found ", i, " objects" + if (i /= 4) error stop "test_iterate: expected 4 objects" + +contains + + ! Define a callback subroutine + subroutine my_callback(group_name, object_name, object_type) + character(len=*), intent(in) :: group_name, object_name, object_type + print *, "test_iterate: at group ", trim(group_name), ' we found ', trim(object_name), ' which is a ', trim(object_type) + i = i + 1 + end subroutine my_callback + +end program test_iterate diff --git a/test/test_visit.f90 b/test/test_visit.f90 new file mode 100644 index 0000000..27a581a --- /dev/null +++ b/test/test_visit.f90 @@ -0,0 +1,46 @@ +program test_visit + use, intrinsic :: iso_fortran_env, only: real64 + use h5fortran + use hdf5 + implicit none + + type(hdf5_file) :: h + character(*), parameter :: filename='test_visit.h5' + integer :: i + + ! Create a sample HDF5 file + call h%open(filename, "w") + + call h%create_group("/group1") + call h%create_group("/group1/group2") + call h%write("/dataset1", 1.0_real64) + call h%write("/group1/dataset2", 2.0_real64) + + call h%close() + + ! Reopen the file for testing + call h%open(filename, "r") + + ! visit the root group + print*, "test_visit: visiting root group" + call h%visit("/", my_callback) + + print*, "test_visit: visiting /group1" + ! visit a subgroup + call h%visit("/group1", my_callback) + + call h%close() + + print*, "test_visit: found ", i, " objects" + if (i /= 8) error stop "test_visit: expected 8 objects" + +contains + + ! Define a callback subroutine + subroutine my_callback(group_name, object_name, object_type) + character(len=*), intent(in) :: group_name, object_name, object_type + print *, "test_visit: at group ", trim(group_name), ' we found ', trim(object_name), ' that is a ', trim(object_type) + i = i + 1 + end subroutine my_callback + +end program test_visit From ad73f3ae28ebb0e1be4befaf6672b82ae8554d65 Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Fri, 6 Jun 2025 16:34:34 -0300 Subject: [PATCH 07/13] (bugfix) variable was uninitialized --- test/test_iterate.f90 | 2 ++ test/test_visit.f90 | 2 ++ 2 files changed, 4 insertions(+) diff --git a/test/test_iterate.f90 b/test/test_iterate.f90 index 92812c5..4351c3a 100644 --- a/test/test_iterate.f90 +++ b/test/test_iterate.f90 @@ -8,6 +8,8 @@ program test_iterate character(*), parameter :: filename='test_iterate.h5' integer :: i + i = 0 + ! Create a sample HDF5 file call h%open(filename, "w") diff --git a/test/test_visit.f90 b/test/test_visit.f90 index 27a581a..172cfe4 100644 --- a/test/test_visit.f90 +++ b/test/test_visit.f90 @@ -8,6 +8,8 @@ program test_visit character(*), parameter :: filename='test_visit.h5' integer :: i + i = 0 + ! Create a sample HDF5 file call h%open(filename, "w") From 765d6fe9d9b7bef29783ff0fd61dc68cae1ee8c0 Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Fri, 6 Jun 2025 16:45:42 -0300 Subject: [PATCH 08/13] (bugfix) workaround to unnused variable --- src/iterate.f90 | 4 ++++ src/visit.f90 | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/iterate.f90 b/src/iterate.f90 index 06c9fe1..72e55fb 100644 --- a/src/iterate.f90 +++ b/src/iterate.f90 @@ -77,6 +77,10 @@ integer(c_int) function internal_iterate_callback(grp_id, name, info, op_data) b character(len=256) :: name_string character(:), allocatable :: object_type + ! FIXME - This is a workaround for the Fortran unused variable warning/error. + if (info % type == info % type) continue + if (c_associated(op_data)) continue + ! Build a Fortran string from the character array. do i = 0, 255 len = i diff --git a/src/visit.f90 b/src/visit.f90 index dfa5fb1..609c259 100644 --- a/src/visit.f90 +++ b/src/visit.f90 @@ -77,6 +77,10 @@ integer(c_int) function internal_visit_callback(grp_id, name, info, op_data) bin character(len=256) :: name_string character(:), allocatable :: object_type + ! FIXME - This is a workaround for the Fortran unused variable warning/error. + if (info % type == info % type) continue + if (c_associated(op_data)) continue + ! Build a Fortran string from the character array. do i = 0, 255 len = i From 136a902c6c68ecadb94a70b16cd754d2d596ead5 Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Fri, 6 Jun 2025 16:52:24 -0300 Subject: [PATCH 09/13] (bugfix) flang: Module 'h5fortran' cannot USE itself from its own submodule 'iterate_smod' --- src/iterate.f90 | 1 - src/visit.f90 | 1 - 2 files changed, 2 deletions(-) diff --git a/src/iterate.f90 b/src/iterate.f90 index 72e55fb..9e6f899 100644 --- a/src/iterate.f90 +++ b/src/iterate.f90 @@ -1,5 +1,4 @@ submodule (h5fortran) iterate_smod - use h5fortran use hdf5 implicit none diff --git a/src/visit.f90 b/src/visit.f90 index 609c259..277d13c 100644 --- a/src/visit.f90 +++ b/src/visit.f90 @@ -1,5 +1,4 @@ submodule (h5fortran) visit_smod - use h5fortran use hdf5 implicit none From 980f37a3f2cd5c03f8f495bbcf906eccb299c1d1 Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Fri, 6 Jun 2025 16:59:28 -0300 Subject: [PATCH 10/13] (docs) minor fix to the callback description --- src/interface.f90 | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/interface.f90 b/src/interface.f90 index 712c1b9..f75f655 100644 --- a/src/interface.f90 +++ b/src/interface.f90 @@ -653,7 +653,6 @@ module subroutine hdf_iterate(self, group_name, callback) !! all members of the group. For each member the user‐provided !! callback is invoked with: !! - !! self - the HDF5 file object !! group_name - name of the group !! object_name - name of the member object !! object_type - a short string indicating type ("group", "dataset", @@ -680,7 +679,6 @@ module subroutine hdf_visit(self, group_name, callback) !! all members of the group. For each member the user‐provided !! callback is invoked with: !! - !! self - the HDF5 file object !! group_name - name of the group !! object_name - name of the member object !! object_type - a short string indicating type ("group", "dataset", From 13cf0e2727809de02c39eef26831dd772df24a82 Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Fri, 6 Jun 2025 17:20:24 -0300 Subject: [PATCH 11/13] (bugfix) importing c_long to ensure the correct kind is being set --- src/iterate.f90 | 2 +- src/visit.f90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/iterate.f90 b/src/iterate.f90 index 9e6f899..c33fb00 100644 --- a/src/iterate.f90 +++ b/src/iterate.f90 @@ -64,7 +64,7 @@ integer(c_int) function internal_iterate_callback(grp_id, name, info, op_data) b !! It extracts the object name from the provided character array, !! calls H5Oget_info_by_name_f to determine the object type, and then !! calls the user's callback with the high-level parameters. - use ISO_C_BINDING, only: c_int, c_ptr, c_null_char + use ISO_C_BINDING, only: c_int, c_long, c_ptr, c_null_char implicit none integer(c_long), value :: grp_id character(kind=c_char, len=1) :: name(0:255) diff --git a/src/visit.f90 b/src/visit.f90 index 277d13c..2e6c8c8 100644 --- a/src/visit.f90 +++ b/src/visit.f90 @@ -64,7 +64,7 @@ integer(c_int) function internal_visit_callback(grp_id, name, info, op_data) bin !! It extracts the object name from the provided character array, !! calls H5Oget_info_by_name_f to determine the object type, and then !! calls the user's callback with the high-level parameters. - use ISO_C_BINDING, only: c_int, c_ptr, c_null_char + use ISO_C_BINDING, only: c_int, c_long, c_ptr, c_null_char implicit none integer(c_long), value :: grp_id character(kind=c_char, len=1) :: name(0:255) From 98c0ff6f21c3ff6cc69ba5e92ccc7acbf0dd4272 Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Tue, 10 Jun 2025 18:09:42 -0300 Subject: [PATCH 12/13] (enh) simplify the callback pointer storage --- src/iterate.f90 | 11 +++-------- src/visit.f90 | 11 +++-------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/iterate.f90 b/src/iterate.f90 index c33fb00..d8e4f47 100644 --- a/src/iterate.f90 +++ b/src/iterate.f90 @@ -14,10 +14,6 @@ subroutine user_callback_interface(group_name, object_name, object_type) end subroutine end interface - type :: iterate_data_t - procedure(user_callback_interface), nopass, pointer :: callback => null() - end type iterate_data_t - contains module procedure hdf_iterate @@ -29,11 +25,10 @@ subroutine user_callback_interface(group_name, object_name, object_type) type(c_funptr) :: funptr type(c_ptr) :: op_data_ptr integer(c_int) :: return_value - - type(iterate_data_t) :: data + procedure(user_callback_interface), pointer :: user_callback => null() ! Fill the iteration data with the user’s group name and callback. - data % callback => callback + user_callback => callback ! Open the group. call H5Gopen_f(self%file_id, trim(group_name), group_id, status) @@ -105,7 +100,7 @@ integer(c_int) function internal_iterate_callback(grp_id, name, info, op_data) b endif ! Call the user’s callback procedure. - call data % callback(group_name, name_string(1:len), object_type) + call user_callback(group_name, name_string(1:len), object_type) internal_iterate_callback = 0 ! Indicate success. end function internal_iterate_callback diff --git a/src/visit.f90 b/src/visit.f90 index 2e6c8c8..7877986 100644 --- a/src/visit.f90 +++ b/src/visit.f90 @@ -14,10 +14,6 @@ subroutine user_callback_interface(group_name, object_name, object_type) end subroutine end interface - type :: visit_data_t - procedure(user_callback_interface), nopass, pointer :: callback => null() - end type visit_data_t - contains module procedure hdf_visit @@ -29,11 +25,10 @@ subroutine user_callback_interface(group_name, object_name, object_type) type(c_funptr) :: funptr type(c_ptr) :: op_data_ptr integer(c_int) :: return_value - - type(visit_data_t) :: data + procedure(user_callback_interface), pointer :: user_callback => null() ! Fill the iteration data with the user’s group name and callback. - data % callback => callback + user_callback => callback ! Open the group. call H5Gopen_f(self%file_id, trim(group_name), group_id, status) @@ -105,7 +100,7 @@ integer(c_int) function internal_visit_callback(grp_id, name, info, op_data) bin endif ! Call the user’s callback procedure. - call data % callback(group_name, name_string(1:len), object_type) + call user_callback(group_name, name_string(1:len), object_type) internal_visit_callback = 0 ! Indicate success. end function internal_visit_callback From 04afdafb32785df04e3751ec600720a39d0f2bbf Mon Sep 17 00:00:00 2001 From: Ian Giestas Pauli Date: Wed, 11 Jun 2025 17:20:30 -0300 Subject: [PATCH 13/13] (bugfix) ci_windows: use the integer(hid_t) when calling from fortran --- src/iterate.f90 | 4 +++- src/visit.f90 | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/iterate.f90 b/src/iterate.f90 index d8e4f47..0bebf1c 100644 --- a/src/iterate.f90 +++ b/src/iterate.f90 @@ -67,6 +67,7 @@ integer(c_int) function internal_iterate_callback(grp_id, name, info, op_data) b type(c_ptr) :: op_data integer :: status, i, len + integer(hid_t) :: loc_id type(H5O_info_t) :: infobuf character(len=256) :: name_string character(:), allocatable :: object_type @@ -83,7 +84,8 @@ integer(c_int) function internal_iterate_callback(grp_id, name, info, op_data) b end do ! Retrieve object info using the object name. - call H5Oget_info_by_name_f(grp_id, name_string(1:len), infobuf, status) + loc_id = int(grp_id, kind=hid_t) + call H5Oget_info_by_name_f(loc_id, name_string(1:len), infobuf, status) if (status /= 0) then internal_iterate_callback = status return diff --git a/src/visit.f90 b/src/visit.f90 index 7877986..59abad3 100644 --- a/src/visit.f90 +++ b/src/visit.f90 @@ -67,6 +67,7 @@ integer(c_int) function internal_visit_callback(grp_id, name, info, op_data) bin type(c_ptr) :: op_data integer :: status, i, len + integer(hid_t) :: loc_id type(H5O_info_t) :: infobuf character(len=256) :: name_string character(:), allocatable :: object_type @@ -83,7 +84,8 @@ integer(c_int) function internal_visit_callback(grp_id, name, info, op_data) bin end do ! Retrieve object info using the object name. - call H5Oget_info_by_name_f(grp_id, name_string(1:len), infobuf, status) + loc_id = int(grp_id, kind=hid_t) + call H5Oget_info_by_name_f(loc_id, name_string(1:len), infobuf, status) if (status /= 0) then internal_visit_callback = status return