netcdf_utils.F90 Source File


Source Code

! 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