From 0ce7b717be63e1dc78920785e041e2c95aa315b7 Mon Sep 17 00:00:00 2001 From: Norbert Podhorszki Date: Fri, 10 Sep 2021 09:24:12 -0400 Subject: [PATCH 1/4] Remove F2008 string allocation from Fortran binding. sadios2_available_variables() and adios2_available_attributes return a struct, user has to allocate character array and call adios2_retrieve_names() to fill the array with the names. --- bindings/Fortran/f2c/adios2_f2c_io.cpp | 67 +++----------- bindings/Fortran/modules/adios2_io_mod.f90 | 89 +++++++++++++------ .../Fortran/modules/adios2_parameters_mod.f90 | 7 ++ .../fortran/TestBPWriteReadAttributes.F90 | 29 ++++-- .../bindings/fortran/TestBPWriteTypes.F90 | 21 +++-- 5 files changed, 120 insertions(+), 93 deletions(-) diff --git a/bindings/Fortran/f2c/adios2_f2c_io.cpp b/bindings/Fortran/f2c/adios2_f2c_io.cpp index dd5bec6317..74234501c4 100644 --- a/bindings/Fortran/f2c/adios2_f2c_io.cpp +++ b/bindings/Fortran/f2c/adios2_f2c_io.cpp @@ -236,7 +236,6 @@ void FC_GLOBAL(adios2_available_variables_f2c, cnamelist *info = new (cnamelist); info->names = adios2_available_variables(*io, &info->count); *vars_count = static_cast(info->count); - size_t maxlen = 0; for (size_t i = 0; i < info->count; ++i) { @@ -247,47 +246,10 @@ void FC_GLOBAL(adios2_available_variables_f2c, } } *max_var_name_len = static_cast(maxlen); - *namestruct = static_cast(reinterpret_cast(info)); *ierr = 0; } -void FC_GLOBAL(adios2_retrieve_variable_names_f2c, - ADIOS2_RETRIEVE_VARIABLE_NAMES_F2C)(int64_t *namestruct, - int *count, - int *max_name_len, - void *vnamelist, int *ierr, - int vnamelist_len) -{ - cnamelist *info = reinterpret_cast(*namestruct); - int cnt = info->count; - if (cnt > *count) - { - cnt = *count; - } - if (info != NULL && static_cast(*count) == info->count) - { - for (int i = 0; i < *count; i++) - { - char *fs = (char *)vnamelist + i * vnamelist_len; - size_t len = strlen(info->names[i]); - if (len > static_cast(vnamelist_len)) - { - len = static_cast(vnamelist_len); - } - // copy C string without '\0' - strncpy(fs, info->names[i], len); - // pad with spaces - memset(fs + len, ' ', vnamelist_len - len); - } - *ierr = 0; - } - else - { - *ierr = 1; - } -} - void FC_GLOBAL(adios2_available_attributes_f2c, ADIOS2_AVAILABLE_ATTRIBUTES_F2C)(adios2_io **io, int64_t *namestruct, @@ -314,35 +276,30 @@ void FC_GLOBAL(adios2_available_attributes_f2c, *ierr = 0; } -void FC_GLOBAL(adios2_retrieve_attribute_names_f2c, - ADIOS2_RETRIEVE_ATTRIBUTE_NAMES_F2C)(int64_t *namestruct, - int *count, - int *max_name_len, - void *anamelist, int *ierr, - int anamelist_len) +void FC_GLOBAL(adios2_retrieve_namelist_f2c, + ADIOS2_RETRIEVE_NAMELIST_F2C)(int64_t *namestruct, + void *namelist, int *ierr, + int namelist_len) { cnamelist *info = reinterpret_cast(*namestruct); - int cnt = info->count; - if (cnt > *count) - { - cnt = *count; - } - if (info != NULL && static_cast(*count) == info->count) + if (info != NULL) { - for (int i = 0; i < *count; i++) + for (size_t i = 0; i < info->count; i++) { - char *fs = (char *)anamelist + i * anamelist_len; + char *fs = (char *)namelist + i * namelist_len; size_t len = strlen(info->names[i]); - if (len > static_cast(anamelist_len)) + if (len > static_cast(namelist_len)) { - len = static_cast(anamelist_len); + len = static_cast(namelist_len); } // copy C string without '\0' strncpy(fs, info->names[i], len); // pad with spaces - memset(fs + len, ' ', anamelist_len - len); + memset(fs + len, ' ', namelist_len - len); } *ierr = 0; + delete (info); + *namestruct = 0; } else { diff --git a/bindings/Fortran/modules/adios2_io_mod.f90 b/bindings/Fortran/modules/adios2_io_mod.f90 index cc0482bded..0d234e1700 100644 --- a/bindings/Fortran/modules/adios2_io_mod.f90 +++ b/bindings/Fortran/modules/adios2_io_mod.f90 @@ -158,26 +158,53 @@ subroutine adios2_set_transport_parameter(io, transport_index, key, value, & end subroutine - subroutine adios2_available_variables(io, nvars, varnamelist, ierr) + subroutine adios2_available_variables(io, namestruct, ierr) type(adios2_io), intent(in) :: io - integer, intent(out) :: nvars - character(len=:), dimension(:), allocatable, intent(out) :: varnamelist + type(adios2_namestruct), intent(out) :: namestruct integer, intent(out) :: ierr - integer(kind=8):: namestruct - integer :: count, max_name_len - - call adios2_available_variables_f2c(io%f2c, namestruct, count, & - max_name_len, ierr) + call adios2_available_variables_f2c(io%f2c, namestruct%f2c, & + namestruct%count, namestruct%max_name_len, ierr) if (ierr == 0) then - allocate(character(len=max_name_len) :: varnamelist(count)) + namestruct%valid = .true. endif + end subroutine + + subroutine adios2_retrieve_names(namestruct, namelist, ierr) + type(adios2_namestruct), intent(inout) :: namestruct + character(*), dimension(*), intent(inout) :: namelist + integer, intent(out) :: ierr - call adios2_retrieve_variable_names_f2c(namestruct, count, & - max_name_len, varnamelist, ierr) - nvars = count + if (namestruct%valid .and. namestruct%f2c > 0_8) then + call adios2_retrieve_namelist_f2c(namestruct%f2c, namelist, ierr) + else + write(*,*) "ADIOS2 Fortran ERROR: invalid namestruct when calling adios2_retrieve_names()" + endif + namestruct%valid = .false. end subroutine + ! + ! F2008 implementation that allows for allocating a character array inside + ! + ! subroutine adios2_available_variables(io, nvars, varnamelist, ierr) + ! type(adios2_io), intent(in) :: io + ! integer, intent(out) :: nvars + ! character(len=:), dimension(:), allocatable, intent(out) :: varnamelist + ! integer, intent(out) :: ierr + + ! integer(kind=8):: namestruct + ! integer :: count, max_name_len + + ! call adios2_available_variables_f2c(io%f2c, namestruct, count, & + ! max_name_len, ierr) + ! if (ierr == 0) then + ! allocate(character(len=max_name_len) :: varnamelist(count)) + ! endif + + ! call adios2_retrieve_variable_names_f2c(namestruct, varnamelist, ierr) + ! nvars = count + ! end subroutine + subroutine adios2_inquire_variable(variable, io, name, ierr) type(adios2_variable), intent(out) :: variable @@ -233,26 +260,38 @@ subroutine adios2_remove_all_variables(io, ierr) end subroutine - subroutine adios2_available_attributes(io, nattrs, attrnamelist, ierr) + subroutine adios2_available_attributes(io, namestruct, ierr) type(adios2_io), intent(in) :: io - integer, intent(out) :: nattrs - character(len=:), dimension(:), allocatable, intent(out) :: attrnamelist + type(adios2_namestruct), intent(out) :: namestruct integer, intent(out) :: ierr - integer(kind=8):: namestruct - integer :: count, max_name_len - - call adios2_available_attributes_f2c(io%f2c, namestruct, count, & - max_name_len, ierr) + call adios2_available_attributes_f2c(io%f2c, namestruct%f2c, & + namestruct%count, namestruct%max_name_len, ierr) if (ierr == 0) then - allocate(character(len=max_name_len) :: attrnamelist(count)) + namestruct%valid = .true. endif - - call adios2_retrieve_attribute_names_f2c(namestruct, count, & - max_name_len, attrnamelist, ierr) - nattrs = count end subroutine + ! subroutine adios2_available_attributes(io, nattrs, attrnamelist, ierr) + ! type(adios2_io), intent(in) :: io + ! integer, intent(out) :: nattrs + ! character(len=:), dimension(:), allocatable, intent(out) :: attrnamelist + ! integer, intent(out) :: ierr + + ! integer(kind=8):: namestruct + ! integer :: count, max_name_len + + ! call adios2_available_attributes_f2c(io%f2c, namestruct, count, & + ! max_name_len, ierr) + ! if (ierr == 0) then + ! allocate(character(len=max_name_len) :: attrnamelist(count)) + ! endif + + ! call adios2_retrieve_attribute_names_f2c(namestruct, count, & + ! max_name_len, attrnamelist, ierr) + ! nattrs = count + ! end subroutine + subroutine adios2_inquire_attribute(attribute, io, name, ierr) type(adios2_attribute), intent(out) :: attribute type(adios2_io), intent(in) :: io diff --git a/bindings/Fortran/modules/adios2_parameters_mod.f90 b/bindings/Fortran/modules/adios2_parameters_mod.f90 index c3376321d7..6be4deb2d9 100644 --- a/bindings/Fortran/modules/adios2_parameters_mod.f90 +++ b/bindings/Fortran/modules/adios2_parameters_mod.f90 @@ -127,4 +127,11 @@ module adios2_parameters_mod character(len=64):: type = '' end type + type adios2_namestruct + integer(kind=8):: f2c = 0_8 + logical :: valid = .false. + integer :: count + integer :: max_name_len + end type + end module diff --git a/testing/adios2/bindings/fortran/TestBPWriteReadAttributes.F90 b/testing/adios2/bindings/fortran/TestBPWriteReadAttributes.F90 index dcf0daf18d..6209c60f0b 100644 --- a/testing/adios2/bindings/fortran/TestBPWriteReadAttributes.F90 +++ b/testing/adios2/bindings/fortran/TestBPWriteReadAttributes.F90 @@ -27,8 +27,9 @@ program TestBPWriteAttributes real, dimension(3) :: r32_array real(kind=8), dimension(3):: r64_array - character(len=:), dimension(:), allocatable :: attrnamelist - integer :: nattrs + type(adios2_namestruct) :: namestruct + character(len=4096), dimension(:), allocatable :: attrnamelist + ! Launch MPI call MPI_Init(ierr) @@ -109,15 +110,27 @@ program TestBPWriteAttributes call adios2_open(bpReader, ioRead, 'fattr_types.bp', adios2_mode_read, ierr) - call adios2_available_attributes(ioRead, nattrs, attrnamelist, ierr) - if (ierr /= 0) stop 'adios2_available_variables returned with error' - write(*,*) 'Number of attributes = ', nattrs - if (nattrs /= 14) stop 'adios2_available_attributes returned not the expected 14' - do i=1,nattrs - write(*,'("Var[",i2,"] = ",a20)') i, attrnamelist(i) + + ! Test getting list of attribute names + call adios2_available_attributes(ioRead, namestruct, ierr) + if (ierr /= 0) stop 'adios2_available_attributes returned with error' + if (.not.namestruct%valid) stop 'adios2_available_attributes returned invalid struct' + write(*,*) 'Number of attributes = ', namestruct%count + write(*,*) 'Max name length = ', namestruct%max_name_len + if (namestruct%count /= 14) stop 'adios2_available_attributes returned not the expected 14' + + allocate(attrnamelist(namestruct%count)) + + call adios2_retrieve_names(namestruct, attrnamelist, ierr) + if (ierr /= 0) stop 'adios2_retrieve_names returned with error' + do i=1,namestruct%count + write(*,'("Attr[",i2,"] = ",a20)') i, attrnamelist(i) end do deallocate(attrnamelist) + if (namestruct%f2c /= 0_8) stop 'namestruct f2c pointer is not null after adios2_retrieve_names()' + if (namestruct%valid) stop 'namestruct is not invalidated after adios2_retrieve_names()' + call adios2_inquire_attribute(attributes_in(1), ioRead, 'att_String', ierr) call adios2_inquire_attribute(attributes_in(2), ioRead, 'att_i8', ierr) diff --git a/testing/adios2/bindings/fortran/TestBPWriteTypes.F90 b/testing/adios2/bindings/fortran/TestBPWriteTypes.F90 index 492e3d8a17..c6d93b58f9 100644 --- a/testing/adios2/bindings/fortran/TestBPWriteTypes.F90 +++ b/testing/adios2/bindings/fortran/TestBPWriteTypes.F90 @@ -26,7 +26,8 @@ program TestBPWriteTypes integer(kind=4) :: ndims integer(kind=8), dimension(:), allocatable :: shape_in - character(len=:), dimension(:), allocatable :: varnamelist + character(len=4096), dimension(:), allocatable :: varnamelist + type(adios2_namestruct) :: namestruct integer :: nvars #if ADIOS2_USE_MPI @@ -235,15 +236,25 @@ program TestBPWriteTypes call adios2_steps(nsteps, bpReader, ierr) if(nsteps /= 3) stop 'ftypes.bp must have 3 steps' - call adios2_available_variables(ioRead, nvars, varnamelist, ierr) + call adios2_available_variables(ioRead, namestruct, ierr) if (ierr /= 0) stop 'adios2_available_variables returned with error' - write(*,*) 'Number of variables = ', nvars - if (nvars /= 14) stop 'adios2_available_variables returned not the expected 14' - do i=1,nvars + if (.not.namestruct%valid) stop 'adios2_available_variables returned invalid struct' + write(*,*) 'Number of variables = ', namestruct%count + write(*,*) 'Max name length = ', namestruct%max_name_len + if (namestruct%count /= 14) stop 'adios2_available_variables returned not the expected 14' + + allocate(varnamelist(namestruct%count)) + + call adios2_retrieve_names(namestruct, varnamelist, ierr) + if (ierr /= 0) stop 'adios2_retrieve_names returned with error' + do i=1,namestruct%count write(*,'("Var[",i2,"] = ",a12)') i, varnamelist(i) end do deallocate(varnamelist) + if (namestruct%f2c /= 0_8) stop 'namestruct f2c pointer is not null after adios2_retrieve_names()' + if (namestruct%valid) stop 'namestruct is not invalidated after adios2_retrieve_names()' + call adios2_inquire_variable(variables(1), ioRead, "var_I8", ierr) if (variables(1)%name /= 'var_I8') stop 'var_I8 not recognized' From a22885b5ed9bcd4b0a5bc869e6718026ba3dac5d Mon Sep 17 00:00:00 2001 From: Norbert Podhorszki Date: Fri, 10 Sep 2021 09:43:30 -0400 Subject: [PATCH 2/4] remove unused variable --- testing/adios2/bindings/fortran/TestBPWriteTypes.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/testing/adios2/bindings/fortran/TestBPWriteTypes.F90 b/testing/adios2/bindings/fortran/TestBPWriteTypes.F90 index c6d93b58f9..4187762225 100644 --- a/testing/adios2/bindings/fortran/TestBPWriteTypes.F90 +++ b/testing/adios2/bindings/fortran/TestBPWriteTypes.F90 @@ -28,7 +28,6 @@ program TestBPWriteTypes character(len=4096), dimension(:), allocatable :: varnamelist type(adios2_namestruct) :: namestruct - integer :: nvars #if ADIOS2_USE_MPI ! Launch MPI From 9e17a7627c8f23d0f260cb7aef5d2f114c85689b Mon Sep 17 00:00:00 2001 From: Norbert Podhorszki Date: Fri, 10 Sep 2021 09:58:56 -0400 Subject: [PATCH 3/4] declare missing externals --- bindings/Fortran/modules/adios2_io_mod.f90 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bindings/Fortran/modules/adios2_io_mod.f90 b/bindings/Fortran/modules/adios2_io_mod.f90 index 0d234e1700..8ace5f8835 100644 --- a/bindings/Fortran/modules/adios2_io_mod.f90 +++ b/bindings/Fortran/modules/adios2_io_mod.f90 @@ -24,6 +24,9 @@ module adios2_io_mod external adios2_get_parameter_f2c external adios2_get_parameter_length_f2c external adios2_in_config_file_f2c + external adios2_available_variables_f2c + external adios2_available_attributes_f2c + external adios2_retrieve_namelist_f2c external adios2_inquire_attribute_f2c external adios2_inquire_variable_f2c external adios2_io_engine_type_f2c From 7c9f87fd2baf2092480f203a7444e22861a6d1e5 Mon Sep 17 00:00:00 2001 From: Norbert Podhorszki Date: Fri, 10 Sep 2021 11:22:04 -0400 Subject: [PATCH 4/4] use older funcparserlib 0.3.6 or older --- docs/environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/environment.yml b/docs/environment.yml index 1143ed4720..0c0c43fd46 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -9,6 +9,7 @@ dependencies: - adios2-openmpi - sphinx - breathe=4.18.1 + - funcparserlib>=0.3.6 - pip - pip: - blockdiag>=1.5.4