|
|
|||
|
||||
[Next] [Previous] [Top] [Contents] [Index] [netCDF Home Page] [Unidata Home Page]
NetCDF User's Guide for C
NetCDF version 3 includes a complete rewrite of the netCDF library. It is about twice as fast as the previous version. The netCDF file format is unchanged, so files written with version 3 can be read with version 2 code and vice versa.
The core library is now written in ANSI
C. For example, prototypes are used throughout as well as const
qualifiers where appropriate. You must have an ANSI C compiler to compile
this version.
Rewriting the library offered an opportunity to implement improved C and FORTRAN interfaces that provide some significant benefits:
It is not necessary to rewrite programs that use the version 2 C interface,
because the netCDF-3 library includes a backward
compatibility interface that supports all the old functions, globals, and
behavior. We are hoping that the benefits of the new interface will be an
incentive to use it in new netCDF applications. It is possible to convert
old applications to the new interface incrementally, replacing netCDF-2 calls
with the corresponding netCDF-3 calls one at a time. If you want to check
that only netCDF-3 calls are used in an application, a preprocessor
macro (NO_NETCDF_2) is available for that purpose.
Other changes in the implementation of netCDF result in improved portability, maintainability, and performance on most platforms. A clean separation between I/O and type layers facilitates platform-specific optimizations. The new library no longer uses a vendor-provided XDR library, which simplifies linking programs that use netCDF and speeds up data access significantly in most cases.
First, here's an example of C code that uses the netCDF-2 interface:
void *bufferp;
nc_type xtype;
ncvarinq(ncid, varid, ..., &xtype, ...
...
/* allocate bufferp based on dimensions and type */
...
if (ncvarget(ncid, varid, start, count, bufferp) == -1) {
fprintf(stderr, "Can't get data, error code = %d\n",ncerr);
/* deal with it */
...
}
switch(xtype) {
/* deal with the data, according to type */
...
case NC_FLOAT:
fanalyze((float *)bufferp);
break;
case NC_DOUBLE:
danalyze((double *)bufferp);
break;
}
Here's how you might handle this with the new netCDF-3 C interface:
/*
* I want to use doubles for my analysis.
*/
double dbuf[NDOUBLES];
int status;
/* So, I use the function that gets the data as doubles. */
status = nc_get_vara_double(ncid, varid, start, count, dbuf)
if (status != NC_NOERR) {
fprintf(stderr, "Can't get data: %s\n", nc_strerror(status));
/* deal with it */
...
}
danalyze(dbuf);
The example above illustrates changes in function names, data type conversion, and error handling, discussed in detail in the sections below.
The netCDF-3 C library employs a new naming convention, intended to make
netCDF programs more readable. For example, the name of the function to rename
a variable is now nc_rename_var instead
of the previous ncvarrename.
All netCDF-3 C function names begin with the nc_
prefix. The second part of the name is a verb,
like get, put,
inq (for inquire), or open.
The third part of the name is typically the object of the verb: for example
dim, var,
or att for functions dealing with
dimensions, variables, or attributes. To distinguish the various I/O operations
for variables, a single character modifier is appended to var:
var entire variable access
var1 single value access
vara array or array section access
vars strided access to a subsample
of values
varm mapped access to values not
contiguous in memory
At the end of the name for variable and attribute functions, there is a component
indicating the type of the final argument: text,
uchar, schar, short,
int, long, float,
or double. This part of the function
name indicates the type of the data container you are using in your program:
character string, unsigned char, signed char, and
so on.
Also, all macro
names in the public C interface
begin with the prefix NC_. For example,
the macro which was formerly MAX_NC_NAME
is now NC_MAX_NAME,
and the former FILL_FLOAT is now NC_FILL_FLOAT.
As previously mentioned, all the old names are still supported for backward compatibility.
With the new interface, users need not be aware of the external type of numeric variables, since automatic conversion to or from any desired numeric type is now available. You can use this feature to simplify code, by making it independent of external types. The elimination of void* pointers provides detection of type errors at compile time that could not be detected with the previous interface. Programs may be made more robust with the new interface, because they need not be changed to accommodate a change to the external type of a variable.
If conversion to or from an external numeric type is necessary, it is handled by the library. This automatic conversion and separation of external data representation from internal data types will become even more important in netCDF version 4, when new external types will be added for packed data for which there is no natural corresponding internal type, for example, arrays of 11-bit values.
Converting
from one numeric type to another may result in an error if the target type
is not capable of representing the converted value. (In netCDF-2, such overflows
can only happen in the XDR layer.) For example, a float may
not be able to hold data stored externally as an NC_DOUBLE (an
IEEE floating-point number). When accessing an array of values, an NC_ERANGE
error is returned if one or more values are out
of the range of representable values, but other values are converted properly.
Note that mere loss of precision in type conversion does not return an error. Thus, if you read double precision values into an int, for example, no error results unless the magnitude of the double precision value exceeds the representable range of ints on your platform. Similarly, if you read a large integer into a float incapable of representing all the bits of the integer in its mantissa, this loss of precision will not result in an error. If you want to avoid such precision loss, check the external types of the variables you access to make sure you use an internal type that has a compatible precision.
The
new interface distinguishes arrays of characters intended to represent text
strings from arrays of 8-bit bytes intended to represent small integers. The
interface supports the internal types text, uchar,
and schar, intended for text strings,
unsigned byte values, and signed byte values.
The _uchar and _schar functions were introduced
in netCDF-3 to eliminate an ambiguity, and support both signed and unsigned
byte data. In netCDF-2, whether the external NC_BYTE type represented
signed or unsigned values was left up to the user. In netcdf-3, we treat NC_BYTE
as signed for the purposes of conversion to short, int, long, float, or double.
(Of course, no conversion takes place when the internal type is signed char.)
In the _uchar functions, we treat NC_BYTE as if it were unsigned.
Thus, no NC_ERANGE error can occur converting between NC_BYTE
and unsigned char.
The new interface handles errors differently than netCDF-2. In the old interface,
the default behavior when an error was detected was to print an error message
and exit. To get control of error handling, you had to set flag bits in a
global variable, ncopts, and to determine the cause
of an error, you had to test the value of another global variable ncerr.
In the new interface, functions return an integer status that indicates not
only success or failure, but also the cause of the error. The
global variables ncerr and ncopt have been eliminated. The library will never
try to print anything, nor will it call exit (unless you are
using the netCDF version 2 compatibility functions). You will have to check
the function return status and do this yourself. We eliminated these globals
in the interest of supporting parallel (multiprocessor) execution cleanly,
as well as reducing the number of assumptions about the environment where
netCDF is used. The new behavior should provide better support for using netCDF
as a hidden layer in applications that have their own GUI interface.
NC_LONG
and NC_INT Where the netCDF-2 interface used NC_LONG to
identify an external data type corresponding to 32-bit integers, the new interface
uses NC_INT instead. NC_LONG
is defined to have the same value as NC_INT
for backward compatibility, but it should not be
used in new code. With new 64-bit platforms using long for 64-bit integers,
we would like to reduce the confusion caused by this name clash. Note that
there is still no netCDF external data type corresponding to 64-bit integers.
The new C interface omits three "record I/O" functions, ncrecput,
ncrecget, and ncrecinq,
from the netCDF-2 interface, although these functions are still supported
via the netCDF-2 compatibility interface.
This means you may have to replace one record-oriented call with multiple
type-specific calls, one for each record variable. For example, a single call
to ncrecput can always be replaced by multiple calls to the appropriate nc_put_var
functions, one call for each variable accessed. The record-oriented functions
were omitted, because there is no simple way to provide type-safety and automatic
type conversion for such an interface.
There is no function corresponding to the nctypelen
function from the version 2 interface. The separation
of internal and external types and the new type-conversion interfaces make
nctypelen unnecessary. Since users
read into and write out of native types, the sizeof operator
is perfectly adequate to determine how much space
to allocate for a value.
In
the previous library, there was no checking that the characters used in the
name of a netCDF object were compatible with CDL restrictions. The ncdump
and ncgen utilities that use CDL permit only alphanumeric characters, "_"
and "-" in names. Now this restriction is also enforced by the
library for creation of new dimensions, variables, and attributes. Previously
existing components with less restrictive names will still work OK.
There are two new functions in netCDF-3 that don't correspond to any netCDF-2
functions: nc_inq_libvers and nc_strerror.
The version of the netCDF library in use is returned as a string by nc_inq_libvers.
An error message corresponding to the status returned by a netCDF function
call is returned as a string by the nc_strerror function.
A new NC_SHARE flag
is available for use in an nc_open or
nc_create call, to suppress
the default buffering of accesses. The use of NC_SHARE for
concurrent access to a netCDF dataset means you don't have to call nc_sync
after every access to make sure that disk updates
are synchronous. It is important to note that changes to ancillary data, such
as attribute values, are not propagated automatically by use of the NC_SHARE
flag. Use of the nc_sync
function is still required for this purpose.
The version 2 interface had a single inquiry function, ncvarinq for
getting the name, type, and shape of a variable. Similarly, only a single
inquiry function was available for getting information about a dimension,
an attribute, or a netCDF dataset. When you only wanted a subset of this information,
you had to provide NULL arguments as placeholders
for the unneeded information. The new interface includes additional inquire
functions that return each item separately, so errors are less likely from
miscounting arguments.
The previous implementation returned an error when 0-valued
count components were specified in ncvarput and
ncvarget calls. This restriction has
been removed, so that now functions in the nc_put_var and
nc_get_var families may be called
with 0-valued count components, resulting in no data being accessed. Although
this may seem useless, it simplifies some programs to not treat 0-valued counts
as a special case.
The previous implementation returned an error when the same dimension was used more than once in specifying the shape of a variable in ncvardef. This restriction is relaxed in the netCDF-3 implementation, because an autocorrelation matrix is a good example where using the same dimension twice makes sense.
In the new interface, units for the imap argument
to the nc_put_varm and nc_get_varm
families of functions are now in terms of the number
of data elements of the desired internal type, not in terms of bytes as in
the netCDF version-2 mapped access interfaces.
Following is a table of netCDF-2 function names and names of the corresponding netCDF-3 functions. For parameter lists of netCDF-2 functions, see the netCDF-2 User's Guide.
ncabort |
nc_abort |
ncattcopy |
nc_copy_att |
ncattdel |
nc_del_att |
ncattget |
nc_get_att_double, nc_get_att_float, nc_get_att_int, nc_get_att_long, nc_get_att_schar, nc_get_att_short, nc_get_att_text, nc_get_att_uchar |
ncattinq |
nc_inq_att, nc_inq_attid, nc_inq_attlen, nc_inq_atttype |
ncattname |
nc_inq_attname |
ncattput |
nc_put_att_double, nc_put_att_float, nc_put_att_int, nc_put_att_long, nc_put_att_schar, nc_put_att_short, nc_put_att_text, nc_put_att_uchar |
ncattrename |
nc_rename_att |
ncclose |
nc_close |
nccreate |
nc_create |
ncdimdef |
nc_def_dim |
ncdimid |
nc_inq_dimid |
ncdiminq |
nc_inq_dim, nc_inq_dimlen, nc_inq_dimname |
ncdimrename |
nc_rename_dim |
ncendef |
nc_enddef |
ncinquire |
nc_inq, nc_inq_natts, nc_inq_ndims, nc_inq_nvars, nc_inq_unlimdim |
ncopen |
nc_open |
ncrecget |
(none) |
ncrecinq |
(none) |
ncrecput |
(none) |
ncredef |
nc_redef |
ncsetfill |
nc_set_fill |
ncsync |
nc_sync |
nctypelen |
(none) |
ncvardef |
nc_def_var |
ncvarget |
nc_get_vara_double, nc_get_vara_float, nc_get_vara_int, nc_get_vara_long, nc_get_vara_schar, nc_get_vara_short, nc_get_vara_text, nc_get_vara_uchar |
ncvarget1 |
nc_get_var1_double, nc_get_var1_float, nc_get_var1_int, nc_get_var1_long, nc_get_var1_schar, nc_get_var1_short, nc_get_var1_text, nc_get_var1_uchar |
ncvargetg |
nc_get_varm_double, nc_get_varm_float, nc_get_varm_int, nc_get_varm_long, nc_get_varm_schar, nc_get_varm_short, nc_get_varm_text, nc_get_varm_uchar, nc_get_vars_double, nc_get_vars_float, nc_get_vars_int, nc_get_vars_long, nc_get_vars_schar, nc_get_vars_short, nc_get_vars_text, nc_get_vars_uchar |
ncvarid |
nc_inq_varid |
ncvarinq |
nc_inq_var, nc_inq_vardimid, nc_inq_varname, nc_inq_varnatts, nc_inq_varndims, nc_inq_vartype |
ncvarput |
nc_put_vara_double, nc_put_vara_float, nc_put_vara_int, nc_put_vara_long, nc_put_vara_schar, nc_put_vara_short, nc_put_vara_text, nc_put_vara_uchar |
ncvarput1 |
nc_put_var1_double, nc_put_var1_float, nc_put_var1_int, nc_put_var1_long, nc_put_var1_schar, nc_put_var1_short, nc_put_var1_text, nc_put_var1_uchar |
ncvarputg |
nc_put_varm_double, nc_put_varm_float, nc_put_varm_int, nc_put_varm_long, nc_put_varm_schar, nc_put_varm_short, nc_put_varm_text, nc_put_varm_uchar, nc_put_vars_double, nc_put_vars_float, nc_put_vars_int, nc_put_vars_long, nc_put_vars_schar, nc_put_vars_short, nc_put_vars_text, nc_put_vars_uchar |
ncvarrename |
nc_rename_var |
(none) |
nc_inq_libvers |
(none) |
nc_strerror |
[Next] [Previous] [Top] [Contents] [Index] [netCDF Home Page] [Unidata Home Page]
| Contact Us Site Map Search Terms and Conditions Privacy Policy Participation Policy | ||||||
|
||||||