3
votes

I'm trying to write a time variable from a hydrodynamic model into a netcdf file (unlimited dimension variable). I've attached a simplified code example in Fortran90 that highlights my issue.

The subroutine to write the netcdf file is called multiple times during a simulation depending on a user specified output interval (10 times for this example). I can create the file and add attributes for the first time the subroutine is called.

I can't get the start and count variables correct to write the time variable to the file during the subsequent calls of the subroutine. This is the error, at the writing the model time variable, I receive when trying to compile the code: Error: There is no specific function for the generic 'nf90_put_var'

PROGRAM test_netcdf

  IMPLICIT NONE

  INTEGER :: N
  REAL :: time_step = 2.

  ! Call efdc_netcdf 10 times
  DO N=1,10

     CALL efdc_netcdf(N, time_step)

     time_step=time_step + 1.

  ENDDO

END PROGRAM test_netcdf

************************************
! Create NetCDF file and write variables
SUBROUTINE efdc_netcdf(N, time_step)

USE netcdf
IMPLICIT NONE

LOGICAL,SAVE::FIRST_NETCDF=.FALSE.
CHARACTER (len = *), PARAMETER :: FILE_NAME = "efdc_test.nc"
INTEGER :: ncid, status
INTEGER :: time_dimid
INTEGER :: ts_varid, time_varid

INTEGER :: start(1), count(1)
INTEGER :: deltat

INTEGER :: N
REAL :: time_step

start=(/N/)
count=(/1/)

! Create file and add attributes during first call of efdc_netcdf
IF(.NOT.FIRST_NETCDF)THEN

    status=nf90_create(FILE_NAME, NF90_CLOBBER, ncid)

    ! Define global attributes once
    status=nf90_put_att(ncid, NF90_GLOBAL, 'format', 'netCDF-3 64bit offset file')
    status=nf90_put_att(ncid, NF90_GLOBAL, 'os', 'Linux')
    status=nf90_put_att(ncid, NF90_GLOBAL, 'arch', 'x86_64')

    ! Define deltat variable
    status=nf90_def_var(ncid,'deltat',nf90_int,ts_varid)

    ! Define model time dimension
    status=nf90_def_dim(ncid,'efdc_time',nf90_unlimited,time_dimid)

    ! Define model time variable
    status=nf90_def_var(ncid,'efdc_time',nf90_real,time_dimid,time_varid)

    status=nf90_enddef(ncid)

    ! Put deltat during first call
    deltat=7
    status=nf90_put_var(ncid, ts_varid, deltat)

    FIRST_NETCDF=.TRUE.

ENDIF

! Put model time variable
status=nf90_put_var(ncid, time_varid, time_step, start=start, count=count)

! Close file at end of DO loop
IF(N.EQ.10) THEN
   status=nf90_close(ncid)
ENDIF

RETURN
END SUBROUTINE efdc_netcdf
1
Scratch that earlier comment. The count argument to nf90_put_var doesn't make any sense with a scalar argument (like a single real). Omitting that, your program otherwise works as written here (gfortran, netcdf 4.1.3 and 4.2.1).Jonathan Dursi
I will try to omit the count as well but when I added DIMENSION(1) to both REAL variable declarations, the code worked.Chris

1 Answers

3
votes

The issue is in the line the compiler flags:

status=nf90_put_var(ncid, time_varid, time_step, start=start, count=count)

You are (correctly) trying to write a scalar variable, time_step, into a specific index (start) along variable time_varid, which is defined on a 1-d, infinite-extent dimension. However, in this case, the optional argument count isn't meaningful; you are writing the scalar, and count can only ever be 1. As a result, the fortran bindings for a nf90_put_var() taking a single scalar for input don't have the optional argument defined for count, and that's why you're getting the "no specific function for the generic' nf90_put_var" error from the compiler. This is all perfectly reasonable, but neither the error message nor the docs are super helpful in figuring out how to solve the problem.

You can fix your code by putting the time_step data into a real, dimension(1) variable, and putting that, instead; but easiest is to just get rid of the count specification, which isn't necessary here anyway:

status=nf90_put_var(ncid, time_varid, time_step, start=start)