1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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()
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
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
48 NC_NAT = 0
49 NC_BYTE = 1
50 NC_CHAR = 2
51 NC_SHORT = 3
52 NC_INT = 4
53 NC_LONG = NC_INT
54 NC_FLOAT = 5
55 NC_DOUBLE = 6
56 NC_UBYTE = 7
57 NC_USHORT = 8
58 NC_UINT = 9
59 NC_INT64 = 10
60 NC_UINT64 = 11
61 NC_STRING = 12
62
63
64 NC_VLEN = 13
65 NC_OPAQUE = 14
66 NC_ENUM = 15
67 NC_COMPOUND = 16
68
69
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
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
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
106 _FillValue = '_FillValue'
107 NC_FILL = 0
108 NC_NOFILL = 0x100
109
110
111 NC_NOWRITE = 0
112 NC_WRITE = 0x0001
113
114 NC_CLOBBER = 0
115 NC_NOCLOBBER = 0x0004
116 NC_64BIT_OFFSET = 0x0200
117 NC_NETCDF4 = 0x1000
118 NC_CLASSICAL_MODE = 0x0100
119
120 NC_SHARE = 0x0800
121 NC_MPIIO = 0x2000
122 NC_MPIPOSIX = 0x4000
123 NC_PNETXCDF = 0x8000
124
125 NC_LOCK = 0x0400
126
127
128 NC_FORMAT_CLASSIC = 1
129 NC_FORMAT_64BIT = 2
130 NC_FORMAT_NETCDF4 = 3
131 NC_FORMAT_NETCDF4_CLASSIC = 4
132
133
134 NC_SIZEHINT_DEFAULT = 0
135
136
137 NC_ALIGN_CHUNK = -1
138
139
140 NC_UNLIMITED = 0
141
142
143 NC_GLOBAL = -1
144
145
146 NC_MAX_DIMS = 1024
147 NC_MAX_ATTRS = 8192
148 NC_MAX_VARS = 8192
149 NC_MAX_NAME = 256
150 NC_MAX_VAR_DIMS = NC_MAX_DIMS
151
152
153 NC_ENDIAN_NATIVE = 0
154 NC_ENDIAN_LITTLE = 1
155 NC_ENDIAN_BIG = 2
156
157 NC_CHUNKED = 0
158 NC_CONTIGUOUS = 1
159
160 NC_NOCHECKSUM = 0
161 NC_FLETCHER32 = 1
162
163 NC_NOSHUFFLE = 0
164 NC_SHUFFLE = 1
165
166
167 NC_NOERR = 0
168
169 NC2_ERR = -1
170 NC_EBADID = -33
171 NC_ENFILE = -34
172 NC_EEXIST = -35
173 NC_EINVAL = -36
174 NC_EPERM = -37
175 NC_ENOTINDEFINE = -38
176 NC_EINDEFINE = -39
177 NC_EINVALCOORDS = -40
178 NC_EMAXDIMS = -41
179 NC_ENAMEINUSE = -42
180 NC_ENOTATT = -43
181 NC_EMAXATTS = -44
182 NC_EBADTYPE = -45
183 NC_EBADDIM = -46
184 NC_EUNLIMPOS = -47
185 NC_EMAXVARS = -48
186 NC_ENOTVAR = -49
187 NC_EGLOBAL = -50
188 NC_ENOTNC = -51
189 NC_ESTS = -52
190 NC_EMAXNAME = -53
191 NC_EUNLIMIT = -54
192 NC_ENORECVARS = -55
193 NC_ECHAR = -56
194 NC_EEDGE = -57
195 NC_ESTRIDE = -58
196 NC_EBADNAME = -59
197
198
199
200 NC_ERANGE = -60
201 NC_ENOMEM = -61
202 NC_EVARSIZE = -62
203
204 NC_EDIMSIZE = -63
205 NC_ETRUNC = -64
206 NC_EAXISTYPE = -65
207
208
209 NC_EDAP = -66
210 NC_ECURL = -67
211 NC_EIO = -68
212 NC_ENODATA = -69
213 NC_EDAPSVC = -70
214 NC_EDAS = -71
215 NC_EDDS = -72
216 NC_EDATADDS = -73
217 NC_EDAPURL = -74
218 NC_EDAPCONSTRAINT = -75
219
220
221
222 NC4_FIRST_ERROR = -100
223 NC_EHDFERR = -101
224 NC_ECANTREAD = -102
225 NC_ECANTWRITE = -103
226 NC_ECANTCREATE = -104
227 NC_EFILEMETA = -105
228 NC_EDIMMETA = -106
229 NC_EATTMETA = -107
230 NC_EVARMETA = -108
231 NC_ENOCOMPOUND = -109
232 NC_EATTEXISTS = -110
233 NC_ENOTNC4 = -111
234 NC_ESTRICTNC3 = -112
235
236 NC_ENOTNC3 = -113
237 NC_ENOPAR = -114
238
239 NC_EPARINIT = -115
240 NC_EBADGRPID = -116
241 NC_EBADTYPID = -117
242 NC_ETYPDEFINED = -118
243
244 NC_EBADFIELD = -119
245 NC_EBADCLASS = -120
246 NC_EMAPTYPE = -121
247 NC_ELATEFILL = -122
248
249 NC_ELATEDEF = -123
250
251 NC_EDIMSCALE = -124
252 NC_ENOGRP = -125
253 NC_ESTORAGE = -126
254 NC_EBADCHUNK = -127
255 NC_ENOTBUILT = -128
256
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
270 self.nc_strerror.restype = c_char_p
271 self.nc_inq_libvers.restype = c_char_p
272
273 if path is not None:
274 self.open_file(path, omode)
276 if key.startswith('nc_'):
277 return getattr(self.lib, key)
278
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
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
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
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
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
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
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
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
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
388 arr = empty(shape, dtype='byte')
389
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
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