Package solvcon :: Package io :: Module netcdf
[hide private]
[frames] | no frames]

Source Code for Module solvcon.io.netcdf

  1  # -*- coding: UTF-8 -*- 
  2  # 
  3  # Copyright (C) 2011 Yung-Yu Chen <yyc@solvcon.net>. 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License along 
 16  # with this program; if not, write to the Free Software Foundation, Inc., 
 17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 18   
 19  """ 
 20  This is a simple wrapper to netCDF C library.  This wrapper is designed to be 
 21  self-sufficient.  That is, this should be kept to be an one-file module. 
 22   
 23  The module is designed for reading rather than writing.  Only limited Pythonic 
 24  API is implemented.  All constants are taken from the netcdf.h file in the 
 25  official distribution (4.1.1). 
 26   
 27  For more information about netCDF, please refer to  
 28  http://www.unidata.ucar.edu/software/netcdf/index.html 
 29  """ 
 30   
 31  _libs = dict() 
32 -def get_lib(path):
33 from ctypes import CDLL 34 if path in _libs: 35 lib = _libs[path] 36 else: 37 lib = _libs[path] = CDLL('libnetcdf.so') 38 return lib
39
40 -class NetCDF(object):
41 """ 42 Wrapper for the netCDF library by using ctypes. Mainly designed for 43 reading. Native functions remains to be nc_*. NC_* are class members for 44 constants defined in the header file. 45 """ 46 47 # netcdf external data types 48 NC_NAT = 0 # Not A Type. 49 NC_BYTE = 1 # signed 1 byte integer. 50 NC_CHAR = 2 # ISO/ASCII character. 51 NC_SHORT = 3 # signed 2 byte integer. 52 NC_INT = 4 # signed 4 byte integer. 53 NC_LONG = NC_INT # deprecated, but required for backward compatibility. 54 NC_FLOAT = 5 # single precision floating point number. 55 NC_DOUBLE = 6 # double precision floating point number. 56 NC_UBYTE = 7 # unsigned 1 byte int. 57 NC_USHORT = 8 # unsigned 2-byte int. 58 NC_UINT = 9 # unsigned 4-byte int. 59 NC_INT64 = 10 # signed 8-byte int. 60 NC_UINT64 = 11 # unsigned 8-byte int. 61 NC_STRING = 12 # string. 62 # used internally in support of user-defines types. They are also the class 63 # returned by nc_inq_user_type. 64 NC_VLEN = 13 # used internally for vlen types. 65 NC_OPAQUE = 14 # used internally for opaque types. 66 NC_ENUM = 15 # used internally for enum types. 67 NC_COMPOUND = 16 # used internally for compound types. 68 69 # Default fill values. 70 NC_FILL_BYTE = -127 71 NC_FILL_CHAR = 0 72 NC_FILL_SHORT = -32767 73 NC_FILL_INT = -2147483647L 74 NC_FILL_FLOAT = 9.9692099683868690e+36 # near 15 * 2^119. 75 NC_FILL_DOUBLE = 9.9692099683868690e+36 76 NC_FILL_UBYTE = 255 77 NC_FILL_USHORT = 65535 78 NC_FILL_UINT = 4294967295 79 NC_FILL_INT64 = -9223372036854775806 80 NC_FILL_UINT64 = 18446744073709551614 81 NC_FILL_STRING = '' 82 83 # max and min. 84 NC_MAX_BYTE = 127 85 NC_MIN_BYTE = -NC_MAX_BYTE - 1 86 NC_MAX_CHAR = 255 87 NC_MAX_SHORT = 32767 88 NC_MIN_SHORT = -NC_MAX_SHORT - 1 89 NC_MAX_INT = 2147483647 90 NC_MIN_INT = -NC_MAX_INT - 1 91 NC_MAX_FLOAT = 3.402823466e+38 92 NC_MIN_FLOAT = -NC_MAX_FLOAT 93 NC_MAX_DOUBLE = 1.7976931348623157e+308 94 NC_MIN_DOUBLE = -NC_MAX_DOUBLE 95 NC_MAX_UBYTE = NC_MAX_CHAR 96 NC_MAX_USHORT = 65535 97 NC_MAX_UINT = 4294967295 98 NC_MAX_INT64 = 9223372036854775807 99 NC_MIN_INT64 = -9223372036854775807 - 1 100 NC_MAX_UINT64 = 18446744073709551615 101 X_INT64_MAX = 9223372036854775807 102 X_INT64_MIN = -X_INT64_MAX - 1 103 X_UINT64_MAX = 18446744073709551615 104 105 # for fill. 106 _FillValue = '_FillValue' 107 NC_FILL = 0 108 NC_NOFILL = 0x100 109 110 # mode for nc_open 111 NC_NOWRITE = 0 # default read-only. 112 NC_WRITE = 0x0001 # read and write. 113 # mode for nc_create 114 NC_CLOBBER = 0 115 NC_NOCLOBBER = 0x0004 # don't descroy existing file. 116 NC_64BIT_OFFSET = 0x0200 # use 64-bit (large) file offsets. 117 NC_NETCDF4 = 0x1000 # use netCDF-4/HDF5 format. 118 NC_CLASSICAL_MODE = 0x0100 # enforce classic model with NC_NETCDF4. 119 # mode for both nc_open and nc_create. 120 NC_SHARE = 0x0800 # share updates, limit cache. 121 NC_MPIIO = 0x2000 122 NC_MPIPOSIX = 0x4000 123 NC_PNETXCDF = 0x8000 124 # future mode for nc_open and nc_create 125 NC_LOCK = 0x0400 126 127 # formats; there are more than one format since 3.6. 128 NC_FORMAT_CLASSIC = 1 129 NC_FORMAT_64BIT = 2 130 NC_FORMAT_NETCDF4 = 3 131 NC_FORMAT_NETCDF4_CLASSIC = 4 132 133 # for nc__open and nc__create. 134 NC_SIZEHINT_DEFAULT = 0 135 136 # in nc__enddef, align to chunk size. 137 NC_ALIGN_CHUNK = -1 138 139 # size argument to ncdimdef for unlimit. 140 NC_UNLIMITED = 0 141 142 # attribute ID for global attributes. 143 NC_GLOBAL = -1 144 145 # interfacial max; nothing to do with netCDF internal implementation. 146 NC_MAX_DIMS = 1024 # max dimensions per file. 147 NC_MAX_ATTRS = 8192 # max global or per variable attributes. 148 NC_MAX_VARS = 8192 # max variables per file. 149 NC_MAX_NAME = 256 # max length of a name. 150 NC_MAX_VAR_DIMS = NC_MAX_DIMS # max per variable dimensions. 151 152 # endianness for HDF5 files. 153 NC_ENDIAN_NATIVE = 0 154 NC_ENDIAN_LITTLE = 1 155 NC_ENDIAN_BIG = 2 156 # chunk or continuous for HDF5 files. 157 NC_CHUNKED = 0 158 NC_CONTIGUOUS = 1 159 # checksum for HDF5 files. 160 NC_NOCHECKSUM = 0 161 NC_FLETCHER32 = 1 162 # shuffle for HDF5 files. 163 NC_NOSHUFFLE = 0 164 NC_SHUFFLE = 1 165 166 # errors. 167 NC_NOERR = 0 # no error. 168 169 NC2_ERR = -1 # for all errors in the v2 API. 170 NC_EBADID = -33 # Not a netcdf id. 171 NC_ENFILE = -34 # Too many netcdfs open. 172 NC_EEXIST = -35 # netcdf file exists && NC_NOCLOBBER. 173 NC_EINVAL = -36 # Invalid Argument. 174 NC_EPERM = -37 # Write to read only. 175 NC_ENOTINDEFINE = -38 # Operation not allowed in data mode. 176 NC_EINDEFINE = -39 # Operation not allowed in define mode. 177 NC_EINVALCOORDS = -40 # Index exceeds dimension bound. 178 NC_EMAXDIMS = -41 # NC_MAX_DIMS exceeded. 179 NC_ENAMEINUSE = -42 # String match to name in use. 180 NC_ENOTATT = -43 # Attribute not found. 181 NC_EMAXATTS = -44 # NC_MAX_ATTRS exceeded. 182 NC_EBADTYPE = -45 # Not a netcdf data type. 183 NC_EBADDIM = -46 # Invalid dimension id or name. 184 NC_EUNLIMPOS = -47 # NC_UNLIMITED in the wrong index. 185 NC_EMAXVARS = -48 # NC_MAX_VARS exceeded. 186 NC_ENOTVAR = -49 # Variable not found. 187 NC_EGLOBAL = -50 # Action prohibited on NC_GLOBAL varid. 188 NC_ENOTNC = -51 # Not a netcdf file. 189 NC_ESTS = -52 # In Fortran, string too short. 190 NC_EMAXNAME = -53 # NC_MAX_NAME exceeded. 191 NC_EUNLIMIT = -54 # NC_UNLIMITED size already in use. 192 NC_ENORECVARS = -55 # nc_rec op when there are no record vars. 193 NC_ECHAR = -56 # Attempt to convert between text & numbers. 194 NC_EEDGE = -57 # Start+count exceeds dimension bound. 195 NC_ESTRIDE = -58 # Illegal stride. 196 NC_EBADNAME = -59 # Attribute or variable name contains illegal 197 # characters. 198 199 # following must match value in ncx.h 200 NC_ERANGE = -60 # Math result not representable. 201 NC_ENOMEM = -61 # Memory allocation (malloc) failure. 202 NC_EVARSIZE = -62 # One or more variable sizes violate format 203 # constraints. 204 NC_EDIMSIZE = -63 # Invalid dimension size. 205 NC_ETRUNC = -64 # File likely truncated or possibly corrupted. 206 NC_EAXISTYPE = -65 # Unknown axis type. 207 208 # following errors are added for DAP. 209 NC_EDAP = -66 # Generic DAP error. 210 NC_ECURL = -67 # Generic libcurl error. 211 NC_EIO = -68 # Generic IO error. 212 NC_ENODATA = -69 # Attempt to access variable with no data. 213 NC_EDAPSVC = -70 # DAP Server side error. 214 NC_EDAS = -71 # Malformed or inaccessible DAS. 215 NC_EDDS = -72 # Malformed or inaccessible DDS. 216 NC_EDATADDS = -73 # Malformed or inaccessible DATADDS. 217 NC_EDAPURL = -74 # Malformed DAP URL. 218 NC_EDAPCONSTRAINT = -75 # Malformed DAP Constraint. 219 220 # following was added in support of netcdf-4. Make all netcdf-4 error codes 221 # < -100 so that errors can be added to netcdf-3 if needed. 222 NC4_FIRST_ERROR = -100 223 NC_EHDFERR = -101 # Error at HDF5 layer. 224 NC_ECANTREAD = -102 # Can't read. 225 NC_ECANTWRITE = -103 # Can't write. 226 NC_ECANTCREATE = -104 # Can't create. 227 NC_EFILEMETA = -105 # Problem with file metadata. 228 NC_EDIMMETA = -106 # Problem with dimension metadata. 229 NC_EATTMETA = -107 # Problem with attribute metadata. 230 NC_EVARMETA = -108 # Problem with variable metadata. 231 NC_ENOCOMPOUND = -109 # Not a compound type. 232 NC_EATTEXISTS = -110 # Attribute already exists. 233 NC_ENOTNC4 = -111 # Attempting netcdf-4 operation on netcdf-3 file. 234 NC_ESTRICTNC3 = -112 # Attempting netcdf-4 operation on strict nc3 235 # netcdf-4 file. 236 NC_ENOTNC3 = -113 # Attempting netcdf-3 operation on netcdf-4 file. 237 NC_ENOPAR = -114 # Parallel operation on file opened for non-parallel 238 # access. 239 NC_EPARINIT = -115 # Error initializing for parallel access. 240 NC_EBADGRPID = -116 # Bad group ID. 241 NC_EBADTYPID = -117 # Bad type ID. 242 NC_ETYPDEFINED = -118 # Type has already been defined and may not be 243 # edited. 244 NC_EBADFIELD = -119 # Bad field ID. 245 NC_EBADCLASS = -120 # Bad class. 246 NC_EMAPTYPE = -121 # Mapped access for atomic types only. 247 NC_ELATEFILL = -122 # Attempt to define fill value when data already 248 # exists. 249 NC_ELATEDEF = -123 # Attempt to define var properties, like deflate, after 250 # enddef. 251 NC_EDIMSCALE = -124 # Probem with HDF5 dimscales. 252 NC_ENOGRP = -125 # No group found. 253 NC_ESTORAGE = -126 # Can't specify both contiguous and chunking. 254 NC_EBADCHUNK = -127 # Bad chunksize. 255 NC_ENOTBUILT = -128 # Attempt to use feature that was not turned on when 256 # netCDF was built. 257 NC4_LAST_ERROR = -128 258
259 - def __init__(self, path=None, omode=None, libname='libnetcdf.so'):
260 """ 261 @keyword path: the file to open. 262 @type path: str 263 @keyword omode: opening mode. 264 @type omode: int 265 """ 266 from ctypes import c_char_p 267 self.lib = get_lib(libname) 268 self.ncid = None 269 # set up return type. 270 self.nc_strerror.restype = c_char_p 271 self.nc_inq_libvers.restype = c_char_p 272 # open file. 273 if path is not None: 274 self.open_file(path, omode)
275 - def __getattr__(self, key):
276 if key.startswith('nc_'): 277 return getattr(self.lib, key)
278
279 - def open_file(self, path, omode=None):
280 """ 281 Open a NetCDF file. 282 283 @keyword path: the file to open. 284 @type path: str 285 @keyword omode: opening mode. 286 @type omode: int 287 @return: ncid 288 @rtype: int 289 """ 290 from ctypes import c_int, byref 291 omode = self.NC_NOWRITE if omode is None else omode 292 if self.ncid is not None: 293 raise IOError('ncid %d has been opened'%self.ncid) 294 ncid = c_int() 295 retval = self.nc_open(path, omode, byref(ncid)) 296 if retval != self.NC_NOERR: 297 raise IOError(self.nc_strerror(retval)) 298 self.ncid = ncid.value 299 return self.ncid
300 - def close_file(self):
301 """ 302 Close the associated NetCDF file. 303 304 @return: nothing 305 """ 306 retval = self.nc_close(self.ncid) 307 if retval != self.NC_NOERR: 308 raise IOError(self.nc_strerror(retval)) 309 self.ncid = None
310
311 - def get_dim(self, name):
312 """ 313 Get the dimension of the given name. 314 315 @param name: the name of the dimension. 316 @type name: str 317 @return: the dimension (length). 318 @rtype: int 319 """ 320 from ctypes import c_int, c_long, byref 321 dimid = c_int() 322 length = c_long() 323 retval = self.nc_inq_dimid(self.ncid, name, byref(dimid)) 324 if retval != self.NC_NOERR: 325 raise IOError(self.nc_strerror(retval)) 326 retval = self.nc_inq_dimlen(self.ncid, dimid, byref(length)) 327 if retval != self.NC_NOERR: 328 raise IOError(self.nc_strerror(retval)) 329 return length.value
330
331 - def get_array(self, name, shape, dtype):
332 """ 333 Load ndarray from netCDF file. 334 335 @param name: the data to be loaded. 336 @type name: str 337 @param shape: the shape of ndarray. 338 @type shape: tuple 339 @param dtype: the dtype of ndarray. 340 @type dtype: str 341 @return: the loaded ndarray. 342 @rtype: numpy.ndarray 343 """ 344 from ctypes import POINTER, c_int, c_float, c_double, byref 345 from numpy import empty 346 # get value ID. 347 varid = c_int() 348 retval = self.nc_inq_varid(self.ncid, name, byref(varid)) 349 if retval != self.NC_NOERR: 350 raise IOError(self.nc_strerror(retval)) 351 # prepare array and loader. 352 arr = empty(shape, dtype=dtype) 353 if dtype == 'int32': 354 func = self.nc_get_var_int 355 elif dtype == 'float32': 356 func = self.nc_get_var_float 357 elif dtype == 'float64': 358 func = self.nc_get_var_double 359 else: 360 raise TypeError('now surrport only int, float, double, and char') 361 # load array. 362 retval = func(self.ncid, varid, arr.ctypes._as_parameter_) 363 if retval != self.NC_NOERR: 364 raise IOError(self.nc_strerror(retval)) 365 return arr
366
367 - def get_lines(self, name, shape):
368 """ 369 Load string from netCDF file. 370 371 @param name: the data to be loaded. 372 @type name: str 373 @param shape: the shape of ndarray. Must be 1 or 2. 374 @type shape: tuple 375 @return: the loaded ndarray. 376 @rtype: numpy.ndarray 377 """ 378 from ctypes import POINTER, c_int, c_char, byref 379 from numpy import empty 380 if len(shape) > 2: 381 raise IndexError('array should have no more than two dimension') 382 # get value ID. 383 varid = c_int() 384 retval = self.nc_inq_varid(self.ncid, name, byref(varid)) 385 if retval != self.NC_NOERR: 386 raise IOError(self.nc_strerror(retval)) 387 # prepare array and loader. 388 arr = empty(shape, dtype='byte') 389 # load string data. 390 retval = self.nc_get_var_text(self.ncid, varid, 391 arr.ctypes._as_parameter_) 392 if retval != self.NC_NOERR: 393 raise IOError(self.nc_strerror(retval)) 394 # convert to string. 395 shape = (1, shape[0]) if len(shape) < 2 else shape 396 arr = arr.reshape(shape) 397 lines = [] 398 for ii in range(shape[0]): 399 for ij in range(shape[1]): 400 if arr[ii,ij] == 0: 401 lines.append(arr[ii,:ij].tostring()) 402 break 403 if len(lines) <= ii: 404 lines.append(arr[ii,:].tostring()) 405 return lines
406