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]

4 Use of the NetCDF Library


You can use the netCDF library without knowing about all of the netCDF interface. If you are creating a netCDF dataset, only a handful of routines are required to define the necessary dimensions, variables, and attributes, and to write the data to the netCDF dataset. (Even less are needed if you use the ncgen utility, see 10.4 "ncgen," page 93, to create the dataset before running a program using netCDF library calls to write data.) Similarly, if you are writing software to access data stored in a particular netCDF object, only a small subset of the netCDF library is required to open the netCDF dataset and access the data. Authors of generic applications that access arbitrary netCDF datasets need to be familiar with more of the netCDF library.

In this chapter we provide templates of common sequences of netCDF calls needed for common uses. For clarity we present only the names of routines; omit declarations and error checking; omit the type-specific suffixes of routine names for variables and attributes; indent statements that are typically invoked multiple times; and use ... to represent arbitrary sequences of other statements. Full parameter lists are described in later chapters.

4.1 Creating a NetCDF Dataset

Here is a typical sequence of netCDF calls used to create a new netCDF dataset:

     NF90_CREATE           ! create netCDF dataset: enter define mode
          ... 
        NF90_DEF_DIM       ! define dimensions: from name and length
          ... 
        NF90_DEF_VAR       ! define variables: from name, type, dims
          ... 
        NF90_PUT_ATT       ! assign attribute values
          ... 
     NF90_ENDDEF           ! end definitions: leave define mode
          ... 
        NF90_PUT_VAR       ! provide values for variable
          ... 
     NF90_CLOSE            ! close: save new netCDF dataset
 

Only one call is needed to create a netCDF dataset, at which point you will be in the first of two netCDF modes. When accessing an open netCDF dataset, it is either in define mode or data mode. In define mode, you can create dimensions, variables, and new attributes, but you cannot read or write variable data. In data mode, you can access data and change existing attributes, but you are not permitted to create new dimensions, variables, or attributes.

One call to NF90_DEF_DIM is needed for each dimension created. Similarly, one call to NF90_DEF_VAR is needed for each variable creation, and one call to a member of the NF90_PUT_ATT family is needed for each attribute defined and assigned a value. To leave define mode and enter data mode, call NF90_ENDDEF.

Once in data mode, you can add new data to variables, change old values, and change values of existing attributes (so long as the attribute changes do not require more storage space). Data of all types is written to a netCDF variable using the NF90_PUT_VAR subroutine. Single values, arrays, or array sections may be supplied to NF90_PUT_VAR; optional arguments allow the writing of subsampled or mapped portions of the variable. (Subsampled and mapped access are general forms of data access that are explained later.)

Finally, you should explicitly close all netCDF datasets that have been opened for writing by calling NF90_CLOSE. By default, access to the file system is buffered by the netCDF library. If a program terminates abnormally with netCDF datasets open for writing, your most recent modifications may be lost. This default buffering of data is disabled by setting the NF90_SHARE flag when opening the dataset. But even if this flag is set, changes to attribute values or changes made in define mode are not written out until NF90_SYNC or NF90_CLOSE is called.

4.2 Reading a NetCDF Dataset with Known Names

Here we consider the case where you know the names of not only the netCDF datasets, but also the names of their dimensions, variables, and attributes. (Otherwise you would have to do "inquire" calls.) The order of typical calls to read data from those variables in a netCDF dataset is:

     NF90_OPEN               ! open existing netCDF dataset
          ... 
        NF90_INQ_DIMID       ! get dimension IDs
          ... 
        NF90_INQ_VARID       ! get variable IDs
          ... 
        NF90_GET_ATT         ! get attribute values
          ... 
        NF90_GET_VAR         ! get values of variables
          ... 
     NF90_CLOSE              ! close netCDF dataset

First, a single call opens the netCDF dataset, given the dataset name, and returns a netCDF ID that is used to refer to the open netCDF dataset in all subsequent calls.

Next, a call to NF90_INQ_DIMID for each dimension of interest gets the dimension ID from the dimension name. Similarly, each required variable ID is determined from its name by a call to NF90_INQ_VARID. Once variable IDs are known, variable attribute values can be retrieved using the netCDF ID, the variable ID, and the desired attribute name as input to NF90_GET_ATT for each desired attribute. Variable data values can be directly accessed from the netCDF dataset with calls to NF90_GET_VAR.

Finally, the netCDF dataset is closed with NF90_CLOSE. There is no need to close a dataset open only for reading.

4.3 Reading a netCDF Dataset with Unknown Names

It is possible to write programs (e.g., generic software) which do such things as processing every variable, without needing to know in advance the names of these variables. Similarly, the names of dimensions and attributes may be unknown.

Names and other information about netCDF objects may be obtained from netCDF datasets by calling inquire functions. These return information about a whole netCDF dataset, a dimension, a variable, or an attribute. The following template illustrates how they are used:

     NF90_OPEN                 ! open existing netCDF dataset
       ... 
     NF90_Inquire              ! find out what is in it
          ... 
        NF90_Inquire_Dimension ! get dimension names, lengths
          ... 
        NF90_Inquire_Variable  ! get variable names, types, shapes
             ... 
           NF90_INQ_ATTNAME    ! get attribute names
             ... 
           NF90_Inquire_Attribute ! get attribute values
             ... 
           NF90_GET_ATT        ! get attribute values
             ... 
        NF90_GET_VAR           ! get values of variables
          ... 
     NF90_CLOSE                ! close netCDF dataset

As in the previous example, a single call opens the existing netCDF dataset, returning a netCDF ID. This netCDF ID is given to the NF90_Inquire routine, which returns the number of dimensions, the number of variables, the number of global attributes, and the ID of the unlimited dimension, if there is one.

All the inquire functions are inexpensive to use and require no I/O, since the information they provide is stored in memory when a netCDF dataset is first opened.

Dimension IDs use consecutive integers, beginning at 1. Also dimensions, once created, cannot be deleted. Therefore, knowing the number of dimension IDs in a netCDF dataset means knowing all the dimension IDs: they are the integers 1, 2, 3, ...up to the number of dimensions. For each dimension ID, a call to the inquire function NF90_Inquire_Dimension returns the dimension name and length.

Variable IDs are also assigned from consecutive integers 1, 2, 3, ... up to the number of variables. These can be used in NF90_Inquire_Variable calls to find out the names, types, shapes, and the number of attributes assigned to each variable.

Once the number of attributes for a variable is known, successive calls to NF90_INQ_ATTNAME return the name for each attribute given the netCDF ID, variable ID, and attribute number. Armed with the attribute name, a call to NF90_Inquire_Variablereturns its type and length. Given the type and length, you can allocate enough space to hold the attribute values. Then a call to NF90_GET_ATT returns the attribute values.

Once the IDs and shapes of netCDF variables are known, data values can be accessed by calling NF90_GET_VAR.

4.4 Writing Data in an Existing NetCDF Dataset

With write access to an existing netCDF dataset, you can overwrite data values in existing variables or append more data to record variables along the unlimited (record) dimension. To append more data to non-record variables requires changing the shape of such variables, which means creating a new netCDF dataset, defining new variables with the desired shape, and copying data. The netCDF data model was not designed to make such "schema changes" efficient or easy, so it is best to specify the shapes of variables correctly when you create a netCDF dataset, and to anticipate which variables will later grow by using the unlimited dimension in their definition.

The following code template lists a typical sequence of calls to overwrite some existing values and add some new records to record variables in an existing netCDF dataset with known variable names:

     NF90_OPEN             ! open existing netCDF dataset
       ... 
       NF90_INQ_VARID      ! get variable IDs
       ... 
       NF90_PUT_VAR        ! provide new values for variables, if any
       ... 
       NF90_PUT_ATT        ! provide new values for attributes, if any
         ... 
     NF90_CLOSE            ! close netCDF dataset

A netCDF dataset is first opened by the NF90_OPEN call. This call puts the open dataset in data mode, which means existing data values can be accessed and changed, existing attributes can be changed, but no new dimensions, variables, or attributes can be added.

Next, calls to NF90_INQ_VARID get the variable ID from the name, for each variable you want to write. Then each call to NF90_PUT_VAR writes data into a specified variable, either a single value at a time, or a whole set of values at a time, depending on which variant of the interface is used. The calls used to overwrite values of non-record variables are the same as are used to overwrite values of record variables or append new data to record variables. The difference is that, with record variables, the record dimension is extended by writing values that don't yet exist in the dataset. This extends all record variables at once, writing "fill values" for record variables for which the data has not yet been written (but see 7.8 "Fill Values," page 67 for how to specify different behavior).

Calls to NF90_PUT_ATT may be used to change the values of existing attributes, although data that changes after a file is created is typically stored in variables rather than attributes.

Finally, you should explicitly close any netCDF datasets into which data has been written by calling NF90_CLOSE before program termination. Otherwise, modifications to the dataset may be lost.

4.5 Adding New Dimensions, Variables, Attributes

An existing netCDF dataset can be extensively altered. New dimensions, variables, and attributes can be added or existing ones renamed, and existing attributes can be deleted. Existing dimensions, variables, and attributes can be renamed. The following code template lists a typical sequence of calls to add new netCDF components to an existing dataset:

     NF90_OPEN             ! open existing netCDF dataset
       ... 
     NF90_REDEF            ! put it into define mode
         ... 
       NF90_DEF_DIM        ! define additional dimensions (if any)
         ... 
       NF90_DEF_VAR        ! define additional variables (if any)
         ... 
       NF90_PUT_ATT        ! define other attributes (if any)
         ... 
     NF90_ENDDEF           ! check definitions, leave define mode
         ... 
       NF90_PUT_VAR        ! provide new variable values
         ... 
     NF90_CLOSE            ! close netCDF dataset

A netCDF dataset is first opened by the NF90_OPEN call. This call puts the open dataset in data mode, which means existing data values can be accessed and changed, existing attributes can be changed (so long as they do not grow), but nothing can be added. To add new netCDF dimensions, variables, or attributes you must enter define mode, by calling NF90_REDEF. In define mode, call NF90_DEF_DIM to define new dimensions, NF90_DEF_VAR to define new variables, and NF90_PUT_ATT to assign new attributes to variables or enlarge old attributes.

You can leave define mode and reenter data mode, checking all the new definitions for consistency and committing the changes to disk, by calling NF90_ENDDEF. If you do not wish to reenter data mode, just call NF90_CLOSE, which will have the effect of first calling NF90_ENDDEF.

Until the NF90_ENDDEF call, you may back out of all the redefinitions made in define mode and restore the previous state of the netCDF dataset by calling NF90_ABORT. You may also use the NF90_ABORT call to restore the netCDF dataset to a consistent state if the call to NF90_ENDDEF fails. If you have called NF90_CLOSE from definition mode and the implied call to NF90_ENDDEF fails, NF90_ABORT will automatically be called to close the netCDF dataset and leave it in its previous consistent state (before you entered define mode).

At most one process should have a netCDF dataset open for writing at one time. The library is designed to provide limited support for multiple concurrent readers with one writer, via disciplined use of the NF90_SYNC function and the NF90_SHARE flag. If a writer makes changes in define mode, such as the addition of new variables, dimensions, or attributes, some means external to the library is necessary to prevent readers from making concurrent accesses and to inform readers to call NF90_SYNC before the next access.

4.6 Error Handling

The netCDF library provides the facilities needed to handle errors in a flexible way. Each netCDF function returns an integer status value. If the returned status value indicates an error, you may handle it in any way desired, from printing an associated error message and exiting to ignoring the error indication and proceeding (not recommended!). For simplicity, the examples in this guide check the error status and call a separate function to handle any errors.

The NF90_STRERROR function is available to convert a returned integer error status into an error message string.

Occasionally, low-level I/O errors may occur in a layer below the netCDF library. For example, if a write operation causes you to exceed disk quotas or to attempt to write to a device that is no longer available, you may get an error from a layer below the netCDF library, but the resulting write error will still be reflected in the returned status value.

4.7 Compiling and Linking with the NetCDF Library

Details of how to compile and link a program that uses the netCDF C or FORTRAN interfaces differ, depending on the operating system, the available compilers, and where the netCDF library and include files are installed. Nevertheless, we provide here examples of how to compile and link a program that uses the netCDF library on a Unix platform, so that you can adjust these examples to fit your installation.

Every Fortran 90 procedure or module which references netCDF constants or procedures must have access to the module information created when the netCDF module was compiled. The suffix for this file depends on the compiler, but is often .MOD. Most Fortran 90 compilers do not allow you to specify an alternative location for this file as you might the location of external libraries. The simplest solution, therefore, is to create a symbolic link from the directory in which your code resides to the location of the pre-compiled netCDF module. For example:

 ln -s /usr/local/netcdf/src/f90/netcdf.mod .

You may then compile source files which reference netCDF constants or procedures.

 f90 -c mymodule.f90 

Unless the netCDF library is installed in a standard directory where the linker always looks, you must use the -L and -l options to link an object file that uses the netCDF library. For example:

 f90 -o myprogram myprogram.o -L/usr/local/netcdf/lib -lnetcdf

[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