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()
40
42 """
43 Wrapper for the netCDF library by using ctypes. Mainly designed for
44 reading. Native functions remains to be nc_*. NC_* are class members for
45 constants defined in the header file.
46 """
47
48
49 NC_NAT = 0
50 NC_BYTE = 1
51 NC_CHAR = 2
52 NC_SHORT = 3
53 NC_INT = 4
54 NC_LONG = NC_INT
55 NC_FLOAT = 5
56 NC_DOUBLE = 6
57 NC_UBYTE = 7
58 NC_USHORT = 8
59 NC_UINT = 9
60 NC_INT64 = 10
61 NC_UINT64 = 11
62 NC_STRING = 12
63
64
65 NC_VLEN = 13
66 NC_OPAQUE = 14
67 NC_ENUM = 15
68 NC_COMPOUND = 16
69
70
71 NC_FILL_BYTE = -127
72 NC_FILL_CHAR = 0
73 NC_FILL_SHORT = -32767
74 NC_FILL_INT = -2147483647L
75 NC_FILL_FLOAT = 9.9692099683868690e+36
76 NC_FILL_DOUBLE = 9.9692099683868690e+36
77 NC_FILL_UBYTE = 255
78 NC_FILL_USHORT = 65535
79 NC_FILL_UINT = 4294967295
80 NC_FILL_INT64 = -9223372036854775806
81 NC_FILL_UINT64 = 18446744073709551614
82 NC_FILL_STRING = ''
83
84
85 NC_MAX_BYTE = 127
86 NC_MIN_BYTE = -NC_MAX_BYTE - 1
87 NC_MAX_CHAR = 255
88 NC_MAX_SHORT = 32767
89 NC_MIN_SHORT = -NC_MAX_SHORT - 1
90 NC_MAX_INT = 2147483647
91 NC_MIN_INT = -NC_MAX_INT - 1
92 NC_MAX_FLOAT = 3.402823466e+38
93 NC_MIN_FLOAT = -NC_MAX_FLOAT
94 NC_MAX_DOUBLE = 1.7976931348623157e+308
95 NC_MIN_DOUBLE = -NC_MAX_DOUBLE
96 NC_MAX_UBYTE = NC_MAX_CHAR
97 NC_MAX_USHORT = 65535
98 NC_MAX_UINT = 4294967295
99 NC_MAX_INT64 = 9223372036854775807
100 NC_MIN_INT64 = -9223372036854775807 - 1
101 NC_MAX_UINT64 = 18446744073709551615
102 X_INT64_MAX = 9223372036854775807
103 X_INT64_MIN = -X_INT64_MAX - 1
104 X_UINT64_MAX = 18446744073709551615
105
106
107 _FillValue = '_FillValue'
108 NC_FILL = 0
109 NC_NOFILL = 0x100
110
111
112 NC_NOWRITE = 0
113 NC_WRITE = 0x0001
114
115 NC_CLOBBER = 0
116 NC_NOCLOBBER = 0x0004
117 NC_64BIT_OFFSET = 0x0200
118 NC_NETCDF4 = 0x1000
119 NC_CLASSICAL_MODE = 0x0100
120
121 NC_SHARE = 0x0800
122 NC_MPIIO = 0x2000
123 NC_MPIPOSIX = 0x4000
124 NC_PNETXCDF = 0x8000
125
126 NC_LOCK = 0x0400
127
128
129 NC_FORMAT_CLASSIC = 1
130 NC_FORMAT_64BIT = 2
131 NC_FORMAT_NETCDF4 = 3
132 NC_FORMAT_NETCDF4_CLASSIC = 4
133
134
135 NC_SIZEHINT_DEFAULT = 0
136
137
138 NC_ALIGN_CHUNK = -1
139
140
141 NC_UNLIMITED = 0
142
143
144 NC_GLOBAL = -1
145
146
147 NC_MAX_DIMS = 1024
148 NC_MAX_ATTRS = 8192
149 NC_MAX_VARS = 8192
150 NC_MAX_NAME = 256
151 NC_MAX_VAR_DIMS = NC_MAX_DIMS
152
153
154 NC_ENDIAN_NATIVE = 0
155 NC_ENDIAN_LITTLE = 1
156 NC_ENDIAN_BIG = 2
157
158 NC_CHUNKED = 0
159 NC_CONTIGUOUS = 1
160
161 NC_NOCHECKSUM = 0
162 NC_FLETCHER32 = 1
163
164 NC_NOSHUFFLE = 0
165 NC_SHUFFLE = 1
166
167
168 NC_NOERR = 0
169
170 NC2_ERR = -1
171 NC_EBADID = -33
172 NC_ENFILE = -34
173 NC_EEXIST = -35
174 NC_EINVAL = -36
175 NC_EPERM = -37
176 NC_ENOTINDEFINE = -38
177 NC_EINDEFINE = -39
178 NC_EINVALCOORDS = -40
179 NC_EMAXDIMS = -41
180 NC_ENAMEINUSE = -42
181 NC_ENOTATT = -43
182 NC_EMAXATTS = -44
183 NC_EBADTYPE = -45
184 NC_EBADDIM = -46
185 NC_EUNLIMPOS = -47
186 NC_EMAXVARS = -48
187 NC_ENOTVAR = -49
188 NC_EGLOBAL = -50
189 NC_ENOTNC = -51
190 NC_ESTS = -52
191 NC_EMAXNAME = -53
192 NC_EUNLIMIT = -54
193 NC_ENORECVARS = -55
194 NC_ECHAR = -56
195 NC_EEDGE = -57
196 NC_ESTRIDE = -58
197 NC_EBADNAME = -59
198
199
200
201 NC_ERANGE = -60
202 NC_ENOMEM = -61
203 NC_EVARSIZE = -62
204
205 NC_EDIMSIZE = -63
206 NC_ETRUNC = -64
207 NC_EAXISTYPE = -65
208
209
210 NC_EDAP = -66
211 NC_ECURL = -67
212 NC_EIO = -68
213 NC_ENODATA = -69
214 NC_EDAPSVC = -70
215 NC_EDAS = -71
216 NC_EDDS = -72
217 NC_EDATADDS = -73
218 NC_EDAPURL = -74
219 NC_EDAPCONSTRAINT = -75
220
221
222
223 NC4_FIRST_ERROR = -100
224 NC_EHDFERR = -101
225 NC_ECANTREAD = -102
226 NC_ECANTWRITE = -103
227 NC_ECANTCREATE = -104
228 NC_EFILEMETA = -105
229 NC_EDIMMETA = -106
230 NC_EATTMETA = -107
231 NC_EVARMETA = -108
232 NC_ENOCOMPOUND = -109
233 NC_EATTEXISTS = -110
234 NC_ENOTNC4 = -111
235 NC_ESTRICTNC3 = -112
236
237 NC_ENOTNC3 = -113
238 NC_ENOPAR = -114
239
240 NC_EPARINIT = -115
241 NC_EBADGRPID = -116
242 NC_EBADTYPID = -117
243 NC_ETYPDEFINED = -118
244
245 NC_EBADFIELD = -119
246 NC_EBADCLASS = -120
247 NC_EMAPTYPE = -121
248 NC_ELATEFILL = -122
249
250 NC_ELATEDEF = -123
251
252 NC_EDIMSCALE = -124
253 NC_ENOGRP = -125
254 NC_ESTORAGE = -126
255 NC_EBADCHUNK = -127
256 NC_ENOTBUILT = -128
257
258 NC4_LAST_ERROR = -128
259
260 - def __init__(self, path=None, omode=None, libname='libnetcdf.so'):
261 """
262 @keyword path: the file to open.
263 @type path: str
264 @keyword omode: opening mode.
265 @type omode: int
266 """
267 from ctypes import c_char_p
268 self.lib = get_lib(libname)
269 self.ncid = None
270
271 self.nc_strerror.restype = c_char_p
272 self.nc_inq_libvers.restype = c_char_p
273
274 if path is not None:
275 self.open_file(path, omode)
277 if key.startswith('nc_'):
278 return getattr(self.lib, key)
279
281 """
282 Open a NetCDF file.
283
284 @keyword path: the file to open.
285 @type path: str
286 @keyword omode: opening mode.
287 @type omode: int
288 @return: ncid
289 @rtype: int
290 """
291 from ctypes import c_int, byref
292 omode = self.NC_NOWRITE if omode is None else omode
293 if self.ncid is not None:
294 raise IOError('ncid %d has been opened'%self.ncid)
295 ncid = c_int()
296 retval = self.nc_open(path, omode, byref(ncid))
297 if retval != self.NC_NOERR:
298 raise IOError(self.nc_strerror(retval))
299 self.ncid = ncid.value
300 return self.ncid
302 """
303 Close the associated NetCDF file.
304
305 @return: nothing
306 """
307 retval = self.nc_close(self.ncid)
308 if retval != self.NC_NOERR:
309 raise IOError(self.nc_strerror(retval))
310 self.ncid = None
311
313 """
314 Get the dimension of the given name.
315
316 @param name: the name of the dimension.
317 @type name: str
318 @return: the dimension (length).
319 @rtype: int
320 """
321 from ctypes import c_int, c_long, byref
322 dimid = c_int()
323 length = c_long()
324 retval = self.nc_inq_dimid(self.ncid, name, byref(dimid))
325 if retval != self.NC_NOERR:
326 raise IOError(self.nc_strerror(retval))
327 retval = self.nc_inq_dimlen(self.ncid, dimid, byref(length))
328 if retval != self.NC_NOERR:
329 raise IOError(self.nc_strerror(retval))
330 return length.value
331
333 """
334 Load ndarray from netCDF file.
335
336 @param name: the data to be loaded.
337 @type name: str
338 @param shape: the shape of ndarray.
339 @type shape: tuple
340 @param dtype: the dtype of ndarray.
341 @type dtype: str
342 @return: the loaded ndarray.
343 @rtype: numpy.ndarray
344 """
345 from ctypes import POINTER, c_int, c_float, c_double, byref
346 from numpy import empty
347
348 varid = c_int()
349 retval = self.nc_inq_varid(self.ncid, name, byref(varid))
350 if retval != self.NC_NOERR:
351 raise IOError(self.nc_strerror(retval))
352
353 arr = empty(shape, dtype=dtype)
354 if dtype == 'int32':
355 func = self.nc_get_var_int
356 elif dtype == 'float32':
357 func = self.nc_get_var_float
358 elif dtype == 'float64':
359 func = self.nc_get_var_double
360 else:
361 raise TypeError('now surrport only int, float, double, and char')
362
363 retval = func(self.ncid, varid, arr.ctypes._as_parameter_)
364 if retval != self.NC_NOERR:
365 raise IOError(self.nc_strerror(retval))
366 return arr
367
369 """
370 Load string from netCDF file.
371
372 @param name: the data to be loaded.
373 @type name: str
374 @param shape: the shape of ndarray. Must be 1 or 2.
375 @type shape: tuple
376 @return: the loaded ndarray.
377 @rtype: numpy.ndarray
378 """
379 from ctypes import POINTER, c_int, c_char, byref
380 from numpy import empty
381 if len(shape) > 2:
382 raise IndexError('array should have no more than two dimension')
383
384 varid = c_int()
385 retval = self.nc_inq_varid(self.ncid, name, byref(varid))
386 if retval != self.NC_NOERR:
387 raise IOError(self.nc_strerror(retval))
388
389 arr = empty(shape, dtype='byte')
390
391 retval = self.nc_get_var_text(self.ncid, varid,
392 arr.ctypes._as_parameter_)
393 if retval != self.NC_NOERR:
394 raise IOError(self.nc_strerror(retval))
395
396 shape = (1, shape[0]) if len(shape) < 2 else shape
397 arr = arr.reshape(shape)
398 lines = []
399 for ii in range(shape[0]):
400 for ij in range(shape[1]):
401 if arr[ii,ij] == 0:
402 lines.append(arr[ii,:ij].tostring())
403 break
404 if len(lines) <= ii:
405 lines.append(arr[ii,:].tostring())
406 return lines
407