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

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

tidied up ncq3 and associated unit test; added force-<nclib> options; debugged Scientific and python netCDF4 support

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