source: CCCC/trunk/ceda_cc/file_utils.py @ 549

Subversion URL: http://proj.badc.rl.ac.uk/svn/exarch/CCCC/trunk/ceda_cc/file_utils.py
Revision 549, 12.2 KB checked in by mjuckes, 4 years ago (diff)

bud associated with cdms2 treatment of absent missing_value fixed

Line 
1
2# Standard library imports
3import string, pkgutil
4
5from xceptions import *
6
7# Third party imports
8
9#### netcdf --- currently support cdms2, python-netCDF4 and Scientific
10
11l = pkgutil.iter_modules()
12ll = map( lambda x: x[1], l )
13
14supportedNetcdf = ['cdms2','netCDF4','Scientific','ncq3']
15
16installedSupportedNetcdf = []
17##ll = []
18
19for x in supportedNetcdf:
20  if x in ll:
21    if len(installedSupportedNetcdf) == 0:
22      try: 
23        cmd = 'import %s' % x
24        exec cmd
25        installedSupportedNetcdf.append( x )
26      except:
27        print 'Failed to install %s' % x
28    else:
29      installedSupportedNetcdf.append( x )
30
31if len(installedSupportedNetcdf) > 0:
32  ncLib = installedSupportedNetcdf[0]
33else:
34  print """No supported netcdf module found.
35         Supported modules are %s.
36         Attempting to run with experimental ncq3
37         Execution may fail, depending on options chosen.
38         """ % str(supportedNetcdf)
39  ncLib = 'ncq3'
40
41if ncLib == 'Scientific':
42  from Scientific.IO import NetCDF as ncdf
43
44## end of netcdf import.
45
46## utility function to convert "type" to string and standardise terminology
47def tstr( x ):
48  x1 = str(x)
49  return {'real':'float32', 'integer':'int32', 'float':'float32', 'double':'float64' }.get( x1, x1 )
50
51class fileMetadata(object):
52
53  def __init__(self,dummy=False,attributeMappingsLog=None,forceLib=None):
54     
55    self.dummy = dummy
56    self.atMapLog = attributeMappingsLog
57    self.forceLib = forceLib
58    self.ncLib = ncLib
59    if self.atMapLog == None:
60       self.atMapLog = open( 'cccc_atMapLog.txt', 'a' )
61
62    if self.forceLib == 'ncq3':
63      import ncq3
64      self.ncq3 = ncq3
65      self.ncLib = 'ncq3'
66    elif self.forceLib == 'cdms2':
67      import cdms2
68      self.cdms2 = cdms2
69      self.ncLib = 'cdms2'
70    elif self.forceLib == 'netCDF4':
71      import netCDF4
72      self.netCDF4 = netCDF4
73      self.ncLib = 'netCDF4 [%s]' % netCDF4.__version__
74    elif self.forceLib == 'Scientific':
75      import Scientific
76      from Scientific.IO import NetCDF as ncdf
77      self.ncdf = ncdf
78      self.ncLib = 'Scientific [%s]' % Scientific.__version__
79    else:
80      self.ncLib = ncLib
81
82  def close(self):
83    self.atMapLog.close()
84
85  def loadNc(self,fpath):
86    self.fpath = fpath
87    self.fn = string.split( fpath, '/' )[-1]
88    self.fparts = string.split( self.fn[:-3], '_' )
89    self.ga = {}
90    self.va = {}
91    self.da = {}
92    if self.dummy:
93      self.makeDummyFileImage()
94      return
95    elif self.ncLib == 'cdms2':
96      import cdms2
97      self.cdms2 = cdms2
98      self.loadNc__Cdms(fpath)
99    elif self.ncLib[:7] == 'netCDF4':
100      import netCDF4
101      self.netCDF4 = netCDF4
102      self.loadNc__Netcdf4(fpath)
103    elif self.ncLib[:10] == 'Scientific':
104      from Scientific.IO import NetCDF as ncdf
105      self.ncdf = ncdf
106      self.loadNc__Scientific(fpath)
107    else:
108      import ncq3
109      self.ncq3 = ncq3
110      self.loadNc__ncq(fpath)
111      ##raise baseException( 'No supported netcdf module assigned' )
112
113  def loadNc__ncq(self,fpath):
114    self.nc0 = self.ncq3.open( fpath )
115    self.nc0.getDigest()
116    self.ncq3.close( self.nc0 )
117    self.nc = self.ncq3.Browse( self.nc0.digest )
118    for a in self.nc._gal:
119       self.ga[a.name] = a.value
120    for v in self.nc._vdict.keys():
121      thisv = self.nc._vdict[v][0]
122      if v not in self.nc._ddict.keys():
123        self.va[v] = {}
124        for a in self.nc._ll[thisv.id]:
125          self.va[v][a.name] = a.value
126        self.va[v]['_type'] = tstr( thisv.type )
127        if v in ['plev','plev_bnds','height']:
128          x = thisv.data
129          if type(x) != type([]):
130            x = [x]
131          self.va[v]['_data'] = x
132      else:
133        self.da[v] = {}
134        thisa = self.nc._ddict[v]
135        for a in self.nc._ll[thisv.id]:
136          self.da[v][a.name] = a.value
137        self.da[v]['_type'] = tstr( thisv.type )
138        self.da[v]['_data'] = thisv.data
139   
140  def loadNc__Cdms(self,fpath):
141    self.nc = self.cdms2.open( fpath )
142    for k in self.nc.attributes.keys():
143      self.ga[k] = self.nc.attributes[k]
144      if len( self.ga[k] ) == 1:
145        self.ga[k] = self.ga[k][0]
146## nasty fix to deal with fact that cdms2 does not read the 'id' global attribute
147    try:
148      thisid = self.nc.id
149      self.ga['id'] = thisid
150    except:
151      pass
152    for v in self.nc.variables.keys():
153      self.va[v] = {}
154      for k in self.nc.variables[v].attributes.keys():
155        x = self.nc.variables[v].attributes[k]
156     ## returns a list for some scalar attributes.
157        if type(x) == type([]) and len(x) == 1:
158          x = x[0]
159        self.va[v][k] = x
160      self.va[v]['_type'] = tstr( self.nc.variables[v].dtype )
161      if v in ['plev','plev_bnds','height']:
162        x = self.nc.variables[v].getValue().tolist()
163        if type(x) != type([]):
164          x = [x]
165        self.va[v]['_data'] = x
166        ### Note: returns a scalar if data has a scalar value.
167## remove missing_value == None
168      if self.va[v].has_key( 'missing_value' ) and self.va[v]['missing_value'] == None:
169        self.va[v].pop( 'missing_value' )
170
171    for v in self.nc.axes.keys():
172      self.da[v] = {}
173      for k in self.nc.axes[v].attributes.keys():
174        self.da[v][k] = self.nc.axes[v].attributes[k]
175      self.da[v]['_type'] = tstr( self.nc.axes[v].getValue().dtype )
176      self.da[v]['_data'] = self.nc.axes[v].getValue().tolist()
177     
178    self.nc.close()
179
180###
181### attributes in .__dict__ dictionary
182### variables in .variables dicttionary
183### dimension lengths in .dimensions
184### <variable>.getValue() returns an numpy.ndarray
185### data type in <variable>.getValue().dtype
186### for scalar variables, <variable>.getValue().tolist() returns a scalar.
187###
188  def loadNc__Scientific(self,fpath):
189    self.nc = self.ncdf.NetCDFFile( fpath, 'r' )
190    for k in self.nc.__dict__.keys():
191      self.ga[k] = self.nc.__dict__[k]
192      if type(self.ga[k]) not in [type('x'),type(1),type(1.)] and len(self.ga[k]) == 1:
193        self.ga[k] = self.ga[k][0]
194    for v in self.nc.variables.keys():
195      if v not in self.nc.dimensions.keys():
196        self.va[v] = {}
197        for k in self.nc.variables[v].__dict__.keys():
198          self.va[v][k] = self.nc.variables[v].__dict__[k]
199        self.va[v]['_type'] = tstr( self.nc.variables[v].getValue().dtype )
200        if v in ['plev','plev_bnds','height']:
201        ### Note: returns a scalar if data has a scalar value.
202          x = self.nc.variables[v].getValue().tolist()
203          if type(x) != type([]):
204            x = [x]
205          self.va[v]['_data'] = x
206
207    for v in self.nc.dimensions.keys():
208      self.da[v] = {}
209      if v in self.nc.variables.keys():
210        for k in self.nc.variables[v].__dict__.keys():
211          self.da[v][k] = self.nc.variables[v].__dict__[k]
212        self.da[v]['_type'] = tstr( self.nc.variables[v].getValue().dtype )
213        self.da[v]['_data'] = self.nc.variables[v].getValue().tolist()
214      else:
215        self.da[v]['_type'] = 'index (no data variable)'
216     
217    self.nc.close()
218
219  def loadNc__Netcdf4(self,fpath):
220    self.nc = self.netCDF4.Dataset(fpath, 'r')
221    for k in self.nc.ncattrs():
222      self.ga[k] = self.nc.getncattr(k)
223      if type( self.ga[k] ) in [ type([]),type(()) ]:
224        if len( self.ga[k] ) == 1:
225          self.ga[k] = self.ga[k][0]
226    for v in self.nc.variables.keys():
227      if v not in self.nc.dimensions.keys():
228        self.va[v] = {}
229        for k in self.nc.variables[v].ncattrs():
230          self.va[v][k] = self.nc.variables[v].getncattr(k)
231        try:
232          self.va[v]['_type'] = tstr( self.nc.variables[v].dtype )
233        except:
234          self.va[v]['_type'] = tstr( self.nc.variables[v].datatype )
235        if v in ['plev','plev_bnds','height']:
236          self.va[v]['_data'] = self.nc.variables[v][:].tolist()
237          if type( self.va[v]['_data'] ) != type( [] ):
238            self.va[v]['_data'] = [self.va[v]['_data'],]
239
240    for v in self.nc.dimensions.keys():
241      self.da[v] = {}
242      if v in self.nc.variables.keys():
243        for k in self.nc.variables[v].ncattrs():
244          self.da[v][k] = self.nc.variables[v].getncattr(k)
245        try:
246          self.da[v]['_type'] = tstr( self.nc.variables[v].dtype )
247        except:
248          self.da[v]['_type'] = tstr( self.nc.variables[v].datatype )
249
250        self.da[v]['_data'] = self.nc.variables[v][:].tolist()
251        if type( self.da[v]['_data'] ) != type( [] ):
252            self.da[v]['_data'] = [self.da[v]['_data'],]
253      else:
254        self.da[v]['_type'] = 'index (no data variable)'
255     
256    self.nc.close()
257
258  def makeDummyFileImage(self):
259    for k in range(10):
260      self.ga['ga%s' % k] =  str(k)
261    for v in [self.fparts[0],]:
262      self.va[v] = {}
263      self.va[v]['standard_name'] = 's%s' % v
264      self.va[v]['long_name'] = v
265      self.va[v]['cell_methods'] = 'time: point'
266      self.va[v]['units'] = '1'
267      self.va[v]['_type'] = 'float32'
268
269    for v in ['lat','lon','time']:
270      self.da[v] = {}
271      self.da[v]['_type'] = 'float64'
272      self.da[v]['_data'] = range(5)
273    dlist = ['lat','lon','time']
274    svals = lambda p,q: map( lambda y,z: self.da[y].__setitem__(p, z), dlist, q )
275    svals( 'standard_name', ['latitude', 'longitude','time'] )
276    svals( 'long_name', ['latitude', 'longitude','time'] )
277    svals( 'units', ['degrees_north', 'degrees_east','days since 19590101'] )
278
279  def applyMap( self, mapList, globalAttributesInFn, log=None ):
280    for m in mapList:
281      if m[0] == 'am001':
282        if m[1][0][0] == "@var":
283          if m[1][0][1] in self.va.keys():
284            this = self.va[m[1][0][1]]
285            apThis = True
286            for c in m[1][1:]:
287              if c[0] not in this.keys():
288                apThis = False
289              elif c[1] != this[c[0]]:
290                apThis = False
291            if m[2][0] != '':
292              targ = m[2][0]
293            else:
294              targ = m[1][-1][0]
295            if apThis:
296              if log != None:
297                log.info( 'Setting %s to %s' % (targ,m[2][1]) )
298              ##print 'Setting %s:%s to %s' % (m[1][0][1],targ,m[2][1])
299              thisval = self.va[m[1][0][1]].get( targ, None )
300              self.va[m[1][0][1]][targ] = m[2][1]
301              self.atMapLog.write( '@var:"%s","%s","%s","%s","%s"\n' % (self.fpath, m[1][0][1], targ, thisval, m[2][1] ) )
302
303        elif m[1][0][0] == "@ax":
304          ##print 'checking dimension ',m[1][0][1], self.da.keys()
305          if m[1][0][1] in self.da.keys():
306            ##print 'checking dimension [2]',m[1][0][1]
307            this = self.da[m[1][0][1]]
308            apThis = True
309            for c in m[1][1:]:
310              if c[0] not in this.keys():
311                apThis = False
312              elif c[1] != this[c[0]]:
313                apThis = False
314            if m[2][0] != '':
315              targ = m[2][0]
316            else:
317              targ = m[1][-1][0]
318            if apThis:
319              if log != None:
320                log.info( 'Setting %s to %s' % (targ,m[2][1]) )
321              ##print 'Setting %s:%s to %s' % (m[1][0][1],targ,m[2][1])
322              thisval = self.da[m[1][0][1]].get( targ, None )
323              self.da[m[1][0][1]][targ] = m[2][1]
324              self.atMapLog.write( '@ax:"%s","%s","%s","%s","%s"\n' % (self.fpath, m[1][0][1], targ, thisval, m[2][1]) )
325        elif m[1][0][0] == "@":
326            this = self.ga
327            apThis = True
328## apply change where attribute absent only
329            for c in m[1][1:]:
330              if c[0] not in this.keys():
331                if c[1] != '__absent__':
332                  apThis = False
333              elif c[1] == '__absent__' or c[1] != this[c[0]]:
334                apThis = False
335            if m[2][0] != '':
336              targ = m[2][0]
337            else:
338              targ = m[1][-1][0]
339            if apThis:
340              if log != None:
341                log.info( 'Setting %s to %s' % (targ,m[2][1]) )
342              ##print 'Setting %s to %s' % (targ,m[2][1])
343              thisval = self.ga.get( targ, None )
344              self.ga[targ] = m[2][1]
345              self.atMapLog.write( '@:"%s","%s","%s","%s","%s"\n' % (self.fpath, 'ga', targ, thisval, m[2][1]) )
346##
347              if targ in globalAttributesInFn:
348                i = globalAttributesInFn.index(targ)
349                thisval = self.fparts[ i ]
350                self.fparts[ i ] = m[2][1]
351                self.fn = string.join( self.fparts, '_' ) + '.nc'
352                self.atMapLog.write( '@fn:"%s","%s","%s"\n' % (self.fpath, thisval, m[2][1]) )
353        else:
354          print 'Token %s not recognised' % m[1][0][0]
Note: See TracBrowser for help on using the repository browser.