Unidata - To provide the data services, tools, and cyberinfrastructure leadership that advance Earth system science, enhance educational opportunities, and broaden participation. Unidata
         
  advanced  
 
[Next] [Previous] [Top] [Contents] [Index] [netCDF Home Page] [Unidata Home Page]

7 Variables


Variables for a netCDF dataset are defined when the dataset is created, while the netCDF dataset is in define mode. Other variables may be added later by reentering define mode. A netCDF variable has a name, a type, and a shape, which are specified when it is defined. A variable may also have values, which are established later in data mode.

Ordinarily, the name, type, and shape are fixed when the variable is first defined. The name may be changed, but the type and shape of a variable cannot be changed. However, a variable defined in terms of the unlimited dimension can grow without bound in that dimension.

A netCDF variable in an open netCDF dataset is referred to by a small integer called a variable ID.

Variable IDs reflect the order in which variables were defined within a netCDF dataset. Variable IDs are 1, 2, 3, ..., in the order in which the variables were defined. A function is available for getting the variable ID from the variable name and vice-versa.

Attributes (see Chapter 8 "Attributes," page 69) may be associated with a variable to specify such properties as units.

Operations supported on variables are:

7.1 Language Types Corresponding to NetCDF External Data Types

The following table gives the netCDF external data types and the corresponding type constants for defining variables in the Fortran 90 interface:

netCDF/CDL Data Type
Fortran 90 API Mnemonic
Bits
byte
NF90_BYTE
8
char
NF90_CHAR
8
short
NF90_SHORT
16
int
NF90_INT
32
float
NF90_FLOAT
32
double
NF90_DOUBLE
64

The first column gives the netCDF external data type, which is the same as the CDL data type. The next column gives the corresponding Fortran 90 parameter for use in netCDF functions (the parameters are defined in the netCDF Fortran 90 module netcdf.f90). The last column gives the number of bits used in the external representation of values of the corresponding type.

Note that there are no netCDF types corresponding to 64-bit integers or to characters wider than 8 bits in the current version of the netCDF library.

7.2 Create a Variable: NF90_DEF_VAR

The function NF90_DEF_VAR adds a new variable to an open netCDF dataset in define mode. It returns (as an argument) a variable ID, given the netCDF ID, the variable name, the variable type, the number of dimensions, and a list of the dimension IDs.

Usage

 function nf90_def_var(ncid, name, xtype, dimids, varid)
   integer,               intent( in) :: ncid
   character (len = *),   intent( in) :: name
   integer,               intent( in) :: xtype
   integer, dimension(:), intent( in) :: dimids
   integer                            :: nf90_def_var
ncid
NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
name
Name for this variable. Must begin with an alphabetic character, which is followed by zero or more alphanumeric characters including the underscore (`_'). Case is significant.
xtype
The external type for this variable, one of the set of predefined netCDF external data types: NF90_BYTE, NF90_CHAR, NF90_SHORT, NF90_INT, NF90_FLOAT, or NF90_DOUBLE.
dimids
Dimension ID(s) corresponding to this variable's dimension(s). If the ID of the unlimited dimension is included, it must be first. Optional argument dimids may be a vector or, if the variable has only one dimension, a scalar; if the argument is omitted the netCDF variable is defined as a scalar.
varid
Returned variable ID

Errors

NF90_DEF_VAR returns the value NF90_NOERR if no errors occurred. Otherwise, the returned status indicates an error. Possible causes of errors include:

Example

Here is an example using NF90_DEF_VAR to create a variable named rh of type double with three dimensions, time, lat, and lon in a new netCDF dataset named foo.nc:

    use netcdf
 implicit none
 integer :: status, ncid
 integer :: LonDimId, LatDimId, TimeDimId
 integer :: RhVarId
 ...
 status = nf90_create("foo.nc", nf90_NoClobber, ncid)
 if(status /= nf90_NoErr) call handle_error(status)
 ...
 ! Define the dimensions
 status = nf90_def_dim(ncid, "lat", 5, LatDimId)
 if(status /= nf90_NoErr) call handle_error(status)
 status = nf90_def_dim(ncid, "lon", 10, LonDimId)
 if(status /= nf90_NoErr) call handle_error(status)
 status = nf90_def_dim(ncid, "time", nf90_unlimited, TimeDimId)
 if(status /= nf90_NoErr) call handle_error(status)
 ...
 ! Define the variable
 status = nf90_def_var(ncid, "rh", nf90_double, &
                       (/ LonDimId, LatDimID, TimeDimID /), RhVarId)
 if(status /= nf90_NoErr) call handle_error(status)

7.3 Get a Variable ID from Its Name: NF90_INQ_VARID

The function NF90_INQ_VARID returns the ID of a netCDF variable, given its name.

Usage

 function nf90_inq_varid(ncid, name, varid)
   integer,             intent( in) :: ncid
   character (len = *), intent( in) :: name
   integer,             intent(out) :: varid
   integer                          :: nf90_inq_varid
ncid
NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
name
Variable name for which ID is desired.
varid
Returned variable ID.

Errors

NF90_INQ_VARID returns the value NF90_NOERR if no errors occurred. Otherwise, the returned status indicates an error. Possible causes of errors include:

Example

Here is an example using NF90_INQ_VARID to find out the ID of a variable named rh in an existing netCDF dataset named foo.nc:

    use netcdf
 implicit none
 integer :: status, ncid, RhVarId
 ...
 status = nf90_open("foo.nc", nf90_NoWrite, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", RhVarId)
 if(status /= nf90_NoErr) call handle_err(status)

7.4 Get Information about a Variable from Its ID: NF90_Inquire_Variable

NF90_Inquire_Variable returns information about a netCDF variable given its ID. Information about a variable includes its name, type, number of dimensions, a list of dimension IDs describing the shape of the variable, and the number of variable attributes that have been assigned to the variable.

Usage

 function nf90_Inquire_Variable(ncid, varid, name, xtype, ndims, dimids, nAtts)
   integer,                         intent( in) :: ncid, varid
   character (len = *),   optional, intent(out) :: name
   integer,               optional, intent(out) :: xtype, ndims 
   integer, dimension(*), optional, intent(out) :: dimids
   integer,               optional, intent(out) :: nAtts
   integer                                      :: nf90_Inquire_Variable
ncid
NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
varid
Variable ID.
name
Returned variable name. The caller must allocate space for the returned name. The maximum possible length, in characters, of a variable name is given by the predefined constant NF90_MAX_NAME.
xtype
Returned external type for this variable, one of the set of predefined netCDF external data types. The valid netCDF external data types are NF90_BYTE, NF90_CHAR, NF90_SHORT, NF90_INT, NF90_FLOAT, and NF90_DOUBLE.
ndims
Returned number of dimensions for this variable. For example, 2 indicates a matrix, 1 indicates a vector, and 0 means the variable is a scalar with no dimensions.
dimids
Returned vector of NDIMS dimension IDs corresponding to the variable dimensions. The caller must allocate enough space for a vector of at least NDIMS integers to be returned. The maximum possible number of dimensions for a variable is given by the predefined constant NF90_MAX_VAR_DIMS.
natts
Returned number of variable attributes assigned to this variable. Note that you can get the number of global attributes by using the NF90_GLOBAL pseudo-variable ID

Errors

Function NF90_Inquire_Variable returns the value NF90_NOERR if no errors occurred. Otherwise, the returned status indicates an error. Possible causes of errors include:

Example

Here is an example using NF90_Inquire_Variable to find out about a variable named rh in an existing netCDF dataset named foo.nc:

    use netcdf
    implicit none
    integer                                :: status, ncid, &
                                           RhVarId       &
                                           numDims, numAtts
 integer, dimension(nf90_max_var_dims) :: rhDimIds
 ...
 status = nf90_open("foo.nc", nf90_NoWrite, ncid)
 if(status /= nf90_NoErr) call handle_error(status)
 ...
 status = nf90_inq_varid(ncid, "rh", RhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_Inquire_Var(ncid, RhVarId, ndims = numDims, natts = numAtts)
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_Inquire_Var(ncid, RhVarId, dimids = rhDimIds(:numDims))
 if(status /= nf90_NoErr) call handle_err(status)

7.5 Writing Data Values: NF90_PUT_VAR

The function NF90_PUT_VAR puts one or more data values into the variable of an open netCDF dataset that is in data mode. Required inputs are the netCDF ID, the variable ID, and one or more data values. Optional inputs may indicate the starting position of the data values in the netCDF variable (argument start), the sampling frequency with which data values are written into the netCDF variable (argument stride), and a mapping between the dimensions of the data array and the netCDF variable (argument map). The values to be written are associated with the netCDF variable by assuming that the first dimension of the netCDF variable varies fastest in the Fortran 90 interface. Data values converted to the external type of the variable, if necessary.

Take care when using the simplest forms of this interface with record variables 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 of a record variable but there are more records in the file than you assume, more data may be written to the file than you supply, which may result in a segmentation violation.

Usage

 function nf90_put_var(ncid, varid, values, start, count, stride, map)
   integer,                         intent( in) :: ncid, varid
   any valid type, scalar or array of any rank, &
                                    intent( in) :: values
   integer, dimension(:), optional, intent( in) :: start, count, stride, map
   integer                                      :: nf90_put_var
ncid
NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
varid
Variable ID.
values
The data value(s) to be written. The data may be of any type, and may be a scalar or an array of any rank.
You cannot put CHARACTER data into a numeric variable or numeric data into a text variable. For numeric data, if the type of data differs from the netCDF variable type, type conversion will occur. See Section 3.3 "Type Conversion," page 24, for details.
start
A vector of integers specifying the index in the variable where the first (or only) of the data values will be written. The indices are relative to 1, so for example, the first data value of a variable would have index (1, 1, ..., 1). The elements of start correspond, in order, to the variable's dimensions. Hence, if the variable is a record variable, the last index would correspond to the starting record number for writing the data values.
By default, start(:) = 1.
count
A vector of integers specifying the number of indices selected along each dimension. To write a single value, for example, specify count as (1, 1, ..., 1). The elements of count correspond, in order, to the variable's dimensions. Hence, if the variable is a record variable, the last element of count corresponds to a count of the number of records to write.
By default, count(:numDims) = shape(values) and
count(numDims + 1:) = 1, where numDims = size(shape(values)).
stride
A vector of integers that specifies the sampling interval along each dimension of the netCDF variable. The elements of the stride vector correspond, in order, to the netCDF variable's dimensions (stride(1) gives the sampling interval along the most rapidly varying dimension of the netCDF variable). Sampling intervals are specified in type-independent units of elements (a value of 1 selects consecutive elements of the netCDF variable along the corresponding dimension, a value of 2 selects every other element, etc.).
By default, stride(:) = 1.
map
A vector of integers that specifies the mapping between the dimensions of a netCDF variable and the in-memory structure of the internal data array. The elements of the index mapping vector correspond, in order, to the netCDF variable's dimensions (map(1) gives the distance between elements of the internal array corresponding to the most rapidly varying dimension of the netCDF variable). Distances between elements are specified in units of elements.
By default, edgeLengths = shape(values), and
map = (/ 1, (product(edgeLengths(:i)), &
i = 1, size(edgeLengths) - 1) /)
,
that is, there is no mapping.
Use of Fortran 90 intrinsic functions (including reshape, transpose, and spread) may let you avoid using this argument.

Errors

NF90_PUT_VAR returns the value NF90_NOERR if no errors occurred. Otherwise, the returned status indicates an error. Possible causes of errors include:

(As noted above, another possible source of error is using this interface to write all the values of a record variable without specifying the number of records. If there are a different number of records in the file than you assume, the amount of data written may be different from what you expect!)

Example

Here is an example using NF90_PUT_VAR to set the (4,3,2) element of the variable named rh to 0.5 in an existing netCDF dataset named foo.nc. For simplicity in this example, we assume that we know that rh is dimensioned with lon, lat, and time, so we want to set the value of rh that corresponds to the fourth lon value, the third lat value, and the second time value:

 use netcdf
 implicit none
 integer :: ncId, rhVarId, status
 ...
 status = nf90_open("foo.nc", nf90_Write, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...ß
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_put_var(ncid, rhVarId, 0.5, start = (/ 4, 3, 2 /) )
 if(status /= nf90_NoErr) call handle_err(status)

In this example we use NF90_PUT_VAR to add or change all the values of the variable named rh to 0.5 in an existing netCDF dataset named foo.nc. We assume that we know that rh is dimensioned with lon, lat, and time. In this example we query the netCDF file to discover the lengths of the dimensions, then use the Fortran 90 intrinsic function reshape to create a temporary array of data values which is the same shape as the netCDF variable.

 use netcdf
 implicit none
 integer                               :: ncId, rhVarId,status,          &
                                          lonDimID, latDimId, timeDimId, &
                                          numLons, numLats, numTimes,    &
                                          i
 integer, dimension(nf90_max_var_dims) :: dimIDs
 ...
 status = nf90_open("foo.nc", nf90_Write, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 ! How big is the netCDF variable, that is, what are the lengths of 
 !   its constituent dimensions? 
 status = nf90_Inquire_Variable(ncid, rhVarId, dimids = dimIDs)
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_Inquire_Dimension(ncid, dimIDs(1), len = numLons)
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_Inquire_Dimension(ncid, dimIDs(2), len = numLats)
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_Inquire_Dimension(ncid, dimIDs(3), len = numTimes)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 ! Make a temporary array the same shape as the netCDF variable. 
 status = nf90_put_var(ncid, rhVarId, &
                       reshape( &
                         (/ (0.5, i = 1, numLons * numLats * numTimes) /) , &
                        shape = (/ numLons, numLats, numTimes /) )
 if(status /= nf90_NoErr) call handle_err(status)

Here is an example using NF90_PUT_VAR to add or change a section of the variable named rh to 0.5 in an existing netCDF dataset named foo.nc. For simplicity in this example, we assume that we know that rh is dimensioned with lon, lat, and time, that there are ten lon values, five lat values, and three time values, and that we want to replace all the values at the last time.

 use netcdf
 implicit none
 integer            :: ncId, rhVarId, status
 integer, parameter :: numLons = 10, numLats = 5, numTimes = 3
 real, dimension(numLons, numLats) &
                    :: rhValues
 ...
 status = nf90_open("foo.nc", nf90_Write, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 ! Fill in all values at the last time
 rhValues(:, :) = 0.5
 status = nf90_put_var(ncid, rhVarId,rhvalues,       &
                       start = (/ 1, 1, numTimes /), &
                       count = (/ numLats, numLons, 1 /))
 if(status /= nf90_NoErr) call handle_err(status)

Here is an example of using NF_PUT_VAR to write every other point of a netCDF variable named rh having dimensions (6, 4).

 use netcdf
 implicit none
 integer            :: ncId, rhVarId, status
 integer, parameter :: numLons = 6, numLats = 4
 real, dimension(numLons, numLats) &
                    :: rhValues = 0.5
 ...
 status = nf90_open("foo.nc", nf90_Write, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 ! Fill in every other value using an array section 
 status = nf90_put_var(ncid, rhVarId, rhValues(::2, ::2), &
                       stride = (/ 2, 2 /))
 if(status /= nf90_NoErr) call handle_err(status)

The following map vector shows the default mapping between a 2x3x4 netCDF variable and an internal array of the same shape:

 real,    dimension(2, 3, 4):: a  ! same shape as netCDF variable
 integer, dimension(3)      :: map  = (/ 1, 2, 6 /) 
                     ! netCDF dimension inter-element distance
                     ! ---------------- ----------------------
                     ! most rapidly varying       1
                     ! intermediate               2 (= map(1)*2)
                     ! most slowly varying        6 (= map(2)*3)

Using the map vector above obtains the same result as simply not passing a map vector at all.

Here is an example of using nf90_put_var to write a netCDF variable named rh whose dimensions are the transpose of the Fortran 90 array:

 use netcdf
 implicit none
 integer                           :: ncId, rhVarId, status
 integer, parameter                :: numLons = 6, numLats = 4
 real, dimension(numLons, numLats) :: rhValues
 ! netCDF variable has dimensions (numLats, numLons)
 ...
 status = nf90_open("foo.nc", nf90_Write, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 !Write transposed values: map vector would be (/ 1, numLats /) for 
 !   no transposition
 status = nf90_put_var(ncid, rhVarId,rhValues, map = (/ numLons, 1 /)) 
 if(status /= nf90_NoErr) call handle_err(status)

The same effect can be obtained more simply using Fortran 90 intrinsic functions:

 use netcdf
 implicit none
 integer                           :: ncId, rhVarId, status
 integer, parameter                :: numLons = 6, numLats = 4
 real, dimension(numLons, numLats) :: rhValues
 ! netCDF variable has dimensions (numLats, numLons)
 ...
 status = nf90_open("foo.nc", nf90_Write, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_put_var(ncid, rhVarId, transpose(rhValues)) 
 if(status /= nf90_NoErr) call handle_err(status)

7.6 Reading Data Values: NF90_GET_VAR

The function NF90_GET_VAR gets one or more data values from a netCDF variable of an open netCDF dataset that is in data mode. Required inputs are the netCDF ID, the variable ID, and a specification for the data values into which the data will be read. Optional inputs may indicate the starting position of the data values in the netCDF variable (argument start), the sampling frequency with which data values are read from the netCDF variable (argument stride), and a mapping between the dimensions of the data array and the netCDF variable (argument map). The values to be read are associated with the netCDF variable by assuming that the first dimension of the netCDF variable varies fastest in the Fortran 90 interface. Data values are converted from the external type of the variable, if necessary.

Take care when using the simplest forms of this interface with record variables when you don't specify how many records are to be read. If you try to read all the values of a record variable into an array but there are more records in the file than you assume, more data will be read than you expect, which may cause a segmentation violation.

Usage

 function nf90_get_var(ncid, varid, values, start, count, stride, map)
   integer,                         intent( in) :: ncid, varid
   any valid type, scalar or array of any rank, &
                                    intent(out) :: values
   integer, dimension(:), optional, intent( in) :: start, count, stride, map
   integer                                      :: nf90_get_var
ncid
NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
varid
Variable ID.
values
The data value(s) to be read. The data may be of any type, and may be a scalar or an array of any rank.
You cannot read CHARACTER data from a numeric variable or numeric data from a text variable. For numeric data, if the type of data differs from the netCDF variable type, type conversion will occur. See Section 3.3 "Type Conversion," page 24, for details.
start
A vector of integers specifying the index in the variable from which the first (or only) of the data values will be read. The indices are relative to 1, so for example, the first data value of a variable would have index (1, 1, ..., 1). The elements of start correspond, in order, to the variable's dimensions. Hence, if the variable is a record variable, the last index would correspond to the starting record number for writing the data values.
By default, start(:) = 1.
count
A vector of integers specifying the number of indices selected along each dimension. To read a single value, for example, specify count as (1, 1, ..., 1). The elements of count correspond, in order, to the variable's dimensions. Hence, if the variable is a record variable, the last element of count corresponds to a count of the number of records to read.
By default, count(:numDims) = shape(values) and
count(numDims + 1:) = 1, where numDims = size(shape(values)).
stride
A vector of integers that specifies the sampling interval along each dimension of the netCDF variable. The elements of the stride vector correspond, in order, to the netCDF variable's dimensions (stride(1) gives the sampling interval along the most rapidly varying dimension of the netCDF variable). Sampling intervals are specified in type-independent units of elements (a value of 1 selects consecutive elements of the netCDF variable along the corresponding dimension, a value of 2 selects every other element, etc.).
By default, stride(:) = 1.
map
A vector of integers that specifies the mapping between the dimensions of a netCDF variable and the in-memory structure of the internal data array. The elements of the index mapping vector correspond, in order, to the netCDF variable's dimensions (map(1) gives the distance between elements of the internal array corresponding to the most rapidly varying dimension of the netCDF variable). Distances between elements are specified in units of elements.
By default, edgeLengths = shape(values), and
map = (/ 1, (product(edgeLengths(:i)), &
i = 1, size(edgeLengths) - 1) /)
,
that is, there is no mapping.
Use of Fortran 90 intrinsic functions (including reshape, transpose, and spread) may let you avoid using this argument.

Errors

NF90_GET_VAR returns the value NF90_NOERR if no errors occurred. Otherwise, the returned status indicates an error. Possible causes of errors include:

(As noted above, another possible source of error is using this interface to read all the values of a record variable without specifying the number of records. If there are more records in the file than you assume, more data will be read than you expect!)

Example

Here is an example using NF90_GET_VAR to read the (4,3,2) element of the variable named rh from an existing netCDF dataset named foo.nc. For simplicity in this example, we assume that we know that rh is dimensioned with lon, lat, and time, so we want to read the value of rh that corresponds to the fourth lon value, the third lat value, and the second time value:

 use netcdf
 implicit none
 integer :: ncId, rhVarId, status
 real    :: rhValue
 ...
 status = nf90_open("foo.nc", nf90_NoWrite, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 -
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_get_var(ncid, rhVarId, rhValue, start = (/ 4, 3, 2 /) )
 if(status /= nf90_NoErr) call handle_err(status)

In this example we use NF90_GET_VAR to read all the values of the variable named rh from an existing netCDF dataset named foo.nc. We assume that we know that rh is dimensioned with lon, lat, and time. In this example we query the netCDF file to discover the lengths of the dimensions, then allocate a Fortran 90 array the same shape as the netCDF variable.

 use netcdf
 implicit none
 integer                               :: ncId, rhVarId, &
                                          lonDimID, latDimId, timeDimId, &
                                          numLons, numLats, numTimes,    &
                                          status
 integer, dimension(nf90_max_var_dims) :: dimIDs
 real, dimension(:, :, :), allocatable :: rhValues
 ...
 status = nf90_open("foo.nc", nf90_NoWrite, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 ! How big is the netCDF variable, that is, what are the lengths of 
 !   its constituent dimensions? 
 status = nf90_Inquire_Variable(ncid, rhVarId, dimids = dimIDs)
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_Inquire_Dimension(ncid, dimIDs(1), len = numLons)
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_Inquire_Dimension(ncid, dimIDs(2), len = numLats)
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_Inquire_Dimension(ncid, dimIDs(3), len = numTimes)
 if(status /= nf90_NoErr) call handle_err(status)
 allocate(rhValues(numLons, numLats, numTimes))
 ...
 status = nf90_get_var(ncid, rhVarId, rhValues)
 if(status /= nf90_NoErr) call handle_err(status)

Here is an example using NF90_GET_VAR to read a section of the variable named rh from an existing netCDF dataset named foo.nc. For simplicity in this example, we assume that we know that rh is dimensioned with lon, lat, and time, that there are ten lon values, five lat values, and three time values, and that we want to replace all the values at the last time.

 use netcdf
 implicit none
 integer            :: ncId, rhVarId, status
 integer, parameter :: numLons = 10, numLats = 5, numTimes = 3
 real, dimension(numLons, numLats, numTimes) &
                    :: rhValues
 ...
 status = nf90_open("foo.nc", nf90_NoWrite, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 !Read the values at the last time by passing an array section 
 status = nf90_get_var(ncid, rhVarId, rhValues(:, :, 3), &
                       start = (/ 1, 1, numTimes /),     &
                       count = (/ numLats, numLons, 1 /))
 if(status /= nf90_NoErr) call handle_err(status)

Here is an example of using NF_GET_VAR to read every other point of a netCDF variable named rh having dimensions (6, 4).

 use netcdf
 implicit none
 integer            :: ncId, rhVarId, status
 integer, parameter :: numLons = 6, numLats = 4
 real, dimension(numLons, numLats) &
                    :: rhValues
 ...
 status = nf90_open("foo.nc", nf90_NoWrite, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 ! Read every other value into an array section 
 status = nf90_get_var(ncid, rhVarId, rhValues(::2, ::2) &
                       stride = (/ 2, 2 /))
 if(status /= nf90_NoErr) call handle_err(status)

The following map vector shows the default mapping between a 2x3x4 netCDF variable and an internal array of the same shape:

 real,    dimension(2, 3, 4):: a  ! same shape as netCDF variable
 integer, dimension(3)      :: map  = (/ 1, 2, 6 /) 
                     ! netCDF dimension inter-element distance
                     ! ---------------- ----------------------
                     ! most rapidly varying       1
                     ! intermediate               2 (= map(1)*2)
                     ! most slowly varying        6 (= map(2)*3)

Using the map vector above obtains the same result as simply not passing a map vector at all.

Here is an example of using nf90_get_var to read a netCDF variable named rh whose dimensions are the transpose of the Fortran 90 array:

 use netcdf
 implicit none
 integer                           :: ncId, rhVarId, status
 integer, parameter                :: numLons = 6, numLats = 4
 real, dimension(numLons, numLats) :: rhValues
 ! netCDF variable has dimensions (numLats, numLons)
 ...
 status = nf90_open("foo.nc", nf90_NoWrite, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 ! Read transposed values: map vector would be (/ 1, numLats /) for 
 !   no transposition
 status = nf90_get_var(ncid, rhVarId,rhValues, map = (/ numLons, 1 /)) 
 if(status /= nf90_NoErr) call handle_err(status)

The same effect can be obtained more simply, though using more memory, using Fortran 90 intrinsic functions:

 use netcdf
 implicit none
 integer                           :: ncId, rhVarId, status
 integer, parameter                :: numLons = 6, numLats = 4
 real, dimension(numLons, numLats) :: rhValues
 ! netCDF variable has dimensions (numLats, numLons)
 real, dimension(numLons, numLats) :: tempValues
 ...
 status = nf90_open("foo.nc", nf90_NoWrite, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_get_var(ncid, rhVarId, tempValues)) 
 if(status /= nf90_NoErr) call handle_err(status)
 rhValues(:, :) = transpose(tempValues)

7.7 Reading and Writing Character String Values

Character strings are not a primitive netCDF external data type, in part because FORTRAN does not support the abstraction of variable-length character strings (the FORTRAN LEN function returns the static length of a character string, not its dynamic length). As a result, a character string cannot be written or read as a single object in the netCDF interface. Instead, a character string must be treated as an array of characters, and array access must be used to read and write character strings as variable data in netCDF datasets. Furthermore, variable-length strings are not supported by the netCDF interface except by convention; for example, you may treat a zero byte as terminating a character string, but you must explicitly specify the length of strings to be read from and written to netCDF variables.

Character strings as attribute values are easier to use, since the strings are treated as a single unit for access. However, the value of a character-string attribute is still an array of characters with an explicit length that must be specified when the attribute is defined.

When you define a variable that will have character-string values, use a character-position dimension as the most quickly varying dimension for the variable (the first dimension for the variable in Fortran 90). The length of the character-position dimension will be the maximum string length of any value to be stored in the character-string variable. Space for maximum-length strings will be allocated in the disk representation of character-string variables whether you use the space or not. If two or more variables have the same maximum length, the same character-position dimension may be used in defining the variable shapes.

To write a character-string value into a character-string variable, use either entire variable access or array access. The latter requires that you specify both a corner and a vector of edge lengths. The character-position dimension at the corner should be one for Fortran 90. If the length of the string to be written is n, then the vector of edge lengths will specify n in the character-position dimension, and one for all the other dimensions: (n, 1, 1, ..., 1).

In Fortran 90, fixed-length strings may be written to a netCDF dataset without a terminating character, to save space. Variable-length strings should follow the C convention of writing strings with a terminating zero byte so that the intended length of the string can be determined when it is later read by either C or Fortran 90 programs.

7.8 Fill Values

What happens when you try to read a value that was never written in an open netCDF dataset? You might expect that this should always be an error, and that you should get an error message or an error status returned. You do get an error if you try to read data from a netCDF dataset that is not open for reading, if the variable ID is invalid for the specified netCDF dataset, or if the specified indices are not properly within the range defined by the dimension lengths of the specified variable. Otherwise, reading a value that was not written returns a special fill value used to fill in any undefined values when a netCDF variable is first written.

You may ignore fill values and use the entire range of a netCDF external data type, but in this case you should make sure you write all data values before reading them. If you know you will be writing all the data before reading it, you can specify that no prefilling of variables with fill values will occur by calling writing. This may provide a significant performance gain for netCDF writes.

The variable attribute _FillValue may be used to specify the fill value for a variable. There are default fill values for each type, defined in module netcdf: NF90_FILL_CHAR, NF90_FILL_INT1 (same as NF90_FILL_BYTE), NF90_FILL_INT2 (same as NF90_FILL_SHORT), NF90_FILL_INT, NF90_FILL_REAL (same as NF90_FILL_FLOAT), and NF90_FILL_DOUBLE

The netCDF byte and character types have different default fill values. The default fill value for characters is the zero byte, a useful value for detecting the end of variable-length C character strings. If you need a fill value for a byte variable, it is recommended that you explicitly define an appropriate _FillValue attribute, as generic utilities such as ncdump will not assume a default fill value for byte variables.

Type conversion for fill values is identical to type conversion for other values: attempting to convert a value from one type to another type that can't represent the value results in a range error. Such errors may occur on writing or reading values from a larger type (such as double) to a smaller type (such as float), if the fill value for the larger type cannot be represented in the smaller type.

7.9 Rename a Variable: NF90_RENAME_VAR

The function NF90_RENAME_VAR changes the name of a netCDF variable in an open netCDF dataset. If the new name is longer than the old name, the netCDF dataset must be in define mode. You cannot rename a variable to have the name of any existing variable.

Usage

 function nf90_rename_var(ncid, varid, newname)
   integer,             intent( in) :: ncid, varid
   character (len = *), intent( in) :: newname
   integer                          :: nf90_rename_var
ncid
NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
varid
Variable ID.
newname
New name for the specified variable.

Errors

NF90_RENAME_VAR returns the value NF90_NOERR if no errors occurred. Otherwise, the returned status indicates an error. Possible causes of errors include:

Example

Here is an example using NF90_RENAME_VAR to rename the variable rh to rel_hum in an existing netCDF dataset named foo.nc:

 use netcdf
 implicit none
 integer :: ncId, rhVarId, status
 ...
 status = nf90_open("foo.nc", nf90_Write, ncid)
 if(status /= nf90_NoErr) call handle_err(status)
 ...
 status = nf90_inq_varid(ncid, "rh", rhVarId)
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_redef(ncid)  ! Enter define mode to change variable name
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_rename_var(ncid, rhVarId, "rel_hum")
 if(status /= nf90_NoErr) call handle_err(status)
 status = nf90_enddef(ncid) ! Leave define mode
 if(status /= nf90_NoErr) call handle_err(status)

[Next] [Previous] [Top] [Contents] [Index] [netCDF Home Page] [Unidata Home Page]
 
 
  Contact Us     Site Map     Search     Terms and Conditions     Privacy Policy     Participation Policy
 
National Science Foundation (NSF) UCAR Office of Programs University Corporation for Atmospheric Research (UCAR)   Unidata is a member of the UCAR Office of Programs, is managed by the University Corporation for Atmospheric Research, and is sponsored by the National Science Foundation.
P.O. Box 3000     Boulder, CO 80307-3000 USA     Tel: 303-497-8643     Fax: 303-497-8690