diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a7979c..c8d81b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,3 +65,103 @@ jobs: ./build-tests/h5testrunner_mpi mpirun --allow-run-as-root --oversubscribe \ -np 2 ./build-tests/h5testrunner_mpi + + + build_serial_HDF5_with_ifx: + runs-on: ubuntu-latest + container: + image: intel/fortran-essentials:latest + + steps: + - uses: actions/checkout@v4 + + - name: Install system dependencies + run: | + apt-get update + apt-get install -y \ + cmake make gcc g++ \ + libhdf5-dev \ + wget \ + gpg + + - name: Install serial HDF5 1.14.6 with IFX + shell: bash + run: | + wget -O hdf5-1.14.6.tar.gz \ + https://sourceforge.net/projects/hdf5.mirror/files/hdf5_1.14.6/hdf5-1.14.6.tar.gz/download + tar -xzf hdf5-1.14.6.tar.gz + mkdir -p build-hdf5-ifx + + # configure with ifx + cmake -S ./hdf5-1.14.6 -B build-hdf5-ifx \ + -DCMAKE_Fortran_COMPILER=ifx \ + -DHDF5_BUILD_FORTRAN=ON \ + -DCMAKE_INSTALL_PREFIX=$HOME/hdf5-ifx \ + -DCMAKE_Fortran_FLAGS="-fPIE" \ + -DCMAKE_POSITION_INDEPENDENT_CODE=ON + + cmake --build build-hdf5-ifx -j + cmake --install build-hdf5-ifx + + - name: Build and run tests with ifx + shell: bash + run: | + ifx --version + + cmake -S ./test/. -B build-tests-ifx \ + -DCMAKE_PREFIX_PATH=$HOME/hdf5-ifx \ + -DCMAKE_Fortran_COMPILER=ifx + cmake --build build-tests-ifx + ./build-tests-ifx/h5testrunner + + # hpckit requires more disk space than available on GitHub runner + # build_parallel_HDF5_with_ifx: + # runs-on: ubuntu-latest + # container: + # image: intel/fortran-hpckit:latest + + # steps: + # - uses: actions/checkout@v4 + + # - name: Install system dependencies + # run: | + # sudo apt-get update + # sudo apt-get install -y wget cmake make gcc g++ gpg + + # - name: Install parallel HDF5 1.14.6 with IFX + # shell: bash + # run: | + # wget -O hdf5-1.14.6.tar.gz \ + # https://sourceforge.net/projects/hdf5.mirror/files/hdf5_1.14.6/hdf5-1.14.6.tar.gz/download + # tar -xzf hdf5-1.14.6.tar.gz + # mkdir -p build-hdf5-mpiifx + + # cmake -S hdf5-1.14.6 -B build-hdf5-mpiifx \ + # -DCMAKE_Fortran_COMPILER=mpiifx \ + # -DCMAKE_C_COMPILER=mpiicx \ + # -DBUILD_SHARED_LIBS=OFF \ + # -DHDF5_BUILD_FORTRAN=ON \ + # -DHDF5_ENABLE_PARALLEL=ON \ + # -DHDF5_ENABLE_Z_LIB_SUPPORT=OFF \ + # -DHDF5_ENABLE_SZIP_SUPPORT=OFF \ + # -DCMAKE_INSTALL_PREFIX=$HOME/hdf5-mpiifx \ + + # cmake --build build-hdf5-mpiifx -j + # cmake --install build-hdf5-mpiifx + + # - name: Build and run MPI tests with mpiifx + # shell: bash + # run: | + # mpiifx --version + + # cmake -S ./test/. -B build-tests-mpiifx \ + # -DCMAKE_Fortran_COMPILER=mpiifx \ + # -DCMAKE_PREFIX_PATH=$HOME/hdf5-mpiifx \ + # -DMPI_VERSION=ON + # cmake --build build-tests-mpiifx + + # ./build-tests-mpiifx/h5testrunner + # ./build-tests-mpiifx/h5testrunner_mpi + # mpirun --allow-run-as-root --oversubscribe \ + # -np 2 ./build-tests-mpiifx/h5testrunner_mpi + \ No newline at end of file diff --git a/README.md b/README.md index 7b71736..bf4a91f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,50 @@ # HDF5_Fortran_API -A Fortran library which handles the interface to HDF5 library to give simpler I/O proceedures usable within Fortran coding projects + +A Fortran library which handles the interface to HDF5 library to give simpler I/O proceedures usable within Fortran coding projects. + +The modhdf5.f90 module contains subroutines which interface with the HDF5 library so that you do not need to use it directly in your code. You only need to call upon this module to perform the I/O to the .h5 file. + +You can look at examples of how this module is used within the `./tests/testio.f90` code. + +__Author:__ Alyn D. N. James + +__Version:__ 0.1.0 + +## How to use + +To add this to your Fortran code, add this module .f90 file to the compilation (cmake, make and so on) and load the public subroutines module in your Fortran code via + +```Fortran +use modhdf5 +``` + +The .inc files will needed to be in the same directory as the .f90 file, but these will automatically be included during the compilation. (These .inc files are used to reduce the amount of repetative code.) + +This module uses macro preprocessors to be compatible with both the serial and parallel HDF5 library. However, to enable the (MPI) parallel HDF5 capabilities in modhdf5, you need to add the -DMPI_modhdf5 flag to the `make` compilation step. This is done within cmake as seen in the `Tests` section below. + +## Dependencies + +Here is the list of libraries required for the modhdf5 module (with the version it was tested with): +- HDF5 library (1.14.6) +- Fortran 2018+ (gcc 15.1.0 and ifx 2025.3.0) +- MPI (for parallel enabled version) (Openmpi 5.0.8) + +For the repository, the following additional packages (with the version it was tested with) are needed: +- cmake (3.22.1) + +## Documentation + +Within modhdf5, the public subroutines to be used in your code are given at the top of the file. All the global variables are commented, and the inputs and outputs of all of the subroutines are labelled. The subroutines are named to be self-explanatory (some have short doc-strings for clarity). ## Tests -Compile the test runner (within gnu) with +This repository uses the [naturalFRUIT v0.7.4](https://cibinjoseph.github.io/naturalFRUIT/index.html) .f90 code for constructing the test runner for testing the functionality of the code base. Credit goes to the developers for `naturalfruit.f90`. + +Please look at the `.github/workflows/ci.yml` to see how modhdf5 has been compiled in different setups. + +### Serial Tests + +Compile the test runner (within GCC+Openmpi) with ``` cmake ../ -DCMAKE_Fortran_COMPILER=mpif90 @@ -20,3 +61,36 @@ run the test suite via ``` ./h5testrunner ``` + + +### (MPI) Parallel Tests + +Compile the test runner (within GCC+Openmpi) with + +``` +cmake ../ -DCMAKE_Fortran_COMPILER=mpif90 -DMPI_VERSION=ON +``` + +For conda environment, use + +``` +cmake ../ -DCMAKE_Fortran_COMPILER=mpif90 -DMPI_VERSION=ON -DCMAKE_PREFIX_PATH=$CONDA_PREFIX +``` + +run the test suite via + +``` +mpirun -np 2 ./h5testrunner_mpi +``` + +## Developer notes + +This modhdf5 has been written for HDF5 version 1.x.y. The additional functionality of HDF5 2.x.y has not been included. + +modhdf5 uses polymorphic, assumed-rank variable inputs to keep the interface generic. The variable rank and type are resolved within the read/write subroutines to interface with the HDF5 library Fortran APIs. modhdf5 currently sticks to the standard H5 native types available within the HDF5 library. These are: +- H5T_NATIVE_INTEGER +- H5T_NATIVE_REAL +- H5T_NATIVE_DOUBLE +- H5T_FORTRAN_S1 (modhdf5 extends this to a custom n-sized character type to handle aribitary sized character variable.) + +It is suggested for users to resolve their data types to conform with these native types and add the Fortran data type it was originally to the `fortran_type` attribute (via `fdtype_name` subroutine input/output) so that other users know its origin. \ No newline at end of file diff --git a/src/modhdf5.f90 b/src/modhdf5.f90 index 61ea857..dadd037 100644 --- a/src/modhdf5.f90 +++ b/src/modhdf5.f90 @@ -14,53 +14,54 @@ module modhdf5 write_attributeHDF5, read_attributeHDF5, writeHDF5, readHDF5, writeHDF5_hypersplice, & readHDF5_hypersplice private :: mpi_open_hdf5_file, set_dxpl_id, get_var_dims, get_file_or_group_id, get_file_or_group_hyp, & - get_array_dset_type, get_dset_type, create_char_dset_type, config_hyper_dims, h5dataset_write, & - h5dataset_read + get_array_dset_type, get_dset_type, create_char_dset_type, config_hyper_dims ! modHDF5 variables ! !HDF5 extension character(256), public :: h5filext='.h5' +!HDF5 extension +character(256), public :: modhdf5_version='0.1.0' !user input to use the hdf5 files logical, public :: use_hdf5=.false. !h5 compression level integer, private :: compression_level = 4 type h5_ids_t -!hyperslab/hypersplice property list ids -integer(HID_T) :: plist = -1 -!hyperslab/hypersplice dataset ids -integer(HID_T) :: dset = -1 -!hyperslab/hypersplice dataspace ids -integer(HID_T) :: dspace = -1 -!dimensions of the hyperspliced array -integer(HSIZE_T) :: dims(7) -!used for h5 collective mpi read/write (when mpi_h5=.true.) -integer(HID_T) :: dxpl = -1 -!h5 compatible data type for variable to/from h5 file -integer(HID_T) :: dset_type = -1 + !hyperslab/hypersplice property list ids + integer(HID_T) :: plist = -1 + !hyperslab/hypersplice dataset ids + integer(HID_T) :: dset = -1 + !hyperslab/hypersplice dataspace ids + integer(HID_T) :: dspace = -1 + !dimensions of the hyperspliced array + integer(HSIZE_T) :: dims(7) + !used for h5 collective mpi read/write (when mpi_h5=.true.) + integer(HID_T) :: dxpl = -1 + !h5 compatible data type for variable to/from h5 file + integer(HID_T) :: dset_type = -1 end type h5_ids_t ! derived type containing the h5 file ids for each file in use type h5_file_ids_t -!HDF5 file handle -integer(HID_T) :: fid -!h5 mpicheck - set to false by default -logical :: mpi_h5 = .false. -!h5 mpicomm copy -integer :: mpicomm_h5 = -1 -!hyperslab/hypersplice ids -type(h5_ids_t) :: hyp(10) + !HDF5 file handle + integer(HID_T) :: fid + !h5 mpicheck - set to false by default + logical :: mpi_h5 = .false. + !h5 mpicomm copy + integer :: mpicomm_h5 = -1 + !hyperslab/hypersplice ids + type(h5_ids_t) :: hyp(10) end type h5_file_ids_t type(h5_file_ids_t), private, target :: h5_fids(10) ! derived type containing the h5 file ids for each file in use type h5_group_ids_t -!HDF5 file index for h5_file_ids_t -integer :: file_idx -!h5 group id -integer(HID_T) :: gid -!hyperslab/hypersplice ids -type(h5_ids_t) :: hyp(10) + !HDF5 file index for h5_file_ids_t + integer :: file_idx + !h5 group id + integer(HID_T) :: gid + !hyperslab/hypersplice ids + type(h5_ids_t) :: hyp(10) end type h5_group_ids_t type(h5_group_ids_t), private, target :: h5_gids(10) @@ -68,11 +69,11 @@ module modhdf5 subroutine open_hdf5_file(fid_idx,filename,writing,mpi_file,mpicom) -character(len=*), intent(in) :: filename -integer, intent(in) :: fid_idx -logical, intent(in) :: writing -logical, optional, intent(in) :: mpi_file -integer, optional, intent(in) :: mpicom +character(len=*), intent(in) :: filename !prefix of .h5 file +integer, intent(in) :: fid_idx !file index to use this file +logical, intent(in) :: writing !writing (.true.) or reading (.false.) file +logical, optional, intent(in) :: mpi_file !.true. if open file in mpi mode +integer, optional, intent(in) :: mpicom !mpi communicator integer hdferr @@ -95,15 +96,16 @@ end subroutine open_hdf5_file subroutine mpi_open_hdf5_file(fid_idx,filename,writing,mpicom) + ! use the mpi library within mpi HDF5 enabled #ifdef MPI_modhdf5 use mpi, only: MPI_COMM_NULL, MPI_INFO_NULL #endif -character(len=*), intent(in) :: filename -integer, intent(in) :: fid_idx -logical, intent(in) :: writing -integer, intent(in) :: mpicom +character(len=*), intent(in) :: filename !prefix of .h5 file +integer, intent(in) :: fid_idx !file index to use this file +logical, intent(in) :: writing !writing (.true.) or reading (.false.) file +integer, intent(in) :: mpicom !mpi communicator integer hdferr type(h5_ids_t) :: h5_id @@ -140,8 +142,8 @@ end subroutine mpi_open_hdf5_file subroutine create_hdf5_group(fid_idx,gid_idx,groupname) -character(len=*), intent(in) :: groupname -integer, intent(in) :: fid_idx, gid_idx +character(len=*), intent(in) :: groupname !h5 group name +integer, intent(in) :: fid_idx, gid_idx !file and group indices (used to associate group to file) integer hdferr @@ -153,8 +155,8 @@ end subroutine create_hdf5_group subroutine open_hdf5_group(fid_idx,gid_idx,groupname) -character(len=*), intent(in) :: groupname -integer, intent(in) :: fid_idx, gid_idx +character(len=*), intent(in) :: groupname !h5 group name +integer, intent(in) :: fid_idx, gid_idx !file and group indices (used to associate group to file) integer hdferr @@ -166,7 +168,7 @@ end subroutine open_hdf5_group subroutine close_hdf5_group(gid_idx) -integer, intent(in) :: gid_idx +integer, intent(in) :: gid_idx !group index integer hdferr @@ -177,7 +179,7 @@ end subroutine close_hdf5_group subroutine close_hdf5_file(fid_idx) -integer, intent(in) :: fid_idx +integer, intent(in) :: fid_idx !file index integer hdferr @@ -192,6 +194,7 @@ end subroutine close_hdf5_file subroutine set_dxpl_id(dxpl_id,using_mpi,mpi_independent) +! Set dxpl id for mpi handling (independent or collective modes) within the .h5 file integer(HID_T), intent(inout) :: dxpl_id logical, intent(in) :: using_mpi, mpi_independent @@ -216,9 +219,9 @@ end subroutine set_dxpl_id subroutine get_var_dims(variable,rnk,dims) -class(*), intent(in), dimension(..) :: variable -integer, intent(inout) :: rnk -integer(HSIZE_T), intent(inout) :: dims(7) +class(*), intent(in), dimension(..) :: variable !variable of interest +integer, intent(inout) :: rnk !rank of variable +integer(HSIZE_T), intent(inout) :: dims(7) !dimension of each rank integer i @@ -236,10 +239,10 @@ end subroutine get_var_dims subroutine get_file_or_group_id(to_group,id_idx,file_or_group_id,using_mpi) -logical, intent(in) :: to_group !logical for distinguishing whether to write to group or not -integer, intent(in) :: id_idx !index for file_id/group_id -integer(HID_T), intent(out) :: file_or_group_id -logical, intent(out) :: using_mpi +logical, intent(in) :: to_group !logical for distinguishing whether to write to group or file +integer, intent(in) :: id_idx !index for file/group +integer(HID_T), intent(out) :: file_or_group_id !h5 file/group id +logical, intent(out) :: using_mpi !.true. if file is using mpi mode if (to_group) then file_or_group_id = h5_gids(id_idx)%gid @@ -254,8 +257,8 @@ end subroutine get_file_or_group_id subroutine get_file_or_group_hyp(to_group,id_idx,hyp_id_idx,hyp) -logical, intent(in) :: to_group !logical for distinguishing whether to write to group or not -integer, intent(in) :: id_idx, hyp_id_idx +logical, intent(in) :: to_group !logical for whether to read/write to group or not +integer, intent(in) :: id_idx, hyp_id_idx !group/file index and hypersplice/hyperslab index type(h5_ids_t), intent(inout), pointer :: hyp !hypersplice/hyperslab datatype if (to_group) then @@ -268,9 +271,9 @@ end subroutine get_file_or_group_hyp subroutine get_array_dset_type(variable,dset_type,custom_type) -class(*), intent(in), dimension(..) :: variable -integer(HID_T), intent(out) :: dset_type -logical, intent(out) :: custom_type +class(*), intent(in), dimension(..) :: variable !variable of interest +integer(HID_T), intent(out) :: dset_type !corresponding h5 dataset type for I/O +logical, intent(out) :: custom_type !.true. if dset_type is a custom type select rank(variable) rank(0); call get_dset_type(variable,dset_type,custom_type) @@ -287,9 +290,10 @@ end subroutine get_array_dset_type subroutine get_dset_type(variable,dset_type,custom_type) -class(*), intent(in) :: variable -integer(HID_T), intent(out) :: dset_type -logical, intent(out) :: custom_type + +class(*), intent(in) :: variable !variable of interest +integer(HID_T), intent(out) :: dset_type !corresponding h5 dataset type for I/O +logical, intent(out) :: custom_type !.true. if dset_type is a custom type custom_type=.false. @@ -304,9 +308,10 @@ end subroutine get_dset_type subroutine create_char_dset_type(variable,char_type,custom_type) -character(*), intent(in) :: variable -integer(HID_T), intent(out) :: char_type -logical, intent(out) :: custom_type + +character(*), intent(in) :: variable !variable of interest +integer(HID_T), intent(out) :: char_type !corresponding custom h5 character type for I/O +logical, intent(out) :: custom_type !.true. if dset_type is a custom type integer :: hdferr @@ -318,51 +323,51 @@ subroutine create_char_dset_type(variable,char_type,custom_type) subroutine init_hyperspliced_array(id_idx,dataset_name,variable,write_to_group,hyp_id_idx,n_hyp_dim,fdtype_name) +! Initiate the hypersplice/hyperslab array for writing -integer, intent(in) :: id_idx -character(len=*), intent(in) :: dataset_name -class(*), intent(in), dimension(..) :: variable -logical, intent(in) :: write_to_group -integer, intent(in) :: hyp_id_idx,n_hyp_dim -character(len=*), optional, intent(in) :: fdtype_name +integer, intent(in) :: id_idx !index for file/group +character(len=*), intent(in) :: dataset_name !name of h5 dataset +class(*), intent(in), dimension(..) :: variable !variable slice to write +logical, intent(in) :: write_to_group !.true. to write to group, otherwise to file +integer, intent(in) :: hyp_id_idx,n_hyp_dim !hypersplice/slab index and hyper dimension size (for last rank not in slice) +character(len=*), optional, intent(in) :: fdtype_name !variable datatype name within dataset attribute integer(HID_T) :: dspace_id, dset_id, file_or_group_id, dset_type -integer :: hdferr, i, r +integer :: hdferr, i, rnk integer(HSIZE_T) :: dims(7), chunk_dims(7) logical custom_type, using_mpi type(h5_ids_t), pointer :: hyp -r = rank(variable) +rnk = rank(variable) -if ((r < 0) .or. (r > 6)) then +if ((rnk < 0) .or. (rnk > 6)) then write(*,*) "(init_hyperspliced_array): input variable has invalid rank. Only a rank between 0 and 6 can be used." stop "Stopping." end if call get_file_or_group_id(write_to_group,id_idx,file_or_group_id,using_mpi) call get_file_or_group_hyp(write_to_group,id_idx,hyp_id_idx,hyp) -call get_var_dims(variable,r,hyp%dims) +call get_var_dims(variable,rnk,hyp%dims) call get_array_dset_type(variable,hyp%dset_type,custom_type) call set_dxpl_id(hyp%dxpl,using_mpi,mpi_independent=.false.) chunk_dims = hyp%dims -r = r + 1 -hyp%dims(r) = n_hyp_dim -chunk_dims(r) = 1 +rnk = rnk + 1 +hyp%dims(rnk) = n_hyp_dim +chunk_dims(rnk) = 1 ! Create dataspace for whole dataset -call h5screate_simple_f(r, hyp%dims(1:r), hyp%dspace, hdferr) +call h5screate_simple_f(rnk, hyp%dims(1:rnk), hyp%dspace, hdferr) ! Create property list for chunking, and then compression call h5pcreate_f(H5P_DATASET_CREATE_F, hyp%plist, hdferr) -call h5pset_chunk_f(hyp%plist, r, chunk_dims, hdferr) ! Set chunking +call h5pset_chunk_f(hyp%plist, rnk, chunk_dims, hdferr) ! Set chunking call h5pset_deflate_f(hyp%plist, compression_level, hdferr) ! Enable compression (GZIP level 4) call h5pset_shuffle_f(hyp%plist, hdferr) ! Enable shuffle filter (best compression) ! Create dataset with chunking + compression -call h5dcreate_f(file_or_group_id, trim(dataset_name), hyp%dset_type, & - hyp%dspace, hyp%dset, hdferr, hyp%plist) +call h5dcreate_f(file_or_group_id, trim(dataset_name), hyp%dset_type, hyp%dspace, hyp%dset, hdferr, hyp%plist) if (present(fdtype_name)) call write_attributeHDF5(id_idx,dataset_name,"fortran_type",fdtype_name,write_to_group,hyp%dset) @@ -370,31 +375,32 @@ end subroutine init_hyperspliced_array subroutine open_hyperspliced_array(id_idx,dataset_name,variable,read_group,hyp_id_idx,fdtype_name) +! Open the hypersplice/hyperslab array for reading -integer, intent(in) :: id_idx -character(len=*), intent(in) :: dataset_name -class(*), intent(in), dimension(..) :: variable -logical, intent(in) :: read_group -integer, intent(in) :: hyp_id_idx -character(len=*), optional, intent(inout) :: fdtype_name +integer, intent(in) :: id_idx !index for file/group +character(len=*), intent(in) :: dataset_name !name of h5 dataset +class(*), intent(in), dimension(..) :: variable !variable slice/slab to read +logical, intent(in) :: read_group !.true. to read from group, otherwise from file +integer, intent(in) :: hyp_id_idx !hypersplice/slab index +character(len=*), optional, intent(inout) :: fdtype_name !datatype name for corresponding attribute integer(HID_T) :: dspace_id, dset_id, file_or_group_id, dset_type -integer :: hdferr, i, r +integer :: hdferr, i, rnk integer(HSIZE_T) :: dims(7), chunk_dims(7) logical custom_type, using_mpi type(h5_ids_t), pointer :: hyp -r = rank(variable) +rnk = rank(variable) -if ((r < 0) .or. (r > 6)) then +if ((rnk < 0) .or. (rnk > 6)) then write(*,*) "(init_hyperspliced_array): input variable has invalid rank. Only a rank between 0 and 6 can be used." stop "Stopping." end if call get_file_or_group_id(read_group,id_idx,file_or_group_id,using_mpi) call get_file_or_group_hyp(read_group,id_idx,hyp_id_idx,hyp) -call get_var_dims(variable,r,hyp%dims) +call get_var_dims(variable,rnk,hyp%dims) call get_array_dset_type(variable,hyp%dset_type,custom_type) call set_dxpl_id(hyp%dxpl,using_mpi,mpi_independent=.true.) @@ -408,8 +414,8 @@ end subroutine open_hyperspliced_array subroutine close_entire_hyperspliced_dataset(id_idx,hyp_id_idx,in_group) -integer, intent(in) :: id_idx, hyp_id_idx -logical, intent(in) :: in_group +integer, intent(in) :: id_idx, hyp_id_idx !index for file/group and hypersplice/slab index +logical, intent(in) :: in_group !.true. if variable is in group integer :: hdferr type(h5_ids_t) :: reset_hyp @@ -426,9 +432,10 @@ end subroutine close_entire_hyperspliced_dataset subroutine config_hyper_dims(rnk,nslice,hyp_idx,dims,offset) -integer, intent(inout) :: rnk -integer, intent(in) :: nslice, hyp_idx -integer(HSIZE_T), intent(inout) :: dims(7), offset(7) + +integer, intent(inout) :: rnk !variable rank +integer, intent(in) :: nslice, hyp_idx !number of hyper slices and hypersplice/slab index +integer(HSIZE_T), intent(inout) :: dims(7), offset(7) !variable dimensions and offset position for I/O offset(:) = 0 if (nslice == 1) then !hypersplice @@ -438,24 +445,20 @@ subroutine config_hyper_dims(rnk,nslice,hyp_idx,dims,offset) else if (nslice >= 1) then !hyperslab dims(rnk) = nslice offset(rnk) = hyp_idx - 1 -else !dummy write +else !dummy write dims(:) = 0 end if end subroutine config_hyper_dims -!-----------------------------! -! Writing Subroutines ! -!-----------------------------! - - subroutine write_attributeHDF5(id_idx,dataset_name,attr_name,attr,write_group,dset_id) +! Write the attribute to h5 dataset -integer, intent(in) :: id_idx -character(len=*), intent(in) :: dataset_name,attr_name -class(*), intent(in), dimension(..) :: attr -logical, intent(in) :: write_group -integer(HID_T), optional, intent(in) :: dset_id +integer, intent(in) :: id_idx !index for file/group +character(len=*), intent(in) :: dataset_name,attr_name !h5 dataset and attribute name +class(*), intent(in), dimension(..) :: attr !attribute of interest +logical, intent(in) :: write_group !.true. to write to group, otherwise to file +integer(HID_T), optional, intent(in) :: dset_id !corresponding h5 dataset id integer(HID_T) :: dset_id_, space_id, file_or_group_id, type_id, attr_id integer(HSIZE_T) :: dims(7) @@ -502,87 +505,54 @@ subroutine write_attributeHDF5(id_idx,dataset_name,attr_name,attr,write_group,ds end subroutine -subroutine read_attributeHDF5(id_idx,dataset_name,attr_name,attr,read_group,dset_id) - -integer, intent(in) :: id_idx -character(len=*), intent(in) :: dataset_name,attr_name -class(*), intent(inout), dimension(..) :: attr -logical, intent(in) :: read_group -integer(HID_T), optional, intent(in) :: dset_id - -integer(HID_T) :: dset_id_, file_or_group_id, type_id, attr_id -integer(HSIZE_T) :: dims(7) -integer :: hdferr, rnk -logical :: custom_type,using_mpi - -rnk = rank(attr) -call get_var_dims(attr,rnk,dims) -call get_file_or_group_id(read_group,id_idx,file_or_group_id,using_mpi) -call get_array_dset_type(attr,type_id,custom_type) - -if(.not. present(dset_id)) then - call h5dopen_f(file_or_group_id, trim(dataset_name), dset_id_, hdferr) -else - dset_id_ = dset_id -end if -! Get read attribute -call h5aopen_f(dset_id_, trim(attr_name), attr_id, hdferr) - -select rank(attr) -rank(0) -#include "modhdf5_attribute_read.inc" -rank(1) -#include "modhdf5_attribute_read.inc" -rank(2) -#include "modhdf5_attribute_read.inc" -rank(3) -#include "modhdf5_attribute_read.inc" -rank(4) -#include "modhdf5_attribute_read.inc" -rank(5) -#include "modhdf5_attribute_read.inc" -rank(6) -#include "modhdf5_attribute_read.inc" -rank(7) -#include "modhdf5_attribute_read.inc" -end select - -call h5aclose_f(attr_id, hdferr) -if (custom_type) call h5tclose_f(type_id, hdferr) !close custom dset_type -if(.not. present(dset_id)) call h5dclose_f(dset_id_, hdferr) - -end subroutine read_attributeHDF5 - - subroutine writeHDF5(id_idx,dataset_name,variable_to_write,write_to_group,fdtype_name) +! Write the variable_to_write to h5 dataset -integer, intent(in) :: id_idx -character(len=*), intent(in) :: dataset_name -class(*), intent(in), dimension(..) :: variable_to_write -logical, intent(in) :: write_to_group -character(len=*), optional, intent(in) :: fdtype_name +integer, intent(in) :: id_idx !index for file/group +character(len=*), intent(in) :: dataset_name !h5 dataset name +class(*), intent(in), dimension(..) :: variable_to_write !variable of interest +logical, intent(in) :: write_to_group !.true. to write to group, otherwise to file +character(len=*), optional, intent(in) :: fdtype_name !variable datatype name within dataset attribute integer(HID_T) :: file_or_group_id -integer :: hdferr, i, r +integer :: hdferr, rnk logical custom_type,using_mpi type(h5_ids_t) :: h5_ids -r = rank(variable_to_write) +rnk = rank(variable_to_write) -if ((r < 0) .or. (r > 7)) then +if ((rnk < 0) .or. (rnk > 7)) then write(*,*) "(writeHDF5): input variable to write has invalid rank. Only a rank between 0 and 7 can be used." stop "Stopping." end if -call get_var_dims(variable_to_write,r,h5_ids%dims) +call get_var_dims(variable_to_write,rnk,h5_ids%dims) call get_array_dset_type(variable_to_write,h5_ids%dset_type,custom_type) call get_file_or_group_id(write_to_group,id_idx,file_or_group_id,using_mpi) call set_dxpl_id(h5_ids%dxpl,using_mpi,mpi_independent=.true.) ! Create dataspace (within group or not) for integer and save within that space -call h5screate_simple_f(r, h5_ids%dims(1:r), h5_ids%dspace, hdferr) +call h5screate_simple_f(rnk, h5_ids%dims(1:rnk), h5_ids%dspace, hdferr) call h5dcreate_f(file_or_group_id, trim(dataset_name), h5_ids%dset_type, h5_ids%dspace, h5_ids%dset, hdferr) -call h5dataset_write(variable_to_write, h5_ids%dims, h5_ids%dset_type, h5_ids%dset, h5_ids%dxpl) + +select rank(variable_to_write) +rank(0) +#include "modhdf5_write.inc" +rank(1) +#include "modhdf5_write.inc" +rank(2) +#include "modhdf5_write.inc" +rank(3) +#include "modhdf5_write.inc" +rank(4) +#include "modhdf5_write.inc" +rank(5) +#include "modhdf5_write.inc" +rank(6) +#include "modhdf5_write.inc" +rank(7) +#include "modhdf5_write.inc" +end select if (present(fdtype_name)) call write_attributeHDF5(id_idx,dataset_name,"fortran_type",fdtype_name,write_to_group,h5_ids%dset) @@ -595,33 +565,33 @@ end subroutine writeHDF5 subroutine writeHDF5_hypersplice(id_idx,dataset_name,variable_to_write,write_to_group,hyp_id_idx,hyp_idx,nslice) +! Write the hypersplice/hyperslab array to h5 dataset -integer, intent(in) :: id_idx !index for file_id/group_id -character(len=*), intent(in) :: dataset_name !name of dataset in h5 file -class(*), intent(in), dimension(..) :: variable_to_write !value to be written -logical, intent(in) :: write_to_group !logical for distinguishing whether to write to group or not -integer, intent(in) :: hyp_id_idx -integer, intent(in) :: hyp_idx -integer, intent(in) :: nslice !>= 1 to write slice/slab, else do not write data +integer, intent(in) :: id_idx !index for file/group +character(len=*), intent(in) :: dataset_name !name of h5 dataset +class(*), intent(in), dimension(..) :: variable_to_write !variable of interest +logical, intent(in) :: write_to_group !.true. to write to group, otherwise to file +integer, intent(in) :: hyp_id_idx, hyp_idx !hypersplice/slab index and hyper array index (for last rank not in slice) +integer, intent(in) :: nslice !number of hyper slices (> 1 to write slab, = 1 for slice, else do not write data) integer(HID_T) :: file_or_group_id, dset_type, memspace_id -integer :: hdferr, i, r +integer :: hdferr, rnk integer(HSIZE_T) :: dims(7), offset(7) logical :: dset_exists, custom_type,using_mpi type(h5_ids_t), pointer :: hyp -r = rank(variable_to_write) +rnk = rank(variable_to_write) -if ((r < 0) .or. (r > 6)) then +if ((rnk < 0) .or. (rnk > 6)) then write(*,*) "(writeHDF5_hypersplice): input variable to write has invalid rank. Only a rank between 0 and 6 can be used." stop "Stopping." end if call get_file_or_group_id(write_to_group,id_idx,file_or_group_id,using_mpi) call get_file_or_group_hyp(write_to_group,id_idx,hyp_id_idx,hyp) -call get_var_dims(variable_to_write,r,dims) +call get_var_dims(variable_to_write,rnk,dims) call get_array_dset_type(variable_to_write,dset_type,custom_type) -call config_hyper_dims(r,nslice,hyp_idx,dims,offset) +call config_hyper_dims(rnk,nslice,hyp_idx,dims,offset) ! Check if dataset already exists call h5lexists_f(file_or_group_id, trim(dataset_name), dset_exists, hdferr) @@ -630,9 +600,27 @@ subroutine writeHDF5_hypersplice(id_idx,dataset_name,variable_to_write,write_to_ stop "Stopping." end if -call h5sselect_hyperslab_f(hyp%dspace, H5S_SELECT_SET_F, offset(1:r), dims(1:r), hdferr) -call h5screate_simple_f(r, dims(1:r), memspace_id, hdferr) -call h5dataset_write(variable_to_write, dims, dset_type, hyp%dset, hyp%dxpl, memspace_id, hyp%dspace) +call h5sselect_hyperslab_f(hyp%dspace, H5S_SELECT_SET_F, offset(1:rnk), dims(1:rnk), hdferr) +call h5screate_simple_f(rnk, dims(1:rnk), memspace_id, hdferr) + +select rank(variable_to_write) +rank(0) +#include "modhdf5_write_hyper.inc" +rank(1) +#include "modhdf5_write_hyper.inc" +rank(2) +#include "modhdf5_write_hyper.inc" +rank(3) +#include "modhdf5_write_hyper.inc" +rank(4) +#include "modhdf5_write_hyper.inc" +rank(5) +#include "modhdf5_write_hyper.inc" +rank(6) +#include "modhdf5_write_hyper.inc" +rank(7) +#include "modhdf5_write_hyper.inc" +end select if (custom_type) call h5tclose_f(dset_type, hdferr) !close custom dset_type call h5sclose_f(memspace_id, hdferr) @@ -640,38 +628,105 @@ subroutine writeHDF5_hypersplice(id_idx,dataset_name,variable_to_write,write_to_ end subroutine writeHDF5_hypersplice -!-----------------------------! -! Reading Subroutines ! -!-----------------------------! +subroutine read_attributeHDF5(id_idx,dataset_name,attr_name,attr,read_group,dset_id) +! Read the attribute from h5 dataset + +integer, intent(in) :: id_idx !index for file/group +character(len=*), intent(in) :: dataset_name,attr_name !h5 dataset and attribute name +class(*), intent(inout), dimension(..) :: attr !attribute of interest +logical, intent(in) :: read_group !.true. to read from group, otherwise from file +integer(HID_T), optional, intent(in) :: dset_id !corresponding h5 dataset id + +integer(HID_T) :: dset_id_, file_or_group_id, type_id, attr_id +integer(HSIZE_T) :: dims(7) +integer :: hdferr, rnk +logical :: custom_type,using_mpi + +rnk = rank(attr) +call get_var_dims(attr,rnk,dims) +call get_file_or_group_id(read_group,id_idx,file_or_group_id,using_mpi) +call get_array_dset_type(attr,type_id,custom_type) + +if(.not. present(dset_id)) then + call h5dopen_f(file_or_group_id, trim(dataset_name), dset_id_, hdferr) +else + dset_id_ = dset_id +end if +! Get read attribute +call h5aopen_f(dset_id_, trim(attr_name), attr_id, hdferr) + +select rank(attr) +rank(0) +#include "modhdf5_attribute_read.inc" +rank(1) +#include "modhdf5_attribute_read.inc" +rank(2) +#include "modhdf5_attribute_read.inc" +rank(3) +#include "modhdf5_attribute_read.inc" +rank(4) +#include "modhdf5_attribute_read.inc" +rank(5) +#include "modhdf5_attribute_read.inc" +rank(6) +#include "modhdf5_attribute_read.inc" +rank(7) +#include "modhdf5_attribute_read.inc" +end select + +call h5aclose_f(attr_id, hdferr) +if (custom_type) call h5tclose_f(type_id, hdferr) !close custom dset_type +if(.not. present(dset_id)) call h5dclose_f(dset_id_, hdferr) + +end subroutine read_attributeHDF5 subroutine readHDF5(id_idx,dataset_name,variable_to_read,read_group,fdtype_name) +! Read the variable_to_read from h5 dataset -integer, intent(in) :: id_idx -character(len=*), intent(in) :: dataset_name -class(*), intent(inout), dimension(..) :: variable_to_read -logical, intent(in) :: read_group -character(len=*), optional, intent(inout) :: fdtype_name +integer, intent(in) :: id_idx !index for file/group +character(len=*), intent(in) :: dataset_name !h5 dataset name +class(*), intent(inout), dimension(..) :: variable_to_read !variable of interest +logical, intent(in) :: read_group !.true. to read from group, otherwise from file +character(len=*), optional, intent(inout) :: fdtype_name !variable datatype name within dataset attribute integer(HID_T) :: file_or_group_id -integer :: hdferr, i, r +integer :: hdferr, rnk logical custom_type,using_mpi type(h5_ids_t) :: h5_ids -r = rank(variable_to_read) +rnk = rank(variable_to_read) -if ((r < 0) .or. (r > 7)) then +if ((rnk < 0) .or. (rnk > 7)) then write(*,*) "(readHDF5): input variable to read has invalid rank. Only a rank between 0 and 7 can be used." stop "Stopping." end if call get_file_or_group_id(read_group,id_idx,file_or_group_id,using_mpi) -call get_var_dims(variable_to_read,r,h5_ids%dims) +call get_var_dims(variable_to_read,rnk,h5_ids%dims) call get_array_dset_type(variable_to_read,h5_ids%dset_type,custom_type) call set_dxpl_id(h5_ids%dxpl,using_mpi,mpi_independent=.true.) call h5dopen_f(file_or_group_id, trim(dataset_name), h5_ids%dset, hdferr) -call h5dataset_read(variable_to_read, h5_ids%dims, h5_ids%dset_type, h5_ids%dset, h5_ids%dxpl) + +select rank(variable_to_read) +rank(0) +#include "modhdf5_read.inc" +rank(1) +#include "modhdf5_read.inc" +rank(2) +#include "modhdf5_read.inc" +rank(3) +#include "modhdf5_read.inc" +rank(4) +#include "modhdf5_read.inc" +rank(5) +#include "modhdf5_read.inc" +rank(6) +#include "modhdf5_read.inc" +rank(7) +#include "modhdf5_read.inc" +end select if (present(fdtype_name)) call read_attributeHDF5(id_idx,dataset_name,"fortran_type",fdtype_name,read_group,h5_ids%dset) @@ -683,108 +738,61 @@ end subroutine readHDF5 subroutine readHDF5_hypersplice(id_idx,dataset_name,variable_to_read,read_group,hyp_id_idx,hyp_idx,nslice) +! Read the hypersplice/hyperslab array from h5 dataset -integer, intent(in) :: id_idx -character(len=*), intent(in) :: dataset_name -class(*), intent(inout), dimension(..) :: variable_to_read -logical, intent(in) :: read_group -integer, intent(in) :: hyp_id_idx -integer, intent(in) :: hyp_idx -integer, intent(in) :: nslice !>= 1 to write slice/slab, else do not write data +integer, intent(in) :: id_idx !index for file/group +character(len=*), intent(in) :: dataset_name !name of h5 dataset +class(*), intent(inout), dimension(..) :: variable_to_read !variable of interest +logical, intent(in) :: read_group !.true. to read from group, otherwise from file +integer, intent(in) :: hyp_id_idx, hyp_idx !hypersplice/slab index and hyper array index (for last rank not in slice) +integer, intent(in) :: nslice !number of hyper slices (> 1 to read slab, = 1 for slice, else do not read data) integer(HID_T) :: file_or_group_id, dset_type, memspace_id, filespace_id -integer :: hdferr, i, r +integer :: hdferr, rnk integer(HSIZE_T) :: dims(7), offset(7) logical custom_type,using_mpi type(h5_ids_t), pointer :: hyp -r = rank(variable_to_read) +rnk = rank(variable_to_read) -if ((r < 0) .and. (r > 6)) then +if ((rnk < 0) .and. (rnk > 6)) then write(*,*) "(readHDF5_hypersplice): input variable to read has invalid rank. Only a rank between 0 and 6 can be used." stop "Stopping." end if call get_file_or_group_id(read_group,id_idx,file_or_group_id,using_mpi) call get_file_or_group_hyp(read_group,id_idx,hyp_id_idx,hyp) -call get_var_dims(variable_to_read,r,dims) +call get_var_dims(variable_to_read,rnk,dims) call get_array_dset_type(variable_to_read,dset_type,custom_type) -call config_hyper_dims(r,nslice,hyp_idx,dims,offset) +call config_hyper_dims(rnk,nslice,hyp_idx,dims,offset) -call h5sselect_hyperslab_f(hyp%dspace, H5S_SELECT_SET_F, offset(1:r), dims(1:r), hdferr) -if (nslice == 1) r = r - 1 !hypersplice -call h5screate_simple_f(r, dims(1:r), memspace_id, hdferr) -call h5dataset_read(variable_to_read, dims, dset_type, hyp%dset, hyp%dxpl, memspace_id, hyp%dspace) +call h5sselect_hyperslab_f(hyp%dspace, H5S_SELECT_SET_F, offset(1:rnk), dims(1:rnk), hdferr) +if (nslice == 1) rnk = rnk - 1 !hypersplice +call h5screate_simple_f(rnk, dims(1:rnk), memspace_id, hdferr) -if (custom_type) call h5tclose_f(dset_type, hdferr) !close custom dset_type -call h5sclose_f(memspace_id, hdferr) - -end subroutine readHDF5_hypersplice - - -!----------------------------------! -! IO Interface Subroutines ! -!----------------------------------! - - -subroutine h5dataset_write(variable, dims, dset_type, dset_id, dxpl_id, memspace_id, filespace_id) -integer(HID_T), intent(in) :: dset_id, dset_type, dxpl_id -class(*), intent(in), dimension(..) :: variable !value to be written -integer(HSIZE_T), intent(in) :: dims(7) -integer(HID_T), intent(in), optional :: memspace_id, filespace_id - -integer :: hdferr, rnk - -select rank(variable) +select rank(variable_to_read) rank(0) -#include "modhdf5_write.inc" +#include "modhdf5_read_hyper.inc" rank(1) -#include "modhdf5_write.inc" +#include "modhdf5_read_hyper.inc" rank(2) -#include "modhdf5_write.inc" +#include "modhdf5_read_hyper.inc" rank(3) -#include "modhdf5_write.inc" +#include "modhdf5_read_hyper.inc" rank(4) -#include "modhdf5_write.inc" +#include "modhdf5_read_hyper.inc" rank(5) -#include "modhdf5_write.inc" +#include "modhdf5_read_hyper.inc" rank(6) -#include "modhdf5_write.inc" +#include "modhdf5_read_hyper.inc" rank(7) -#include "modhdf5_write.inc" +#include "modhdf5_read_hyper.inc" end select -end subroutine h5dataset_write - - -subroutine h5dataset_read(variable, dims, dset_type, dset_id, dxpl_id, memspace_id, filespace_id) -integer(HID_T), intent(in) :: dset_id, dset_type, dxpl_id -class(*), intent(inout), dimension(..) :: variable !value to be written -integer(HSIZE_T), intent(in) :: dims(7) -integer(HID_T), intent(in), optional :: memspace_id, filespace_id - -integer :: hdferr, rnk - -select rank(variable) -rank(0) -#include "modhdf5_read.inc" -rank(1) -#include "modhdf5_read.inc" -rank(2) -#include "modhdf5_read.inc" -rank(3) -#include "modhdf5_read.inc" -rank(4) -#include "modhdf5_read.inc" -rank(5) -#include "modhdf5_read.inc" -rank(6) -#include "modhdf5_read.inc" -rank(7) -#include "modhdf5_read.inc" -end select +if (custom_type) call h5tclose_f(dset_type, hdferr) !close custom dset_type +call h5sclose_f(memspace_id, hdferr) -end subroutine h5dataset_read +end subroutine readHDF5_hypersplice end module diff --git a/src/modhdf5_attribute_read.inc b/src/modhdf5_attribute_read.inc index 0f8e3ec..f03e666 100644 --- a/src/modhdf5_attribute_read.inc +++ b/src/modhdf5_attribute_read.inc @@ -3,7 +3,6 @@ ! See the file COPYING for license details. ! can only be used in read_attributeHDF5() -rnk = rank(attr) select type(attr) type is (integer) call h5aread_f(attr_id, type_id, attr, dims(1:rnk), hdferr) diff --git a/src/modhdf5_attribute_write.inc b/src/modhdf5_attribute_write.inc index c88b0e3..3d84c16 100644 --- a/src/modhdf5_attribute_write.inc +++ b/src/modhdf5_attribute_write.inc @@ -3,7 +3,6 @@ ! See the file COPYING for license details. ! can only be used in write_attributeHDF5() -rnk = rank(attr) select type(attr) type is (integer) call h5awrite_f(attr_id, type_id, attr, dims(1:rnk), hdferr) diff --git a/src/modhdf5_read.inc b/src/modhdf5_read.inc index 86c1cc7..c31d863 100644 --- a/src/modhdf5_read.inc +++ b/src/modhdf5_read.inc @@ -2,31 +2,14 @@ ! This file is distributed under the terms of the GNU General Public License. ! See the file COPYING for license details. -! can only be used in h5dataset_read() -rnk = rank(variable) -select type(variable) +! can only be used in readHDF5() +select type(variable_to_read) type is (integer) - if (present(memspace_id) .and. present(filespace_id)) then - call h5dread_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, memspace_id, filespace_id, xfer_prp=dxpl_id) - else - call h5dread_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, xfer_prp=dxpl_id) - end if + call h5dread_f(h5_ids%dset, h5_ids%dset_type, variable_to_read, h5_ids%dims(1:rnk), hdferr, xfer_prp=h5_ids%dxpl) type is (real) - if (present(memspace_id) .and. present(filespace_id)) then - call h5dread_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, memspace_id, filespace_id, xfer_prp=dxpl_id) - else - call h5dread_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, xfer_prp=dxpl_id) - end if + call h5dread_f(h5_ids%dset, h5_ids%dset_type, variable_to_read, h5_ids%dims(1:rnk), hdferr, xfer_prp=h5_ids%dxpl) type is (real(8)) - if (present(memspace_id) .and. present(filespace_id)) then - call h5dread_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, memspace_id, filespace_id, xfer_prp=dxpl_id) - else - call h5dread_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, xfer_prp=dxpl_id) - end if + call h5dread_f(h5_ids%dset, h5_ids%dset_type, variable_to_read, h5_ids%dims(1:rnk), hdferr, xfer_prp=h5_ids%dxpl) type is (character(*)) - if (present(memspace_id) .and. present(filespace_id)) then - call h5dread_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, memspace_id, filespace_id, xfer_prp=dxpl_id) - else - call h5dread_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, xfer_prp=dxpl_id) - end if + call h5dread_f(h5_ids%dset, h5_ids%dset_type, variable_to_read, h5_ids%dims(1:rnk), hdferr, xfer_prp=h5_ids%dxpl) end select \ No newline at end of file diff --git a/src/modhdf5_read_hyper.inc b/src/modhdf5_read_hyper.inc new file mode 100644 index 0000000..55efc63 --- /dev/null +++ b/src/modhdf5_read_hyper.inc @@ -0,0 +1,15 @@ +! Copyright (C) 2025 A. D. N. James. +! This file is distributed under the terms of the GNU General Public License. +! See the file COPYING for license details. + +! can only be used in readHDF5_hypersplice() +select type(variable_to_read) +type is (integer) + call h5dread_f(hyp%dset, dset_type, variable_to_read, dims(1:rnk), hdferr, memspace_id, hyp%dspace, xfer_prp=hyp%dxpl) +type is (real) + call h5dread_f(hyp%dset, dset_type, variable_to_read, dims(1:rnk), hdferr, memspace_id, hyp%dspace, xfer_prp=hyp%dxpl) +type is (real(8)) + call h5dread_f(hyp%dset, dset_type, variable_to_read, dims(1:rnk), hdferr, memspace_id, hyp%dspace, xfer_prp=hyp%dxpl) +type is (character(*)) + call h5dread_f(hyp%dset, dset_type, variable_to_read, dims(1:rnk), hdferr, memspace_id, hyp%dspace, xfer_prp=hyp%dxpl) +end select \ No newline at end of file diff --git a/src/modhdf5_write.inc b/src/modhdf5_write.inc index 5348e99..7d6ff74 100644 --- a/src/modhdf5_write.inc +++ b/src/modhdf5_write.inc @@ -2,31 +2,14 @@ ! This file is distributed under the terms of the GNU General Public License. ! See the file COPYING for license details. -! can only be used in h5dataset_write() -rnk = rank(variable) -select type(variable) +! can only be used in writeHDF5() +select type(variable_to_write) type is (integer) - if (present(memspace_id) .and. present(filespace_id)) then - call h5dwrite_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, memspace_id, filespace_id, xfer_prp=dxpl_id) - else - call h5dwrite_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, xfer_prp=dxpl_id) - end if + call h5dwrite_f(h5_ids%dset, h5_ids%dset_type, variable_to_write, h5_ids%dims(1:rnk), hdferr, xfer_prp=h5_ids%dxpl) type is (real) - if (present(memspace_id) .and. present(filespace_id)) then - call h5dwrite_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, memspace_id, filespace_id, xfer_prp=dxpl_id) - else - call h5dwrite_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, xfer_prp=dxpl_id) - end if + call h5dwrite_f(h5_ids%dset, h5_ids%dset_type, variable_to_write, h5_ids%dims(1:rnk), hdferr, xfer_prp=h5_ids%dxpl) type is (real(8)) - if (present(memspace_id) .and. present(filespace_id)) then - call h5dwrite_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, memspace_id, filespace_id, xfer_prp=dxpl_id) - else - call h5dwrite_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, xfer_prp=dxpl_id) - end if + call h5dwrite_f(h5_ids%dset, h5_ids%dset_type, variable_to_write, h5_ids%dims(1:rnk), hdferr, xfer_prp=h5_ids%dxpl) type is (character(*)) - if (present(memspace_id) .and. present(filespace_id)) then - call h5dwrite_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, memspace_id, filespace_id, xfer_prp=dxpl_id) - else - call h5dwrite_f(dset_id, dset_type, variable, dims(1:rnk), hdferr, xfer_prp=dxpl_id) - end if + call h5dwrite_f(h5_ids%dset, h5_ids%dset_type, variable_to_write, h5_ids%dims(1:rnk), hdferr, xfer_prp=h5_ids%dxpl) end select \ No newline at end of file diff --git a/src/modhdf5_write_hyper.inc b/src/modhdf5_write_hyper.inc new file mode 100644 index 0000000..c786380 --- /dev/null +++ b/src/modhdf5_write_hyper.inc @@ -0,0 +1,15 @@ +! Copyright (C) 2025 A. D. N. James. +! This file is distributed under the terms of the GNU General Public License. +! See the file COPYING for license details. + +! can only be used in writeHDF5_hypersplice() +select type(variable_to_write) +type is (integer) + call h5dwrite_f(hyp%dset, dset_type, variable_to_write, dims(1:rnk), hdferr, memspace_id, hyp%dspace, xfer_prp=hyp%dxpl) +type is (real) + call h5dwrite_f(hyp%dset, dset_type, variable_to_write, dims(1:rnk), hdferr, memspace_id, hyp%dspace, xfer_prp=hyp%dxpl) +type is (real(8)) + call h5dwrite_f(hyp%dset, dset_type, variable_to_write, dims(1:rnk), hdferr, memspace_id, hyp%dspace, xfer_prp=hyp%dxpl) +type is (character(*)) + call h5dwrite_f(hyp%dset, dset_type, variable_to_write, dims(1:rnk), hdferr, memspace_id, hyp%dspace, xfer_prp=hyp%dxpl) +end select \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 773b45d..c80b048 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -32,8 +32,29 @@ set(SOURCE_FILES # Create the executable target first (common to both compilers) add_executable(${Executable} ${SOURCE_FILES}) -# Handle Intel Fortran -if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") +# Handle Intel Fortran (ifx) +if(CMAKE_Fortran_COMPILER_ID STREQUAL "IntelLLVM") + # Check minimum version + if(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 2022.0) + message(FATAL_ERROR "Intel Fortran LLVM (ifx) version 2022.0 or later is required.") + endif() + + # Set compilation flags + if(USE_DEBUG_FLAGS) + message(STATUS "IntelLLVM Fortran debug flags are enabled.") + set(COMPILER_FLAGS "-fpp -O3 -fopenmp -g -check all -traceback -Wall -fstack-protector -O0") + else() + set(COMPILER_FLAGS "-fpp -O3 -fopenmp") + endif() + + # Apply flags to target + set_property(TARGET ${Executable} PROPERTY COMPILE_OPTIONS ${COMPILER_FLAGS}) + + # Link OpenMP library explicitly + set(OPENMP_LIB "-liomp5") + +# Handle older Intel Fortran (ifort) +elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") # Check minimum version if(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 18.0) message(FATAL_ERROR "Intel Fortran Compiler version 18.0 or later is required.") @@ -42,9 +63,9 @@ if(CMAKE_Fortran_COMPILER_ID STREQUAL "Intel") # Set compilation flags if(USE_DEBUG_FLAGS) message(STATUS "Intel Fortran debug flags are enabled.") - set(COMPILER_FLAGS "-qopenmp -cpp -g -assume realloc_lhs -check all -traceback -warn all -fstack-protector -assume protect_parens -O0") + set(COMPILER_FLAGS "-qopenmp -fpp -g -assume realloc_lhs -check all -traceback -warn all -fstack-protector -assume protect_parens -O0") else() - set(COMPILER_FLAGS "-qopenmp -O3 -cpp") + set(COMPILER_FLAGS "-qopenmp -O3 -fpp") endif() # Apply flags to target