A first time primer for reading netcdf files

Contents

1.0 Why use netCDF for the WOCE Global Data set?
2.0 Using FORTRAN to read neCDF files
3.0 Using MATLAB to read netCDF files
4.0 Using C to read netCDF files
5.0 Using IDL to read netCDF files
6.0 Other methods and examining netCDF files
7.0 Important Web sites
Appendix 1: Readnet.f created from cdf2fortran
Appendix 2: Example Matlab script for current meter data
Appendix 3: Example output from ncdump
Appendix 4: Bug in gennet.for

Return to the previous document.


Summary

This document describes some simple tools that are available for reading the netCDF files found in the WOCE Global Data set Volume 3. These tools allow the netCDF files to be read quickly and easily and to be manipulated by many common analysis packages in addition to traditional languages such as Fortran (both Fortran 77 and Fortran 90), C/C++ and Java.

Because netCDF format is now used for all of the data products in the WOCE Global Data set, the skills required to read one data product are the same as those needed to read the others. This reduces the hurdles involved in reading the different data products and allows the analyst to concentrate on the interpretation of observations from many different sources. Because the netCDF files are self-describing, the attributes of each variable (such as units and name) are defined in the data file, along with other information such as the source, creation date, investigator, position, etc. This documentation preserves much of the original information in the data file, reducing the chance of errors occurring during analysis.

Return to the top of the primer.


1.0 Why use netCDF for the WOCE CDROMs?

The netCDF format has many advantages, the most important of which is that it is self-describing, meaning that software packages can directly read the data and determine its structure, the variable names and essential metadata such as the units. This self-describing aspect of netCDF file format means that the information needed to ensure accurate work (reduce the incidence of errors) is available with the data itself. Secondly, it means that programs described below can examine a netCDF file and generate the code needed to read the file whether it be Fortran, C/C++, JAVA or PERL. Thirdly, plotting and analysis packages (e.g. FERRET, IDL, Matlab) can directly read the netCDF files for plotting or analysis.

Although there is an initial learning curve for the inexperienced netCDF user, high efficiency in reading netCDF files and files from multiple sources can be readily achieved as shown in the examples below. These savings translate to more time for analysing data and addressing the synthesis of the WOCE Global Data.

I have assumed that netCDF libraries have already been installed on your system. They can be obtained from UCAR's netCDF site and are available for Unix, Windows and Macintosh based systems. This site also contains an excellent description of the Fortran, JAVA and PERL interfaces for netCDF files. Free and commercial software that uses netCDF for input is also listed at these sites and includes products such as FERRET, GMT and GrADs as well as commercial products such as Matlab, NCAR Graphics, IDL and others. Here we focus on reading netCDF files with FORTRAN, Matlab, C, IDL, ncdump and ncBrowse.

Return to the top of the primer.


Using FORTRAN to read netCDF files

The simplest way to create the Fortran code you need to read a netCDF file is to use either of the Fortran programs cdf2fortran.f or gennet.for. cdf2fortran.f can be obtained at the UCAR site given above or at

http://www-c4.ucsd.edu/~cids/software/visual.html,

and gennet.for can be downloaded from

www.unidata.ucar.edu/packages/netcdf/contrib.html.

These programs read a netCDF file and create another Fortran program with the required calls to the netCDF libraries. This machine-generated program needs only to be compiled (with the correct include file and netCDF libraries). When executed this code fragment can then read the netCDF file and is ready for the Fortran code to be added to undertake the analysis required by the user. The variable names reflect the internal structure of the netCDF file and this machine generated code is quite readable by humans.

2.1 Worked example of cdf2fortran

The cdf2fortran.f code has been tested on samples of the netCDF files in the WOCE dataset. To utilize it, retrieve and unpack the cdf2fortran tar file; then use the make command to compile the code. cdf2fortran.f utilizes the Unidata netCDF libraries and includes, which you should already have downloaded from Unidata and installed on your computer. You will have to check that the include directory and the library directory are correct for your particular installation of the Unidata materials. Note that the example shown here assumes a UNIX/Linux environment. You may need to employ a different but equivalent procedure in a different environment. To compile cdf2fortran just type

> make cdf2fortran

To execute the cdf2fortran code, provide cdf2fortran with the name of a netcdf file, in this case a current meter record named rcm00683.nc. cdf2fortran will create a new Fortran program named readnet.f:

> cdf2fortran rcm00683.nc

Generated Fortran program called readnet.f

>

Next, edit readnet.f to correct the "include ‘netcdf.inc’" statement for your particular installation. Then compile readnet.f with

> f77 readnet.f

Alternatively, you can compile readnet.f using the -I option to get the correct include file and the -l option to get the correct library file:

> f77 -c readnet.f -I/usr/local/netcdf/include

> f77 -o readnet readnet.o -l/usr/local/netcdf/lib/libnetcdf.a

Sometimes there is a problem at compilation because one of the netCDF file's variable names may be the same as a parameter name in readnet.f. Changing the parameter name fixes this problem and now you should have a complete Fortran code able to read your particular netCDF file. The result of compiling readnet.f for a sample of the current meter data in WOCE Global Data Set is shown in Appendix 1. Although this piece of code is quite long (compared to the examples shown below) it is reliable and is quick to develop compared to reading files that are not self-describing, such as plain ASCII files. The sample code fragment can in principle be generalised to read the netCDF data for all of the different current meter records. The program gennet.for works in a very similar way and produces a slightly better-documented Fortran code. See Appendix 4 for fixing a bug in the readnet.f programs created by gennet.for.

Return to the top of the primer.


3.0 Using Matlab to read netCDF files

Commonwealth Scientific Industrial Research Organisation (CSIRO) distributes a Matlab interface for reading netCDF files (www.marine.csiro.au/sw/matlab-netcdf.html). This is a very powerful tool for those who are only interested in reading netCDF files. Those who want to create netCDF files from within Matlab should use Chuck Denham's interface (http://crusty.er.usgs.gov/~cdenham). You will also need this software to use the CSIRO Matlab/netCDF interface anyway. Follow the install instructions at the two web sites above.

3.1 Sample commands of CSIRO Matlab/netCDF interface

Of the 6 main commands, the two most important are getnc (getcdf) and inqnc (inqcdf). Detailed instructions on their use can be found at www.marine.csiro.au/sw/matlab-netcdf.html; only a bare bones description is given here. The use of inqnc allows interactive interrogation of the netCDF file. In Matlab, for example:

>> inqnc('rcm01037')

--- Global attributes ---

experiment_name: Deep Currents (PCM6)
mooring_name: WHOI 947
pi_name: B.Owens/B.Warren
instrument_type: VACM
latitude: 40.6000
longitude: 147.3492
instrument_depth: 1999.0 m
seafloor_depth: 5280 m
sampling_interval: 30 min
earliest_start_time: 12-jun-1993 12:15:00
latest_stop_time: 01-jul-1995 12:45:00
null_value: -999.9
The 1 dimensions are 1) time = 35954.
time is unlimited in length

----- Get further information about the following variables -----

-1) None of them (no further information)
0) All of the variables
1) date 2) time 3) speed
4) direction 5) u 6) v
7) temperature 8) pressure

>>

creates a description of the contents of the current meter record rcm01037.nc. The global attributes consist of general information about the data, and in this example include the principal investigator, the instrument name, experiment name, etc. In addition inqnc gives a list of the variables that are contained within the file. In this case there are 8 different variables (date, time, speed, etc.) that are organised as vectors with each element corresponding to a particular time (i.e., these are time series). All the vectors have a length of 35954. Because inqnc is interactive it is possible to determine the attributes of each of the variables. To retrieve one of the variables within the above data set, such as speed, the getnc command is used:

>> speed=getnc('rcm01037','speed');

This is the simplest use of the getnc command. Because only two arguments are provided getnc assumes that the data are to be automatically scaled, flagged data will be changed to NaN (not a number), and all data are required. The Matlab script in Appendix 2 shows how all of the Matlab data in the above test file can be read with just 7 lines of code. This is considerably less than in the Fortran example shown in Appendix 1. However the development time for the Fortran and Matlab examples is similar and quick.

The getnc command also has arguments that allow changing missing values, changing the stride length (i.e. allow sub-sampling of the variable), etc. In this way the user can sub-sample, scale the data and read only the variables that are required from the netCDF file. In very large files this represents an important advantage to the user. A nice example of this capability is shown on the above website (by Jim Mansbridge). The website also shows an example of the Matlab command

>> help inqnc

in which all the arguments are listed.

All of the netCDF files that appear in the WOCE Global Data Set can be read by scripts based on just these two Matlab commands. By using the simplest form of getnc you will be able to read most of the netCDF files from a particular WOCE Data Assembly Centre with a single script. Thus it is easy and quick to create macros that can read the different netCDF files from a WOCE Data Assembly Centre, leading to significant savings in time and effort. Other important commands are whatnc (gives a list of netCDF files in local directory) and attnc (gets the attributes of particular variables, such as scale factor).

If necessary the scale factor applied to data can be obtained from the netCDF file by using the attnc comand. For example,

>> Latitude=getnc(file,'Latitude')*attnc(file,'Latitude','Scale');

would force the Latitude to be correctly scaled by the scale factor from within the netcCDF file.

Return to the top of the primer.


4.0 Using C to read netCDF files

The simplest way to create the C code you need to read a netCDF is to use the C program cdf2c.c, which can be obtained from the Unidata site or from

http://www-c4.ucsd.edu/~cids/software/visual.html.

This program reads a netCDF file and creates another C program with the required calls to the netCDF libraries. The latter machine-generated program only needs to be compiled, with the correct include file and netCDF library. When executed this code fragment can then read the netCDF file and is ready for C code to be added to undertake the analysis required by the user. The procedure for installing and compiling is described in the documentation from the web site listed above and is similar in operation to the cdf2fortran program described above.

Return to the top of the primer.


5.0 Using IDL to read netCDF files

IDL can read netCDF files and specifically has a browser to do this (see page 137 of What's new in IDL 5.3). In addition IDL has specific routines for reading netCDF files. However, the simplest way to create the IDL code you need to read a netCDF file is to use the IDL program cdf2idl, which is available at the Unidata site or at

http://www-c4.ucsd.edu/~cids/software/visual.html.

The concept of this program is similar to that of the cdf2fortran.f, cdf2c.c, and cdf2asc.c programs and is provided by the same group (C4 Interactive Display System). The program reads a netCDF file and create another IDL script which can read the netCDF file.

5.1 Example of using cdf2idl

From within IDL all you need to do, to read the current meter record used in the cdf2fortran example (Section 2.1) is

IDL> .run cdf2idl.pro

IDL> cdf2idl, 'rcm00683.nc'

IDL> @script.idl

At the completion of this script all of the current meter data are in memory ready to be analysed. A total of 3 lines of IDL code is needed to read this data set. These three lines of code are so general that they will actually read any of the netCDF files from any of the WOCE Data Assembly Centres provided as part of the WOCE Global Data Set.

Return to the top of the primer.


6.0 Other methods and examining netCDF files

6.1 ncdump

This utility is a very useful program for those who do not have Matlab or IDL and want to check the attributes and obtain the data from a netCDF file. The NetCDF User's Guide, which you can download from Unidata, describes this command (and its partner ncgen) in detail. To obtain the attributes of the current meter data one would enter

>ncdump -h rcm00683.nc

Appendix 3 shows the output from this command. To obtain the speed data in this file type

>ncdump -v speed rcm00683.nc

or to obtain the speed and the direction data enter

>ncdump -v speed, direction rcm00683.nc

The last command can lead to large files ASCII files that have a relatively simple structure and can be read by programs. However, the chief value of ncdump is that it allows one to check attributes and structure of netcdf files quickly and easily. A more convenient way to examine netCDF files is to be able to visualise the data using a graphical interface such as ncBrowse.

6.2 ncBrowse

This program is a Java application. It can be obtained at www.epic.noaa.gov/java/ncBrowse/. ncBrowse allows the contents of variables and global attributes to be viewed graphically. It can run on any computer - UNIX workstation, PC or Macintosh - that has the Java Virtual Machine installed. (See the above web site or http://java.sun.com/products/jdk/1.2 for information about Java.) The interface is largely self-explanatory and provides a wonderful method for browsing generic netCDF files. ncBrowse can be slow on older computers but is well worth installing and using to check netCDF files. Some of the netCDF files on the WOCE Global Data CDROMs are EPIC compliant, which makes the visualisation and plotting of these compliant data even easier.

Return to the top of the primer.


7.0 Important Web sites

Return to the top of the primer.


Appendix 1: Readnet.f created from cdf2fortran

This is a sample file produced by the cdf2fortran utility with the netCDF current meter record rcm00683.nc found in the WOCE CDROM set. Note that this Fortran routine can easily be generalised to read all of the WOCE current meter records.


c-----------------------------------------------------------------------
c
c readnet.f 
c This file is a Fortran template file designed to read the given
c netCDF file into memory.
c
c-----------------------------------------------------------------------
c Do not forget to include the -I path_to_netcdf_includes in your
c compile statement

c Required include.  Replace the location below with the directory where
c netcdf.inc has been placed on your machine (it will not necessarily be
c in /usr/local/netcdf/include).

      include '/usr/local/netcdf/include/netcdf.inc'

c Define Variables.
c Variable ids run sequentially from 1 to nvars = 08

      parameter (nvars = 8) ! number of variables
      parameter (nrec= 36434) ! change this 'to generalize
      parameter (ndims = 1) ! number of dimensions
      parameter (itime = 36434)
      integer*4 rcode ! error code
      integer*4 recdim ! record dimension
      real*8 date(nrec)
      real*8 time(nrec)
      real*4 speed(nrec)
      real*4 direction(nrec)
      real*4 u(nrec)
      real*4 v(nrec)
      real*4 temperature(nrec)
      real*4 pressure(nrec)
      integer*4 start(ndims) ! hyperslab starting index
      integer*4 count(ndims) ! hyperslab count from start
      integer vdims(ndims)   ! max # of var dims
      character*1024 strbuf  ! string buffer for var and attr names

c Open netCDF file.

      ncid=ncopn('rcm00683.nc',ncnowrit,rcode)

c Get info on the record dimension for this file.

      call ncinq(ncid,ndims,nvars,ngatts,recdim,rcode)
      call ncdinq(ncid,recdim,strbuf,nrecs,rcode)

c nrecs now contains the # of records for this file.
c Retrieve data for date variable.

      call ncvinq(ncid, 1,strbuf,nctype,nvdim,vdims,nvatts,rcode)
      lenstr=1
      do j=1,nvdim
         call ncdinq(ncid,vdims(j),strbuf,ndsize,rcode)
         lenstr=lenstr*ndsize
         start(j)=1
         count(j)=ndsize
      end do
      call ncvgt(ncid, 1,start,count,date,rcode)

c Retrieve data for time variable.

      call ncvinq(ncid, 2,strbuf,nctype,nvdim,vdims,nvatts,rcode)
      lenstr=1
      do j=1,nvdim
         call ncdinq(ncid,vdims(j),strbuf,ndsize,rcode)
         lenstr=lenstr*ndsize
         start(j)=1
         count(j)=ndsize
      end do
      call ncvgt(ncid, 2,start,count,time,rcode)

c Retrieve data for speed variable.

      call ncvinq(ncid, 3,strbuf,nctype,nvdim,vdims,nvatts,rcode)
      lenstr=1
      do j=1,nvdim
         call ncdinq(ncid,vdims(j),strbuf,ndsize,rcode)
         lenstr=lenstr*ndsize
         start(j)=1
         count(j)=ndsize
      end do
      call ncvgt(ncid, 3,start,count,speed,rcode)

c Retrieve data for direction variable.

      call ncvinq(ncid, 4,strbuf,nctype,nvdim,vdims,nvatts,rcode)
      lenstr=1
      do j=1,nvdim
         call ncdinq(ncid,vdims(j),strbuf,ndsize,rcode)
         lenstr=lenstr*ndsize
         start(j)=1
         count(j)=ndsize
      end do
      call ncvgt(ncid, 4,start,count,direction,rcode)

c Retrieve data for u variable.

      call ncvinq(ncid, 5,strbuf,nctype,nvdim,vdims,nvatts,rcode)
      lenstr=1
      do j=1,nvdim
         call ncdinq(ncid,vdims(j),strbuf,ndsize,rcode)
         lenstr=lenstr*ndsize
         start(j)=1
         count(j)=ndsize
      end do
      call ncvgt(ncid, 5,start,count,u,rcode)

c Retrieve data for v variable.

      call ncvinq(ncid, 6,strbuf,nctype,nvdim,vdims,nvatts,rcode)
      lenstr=1
      do j=1,nvdim
         call ncdinq(ncid,vdims(j),strbuf,ndsize,rcode)
         lenstr=lenstr*ndsize
         start(j)=1
         count(j)=ndsize
      end do
      call ncvgt(ncid, 6,start,count,v,rcode)

c Retrieve data for temperature variable.

      call ncvinq(ncid, 7,strbuf,nctype,nvdim,vdims,nvatts,rcode)
      lenstr=1
      do j=1,nvdim
         call ncdinq(ncid,vdims(j),strbuf,ndsize,rcode)
         lenstr=lenstr*ndsize
         start(j)=1
         count(j)=ndsize
      end do
      call ncvgt(ncid, 7,start,count,temperature,rcode)

c Retrieve data for pressure variable.

      call ncvinq(ncid, 8,strbuf,nctype,nvdim,vdims,nvatts,rcode)
      lenstr=1
      do j=1,nvdim
         call ncdinq(ncid,vdims(j),strbuf,ndsize,rcode)
         lenstr=lenstr*ndsize
         start(j)=1
         count(j)=ndsize
      end do
      call ncvgt(ncid, 8,start,count,pressure,rcode)

c ******************************************
c Begin writing statements to use the data.
c ******************************************

c End Program.
      stop
      end

Return to the top of the primer.


Appendix 2: Example Matlab script for current meter data

This is a Matlab macro to read the netCDF file rcm01037.nc found in the WOCE data set. This file is the equivalent of the Fortran code listed in Appendix 1. Note that this macro routine can be generalised to read all of the WOCE current meter records.


%
% A simple Matlab script to read the RCM netcdf file.
%
% Author: Nathan Bindoff
% Date: 28 March 2000
% The script uses Jim Mansbridge's netcdf routines for Matlab.
%
% Documetation and description of these routines can be found at 
% http://www.marine.csiro.au/sw/matlab-netcdf.html.
%
%
% Read the current meter data 
%
inqnc('rcm01037')
%
%
file='rcm01037'
%
%
woce_date=getcdf(file,'date');
woce_time_of_day=getcdf(file,'time');
speed=getcdf(file,'speed');
direction=getcdf(file,'direction');
u=getcdf(file,'u');
v=getcdf(file,'v');
temperature=getcdf(file,'temperature');
pressure=getcdf(file,'pressure');
%
%  Example of contents of inqnc('rcm01037')
%
%
%                ---  Global attributes  ---
%experiment_name: Deep Currents (PCM6)
%mooring_name: WHOI 947
%pi_name: B.Owens/B.Warren
%instrument_type: VACM
%latitude:  40.6000
%longitude:  147.3492
%instrument_depth: 1999.0 m
%seafloor_depth:  5280 m
%sampling_interval:   30 min
%earliest_start_time: 12-jun-1993 12:15:00
%latest_stop_time: 01-jul-1995 12:45:00
%null_value: -999.9  
% 
%The 1 dimensions are  1) time = 35954.
%time is unlimited in length
% 
%----- Get further information about the following variables -----
% 
%  -1) None of them (no further information)
%   0) All of the variables
%   1) date                   2) time                   3) speed
%   4) direction              5) u                      6) v
%   7) temperature            8) pressure 

Return to the top of the primer.


Appendix 3: Example output from ncdump

We list below the attributes of the current meter record rcm00683.nc obtained from ncdump -h. This is equivalent to the Matlab inqnc command. It describes the global attributes, and each of the variables.


netcdf rcm00683 {

dimensions:
	time = unlimited; // (36434 currently)

variables:
	double woce_date(time);
		woce_date:long_name = "date (yr, mo, day)";
		woce_date:units = "YYYYMMDD";
		woce_date:valid_range = 19500101, 20501231;
	double woce_time_of_day(time);
		woce_time_of_day:long_name = "time (hr, min, sec)";
		woce_time_of_day:units = "hhmmss.dd";
		woce_time_of_day:valid_range = 0.0, 235959.99;
	float speed(time);
		speed:units = "m/sec";
		speed:valid_range = 0.0, 3.0;
	float direction(time);
		direction:long_name = "true direction (toward)";
		direction:units = "degrees, clockwise from N";
		direction:valid_range = 0.0, 360.0;
	float u(time);
		u:long_name = "eastward velocity component";
		u:units = "m/sec";
		u:valid_range = -3.0, 3.0;
	float v(time);
		v:long_name = "northward velocity component";
		v:units = "m/sec";
		v:valid_range = -3.0, 3.0;
	float temperature(time);
		temperature:long_name = "water temperature";
		temperature:units = "degrees C";
		temperature:valid_range = -2.0, 35.0;
	float pressure(time);
		pressure:units = "decibars";
		pressure:valid_range = 0.0, 12000.0;

// global attributes
		:experiment_name = "Deep Currents (PCM6)";
		:mooring_name = "WHOI 942";
		:pi_name = "B.Owens/B.Warren";
		:instrument_type = "VACM";
		:latitude = " 36.4025";
		:longitude = " 150.2307";
		:instrument_depth = "2001.0 m";
		:seafloor_depth = " 5829 m";
		:sampling_interval = "  30 min";
		:earliest_start_time = "08-jun-1993 12:15:00";
		:latest_stop_time = "07-jul-1995 12:45:00";
		:null_value = -999.9;
}

Return to the top of the primer.


Appendix 4: Bug in gennet.for

The program in gennet.for is not quite perfect. When it creates the readnet.f program it some times places the wrong routine call in readnet.for. If you get a message like

>NCAGT: : Attempt to convert between text & numbers

the following may fix the problem. The line where readnet.for crashes is a call to NCAGT. At this point, readnet.for tries to read a character variable attribute "long_name" using a routine that is designed for numeric attributes (NCAGT). To make the code work substitute a call to NCAGTC at this point in the code and also to assign mtlen = 50 (the character width dimension of "name"). With these two changes the code runs like a charm.

Return to the top of the primer.