Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add netcdf debugging utilities #550

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ else()
src/offline/spincasacnp.F90
src/util/cable_climate_type_mod.F90
src/util/masks_cbl.F90
src/util/netcdf_utils.F90
)

target_link_libraries(cable_common PRIVATE PkgConfig::NETCDF)
Expand Down
207 changes: 207 additions & 0 deletions src/util/netcdf_utils.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
! CSIRO Open Source Software License Agreement (variation of the BSD / MIT License)
! Copyright (c) 2015, Commonwealth Scientific and Industrial Research Organisation
! (CSIRO) ABN 41 687 119 230.

MODULE netcdf_utils
!! Module for common NetCDF utility procedures.
USE netcdf
USE iso_fortran_env, ONLY: int32, real32, real64

IMPLICIT NONE

PRIVATE

PUBLIC :: to_netcdf

INTERFACE to_netcdf
!* Overloads for the `to_netcdf` subroutine.
!
! Usage:
! ```fortran
! CALL to_netcdf("data.nc", values)
! ```
! where `values` is an array and its type is supported by the following overloads.
!
! **WARNING:** this subroutine should **not** be used to write standard
! CABLE outputs as the resulting NetCDF files do not include the required
! metadata. This subroutine is to be used for debugging purposes only. New
! outputs for the CABLE model should be implemented in cable_output.F90.
MODULE PROCEDURE to_netcdf_int32_1d, to_netcdf_int32_2d, to_netcdf_int32_3d
MODULE PROCEDURE to_netcdf_real32_1d, to_netcdf_real32_2d, to_netcdf_real32_3d
MODULE PROCEDURE to_netcdf_real64_1d, to_netcdf_real64_2d, to_netcdf_real64_3d
END INTERFACE to_netcdf

CONTAINS

SUBROUTINE check(status)
!! Check NetCDF error status.
INTEGER, INTENT(IN) :: status !! Error status
IF (status /= NF90_NOERR) THEN
PRINT *, trim(nf90_strerror(status))
STOP
END IF
END SUBROUTINE check

SUBROUTINE to_netcdf_int32_1d(filename, values)
!* Dump values to NetCDF file.
! Any existing dataset with the same filename will be overwritten.
CHARACTER (len=*), INTENT(IN) :: filename
INTEGER (kind=int32), DIMENSION(:), INTENT(IN) :: values
INTEGER :: ncid, varid, dimids(1), i
CHARACTER (len=2) :: dimc
CALL check( nf90_create(filename, NF90_CLOBBER, ncid) )
DO i = 1, size(shape(values))
WRITE (dimc, "(I2.2)") i
CALL check( nf90_def_dim(ncid, "dim" // dimc, size(values, i), dimids(i)) )
END DO
CALL check( nf90_def_var(ncid, "values", NF90_INT, dimids, varid) )
CALL check( nf90_enddef(ncid) )
CALL check( nf90_put_var(ncid, varid, values) )
CALL check( nf90_close(ncid) )
END SUBROUTINE to_netcdf_int32_1d

SUBROUTINE to_netcdf_int32_2d(filename, values)
!* Dump values to NetCDF file.
! Any existing dataset with the same filename will be overwritten.
CHARACTER (len=*), INTENT(IN) :: filename
INTEGER (kind=int32), DIMENSION(:,:), INTENT(IN) :: values
INTEGER :: ncid, varid, dimids(2), i
CHARACTER (len=2) :: dimc
CALL check( nf90_create(filename, NF90_CLOBBER, ncid) )
DO i = 1, size(shape(values))
WRITE (dimc, "(I2.2)") i
CALL check( nf90_def_dim(ncid, "dim" // dimc, size(values, i), dimids(i)) )
END DO
CALL check( nf90_def_var(ncid, "values", NF90_INT, dimids, varid) )
CALL check( nf90_enddef(ncid) )
CALL check( nf90_put_var(ncid, varid, values) )
CALL check( nf90_close(ncid) )
END SUBROUTINE to_netcdf_int32_2d

SUBROUTINE to_netcdf_int32_3d(filename, values)
!* Dump values to NetCDF file.
! Any existing dataset with the same filename will be overwritten.
CHARACTER (len=*), INTENT(IN) :: filename
INTEGER (kind=int32), DIMENSION(:,:,:), INTENT(IN) :: values
INTEGER :: ncid, varid, dimids(3), i
CHARACTER (len=2) :: dimc
CALL check( nf90_create(filename, NF90_CLOBBER, ncid) )
DO i = 1, size(shape(values))
WRITE (dimc, "(I2.2)") i
CALL check( nf90_def_dim(ncid, "dim" // dimc, size(values, i), dimids(i)) )
END DO
CALL check( nf90_def_var(ncid, "values", NF90_INT, dimids, varid) )
CALL check( nf90_enddef(ncid) )
CALL check( nf90_put_var(ncid, varid, values) )
CALL check( nf90_close(ncid) )
END SUBROUTINE to_netcdf_int32_3d

SUBROUTINE to_netcdf_real32_1d(filename, values)
!* Dump values to NetCDF file.
! Any existing dataset with the same filename will be overwritten.
CHARACTER (len=*), INTENT(IN) :: filename
REAL (kind=real32), DIMENSION(:), INTENT(IN) :: values
INTEGER :: ncid, varid, dimids(1), i
CHARACTER (len=2) :: dimc
CALL check( nf90_create(filename, NF90_CLOBBER, ncid) )
DO i = 1, size(shape(values))
WRITE (dimc, "(I2.2)") i
CALL check( nf90_def_dim(ncid, "dim" // dimc, size(values, i), dimids(i)) )
END DO
CALL check( nf90_def_var(ncid, "values", NF90_FLOAT, dimids, varid) )
CALL check( nf90_enddef(ncid) )
CALL check( nf90_put_var(ncid, varid, values) )
CALL check( nf90_close(ncid) )
END SUBROUTINE to_netcdf_real32_1d

SUBROUTINE to_netcdf_real32_2d(filename, values)
!* Dump values to NetCDF file.
! Any existing dataset with the same filename will be overwritten.
CHARACTER (len=*), INTENT(IN) :: filename
REAL (kind=real32), DIMENSION(:,:), INTENT(IN) :: values
INTEGER :: ncid, varid, dimids(2), i
CHARACTER (len=2) :: dimc
CALL check( nf90_create(filename, NF90_CLOBBER, ncid) )
DO i = 1, size(shape(values))
WRITE (dimc, "(I2.2)") i
CALL check( nf90_def_dim(ncid, "dim" // dimc, size(values, i), dimids(i)) )
END DO
CALL check( nf90_def_var(ncid, "values", NF90_FLOAT, dimids, varid) )
CALL check( nf90_enddef(ncid) )
CALL check( nf90_put_var(ncid, varid, values) )
CALL check( nf90_close(ncid) )
END SUBROUTINE to_netcdf_real32_2d

SUBROUTINE to_netcdf_real32_3d(filename, values)
!* Dump values to NetCDF file.
! Any existing dataset with the same filename will be overwritten.
CHARACTER (len=*), INTENT(IN) :: filename
REAL (kind=real32), DIMENSION(:,:,:), INTENT(IN) :: values
INTEGER :: ncid, varid, dimids(3), i
CHARACTER (len=2) :: dimc
CALL check( nf90_create(filename, NF90_CLOBBER, ncid) )
DO i = 1, size(shape(values))
WRITE (dimc, "(I2.2)") i
CALL check( nf90_def_dim(ncid, "dim" // dimc, size(values, i), dimids(i)) )
END DO
CALL check( nf90_def_var(ncid, "values", NF90_FLOAT, dimids, varid) )
CALL check( nf90_enddef(ncid) )
CALL check( nf90_put_var(ncid, varid, values) )
CALL check( nf90_close(ncid) )
END SUBROUTINE to_netcdf_real32_3d

SUBROUTINE to_netcdf_real64_1d(filename, values)
!* Dump values to NetCDF file.
! Any existing dataset with the same filename will be overwritten.
CHARACTER (len=*), INTENT(IN) :: filename
REAL (kind=real64), DIMENSION(:), INTENT(IN) :: values
INTEGER :: ncid, varid, dimids(1), i
CHARACTER (len=2) :: dimc
CALL check( nf90_create(filename, NF90_CLOBBER, ncid) )
DO i = 1, size(shape(values))
WRITE (dimc, "(I2.2)") i
CALL check( nf90_def_dim(ncid, "dim" // dimc, size(values, i), dimids(i)) )
END DO
CALL check( nf90_def_var(ncid, "values", NF90_DOUBLE, dimids, varid) )
CALL check( nf90_enddef(ncid) )
CALL check( nf90_put_var(ncid, varid, values) )
CALL check( nf90_close(ncid) )
END SUBROUTINE to_netcdf_real64_1d

SUBROUTINE to_netcdf_real64_2d(filename, values)
!* Dump values to NetCDF file.
! Any existing dataset with the same filename will be overwritten.
CHARACTER (len=*), INTENT(IN) :: filename
REAL (kind=real64), DIMENSION(:,:), INTENT(IN) :: values
INTEGER :: ncid, varid, dimids(2), i
CHARACTER (len=2) :: dimc
CALL check( nf90_create(filename, NF90_CLOBBER, ncid) )
DO i = 1, size(shape(values))
WRITE (dimc, "(I2.2)") i
CALL check( nf90_def_dim(ncid, "dim" // dimc, size(values, i), dimids(i)) )
END DO
CALL check( nf90_def_var(ncid, "values", NF90_DOUBLE, dimids, varid) )
CALL check( nf90_enddef(ncid) )
CALL check( nf90_put_var(ncid, varid, values) )
CALL check( nf90_close(ncid) )
END SUBROUTINE to_netcdf_real64_2d

SUBROUTINE to_netcdf_real64_3d(filename, values)
!* Dump values to NetCDF file.
! Any existing dataset with the same filename will be overwritten.
CHARACTER (len=*), INTENT(IN) :: filename
REAL (kind=real64), DIMENSION(:,:,:), INTENT(IN) :: values
INTEGER :: ncid, varid, dimids(3), i
CHARACTER (len=2) :: dimc
CALL check( nf90_create(filename, NF90_CLOBBER, ncid) )
DO i = 1, size(shape(values))
WRITE (dimc, "(I2.2)") i
CALL check( nf90_def_dim(ncid, "dim" // dimc, size(values, i), dimids(i)) )
END DO
CALL check( nf90_def_var(ncid, "values", NF90_DOUBLE, dimids, varid) )
CALL check( nf90_enddef(ncid) )
CALL check( nf90_put_var(ncid, varid, values) )
CALL check( nf90_close(ncid) )
END SUBROUTINE to_netcdf_real64_3d

END MODULE netcdf_utils