There are three steps required to convert data to netCDF if your data is not already readable by Ferret:
1. Create a CDL (the ASCII NetCDF Description Language) file that describes the axes, grids, and variables of the desired output data set. Note: Ferret itself often provides the simplest way to create the CDL file (see the following section).
2. Convert this CDL file into a netCDF file with the ncgen utility.
3. Create a program that will read your particular data and insert them into the netCDF file. The ncgen utility will create most of the FORTRAN or C code needed for this task.
The file converting_to_netcdf.f which is located in the Ferret documentation directory ($FER_DIR/doc) contains a complete description and example of these three steps. The remainder of this section provides further details.
10.3.1 Creating a CDL file with Ferret
Suppose that we wish to create a CDL file to describe a data set entitled "My Global Data" which contains variables u and v in cm/sec on a 5×5 degree global lat/long grid. The following commands would achieve the goal with Ferret doing the majority of the work:
• From Ferret issue the commands
DEFINE AXIS/X=2.5E:2.5W:5/UNITS=degrees xlong DEFINE AXIS/Y=87.5S:87.5N:5/UNITS=degrees ylat DEFINE GRID/X=xlong/Y=ylat my_grid LET shape_2d = x[G=my_grid]+y[G=my_grid] LET U = 1/0*SHAPE_2D LET V = 1/0*SHAPE_2D SET VARIABLE/TITLE="Zonal Velocity"/UNITS="cm/sec" u SET VARIABLE/TITLE="Meridional Velocity"/UNITS="cm/sec" v SAVE/FILE=my_file.cdf/TITLE="My Global Data" u,v QUIT
ncdump -c my_file.cdf > my_file.cdl
The resulting file my_file.cdl is ready to use or to make final modifications to with an editor.
10.3.2 The CDL file
A CDL file consists of three sections: Dimensions, Variables, and Data. All of the following text in small Courier font constitutes a real CDL file; it can be copied verbatim and used to generate a netCDF file. The full text of this file is included with the Ferret distribution as $FER_DIR/doc/converting_to_netcdf.basic.
netcdf converting_to_netcdf.basic {
10.3.2.1 Dimensions
In this section, the sizes of the grid dimensions are specified. One of these dimensions can be of "unlimited" size (i.e., it can grow).
Dimensions: lon = 160 ; // longitude lat = 100 ; // latitude depth = 27 ; // depth time = unlimited ;
These are essentially parameter statements that assign certain numbers that will be used in the Variables section to define axes and variable dimensions. The "//" is the CDL comment syntax.
The dimension variables are available to you in Ferret commands as pseudo-variables. For example, to use the "depth" dimension variable from the above example, you can say:
yes? let valz = z[gz=depth] yes? let offset = valz + a
See the next section about axes for more on dimension variables.
10.3.2.2 Variables
Variables, variable attributes, axes, axis attributes, and global attributes are specified.
variables: float temp(time, depth, lat, lon) ; temp: long_name = "TEMPERATURE" ; temp: units = "deg. C" ; temp: _FillValue = 1E34 ; float salt(time, depth, lat, lon) ; salt: long_name = "(SALINITY(ppt) - 35) /1000" ; salt: units = "frac. by wt. less .035" ; salt: _FillValue = -999. ;
The declaration "float" indicates that the variable is to be stored as single precision, floating point (32-bit IEEE representation). The declarations "long" (32-bit integer), "short" (16-bit integer), "byte" (8-bit integer) and "double" (64-bit IEEE floating point) are also supported by Ferret. Note that although these data types may result in smaller files, they will not affect Ferret's memory usage, as all variables are converted to "double" internally as they are read by Ferret. (Prior to Ferret v6.8, they were read as "float".)
Variable names in netCDF files should follow the same guidelines as Ferret variable names:
- case insensitive (avoid names that are identical apart from case)
- 1 to 24 characters (letters, digits, $ and _) beginning with a letter
- avoid reserved names (I, J, K, L, X, Y, Z, T, XBOX, ...)
See reference for how to handle invalid variable names that are already in a netCDF file.
The _FillValue attribute informs Ferret that any data value matching this value is a missing (invalid) data point. For example, an ocean data set may label land locations with a value such as 1E34. By identifying 1E34 as a fill value, Ferret knows to ignore points matching this value. The attribute "missing_value" is similar to "_FillValue" when reading data; but "_FillValue" also specifies a value to be inserted into unspecified regions during file creation. You may specify two distinct flags for invalid data in the same variable by using "_FillValue" and "missing_value" together.
Scale and offset values may be specified by the scale_factor and add_offset attributes.
Ferret variables may have from 1 to 4 dimensions. If any of the axes have the special interpretations of: 1) latitude, 2) longitude, 3) depth, or 4) time (date), then the relative order of those axes in the CDL variable declaration must be T, then Z, then Y, and then X, as above. Any of these special axes can be omitted and other axes (for example, an axis called "distance") may be inserted between them.
axis definitions: double lon(lon) ; lon: units = "degrees"; double lat(lat) ; lat: units = "degrees"; double depth(depth) ; depth: units = "meters"; double time(time) ; time: units = "seconds since 1972-01-01";
Axes, also known as coordinate variables, are distinguished from other 1-dimensional netCDF variables by their variable names being identical to their dimension names. Special axis interpretations are inferred by Ferret through a variety of "clues."
The direction of the axis may be specified by the attribute AXIS or CARTESIAN_AXIS. Files written by Ferret (as of version 5.5) include the AXIS attribute for coordinate variables.
lon: axis="X";
Date/time axes are inferred by units of "years," "days," "hours," "minutes," or "seconds," or by axis names "time," "date," or "t" (case-insensitive). Calendar date formatting requires the "units" attribute to be formatted with both a valid time unit and "since yyyy-mm-dd".
Vertical axes are identified by axis names containing the strings "depth", "elev", or "z", or by units of "millibars." Depth axes are positive downward by default. The attribute positive= "down" can also be used to create a downward-pointing Z axis. The positive= attribute may be used on any axis, with the values positive= "down" or positive="up", however positive="down" is applied only to Z axes and is ignored otherwise.
Latitude axes are inferred by units of "degrees" or "latitude" with axis names containing the strings "lat" or "y". Longitude axes are inferred by units of "degrees" or "longitude" with axis names containing the strings "lon" or "x".
Axis direction is determined by Ferret as in this order:
1) AXIS attribute
2) CARTESIAN_AXIS attribute
3) positive="down", indicating a z axis
4) Axis units
5) Axis name
Once the direction is determined, other conflicting information is ignored. Thus if an axis has the attribute AXIS="Y" it is a Y axis, even though its units might be "days" or its name might be "longitude".
Axes are either netCDF coordinate variables or are synthesized (as simple indices 1, 2, 3, ...) if coordinate definitions are missing for a variable. The axes of a variable are available as "pseudo-variables" using the syntax X[g=var], where "var" is the name of the netCDF variable, and similarly for the Y,Z, and T axes. When the data set is canceled the associated axes are canceled, too. The exception is that axes will be retained if they are in use in a DEFINE GRID definition -- and they will be erased from memory at the time all grids using them are canceled.
Some files contain axis definitions (coordinate variables) without associated variables. Like all axes they are visible with the SHOW AXIS command. To obtain the values of those coordinate variables as Ferret pseudo-variables use the syntax X[gx=axname], where axname is the name of the coordinate variable (also the netCDF dimension name) and likewise for Y,Z, and T axes. Note that when the data set is cancelled, axis definitions of this variety are retained -- unlike axes that are used in variables.
Global attributes, or attributes that apply to the entire data set, can be specified as well.
global attributes: :title = "NetCDF Example"; :message = "This message will be displayed when the CDF file is opened by Ferret"; :history = "Documentation on the origins and evolution of this data set or variable";
10.3.2.3 Data
In this section, values are assigned to grid coordinates and to the variables of the file. Below are 100 latitude coordinates entered (in degrees) into the variable axis "lat", 160 longitude coordinates in "lon", and 27 depth coordinates (in meters) in "depth". Longitude coordinates must be specified with 0 at Greenwich, continuous across the dateline, with positive eastward (modulo 360).
Data: lat= -28.8360729218,-26.5299491882,-24.2880744934,-22.1501560211,-20.151357650, -18.3207626343,-16.6801033020,-15.2428140640,-14.0134353638,-12.987424850, -12.1513509750,-11.4834814072,-10.9547319412,-10.5299386978,-10.169393539, -9.8333206177,-9.4999876022,-9.1666536331,-8.8333196640,-8.4999856949, -8.1666526794,-7.8333187103,-7.4999847412,-7.1666512489,-6.8333182335, -6.4999852180,-6.1666517258,-5.8333182335,-5.4999852180,-5.1666517258, -4.8333187103,-4.4999852180,-4.1666517258,-3.8333187103,-3.4999852180, -3.1666517258,-2.8333184719,-2.4999852180,-2.1666519642,-1.8333185911, -1.4999852180,-1.1666518450,-0.8333183527,-0.4999849498,-0.1666515470, 0.1666818559,0.5000152588,0.8333486915,1.1666821241,1.5000154972, 1.8333489895,2.1666824818,2.5000159740,2.8333494663,3.1666829586, 3.5000162125,3.8333497047,4.1666831970,4.5000162125,4.8333497047, 5.1666831970,5.5000162125,5.8333497047,6.1666827202,6.5000162125, 6.8333497047,7.1666827202,7.5000166893,7.8333501816,8.1666841507, 8.5000181198,8.8333511353,9.1666851044,9.5000190735,9.8333530426, 10.1679363251,10.5137376785,10.8892869949,11.3138961792,11.8060989380, 12.3833675385,13.0618314743,13.8560228348,14.7786512375,15.8403968811, 17.0497493744,18.4128704071,19.9334945679,21.6128730774,23.4497566223, 25.4404067993,27.5786647797,29.8560409546,32.2618522644,34.7833900452, 37.4061241150,40.1139259338,42.8893203735,45.7137718201,48.5679702759; lon= 130.5,131.5,132.5,133.5,134.5,135.5,136.5,137.5,138.5,139.5,140.5, 141.5,142.5,143.5,144.5,145.5,146.5,147.5,148.5,149.5,150.5,151.5, 152.5,153.5,154.5,155.5,156.5,157.5,158.5,159.5,160.5,161.5,162.5, 163.5,164.5,165.5,166.5,167.5,168.5,169.5,170.5,171.5,172.5,173.5, 174.5,175.5,176.5,177.5,178.5,179.5,180.5,181.5,182.5,183.5,184.5, 185.5,186.5,187.5,188.5,189.5,190.5,191.5,192.5,193.5,194.5,195.5, 196.5,197.5,198.5,199.5,200.5,201.5,202.5,203.5,204.5,205.5,206.5, 207.5,208.5,209.5,210.5,211.5,212.5,213.5,214.5,215.5,216.5,217.5, 218.5,219.5,220.5,221.5,222.5,223.5,224.5,225.5,226.5,227.5,228.5, 229.5,230.5,231.5,232.5,233.5,234.5,235.5,236.5,237.5,238.5,239.5, 240.5,241.5,242.5,243.5,244.5,245.5,246.5,247.5,248.5,249.5,250.5, 251.5,252.5,253.5,254.5,255.5,256.5,257.5,258.5,259.5,260.5,261.5, 262.5,263.5,264.5,265.5,266.5,267.5,268.5,269.5,270.5,271.5,272.5, 273.5,274.5,275.5,276.5,277.5,278.5,279.5,280.5,281.5,282.5,283.5, 284.5,285.5,286.5,287.5,288.5,289.5; depth= 5.0,15.0,25.0,35.0,45.0,55.0,65.0,75.0,85.0,95.0,106.25,120.0,136.25, 155.0,177.5,205.0,240.0,288.5,362.5,483.5,680.0,979.5,1395.5,1916.0, 2524.0,3174.0,3824.0; }
% ncgen -o my_data.cdf converting_to_netcdf.basic
This will create a file called "my_data.cdf" to which data can be directed (see next section).
Another netCDF command, "ncdump", can be used to generate a CDL file from an existing netCDF file. The command
% ncdump -h my_data.cdf
will list the CDL representation of a preexisting my_data.cdf without the Data section, while
% ncdump my_data.cdf
will list the CDL file with the Data section. The command
% ncdump -c my_data.cdf
will create a CDL file in which only coordinate variables are included in the Data section. The listed output can be redirected to a file as in the command
% ncdump -c my_data.cdf > my_data.cdl
10.3.3 Standardized NetCDF attributes
Ferret adheres to the COARDS netCDF conventions, also available at
http://www.unidata.ucar.edu/packages/netcdf/conventions.html
The following are the attributes most commonly used with Ferret. They are described in greater detail in the reference document named above.
Global Attributes
:title = "my data set title"
:history = "general background information"
Data Variable Attributes
long_name = "title of my variable"
units = "units for this variable"
_FillValue = missing value flag
missing_value = alternative missing value flag
scale_factor = (optional) the data are to be multiplied by this factor
add_offset = (optional) this number is to be added to the data
Special Coordinate Variable Attributes
time_axis:units = "seconds since 1992-10-8 15:15:42.5 -6:00"; // example
y_axis:units = "degrees_north"
x_axis:units = "degrees_east"
z_axis:positive = "down"; // to indicate preferred plotting orientation
my_axis:point_spacing = "even"; // improved performance if present
axis: "X", "Y", "Z", or "T" indicating the direction of the axis.
See the SAVE command to write to a netCDF file. Note that when using Ferret to output into netCDF files that Ferret did not itself create, the results may not be entirely as expected. Case-sensitivity of names is one aspect of this. Since Ferret is (by default) case insensitive and netCDF files are case-sensitive writing into a "foreign" file may result in duplicated entities in the file which differ only in case. With Ferret v6.2, the qualifier SAVE/KEEP_AXISNAMES forces original axis names to be used, even if Ferret would otherwise change the names. You can also SET or CANCEL MODE upcase_output to control whether variables names are output in upper-case form, or kept in their original upper- or lower-case spelling.
When appending to a file, the behavior for global attributes history and Conventions is as follows:
Ferret replaces a history attribute which is simply a Ferret version number and date, with the version number of the Ferret executable writing to the file, and the current date. If there are other contents to the history attribute, Ferret appends a comma and newline character, then the Ferret version number and date.
Ferret replaces a Conventions attribute which is simply CF-x.x with the current conventions information, now CF-1.6. If there are other contents of the Conventions attribute, Ferret will append a comma and the current CF conventions number.
10.3.4 Directing data to a CDF file
The following is an example program which can be used on-line to convert existing data sets into netCDF files. It also should provide guidance on sending data generated by numerical models directly to netCDF files. This program assumes you have created the netCDF file as described in the previous section. It is included in the distribution as $FER_DIR/doc/converting_to_netcdf.f.
program converting_to_netcdf c written by Dan Trueman c updated 4/94 *sh* c This program provides a model for converting a data set to NetCDF. c The basic strategy used in this program is to open an existing NetCDF c file, query the file for the ID's of the variables it contains, and c then write the data to those variables. c The output NetCDF file must be created **before** this program is run. c The simplest way to do this is to cd to your scratch directory and c % cp $FER_DIR/doc/converting_to_netcdf.basic converting_to_netcdf.cdl c and then edit converting_to_netcdf.cdl (an ASCII file) to describe YOUR c data set. If your data set requires unequally spaced axes, climatological c time axes, staggered grids, etc. then converting_to_netcdf.supplement may c be a better starting point then the "basic" file used above. c After you edit converting_to_netcdf.cdl then create the NetCDF file with c the command c % ncgen -o converting_to_netcdf.cdf converting_to_netcdf.cdl c Now we will read in **your** data (gridded oceanic temperature and c salt in this example) and write it out into the NetCDF file c converting_to_netcdf.cdf. Note that the axis coordinates can be written c out exactly the same methodology - including time step values (as below). ************************************************************************* c An alternative to modifying this program is to use the command: c ncgen -f converting_to_netcdf.cdl c This will create a large source code to which select lines can c be added to write out your data. ************************************************************************* c To compile and link converting_to_netcdf.f, use: c f77 -o converting_to_netcdf converting_to_netcdf.f -lnetcdf ************************************************************************* c include file necessary for NetCDF include 'netcdf.inc' ! may be found in $FER_DIR/fmt/cmn ************************************************************************* c parameters relevant to the data being read in c THESE NORMALLY MATCH THE DIMENSIONS IN THE CDL FILE c (except nt which may be "unlimited") integer imt, jmt, km, nt, lnew, inlun parameter (imt=160, jmt=100, km=27, nt=5) c imt is longitude, jmt latitude, km depth, and nt number of time steps ************************************************************************* c variable declaration real temp(imt,jmt,km),salt(imt,jmt,km),time_step integer cdfid, rcode c ** cdfid = id number for the NetCDF file my_data.cdf c ** rcode = error id number integer tid, sid, timeaxid c ** tid = variable id number for temperature c ** sid = variable id number for salt c ** timeaxid = variable id for the time axis integer itime c ** itime = index for do loop ************************************************************************* c dimension corner and step for defining size of gridded data integer corner(4) integer step(4) c corner and step are used to define the size of the gridded data c to be written out. Since temp and salt are four dimensional arrays, c corner and step must be four dimensions as well. In each output c to my_data.cdf within the do loop, the entire array of data (160 long. c pts, 100 lat. pts., 27 depth pts.) will be written for one time step. c Corner tells NetCDF where to start, and step indicates how many steps c in each dimension to take. data corner/1, 1, 1, -1/ ! -1 is arbitrary; the time value ! of corner will be initialized ! within the do loop. data step/imt, jmt, km, 1/ ! NOT /1, km, jmt, imt/ c ***NOTE*** Since Fortran and C access data differently, the order of c the variables in the Fortran code must be opposite that in the CDL c file. In Fortran, the first index varies fastest while in C, the c last index varies fastest. ************************************************************************** c initialize cdfid by using ncopn cdfid = ncopn('converting_to_netcdf.cdf', ncwrite, rcode) if (rcode.ne.ncnoerr) stop 'error with ncopn' ************************************************************************** c get variable id's by using ncvid c THE VARIABLE NAMES MUST MATCH THE CDL FILE (case sensitive) tid = ncvid(cdfid, 'temp', rcode) if (rcode.ne.ncnoerr) stop 'error with tid' sid = ncvid(cdfid, 'salt', rcode) if (rcode.ne.ncnoerr) stop 'error with sid' timeaxid = ncvid(cdfid, 'time', rcode) if (rcode.ne.ncnoerr) stop 'error with timeaxid' ************************************************************************** c this is a good place to open your input data file ! OPEN (FILE=my_data.dat,STATUS='OLD') ************************************************************************** c begin do loop. Each step will read in one time step of data c and then write it out to my_data.cdf. do 10 itime = 1, nt corner(4) = itime ! initialize time step in corner time_step = float(itime) ! or you may read this from your file * insert your data reading routine here ! CALL READ_MY_DATA(temp,salt) ! you write this write (6,*) 'writing time step: ',itime, time_step ! diagnostic output call ncvpt(cdfid,tid,corner,step,temp(1,1,1),rcode) ! write data to if (rcode.ne.ncnoerr) stop 'error with t-put' call ncvpt(cdfid,sid,corner,step,salt(1,1,1),rcode) ! my_data.cdf with if (rcode.ne.ncnoerr) stop 'error with s-put' call ncvpt1(cdfid,timeaxid,itime,time_step,rcode) ! ncvpt if (rcode.ne.ncnoerr) stop 'error with timax-put' c ncvpt1 writes a single data point to the specified location within c timeaxid. The itime argument in ncvpt1 specifies the location within c time to write. c float(itime) is used (rather than simply itime) so the type matches the c type of time declared in the CDL file. 10 continue ************************************************************************** c close my_data.cdf using ncclos call ncclos(cdfid, rcode) if (rcode.ne.ncnoerr) stop 'error with ncclos' ************************************************************************** stop end
10.3.5 Advanced NetCDF procedures
This section describes:
1. Setting up a CDL file capable of handling data on staggered grids.
2. Defining coordinate systems such that the data in the netCDF file may be regarded as hyperslabs of larger coordinate spaces.
3. Defining boundaries between unevenly spaced axis coordinates (used in numerical integrations).
4. Setting up "modulo" axes such as climatological time and longitude.
5. Converting dates into numerical data appropriate for a netCDF time axis.
The final section of this chapter contains the text of the CDL file for the example we use throughout this section.
In this sample data set, we will consider wind, salt, and velocity calculated using a staggered-grid, finite-difference technique. The wind data is limited to the surface layer of the ocean (i.e., normal to the depth axis). We will also consider the salt data to be limited to a narrow slab from 139E to 90W (I=10 to 140), 32.5N to 34.9N (J=80 to 82), and for all depth and time values.
10.3.5.1 Staggered grid
Ferret permits each variable of a netCDF file to be defined on distinct axes and grids. Staggered grids are a straightforward application of this principle. Dimensions for each grid axis must be defined, the axes themselves must be defined (in Variables), and the coordinate values for each axis must be initialized (in Data). In the case of the example we use throughout this and the next section, there are two grids—a wind grid, and a velocity grid; slon, slat and sdepth are defined for the wind grid, and ulon, ulat, and wdepth for the velocity grid. The variables are then given dimensions to place them in their proper grids (i.e., wind(time, sdepth, slat, slon)).
There are a number of steps required to set up a netCDF data set that represents a hyperslab of data from a larger grid definition (a parent grid).
1. Define a dimension named "grid_definition." This dimension should be set equal to 1.
2. Define parent grids in Variables with the argument "grid_definition".
char wind_grid(grid_definition) ; char salt_grid(grid_definition) ;
3. Define the 4 axes of the parent grids using the "axes" attribute.
wind_grid: axes = "slon slat normal time" ; salt_grid: axes = "slon slat sdepth time" ;
The arguments are always a list of four axis names. Note that the order of arguments is opposite that in the variable declaration. The argument "normal" indicates that wind_grid is normal to the depth axis.
4. Define the variables that are hyperslabs of these grids with the proper dimensions.
float wind(time, slat, slon) ; float salt(time, sdepth, slat80_82, slon10_140) ;
where the dimension slat80_82 = 3 and slon10_140 = 131. Optionally, these axes may be defined themselves with the attribute "child_axis".
float slat80_82(slat80_82) ; slat80_82: child_axis = " " ;
These "child axes" need not be initialized in data, nor do edges need to be defined for them; Ferret will retrieve this information from the parent axis definitions. However, it is recommended that they be initialized to accommodate other software that may not recognize parent grids.
5. Use the "parent_grid" variable attribute to point to the parent grid.
wind: parent_grid = "wind_grid" salt: parent_grid = "salt_grid"
6. Also, as a variable attribute, define the index range of interest within the parent grid.
wind: slab_min_index = 1s, 1s, 1s, 0s ; wind: slab_max_index = 160s, 100s, 1s, 0s ; salt: slab_min_index = 10s, 80s, 1s, 0s ; salt: slab_max_index = 140s, 82s, 27s, 0s ;
The "s" after each integer indicates a "short" 16-bit integer rather than the default "long" 32-bit integer. If an axis dimension is designated as "unlimited" then the index bounds for this axis must be designated as "0s".
These attributes will effectively locate the wind and salt data within the parent grid.
10.3.5.3 Unevenly spaced coordinates
For coordinate axes with uneven spacing, the boundaries between each coordinate can be indicated by pointing to an additional axis that contains the locations of the boundaries. This can be done in one of two ways: The axis edges may be listed, N+1 edges for an axis of N coordinaes. Or cell bounds may be listed, with the lower and upper bound of each cell for a list of N*2 bounds. (The bounds attribute was implemented in Ferret version 5.70.)
If edges or bounds are not explicitly defined for an unevenly spaced axis, the midpoint between coordinates is assumed by default.
To define edges:
1. Define a dimension one larger than the coordinate axis. For the sdepth axis, with 27 coordinates, define:
sdepth_edges = 28 ;
2. Define an axis called sdepth_edges.
3. Initialize this axis with the desired boundaries (in Data).
4. As an attribute of the main axis, point to edges list:
sdepth: edges = "sdepth_edges" ;
To define bounds
1. Define a dimension twice as large as the coordinate axis. For the sdepth axis, with 27 coordinates, define:
sdepth_bnds = 54;
2. Define an axis called sdepth_bnds.
3. Initialize this axis with the desired boundaries (in Data). The ordering is box_lo_1, box_hi_1, box_lo_2, box_hi_2, ...
4. For a valid Ferret axis, the low bound of each cell must equal the high bound of the previous cell.
5. As an attribute of the main axis, point to bounds list:
sdepth: bounds = "sdepth_bnds" ;
10.3.5.4 Evenly spaced coordinates (long axes)
If the coordinate axes are evenly spaced, the attribute "point spacing" should be used:
slat: point_spacing = "even" ;
When used, this attribute will improve memory use efficiency in Ferret. This is especially important for very large axes—10,000 points or more.
The "modulo" axis attribute indicates that the axis wraps around, the first point immediately following the last. The most common uses of modulo axes are:
1. longitude axes for globe-encircling data. If the modulo length is different from 360 degrees, specify the value.
2. time axes for climatological data
time: modulo = " " ; xavr: modulo = "100" ;
If the climatological data occurs in the years 0000 or 0001 then the year will be omitted from Ferret's output format.
NetCDF time axes encoded as year 0000 or 0001 are automatically flagged as modulo axes.
As of Ferret version5.5, longitude axes and climatological time axes are always detected as modulo, or as sub-span modulo when appropriate, unless Ferret is specifically directed that the axis is NOT modulo. See the sections on modulo axes and subspan modulo axes for more information.
10.3.5.6 Reversed-coordinate axes
NetCDF axes may contain monotonically decreasing axis coordinates instead of monotonically increasing coordinates. Ferret will hide this aspect of the file data ordering.
10.3.5.7 Converting time word data to numerical data
To set up a time axis for data represented as dates (e.g., "1972 January 15 at 12:15") it is necessary to determine a numerical representation for each of the dates. Ferret can assist with this process, as the following example shows.
Suppose the data are 6-hourly observations from 1-JAN-1991 at 12:00 to 15-MAR-1991 at 18:00. These commands will assist in creating the necessary time axis for a netCDF file:
yes? DEFINE AXIS/T="1-JAN-1991:12:00":"15-MAR-1991:18:00":6/UNITS=hours\ my_time yes? DEFINE GRID/T=my_time tgrid yes? SET REGION/T="1-JAN-1991:12:00":"15-MAR-1991:18:00" yes? LIST T[g=tgrid] !to see the time values yes? SAVE/FILE=my_time.cdf T[g=tgrid]
The file my_time.cdf now contains a model of exactly the desired time axis. Use the Unix command
% ncdump my_time.cdf > my_time.cdl
to obtain the time axis definition as text that can be inserted into your CDL file.
10.3.6 Example CDL file
The following is an example CDL file utilizing many of the features described in the preceding section.
netcdf converting_to_netcdf_supplement { // CONVERTING DATA TO THE "NETWORK COMMON DATA FORM" (NetCDF): // A SUPPLEMENT // // NOAA PMEL Thermal Modeling and Analysis Project (TMAP) // Dan Trueman, Steve Hankin // last revised: 1 Dec 1993: slat80_82 and slon10_140 coordinates included // // I. INTRODUCTION // // This supplement to "Converting Data to the Network Common Data Form: // an Introduction" describes: // // 1. How to set up a cdl file capable of handling data // on staggered grids. // 2. How to define coordinate systems such that the data // in the NetCDF file may be regarded as hyperslabs of // larger coordinate spaces. // 3. How to define variables of 1, 2, or 3 dimensions. // 4. How to define boundaries between unevenly spaced axis // coordinates (used in numerical integrations). // 5. How to set up climatological "modulo" time axes. // 6. How to convert time word data into numerical data // appropriate for NetCDF. // // In this sample data set, we will consider wind, salt, and // velocity calculated using a staggered-grid, finite-difference // technique. The wind data is naturally limited to the surface // layer of the ocean (i.e. normal to the depth axis). We will // also consider the salt data to be limited to a narrow slab from // 139E to 90W (I=10 to 140), 32.5N to 34.9N (J=80 to 82), and for // all depth and time values. // // II. STAGGERED GRIDS // // Dealing with staggered grids is fairly straightforward. Dimensions // for each grid axis must be defined, the axes themselves must be // defined (in Variables), and the coordinate values for each axis must // be initialized (in Data). In this case, there are two grids, a // wind grid, and a velocity grid, so tlon, tlat and tdepth are // defined for the wind grid, and ulon, ulat, and udepth for the velocity // grid. The variables are then given arguments to place them in their // proper grids (i.e. wind(time, sdepth, slat, slon)). // // III. HYPERSLABS // // There are a number of steps required to set up a NetCDF data set that // represents a hyperslab of data from a larger grid definition. // // 1. Define a dimension named "grid_definition". This dimension // should be set equal to 1. // 2. Define parent grids in Variables with the argument // "grid_definition". // // char wind_grid(grid_definition) ; // char salt_grid(grid_definition) ; // // 3. Define the 4 axes of the parent grids using the "axes" attribute. // // wind_grid: axes = "slon slat normal time" ; // salt_grid: axes = "slon slat sdepth time" ; // // Note that the order of arguments is opposite that in the // variable declaration. The argument "normal" indicates that // wind_grid is normal to the depth axis. // // 4. Define the variables which are hyperslabs of these grids with // the proper dimensions. // // float wind(time, slat, slon) ; // float salt(time, sdepth, slat80_82, slon10_140) ; // // where slat80_82 = 3 and slon10_140 = 131. The axis names are /// arbitrary - chosen for readability. These axes (child axes) // must be defined with the attribute "child_axis" as follows: // // float slat80_82(slat80_82) ; // slat80_82: child_axis = " " ; // // These "child axes" need not be initialized in Data, nor do their // edges need be defined; Ferret retrieves this information from // the parent axes. // // 5. Use the "parent_grid" variable attribute to point to the // parent grid. // // wind: parent_grid = "wind_grid" // // 6. Also as a variable attribute, define the index range of interest // within the parent grid. // // wind: slab_min_index = 1s, 1s, 1s, 0s ; // wind: slab_max_index = 160s, 100s, 1s, 0s ; // salt: slab_min_index = 10s, 80s, 1s, 0s ; // salt: slab_max_index = 140s, 82s, 27s, 0s ; // // The "s" after each integer indicates a "short" 16-bit integer // rather than the default "long" 32-bit integer. If an axis // dimension is designated as "unlimited" then the index bounds // for this axis must be designated as "0s". // // These commands will effectively locate the wind and salt data within // the full grid. // // IV. VARIABLES OF 1, 2, or 3 DIMENSIONS // // One, two, or three dimensional variables may be set up in one of // two ways - either using the parent_grid and child_axis attributes // as illustrated in the 3-dimensional variable "wind" from the hyperslab // example, above, or by selecting axis names and units that provide // Ferret with adequate hints to map this variable onto 4-dimensional // space and time. The following hints are recognized by Ferret: // // Units of days, hours, minutes, etc. or an axis name of "TIME", "DATE" // implies a time axis. // Units of "degrees xxxx" where "xxxx" contains "lat" or "lon" implies // a latitude or longitude axis, respectively. // Units of "degrees" together with an axis name containing "LAT" or // "Y" implies a latitude axis else longitude is assumed. // Units of millibars, "layer" or "level" or an axis name containing // "Z" or "ELEV" implies a vertical axis. // // V. UNEVENLY SPACED COORDINATE BOUNDARIES // // For coordinate axes with uneven spacing, the boundaries between each // coordinate can be indicated by pointing to an additional axis that // contains the locations of the boundaries. The dimension of this "edge" // axis will necessarily be one larger than the coordinate axis concerned. // If edges are not defined for an unevenly spaced axis, the midpoint // between coordinates will be assumed by default. // // 1. Define a dimension one larger than the coordinate axis. For // the sdepth axis, with 27 coordinates, define: // // sdepth_edges = 28 ; // // 2. Define an axis called sdepth_edges. // 3. Initialize this axis appropriately (in Data). // 4. As a sdepth axis attribute, point to sdepth_edges: // // sdepth: edges = "sdepth_edges" ; // // If the coordinate axes are evenly spaced, the attribute "point spacing" // should be used: // // slat: point_spacing = "even" ; // // When used, this attribute will improve memory use efficiency in Ferret. // // VI. CLIMATOLOGICAL "MODULO" AXES // // The "modulo" axis attribute indicates that the axis wraps around, // the first point immediately following the last. The most common // uses of modulo axes are: // // 1. As longitude axes for globe-encircling data. // 2. As time axes for climatological data. // // time: modulo = " " ; // any arbitrary string is allowed // // If the climatological data occurs in the years 0000 or 0001 then Ferret // will omit the year from the output formatting. // // VII. CONVERTING TIME WORD DATA TO NUMERICAL DATA // // If the time data being converted to NetCDF format exists in string format // (i.e. 1972 - JANUARY 15 2:15:00), rather than numerical format (i.e. 55123 // seconds) a number of TMAP routines are available to aid in the conversion // process. The steps required for conversion are as follows: // // 1. Break the time string into its 6 pieces. If the data is of the // form dd-mmm-yyyy:hh:mm:dd, the TMAP routine "tm_break_date.f" can // be used. // 2. Choose a time_origin before the beginning of the time data to // assure that all time values are positive. i.e. if the data begins // at 15-JAN-1982:05:30:00, choose a time origin of // 15-JAN-1981:00:00:00. This time_origin should then be an attribute // of the time axis variable in the CDL file. // 3. Produce numerical time data by using "tm_sec_from_bc.f", which // calculates the number of seconds between 01-01-0000:00:00:00 and // the date specified. Continuing the example from (2), the time value // for the first time step with respect to the time_origin could be // calculated as follows: // // time(1) = tm_sec_from_bc(1982, 1, 15, 5, 30, 0) - // tm_sec_from_bc(1981, 1, 15, 0, 0, 0) // // or more generally // // time(n)=tm_sec_from_bc(nyear,nmonth,nday,nhour,nminute,nsecond) - // tm-sec_from_bc(oyear,omonth,oday,ohour,ominute,osecond) // // where nyear is the year for the nth time step and oyear is the year // of time_origin. // // VII. EXAMPLE CDL FILE dimensions: // staggered grid dimension definitions: slon = 160 ; // wind/salt longitude dimension ulon = 160 ; // velocity longitude dimension slat = 100 ; // wind/salt latitude dimension ulat = 100 ; // velocity latitude dimension sdepth = 27 ; // salt depth dimension wdepth = 27 ; // velocity depth dimension slon10_140 = 131 ; // for salt hyperslab slat80_82 = 3 ; // for salt hyperslab time = unlimited ; // grid_definition is the dimension name to be used for all grid definitions grid_definition = 1 ; // edge dimension definitions: sdepth_edges = 28 ; wdepth_edges = 28 ; variables: // variable definitions: float wind(time, slat, slon) ; // 3-dimensional variable wind: parent_grid = "wind_grid" ; wind: slab_min_index = 1s, 1s, 1s, 0s ; wind: slab_max_index = 160s, 100s, 1s, 0s ; wind: long_name = "WIND" ; wind: units = "deg. C" ; wind: _FillValue = 1E34f ; float salt(time, sdepth, slat80_82, slon10_140) ; // 4-dim. Variable salt: parent_grid = "salt_grid" ; salt: slab_min_index = 10s, 80s, 1s, 0s ; salt: slab_max_index = 140s, 82s, 27s, 0s ; salt: long_name = "(SALINITY(ppt) - 35) /1000" ; salt: units = "frac. by wt. less .035" ; salt: _FillValue = -999.f ; float u(time, sdepth, ulat, ulon) ; u: long_name = "ZONAL VELOCITY" ; u: units = "cm/sec" ; u: _FillValue = 1E34f ; float v(time, sdepth, ulat, ulon) ; v: long_name = "MERIDIONAL VELOCITY" ; v: units = "cm/sec" ; v: _FillValue = 1E34f ; float w(time, wdepth, slat, slon) ; w: long_name = "VERTICAL VELOCITY" ; w: units = "cm/sec" ; w: _FillValue = 1E34f ; // axis definitions: float slon(slon) ; slon: units = "degrees" ; slon: point_spacing = "even" ; float ulon(ulon) ; ulon: units = "degrees" ; ulon: point_spacing = "even" ; float slat(slat) ; slat: units = "degrees" ; slat: point_spacing = "even" ; float ulat(ulat) ; ulat: units = "degrees" ; ulat: point_spacing = "even" ; float sdepth(sdepth) ; sdepth: units = "meters" ; sdepth: positive = "down" ; sdepth: edges = "sdepth_edges" ; float wdepth(wdepth) ; wdepth: units = "meters" ; wdepth: positive = "down" ; wdepth: edges = "wdepth_edges" ; float time(time) ; time: modulo = " " ; time: time_origin = "15-JAN-1981:00:00:00" ; time: units = "seconds" ; // child grid definitions: float slon10_140(slon10_140) ; slon10_140: child_axis = " " ; slon10_140: units = "degrees" ; float slat80_82(slat80_82) ; slat80_82: child_axis = " " ; slat80_82: units = "degrees" ; // edge axis definitions: float sdepth_edges(sdepth_edges) ; float wdepth_edges(wdepth_edges) ; // parent grid definition: char wind_grid(grid_definition) ; wind_grid: axes = "slon slat normal time" ; char salt_grid(grid_definition) ; salt_grid: axes = "slon slat sdepth time" ; // global attributes: :title = "NetCDF Title" ; data: // // ignore this block // //This next data entry, for time, should be ignored. Time is initialized here // only so that Ferret can read test.cdf (the file created by this cdl file) // with no additional data inserted into it. Time=1000; // // end of ignored block // slat= -28.8360729218,-26.5299491882,-24.2880744934,-22.1501560211,-20.1513576508, -18.3207626343,-16.6801033020,-15.2428140640,-14.0134353638,-12.9874248505, -12.1513509750,-11.4834814072,-10.9547319412,-10.5299386978,-10.1693935394, -9.8333206177,-9.4999876022,-9.1666536331,-8.8333196640,-8.4999856949, -8.1666526794,-7.8333187103,-7.4999847412,-7.1666512489,-6.8333182335, -6.4999852180,-6.1666517258,-5.8333182335,-5.4999852180,-5.1666517258, -4.8333187103,-4.4999852180,-4.1666517258,-3.8333187103,-3.4999852180, -3.1666517258,-2.8333184719,-2.4999852180,-2.1666519642,-1.8333185911, -1.4999852180,-1.1666518450,-0.8333183527,-0.4999849498,-0.1666515470, 0.1666818559,0.5000152588,0.8333486915,1.1666821241,1.5000154972, 1.8333489895,2.1666824818,2.5000159740,2.8333494663,3.1666829586, 3.5000162125,3.8333497047,4.1666831970,4.5000162125,4.8333497047, 5.1666831970,5.5000162125,5.8333497047,6.1666827202,6.5000162125, 6.8333497047,7.1666827202,7.5000166893,7.8333501816,8.1666841507, 8.5000181198,8.8333511353,9.1666851044,9.5000190735,9.8333530426, 10.1679363251,10.5137376785,10.8892869949,11.3138961792,11.8060989380, 12.3833675385,13.0618314743,13.8560228348,14.7786512375,15.8403968811, 17.0497493744,18.4128704071,19.9334945679,21.6128730774,23.4497566223, 25.4404067993,27.5786647797,29.8560409546,32.2618522644,34.7833900452, 37.4061241150,40.1139259338,42.8893203735,45.7137718201,48.5679702759; ulat= -27.6721439362,-25.3877544403,-23.1883945465,-21.1119174957,-19.1907978058, -17.4507274628,-15.9094810486,-14.5761461258,-13.4507236481,-12.5241250992, -11.7785758972,-11.1883859634,-10.7210769653,-10.3387994766,-9.9999876022, -9.6666545868,-9.3333206177,-8.9999866486,-8.6666526794,-8.3333196640, -7.9999856949,-7.6666517258,-7.3333182335,-6.9999847412,-6.6666512489, -6.3333182335,-5.9999847412,-5.6666517258,-5.3333182335,-4.9999847412, -4.6666517258,-4.3333182335,-3.9999849796,-3.6666517258,-3.3333184719, -2.9999852180,-2.6666519642,-2.3333184719,-1.9999853373,-1.6666518450, -1.3333184719,-0.9999850392,-0.6666516662,-0.3333182633,0.0000151545, 0.3333485723,0.6666819453,1.0000153780,1.3333487511,1.6666821241, 2.0000154972,2.3333489895,2.6666827202,3.0000162125,3.3333497047, 3.6666829586,4.0000162125,4.3333497047,4.6666827202,5.0000162125, 5.3333492279,5.6666827202,6.0000162125,6.3333492279,6.6666827202, 7.0000157356,7.3333497047,7.6666831970,8.0000171661,8.3333511353, 8.6666841507,9.0000181198,9.3333520889,9.6666860580,10.0000190735, 10.3358526230,10.6916217804,11.0869522095,11.5408391953,12.0713586807, 12.6953773499,13.4282865524,14.2837600708,15.2735414505,16.4072513580, 17.6922454834,19.1334934235,20.7334957123,22.4922523499,24.4072608948, 26.4735546112,28.6837768555,31.0283031464,33.4953994751,36.0713844299, 38.7408676147,41.4869842529,44.2916526794,47.1358833313,50.0000534058; slon= 130.5,131.5,132.5,133.5,134.5,135.5,136.5,137.5,138.5,139.5,140.5,141.5, 142.5,143.5,144.5,145.5,146.5,147.5,148.5,149.5,150.5,151.5,152.5,153.5, 154.5,155.5,156.5,157.5,158.5,159.5,160.5,161.5,162.5,163.5,164.5,165.5, 166.5,167.5,168.5,169.5,170.5,171.5,172.5,173.5,174.5,175.5,176.5,177.5, 178.5,179.5,180.5,181.5,182.5,183.5,184.5,185.5,186.5,187.5,188.5,189.5, 190.5,191.5,192.5,193.5,194.5,195.5,196.5,197.5,198.5,199.5,200.5,201.5, 202.5,203.5,204.5,205.5,206.5,207.5,208.5,209.5,210.5,211.5,212.5,213.5, 214.5,215.5,216.5,217.5,218.5,219.5,220.5,221.5,222.5,223.5,224.5,225.5, 226.5,227.5,228.5,229.5,230.5,231.5,232.5,233.5,234.5,235.5,236.5,237.5, 238.5,239.5,240.5,241.5,242.5,243.5,244.5,245.5,246.5,247.5,248.5,249.5, 250.5,251.5,252.5,253.5,254.5,255.5,256.5,257.5,258.5,259.5,260.5,261.5, 262.5,263.5,264.5,265.5,266.5,267.5,268.5,269.5,270.5,271.5,272.5,273.5, 274.5,275.5,276.5,277.5,278.5,279.5,280.5,281.5,282.5,283.5,284.5,285.5, 286.5,287.5,288.5,289.5; ulon= 131.0,132.0,133.0,134.0,135.0,136.0,137.0,138.0,139.0,140.0,141.0,142.0, 143.0,144.0,145.0,146.0,147.0,148.0,149.0,150.0,151.0,152.0,153.0,154.0, 155.0,156.0,157.0,158.0,159.0,160.0,161.0,162.0,163.0,164.0,165.0,166.0, 167.0,168.0,169.0,170.0,171.0,172.0,173.0,174.0,175.0,176.0,177.0,178.0, 179.0,180.0,181.0,182.0,183.0,184.0,185.0,186.0,187.0,188.0,189.0,190.0, 191.0,192.0,193.0,194.0,195.0,196.0,197.0,198.0,199.0,200.0,201.0,202.0, 203.0,204.0,205.0,206.0,207.0,208.0,209.0,210.0,211.0,212.0,213.0,214.0, 215.0,216.0,217.0,218.0,219.0,220.0,221.0,222.0,223.0,224.0,225.0,226.0, 227.0,228.0,229.0,230.0,231.0,232.0,233.0,234.0,235.0,236.0,237.0,238.0, 239.0,240.0,241.0,242.0,243.0,244.0,245.0,246.0,247.0,248.0,249.0,250.0, 251.0,252.0,253.0,254.0,255.0,256.0,257.0,258.0,259.0,260.0,261.0,262.0, 263.0,264.0,265.0,266.0,267.0,268.0,269.0,270.0,271.0,272.0,273.0,274.0, 275.0,276.0,277.0,278.0,279.0,280.0,281.0,282.0,283.0,284.0,285.0,286.0, 287.0,288.0,289.0,290.0; sdepth= 5.0,15.0,25.0,35.0,45.0,55.0,65.0,75.0,85.0,95.0,106.25,120.0,136.25,155.0, 177.5,205.0,240.0,288.5,362.5,483.5,680.0,979.5,1395.5,1916.0,2524.0,3174.0, 3824.0; sdepth_edges= 0.0,10.0,20.0,30.0,40.0,50.0,60.0,70.0,80.0,90.0,100.0,112.5,127.5, 145.0,165.0,190.0,220.0,260.0,317.0,408.0,559.0,801.0,1158.0,1633.0,2199.0, 2849.0,3499.0,4149.0; wdepth= 10.0,20.0,30.0,40.0,50.0,60.0,70.0,80.0,90.0,100.0,112.5,127.5,145.0,165.0, 190.0,220.0,260.0,317.0,408.0,559.0,801.0,1158.0,1633.0,2199.0,2849.0,3499.0, 4149.0; wdepth_edges= 5.0,15.0,25.0,35.0,45.0,55.0,65.0,75.0,85.0,94.375,105.625,119.375,135.625, 153.75,176.25,202.5,235.75,280.0,347.5,460.75,651.25,950.0,1372.75,1895.0, 2524.0,3174.0,3986.5,4311.0; slon10_140= 139.5, 140.5, 141.5, 142.5, 143.5, 144.5, 145.5, 146.5, 147.5, 148.5, 149.5, 150.5, 151.5, 152.5, 153.5, 154.5, 155.5, 156.5, 157.5, 158.5, 159.5, 160.5, 161.5, 162.5, 163.5, 164.5, 165.5, 166.5, 167.5, 168.5, 169.5, 170.5, 171.5, 172.5, 173.5, 174.5, 175.5, 176.5, 177.5, 178.5, 179.5, 180.5, 181.5, 182.5, 183.5, 184.5, 185.5, 186.5, 187.5, 188.5, 189.5, 190.5, 191.5, 192.5, 193.5, 194.5, 195.5, 196.5, 197.5, 198.5, 199.5, 200.5, 201.5, 202.5, 203.5, 204.5, 205.5, 206.5, 207.5, 208.5, 209.5, 210.5, 211.5, 212.5, 213.5, 214.5, 215.5, 216.5, 217.5, 218.5, 219.5, 220.5, 221.5, 222.5, 223.5, 224.5, 225.5, 226.5, 227.5, 228.5, 229.5, 230.5, 231.5, 232.5, 233.5, 234.5, 235.5, 236.5, 237.5, 238.5, 239.5, 240.5, 241.5, 242.5, 243.5, 244.5, 245.5, 246.5, 247.5, 248.5, 249.5, 250.5, 251.5, 252.5, 253.5, 254.5, 255.5, 256.5, 257.5, 258.5, 259.5, 260.5, 261.5, 262.5, 263.5, 264.5, 265.5, 266.5, 267.5, 268.5, 269.5 ; slat80_82= 11.8060989379883, 12.3833675384522, 13.0618314743042 ; }