Skip to content

Commit

Permalink
Merge pull request #5 from PlasmaFAIR/bugfix/type-of-zero-length-arrays
Browse files Browse the repository at this point in the history
Error on creating fixed zero-length dimensions
  • Loading branch information
ZedThree authored Apr 3, 2023
2 parents afb2b2f + a5ed2bd commit 5a7b585
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 26 deletions.
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ neasy-f, then disable source generation with NEASYF_GENERATE_SOURCE=off.")
)
endif()

# Add some extra flags when compiling in debug mode
target_compile_options(neasyf PRIVATE
$<$<CONFIG:Debug>:
$<$<Fortran_COMPILER_ID:GNU>:
-g -Wall -fimplicit-none -fbounds-check >
$<$<Fortran_COMPILER_ID:Intel>:
-g -implicitnone -warn all -nogen-interfaces -CB -traceback >
>
)

##################################################
# Dependencies

Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ netCDF4 files, and so requires netCDF to have been built with HDF5.

Tested with gfortran 11 and netCDF-Fortran 4.5.3.

Known Issues
------------

- gfortran has a bug when passing slices of arrays of derived types:
trying to write `some_array%member` will result in the wrong values
getting written. To workaround this, copy `some_array%member` into a
temporary variable and pass that to `neasyf_write`

- Creating fixed zero-length variables or dimensions is not possible,
as netCDF uses `size = 0` to represent unlimited dimensions

Compilation
-----------

Expand Down
27 changes: 14 additions & 13 deletions src/neasyf.f90
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,7 @@ subroutine neasyf_dim(parent_id, name, values, dim_size, dimid, varid, units, lo
!> NetCDF ID of the parent group/file
integer, intent(in) :: parent_id
!> Coordinate values
class(*), dimension(:), optional, intent(in) :: values
class(*), dimension(:), optional, target, intent(in) :: values
!> Size of the dimension if values isn't specified
integer, optional, intent(in) :: dim_size
!> NetCDF ID of the dimension
Expand All @@ -777,12 +777,11 @@ subroutine neasyf_dim(parent_id, name, values, dim_size, dimid, varid, units, lo
!> Is this dimension unlimited?
logical, optional, intent(in) :: unlimited

integer(nf_kind) :: nf_type
integer :: status
integer(nf_kind) :: dim_id, var_id
integer :: i
integer :: local_size
integer, dimension(:), allocatable :: local_values
class(*), dimension(:), pointer :: local_values
logical :: local_unlimited

if (present(values) .and. present(dim_size)) then
Expand Down Expand Up @@ -821,12 +820,10 @@ subroutine neasyf_dim(parent_id, name, values, dim_size, dimid, varid, units, lo
! initial size of the dimension
if (present(values)) then
local_size = size(values)
nf_type = neasyf_type(values)
! TODO: check if nf_type indicates a derived type
local_values => values
else if (present(dim_size)) then
local_size = dim_size
local_values = [(i, i=1, dim_size)]
nf_type = neasyf_type(local_values)
allocate(local_values, source=[(i, i=1, dim_size)])
end if

! Setting the dimension to be unlimited overrides the size
Expand All @@ -842,6 +839,11 @@ subroutine neasyf_dim(parent_id, name, values, dim_size, dimid, varid, units, lo
&Either pass one of 'values' or 'dim_size', or set 'unlimited=.true.'"
end if

if (local_size == 0 .and. .not. local_unlimited) then
error stop "neasyf_dim: Dimension does not exist, and initial size is 0. &
&If you're trying to create an unlimited dimension, pass 'unlimited=.true.' instead"
end if

status = nf90_def_dim(parent_id, name, local_size, dim_id)
call neasyf_error(status, dim=name, dimid=dim_id, message="creating dimension")

Expand All @@ -858,16 +860,15 @@ subroutine neasyf_dim(parent_id, name, values, dim_size, dimid, varid, units, lo
return
end if

! We could avoid the duplicated call here by copying the values into an allocatable class(*)
if (present(values)) then
call neasyf_write(parent_id, name, values, dim_ids=[dim_id], units=units, long_name=long_name, varid=var_id)
else
call neasyf_write(parent_id, name, local_values, dim_ids=[dim_id], units=units, long_name=long_name, varid=var_id)
end if
call neasyf_write(parent_id, name, local_values, dim_ids=[dim_id], units=units, long_name=long_name, varid=var_id)

if (present(varid)) then
varid = var_id
end if

! If we allocated local_values, best free the memory. Note that
! `allocated(local_values)` doesn't work here, because Fortran.
if (.not. present(values) .and. present(dim_size)) deallocate(local_values)
end subroutine neasyf_dim

subroutine neasyf_write_scalar(parent_id, name, values, dim_ids, dim_names, units, long_name, start)
Expand Down
27 changes: 14 additions & 13 deletions src/neasyf.in.f90
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ subroutine neasyf_dim(parent_id, name, values, dim_size, dimid, varid, units, lo
!> NetCDF ID of the parent group/file
integer, intent(in) :: parent_id
!> Coordinate values
class(*), dimension(:), optional, intent(in) :: values
class(*), dimension(:), optional, target, intent(in) :: values
!> Size of the dimension if values isn't specified
integer, optional, intent(in) :: dim_size
!> NetCDF ID of the dimension
Expand All @@ -337,12 +337,11 @@ subroutine neasyf_dim(parent_id, name, values, dim_size, dimid, varid, units, lo
!> Is this dimension unlimited?
logical, optional, intent(in) :: unlimited

integer(nf_kind) :: nf_type
integer :: status
integer(nf_kind) :: dim_id, var_id
integer :: i
integer :: local_size
integer, dimension(:), allocatable :: local_values
class(*), dimension(:), pointer :: local_values
logical :: local_unlimited

if (present(values) .and. present(dim_size)) then
Expand Down Expand Up @@ -381,12 +380,10 @@ subroutine neasyf_dim(parent_id, name, values, dim_size, dimid, varid, units, lo
! initial size of the dimension
if (present(values)) then
local_size = size(values)
nf_type = neasyf_type(values)
! TODO: check if nf_type indicates a derived type
local_values => values
else if (present(dim_size)) then
local_size = dim_size
local_values = [(i, i=1, dim_size)]
nf_type = neasyf_type(local_values)
allocate(local_values, source=[(i, i=1, dim_size)])
end if

! Setting the dimension to be unlimited overrides the size
Expand All @@ -402,6 +399,11 @@ subroutine neasyf_dim(parent_id, name, values, dim_size, dimid, varid, units, lo
&Either pass one of 'values' or 'dim_size', or set 'unlimited=.true.'"
end if

if (local_size == 0 .and. .not. local_unlimited) then
error stop "neasyf_dim: Dimension does not exist, and initial size is 0. &
&If you're trying to create an unlimited dimension, pass 'unlimited=.true.' instead"
end if

status = nf90_def_dim(parent_id, name, local_size, dim_id)
call neasyf_error(status, dim=name, dimid=dim_id, message="creating dimension")

Expand All @@ -418,16 +420,15 @@ subroutine neasyf_dim(parent_id, name, values, dim_size, dimid, varid, units, lo
return
end if

! We could avoid the duplicated call here by copying the values into an allocatable class(*)
if (present(values)) then
call neasyf_write(parent_id, name, values, dim_ids=[dim_id], units=units, long_name=long_name, varid=var_id)
else
call neasyf_write(parent_id, name, local_values, dim_ids=[dim_id], units=units, long_name=long_name, varid=var_id)
end if
call neasyf_write(parent_id, name, local_values, dim_ids=[dim_id], units=units, long_name=long_name, varid=var_id)

if (present(varid)) then
varid = var_id
end if

! If we allocated local_values, best free the memory. Note that
! `allocated(local_values)` doesn't work here, because Fortran.
if (.not. present(values) .and. present(dim_size)) deallocate(local_values)
end subroutine neasyf_dim

subroutine neasyf_write_scalar(parent_id, name, values, dim_ids, dim_names, units, long_name, start)
Expand Down

0 comments on commit 5a7b585

Please sign in to comment.