NetCDF Tutorial
***************

This tutorial aims to give a quick and painless introduction to netCDF.
Then again, the guillotine was also intended to be painless.

   The first chapter, "What is NetCDF?," covers the basics concepts of
netCDF. Read this to understand the netCDF data model.

   The second chapter, "Example Programs," contains three sets of
examples of increasing complexity. The example programs are provided
for each of four netCDF API languages, C, C++, F77, and F90.

   The final chapter, "The Functions You Need in NetCDF-3," provides a
quick reference to the important functions in each API, with
hyper-links to the full documentation of each function.

   This document applies to netCDF version 3.6.2; it was last updated
on 19 February 2007.

1 What is NetCDF?
*****************

NetCDF is a set of data formats, programming interfaces, and software
libraries that help read and write scientific data files.

   NetCDF was developed and is maintained at Unidata.

   Unidata, funded primarily by the National Science Foundation, is one
of eight programs in the University Corporation for Atmospheric
Research (UCAR) Office of Programs (UOP).

   Unidata provides data and software tools for use in geoscience
education and research. For more information see the web sites of
Unidata (`http://www.unidata.ucar.edu'), UOP
(`http://www.uop.ucar.edu'), and UCAR (`http://www.ucar.edu').

   This tutorial may serve as an introduction to netCDF. Full netCDF
documentation is available on-line (*note Documentation::).

1.1 The NetCDF Data Model
=========================

The netCDF data model consists of "variables", "dimensions", and
"attributes".

`Variables'
     N-dimensional arrays of data. Variables in netCDF files can be one
     of six types (char, byte, short, int, float, double). For more
     information see *Note Variables: (netcdf)Variables.

`Dimensions'
     describe the axes of the data arrays. A dimension has a name and a
     length. An unlimited dimension has a length that can be expanded
     at any time, as more data are written to it. NetCDF files can
     contain at most one unlimited dimension. For more information see
     *Note Dimensions: (netcdf)Dimensions.

`Attributes'
     annotate variables or files with small notes or supplementary
     metadata. Attributes are always scalar values or 1D arrays, which
     can be associated with either a variable or the file as a whole.
     Although there is no enforced limit, the user is expected to keep
     attributes small. For more information see *Note Attributes:
     (netcdf)Attributes.


   For more information on the netCDF data model see *Note The NetCDF
Data Model: (netcdf)The NetCDF Data Model.

1.1.1 Meteorological Example
----------------------------

NetCDF can be used to store many kinds of data, but it was originally
developed for the Earth science community.

   NetCDF views the world of scientific data in the same way that an
atmospheric scientist might: as sets of related arrays. There are
various physical quantities (such as pressure and temperature) located
at points at a particular latitude, longitude, vertical level, and time.

   A scientist might also like to store supporting information, such as
the units, or some information about how the data were produced.

   The axis information (latitude, longitude, level, and time) would be
stored as netCDF dimensions. Dimensions have a length and a name.

   The physical quantities (pressure, temperature) would be stored as
netCDF variables. Variables are N-dimensional arrays of data, with a
name and an associated set of netCDF dimensions.

   It is also customary to add one variable for each dimension, to hold
the values along that axis. These variables are call "coordinate
variables." The latitude coordinate variable would be a one-dimensional
variable (with latitude as it's dimension), and it would hold the
latitude values at each point along the axis.

   The additional bits of metadata would be stored as netCDF attributes.

   Attributes are always single values or one-dimensional arrays. (This
works out well for a string, which is a one-dimensional array of ASCII
characters.)

   The pres_temp_4D example in this tutorial shows how to write and read
a file containing some four-dimensional pressure and temperature data,
including all the metadata needed. *Note pres_temp_4D::.

1.2 NetCDF Error Handling
=========================

Each netCDF function in the C, Fortran 77, and Fortran 90 APIs returns
0 on success, in the tradition of C. (For C++, see below).

   When programming with netCDF in these languages, always check return
values of every netCDF API call. The return code can be looked up in
netcdf.h (for C programmers) or netcdf.inc (for Fortran programmers),
or you can use the strerror function to print out an error message.
(See *Note nc_strerror: (netcdf-c)nc_strerror./*Note NF_STRERROR:
(netcdf-f77)NF_STRERROR./*Note NF90_STRERROR:
(netcdf-f90)NF90_STRERROR.).

   In general, if a function returns an error code, you can assume it
didn't do what you hoped it would. The exception is the NC_ERANGE
error, which is returned by any of the reading or writing functions
when one or more of the values read or written exceeded the range for
the type. (For example if you were to try to read 1000 into an unsigned
byte.)

   In the case of NC_ERANGE errors, the netCDF library completes the
read/write operation, and then returns the error. The type conversion
is handled like a C type conversion, whether or not it is within range.
This may yield bad data, but the netCDF library just returns NC_ERANGE
and leaves it up to the user to handle. (For more information about
type conversion *note Type Conversion: (netcdf-c)Type Conversion.).

   Error handling in C++ is different. For some objects, the is_valid()
method should be called. Other error handling is controlled by the
NcError class. For more information see *Note Class NcError:
(netcdf-cxx)Class NcError.

   For a complete list of netCDF error codes see *Note Error Codes:
(netcdf-c)Error Codes.

1.3 Unlimited Dimensions
========================

Sometimes you don't know the size of all dimensions when you create a
file, or you would like to arbitrarily extend the file along one of the
dimensions.

   For example, model output usually has a time dimension. Rather than
specifying that there will be forty-two output times when creating the
file, you might like to create it with one time, and then add data for
additional times, until you wanted to stop.

   For this purpose netCDF provides the unlimited dimension. By
specifying a length of "unlimited" when defining a dimension, you
indicate to netCDF that the dimension may be extended, and its length
may increase.

   In netCDF files, there can only be one unlimited dimension, and it
must be declared first in the list of dimensions for a variable.

   For programmers, the unlimited dimension will correspond with the
slowest-varying dimension. In C this is the first dimension of an
array, in Fortran, the last.

   The third example in this tutorial, pres_temp_4D, demonstrates how to
write and read data one time step at a time along an unlimited
dimension. *Note pres_temp_4D::.

   For more detailed information about dimensions see *Note Dimensions:
(netcdf)Dimensions.

1.4 Fill Values
===============

Sometimes there are missing values in the data, and some value is
needed to represent them.

   For example, what value do you put in a sea-surface temperature
variable for points over land?

   In netCDF, you can create an attribute for the variable (and of the
same type as the variable) called "_FillValue" that contains a value
that you have used for missing data. Applications that read the data
file can use this to know how to represent these values.

   Using attributes it is possible to capture metadata that would
otherwise be separated from the data. Various conventions have been
established. By using a set of conventions, a data producer is more
likely to produce files that can be easily shared within the research
community, and that contain enough details to be useful as a long-term
archive.

   For more information on _FillValue and other attribute conventions,
see *Note Attribute Conventions: (netcdf)Attribute Conventions.

   Climate and meteorological users are urged to follow the Climate and
Forecast (CF) metadata conventions when producing data files. For more
information about the CF conventions, see `http://cf-pcmdi.llnl.gov'.

   For information about creating attributes, see *Note Creation::.

1.5 Tools for Manipulating NetCDF Files
=======================================

Many existing software applications can read and manipulate netCDF
files. Before writing your own program, check to see if any existing
programs meet your needs.

   Two utilities come with the netCDF distribution: ncdump and ncgen.
The ncdump command reads a netCDF file and outputs ASCII in a format
called CDL. The ncgen command reads an ASCII file in CDL format, and
generates a netCDF data file.

   One common use for ncdump is to examine the metadata of a netCDF
file, to see what it contains. At the beginning of each example in this
tutorial, an ncdump of the resulting data file is shown. *Note
simple_xy::.

   For more information about ncdump and ncgen see *Note NetCDF
Utilities: (netcdf)NetCDF Utilities.

   The following general-purpose tools have been found to be useful in
many situations. Some of the tools on this list are developed at
Unidata. The others are developed elsewhere, and we can make no
guarantees about their continued availability or success. All of these
tools are open-source.

UDUNITS        Unidata library to help with  `http://www.unidata.ucar.edu/software/udunits'
               scientific units.             
IDV            Unidata's Integrated Data     `http://www.unidata.ucar.edu/software/idv'
               Viewer, a 3D visualization    
               and analysis package (Java    
               based).                       
NCL            NCAR Command Language, a      `http://www.ncl.ucar.edu'
               graphics and data             
               manipulation package.         
GrADS          The Grid Analysis and         `http://grads.iges.org/grads/grads.html'
               Display System package.       
NCO            NetCDF Command line           `http://nco.sourceforge.net'
               Operators, tools to           
               manipulate netCDF files.      

   For a list of netCDF tools that we know about see
`http://www.unidata.ucar.edu/software/netcdf/software.html'. If you
know of any that should be added to this list, send email to
support@unidata.ucar.edu.

1.6 The NetCDF Programming APIs
===============================

Unidata supports netCDF APIs in C, C++, Fortran 77, Fortran 90, and
Java.

   The Java API is a complete implementation of netCDF in Java. It is
distributed independently of the other APIs. For more information see
the netCDF Java page:
`http://www.unidata.ucar.edu/software/netcdf-java'. If you are writing
web server software, you should certainly be doing so in Java.

   The C, C++, Fortran 77 and Fortran 90 APIs are distributed and
installed when the netCDF C library is built, if compilers exist to
build them, and if they are not turned off when configuring the netCDF
build.

   The C++ and Fortran APIs depend on the C API. Due to the nature of
C++ and Fortran 90, users of those languages can also use the C and
Fortran 77 APIs (respectively) directly.

   Full documentation exists for each API (*note Documentation::).

   In addition, many other language APIs exist, including Perl, Python,
and Ruby. Most of these APIs were written and supported by netCDF
users. Some of them are listed on the netCDF software page, see
`http://www.unidata.ucar.edu/software/netcdf/software.html'.

   In addition to the main netCDF-3 C API, there is an additional
(older) C API, the netCDF-2 API. This API produces exactly the same
files as the netCDF-3 API - only the API is different. (That is, users
can create either classic format files, the default, or 64-bit offset
files.)

   The version 2 API was the API before netCDF-3.0 came out. It is still
fully supported, however. Programs written to the version 2 API will
continue to work.

   Users writing new programs should use the netCDF-3 API, which
contains better type checking, better error handling, and better
documentation.

   The netCDF-2 API is provided for backward compatibility.
Documentation for the netCDF-2 API can be found on the netCDF website,
see `http://www.unidata.ucar.edu/software/netcdf/guide_toc.html'.

1.7 NetCDF Documentation
========================

This tutorial is brief. A much more complete description of netCDF can
be found in The NetCDF Users Guide. It fully describes the netCDF model
and format. For more information see *Note The NetCDF Users Guide:
(netcdf)Top.

   The netCDF distribution, in various forms, can be obtained from the
netCDF web site: `http://www.unidata.ucar.edu/software/netcdf'.

   A porting and installation guide for the C, C++, Fortran 77, and
Fortran 90 APIs describes how to build these APIs on a variety of
platforms. *Note The NetCDF Installation and Porting Guide:
(netcdf-install)Top.

   Language specific programming guides are available for netCDF for the
C, C++, Fortran 77, Fortran 90, and Java APIs:

`C'
     *Note The NetCDF C Interface Guide: (netcdf-c)Top.

`C++'
     *Note The NetCDF C++ Interface Guide: (netcdf-cxx)Top.

`Fortran 77'
     *Note The NetCDF Fortran 77 Interface Guide: (netcdf-f77)Top.

`Fortran 90'
     *Note The NetCDF Fortran 90 Interface Guide: (netcdf-f90)Top.

`Java'
     `http://www.unidata.ucar.edu/software/netcdf-java/v2.1/NetcdfJavaUserManual.htm'.


   Man pages for the C, F77, and F90 interfaces, and ncgen and ncdump,
are available on the documentation page of the netCDF web site
(`http://www.unidata.ucar.edu/software/netcdf/docs'), and are installed
with the netCDF distribution.

   The latest version of all netCDF documentation can always be found at
the documentation page of the netCDF web site:
`http://www.unidata.ucar.edu/software/netcdf/docs'

1.8 A Note on NetCDF Versions and Formats
=========================================

NetCDF has changed (and improved) over its lifetime. That means the
user must have some understanding of netCDF versions.

   To add to the confusion, there are versions for the APIs, and also
for the data files that they produce. The API version is the version
number that appears in the tarball file that is downloaded from the
netCDF website. For example the current version is 3.6.2.

   Since version 3.6.0 there are two versions of the netCDF file
format. Both underlying formats are accessed by the same netCDF API,
but are stored differently on disk. The formats are called "classic
format," and "64-bit offset format."

   The good news is that all netCDF files ever written can always be
read by the latest netCDF release. That is, we guarantee backward data
compatibility.

   As long as you have a version of netCDF greater than 3.6.0, you can
use either format. To share data in 64-bit offset format, everyone who
wants to read the data must use at least version 3.6.0.

   The default format is classic format. To get 64-bit offset format,
set a flag when creating the file. For more information about the
format, see *Note Format: (netcdf)Format.

   Classic format has some strict limitations for files larger than two
gigabytes. (*note NetCDF Classic Format Limitations: (netcdf)NetCDF
Classic Format Limitations.).

   64-bit offset is very useful for very large data files (over two
gigabytes), however these files can only be shared with those who have
upgraded to version 3.6.0 (or better) of netCDF. Earlier versions of
netCDF will not be able to read these files.

1.9 The Future of NetCDF
========================

NetCDF continues under active development at Unidata (see
`http://www.unidata.ucar.edu').

   The upcoming and long anticipated release of netCDF-4.0 will
introduce another format: HDF5. This does not represent the weakening
of support for the classic and 64-bit offset formats! NetCDF-4.0 will
maintain full backward compatibility, and will continue to use classic
format by default. NetCDF-4.0 will introduce many interesting new
features, such as groups and compound data types, which will only be
available for files using the HDF5 format. Classic and 64-bit offset
files will behave as always, and will be fully supported in netCDF-4.

   NetCDF-4 is in advanced alpha release, and adventurous users can try
it out for themselves, but it is not ready for operational use and
won't be until HDF5 1.8.0 is released. See
`http://www.unidata.ucar.edu/software/netcdf/netcdf-4'.

   The netCDF-Java library has many advanced capabilities, and is
actively maintained and developed. See
`http://www.unidata.ucar.edu/software/netcdf-java/v2.1/NetcdfJavaUserManual.htm'.

2 Example Programs
******************

The netCDF example programs show how to use netCDF.

   In the netCDF distribution, the "examples" directory contains
examples in C, Fortran 77, Fortran 90, C++, and CDL. There are three
sets of example programs in each language. Each language has its own
subdirectory under the "examples" directory (for example, the Fortran
77 examples are in "examples/F77").

   The examples are built and run with the "make check" command. (For
more information on building netCDF, *note The NetCDF Installation and
Porting Guide: (netcdf-install)Top.).

   The examples create, and then read, three different example files, of
increasing complexity.

   The corresponding examples in each language create identical netCDF
data files. For example, the C program sfc_pres_temp_wr.c produces the
same data file as the Fortran 77 program sfc_pres_temp_wr.f.

   For convenience, the complete source code in each language can be
found in this tutorial, as well as in the netCDF distribution.

2.1 The simple_xy Example
=========================

This example is an unrealistically simple netCDF file, to demonstrate
the minimum operation of the netCDF APIs. Users should seek to make
their netCDF files more self-describing than this primitive example.

   As in all the netCDF tutorial examples, this example file is created
by C, Fortran 77, Fortran 90, and C++ programs, and by ncgen, which
creates it from a CDL script. All examples create identical files,
"simple_xy.nc."

   The programs that create this sample file all have the base name
"simple_xy_wr", with different extensions depending on the language.

   Therefore the example files that create simple_xy.nc can be found in:
C/simple_xy_wr.c, F77/simple_xy_wr.f, F90/simple_xy_wr.f90,
CXX/simple_xy_wr.cpp, and CDL/simple_xy_wr.cdl.

   Corresponding read programs (C/simple_xy_rd.c, etc.) read the
simple_xy.nc data file, and ensure that it contains the correct values.

   The simple_xy.nc data file contains two dimensions, "x" and "y", and
one netCDF variable, "data."

   The utility ncdump can be used to show the contents of netCDF files.
By default, ncdump shows the CDL description of the file. This CDL
description can be fed into ncgen to create the data file.

   The CDL for this example is shown below. For more information on
ncdump and ncgen see *Note NetCDF Utilities: (netcdf)NetCDF Utilities.

     netcdf simple_xy {
     dimensions:
     	x = 6 ;
     	y = 12 ;
     variables:
     	int data(x, y) ;
     data:

      data =
       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
       12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
       24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
       36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
       48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
       60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71 ;
     }

2.1.1 simple_xy_wr.c and simple_xy_rd.c
---------------------------------------

These example programs can be found in the netCDF distribution, under
examples/C.

   The example program simple_xy_wr.c creates the example data file
simple_xy.nc. The example program simple_xy_rd.c reads the data file.

2.1.1.1 simple_xy_wr.c
......................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This is a very simple example which writes a 2D array of
        sample data. To handle this in netCDF we create two shared
        dimensions, "x" and "y", and a netCDF variable, called "data".

        This example demonstrates the netCDF C API. This is part of the
        netCDF tutorial, which can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c

        $Id: simple_xy_wr.c,v 1.12 2007/02/14 20:59:21 ed Exp $
     */
     #include <stdlib.h>
     #include <stdio.h>
     #include <netcdf.h>

     /* This is the name of the data file we will create. */
     #define FILE_NAME "simple_xy.nc"

     /* We are writing 2D data, a 6 x 12 grid. */
     #define NDIMS 2
     #define NX 6
     #define NY 12

     /* Handle errors by printing an error message and exiting with a
      * non-zero status. */
     #define ERRCODE 2
     #define ERR(e) {printf("Error: %s\n", nc_strerror(e)); exit(ERRCODE);}

     int
     main()
     {
        /* When we create netCDF variables and dimensions, we get back an
         * ID for each one. */
        int ncid, x_dimid, y_dimid, varid;
        int dimids[NDIMS];

        /* This is the data array we will write. It will be filled with a
         * progression of numbers for this example. */
        int data_out[NX][NY];

        /* Loop indexes, and error handling. */
        int x, y, retval;

        /* Create some pretend data. If this wasn't an example program, we
         * would have some real data to write, for example, model
         * output. */
        for (x = 0; x < NX; x++)
           for (y = 0; y < NY; y++)
     	 data_out[x][y] = x * NY + y;

        /* Always check the return code of every netCDF function call. In
         * this example program, any retval which is not equal to NC_NOERR
         * (0) will cause the program to print an error message and exit
         * with a non-zero return code. */

        /* Create the file. The NC_CLOBBER parameter tells netCDF to
         * overwrite this file, if it already exists.*/
        if ((retval = nc_create(FILE_NAME, NC_CLOBBER, &ncid)))
           ERR(retval);

        /* Define the dimensions. NetCDF will hand back an ID for each. */
        if ((retval = nc_def_dim(ncid, "x", NX, &x_dimid)))
           ERR(retval);
        if ((retval = nc_def_dim(ncid, "y", NY, &y_dimid)))
           ERR(retval);

        /* The dimids array is used to pass the IDs of the dimensions of
         * the variable. */
        dimids[0] = x_dimid;
        dimids[1] = y_dimid;

        /* Define the variable. The type of the variable in this case is
         * NC_INT (4-byte integer). */
        if ((retval = nc_def_var(ncid, "data", NC_INT, NDIMS,
     			    dimids, &varid)))
           ERR(retval);

        /* End define mode. This tells netCDF we are done defining
         * metadata. */
        if ((retval = nc_enddef(ncid)))
           ERR(retval);

        /* Write the pretend data to the file. Although netCDF supports
         * reading and writing subsets of data, in this case we write all
         * the data in one operation. */
        if ((retval = nc_put_var_int(ncid, varid, &data_out[0][0])))
           ERR(retval);

        /* Close the file. This frees up any internal netCDF resources
         * associated with the file, and flushes any buffers. */
        if ((retval = nc_close(ncid)))
           ERR(retval);

        printf("*** SUCCESS writing example file simple_xy.nc!\n");
        return 0;
     }

2.1.1.2 simple_xy_rd.c
......................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This is a simple example which reads a small dummy array, which was
        written by simple_xy_wr.c. This is intended to illustrate the use
        of the netCDF C API.

        This program is part of the netCDF tutorial:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c

        $Id: simple_xy_rd.c,v 1.9 2006/08/17 23:00:55 russ Exp $
     */
     #include <stdlib.h>
     #include <stdio.h>
     #include <netcdf.h>

     /* This is the name of the data file we will read. */
     #define FILE_NAME "simple_xy.nc"

     /* We are reading 2D data, a 6 x 12 grid. */
     #define NX 6
     #define NY 12

     /* Handle errors by printing an error message and exiting with a
      * non-zero status. */
     #define ERRCODE 2
     #define ERR(e) {printf("Error: %s\n", nc_strerror(e)); exit(ERRCODE);}

     int
     main()
     {
        /* This will be the netCDF ID for the file and data variable. */
        int ncid, varid;

        int data_in[NX][NY];

        /* Loop indexes, and error handling. */
        int x, y, retval;

        /* Open the file. NC_NOWRITE tells netCDF we want read-only access
         * to the file.*/
        if ((retval = nc_open(FILE_NAME, NC_NOWRITE, &ncid)))
           ERR(retval);

        /* Get the varid of the data variable, based on its name. */
        if ((retval = nc_inq_varid(ncid, "data", &varid)))
           ERR(retval);

        /* Read the data. */
        if ((retval = nc_get_var_int(ncid, varid, &data_in[0][0])))
           ERR(retval);

        /* Check the data. */
        for (x = 0; x < NX; x++)
           for (y = 0; y < NY; y++)
     	 if (data_in[x][y] != x * NY + y)
     	    return ERRCODE;

        /* Close the file, freeing all resources. */
        if ((retval = nc_close(ncid)))
           ERR(retval);

        printf("*** SUCCESS reading example file %s!\n", FILE_NAME);
        return 0;
     }

2.1.2 simple_xy_wr.f and simple_xy_rd.f
---------------------------------------

These example programs can be found in the netCDF distribution, under
examples/F77.

   The example program simple_xy_wr.f creates the example data file
simple_xy.nc. The example program simple_xy_rd.f reads the data file.

2.1.2.1 simple_xy_wr.f
......................

     C     This is part of the netCDF package.
     C     Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     C     See COPYRIGHT file for conditions of use.

     C     This is a very simple example which writes a 2D array of
     C     sample data. To handle this in netCDF we create two shared
     C     dimensions, "x" and "y", and a netCDF variable, called "data".

     C     This example demonstrates the netCDF Fortran 77 API. This is part
     C     of the netCDF tutorial, which can be found at:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     C     Full documentation of the netCDF Fortran 77 API can be found at:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f77

     C     $Id: simple_xy_wr.f,v 1.10 2007/02/14 20:59:20 ed Exp $

           program simple_xy_wr
           implicit none
           include 'netcdf.inc'

     C     This is the name of the data file we will create.
           character*(*) FILE_NAME
           parameter (FILE_NAME='simple_xy.nc')

     C     We are writing 2D data, a 12 x 6 grid.
           integer NDIMS
           parameter (NDIMS=2)
           integer NX, NY
           parameter (NX = 6, NY = 12)

     C     When we create netCDF files, variables and dimensions, we get back
     C     an ID for each one.
           integer ncid, varid, dimids(NDIMS)
           integer x_dimid, y_dimid

     C     This is the data array we will write. It will just be filled with
     C     a progression of integers for this example.
           integer data_out(NY, NX)

     C     Loop indexes, and error handling.
           integer x, y, retval

     C     Create some pretend data. If this wasn't an example program, we
     C     would have some real data to write, for example, model output.
           do x = 1, NX
              do y = 1, NY
                 data_out(y, x) = (x - 1) * NY + (y - 1)
              end do
           end do

     C     Always check the return code of every netCDF function call. In
     C     this example program, any retval which is not equal to nf_noerr
     C     (0) will call handle_err, which prints a netCDF error message, and
     C     then exits with a non-zero return code.

     C     Create the netCDF file. The nf_clobber parameter tells netCDF to
     C     overwrite this file, if it already exists.
           retval = nf_create(FILE_NAME, NF_CLOBBER, ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Define the dimensions. NetCDF will hand back an ID for each.
           retval = nf_def_dim(ncid, "x", NX, x_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_dim(ncid, "y", NY, y_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     The dimids array is used to pass the IDs of the dimensions of
     C     the variables. Note that in fortran arrays are stored in
     C     column-major format.
           dimids(2) = x_dimid
           dimids(1) = y_dimid

     C     Define the variable. The type of the variable in this case is
     C     NF_INT (4-byte little-endian integer).
           retval = nf_def_var(ncid, "data", NF_INT, NDIMS, dimids, varid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     End define mode. This tells netCDF we are done defining metadata.
           retval = nf_enddef(ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Write the pretend data to the file. Although netCDF supports
     C     reading and writing subsets of data, in this case we write all the
     C     data in one operation.
           retval = nf_put_var_int(ncid, varid, data_out)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Close the file. This frees up any internal netCDF resources
     C     associated with the file, and flushes any buffers.
           retval = nf_close(ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

           print *,'*** SUCCESS writing example file simple_xy.nc!'
           end

           subroutine handle_err(errcode)
           implicit none
           include 'netcdf.inc'
           integer errcode

           print *, 'Error: ', nf_strerror(errcode)
           stop 2
           end

2.1.2.2 simple_xy_rd.f
......................

     C     This is part of the netCDF package.
     C     Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     C     See COPYRIGHT file for conditions of use.

     C     This is a simple example which reads a small dummy array, from a
     C     netCDF data file created by the companion program simple_xy_wr.f.

     C     This is intended to illustrate the use of the netCDF fortran 77
     C     API. This example program is part of the netCDF tutorial, which can
     C     be found at:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     C     Full documentation of the netCDF Fortran 77 API can be found at:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f77

     C     $Id: simple_xy_rd.f,v 1.8 2007/02/14 20:59:20 ed Exp $

           program simple_xy_rd
           implicit none
           include 'netcdf.inc'

     C     This is the name of the data file we will read.
           character*(*) FILE_NAME
           parameter (FILE_NAME='simple_xy.nc')

     C     We are reading 2D data, a 12 x 6 grid.
           integer NX, NY
           parameter (NX = 6, NY = 12)
           integer data_in(NY, NX)

     C     This will be the netCDF ID for the file and data variable.
           integer ncid, varid

     C     Loop indexes, and error handling.
           integer x, y, retval

     C     Open the file. NF_NOWRITE tells netCDF we want read-only access to
     C     the file.
           retval = nf_open(FILE_NAME, NF_NOWRITE, ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Get the varid of the data variable, based on its name.
           retval = nf_inq_varid(ncid, 'data', varid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Read the data.
           retval = nf_get_var_int(ncid, varid, data_in)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Check the data.
           do x = 1, NX
              do y = 1, NY
                 if (data_in(y, x) .ne. (x - 1) * NY + (y - 1)) then
                    print *, 'data_in(', y, ', ', x, ') = ', data_in(y, x)
                    stop 2
                 end if
              end do
           end do

     C     Close the file, freeing all resources.
           retval = nf_close(ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

           print *,'*** SUCCESS reading example file ', FILE_NAME, '!'
           end

           subroutine handle_err(errcode)
           implicit none
           include 'netcdf.inc'
           integer errcode

           print *, 'Error: ', nf_strerror(errcode)
           stop 2
           end

2.1.3 simple_xy_wr.f90 and simple_xy_rd.f90
-------------------------------------------

These example programs can be found in the netCDF distribution, under
examples/F90.

   The example program simple_xy_wr.f90 creates the example data file
simple_xy.nc. The example program simple_xy_rd.f90 reads the data file.

2.1.3.1 simple_xy_wr.f90
........................

     !     This is part of the netCDF package.
     !     Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     !     See COPYRIGHT file for conditions of use.

     !     This is a very simple example which writes a 2D array of
     !     sample data. To handle this in netCDF we create two shared
     !     dimensions, "x" and "y", and a netCDF variable, called "data".

     !     This example demonstrates the netCDF Fortran 90 API. This is part
     !     of the netCDF tutorial, which can be found at:
     !     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     !     Full documentation of the netCDF Fortran 90 API can be found at:
     !     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f90

     !     $Id: simple_xy_wr.f90,v 1.8 2007/02/14 20:59:20 ed Exp $

     program simple_xy_wr
       use netcdf
       implicit none

       ! This is the name of the data file we will create.
       character (len = *), parameter :: FILE_NAME = "simple_xy.nc"

       ! We are writing 2D data, a 12 x 6 grid.
       integer, parameter :: NDIMS = 2
       integer, parameter :: NX = 6, NY = 12

       ! When we create netCDF files, variables and dimensions, we get back
       ! an ID for each one.
       integer :: ncid, varid, dimids(NDIMS)
       integer :: x_dimid, y_dimid

       ! This is the data array we will write. It will just be filled with
       ! a progression of integers for this example.
       integer :: data_out(NY, NX)

       ! Loop indexes, and error handling.
       integer :: x, y

       ! Create some pretend data. If this wasn't an example program, we
       ! would have some real data to write, for example, model output.
       do x = 1, NX
          do y = 1, NY
             data_out(y, x) = (x - 1) * NY + (y - 1)
          end do
       end do

       ! Always check the return code of every netCDF function call. In
       ! this example program, wrapping netCDF calls with "call check()"
       ! makes sure that any return which is not equal to nf90_noerr (0)
       ! will print a netCDF error message and exit.

       ! Create the netCDF file. The nf90_clobber parameter tells netCDF to
       ! overwrite this file, if it already exists.
       call check( nf90_create(FILE_NAME, NF90_CLOBBER, ncid) )

       ! Define the dimensions. NetCDF will hand back an ID for each.
       call check( nf90_def_dim(ncid, "x", NX, x_dimid) )
       call check( nf90_def_dim(ncid, "y", NY, y_dimid) )

       ! The dimids array is used to pass the IDs of the dimensions of
       ! the variables. Note that in fortran arrays are stored in
       ! column-major format.
       dimids =  (/ y_dimid, x_dimid /)

       ! Define the variable. The type of the variable in this case is
       ! NF90_INT (4-byte little-endian integer).
       call check( nf90_def_var(ncid, "data", NF90_INT, dimids, varid) )

       ! End define mode. This tells netCDF we are done defining metadata.
       call check( nf90_enddef(ncid) )

       ! Write the pretend data to the file. Although netCDF supports
       ! reading and writing subsets of data, in this case we write all the
       ! data in one operation.
       call check( nf90_put_var(ncid, varid, data_out) )

       ! Close the file. This frees up any internal netCDF resources
       ! associated with the file, and flushes any buffers.
       call check( nf90_close(ncid) )

       print *, "*** SUCCESS writing example file simple_xy.nc! "

     contains
       subroutine check(status)
         integer, intent ( in) :: status

         if(status /= nf90_noerr) then
           print *, trim(nf90_strerror(status))
           stop "Stopped"
         end if
       end subroutine check
     end program simple_xy_wr

2.1.3.2 simple_xy_rd.f90
........................

     ! This is part of the netCDF package.
     ! Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     ! See COPYRIGHT file for conditions of use.

     ! This is a simple example which reads a small dummy array, from a
     ! netCDF data file created by the companion program simple_xy_wr.f90.

     ! This is intended to illustrate the use of the netCDF fortran 77
     ! API. This example program is part of the netCDF tutorial, which can
     ! be found at:
     ! http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     ! Full documentation of the netCDF Fortran 90 API can be found at:
     ! http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f90

     ! $Id: simple_xy_rd.f90,v 1.8 2007/02/14 20:59:20 ed Exp $

     program simple_xy_rd
       use netcdf
       implicit none

       ! This is the name of the data file we will read.
       character (len = *), parameter :: FILE_NAME = "simple_xy.nc"

       ! We are reading 2D data, a 12 x 6 grid.
       integer, parameter :: NX = 6, NY = 12
       integer :: data_in(NY, NX)

       ! This will be the netCDF ID for the file and data variable.
       integer :: ncid, varid

       ! Loop indexes, and error handling.
       integer :: x, y

       ! Open the file. NF90_NOWRITE tells netCDF we want read-only access to
       ! the file.
       call check( nf90_open(FILE_NAME, NF90_NOWRITE, ncid) )

       ! Get the varid of the data variable, based on its name.
       call check( nf90_inq_varid(ncid, "data", varid) )

       ! Read the data.
       call check( nf90_get_var(ncid, varid, data_in) )

       ! Check the data.
       do x = 1, NX
          do y = 1, NY
             if (data_in(y, x) /= (x - 1) * NY + (y - 1)) then
                print *, "data_in(", y, ", ", x, ") = ", data_in(y, x)
                stop "Stopped"
             end if
          end do
       end do

       ! Close the file, freeing all resources.
       call check( nf90_close(ncid) )

       print *,"*** SUCCESS reading example file ", FILE_NAME, "! "

     contains
       subroutine check(status)
         integer, intent ( in) :: status

         if(status /= nf90_noerr) then
           print *, trim(nf90_strerror(status))
           stop "Stopped"
         end if
       end subroutine check
     end program simple_xy_rd

2.1.4 simple_xy_wr.cpp and simple_xy_rd.cpp
-------------------------------------------

These example programs can be found in the netCDF distribution, under
examples/CXX.

   The example program simple_xy_wr.cpp creates the example data file
simple_xy.nc. The example program simple_xy_rd.cpp reads the data file.

2.1.4.1 simple_xy_wr.cpp
........................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This is a very simple example which writes a 2D array of
        sample data. To handle this in netCDF we create two shared
        dimensions, "x" and "y", and a netCDF variable, called "data".

        This example is part of the netCDF tutorial:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C++ API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx

        $Id: simple_xy_wr.cpp,v 1.15 2007/01/19 12:52:13 ed Exp $
     */

     #include <iostream>
     #include <netcdfcpp.h>

     using namespace std;

     // We are writing 2D data, a 6 x 12 grid.
     static const int NX = 6;
     static const int NY = 12;

     // Return this in event of a problem.
     static const int NC_ERR = 2;

     int
     main(void)
     {
        // This is the data array we will write. It will just be filled
        // with a progression of numbers for this example.
        int dataOut[NX][NY];

        // Create some pretend data. If this wasn't an example program, we
        // would have some real data to write, for example, model output.
        for(int i = 0; i < NX; i++)
           for(int j = 0; j < NY; j++)
     	 dataOut[i][j] = i * NY + j;

        // Create the file. The Replace parameter tells netCDF to overwrite
        // this file, if it already exists.
        NcFile dataFile("simple_xy.nc", NcFile::Replace);

        // You should always check whether a netCDF file creation or open
        // constructor succeeded.
        if (!dataFile.is_valid())
        {
           cout << "Couldn't open file!\n";
           return NC_ERR;
        }

        // For other method calls, the default behavior of the C++ API is
        // to exit with a message if there is an error.  If that behavior
        // is OK, there is no need to check return values in simple cases
        // like the following.

        // When we create netCDF dimensions, we get back a pointer to an
        // NcDim for each one.
        NcDim* xDim = dataFile.add_dim("x", NX);
        NcDim* yDim = dataFile.add_dim("y", NY);

        // Define a netCDF variable. The type of the variable in this case
        // is ncInt (32-bit integer).
        NcVar *data = dataFile.add_var("data", ncInt, xDim, yDim);

        // Write the pretend data to the file. Although netCDF supports
        // reading and writing subsets of data, in this case we write all
        // the data in one operation.
        data->put(&dataOut[0][0], NX, NY);

        // The file will be automatically close when the NcFile object goes
        // out of scope. This frees up any internal netCDF resources
        // associated with the file, and flushes any buffers.
        cout << "*** SUCCESS writing example file simple_xy.nc!" << endl;

        return 0;
     }

2.1.4.2 simple_xy_rd.cpp
........................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This is a very simple example which reads a 2D array of
        sample data produced by simple_xy_wr.cpp.

        This example is part of the netCDF tutorial:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C++ API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx

        $Id: simple_xy_rd.cpp,v 1.13 2007/01/19 12:52:13 ed Exp $
     */

     #include <iostream>
     #include <netcdfcpp.h>

     using namespace std;

     // We are reading 2D data, a 6 x 12 grid.
     static const int NX = 6;
     static const int NY = 12;

     // Return this in event of a problem.
     static const int NC_ERR = 2;

     int main(void)
     {
        // This is the array we will read.
        int dataIn[NX][NY];

        // Open the file. The ReadOnly parameter tells netCDF we want
        // read-only access to the file.
        NcFile dataFile("simple_xy.nc", NcFile::ReadOnly);

        // You should always check whether a netCDF file open or creation
        // constructor succeeded.
        if (!dataFile.is_valid())
        {
           cout << "Couldn't open file!\n";
           return NC_ERR;
        }

        // For other method calls, the default behavior of the C++ API is
        // to exit with a message if there is an error.  If that behavior
        // is OK, there is no need to check return values in simple cases
        // like the following.

        // Retrieve the variable named "data"
        NcVar *data = dataFile.get_var("data");

        // Read all the values from the "data" variable into memory.
        data->get(&dataIn[0][0], NX, NY);

        // Check the values.
        for (int i = 0; i < NX; i++)
           for (int j = 0; j < NY; j++)
     	 if (dataIn[i][j] != i * NY + j)
     	    return NC_ERR;

        // The netCDF file is automatically closed by the NcFile destructor
        cout << "*** SUCCESS reading example file simple_xy.nc!" << endl;

        return 0;
     }

2.2 The sfc_pres_temp Example
=============================

This example has been constructed for the meteorological mind.

   Suppose you have some data you want to write to a netCDF file. For
example, you have one time step of surface temperature and surface
pressure, on a 6 x 12 latitude longitude grid.

   To store this in netCDF, create a file, add two dimensions (latitude
and longitude) and two variables (pressure and temperature).

   In this example we add some netCDF attributes, as is typical in
scientific applications, to further describe the data. In this case we
add a units attribute to every netCDF variable.

   In this example we also add additional netCDF variables to describe
the coordinate system. These "coordinate variables" allow us to specify
the latitudes and longitudes that describe the data grid.

   The CDL version of the data file, generated by ncdump, is shown
below.

   For more information on ncdump and ncgen see *Note NetCDF Utilities:
(netcdf)NetCDF Utilities.

     netcdf sfc_pres_temp {
     dimensions:
     	latitude = 6 ;
     	longitude = 12 ;
     variables:
     	float latitude(latitude) ;
     		latitude:units = "degrees_north" ;
     	float longitude(longitude) ;
     		longitude:units = "degrees_east" ;
     	float pressure(latitude, longitude) ;
     		pressure:units = "hPa" ;
     	float temperature(latitude, longitude) ;
     		temperature:units = "celsius" ;
     data:

      latitude = 25, 30, 35, 40, 45, 50 ;

      longitude = -125, -120, -115, -110, -105, -100, -95, -90, -85, -80, -75, -70 ;

      pressure =
       900, 906, 912, 918, 924, 930, 936, 942, 948, 954, 960, 966,
       901, 907, 913, 919, 925, 931, 937, 943, 949, 955, 961, 967,
       902, 908, 914, 920, 926, 932, 938, 944, 950, 956, 962, 968,
       903, 909, 915, 921, 927, 933, 939, 945, 951, 957, 963, 969,
       904, 910, 916, 922, 928, 934, 940, 946, 952, 958, 964, 970,
       905, 911, 917, 923, 929, 935, 941, 947, 953, 959, 965, 971 ;

      temperature =
       9, 10.5, 12, 13.5, 15, 16.5, 18, 19.5, 21, 22.5, 24, 25.5,
       9.25, 10.75, 12.25, 13.75, 15.25, 16.75, 18.25, 19.75, 21.25, 22.75, 24.25,
         25.75,
       9.5, 11, 12.5, 14, 15.5, 17, 18.5, 20, 21.5, 23, 24.5, 26,
       9.75, 11.25, 12.75, 14.25, 15.75, 17.25, 18.75, 20.25, 21.75, 23.25, 24.75,
         26.25,
       10, 11.5, 13, 14.5, 16, 17.5, 19, 20.5, 22, 23.5, 25, 26.5,
       10.25, 11.75, 13.25, 14.75, 16.25, 17.75, 19.25, 20.75, 22.25, 23.75,
         25.25, 26.75 ;
     }

2.2.1 sfc_pres_temp_wr.c and sfc_pres_temp_rd.c
-----------------------------------------------

These example programs can be found in the netCDF distribution, under
examples/C.

   The example program sfc_pres_temp_wr.c creates the example data file
sfc_pres_temp.nc. The example program sfc_pres_temp_rd.c reads the data
file.

2.2.1.1 sfc_pres_temp_wr.c
..........................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This example writes some surface pressure and temperatures. It is
        intended to illustrate the use of the netCDF C API. The companion
        program sfc_pres_temp_rd.c shows how to read the netCDF data file
        created by this program.

        This program is part of the netCDF tutorial:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c

        $Id: sfc_pres_temp_wr.c,v 1.3 2006/06/13 20:46:16 ed Exp $
     */

     #include <stdio.h>
     #include <string.h>
     #include <netcdf.h>

     /* This is the name of the data file we will create. */
     #define FILE_NAME "sfc_pres_temp.nc"

     /* We are writing 2D data, a 6 x 12 lat-lon grid. We will need two
      * netCDF dimensions. */
     #define NDIMS 2
     #define NLAT 6
     #define NLON 12
     #define LAT_NAME "latitude"
     #define LON_NAME "longitude"

     /* Names of things. */
     #define PRES_NAME "pressure"
     #define TEMP_NAME "temperature"
     #define UNITS "units"
     #define DEGREES_EAST "degrees_east"
     #define DEGREES_NORTH "degrees_north"

     /* These are used to construct some example data. */
     #define SAMPLE_PRESSURE 900
     #define SAMPLE_TEMP 9.0
     #define START_LAT 25.0
     #define START_LON -125.0

     /* Handle errors by printing an error message and exiting with a
      * non-zero status. */
     #define ERR(e) {printf("Error: %s\n", nc_strerror(e)); return 2;}

     int
     main()
     {
        int ncid, lon_dimid, lat_dimid, pres_varid, temp_varid;

     /* In addition to the latitude and longitude dimensions, we will also
        create latitude and longitude netCDF variables which will hold the
        actual latitudes and longitudes. Since they hold data about the
        coordinate system, the netCDF term for these is: "coordinate
        variables." */
        int lat_varid, lon_varid;

        int dimids[NDIMS];

        /* We will write surface temperature and pressure fields. */
        float pres_out[NLAT][NLON];
        float temp_out[NLAT][NLON];
        float lats[NLAT], lons[NLON];

        /* It's good practice for each netCDF variable to carry a "units"
         * attribute. */
        char pres_units[] = "hPa";
        char temp_units[] = "celsius";

        /* Loop indexes. */
        int lat, lon;

        /* Error handling. */
        int retval;

        /* Create some pretend data. If this wasn't an example program, we
         * would have some real data to write, for example, model
         * output. */
        for (lat = 0; lat < NLAT; lat++)
           lats[lat] = START_LAT + 5.*lat;
        for (lon = 0; lon < NLON; lon++)
           lons[lon] = START_LON + 5.*lon;

        for (lat = 0; lat < NLAT; lat++)
           for (lon = 0; lon < NLON; lon++)
           {
     	 pres_out[lat][lon] = SAMPLE_PRESSURE + (lon * NLAT + lat);
     	 temp_out[lat][lon] = SAMPLE_TEMP + .25 * (lon * NLAT + lat);
           }

        /* Create the file. */
        if ((retval = nc_create(FILE_NAME, NC_CLOBBER, &ncid)))
           ERR(retval);

        /* Define the dimensions. */
        if ((retval = nc_def_dim(ncid, LAT_NAME, NLAT, &lat_dimid)))
           ERR(retval);
        if ((retval = nc_def_dim(ncid, LON_NAME, NLON, &lon_dimid)))
           ERR(retval);

        /* Define coordinate netCDF variables. They will hold the
           coordinate information, that is, the latitudes and longitudes. A
           varid is returned for each.*/
        if ((retval = nc_def_var(ncid, LAT_NAME, NC_FLOAT, 1, &lat_dimid,
     			    &lat_varid)))
           ERR(retval);
        if ((retval = nc_def_var(ncid, LON_NAME, NC_FLOAT, 1, &lon_dimid,
     			    &lon_varid)))
           ERR(retval);

        /* Define units attributes for coordinate vars. This attaches a
           text attribute to each of the coordinate variables, containing
           the units. Note that we are not writing a trailing NULL, just
           "units", because the reading program may be fortran which does
           not use null-terminated strings. In general it is up to the
           reading C program to ensure that it puts null-terminators on
           strings where necessary.*/
        if ((retval = nc_put_att_text(ncid, lat_varid, UNITS,
     				 strlen(DEGREES_NORTH), DEGREES_NORTH)))
           ERR(retval);
        if ((retval = nc_put_att_text(ncid, lon_varid, UNITS,
     				 strlen(DEGREES_EAST), DEGREES_EAST)))
           ERR(retval);

        /* Define the netCDF variables. The dimids array is used to pass
           the dimids of the dimensions of the variables.*/
        dimids[0] = lat_dimid;
        dimids[1] = lon_dimid;
        if ((retval = nc_def_var(ncid, PRES_NAME, NC_FLOAT, NDIMS,
     			    dimids, &pres_varid)))
           ERR(retval);
        if ((retval = nc_def_var(ncid, TEMP_NAME, NC_FLOAT, NDIMS,
     			    dimids, &temp_varid)))
           ERR(retval);

        /* Define units attributes for vars. */
        if ((retval = nc_put_att_text(ncid, pres_varid, UNITS,
     				 strlen(pres_units), pres_units)))
           ERR(retval);
        if ((retval = nc_put_att_text(ncid, temp_varid, UNITS,
     				 strlen(temp_units), temp_units)))
           ERR(retval);

        /* End define mode. */
        if ((retval = nc_enddef(ncid)))
           ERR(retval);

        /* Write the coordinate variable data. This will put the latitudes
           and longitudes of our data grid into the netCDF file. */
        if ((retval = nc_put_var_float(ncid, lat_varid, &lats[0])))
           ERR(retval);
        if ((retval = nc_put_var_float(ncid, lon_varid, &lons[0])))
           ERR(retval);

        /* Write the pretend data. This will write our surface pressure and
           surface temperature data. The arrays of data are the same size
           as the netCDF variables we have defined. */
        if ((retval = nc_put_var_float(ncid, pres_varid, &pres_out[0][0])))
           ERR(retval);
        if ((retval = nc_put_var_float(ncid, temp_varid, &temp_out[0][0])))
           ERR(retval);

        /* Close the file. */
        if ((retval = nc_close(ncid)))
           ERR(retval);

        printf("*** SUCCESS writing example file sfc_pres_temp.nc!\n");
        return 0;
     }

2.2.1.2 sfc_pres_temp_rd.c
..........................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This is an example which reads some surface pressure and
        temperatures. The data file read by this program is produced by the
        companion program sfc_pres_temp_wr.c. It is intended to illustrate
        the use of the netCDF C API.

        This program is part of the netCDF tutorial:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c

        $Id: sfc_pres_temp_rd.c,v 1.5 2007/02/14 20:59:21 ed Exp $
     */

     #include <stdio.h>
     #include <string.h>
     #include <netcdf.h>

     /* This is the name of the data file we will read. */
     #define FILE_NAME "sfc_pres_temp.nc"

     /* We are reading 2D data, a 6 x 12 lat-lon grid. */
     #define NDIMS 2
     #define NLAT 6
     #define NLON 12

     #define LAT_NAME "latitude"
     #define LON_NAME "longitude"
     #define PRES_NAME "pressure"
     #define TEMP_NAME "temperature"

     /* These are used to calculate the values we expect to find. */
     #define SAMPLE_PRESSURE 900
     #define SAMPLE_TEMP 9.0
     #define START_LAT 25.0
     #define START_LON -125.0

     /* For the units attributes. */
     #define UNITS "units"
     #define PRES_UNITS "hPa"
     #define TEMP_UNITS "celsius"
     #define LAT_UNITS "degrees_north"
     #define LON_UNITS "degrees_east"
     #define MAX_ATT_LEN 80

     /* Handle errors by printing an error message and exiting with a
      * non-zero status. */
     #define ERR(e) {printf("Error: %s\n", nc_strerror(e)); return 2;}

     int
     main()
     {
        int ncid, pres_varid, temp_varid;
        int lat_varid, lon_varid;

        /* We will read surface temperature and pressure fields. */
        float pres_in[NLAT][NLON];
        float temp_in[NLAT][NLON];

        /* For the lat lon coordinate variables. */
        float lats_in[NLAT], lons_in[NLON];

        /* To check the units attributes. */
        char pres_units_in[MAX_ATT_LEN], temp_units_in[MAX_ATT_LEN];
        char lat_units_in[MAX_ATT_LEN], lon_units_in[MAX_ATT_LEN];

        /* We will learn about the data file and store results in these
           program variables. */
        int ndims_in, nvars_in, ngatts_in, unlimdimid_in;

        /* Loop indexes. */
        int lat, lon;

        /* Error handling. */
        int retval;

        /* Open the file. */
        if ((retval = nc_open(FILE_NAME, NC_NOWRITE, &ncid)))
           ERR(retval);

        /* There are a number of inquiry functions in netCDF which can be
           used to learn about an unknown netCDF file. NC_INQ tells how
           many netCDF variables, dimensions, and global attributes are in
           the file; also the dimension id of the unlimited dimension, if
           there is one. */
        if ((retval = nc_inq(ncid, &ndims_in, &nvars_in, &ngatts_in,
     			&unlimdimid_in)))
           ERR(retval);

        /* In this case we know that there are 2 netCDF dimensions, 4
           netCDF variables, no global attributes, and no unlimited
           dimension. */
        if (ndims_in != 2 || nvars_in != 4 || ngatts_in != 0 ||
            unlimdimid_in != -1) return 2;

        /* Get the varids of the latitude and longitude coordinate
         * variables. */
        if ((retval = nc_inq_varid(ncid, LAT_NAME, &lat_varid)))
           ERR(retval);
        if ((retval = nc_inq_varid(ncid, LON_NAME, &lon_varid)))
           ERR(retval);

        /* Read the coordinate variable data. */
        if ((retval = nc_get_var_float(ncid, lat_varid, &lats_in[0])))
           ERR(retval);
        if ((retval = nc_get_var_float(ncid, lon_varid, &lons_in[0])))
           ERR(retval);

        /* Check the coordinate variable data. */
        for (lat = 0; lat < NLAT; lat++)
           if (lats_in[lat] != START_LAT + 5.*lat)
     	 return 2;
        for (lon = 0; lon < NLON; lon++)
           if (lons_in[lon] != START_LON + 5.*lon)
     	 return 2;

        /* Get the varids of the pressure and temperature netCDF
         * variables. */
        if ((retval = nc_inq_varid(ncid, PRES_NAME, &pres_varid)))
           ERR(retval);
        if ((retval = nc_inq_varid(ncid, TEMP_NAME, &temp_varid)))
           ERR(retval);

        /* Read the data. Since we know the contents of the file we know
         * that the data arrays in this program are the correct size to
         * hold all the data. */
        if ((retval = nc_get_var_float(ncid, pres_varid, &pres_in[0][0])))
           ERR(retval);
        if ((retval = nc_get_var_float(ncid, temp_varid, &temp_in[0][0])))
           ERR(retval);

        /* Check the data. */
        for (lat = 0; lat < NLAT; lat++)
           for (lon = 0; lon < NLON; lon++)
     	 if (pres_in[lat][lon] != SAMPLE_PRESSURE + (lon * NLAT + lat) ||
     	     temp_in[lat][lon] != SAMPLE_TEMP + .25 * (lon * NLAT + lat))
     	    return 2;

        /* Each of the netCDF variables has a "units" attribute. Let's read
           them and check them. */
        if ((retval = nc_get_att_text(ncid, lat_varid, UNITS, lat_units_in)))
           ERR(retval);
        if (strncmp(lat_units_in, LAT_UNITS, strlen(LAT_UNITS)))
           return 2;

        if ((retval = nc_get_att_text(ncid, lon_varid, UNITS, lon_units_in)))
           ERR(retval);
        if (strncmp(lon_units_in, LON_UNITS, strlen(LON_UNITS)))
           return 2;

        if ((retval = nc_get_att_text(ncid, pres_varid, UNITS, pres_units_in)))
           ERR(retval);
        if (strncmp(pres_units_in, PRES_UNITS, strlen(PRES_UNITS)))
           return 2;

        if ((retval = nc_get_att_text(ncid, temp_varid, UNITS, temp_units_in)))
           ERR(retval);
        if (strncmp(temp_units_in, TEMP_UNITS, strlen(TEMP_UNITS))) return 2;

        /* Close the file. */
        if ((retval = nc_close(ncid)))
           ERR(retval);

        printf("*** SUCCESS reading example file sfc_pres_temp.nc!\n");
        return 0;
     }

2.2.2 sfc_pres_temp_wr.f and sfc_pres_temp_rd.f
-----------------------------------------------

These example programs can be found in the netCDF distribution, under
examples/F77.

   The example program sfc_pres_temp_wr.f creates the example data file
sfc_pres_temp.nc. The example program sfc_pres_temp_rd.f reads the data
file.

2.2.2.1 sfc_pres_temp_wr.f
..........................

     C     This is part of the netCDF package.
     C     Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     C     See COPYRIGHT file for conditions of use.

     C     This example writes some surface pressure and temperatures. It is
     C     intended to illustrate the use of the netCDF fortran 77 API. The
     C     companion program sfc_pres_temp_rd.f shows how to read the netCDF
     C     data file created by this program.

     C     This program is part of the netCDF tutorial:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     C     Full documentation of the netCDF Fortran 77 API can be found at:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f77

     C     $Id: sfc_pres_temp_wr.f,v 1.10 2007/02/14 20:59:20 ed Exp $

           program sfc_pres_temp_wr
           implicit none
           include 'netcdf.inc'

     C     This is the name of the data file we will create.
           character*(*) FILE_NAME
           parameter (FILE_NAME='sfc_pres_temp.nc')
           integer ncid

     C     We are writing 2D data, a 12 x 6 lon-lat grid. We will need two
     C     netCDF dimensions.
           integer NDIMS
           parameter (NDIMS=2)
           integer NLATS, NLONS
           parameter (NLATS = 6, NLONS = 12)
           character*(*) LAT_NAME, LON_NAME
           parameter (LAT_NAME='latitude', LON_NAME='longitude')
           integer lon_dimid, lat_dimid

     C     In addition to the latitude and longitude dimensions, we will also
     C     create latitude and longitude netCDF variables which will hold the
     C     actual latitudes and longitudes. Since they hold data about the
     C     coordinate system, the netCDF term for these is: "coordinate
     C     variables."
           real lats(NLATS), lons(NLONS)
           integer lat_varid, lon_varid
           real START_LAT, START_LON
           parameter (START_LAT = 25.0, START_LON = -125.0)

     C     We will write surface temperature and pressure fields.
           character*(*) PRES_NAME, TEMP_NAME
           parameter (PRES_NAME='pressure')
           parameter (TEMP_NAME='temperature')
           integer pres_varid, temp_varid
           integer dimids(NDIMS)

     C     It's good practice for each variable to carry a "units" attribute.
           character*(*) UNITS
           parameter (UNITS = 'units')
           character*(*) PRES_UNITS, TEMP_UNITS, LAT_UNITS, LON_UNITS
           parameter (PRES_UNITS = 'hPa', TEMP_UNITS = 'celsius')
           parameter (LAT_UNITS = 'degrees_north')
           parameter (LON_UNITS = 'degrees_east')

     C     We will create some pressure and temperature data to write out.
           real pres_out(NLONS, NLATS), temp_out(NLONS, NLATS)
           real SAMPLE_PRESSURE
           parameter (SAMPLE_PRESSURE = 900.0)
           real SAMPLE_TEMP
           parameter (SAMPLE_TEMP = 9.0)

     C     Loop indices.
           integer lat, lon

     C     Error handling.
           integer retval

     C     Create pretend data. If this were not an example program, we would
     C     have some real data to write, for example, model output.
           do lat = 1, NLATS
              lats(lat) = START_LAT + (lat - 1) * 5.0
           end do
           do lon = 1, NLONS
              lons(lon) = START_LON + (lon - 1) * 5.0
           end do
           do lon = 1, NLONS
              do lat = 1, NLATS
                 pres_out(lon, lat) = SAMPLE_PRESSURE +
          +           (lon - 1) * NLATS + (lat - 1)
                 temp_out(lon, lat) = SAMPLE_TEMP +
          +           .25 * ((lon - 1) * NLATS + (lat - 1))
              end do
           end do

     C     Create the file.
           retval = nf_create(FILE_NAME, nf_clobber, ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Define the dimensions.
           retval = nf_def_dim(ncid, LAT_NAME, NLATS, lat_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_dim(ncid, LON_NAME, NLONS, lon_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Define the coordinate variables. They will hold the coordinate
     C     information, that is, the latitudes and longitudes. A varid is
     C     returned for each.
           retval = nf_def_var(ncid, LAT_NAME, NF_REAL, 1, lat_dimid,
          +     lat_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_var(ncid, LON_NAME, NF_REAL, 1, lon_dimid,
          +     lon_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Assign units attributes to coordinate var data. This attaches a
     C     text attribute to each of the coordinate variables, containing the
     C     units.
           retval = nf_put_att_text(ncid, lat_varid, UNITS, len(LAT_UNITS),
          +     LAT_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_put_att_text(ncid, lon_varid, UNITS, len(LON_UNITS),
          +     LON_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Define the netCDF variables. The dimids array is used to pass the
     C     dimids of the dimensions of the netCDF variables.
           dimids(1) = lon_dimid
           dimids(2) = lat_dimid
           retval = nf_def_var(ncid, PRES_NAME, NF_REAL, NDIMS, dimids,
          +     pres_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_var(ncid, TEMP_NAME, NF_REAL, NDIMS, dimids,
          +     temp_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Assign units attributes to the pressure and temperature netCDF
     C     variables.
           retval = nf_put_att_text(ncid, pres_varid, UNITS, len(PRES_UNITS),
          +     PRES_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_put_att_text(ncid, temp_varid, UNITS, len(TEMP_UNITS),
          +     TEMP_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     End define mode.
           retval = nf_enddef(ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Write the coordinate variable data. This will put the latitudes
     C     and longitudes of our data grid into the netCDF file.
           retval = nf_put_var_real(ncid, lat_varid, lats)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_put_var_real(ncid, lon_varid, lons)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Write the pretend data. This will write our surface pressure and
     C     surface temperature data. The arrays of data are the same size as
     C     the netCDF variables we have defined.
           retval = nf_put_var_real(ncid, pres_varid, pres_out)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_put_var_real(ncid, temp_varid, temp_out)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Close the file.
           retval = nf_close(ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     If we got this far, everything worked as expected. Yipee!
           print *,'*** SUCCESS writing example file sfc_pres_temp.nc!'
           end

           subroutine handle_err(errcode)
           implicit none
           include 'netcdf.inc'
           integer errcode

           print *, 'Error: ', nf_strerror(errcode)
           stop 2
           end

2.2.2.2 sfc_pres_temp_rd.f
..........................

     C     This is part of the netCDF package.
     C     Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     C     See COPYRIGHT file for conditions of use.

     C     This is an example which reads some surface pressure and
     C     temperatures. The data file read by this program is produced
     C     comapnion program sfc_pres_temp_wr.f. It is intended to illustrate
     C     the use of the netCDF fortran 77 API.

     C     This program is part of the netCDF tutorial:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     C     Full documentation of the netCDF Fortran 77 API can be found at:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f77

     C     $Id: sfc_pres_temp_rd.f,v 1.9 2007/02/14 20:59:20 ed Exp $

           program sfc_pres_temp_rd
           implicit none
           include 'netcdf.inc'

     C     This is the name of the data file we will read.
           character*(*) FILE_NAME
           parameter (FILE_NAME='sfc_pres_temp.nc')
           integer ncid

     C     We are reading 2D data, a 12 x 6 lon-lat grid.
           integer NDIMS
           parameter (NDIMS=2)
           integer NLATS, NLONS
           parameter (NLATS = 6, NLONS = 12)
           character*(*) LAT_NAME, LON_NAME
           parameter (LAT_NAME='latitude', LON_NAME='longitude')
           integer lat_dimid, lon_dimid

     C     For the lat lon coordinate netCDF variables.
           real lats(NLATS), lons(NLONS)
           integer lat_varid, lon_varid

     C     We will read surface temperature and pressure fields.
           character*(*) PRES_NAME, TEMP_NAME
           parameter (PRES_NAME='pressure')
           parameter (TEMP_NAME='temperature')
           integer pres_varid, temp_varid
           integer dimids(NDIMS)

     C     To check the units attributes.
           character*(*) UNITS
           parameter (UNITS = 'units')
           character*(*) PRES_UNITS, TEMP_UNITS, LAT_UNITS, LON_UNITS
           parameter (PRES_UNITS = 'hPa', TEMP_UNITS = 'celsius')
           parameter (LAT_UNITS = 'degrees_north')
           parameter (LON_UNITS = 'degrees_east')
           integer MAX_ATT_LEN
           parameter (MAX_ATT_LEN = 80)
           character*(MAX_ATT_LEN) pres_units_in, temp_units_in
           character*(MAX_ATT_LEN) lat_units_in, lon_units_in
           integer att_len

     C     Read the data into these arrays.
           real pres_in(NLONS, NLATS), temp_in(NLONS, NLATS)

     C     These are used to calculate the values we expect to find.
           real START_LAT, START_LON
           parameter (START_LAT = 25.0, START_LON = -125.0)
           real SAMPLE_PRESSURE
           parameter (SAMPLE_PRESSURE = 900.0)
           real SAMPLE_TEMP
           parameter (SAMPLE_TEMP = 9.0)

     C     We will learn about the data file and store results in these
     C     program variables.
           integer ndims_in, nvars_in, ngatts_in, unlimdimid_in

     C     Loop indices
           integer lat, lon

     C     Error handling
           integer retval

     C     Open the file.
           retval = nf_open(FILE_NAME, nf_nowrite, ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     There are a number of inquiry functions in netCDF which can be
     C     used to learn about an unknown netCDF file. NF_INQ tells how many
     C     netCDF variables, dimensions, and global attributes are in the
     C     file; also the dimension id of the unlimited dimension, if there
     C     is one.
           retval = nf_inq(ncid, ndims_in, nvars_in, ngatts_in,
          +     unlimdimid_in)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     In this case we know that there are 2 netCDF dimensions, 4 netCDF
     C     variables, no global attributes, and no unlimited dimension.
           if (ndims_in .ne. 2 .or. nvars_in .ne. 4 .or. ngatts_in .ne. 0
          +     .or. unlimdimid_in .ne. -1) stop 2

     C     Get the varids of the latitude and longitude coordinate variables.
           retval = nf_inq_varid(ncid, LAT_NAME, lat_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_inq_varid(ncid, LON_NAME, lon_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Read the latitude and longitude data.
           retval = nf_get_var_real(ncid, lat_varid, lats)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_get_var_real(ncid, lon_varid, lons)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Check to make sure we got what we expected.
           do lat = 1, NLATS
              if (lats(lat) .ne. START_LAT + (lat - 1) * 5.0) stop 2
           end do
           do lon = 1, NLONS
              if (lons(lon) .ne. START_LON + (lon - 1) * 5.0) stop 2
           end do

     C     Get the varids of the pressure and temperature netCDF variables.
           retval = nf_inq_varid(ncid, PRES_NAME, pres_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_inq_varid(ncid, TEMP_NAME, temp_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Read the surface pressure and temperature data from the file.
     C     Since we know the contents of the file we know that the data
     C     arrays in this program are the correct size to hold all the data.
           retval = nf_get_var_real(ncid, pres_varid, pres_in)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_get_var_real(ncid, temp_varid, temp_in)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Check the data. It should be the same as the data we wrote.
           do lon = 1, NLONS
              do lat = 1, NLATS
                  if (pres_in(lon, lat) .ne. SAMPLE_PRESSURE +
          +           (lon - 1) * NLATS + (lat - 1)) stop 2
                  if (temp_in(lon, lat) .ne. SAMPLE_TEMP +
          +           .25 * ((lon - 1) * NLATS + (lat - 1))) stop 2
              end do
           end do

     C     Each of the netCDF variables has a "units" attribute. Let's read
     C     them and check them.

           retval = nf_get_att_text(ncid, lat_varid, UNITS, lat_units_in)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_inq_attlen(ncid, lat_varid, UNITS, att_len)
           if (retval .ne. nf_noerr) call handle_err(retval)
           if (lat_units_in(1:att_len) .ne. LAT_UNITS) stop 2

           retval = nf_get_att_text(ncid, lon_varid, UNITS, lon_units_in)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_inq_attlen(ncid, lon_varid, UNITS, att_len)
           if (retval .ne. nf_noerr) call handle_err(retval)
           if (lon_units_in(1:att_len) .ne. LON_UNITS) stop 2

           retval = nf_get_att_text(ncid, pres_varid, UNITS, pres_units_in)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_inq_attlen(ncid, pres_varid, UNITS, att_len)
           if (retval .ne. nf_noerr) call handle_err(retval)
           if (pres_units_in(1:att_len) .ne. PRES_UNITS) stop 2

           retval = nf_get_att_text(ncid, temp_varid, UNITS, temp_units_in)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_inq_attlen(ncid, temp_varid, UNITS, att_len)
           if (retval .ne. nf_noerr) call handle_err(retval)
           if (temp_units_in(1:att_len) .ne. TEMP_UNITS) stop 2

     C     Close the file. This frees up any internal netCDF resources
     C     associated with the file.
           retval = nf_close(ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     If we got this far, everything worked as expected. Yipee!
           print *,'*** SUCCESS reading example file sfc_pres_temp.nc!'
           end

           subroutine handle_err(errcode)
           implicit none
           include 'netcdf.inc'
           integer errcode

           print *, 'Error: ', nf_strerror(errcode)
           stop 2
           end

2.2.3 sfc_pres_temp_wr.f90 and sfc_pres_temp_rd.f90
---------------------------------------------------

These example programs can be found in the netCDF distribution, under
examples/F90.

   The example program sfc_pres_temp_wr.f90 creates the example data
file sfc_pres_temp.nc. The example program sfc_pres_temp_rd.f90 reads
the data file.

2.2.3.1 sfc_pres_temp_wr.f90
............................

     ! This is part of the netCDF package.
     ! Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     ! See COPYRIGHT file for conditions of use.

     ! This example writes some surface pressure and temperatures. It is
     ! intended to illustrate the use of the netCDF fortran 90 API. The
     ! companion program sfc_pres_temp_rd.f90 shows how to read the netCDF
     ! data file created by this program.

     ! This program is part of the netCDF tutorial:
     ! http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     ! Full documentation of the netCDF Fortran 90 API can be found at:
     ! http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f90

     ! $Id: sfc_pres_temp_wr.f90,v 1.10 2007/02/14 20:59:20 ed Exp $

     program sfc_pres_temp_wr
       use netcdf
       implicit none

       ! This is the name of the data file we will create.
       character (len = *), parameter :: FILE_NAME = "sfc_pres_temp.nc"
       integer :: ncid

       ! We are writing 2D data, a 12 x 6 lon-lat grid. We will need two
       ! netCDF dimensions.
       integer, parameter :: NDIMS = 2
       integer, parameter :: NLATS = 6, NLONS = 12
       character (len = *), parameter :: LAT_NAME = "latitude"
       character (len = *), parameter :: LON_NAME = "longitude"
       integer :: lat_dimid, lon_dimid

       ! In addition to the latitude and longitude dimensions, we will also
       ! create latitude and longitude netCDF variables which will hold the
       ! actual latitudes and longitudes. Since they hold data about the
       ! coordinate system, the netCDF term for these is: "coordinate
       ! variables."
       real :: lats(NLATS), lons(NLONS)
       integer :: lat_varid, lon_varid
       real, parameter :: START_LAT = 25.0, START_LON = -125.0

       ! We will write surface temperature and pressure fields.
       character (len = *), parameter :: PRES_NAME="pressure"
       character (len = *), parameter :: TEMP_NAME="temperature"
       integer :: pres_varid, temp_varid
       integer :: dimids(NDIMS)

       ! It's good practice for each variable to carry a "units" attribute.
       character (len = *), parameter :: UNITS = "units"
       character (len = *), parameter :: PRES_UNITS = "hPa"
       character (len = *), parameter :: TEMP_UNITS = "celsius"
       character (len = *), parameter :: LAT_UNITS = "degrees_north"
       character (len = *), parameter :: LON_UNITS = "degrees_east"

       ! We will create some pressure and temperature data to write out.
       real :: pres_out(NLONS, NLATS), temp_out(NLONS, NLATS)
       real, parameter :: SAMPLE_PRESSURE = 900.0
       real, parameter :: SAMPLE_TEMP = 9.0

       ! Loop indices
       integer :: lat, lon

       ! Create pretend data. If this were not an example program, we would
       ! have some real data to write, for example, model output.
       do lat = 1, NLATS
          lats(lat) = START_LAT + (lat - 1) * 5.0
       end do
       do lon = 1, NLONS
          lons(lon) = START_LON + (lon - 1) * 5.0
       end do
       do lon = 1, NLONS
          do lat = 1, NLATS
             pres_out(lon, lat) = SAMPLE_PRESSURE + (lon - 1) * NLATS + (lat - 1)
             temp_out(lon, lat) = SAMPLE_TEMP + .25 * ((lon - 1) * NLATS + (lat - 1))
          end do
       end do

       ! Create the file.
       call check( nf90_create(FILE_NAME, nf90_clobber, ncid) )

       ! Define the dimensions.
       call check( nf90_def_dim(ncid, LAT_NAME, NLATS, lat_dimid) )
       call check( nf90_def_dim(ncid, LON_NAME, NLONS, lon_dimid) )

       ! Define the coordinate variables. They will hold the coordinate
       ! information, that is, the latitudes and longitudes. A varid is
       ! returned for each.
       call check( nf90_def_var(ncid, LAT_NAME, NF90_REAL, lat_dimid, lat_varid) )
       call check( nf90_def_var(ncid, LON_NAME, NF90_REAL, lon_dimid, lon_varid) )

       ! Assign units attributes to coordinate var data. This attaches a
       ! text attribute to each of the coordinate variables, containing the
       ! units.
       call check( nf90_put_att(ncid, lat_varid, UNITS, LAT_UNITS) )
       call check( nf90_put_att(ncid, lon_varid, UNITS, LON_UNITS) )

       ! Define the netCDF variables. The dimids array is used to pass the
       ! dimids of the dimensions of the netCDF variables.
       dimids = (/ lon_dimid, lat_dimid /)
       call check( nf90_def_var(ncid, PRES_NAME, NF90_REAL, dimids, pres_varid) )
       call check( nf90_def_var(ncid, TEMP_NAME, NF90_REAL, dimids, temp_varid) )

       ! Assign units attributes to the pressure and temperature netCDF
       ! variables.
       call check( nf90_put_att(ncid, pres_varid, UNITS, PRES_UNITS) )
       call check( nf90_put_att(ncid, temp_varid, UNITS, TEMP_UNITS) )

       ! End define mode.
       call check( nf90_enddef(ncid) )

       ! Write the coordinate variable data. This will put the latitudes
       ! and longitudes of our data grid into the netCDF file.
       call check( nf90_put_var(ncid, lat_varid, lats) )
       call check( nf90_put_var(ncid, lon_varid, lons) )

       ! Write the pretend data. This will write our surface pressure and
       ! surface temperature data. The arrays of data are the same size as
       ! the netCDF variables we have defined.
       call check( nf90_put_var(ncid, pres_varid, pres_out) )
       call check( nf90_put_var(ncid, temp_varid, temp_out) )

       ! Close the file.
       call check( nf90_close(ncid) )

       ! If we got this far, everything worked as expected. Yipee!
       print *,"*** SUCCESS writing example file sfc_pres_temp.nc!"

     contains
       subroutine check(status)
         integer, intent ( in) :: status

         if(status /= nf90_noerr) then
           print *, trim(nf90_strerror(status))
           stop "Stopped"
         end if
       end subroutine check
     end program sfc_pres_temp_wr

2.2.3.2 sfc_pres_temp_rd.f90
............................

     ! This is part of the netCDF package.
     ! Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     ! See COPYRIGHT file for conditions of use.

     ! This is an example which reads some surface pressure and
     ! temperatures. The data file read by this program is produced
     ! comapnion program sfc_pres_temp_wr.f90. It is intended to illustrate
     ! the use of the netCDF fortran 90 API.

     ! This program is part of the netCDF tutorial:
     ! http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     ! Full documentation of the netCDF Fortran 90 API can be found at:
     ! http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f90

     ! $Id: sfc_pres_temp_rd.f90,v 1.8 2007/02/14 20:59:20 ed Exp $

     program sfc_pres_temp_rd
       use netcdf
       implicit none

       ! This is the name of the data file we will read.
       character (len = *), parameter :: FILE_NAME = "sfc_pres_temp.nc"
       integer :: ncid

       ! We are reading 2D data, a 12 x 6 lon-lat grid.
       integer, parameter :: NDIMS = 2
       integer, parameter :: NLATS = 6, NLONS = 12
       character (len = *), parameter :: LAT_NAME = "latitude"
       character (len = *), parameter :: LON_NAME = "longitude"
       integer :: lat_dimid, lon_dimid

       ! For the lat lon coordinate netCDF variables.
       real :: lats(NLATS), lons(NLONS)
       integer :: lat_varid, lon_varid

       ! We will read surface temperature and pressure fields.
       character (len = *), parameter :: PRES_NAME = "pressure"
       character (len = *), parameter :: TEMP_NAME = "temperature"
       integer :: pres_varid, temp_varid
       integer :: dimids(NDIMS)

       ! To check the units attributes.
       character (len = *), parameter :: UNITS = "units"
       character (len = *), parameter :: PRES_UNITS = "hPa"
       character (len = *), parameter :: TEMP_UNITS = "celsius"
       character (len = *), parameter :: LAT_UNITS = "degrees_north"
       character (len = *), parameter :: LON_UNITS = "degrees_east"
       integer, parameter :: MAX_ATT_LEN = 80
       integer :: att_len
       character*(MAX_ATT_LEN) :: pres_units_in, temp_units_in
       character*(MAX_ATT_LEN) :: lat_units_in, lon_units_in

       ! Read the data into these arrays.
       real :: pres_in(NLONS, NLATS), temp_in(NLONS, NLATS)

       ! These are used to calculate the values we expect to find.
       real, parameter :: START_LAT = 25.0, START_LON = -125.0
       real, parameter :: SAMPLE_PRESSURE = 900.0
       real, parameter :: SAMPLE_TEMP = 9.0

       ! We will learn about the data file and store results in these
       ! program variables.
       integer :: ndims_in, nvars_in, ngatts_in, unlimdimid_in

       ! Loop indices
       integer :: lat, lon

       ! Open the file.
       call check( nf90_open(FILE_NAME, nf90_nowrite, ncid) )

       ! There are a number of inquiry functions in netCDF which can be
       ! used to learn about an unknown netCDF file. NF90_INQ tells how many
       ! netCDF variables, dimensions, and global attributes are in the
       ! file; also the dimension id of the unlimited dimension, if there
       ! is one.
       call check( nf90_inquire(ncid, ndims_in, nvars_in, ngatts_in, unlimdimid_in) )

       ! In this case we know that there are 2 netCDF dimensions, 4 netCDF
       ! variables, no global attributes, and no unlimited dimension.
       if (ndims_in /= 2 .or. nvars_in /= 4 .or. ngatts_in /= 0 &
            .or. unlimdimid_in /= -1) stop 2

       ! Get the varids of the latitude and longitude coordinate variables.
       call check( nf90_inq_varid(ncid, LAT_NAME, lat_varid) )
       call check( nf90_inq_varid(ncid, LON_NAME, lon_varid) )

       ! Read the latitude and longitude data.
       call check( nf90_get_var(ncid, lat_varid, lats) )
       call check( nf90_get_var(ncid, lon_varid, lons) )

       ! Check to make sure we got what we expected.
       do lat = 1, NLATS
          if (lats(lat) /= START_LAT + (lat - 1) * 5.0) stop 2
       end do
       do lon = 1, NLONS
          if (lons(lon) /= START_LON + (lon - 1) * 5.0) stop 2
       end do

       ! Get the varids of the pressure and temperature netCDF variables.
       call check( nf90_inq_varid(ncid, PRES_NAME, pres_varid) )
       call check( nf90_inq_varid(ncid, TEMP_NAME, temp_varid) )

       ! Read the surface pressure and temperature data from the file.
       ! Since we know the contents of the file we know that the data
       ! arrays in this program are the correct size to hold all the data.
       call check( nf90_get_var(ncid, pres_varid, pres_in) )
       call check( nf90_get_var(ncid, temp_varid, temp_in) )

       ! Check the data. It should be the same as the data we wrote.
       do lon = 1, NLONS
          do lat = 1, NLATS
             if (pres_in(lon, lat) /= SAMPLE_PRESSURE + &
                  (lon - 1) * NLATS + (lat - 1)) stop 2
             if (temp_in(lon, lat) /= SAMPLE_TEMP + &
                  .25 * ((lon - 1) * NLATS + (lat - 1))) stop 2
          end do
       end do

       ! Each of the netCDF variables has a "units" attribute. Let's read
       ! them and check them.
       call check( nf90_get_att(ncid, lat_varid, UNITS, lat_units_in) )
       call check( nf90_inquire_attribute(ncid, lat_varid, UNITS, len = att_len) )
       if (lat_units_in(1:att_len) /= LAT_UNITS) stop 2

       call check( nf90_get_att(ncid, lon_varid, UNITS, lon_units_in) )
       call check( nf90_inquire_attribute(ncid, lon_varid, UNITS, len = att_len) )
       if (lon_units_in(1:att_len) /= LON_UNITS) stop 2

       call check( nf90_get_att(ncid, pres_varid, UNITS, pres_units_in) )
       call check( nf90_inquire_attribute(ncid, pres_varid, UNITS, len = att_len) )
       if (pres_units_in(1:att_len) /= PRES_UNITS) stop 2

       call check( nf90_get_att(ncid, temp_varid, UNITS, temp_units_in) )
       call check( nf90_inquire_attribute(ncid, temp_varid, UNITS, len = att_len) )
       if (temp_units_in(1:att_len) /= TEMP_UNITS) stop 2

       ! Close the file. This frees up any internal netCDF resources
       ! associated with the file.
       call check( nf90_close(ncid) )

       ! If we got this far, everything worked as expected. Yipee!
       print *,"*** SUCCESS reading example file sfc_pres_temp.nc!"

     contains
       subroutine check(status)
         integer, intent ( in) :: status

         if(status /= nf90_noerr) then
           print *, trim(nf90_strerror(status))
           stop "Stopped"
         end if
       end subroutine check
     end program sfc_pres_temp_rd

2.2.4 sfc_pres_temp_wr.cpp and sfc_pres_temp_rd.cpp
---------------------------------------------------

These example programs can be found in the netCDF distribution, under
examples/CXX.

   The example program sfc_pres_temp_wr.cpp creates the example data
file sfc_pres_temp.nc. The example program sfc_pres_temp_rd.cpp reads
the data file.

2.2.4.1 sfc_pres_temp_wr.cpp
............................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This example writes some surface pressure and temperatures. It is
        intended to illustrate the use of the netCDF C++ API. The companion
        program sfc_pres_temp_rd.cpp shows how to read the netCDF data file
        created by this program.

        This program is part of the netCDF tutorial:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C++ API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx

        $Id: sfc_pres_temp_wr.cpp,v 1.12 2007/01/19 12:52:13 ed Exp $
     */

     #include <iostream>
     #include <netcdfcpp.h>

     using namespace std;

     // We are writing 2D data, a 6 x 12 lat-lon grid. We will need two
     // netCDF dimensions.
     static const int NLAT = 6;
     static const int NLON = 12;

     // These are used to construct some example data.
     static const float SAMPLE_PRESSURE = 900;
     static const float SAMPLE_TEMP = 9.0;
     static const float START_LAT = 25.0;
     static const float START_LON = -125.0;

     // Return this to OS if there is a failure.
     static const int NC_ERR = 2;

     int main(void)
     {
        // These will hold our pressure and temperature data.
        float presOut[NLAT][NLON];
        float tempOut[NLAT][NLON];

        // These will hold our latitudes and longitudes.
        float lats[NLAT];
        float lons[NLON];

        // Create some pretend data. If this wasn't an example program, we
        // would have some real data to write, for example, model
        // output.
        for(int lat = 0; lat < NLAT; lat++)
           lats[lat] = START_LAT + 5. * lat;

        for(int lon = 0; lon < NLON; lon++)
           lons[lon] = START_LON + 5. * lon;

        for (int lat = 0; lat < NLAT; lat++)
           for(int lon = 0; lon < NLON; lon++)
           {
     	 presOut[lat][lon] = SAMPLE_PRESSURE + (lon * NLAT + lat);
     	 tempOut[lat][lon] = SAMPLE_TEMP + .25 * (lon * NLAT + lat);
           }

        // Change the error behavior of the netCDF C++ API by creating an
        // NcError object. Until it is destroyed, this NcError object will
        // ensure that the netCDF C++ API silently returns error codes
        // on any failure, and leaves any other error handling to the
        // calling program. In the case of this example, we just exit with
        // an NC_ERR error code.
        NcError err(NcError::silent_nonfatal);

        // Create the file. The Replace parameter tells netCDF to overwrite
        // this file, if it already exists.
        NcFile dataFile("sfc_pres_temp.nc", NcFile::Replace);

        // Check to see if the file was created.
        if(!dataFile.is_valid())
           return NC_ERR;

        // Define the dimensions. NetCDF will hand back an ncDim object for
        // each.
        NcDim *latDim, *lonDim;
        if (!(latDim = dataFile.add_dim("latitude", NLAT)))
           return NC_ERR;
        if (!(lonDim = dataFile.add_dim("longitude", NLON)))
           return NC_ERR;

        // In addition to the latitude and longitude dimensions, we will
        // also create latitude and longitude netCDF variables which will
        // hold the actual latitudes and longitudes. Since they hold data
        // about the coordinate system, the netCDF term for these is:
        // "coordinate variables."
        NcVar *latVar, *lonVar;
        if (!(latVar = dataFile.add_var("latitude", ncFloat, latDim)))
           return NC_ERR;
        if (!(lonVar = dataFile.add_var("longitude", ncFloat, lonDim)))
           return NC_ERR;

        // Define units attributes for coordinate vars. This attaches a
        // text attribute to each of the coordinate variables, containing
        // the units.
        if (!lonVar->add_att("units", "degrees_east"))
           return NC_ERR;
        if (!latVar->add_att("units", "degrees_north"))
           return NC_ERR;

        // Define the netCDF data variables.
        NcVar *presVar, *tempVar;
        if (!(presVar = dataFile.add_var("pressure", ncFloat, latDim, lonDim)))
           return NC_ERR;
        if (!(tempVar = dataFile.add_var("temperature", ncFloat, latDim, lonDim)))
           return NC_ERR;

        // Define units attributes for variables.
        if (!presVar->add_att("units", "hPa"))
           return NC_ERR;
        if (!tempVar->add_att("units", "celsius"))
           return NC_ERR;

        // Write the coordinate variable data. This will put the latitudes
        // and longitudes of our data grid into the netCDF file.
        if (!latVar->put(lats, NLAT))
           return NC_ERR;
        if (!lonVar->put(lons, NLON))
           return NC_ERR;

        // Write the pretend data. This will write our surface pressure and
        // surface temperature data. The arrays of data are the same size
        // as the netCDF variables we have defined, and below we write them
        // each in one step.
        if (!presVar->put(&presOut[0][0], NLAT, NLON))
           return NC_ERR;
        if (!tempVar->put(&tempOut[0][0], NLAT, NLON))
           return NC_ERR;

        // The file is automatically closed by the destructor. This frees
        // up any internal netCDF resources associated with the file, and
        // flushes any buffers.
        cout << "*** SUCCESS writing example file sfc_pres_temp.nc!" << endl;

        return 0;
     }

2.2.4.2 sfc_pres_temp_rd.cpp
............................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This is an example which reads some surface pressure and
        temperatures. The data file read by this program is produced
        companion program sfc_pres_temp_wr.cxx. It is intended to
        illustrate the use of the netCDF C++ API.

        This program is part of the netCDF tutorial:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C++ API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx

        $Id: sfc_pres_temp_rd.cpp,v 1.16 2007/01/19 12:52:13 ed Exp $
     */

     #include <iostream>
     #include <netcdfcpp.h>

     using namespace std;

     // We are reading 2D data, a 6 x 12 lat-lon grid.
     static const int NLAT = 6;
     static const int NLON = 12;

     // These are used to calculate the values we expect to find.
     static const float SAMPLE_PRESSURE = 900;
     static const float SAMPLE_TEMP = 9.0;
     static const float START_LAT = 25.0;
     static const float START_LON = -125.0;

     // Return this code to the OS in case of failure.
     static const int NC_ERR = 2;

     int main(void)
     {
        // These will hold our pressure and temperature data.
        float presIn[NLAT][NLON];
        float tempIn[NLAT][NLON];

        // These will hold our latitudes and longitudes.
        float latsIn[NLAT];
        float lonsIn[NLON];

        // Change the error behavior of the netCDF C++ API by creating an
        // NcError object. Until it is destroyed, this NcError object will
        // ensure that the netCDF C++ API silently returns error codes on
        // any failure, and leaves any other error handling to the calling
        // program. In the case of this example, we just exit with an
        // NC_ERR error code.
        NcError err(NcError::silent_nonfatal);

        // Open the file and check to make sure it's valid.
        NcFile dataFile("sfc_pres_temp.nc", NcFile::ReadOnly);
        if(!dataFile.is_valid())
           return NC_ERR;

        // There are a number of inquiry functions in netCDF which can be
        // used to learn about an unknown netCDF file. In this case we know
        // that there are 2 netCDF dimensions, 4 netCDF variables, no
        // global attributes, and no unlimited dimension.
        if (dataFile.num_dims() != 2 || dataFile.num_vars() != 4 ||
            dataFile.num_atts() != 0 || dataFile.rec_dim() != 0)
           return NC_ERR;

        // We get back a pointer to each NcVar we request. Get the
        // latitude and longitude coordinate variables.
        NcVar *latVar, *lonVar;
        if (!(latVar = dataFile.get_var("latitude")))
           return NC_ERR;
        if (!(lonVar = dataFile.get_var("longitude")))
           return NC_ERR;

        // Read the latitude and longitude coordinate variables into arrays
        // latsIn and lonsIn.
        if (!latVar->get(latsIn, NLAT))
           return NC_ERR;
        if (!lonVar->get(lonsIn, NLON))
           return NC_ERR;

        // Check the coordinate variable data.
        for(int lat = 0; lat < NLAT; lat++)
           if (latsIn[lat] != START_LAT + 5. * lat)
     	 return NC_ERR;

        // Check longitude values.
        for (int lon = 0; lon < NLON; lon++)
           if (lonsIn[lon] != START_LON + 5. * lon)
     	 return NC_ERR;

        // We get back a pointer to each NcVar we request.
        NcVar *presVar, *tempVar;
        if (!(presVar = dataFile.get_var("pressure")))
           return NC_ERR;
        if (!(tempVar = dataFile.get_var("temperature")))
           return NC_ERR;

        // Read the data. Since we know the contents of the file we know
        // that the data arrays in this program are the correct size to
        // hold all the data.
        if (!presVar->get(&presIn[0][0], NLAT, NLON))
           return NC_ERR;
        if (!tempVar->get(&tempIn[0][0], NLAT, NLON))
           return NC_ERR;

        // Check the data.
        for (int lat = 0; lat < NLAT; lat++)
           for (int lon = 0; lon < NLON; lon++)
     	 if (presIn[lat][lon] != SAMPLE_PRESSURE + (lon * NLAT + lat)
     	     || tempIn[lat][lon] != SAMPLE_TEMP + .25 * (lon * NLAT + lat))
     	    return NC_ERR;

        // Each of the netCDF variables has a "units" attribute. Let's read
        // them and check them.
        NcAtt *att;
        char *units;

        if (!(att = latVar->get_att("units")))
           return NC_ERR;
        units = att->as_string(0);
        if (strncmp(units, "degrees_north", strlen("degrees_north")))
           return NC_ERR;
        // Attributes and attribute values should be deleted by the caller
        // when no longer needed, to prevent memory leaks.
        delete units;
        delete att;

        if (!(att = lonVar->get_att("units")))
           return NC_ERR;
        units = att->as_string(0);
        if (strncmp(units, "degrees_east", strlen("degrees_east")))
           return NC_ERR;
        delete units;
        delete att;

        if (!(att = presVar->get_att("units")))
           return NC_ERR;
        units = att->as_string(0);
        if (strncmp(units, "hPa", strlen("hPa")))
           return NC_ERR;
        delete units;
        delete att;

        if (!(att = tempVar->get_att("units")))
           return NC_ERR;
        units = att->as_string(0);
        if (strncmp(units, "celsius", strlen("celsius")))
           return NC_ERR;
        delete units;
        delete att;

        // The file will be automatically closed by the destructor. This
        // frees up any internal netCDF resources associated with the file,
        // and flushes any buffers.
        cout << "*** SUCCESS reading example file sfc_pres_temp.nc!" << endl;

        return 0;
     }

2.3 The pres_temp_4D Example
============================

This example expands on the previous example by making our
two-dimensional data into four-dimensional data, adding a vertical
level axis and an unlimited time step axis.

   Additionally, in this example the data are written and read one time
step at a time, as is typical in scientific applications that use the
unlimited dimension.

   The sample data file created by pres_temp_4D_wr can be examined with
the utility ncdump. The output is shown below. For more information on
ncdump see *Note NetCDF Utilities: (netcdf)NetCDF Utilities.

     netcdf pres_temp_4D {
     dimensions:
     	level = 2 ;
     	latitude = 6 ;
     	longitude = 12 ;
     	time = UNLIMITED ; // (2 currently)
     variables:
     	float latitude(latitude) ;
     		latitude:units = "degrees_north" ;
     	float longitude(longitude) ;
     		longitude:units = "degrees_east" ;
     	float pressure(time, level, latitude, longitude) ;
     		pressure:units = "hPa" ;
     	float temperature(time, level, latitude, longitude) ;
     		temperature:units = "celsius" ;
     data:

      latitude = 25, 30, 35, 40, 45, 50 ;

      longitude = -125, -120, -115, -110, -105, -100, -95, -90, -85, -80, -75, -70 ;

      pressure =
       900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911,
       912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923,
       924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935,
       936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947,
       948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959,
       960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971,
       972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983,
       984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995,
       996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007,
       1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019,
       1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031,
       1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043,
       900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911,
       912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923,
       924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935,
       936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947,
       948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959,
       960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971,
       972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983,
       984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995,
       996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007,
       1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019,
       1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031,
       1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043 ;

      temperature =
       9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
       21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
       33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
       45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
       57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
       69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
       81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
       93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
       105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
       117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
       129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
       141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152,
       9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
       21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
       33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
       45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
       57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
       69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
       81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
       93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
       105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
       117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128,
       129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
       141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152 ;
     }

2.3.1 pres_temp_4D_wr.c and pres_temp_4D_rd.c
---------------------------------------------

These example programs can be found in the netCDF distribution, under
examples/C.

   The example program pres_temp_4D_wr.c creates the example data file
pres_temp_4D.nc. The example program pres_temp_4D_rd.c reads the data
file.

2.3.1.1 pres_temp_4D_wr.c
.........................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This is an example program which writes some 4D pressure and
        temperatures. It is intended to illustrate the use of the netCDF
        C API. The companion program pres_temp_4D_rd.c shows how
        to read the netCDF data file created by this program.

        This program is part of the netCDF tutorial:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c

        $Id: pres_temp_4D_wr.c,v 1.5 2006/11/04 21:13:04 russ Exp $
     */

     #include <stdio.h>
     #include <string.h>
     #include <netcdf.h>

     /* This is the name of the data file we will create. */
     #define FILE_NAME "pres_temp_4D.nc"

     /* We are writing 4D data, a 2 x 6 x 12 lvl-lat-lon grid, with 2
        timesteps of data. */
     #define NDIMS 4
     #define NLAT 6
     #define NLON 12
     #define LAT_NAME "latitude"
     #define LON_NAME "longitude"
     #define NREC 2
     #define REC_NAME "time"
     #define LVL_NAME "level"
     #define NLVL 2

     /* Names of things. */
     #define PRES_NAME "pressure"
     #define TEMP_NAME "temperature"
     #define UNITS "units"
     #define DEGREES_EAST "degrees_east"
     #define DEGREES_NORTH "degrees_north"

     /* These are used to construct some example data. */
     #define SAMPLE_PRESSURE 900
     #define SAMPLE_TEMP 9.0
     #define START_LAT 25.0
     #define START_LON -125.0

     /* For the units attributes. */
     #define UNITS "units"
     #define PRES_UNITS "hPa"
     #define TEMP_UNITS "celsius"
     #define LAT_UNITS "degrees_north"
     #define LON_UNITS "degrees_east"
     #define MAX_ATT_LEN 80

     /* Handle errors by printing an error message and exiting with a
      * non-zero status. */
     #define ERR(e) {printf("Error: %s\n", nc_strerror(e)); return 2;}

     int
     main()
     {
        /* IDs for the netCDF file, dimensions, and variables. */
        int ncid, lon_dimid, lat_dimid, lvl_dimid, rec_dimid;
        int lat_varid, lon_varid, pres_varid, temp_varid;
        int dimids[NDIMS];

        /* The start and count arrays will tell the netCDF library where to
           write our data. */
        size_t start[NDIMS], count[NDIMS];

        /* Program variables to hold the data we will write out. We will only
           need enough space to hold one timestep of data; one record. */
        float pres_out[NLVL][NLAT][NLON];
        float temp_out[NLVL][NLAT][NLON];

        /* These program variables hold the latitudes and longitudes. */
        float lats[NLAT], lons[NLON];

        /* Loop indexes. */
        int lvl, lat, lon, rec, i = 0;

        /* Error handling. */
        int retval;

        /* Create some pretend data. If this wasn't an example program, we
         * would have some real data to write, for example, model
         * output. */
        for (lat = 0; lat < NLAT; lat++)
           lats[lat] = START_LAT + 5.*lat;
        for (lon = 0; lon < NLON; lon++)
           lons[lon] = START_LON + 5.*lon;

        for (lvl = 0; lvl < NLVL; lvl++)
           for (lat = 0; lat < NLAT; lat++)
     	 for (lon = 0; lon < NLON; lon++)
     	 {
     	    pres_out[lvl][lat][lon] = SAMPLE_PRESSURE + i;
     	    temp_out[lvl][lat][lon] = SAMPLE_TEMP + i++;
     	 }

        /* Create the file. */
        if ((retval = nc_create(FILE_NAME, NC_CLOBBER, &ncid)))
           ERR(retval);

        /* Define the dimensions. The record dimension is defined to have
         * unlimited length - it can grow as needed. In this example it is
         * the time dimension.*/
        if ((retval = nc_def_dim(ncid, LVL_NAME, NLVL, &lvl_dimid)))
           ERR(retval);
        if ((retval = nc_def_dim(ncid, LAT_NAME, NLAT, &lat_dimid)))
           ERR(retval);
        if ((retval = nc_def_dim(ncid, LON_NAME, NLON, &lon_dimid)))
           ERR(retval);
        if ((retval = nc_def_dim(ncid, REC_NAME, NC_UNLIMITED, &rec_dimid)))
           ERR(retval);

        /* Define the coordinate variables. We will only define coordinate
           variables for lat and lon.  Ordinarily we would need to provide
           an array of dimension IDs for each variable's dimensions, but
           since coordinate variables only have one dimension, we can
           simply provide the address of that dimension ID (&lat_dimid) and
           similarly for (&lon_dimid). */
        if ((retval = nc_def_var(ncid, LAT_NAME, NC_FLOAT, 1, &lat_dimid,
     			    &lat_varid)))
           ERR(retval);
        if ((retval = nc_def_var(ncid, LON_NAME, NC_FLOAT, 1, &lon_dimid,
     			    &lon_varid)))
           ERR(retval);

        /* Assign units attributes to coordinate variables. */
        if ((retval = nc_put_att_text(ncid, lat_varid, UNITS,
     				 strlen(DEGREES_NORTH), DEGREES_NORTH)))
           ERR(retval);
        if ((retval = nc_put_att_text(ncid, lon_varid, UNITS,
     				 strlen(DEGREES_EAST), DEGREES_EAST)))
           ERR(retval);

        /* The dimids array is used to pass the dimids of the dimensions of
           the netCDF variables. Both of the netCDF variables we are
           creating share the same four dimensions. In C, the
           unlimited dimension must come first on the list of dimids. */
        dimids[0] = rec_dimid;
        dimids[1] = lvl_dimid;
        dimids[2] = lat_dimid;
        dimids[3] = lon_dimid;

        /* Define the netCDF variables for the pressure and temperature
         * data. */
        if ((retval = nc_def_var(ncid, PRES_NAME, NC_FLOAT, NDIMS,
     			    dimids, &pres_varid)))
           ERR(retval);
        if ((retval = nc_def_var(ncid, TEMP_NAME, NC_FLOAT, NDIMS,
     			    dimids, &temp_varid)))
           ERR(retval);

        /* Assign units attributes to the netCDF variables. */
        if ((retval = nc_put_att_text(ncid, pres_varid, UNITS,
     				 strlen(PRES_UNITS), PRES_UNITS)))
           ERR(retval);
        if ((retval = nc_put_att_text(ncid, temp_varid, UNITS,
     				 strlen(TEMP_UNITS), TEMP_UNITS)))
           ERR(retval);

        /* End define mode. */
        if ((retval = nc_enddef(ncid)))
           ERR(retval);

        /* Write the coordinate variable data. This will put the latitudes
           and longitudes of our data grid into the netCDF file. */
        if ((retval = nc_put_var_float(ncid, lat_varid, &lats[0])))
           ERR(retval);
        if ((retval = nc_put_var_float(ncid, lon_varid, &lons[0])))
           ERR(retval);

        /* These settings tell netcdf to write one timestep of data. (The
          setting of start[0] inside the loop below tells netCDF which
          timestep to write.) */
        count[0] = 1;
        count[1] = NLVL;
        count[2] = NLAT;
        count[3] = NLON;
        start[1] = 0;
        start[2] = 0;
        start[3] = 0;

        /* Write the pretend data. This will write our surface pressure and
           surface temperature data. The arrays only hold one timestep worth
           of data. We will just rewrite the same data for each timestep. In
           a real application, the data would change between timesteps. */
        for (rec = 0; rec < NREC; rec++)
        {
           start[0] = rec;
           if ((retval = nc_put_vara_float(ncid, pres_varid, start, count,
     				      &pres_out[0][0][0])))
     	 ERR(retval);
           if ((retval = nc_put_vara_float(ncid, temp_varid, start, count,
     				      &temp_out[0][0][0])))
     	 ERR(retval);
        }

        /* Close the file. */
        if ((retval = nc_close(ncid)))
           ERR(retval);

        printf("*** SUCCESS writing example file %s!\n", FILE_NAME);
        return 0;
     }

2.3.1.2 pres_temp_4D_rd.c
.........................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This is an example which reads some 4D pressure and
        temperatures. The data file read by this program is produced by the
        companion program pres_temp_4D_wr.c. It is intended to illustrate
        the use of the netCDF C API.

        This program is part of the netCDF tutorial:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c

        $Id: pres_temp_4D_rd.c,v 1.5 2006/06/26 20:37:31 russ Exp $
     */

     #include <stdio.h>
     #include <string.h>
     #include <netcdf.h>

     /* This is the name of the data file we will read. */
     #define FILE_NAME "pres_temp_4D.nc"

     /* We are reading 4D data, a 2 x 6 x 12 lvl-lat-lon grid, with 2
        timesteps of data. */
     #define NDIMS 4
     #define NLAT 6
     #define NLON 12
     #define LAT_NAME "latitude"
     #define LON_NAME "longitude"
     #define NREC 2
     #define REC_NAME "time"
     #define LVL_NAME "level"
     #define NLVL 2

     /* Names of things. */
     #define PRES_NAME "pressure"
     #define TEMP_NAME "temperature"
     #define UNITS "units"
     #define DEGREES_EAST "degrees_east"
     #define DEGREES_NORTH "degrees_north"

     /* These are used to calculate the values we expect to find. */
     #define SAMPLE_PRESSURE 900
     #define SAMPLE_TEMP 9.0
     #define START_LAT 25.0
     #define START_LON -125.0

     /* For the units attributes. */
     #define UNITS "units"
     #define PRES_UNITS "hPa"
     #define TEMP_UNITS "celsius"
     #define LAT_UNITS "degrees_north"
     #define LON_UNITS "degrees_east"
     #define MAX_ATT_LEN 80

     /* Handle errors by printing an error message and exiting with a
      * non-zero status. */
     #define ERR(e) {printf("Error: %s\n", nc_strerror(e)); return 2;}

     int
     main()
     {
        int ncid, pres_varid, temp_varid;
        int lat_varid, lon_varid;

        /* The start and count arrays will tell the netCDF library where to
           read our data. */
        size_t start[NDIMS], count[NDIMS];

        /* Program variables to hold the data we will read. We will only
           need enough space to hold one timestep of data; one record. */
        float pres_in[NLVL][NLAT][NLON];
        float temp_in[NLVL][NLAT][NLON];

        /* These program variables hold the latitudes and longitudes. */
        float lats[NLAT], lons[NLON];

        /* Loop indexes. */
        int lvl, lat, lon, rec, i = 0;

        /* Error handling. */
        int retval;

        /* Open the file. */
        if ((retval = nc_open(FILE_NAME, NC_NOWRITE, &ncid)))
           ERR(retval);

        /* Get the varids of the latitude and longitude coordinate
         * variables. */
        if ((retval = nc_inq_varid(ncid, LAT_NAME, &lat_varid)))
           ERR(retval);
        if ((retval = nc_inq_varid(ncid, LON_NAME, &lon_varid)))
           ERR(retval);

        /* Read the coordinate variable data. */
        if ((retval = nc_get_var_float(ncid, lat_varid, &lats[0])))
           ERR(retval);
        if ((retval = nc_get_var_float(ncid, lon_varid, &lons[0])))
           ERR(retval);

        /* Check the coordinate variable data. */
        for (lat = 0; lat < NLAT; lat++)
           if (lats[lat] != START_LAT + 5.*lat)
     	 return 2;
        for (lon = 0; lon < NLON; lon++)
           if (lons[lon] != START_LON + 5.*lon)
     	 return 2;

        /* Get the varids of the pressure and temperature netCDF
         * variables. */
        if ((retval = nc_inq_varid(ncid, PRES_NAME, &pres_varid)))
           ERR(retval);
        if ((retval = nc_inq_varid(ncid, TEMP_NAME, &temp_varid)))
           ERR(retval);

        /* Read the data. Since we know the contents of the file we know
         * that the data arrays in this program are the correct size to
         * hold one timestep. */
        count[0] = 1;
        count[1] = NLVL;
        count[2] = NLAT;
        count[3] = NLON;
        start[1] = 0;
        start[2] = 0;
        start[3] = 0;

        /* Read and check one record at a time. */
        for (rec = 0; rec < NREC; rec++)
        {
           start[0] = rec;
           if ((retval = nc_get_vara_float(ncid, pres_varid, start,
     				      count, &pres_in[0][0][0])))
     	 ERR(retval);
           if ((retval = nc_get_vara_float(ncid, temp_varid, start,
     				      count, &temp_in[0][0][0])))
     	 ERR(retval);

           /* Check the data. */
           i = 0;
           for (lvl = 0; lvl < NLVL; lvl++)
     	 for (lat = 0; lat < NLAT; lat++)
     	    for (lon = 0; lon < NLON; lon++)
     	    {
     	       if (pres_in[lvl][lat][lon] != SAMPLE_PRESSURE + i)
     		  return 2;
     	       if (temp_in[lvl][lat][lon] != SAMPLE_TEMP + i)
     		  return 2;
     	       i++;
     	    }

        } /* next record */

        /* Close the file. */
        if ((retval = nc_close(ncid)))
           ERR(retval);

        printf("*** SUCCESS reading example file pres_temp_4D.nc!\n");
        return 0;
     }

2.3.2 pres_temp_4D_wr.f and pres_temp_4D_rd.f
---------------------------------------------

These example programs can be found in the netCDF distribution, under
examples/F77.

   The example program pres_temp_4D_wr.f creates the example data file
pres_temp_4D.nc. The example program pres_temp_4D_rd.f reads the data
file.

2.3.2.1 pres_temp_4D_wr.f
.........................

     C     This is part of the netCDF package.
     C     Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     C     See COPYRIGHT file for conditions of use.

     C     This is an example program which writes some 4D pressure and
     C     temperatures. It is intended to illustrate the use of the netCDF
     C     fortran 77 API. The companion program pres_temp_4D_rd.f shows how
     C     to read the netCDF data file created by this program.

     C     This program is part of the netCDF tutorial:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     C     Full documentation of the netCDF Fortran 77 API can be found at:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f77

     C     $Id: pres_temp_4D_wr.f,v 1.12 2007/02/14 20:59:20 ed Exp $

           program pres_temp_4D_wr
           implicit none
           include 'netcdf.inc'

     C     This is the name of the data file we will create.
           character*(*) FILE_NAME
           parameter (FILE_NAME = 'pres_temp_4D.nc')
           integer ncid

     C     We are writing 4D data, a 12 x 6 x 2 lon-lat-lvl grid, with 2
     C     timesteps of data.
           integer NDIMS, NRECS
           parameter (NDIMS = 4, NRECS = 2)
           integer NLVLS, NLATS, NLONS
           parameter (NLVLS = 2, NLATS = 6, NLONS = 12)
           character*(*) LVL_NAME, LAT_NAME, LON_NAME, REC_NAME
           parameter (LVL_NAME = 'level')
           parameter (LAT_NAME = 'latitude', LON_NAME = 'longitude')
           parameter (REC_NAME = 'time')
           integer lvl_dimid, lon_dimid, lat_dimid, rec_dimid

     C     The start and count arrays will tell the netCDF library where to
     C     write our data.
           integer start(NDIMS), count(NDIMS)

     C     These program variables hold the latitudes and longitudes.
           real lats(NLATS), lons(NLONS)
           integer lon_varid, lat_varid

     C     We will create two netCDF variables, one each for temperature and
     C     pressure fields.
           character*(*) PRES_NAME, TEMP_NAME
           parameter (PRES_NAME='pressure')
           parameter (TEMP_NAME='temperature')
           integer pres_varid, temp_varid
           integer dimids(NDIMS)

     C     We recommend that each variable carry a "units" attribute.
           character*(*) UNITS
           parameter (UNITS = 'units')
           character*(*) PRES_UNITS, TEMP_UNITS, LAT_UNITS, LON_UNITS
           parameter (PRES_UNITS = 'hPa', TEMP_UNITS = 'celsius')
           parameter (LAT_UNITS = 'degrees_north')
           parameter (LON_UNITS = 'degrees_east')

     C     Program variables to hold the data we will write out. We will only
     C     need enough space to hold one timestep of data; one record.
           real pres_out(NLONS, NLATS, NLVLS)
           real temp_out(NLONS, NLATS, NLVLS)
           real SAMPLE_PRESSURE
           parameter (SAMPLE_PRESSURE = 900.0)
           real SAMPLE_TEMP
           parameter (SAMPLE_TEMP = 9.0)

     C     Use these to construct some latitude and longitude data for this
     C     example.
           integer START_LAT, START_LON
           parameter (START_LAT = 25.0, START_LON = -125.0)

     C     Loop indices.
           integer lvl, lat, lon, rec, i

     C     Error handling.
           integer retval

     C     Create pretend data. If this wasn't an example program, we would
     C     have some real data to write, for example, model output.
           do lat = 1, NLATS
              lats(lat) = START_LAT + (lat - 1) * 5.0
           end do
           do lon = 1, NLONS
              lons(lon) = START_LON + (lon - 1) * 5.0
           end do
           i = 0
           do lvl = 1, NLVLS
              do lat = 1, NLATS
                 do lon = 1, NLONS
                    pres_out(lon, lat, lvl) = SAMPLE_PRESSURE + i
                    temp_out(lon, lat, lvl) = SAMPLE_TEMP + i
                    i = i + 1
                 end do
              end do
           end do

     C     Create the file.
           retval = nf_create(FILE_NAME, nf_clobber, ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Define the dimensions. The record dimension is defined to have
     C     unlimited length - it can grow as needed. In this example it is
     C     the time dimension.
           retval = nf_def_dim(ncid, LVL_NAME, NLVLS, lvl_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_dim(ncid, LAT_NAME, NLATS, lat_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_dim(ncid, LON_NAME, NLONS, lon_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_dim(ncid, REC_NAME, NF_UNLIMITED, rec_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Define the coordinate variables. We will only define coordinate
     C     variables for lat and lon.  Ordinarily we would need to provide
     C     an array of dimension IDs for each variable's dimensions, but
     C     since coordinate variables only have one dimension, we can
     C     simply provide the address of that dimension ID (lat_dimid) and
     C     similarly for (lon_dimid).
           retval = nf_def_var(ncid, LAT_NAME, NF_REAL, 1, lat_dimid,
          +     lat_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_var(ncid, LON_NAME, NF_REAL, 1, lon_dimid,
          +     lon_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Assign units attributes to coordinate variables.
           retval = nf_put_att_text(ncid, lat_varid, UNITS, len(LAT_UNITS),
          +     LAT_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_put_att_text(ncid, lon_varid, UNITS, len(LON_UNITS),
          +     LON_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     The dimids array is used to pass the dimids of the dimensions of
     C     the netCDF variables. Both of the netCDF variables we are creating
     C     share the same four dimensions. In Fortran, the unlimited
     C     dimension must come last on the list of dimids.
           dimids(1) = lon_dimid
           dimids(2) = lat_dimid
           dimids(3) = lvl_dimid
           dimids(4) = rec_dimid

     C     Define the netCDF variables for the pressure and temperature data.
           retval = nf_def_var(ncid, PRES_NAME, NF_REAL, NDIMS, dimids,
          +     pres_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_var(ncid, TEMP_NAME, NF_REAL, NDIMS, dimids,
          +     temp_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Assign units attributes to the netCDF variables.
           retval = nf_put_att_text(ncid, pres_varid, UNITS, len(PRES_UNITS),
          +     PRES_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_put_att_text(ncid, temp_varid, UNITS, len(TEMP_UNITS),
          +     TEMP_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     End define mode.
           retval = nf_enddef(ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Write the coordinate variable data. This will put the latitudes
     C     and longitudes of our data grid into the netCDF file.
           retval = nf_put_var_real(ncid, lat_varid, lats)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_put_var_real(ncid, lon_varid, lons)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     These settings tell netcdf to write one timestep of data. (The
     C     setting of start(4) inside the loop below tells netCDF which
     C     timestep to write.)
           count(1) = NLONS
           count(2) = NLATS
           count(3) = NLVLS
           count(4) = 1
           start(1) = 1
           start(2) = 1
           start(3) = 1

     C     Write the pretend data. This will write our surface pressure and
     C     surface temperature data. The arrays only hold one timestep worth
     C     of data. We will just rewrite the same data for each timestep. In
     C     a real application, the data would change between timesteps.
           do rec = 1, NRECS
              start(4) = rec
              retval = nf_put_vara_real(ncid, pres_varid, start, count,
          +        pres_out)
              if (retval .ne. nf_noerr) call handle_err(retval)
              retval = nf_put_vara_real(ncid, temp_varid, start, count,
          +        temp_out)
              if (retval .ne. nf_noerr) call handle_err(retval)
           end do

     C     Close the file. This causes netCDF to flush all buffers and make
     C     sure your data are really written to disk.
           retval = nf_close(ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

           print *,'*** SUCCESS writing example file', FILE_NAME, '!'
           end

           subroutine handle_err(errcode)
           implicit none
           include 'netcdf.inc'
           integer errcode

           print *, 'Error: ', nf_strerror(errcode)
           stop 2
           end

2.3.2.2 pres_temp_4D_rd.f
.........................

     C     This is part of the netCDF package.
     C     Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     C     See COPYRIGHT file for conditions of use.

     C     This is an example program which writes some 4D pressure and
     C     temperatures. It is intended to illustrate the use of the netCDF
     C     fortran 77 API. The companion program pres_temp_4D_rd.f shows how
     C     to read the netCDF data file created by this program.

     C     This program is part of the netCDF tutorial:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     C     Full documentation of the netCDF Fortran 77 API can be found at:
     C     http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f77

     C     $Id: pres_temp_4D_wr.f,v 1.12 2007/02/14 20:59:20 ed Exp $

           program pres_temp_4D_wr
           implicit none
           include 'netcdf.inc'

     C     This is the name of the data file we will create.
           character*(*) FILE_NAME
           parameter (FILE_NAME = 'pres_temp_4D.nc')
           integer ncid

     C     We are writing 4D data, a 12 x 6 x 2 lon-lat-lvl grid, with 2
     C     timesteps of data.
           integer NDIMS, NRECS
           parameter (NDIMS = 4, NRECS = 2)
           integer NLVLS, NLATS, NLONS
           parameter (NLVLS = 2, NLATS = 6, NLONS = 12)
           character*(*) LVL_NAME, LAT_NAME, LON_NAME, REC_NAME
           parameter (LVL_NAME = 'level')
           parameter (LAT_NAME = 'latitude', LON_NAME = 'longitude')
           parameter (REC_NAME = 'time')
           integer lvl_dimid, lon_dimid, lat_dimid, rec_dimid

     C     The start and count arrays will tell the netCDF library where to
     C     write our data.
           integer start(NDIMS), count(NDIMS)

     C     These program variables hold the latitudes and longitudes.
           real lats(NLATS), lons(NLONS)
           integer lon_varid, lat_varid

     C     We will create two netCDF variables, one each for temperature and
     C     pressure fields.
           character*(*) PRES_NAME, TEMP_NAME
           parameter (PRES_NAME='pressure')
           parameter (TEMP_NAME='temperature')
           integer pres_varid, temp_varid
           integer dimids(NDIMS)

     C     We recommend that each variable carry a "units" attribute.
           character*(*) UNITS
           parameter (UNITS = 'units')
           character*(*) PRES_UNITS, TEMP_UNITS, LAT_UNITS, LON_UNITS
           parameter (PRES_UNITS = 'hPa', TEMP_UNITS = 'celsius')
           parameter (LAT_UNITS = 'degrees_north')
           parameter (LON_UNITS = 'degrees_east')

     C     Program variables to hold the data we will write out. We will only
     C     need enough space to hold one timestep of data; one record.
           real pres_out(NLONS, NLATS, NLVLS)
           real temp_out(NLONS, NLATS, NLVLS)
           real SAMPLE_PRESSURE
           parameter (SAMPLE_PRESSURE = 900.0)
           real SAMPLE_TEMP
           parameter (SAMPLE_TEMP = 9.0)

     C     Use these to construct some latitude and longitude data for this
     C     example.
           integer START_LAT, START_LON
           parameter (START_LAT = 25.0, START_LON = -125.0)

     C     Loop indices.
           integer lvl, lat, lon, rec, i

     C     Error handling.
           integer retval

     C     Create pretend data. If this wasn't an example program, we would
     C     have some real data to write, for example, model output.
           do lat = 1, NLATS
              lats(lat) = START_LAT + (lat - 1) * 5.0
           end do
           do lon = 1, NLONS
              lons(lon) = START_LON + (lon - 1) * 5.0
           end do
           i = 0
           do lvl = 1, NLVLS
              do lat = 1, NLATS
                 do lon = 1, NLONS
                    pres_out(lon, lat, lvl) = SAMPLE_PRESSURE + i
                    temp_out(lon, lat, lvl) = SAMPLE_TEMP + i
                    i = i + 1
                 end do
              end do
           end do

     C     Create the file.
           retval = nf_create(FILE_NAME, nf_clobber, ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Define the dimensions. The record dimension is defined to have
     C     unlimited length - it can grow as needed. In this example it is
     C     the time dimension.
           retval = nf_def_dim(ncid, LVL_NAME, NLVLS, lvl_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_dim(ncid, LAT_NAME, NLATS, lat_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_dim(ncid, LON_NAME, NLONS, lon_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_dim(ncid, REC_NAME, NF_UNLIMITED, rec_dimid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Define the coordinate variables. We will only define coordinate
     C     variables for lat and lon.  Ordinarily we would need to provide
     C     an array of dimension IDs for each variable's dimensions, but
     C     since coordinate variables only have one dimension, we can
     C     simply provide the address of that dimension ID (lat_dimid) and
     C     similarly for (lon_dimid).
           retval = nf_def_var(ncid, LAT_NAME, NF_REAL, 1, lat_dimid,
          +     lat_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_var(ncid, LON_NAME, NF_REAL, 1, lon_dimid,
          +     lon_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Assign units attributes to coordinate variables.
           retval = nf_put_att_text(ncid, lat_varid, UNITS, len(LAT_UNITS),
          +     LAT_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_put_att_text(ncid, lon_varid, UNITS, len(LON_UNITS),
          +     LON_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     The dimids array is used to pass the dimids of the dimensions of
     C     the netCDF variables. Both of the netCDF variables we are creating
     C     share the same four dimensions. In Fortran, the unlimited
     C     dimension must come last on the list of dimids.
           dimids(1) = lon_dimid
           dimids(2) = lat_dimid
           dimids(3) = lvl_dimid
           dimids(4) = rec_dimid

     C     Define the netCDF variables for the pressure and temperature data.
           retval = nf_def_var(ncid, PRES_NAME, NF_REAL, NDIMS, dimids,
          +     pres_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_def_var(ncid, TEMP_NAME, NF_REAL, NDIMS, dimids,
          +     temp_varid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Assign units attributes to the netCDF variables.
           retval = nf_put_att_text(ncid, pres_varid, UNITS, len(PRES_UNITS),
          +     PRES_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_put_att_text(ncid, temp_varid, UNITS, len(TEMP_UNITS),
          +     TEMP_UNITS)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     End define mode.
           retval = nf_enddef(ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     Write the coordinate variable data. This will put the latitudes
     C     and longitudes of our data grid into the netCDF file.
           retval = nf_put_var_real(ncid, lat_varid, lats)
           if (retval .ne. nf_noerr) call handle_err(retval)
           retval = nf_put_var_real(ncid, lon_varid, lons)
           if (retval .ne. nf_noerr) call handle_err(retval)

     C     These settings tell netcdf to write one timestep of data. (The
     C     setting of start(4) inside the loop below tells netCDF which
     C     timestep to write.)
           count(1) = NLONS
           count(2) = NLATS
           count(3) = NLVLS
           count(4) = 1
           start(1) = 1
           start(2) = 1
           start(3) = 1

     C     Write the pretend data. This will write our surface pressure and
     C     surface temperature data. The arrays only hold one timestep worth
     C     of data. We will just rewrite the same data for each timestep. In
     C     a real application, the data would change between timesteps.
           do rec = 1, NRECS
              start(4) = rec
              retval = nf_put_vara_real(ncid, pres_varid, start, count,
          +        pres_out)
              if (retval .ne. nf_noerr) call handle_err(retval)
              retval = nf_put_vara_real(ncid, temp_varid, start, count,
          +        temp_out)
              if (retval .ne. nf_noerr) call handle_err(retval)
           end do

     C     Close the file. This causes netCDF to flush all buffers and make
     C     sure your data are really written to disk.
           retval = nf_close(ncid)
           if (retval .ne. nf_noerr) call handle_err(retval)

           print *,'*** SUCCESS writing example file', FILE_NAME, '!'
           end

           subroutine handle_err(errcode)
           implicit none
           include 'netcdf.inc'
           integer errcode

           print *, 'Error: ', nf_strerror(errcode)
           stop 2
           end

2.3.3 pres_temp_4D_wr.f90 and pres_temp_4D_rd.f90
-------------------------------------------------

These example programs can be found in the netCDF distribution, under
examples/F90.

   The example program pres_temp_4D_wr.f90 creates the example data file
pres_temp_4D.nc. The example program pres_temp_4D_rd.f90 reads the data
file.

2.3.3.1 pres_temp_4D_wr.f90
...........................

     ! This is part of the netCDF package.
     ! Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     ! See COPYRIGHT file for conditions of use.

     ! This is an example program which writes some 4D pressure and
     ! temperatures. It is intended to illustrate the use of the netCDF
     ! fortran 90 API. The companion program pres_temp_4D_rd.f shows how
     ! to read the netCDF data file created by this program.

     ! This program is part of the netCDF tutorial:
     ! http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     ! Full documentation of the netCDF Fortran 90 API can be found at:
     ! http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f90

     ! $Id: pres_temp_4D_wr.f90,v 1.8 2007/02/14 20:59:20 ed Exp $

     program pres_temp_4D_wr
       use netcdf
       implicit none

       ! This is the name of the data file we will create.
       character (len = *), parameter :: FILE_NAME = "pres_temp_4D.nc"
       integer :: ncid

       ! We are writing 4D data, a 12 x 6 x 2 lon-lat-lvl grid, with 2
       ! timesteps of data.
       integer, parameter :: NDIMS = 4, NRECS = 2
       integer, parameter :: NLVLS = 2, NLATS = 6, NLONS = 12
       character (len = *), parameter :: LVL_NAME = "level"
       character (len = *), parameter :: LAT_NAME = "latitude"
       character (len = *), parameter :: LON_NAME = "longitude"
       character (len = *), parameter :: REC_NAME = "time"
       integer :: lvl_dimid, lon_dimid, lat_dimid, rec_dimid

       ! The start and count arrays will tell the netCDF library where to
       ! write our data.
       integer :: start(NDIMS), count(NDIMS)

       ! These program variables hold the latitudes and longitudes.
       real :: lats(NLATS), lons(NLONS)
       integer :: lon_varid, lat_varid

       ! We will create two netCDF variables, one each for temperature and
       ! pressure fields.
       character (len = *), parameter :: PRES_NAME="pressure"
       character (len = *), parameter :: TEMP_NAME="temperature"
       integer :: pres_varid, temp_varid
       integer :: dimids(NDIMS)

       ! We recommend that each variable carry a "units" attribute.
       character (len = *), parameter :: UNITS = "units"
       character (len = *), parameter :: PRES_UNITS = "hPa"
       character (len = *), parameter :: TEMP_UNITS = "celsius"
       character (len = *), parameter :: LAT_UNITS = "degrees_north"
       character (len = *), parameter :: LON_UNITS = "degrees_east"

       ! Program variables to hold the data we will write out. We will only
       ! need enough space to hold one timestep of data; one record.
       real :: pres_out(NLONS, NLATS, NLVLS)
       real :: temp_out(NLONS, NLATS, NLVLS)
       real, parameter :: SAMPLE_PRESSURE = 900.0
       real, parameter :: SAMPLE_TEMP = 9.0

       ! Use these to construct some latitude and longitude data for this
       ! example.
       real, parameter :: START_LAT = 25.0, START_LON = -125.0

       ! Loop indices
       integer :: lvl, lat, lon, rec, i

       ! Create pretend data. If this were not an example program, we would
       ! have some real data to write, for example, model output.
       do lat = 1, NLATS
          lats(lat) = START_LAT + (lat - 1) * 5.0
       end do
       do lon = 1, NLONS
          lons(lon) = START_LON + (lon - 1) * 5.0
       end do
       i = 0
       do lvl = 1, NLVLS
          do lat = 1, NLATS
             do lon = 1, NLONS
                pres_out(lon, lat, lvl) = SAMPLE_PRESSURE + i
                temp_out(lon, lat, lvl) = SAMPLE_TEMP + i
                i = i + 1
             end do
          end do
       end do

       ! Create the file.
       call check( nf90_create(FILE_NAME, nf90_clobber, ncid) )

       ! Define the dimensions. The record dimension is defined to have
       ! unlimited length - it can grow as needed. In this example it is
       ! the time dimension.
       call check( nf90_def_dim(ncid, LVL_NAME, NLVLS, lvl_dimid) )
       call check( nf90_def_dim(ncid, LAT_NAME, NLATS, lat_dimid) )
       call check( nf90_def_dim(ncid, LON_NAME, NLONS, lon_dimid) )
       call check( nf90_def_dim(ncid, REC_NAME, NF90_UNLIMITED, rec_dimid) )

       ! Define the coordinate variables. We will only define coordinate
       ! variables for lat and lon.  Ordinarily we would need to provide
       ! an array of dimension IDs for each variable's dimensions, but
       ! since coordinate variables only have one dimension, we can
       ! simply provide the address of that dimension ID (lat_dimid) and
       ! similarly for (lon_dimid).
       call check( nf90_def_var(ncid, LAT_NAME, NF90_REAL, lat_dimid, lat_varid) )
       call check( nf90_def_var(ncid, LON_NAME, NF90_REAL, lon_dimid, lon_varid) )

       ! Assign units attributes to coordinate variables.
       call check( nf90_put_att(ncid, lat_varid, UNITS, LAT_UNITS) )
       call check( nf90_put_att(ncid, lon_varid, UNITS, LON_UNITS) )

       ! The dimids array is used to pass the dimids of the dimensions of
       ! the netCDF variables. Both of the netCDF variables we are creating
       ! share the same four dimensions. In Fortran, the unlimited
       ! dimension must come last on the list of dimids.
       dimids = (/ lon_dimid, lat_dimid, lvl_dimid, rec_dimid /)

       ! Define the netCDF variables for the pressure and temperature data.
       call check( nf90_def_var(ncid, PRES_NAME, NF90_REAL, dimids, pres_varid) )
       call check( nf90_def_var(ncid, TEMP_NAME, NF90_REAL, dimids, temp_varid) )

       ! Assign units attributes to the netCDF variables.
       call check( nf90_put_att(ncid, pres_varid, UNITS, PRES_UNITS) )
       call check( nf90_put_att(ncid, temp_varid, UNITS, TEMP_UNITS) )

       ! End define mode.
       call check( nf90_enddef(ncid) )

       ! Write the coordinate variable data. This will put the latitudes
       ! and longitudes of our data grid into the netCDF file.
       call check( nf90_put_var(ncid, lat_varid, lats) )
       call check( nf90_put_var(ncid, lon_varid, lons) )

       ! These settings tell netcdf to write one timestep of data. (The
       ! setting of start(4) inside the loop below tells netCDF which
       ! timestep to write.)
       count = (/ NLONS, NLATS, NLVLS, 1 /)
       start = (/ 1, 1, 1, 1 /)

       ! Write the pretend data. This will write our surface pressure and
       ! surface temperature data. The arrays only hold one timestep worth
       ! of data. We will just rewrite the same data for each timestep. In
       ! a real :: application, the data would change between timesteps.
       do rec = 1, NRECS
          start(4) = rec
          call check( nf90_put_var(ncid, pres_varid, pres_out, start = start, &
                                   count = count) )
          call check( nf90_put_var(ncid, temp_varid, temp_out, start = start, &
                                   count = count) )
       end do

       ! Close the file. This causes netCDF to flush all buffers and make
       ! sure your data are really written to disk.
       call check( nf90_close(ncid) )

       print *,"*** SUCCESS writing example file ", FILE_NAME, "!"

     contains
       subroutine check(status)
         integer, intent ( in) :: status

         if(status /= nf90_noerr) then
           print *, trim(nf90_strerror(status))
           stop "Stopped"
         end if
       end subroutine check
     end program pres_temp_4D_wr

2.3.3.2 pres_temp_4D_rd.f90
...........................

     ! This is part of the netCDF package.
     ! Copyright 2006 University Corporation for Atmospheric Research/Unidata.
     ! See COPYRIGHT file for conditions of use.

     ! This is an example program which writes some 4D pressure and
     ! temperatures. It is intended to illustrate the use of the netCDF
     ! fortran 90 API. The companion program pres_temp_4D_rd.f shows how
     ! to read the netCDF data file created by this program.

     ! This program is part of the netCDF tutorial:
     ! http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

     ! Full documentation of the netCDF Fortran 90 API can be found at:
     ! http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f90

     ! $Id: pres_temp_4D_wr.f90,v 1.8 2007/02/14 20:59:20 ed Exp $

     program pres_temp_4D_wr
       use netcdf
       implicit none

       ! This is the name of the data file we will create.
       character (len = *), parameter :: FILE_NAME = "pres_temp_4D.nc"
       integer :: ncid

       ! We are writing 4D data, a 12 x 6 x 2 lon-lat-lvl grid, with 2
       ! timesteps of data.
       integer, parameter :: NDIMS = 4, NRECS = 2
       integer, parameter :: NLVLS = 2, NLATS = 6, NLONS = 12
       character (len = *), parameter :: LVL_NAME = "level"
       character (len = *), parameter :: LAT_NAME = "latitude"
       character (len = *), parameter :: LON_NAME = "longitude"
       character (len = *), parameter :: REC_NAME = "time"
       integer :: lvl_dimid, lon_dimid, lat_dimid, rec_dimid

       ! The start and count arrays will tell the netCDF library where to
       ! write our data.
       integer :: start(NDIMS), count(NDIMS)

       ! These program variables hold the latitudes and longitudes.
       real :: lats(NLATS), lons(NLONS)
       integer :: lon_varid, lat_varid

       ! We will create two netCDF variables, one each for temperature and
       ! pressure fields.
       character (len = *), parameter :: PRES_NAME="pressure"
       character (len = *), parameter :: TEMP_NAME="temperature"
       integer :: pres_varid, temp_varid
       integer :: dimids(NDIMS)

       ! We recommend that each variable carry a "units" attribute.
       character (len = *), parameter :: UNITS = "units"
       character (len = *), parameter :: PRES_UNITS = "hPa"
       character (len = *), parameter :: TEMP_UNITS = "celsius"
       character (len = *), parameter :: LAT_UNITS = "degrees_north"
       character (len = *), parameter :: LON_UNITS = "degrees_east"

       ! Program variables to hold the data we will write out. We will only
       ! need enough space to hold one timestep of data; one record.
       real :: pres_out(NLONS, NLATS, NLVLS)
       real :: temp_out(NLONS, NLATS, NLVLS)
       real, parameter :: SAMPLE_PRESSURE = 900.0
       real, parameter :: SAMPLE_TEMP = 9.0

       ! Use these to construct some latitude and longitude data for this
       ! example.
       real, parameter :: START_LAT = 25.0, START_LON = -125.0

       ! Loop indices
       integer :: lvl, lat, lon, rec, i

       ! Create pretend data. If this were not an example program, we would
       ! have some real data to write, for example, model output.
       do lat = 1, NLATS
          lats(lat) = START_LAT + (lat - 1) * 5.0
       end do
       do lon = 1, NLONS
          lons(lon) = START_LON + (lon - 1) * 5.0
       end do
       i = 0
       do lvl = 1, NLVLS
          do lat = 1, NLATS
             do lon = 1, NLONS
                pres_out(lon, lat, lvl) = SAMPLE_PRESSURE + i
                temp_out(lon, lat, lvl) = SAMPLE_TEMP + i
                i = i + 1
             end do
          end do
       end do

       ! Create the file.
       call check( nf90_create(FILE_NAME, nf90_clobber, ncid) )

       ! Define the dimensions. The record dimension is defined to have
       ! unlimited length - it can grow as needed. In this example it is
       ! the time dimension.
       call check( nf90_def_dim(ncid, LVL_NAME, NLVLS, lvl_dimid) )
       call check( nf90_def_dim(ncid, LAT_NAME, NLATS, lat_dimid) )
       call check( nf90_def_dim(ncid, LON_NAME, NLONS, lon_dimid) )
       call check( nf90_def_dim(ncid, REC_NAME, NF90_UNLIMITED, rec_dimid) )

       ! Define the coordinate variables. We will only define coordinate
       ! variables for lat and lon.  Ordinarily we would need to provide
       ! an array of dimension IDs for each variable's dimensions, but
       ! since coordinate variables only have one dimension, we can
       ! simply provide the address of that dimension ID (lat_dimid) and
       ! similarly for (lon_dimid).
       call check( nf90_def_var(ncid, LAT_NAME, NF90_REAL, lat_dimid, lat_varid) )
       call check( nf90_def_var(ncid, LON_NAME, NF90_REAL, lon_dimid, lon_varid) )

       ! Assign units attributes to coordinate variables.
       call check( nf90_put_att(ncid, lat_varid, UNITS, LAT_UNITS) )
       call check( nf90_put_att(ncid, lon_varid, UNITS, LON_UNITS) )

       ! The dimids array is used to pass the dimids of the dimensions of
       ! the netCDF variables. Both of the netCDF variables we are creating
       ! share the same four dimensions. In Fortran, the unlimited
       ! dimension must come last on the list of dimids.
       dimids = (/ lon_dimid, lat_dimid, lvl_dimid, rec_dimid /)

       ! Define the netCDF variables for the pressure and temperature data.
       call check( nf90_def_var(ncid, PRES_NAME, NF90_REAL, dimids, pres_varid) )
       call check( nf90_def_var(ncid, TEMP_NAME, NF90_REAL, dimids, temp_varid) )

       ! Assign units attributes to the netCDF variables.
       call check( nf90_put_att(ncid, pres_varid, UNITS, PRES_UNITS) )
       call check( nf90_put_att(ncid, temp_varid, UNITS, TEMP_UNITS) )

       ! End define mode.
       call check( nf90_enddef(ncid) )

       ! Write the coordinate variable data. This will put the latitudes
       ! and longitudes of our data grid into the netCDF file.
       call check( nf90_put_var(ncid, lat_varid, lats) )
       call check( nf90_put_var(ncid, lon_varid, lons) )

       ! These settings tell netcdf to write one timestep of data. (The
       ! setting of start(4) inside the loop below tells netCDF which
       ! timestep to write.)
       count = (/ NLONS, NLATS, NLVLS, 1 /)
       start = (/ 1, 1, 1, 1 /)

       ! Write the pretend data. This will write our surface pressure and
       ! surface temperature data. The arrays only hold one timestep worth
       ! of data. We will just rewrite the same data for each timestep. In
       ! a real :: application, the data would change between timesteps.
       do rec = 1, NRECS
          start(4) = rec
          call check( nf90_put_var(ncid, pres_varid, pres_out, start = start, &
                                   count = count) )
          call check( nf90_put_var(ncid, temp_varid, temp_out, start = start, &
                                   count = count) )
       end do

       ! Close the file. This causes netCDF to flush all buffers and make
       ! sure your data are really written to disk.
       call check( nf90_close(ncid) )

       print *,"*** SUCCESS writing example file ", FILE_NAME, "!"

     contains
       subroutine check(status)
         integer, intent ( in) :: status

         if(status /= nf90_noerr) then
           print *, trim(nf90_strerror(status))
           stop "Stopped"
         end if
       end subroutine check
     end program pres_temp_4D_wr

2.3.4 pres_temp_4D_wr.cpp and pres_temp_4D_rd.cpp
-------------------------------------------------

These example programs can be found in the netCDF distribution, under
examples/CXX.

   The example program pres_temp_4D_wr.cpp creates the example data file
pres_temp_4D.nc. The example program pres_temp_4D_rd.cpp reads the data
file.

2.3.4.1 pres_temp_4D_wr.cpp
...........................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This is an example program which writes some 4D pressure and
        temperatures. This example demonstrates the netCDF C++ API.

        This is part of the netCDF tutorial:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C++ API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx

        $Id: pres_temp_4D_wr.cpp,v 1.11 2007/01/19 12:52:13 ed Exp $
     */

     #include <iostream>
     #include <netcdfcpp.h>

     using namespace std;

     // We are writing 4D data, a 2 x 6 x 12 lvl-lat-lon grid, with 2
     // timesteps of data.
     static const int NLVL = 2;
     static const int NLAT = 6;
     static const int NLON = 12;
     static const int NREC = 2;

     // These are used to construct some example data.
     static const float SAMPLE_PRESSURE = 900.0;
     static const float SAMPLE_TEMP = 9.0;
     static const float START_LAT = 25.0;
     static const float START_LON = -125.0;

     // Return this code to the OS in case of failure.
     static const int NC_ERR = 2;

     int main()
     {
        // These arrays will store the latitude and longitude values.
        float lats[NLAT],lons[NLON];

        // These arrays will hold the data we will write out. We will
        // only need enough space to hold one timestep of data; one record.
        float pres_out[NLVL][NLAT][NLON];
        float temp_out[NLVL][NLAT][NLON];

        int i = 0;

        // Create some pretend data. If this wasn't an example program, we
        // would have some real data to write for example, model output.
        for (int lat = 0; lat < NLAT; lat++)
           lats[lat] = START_LAT + 5. * lat;
        for (int lon = 0; lon < NLON; lon++)
           lons[lon] = START_LON + 5. * lon;

        for (int lvl = 0; lvl < NLVL; lvl++)
           for (int lat = 0; lat < NLAT; lat++)
     	 for (int lon = 0; lon < NLON; lon++)
     	 {
     	    pres_out[lvl][lat][lon] = SAMPLE_PRESSURE + i;
     	    temp_out[lvl][lat][lon]  = SAMPLE_TEMP + i++;
     	 }

        // Change the error behavior of the netCDF C++ API by creating an
        // NcError object. Until it is destroyed, this NcError object will
        // ensure that the netCDF C++ API returns error codes on any
        // failure, prints an error message, and leaves any other error
        // handling to the calling program. In the case of this example, we
        // just exit with an NC_ERR error code.
        NcError err(NcError::verbose_nonfatal);

        // Create the file.
        NcFile dataFile("pres_temp_4D.nc", NcFile::Replace);

        // Check to see if the file was created.
        if(!dataFile.is_valid())
           return NC_ERR;

        // Define the dimensions. NetCDF will hand back an ncDim object for
        // each.
        NcDim *lvlDim, *latDim, *lonDim, *recDim;
        if (!(lvlDim = dataFile.add_dim("level", NLVL)))
           return NC_ERR;
        if (!(latDim = dataFile.add_dim("latitude", NLAT)))
           return NC_ERR;
        if (!(lonDim = dataFile.add_dim("longitude", NLON)))
           return NC_ERR;
        // Add an unlimited dimension...
        if (!(recDim = dataFile.add_dim("time")))
           return NC_ERR;

        // Define the coordinate variables.
        NcVar *latVar, *lonVar;
        if (!(latVar = dataFile.add_var("latitude", ncFloat, latDim)))
           return NC_ERR;
        if (!(lonVar = dataFile.add_var("longitude", ncFloat, lonDim)))
           return NC_ERR;

        // Define units attributes for coordinate vars. This attaches a
        // text attribute to each of the coordinate variables, containing
        // the units.
        if (!latVar->add_att("units", "degrees_north"))
           return NC_ERR;
        if (!lonVar->add_att("units", "degrees_east"))
           return NC_ERR;

        // Define the netCDF variables for the pressure and temperature
        // data.
        NcVar *presVar, *tempVar;
        if (!(presVar = dataFile.add_var("pressure", ncFloat, recDim,
     				    lvlDim, latDim, lonDim)))
           return NC_ERR;
        if (!(tempVar = dataFile.add_var("temperature", ncFloat, recDim,
     				    lvlDim, latDim, lonDim)))
           return NC_ERR;

        // Define units attributes for data variables.
        if (!presVar->add_att("units", "hPa"))
           return NC_ERR;
        if (!tempVar->add_att("units", "celsius"))
           return NC_ERR;

        // Write the coordinate variable data to the file.
        if (!latVar->put(lats, NLAT))
           return NC_ERR;
        if (!lonVar->put(lons, NLON))
           return NC_ERR;

        // Write the pretend data. This will write our surface pressure and
        // surface temperature data. The arrays only hold one timestep
        // worth of data. We will just rewrite the same data for each
        // timestep. In a real application, the data would change between
        // timesteps.
        for (int rec = 0; rec < NREC; rec++)
        {
           if (!presVar->put_rec(&pres_out[0][0][0], rec))
     	 return NC_ERR;
           if (!tempVar->put_rec(&temp_out[0][0][0], rec))
     	 return NC_ERR;
        }

        // The file is automatically closed by the destructor. This frees
        // up any internal netCDF resources associated with the file, and
        // flushes any buffers.

        cout << "*** SUCCESS writing example file pres_temp_4D.nc!" << endl;
        return 0;
     }

2.3.4.2 pres_temp_4D_rd.cpp
...........................

     /* This is part of the netCDF package.
        Copyright 2006 University Corporation for Atmospheric Research/Unidata.
        See COPYRIGHT file for conditions of use.

        This is an example program which writes some 4D pressure and
        temperatures. This example demonstrates the netCDF C++ API.

        This is part of the netCDF tutorial:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-tutorial

        Full documentation of the netCDF C++ API can be found at:
        http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx

        $Id: pres_temp_4D_wr.cpp,v 1.11 2007/01/19 12:52:13 ed Exp $
     */

     #include <iostream>
     #include <netcdfcpp.h>

     using namespace std;

     // We are writing 4D data, a 2 x 6 x 12 lvl-lat-lon grid, with 2
     // timesteps of data.
     static const int NLVL = 2;
     static const int NLAT = 6;
     static const int NLON = 12;
     static const int NREC = 2;

     // These are used to construct some example data.
     static const float SAMPLE_PRESSURE = 900.0;
     static const float SAMPLE_TEMP = 9.0;
     static const float START_LAT = 25.0;
     static const float START_LON = -125.0;

     // Return this code to the OS in case of failure.
     static const int NC_ERR = 2;

     int main()
     {
        // These arrays will store the latitude and longitude values.
        float lats[NLAT],lons[NLON];

        // These arrays will hold the data we will write out. We will
        // only need enough space to hold one timestep of data; one record.
        float pres_out[NLVL][NLAT][NLON];
        float temp_out[NLVL][NLAT][NLON];

        int i = 0;

        // Create some pretend data. If this wasn't an example program, we
        // would have some real data to write for example, model output.
        for (int lat = 0; lat < NLAT; lat++)
           lats[lat] = START_LAT + 5. * lat;
        for (int lon = 0; lon < NLON; lon++)
           lons[lon] = START_LON + 5. * lon;

        for (int lvl = 0; lvl < NLVL; lvl++)
           for (int lat = 0; lat < NLAT; lat++)
     	 for (int lon = 0; lon < NLON; lon++)
     	 {
     	    pres_out[lvl][lat][lon] = SAMPLE_PRESSURE + i;
     	    temp_out[lvl][lat][lon]  = SAMPLE_TEMP + i++;
     	 }

        // Change the error behavior of the netCDF C++ API by creating an
        // NcError object. Until it is destroyed, this NcError object will
        // ensure that the netCDF C++ API returns error codes on any
        // failure, prints an error message, and leaves any other error
        // handling to the calling program. In the case of this example, we
        // just exit with an NC_ERR error code.
        NcError err(NcError::verbose_nonfatal);

        // Create the file.
        NcFile dataFile("pres_temp_4D.nc", NcFile::Replace);

        // Check to see if the file was created.
        if(!dataFile.is_valid())
           return NC_ERR;

        // Define the dimensions. NetCDF will hand back an ncDim object for
        // each.
        NcDim *lvlDim, *latDim, *lonDim, *recDim;
        if (!(lvlDim = dataFile.add_dim("level", NLVL)))
           return NC_ERR;
        if (!(latDim = dataFile.add_dim("latitude", NLAT)))
           return NC_ERR;
        if (!(lonDim = dataFile.add_dim("longitude", NLON)))
           return NC_ERR;
        // Add an unlimited dimension...
        if (!(recDim = dataFile.add_dim("time")))
           return NC_ERR;

        // Define the coordinate variables.
        NcVar *latVar, *lonVar;
        if (!(latVar = dataFile.add_var("latitude", ncFloat, latDim)))
           return NC_ERR;
        if (!(lonVar = dataFile.add_var("longitude", ncFloat, lonDim)))
           return NC_ERR;

        // Define units attributes for coordinate vars. This attaches a
        // text attribute to each of the coordinate variables, containing
        // the units.
        if (!latVar->add_att("units", "degrees_north"))
           return NC_ERR;
        if (!lonVar->add_att("units", "degrees_east"))
           return NC_ERR;

        // Define the netCDF variables for the pressure and temperature
        // data.
        NcVar *presVar, *tempVar;
        if (!(presVar = dataFile.add_var("pressure", ncFloat, recDim,
     				    lvlDim, latDim, lonDim)))
           return NC_ERR;
        if (!(tempVar = dataFile.add_var("temperature", ncFloat, recDim,
     				    lvlDim, latDim, lonDim)))
           return NC_ERR;

        // Define units attributes for data variables.
        if (!presVar->add_att("units", "hPa"))
           return NC_ERR;
        if (!tempVar->add_att("units", "celsius"))
           return NC_ERR;

        // Write the coordinate variable data to the file.
        if (!latVar->put(lats, NLAT))
           return NC_ERR;
        if (!lonVar->put(lons, NLON))
           return NC_ERR;

        // Write the pretend data. This will write our surface pressure and
        // surface temperature data. The arrays only hold one timestep
        // worth of data. We will just rewrite the same data for each
        // timestep. In a real application, the data would change between
        // timesteps.
        for (int rec = 0; rec < NREC; rec++)
        {
           if (!presVar->put_rec(&pres_out[0][0][0], rec))
     	 return NC_ERR;
           if (!tempVar->put_rec(&temp_out[0][0][0], rec))
     	 return NC_ERR;
        }

        // The file is automatically closed by the destructor. This frees
        // up any internal netCDF resources associated with the file, and
        // flushes any buffers.

        cout << "*** SUCCESS writing example file pres_temp_4D.nc!" << endl;
        return 0;
     }

3 The Functions You Need in NetCDF-3
************************************

The netCDF-3 C and Fortran APIs each have over 100 functions, but most
users need only a handful. Listed below are the essential netCDF
functions for four important tasks in netCDF: creating new files,
reading existing files, learning about a netCDF file of unknown
structure, and reading and writing subsets of data.

   In each case the functions are presented for each of the four
language APIs: C, Fortran 77, Fortran 90, and C++, with hyper-links to
the detailed documentation of each function.

3.1 Creating New Files and Metadata, an Overview
================================================

To construct a netCDF file you need to:

`create the file'
     Specify the name, optionally the format: classic (the default) or
     64bit-offset.

`define metadata'
     Specify the names and types of dimensions, data variables, and
     attributes.

`write data'
     Write arrays of data from program variables to the netCDF file.
     Arrays of data may be written all at once, or in subsets.

`close the file'
     Close the file to flush all buffers to the disk and free all
     resources allocated for this file.


3.1.1 Creating a NetCDF File in C
---------------------------------

Use nc_create to create a file. Then use nc_def_dim to define each
shared dimension. The data variables are then specified with
nc_def_var. Any attributes are added with nc_put_att. Finally, call
nc_enddef to tell the library that you are done defining the metadata,
and ready to start writing the data.

   After all data are written to the file, call nc_close to ensure that
all buffers are flushed, and any resources associated with the open
file are returned to the operating system.

   For a very simple example, *Note simple_xy in C::.

   For a typical sequence of calls to the C versions of these functions,
see *Note Creating a NetCDF Dataset: (netcdf-c)Creating.

*Note nc_create:                     create a new netCDF file
(netcdf-c)nc_create.                 
*Note nc_def_dim:                    define a dimension
(netcdf-c)nc_def_dim.                
*Note nc_def_var:                    define a variable
(netcdf-c)nc_def_var.                
*Note nc_put_att_ type:              write attributes
(netcdf-c)nc_put_att_ type.          
*Note nc_enddef:                     leave define mode
(netcdf-c)nc_enddef.                 
*Note nc_put_vara_ type:             write arrays of data
(netcdf-c)nc_put_vara_ type.         
*Note nc_close: (netcdf-c)nc_close.  close a file

3.1.2 Creating a NetCDF File in Fortran 77
------------------------------------------

Use NF_CREATE to create a file. Then use NF_DEF_DIM to define each
shared dimension. The data variables are then specified with
NF_DEF_VAR. Any attributes are added with NF_PUT_ATT. Finally, call
NF_ENDDEF to tell the library that you are done defining the metadata,
and ready to start writing the data.

   After all data are written to the file, call NF_CLOSE to ensure that
all buffers are flushed, and any resources associated with the open
file are returned to the operating system.

   For a typical sequence of calls see *Note Creating a NetCDF Dataset:
(netcdf-f77)Creating.

   Fortran users take note: the netCDF Fortran 77 API consists of
wrappers around the functions of the netCDF C library. There is no
Fortran 77 code in netCDF except for these wrappers, and tests to
ensure that the wrappers work.

   The name of each Fortran function shows the outline of the C function
it wraps (for example, NF_CREATE is a wrapper around nc_create).

*Note NF_CREATE:                     create a new netCDF file
(netcdf-f77)NF_CREATE.               
*Note NF_DEF_DIM:                    define a dimension
(netcdf-f77)NF_DEF_DIM.              
*Note NF_DEF_VAR:                    define a variable
(netcdf-f77)NF_DEF_VAR.              
*Note NF_PUT_ATT_ type:              write an attribute
(netcdf-f77)NF_PUT_ATT_ type.        
*Note NF_ENDDEF:                     end define mode
(netcdf-f77)NF_ENDDEF.               
*Note NF_PUT_VARA_ type:             write arrays of data
(netcdf-f77)NF_PUT_VARA_ type.       
*Note NF_CLOSE:                      close the netCDF file
(netcdf-f77)NF_CLOSE.                

3.1.3 Creating a NetCDF File in Fortran 90
------------------------------------------

Use NF90_CREATE to create a file. Then use NF90_DEF_DIM to define each
shared dimension. The data variables are then specified with
NF90_DEF_VAR. Any attributes are added with NF90_PUT_ATT. Finally, call
NF90_ENDDEF to tell the library that you are done defining the metadata,
and ready to start writing the data.

   After all data are written to the file, call NF90_CLOSE to ensure
that all buffers are flushed, and any resources associated with the
open file are returned to the operating system.

   For a typical sequence of calls see *Note Creating a NetCDF Dataset:
(netcdf-f90)Creating.

   The netCDF Fortran 90 API calls the Fortran 77 API, which in turn
calls the netCDF C library.

   The name of each Fortran function shows the outline of the F77
function it wraps (for example, NF90_CREATE is a wrapper around
NF_CREATE). The F77 functions are, in turn, wrappers around the C
functions.

*Note NF90_CREATE:                   create a netCDF file
(netcdf-f90)NF90_CREATE.             
*Note NF90_DEF_DIM:                  define a dimension
(netcdf-f90)NF90_DEF_DIM.            
*Note NF90_DEF_VAR:                  define a variable
(netcdf-f90)NF90_DEF_VAR.            
*Note NF90_PUT_ATT_ type:            write an attribute
(netcdf-f90)NF90_PUT_ATT_ type.      
*Note NF90_ENDDEF:                   end define mode
(netcdf-f90)NF90_ENDDEF.             
*Note NF90_PUT_VARA_ type:           write arrays of data
(netcdf-f90)NF90_PUT_VARA_ type.     
*Note NF90_CLOSE:                    close the netCDF file
(netcdf-f90)NF90_CLOSE.              

3.1.4 Creating a NetCDF File in C++
-----------------------------------

Create an instance of the NcFile class to create a netCDF file. Use its
add_dim and add_var methods to add dimensions and variables. The
add_att method is available for both NcFile and NcVar.

   Use the NcError class to specify error handling behavior.

   For an example creating a simple file see *Note simple_xy_wr.cpp::.
For a more complex example see *Note pres_temp_4D_wr.cpp::.

*Note Class NcFile:                  a C++ class to manipulate netCDF
(netcdf-cxx)Class NcFile.            files
*Note Class NcDim:                   a C++ class to manipulate netCDF
(netcdf-cxx)Class NcDim.             dimensions
*Note Class NcVar:                   a C++ class to manipulate netCDF
(netcdf-cxx)Class NcVar.             variables
*Note Class NcAtt:                   a C++ class to manipulate netCDF
(netcdf-cxx)Class NcAtt.             attributes
*Note Class NcError:                 a C++ class to control netCDF error
(netcdf-cxx)Class NcError.           handling

3.2 Reading NetCDF Files of Known Structure
===========================================

To read a netCDF file of known structure, you need to:

`open the file'
     Specify the file name and whether you want read-write or read-only
     access.

`read variable or attribute data'
     Read the data or attributes of interest.

`close the file'
     Release all resources associated with this file.


   Use ncdump to learn the structure of a file (use the -h option). For
more information about ncdump see *Note NetCDF Utilities:
(netcdf)NetCDF Utilities.

3.2.1 Numbering of NetCDF IDs
-----------------------------

In C, Fortran 77, and Fortran 90, netCDF objects are identified by an
integer: the ID. NetCDF functions use this ID to identify the object.
It's helpful for the programmer to understand these IDs.

   Open data files, dimensions, variables, and attributes are each
numbered independently, and are always numbered in the order in which
they were defined. (They also appear in this order in ncdump output.)
Numbering starts with 0 in C, and 1 in Fortran 77/90.

   For example, the first variable defined in a file will have an ID of
0 in C programs, and 1 in Fortran programs, and functions that apply to
a variable will need to know the ID of the variable you mean.

   (The numbering of files is an exception: file IDs are assigned by the
operating system when a file is opened, and are not permanently
associated with the file. IDs for netCDF dimensions and variables are
persistent, but deleting an attribute changes subsequent attribute
numbers.)

   Although netCDF refers to everything by an integer id (varid, dimid,
attnum), there are inquiry functions which, given a name, will return
an ID. For example, in the C API, nc_inq_varid will take a character
string (the name), and give back the ID of the variable of that name.
The variable ID is then used in subsequent calls (to read the data, for
example).

   Other inquiry functions exist to further describe the file. (*note
Inquiry Functions::).

3.2.2 Reading a Known NetCDF File in C
--------------------------------------

For a typical sequence of calls to these C functions see *Note Reading
a NetCDF Dataset with Known Names: (netcdf-c)Reading Known.

*Note        open a netCDF file      
nc_open:                             
(netcdf-c)nc_open.                        
*Note        read an attribute       
nc_get_att:                          
(netcdf-c)nc_get_att.                        
*Note        read arrays of data     
nc_get_vara_                         
type:                                
(netcdf-c)nc_get_vara_                        
type.                                
*Note        close the file          
nc_close:                            
(netcdf-c)nc_close.                        

3.2.3 Reading a Known NetCDF File in Fortran 77
-----------------------------------------------

For a typical sequence of calls to these functions see *Note Reading a
NetCDF Dataset with Known Names: (netcdf-f77)Reading Known.

*Note NF_OPEN: (netcdf-f77)NF_OPEN.  open a netCDF file
*Note NF_GET_ATT:                    read an attribute
(netcdf-f77)NF_GET_ATT.              
*Note NF_GET_VARA_ type:             read arrays of data
(netcdf-f77)NF_GET_VARA_ type.       
*Note NF_CLOSE:                      close the file
(netcdf-f77)NF_CLOSE.                

3.2.4 Reading a Known NetCDF File in Fortran 90
-----------------------------------------------

For a typical sequence of calls to these functions see *Note Reading a
NetCDF Dataset with Known Names: (netcdf-f90)Reading Known.

*Note NF90_OPEN:                     open a netCDF file
(netcdf-f90)NF90_OPEN.               
*Note NF90_GET_ATT:                  read an attribute
(netcdf-f90)NF90_GET_ATT.            
*Note NF90_GET_VARA:                 read arrays of data
(netcdf-f90)NF90_GET_VARA.           
*Note NF90_CLOSE:                    close the file
(netcdf-f90)NF90_CLOSE.              

3.2.5 Reading a Known NetCDF File in C++
----------------------------------------

*Note Class  a C++ class to          
NcFile:      manipulate netCDF files 
(netcdf-cxx)Class                        
NcFile.                              
*Note Class  a C++ class to          
NcDim:       manipulate netCDF       
(netcdf-cxx)Classdimensions              
NcDim.                               
*Note Class  a C++ class to          
NcVar:       manipulate netCDF       
(netcdf-cxx)Classvariables               
NcVar.                               
*Note Class  a C++ class to          
NcAtt:       manipulate netCDF       
(netcdf-cxx)Classattributes              
NcAtt.                               

3.3 Reading NetCDF Files of Unknown Structure
=============================================

Perhaps you would like to write your software to handle more general
cases, so that you don't have to adjust your source every time the grid
size changes, or a variable is added to the file.

   There are inquiry functions that let you find out everything you need
to know about a file. These functions contain "inq" or "INQ" in their
names.

   Using the inquiry functions, it is possible to write code that will
read and understand any netCDF file, whatever its contents. (For
example, ncdump does just that.)

3.3.1 Inquiry in C
------------------

First use nc_inq, which will tell you how many variables and global
attributes there are in the file.

   Start with global attribute 0, and proceed to natts - 1, the number
of global attributes minus one. The nc_inq_att function will tell you
the name, type, and length of each global attribute.

   Then start with dimid 0, and proceed to dimid ndims - 1, calling
nc_inq_dim. This will tell you the name and length of each dimension,
and whether it is unlimited.

   Then start with varid 0, and proceed to varid nvars - 1, calling
nc_inq_var. This will tell you the number of dimensions of this
variable, and their associated IDs. It will also get the name and type
of this variable, and whether there are any attributes attached. If
there are attributes attached, use the nc_inq_att function to get their
names, types, and lengths.

   (To read an attribute, use the appropriate nc_get_att_<TYPE>
function, like nc_get_att_int() to get the data from an attribute that
is an array of integers.)

   There are also functions that return an item's ID, given its name.
To find IDs from the names, use functions nc_inq_dimid, nc_inq_attnum,
and nc_inq_varid.

   For a typical sequence of calls to these functions see *Note Reading
a netCDF Dataset with Unknown Names: (netcdf-c)Reading Unknown.

3.3.1.1 NULL Parameters in Inquiry Functions
............................................

With any of the C inquiry functions, a NULL pointer can be used to
ignore a return parameter. Consider the nc_inq function:

     EXTERNL int
     nc_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp);

   If you call this with NULL for the last three parameters, you can
learn the number of dimensions without bothering about the number of
variables, number of global attributes, and the ID of the unlimited
dimension.

   For further convenience, we provide functions like nc_inq_ndims,
which only finds the number of dimensions, exactly as if you had called
nc_inq, with NULLs in all parameters except ndimsp. (In fact, this is
just what the nc_inq_ndims functions does).

*Note        Find number                     
nc_inq:      of                              
(netcdf-c)nc_inq.dimensions,                     
             variables,                      
             and global                      
             attributes,                     
             and the                         
             unlimited                       
             dimid.                          
*Note        Find                            
nc_inq_att:  attribute                       
(netcdf-c)nc_inq_att.name, type,                     
             and length.                     
*Note        Find                            
nc_inq_dim   dimension                       
Family:      name and                        
(netcdf-c)nc_inq_dimlength.                         
Family.                                      
*Note        Find                            
nc_inq_var:  variable                        
(netcdf-c)nc_inq_var.name, type,                     
             num                             
             dimensions,                     
             dim IDs,                        
             and num                         
             attributes.                     
*Note        Find                            
nc_inq_dimid:dimension                       
(netcdf-c)nc_inq_dimid.ID from its                     
             name.                           
*Note        Find                            
nc_inq_varid:variable ID                     
(netcdf-c)nc_inq_varid.from its                        
             name.                           
*Note        Find file                       
nc_inq_format:format:                         
(netcdf-c)nc_inq_format.classic or                      
             64-bit                          
             offset                          
*Note        Find the                        
nc_inq_libvers:netCDF                          
(netcdf-c)nc_inq_libvers.version.                        
             (Currently                      
             3.6.2).                         

3.3.2 Inquiry in Fortran 77
---------------------------

First use NF_INQ, which will tell you how many variables and global
attributes there are in the file. Then start with varid 1, and proceed
to varid nvars, calling NF_INQ_VAR.

   For a typical sequence of calls to these functions see *Note Reading
a netCDF Dataset with Unknown Names: (netcdf-f77)Reading Unknown.

*Note NF_INQ:       Find number of      
(netcdf-f77)NF_INQ. dimensions,         
                    variables, and      
                    global attributes,  
                    and the unlimited   
                    dimid.              
*Note NF_INQ_DIM:   Find dimension      
(netcdf-f77)NF_INQ_DIM.name and length.    
*Note               Find variable ID    
NF_INQ_VARID:       from its name.      
(netcdf-f77)NF_INQ_VARID.                    
*Note NF_INQ_VAR:   Find variable       
(netcdf-f77)NF_INQ_VAR.name, type, num     
                    dimensions, dim     
                    IDs, and num        
                    attributes.         
*Note               Find dimension ID   
NF_INQ_DIMID:       from its name.      
(netcdf-f77)NF_INQ_DIMID.                    
*Note NF_INQ_DIM:   Find dimension      
(netcdf-f77)NF_INQ_DIM.name and length.    
*Note NF_INQ_ATT:   Find attribute      
(netcdf-f77)NF_INQ_ATT.name, type, and     
                    length.             
*Note               Find file format:   
NF_INQ_FORMAT:      classic or 64-bit   
(netcdf-f77)NF_INQ_FORMAT.offset              
*Note               Find the netCDF     
NF_INQ_LIBVERS:     version.            
(netcdf-f77)NF_INQ_LIBVERS.(Currently 3.6.2).  

3.3.3 Inquiry in Fortran 90
---------------------------

First use NF90_INQ, which will tell you how many variables and global
attributes there are in the file. Then start with varid 1, and proceed
to varid nvars, calling NF90_INQ_VAR.

   For a typical sequence of calls to these functions, see *Note
Reading a netCDF Dataset with Unknown Names: (netcdf-f90)Reading
Unknown.

*Note NF90_INQ:     Find number of      
(netcdf-f90)NF90_INQ.dimensions,         
                    variables, and      
                    global attributes,  
                    and the unlimited   
                    dimid.              
*Note               Find dimension      
NF90_INQ_DIM:       name and length.    
(netcdf-f90)NF90_INQ_DIM.                    
*Note               Find variable ID    
NF90_INQ_VARID:     from its name.      
(netcdf-f90)NF90_INQ_VARID.                    
*Note               Find variable       
NF90_INQ_VAR:       name, type, num     
(netcdf-f90)NF90_INQ_VAR.dimensions, dim     
                    IDs, and num        
                    attributes.         
*Note               Find dimension ID   
NF90_INQ_DIMID:     from its name.      
(netcdf-f90)NF90_INQ_DIMID.                    
*Note               Find dimension      
NF90_INQ_DIM:       name and length.    
(netcdf-f90)NF90_INQ_DIM.                    
*Note               Find attribute      
NF90_INQ_ATT:       name, type, and     
(netcdf-f90)NF90_INQ_ATT.length.             
*Note               Find file format:   
NF90_INQ_FORMAT:    classic or 64-bit   
(netcdf-f90)NF90_INQ_FORMAT.offset              
*Note               Find the netCDF     
NF90_INQ_LIBVERS:   version.            
(netcdf-f90)NF90_INQ_LIBVERS.(Currently 3.6.2).  

3.3.4 Inquiry Functions in the C++ API
--------------------------------------

*Note Class  a C++ class                     
NcFile:      to                              
(netcdf-cxx)Classmanipulate                      
NcFile.      netCDF files                    
*Note Class  a C++ class                     
NcDim:       to                              
(netcdf-cxx)Classmanipulate                      
NcDim.       netCDF                          
             dimensions                      
*Note Class  a C++ class                     
NcVar:       to                              
(netcdf-cxx)Classmanipulate                      
NcVar.       netCDF                          
             variables                       
*Note Class  a C++ class                     
NcAtt:       to                              
(netcdf-cxx)Classmanipulate                      
NcAtt.       netCDF                          
             attributes                      

3.4 Reading and Writing Subsets of Data
=======================================

Usually users are interested in reading or writing subsets of variables
in a netCDF data file. The netCDF APIs provide a variety of functions
for this purpose.

   In the simplest case, you will use the same type for both file and
in-memory storage, but in some cases you may wish to use different
types. For example, you might have a netCDF file that contains integer
data, and you wish to read it into floating-point storage, converting
the data as it is read. The same sort of type conversion can be done
when writing the data.

   To convert to a type while reading data, use the appropriate
nc_get_vara_<TYPE> or NF_GET_VARA_<TYPE> function. For example, the C
function nc_get_vara_float(), and the Fortran function NF_GET_VARA_REAL
will read netCDF data of any numeric type into a floating-point array,
automatically converting each element to the desired type.

   To convert from a type while writing data, use the appropriate
nc_put_vara_<TYPE> or NF_PUT_VARA_<TYPE> function. For example, the C
function nc_put_vara_float(), and the Fortran function NC_PUT_VARA_REAL
will write floating-point data into netCDF arrays, automatically
converting each element of the array to the type of the netCDF variable.

   The <TYPE> in the function name refers to the type of the in-memory
data, in both cases. They type of the file data is determined when the
netCDF variable is defined.

3.4.1 Reading and Writing Subsets of Data in C
----------------------------------------------

The type of the data may be automatically converted on read or write.
For more information about type conversion see *Note Type Conversion:
(netcdf-c)Type Conversion.

Read the entire variable at once     *Note nc_get_var_  
                                     type:              
                                     (netcdf-c)nc_get_var_
                                     type.              
Write the entire variable at once    *Note nc_put_var_  
                                     type:              
                                     (netcdf-c)nc_put_var_
                                     type.              
Read just one value                  *Note              
                                     nc_get_var1_       
                                     type:              
                                     (netcdf-c)nc_get_var1_
                                     type.              
Write just one value                 *Note              
                                     nc_put_var1_       
                                     type:              
                                     (netcdf-c)nc_put_var1_
                                     type.              
Read an array subset                 *Note              
                                     nc_get_vara_       
                                     type:              
                                     (netcdf-c)nc_get_vara_
                                     type.              
Write an array subset                *Note              
                                     nc_put_vara_       
                                     type:              
                                     (netcdf-c)nc_put_vara_
                                     type.              
Read an array with strides           *Note              
                                     nc_get_vars_       
                                     type:              
                                     (netcdf-c)nc_get_vars_
                                     type.              
Write an array with strides          *Note              
                                     nc_put_vars_       
                                     type:              
                                     (netcdf-c)nc_put_vars_
                                     type.              

3.4.2 Reading and Writing Subsets of Data in Fortran 77
-------------------------------------------------------

The type of the data may be automatically converted on read or write.
For more information about type conversion see *Note Type Conversion:
(netcdf-f77)Type Conversion.

Read the entire variable at once     *Note NF_GET_VAR_  
                                     type:              
                                     (netcdf-f77)NF_GET_VAR_
                                     type.              
Write the entire variable at once    *Note NF_PUT_VAR_  
                                     type:              
                                     (netcdf-f77)NF_PUT_VAR_
                                     type.              
Read just one value                  *Note              
                                     NF_GET_VAR1_       
                                     type:              
                                     (netcdf-f77)NF_GET_VAR1_
                                     type.              
Write just one value                 *Note              
                                     NF_PUT_VAR1_       
                                     type:              
                                     (netcdf-f77)NF_PUT_VAR1_
                                     type.              
Read an array subset                 *Note              
                                     NF_GET_VARA_       
                                     type:              
                                     (netcdf-f77)NF_GET_VARA_
                                     type.              
Write an array subset                *Note              
                                     NF_PUT_VARA_       
                                     type:              
                                     (netcdf-f77)NF_PUT_VARA_
                                     type.              
Read an array with strides           *Note              
                                     NF_GET_VARS_       
                                     type:              
                                     (netcdf-f77)NF_GET_VARS_
                                     type.              
Write an array with strides          *Note              
                                     NF_PUT_VARS_       
                                     type:              
                                     (netcdf-f77)NF_PUT_VARS_
                                     type.              

3.4.3 Reading and Writing Subsets of Data in Fortran 90
-------------------------------------------------------

The type of the data may be automatically converted on read or write.
For more information about type conversion see *Note Type Conversion:
(netcdf-f90)Type Conversion.

Read the entire variable at once     *Note              
                                     NF90_GET_VAR_      
                                     type:              
                                     (netcdf-f90)NF90_GET_VAR_
                                     type.              
Write the entire variable at once    *Note              
                                     NF90_PUT_VAR_      
                                     type:              
                                     (netcdf-f90)NF90_PUT_VAR_
                                     type.              
Read just one value                  *Note              
                                     NF90_GET_VAR1_     
                                     type:              
                                     (netcdf-f90)NF90_GET_VAR1_
                                     type.              
Write just one value                 *Note              
                                     NF90_PUT_VAR1_     
                                     type:              
                                     (netcdf-f90)NF90_PUT_VAR1_
                                     type.              
Read an array subset                 *Note              
                                     NF90_GET_VARA_     
                                     type:              
                                     (netcdf-f90)NF90_GET_VARA_
                                     type.              
Write an array subset                *Note              
                                     NF90_PUT_VARA_     
                                     type:              
                                     (netcdf-f90)NF90_PUT_VARA_
                                     type.              
Read an array with strides           *Note              
                                     NF90_GET_VARS_     
                                     type:              
                                     (netcdf-f90)NF90_GET_VARS_
                                     type.              
Write an array with strides          *Note              
                                     NF90_PUT_VARS_     
                                     type:              
                                     (netcdf-f90)NF90_PUT_VARS_
                                     type.              

3.4.4 Reading and Writing Subsets of Data in C++
------------------------------------------------

To read a record of data at a time, use the set_cur method of the NcVar
class to set the number of the record of interest, and then use the get
method to read the record.

*Note Class NcVar:                   a C++ class to     
(netcdf-cxx)Class NcVar.             manipulate netCDF  
                                     variables, use     
                                     the set_cur and    
                                     get methods to     
                                     read records from  
                                     a file.            

Index
*****

64-bit offset format:                          See 1.8.      (line  344)
attribute:                                     See 1.1.      (line   44)
C++, netCDF API:                               See 1.6.      (line  254)
C, netCDF API:                                 See 1.6.      (line  254)
classic format:                                See 1.8.      (line  344)
creating files in C:                           See 3.1.1.    (line 4280)
creating files in C++:                         See 3.1.4.    (line 4390)
creating files in Fortran <1>:                 See 3.1.3.    (line 4351)
creating files in Fortran:                     See 3.1.2.    (line 4312)
creating netCDF files:                         See 3.1.      (line 4258)
data model:                                    See 1.1.      (line   44)
dimension:                                     See 1.1.      (line   44)
example programs:                              See 2.        (line  405)
Fortran 77, netCDF API:                        See 1.6.      (line  254)
Fortran 90, netCDF API:                        See 1.6.      (line  254)
guillotine:
          See ``NetCDF Tutorial''.                           (line    4)
inquiry functions:                             See 3.2.      (line 4413)
language APIs for netCDF:                      See 1.6.      (line  254)
nc_close:                                      See 3.1.1.    (line 4280)
nc_create:                                     See 3.1.1.    (line 4280)
nc_def_dim:                                    See 3.1.1.    (line 4280)
nc_def_var:                                    See 3.1.1.    (line 4280)
nc_enddef:                                     See 3.1.1.    (line 4280)
nc_get_att:                                    See 3.2.2.    (line 4465)
nc_get_var1:                                   See 3.4.1.    (line 4784)
nc_get_vara:                                   See 3.2.2.    (line 4465)
nc_get_varm:                                   See 3.4.1.    (line 4784)
nc_get_vars:                                   See 3.4.1.    (line 4784)
nc_open:                                       See 3.2.2.    (line 4465)
nc_put_att:                                    See 3.1.1.    (line 4280)
nc_put_var1:                                   See 3.4.1.    (line 4784)
nc_put_vara:                                   See 3.1.1.    (line 4280)
nc_put_varm:                                   See 3.4.1.    (line 4784)
nc_put_vars:                                   See 3.4.1.    (line 4784)
ncdump:                                        See 1.5.      (line  208)
NcFile:                                        See 3.2.5.    (line 4515)
ncgen:                                         See 1.5.      (line  208)
netCDF, definition:                            See 1.        (line   24)
netCDF-4:                                      See 1.9.      (line  381)
NF90_CLOSE:                                    See 3.1.3.    (line 4351)
NF90_CREATE:                                   See 3.1.3.    (line 4351)
NF90_DEF_DIM:                                  See 3.1.3.    (line 4351)
NF90_DEF_VAR:                                  See 3.1.3.    (line 4351)
NF90_ENDDEF:                                   See 3.1.3.    (line 4351)
NF90_GET_ATT:                                  See 3.2.4.    (line 4500)
NF90_GET_VAR1:                                 See 3.4.3.    (line 4876)
NF90_GET_VARA:                                 See 3.2.4.    (line 4500)
NF90_GET_VARM:                                 See 3.4.3.    (line 4876)
NF90_GET_VARS:                                 See 3.4.3.    (line 4876)
NF90_OPEN:                                     See 3.2.4.    (line 4500)
NF90_PUT_ATT_ type:                            See 3.1.3.    (line 4351)
NF90_PUT_VAR1:                                 See 3.4.3.    (line 4876)
NF90_PUT_VARA:                                 See 3.1.3.    (line 4351)
NF90_PUT_VARM:                                 See 3.4.3.    (line 4876)
NF90_PUT_VARS:                                 See 3.4.3.    (line 4876)
NF_CLOSE:                                      See 3.1.2.    (line 4312)
NF_CREATE:                                     See 3.1.2.    (line 4312)
NF_DEF_DIM:                                    See 3.1.2.    (line 4312)
NF_DEF_VAR:                                    See 3.1.2.    (line 4312)
NF_ENDDEF:                                     See 3.1.2.    (line 4312)
NF_GET_ATT:                                    See 3.2.3.    (line 4486)
NF_GET_VAR1:                                   See 3.4.2.    (line 4830)
NF_GET_VARA:                                   See 3.2.3.    (line 4486)
NF_GET_VARM:                                   See 3.4.2.    (line 4830)
NF_GET_VARS:                                   See 3.4.2.    (line 4830)
NF_OPEN:                                       See 3.2.3.    (line 4486)
NF_PUT_ATT_ type:                              See 3.1.2.    (line 4312)
NF_PUT_VAR1:                                   See 3.4.2.    (line 4830)
NF_PUT_VARA:                                   See 3.1.2.    (line 4312)
NF_PUT_VARM:                                   See 3.4.2.    (line 4830)
NF_PUT_VARS:                                   See 3.4.2.    (line 4830)
perl, netCDF API:                              See 1.6.      (line  254)
pres_temp_4D example:                          See 2.        (line  405)
python, netCDF API:                            See 1.6.      (line  254)
reading netCDF files of known structure:       See 3.2.      (line 4413)
reading netCDF files with C:                   See 3.2.2.    (line 4465)
reading netCDF files with C++:                 See 3.2.5.    (line 4515)
reading netCDF files with Fortran 77:          See 3.2.3.    (line 4486)
reading netCDF files with Fortran 90:          See 3.2.4.    (line 4500)
ruby, netCDF API:                              See 1.6.      (line  254)
sfc_pres_temp example:                         See 2.        (line  405)
simple_xy example:                             See 2.        (line  405)
software for netCDF:                           See 1.5.      (line  208)
third-party tools:                             See 1.5.      (line  208)
tools for manipulating netCDF:                 See 1.6.      (line  254)
UCAR:                                          See 1.        (line   24)
Unidata:                                       See 1.        (line   24)
V2 API:                                        See 1.6.      (line  254)
variable:                                      See 1.1.      (line   44)
