[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[netCDF #NUC-119714]: struggling with writing data to nc file



Hi Laurens,

> I hope that you are actually working at the moment and not affected by
> the government shutdown; I am already struggling now for some weeks with
> a simple script to read and write data to netcdf in a F77 model code. I
> am able to read-in and then write some manipulated data in F90 version
> but the F77 version gives problems with the writing; I have copied below
> the F90 version of the write_nc routine I used and that works with my
> installation of the netcdf software (3.6.2) on my Suse11.2 linux system. I
> have also copied a version of the F77 subroutine that doesn't work;
> I am basically looking for the F77 equivalent of some of the calls of
> the various nc functions where the help page has helped a lot but not to
> solve this remaining problem. Your feedback would be highly appreciated,

I see a bug in your F90 write_nc that may be a source of the problem:
you should not be using the same variable, tid, for both the dimension
ID of the time dimension and the variable ID of the time variable.
These are two different objects, and may have two different IDs.  Or
they may have the same ID in the F90 version, by coincidence, but have
different values in your F77 program.

You specify a netCDF coordinate variable by giving it the same name as
a dimension, but that's just a convention, and does not have any
effect on what ID is assigned to the variable.  Dimension IDs are just
assigned in the order dimensions are defined, and similarly for
variables.  So if the first dimension defined has the name "time", but
the corresponding "time" variable is the third variable defined, then
the "time" dimension will have dimension ID 1, but the time variable
will have variable ID 3.  This is the way it works in both the F90 and
F77 netCDF APIs.

There is also a problem with the call to NF_PUT_VAR_DOUBLE(), which
can only be used to write *all* the values of a variable.  If instead
you only want to write the values for a single time step, as in the
F90 subroutine, you will need to instead use the function
NF_PUT_VARA_DOUBLE(), for which you need to specify START and COUNT
arguments, as in:

  NF_PUT_VARA_DOUBLE(INTEGER NCID, INTEGER VARID, INTEGER START(*), INTEGER 
COUNT(*), DOUBLE DVALS(*))

> Thanks, Laurens Ganzeveld
> 
> F90:
> 
> The subroutine is called in a timeloop over 12 months writing out the
> global emission field (emis3D), at a resolution of 1x1 degree for each
> month to a new netcdf file:
> 
> SUBROUTINE write_nc_file
> 
> ! write timestep
> CALL nf(nf90_inquire_dimension(ncid, tid, len=timestep))
> timestep = timestep + 1
> 
> print *,'write_nc: timestepping ',timestep
> read (*,*)
> 
> CALL nf(nf90_put_var(ncid, tid, time, (/timestep/) ))

For the above, use the varid for the time variable instead of tid.

> ! syntax: nf90_put_var(ncid, varid, values, start, cnt)
> ! start: start in netcdf variable
> ! cnt: number of netcdf variable points
> ! values: starting point of the fortran variable
> start1d = (/ 1, timestep /)
> start2d = (/ 1, 1, timestep /)
> start3d = (/ 1, 1, 1, timestep /)
> 
> CALL nf(nf90_put_var(ncid, emis3Did, emis3D, start3d, cnt3d)) ! emis.
> 
> END SUBROUTINE write_nc_file
> 
> 
> F77:
> Ncid, tid, emisid are all properly defined as well as the parameter emis
> 
> SUBROUTINE write_nc_file(ii,time,ncid,tid,emisid,emis)
> 
> integer :: ii,timestep,status,ncid,tid,dimtid,timelen,nrecs,
> & emisid,start2d(3),cnt2d(3),j,k
> real :: time,emis(180,360)
> 
> character*(20) recnam
> 
> ! write timestep
> timestep = ii
> print *,'timestep',timestep,time
> 
> CALL nf(nf_put_var_double(ncid, tid, time, (/timestep/) ))
> read (*,*)

There are 3 things wrong with that call to nf_put_var_double: it uses
a dimension id instead of a variable id, it has too many arguments,
and even if the extra last argument is omitted, it writes too many
values.

That call writes *all* the values of the time variable, not just the
one value for the current timestep.  So if time is the unlimited
dimension (i.e. record dimension), and it currently has length 10,
then that nf_put_var_double() call tries to write time(1), time(2),
..., time(10).

Note this warning in the documentation:

   Take care when using the simplest forms of this interface with
   record variables (variables that use the NF_UNLIMITED dimension)
   when you don't specify how many records are to be written. If you
   try to write all the values of a record variable into a netCDF file
   that has no record data yet (hence has 0 records), nothing will be
   written. Similarly, if you try to write all the values of a record
   variable from an array but there are more records in the file than
   you assume, more in-memory data will be accessed than you expect,
   which may cause a segmentation violation. To avoid such problems,
   it is better to use the NF_PUT_VARA_type interfaces for variables
   that use the NF_UNLIMITED dimension. See NF_PUT_VARA_ type.

So you probably instead want to use something like:

  CALL nf(nf_put_vara_double(ncid, tvarid, (/ ii /) , (/ 1 /), time(timestep) ))

to write the one value, time(timestep), as the new value of the time
variable.

> ! syntax: nf90_put_var(ncid, varid, values, start, cnt)
> ! start: start in netcdf variable
> ! cnt: number of netcdf variable points
> ! values: starting point of the fortran variable
> start2d = (/ 1, 1, timestep /)
> cnt2d = (/ 180, 360, 1 /)
> 
> ! write 2d data
> 
> CALL nf(nf_put_var_real(ncid, emisid, emis, start2d, cnt2d)) ! emis .

Here, you also want to follow the documentation for the order of
arguments and use the nf_put_vara_real() function instead, something
like:

  CALL nf_put_vara_real(ncid, emisid, start2d, cnt2d, emis)

assuming "emis" is a 2D variable of the new emissivities.

--Russ

Russ Rew                                         UCAR Unidata Program
address@hidden                      http://www.unidata.ucar.edu



Ticket Details
===================
Ticket ID: NUC-119714
Department: Support netCDF
Priority: Normal
Status: Closed