Python and netCDF

I am building a python interface to netCDF that is at the core of a project I
am working on.  It isn't quite ready for distribution but appended is a 
description of the classes and methods and an example.

It works well on both MacOS (where I do most of the development) and unix 
(Digital Unix).

Python is especially useful since it works both in an interactive mode for 
poking around a netcdf and batch mode for prewritten scripts.  Since it is
dynamically typed, writing generic handler routines is much easier.

--Bill Noon
Northeast Regional Climate Center
Cornell University


---------------------------
Module exports the following:

    ncerror:  Module exception type.

    WRITE, NOWRITE:  Options for nc.open()
    CLOBBER, NOCLOBBER:  Options for nc.create()
    UNLIMITED:  Record dimension definition
    CHAR, BYTE, SHORT, LONG, FLOAT, DOUBLE:  Different netCDF data types.

    open(name [,mode]) returns an ncfile object.  <mode> is either WRITE or
            NOWRITE.
    create(name [,cmode]) returns an ncfile object.  <cmode> is the create mode
            either CLOBBER or NOCLOBBER.

ncfile objects have the following methods:
    close() closes the netCDF file.
    abort() aborts definition changes to the netCDF file.
    sync() syncs the file to disk.
    redef() enters define mode.
    endef() leaves define mode.
    setfill() enables the fill mode.
    setnofill() disables fill mode.
    def_dim(name, length) define a dimension with <name> and <length>.  Must
            be in define mode, ncfile opened writable and <name> not already
            used.
    def_att(name, variable, nctype, data [,length]) define an attribute <name>
            of the variable named <variable>.  If <variable> is "" then the
            attribute will be global.  <data> is either a float/int, a string, 
            or a tuple of float/ints.
    def_var(name, nctype, [(dim[,dim]*)]) define a variable <name> of type
                nctype. The tuple of dimension names defines the variable 
dimensions.
                If a dimension tuple is not defined, the variable is scalar.
    list_dim() list dimensions.
    list_att([name]) returns a dictionary of the attributes of variable <name>.
            If <name> is not supplied it returns the global attributes.
    list_var() list variables.

    var(name) returns a ncvar object for variable <name>.

    get_rec(rec_num) returns a dictionary of all the record variables for
                <num_rec> record.
    put_rec(rec_num, dict) puts the values defined in the <dict> dictiontary
                into the <rec_num> record.  Variables not defined will not be
                inserted or altered.
        append(dict) as above but adds a new record with the <dict> var/value
                pairs.

ncvar objects are either pseudo-sequences or pseudo-variable.  They have
the following methods:
    list_dim()
    list_att()

NetCDF attributes are treated as python attributes and can be put/get but
not created on the fly.  Global attributes are attributes of the ncfile
object, variable attributes are attributes of the ncvar object.  There is
a namespace clash where an attribute may have the same name as one of the
above methods.  In that case, it can be put/get with a put_att() or
get_att() method.

There is a further enhancement that uses the udunits library and the "_units"
attribute to do automatic unit conversion.



---------------------------------------------
>>> import nc
>>> a = nc.create('test.nc',nc.CLOBBER)
>>> a.def_dim('time',nc.UNLIMITED)
>>> a.def_dim('x', 10)
>>> a.def_dim('y', 5)
>>> a.def_att('Title','',nc.CHAR,'Test netCDF dataset')
>>> a.def_var('temp',nc.FLOAT,('time','x'))
>>> a.def_var('pres',nc.FLOAT,('time','y'))
>>> a.def_att('_units','temp',nc.CHAR,'degree_Fahrenheit')
>>> a.endef()

This creates the netCDF file and defines some dimensions, attributes and
variables.  This generally follows the netCDF API.

>>> a.list_var()
[('temp', 5, 1, 2, [0, 1]), ('pres', 5, 0, 2, [0, 2])]
>>> a.list_att()
{'Title': 'Test netCDF dataset'}
>>> a.list_att('temp')
{'_units': 'degree_Fahrenheit'}
>>> temp = a.var('temp')
>>> temp.list_att()
{'_units': 'degree_Fahrenheit'}
>>> temp._units
'degree_Fahrenheit'
>>> temp
<netCDF variable object at 140055a00>

A netCDF variable object has attributes and values.  The current indexing
scheme in python only allows 1 dimension to be addressed.  This is being
fixed with the numerical extensions.

>>> temp[0] = (10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0)
>>> temp[:]
[10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0]
>>> temp[1] = range(20,30)
>>> temp[:]
[[10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0],
[20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0]]
>>> z = temp[0]
>>> z[5] = 200
>>> temp[0] = z
>>> temp[0]
[10.0, 11.0, 12.0, 13.0, 14.0, 200.0, 16.0, 17.0, 18.0, 19.0]
>>> temp[0][5]
200.0
>>> a.close()

The variable object methods hide most of the access routines in the netCDF
API.  

>>> a = nc.open('test.nc')
>>> temp = a.var('temp')
>>> temp[0]
[10.0, 11.0, 12.0, 13.0, 14.0, 200.0, 16.0, 17.0, 18.0, 19.0]
>>> a.close()

One problem is the use of scalar variables.  Due to the python method of always
passing by reference, the syntax can't be the expected simple assign.
If z is a scalar netCDF variable, z = 10.0 would replace the z variable with
the value 10.  I have decided to make all assignment and reference to scalar
values be of the form z[0].



  • 1996 messages navigation, sorted by:
    1. Thread
    2. Subject
    3. Author
    4. Date
    5. ↑ Table Of Contents
  • Search the netcdfgroup archives: