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

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

added esa-cci 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    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
168    for v in self.nc.axes.keys():
169      self.da[v] = {}
170      for k in self.nc.axes[v].attributes.keys():
171        self.da[v][k] = self.nc.axes[v].attributes[k]
172      self.da[v]['_type'] = tstr( self.nc.axes[v].getValue().dtype )
173      self.da[v]['_data'] = self.nc.axes[v].getValue().tolist()
174     
175    self.nc.close()
176
177###
178### attributes in .__dict__ dictionary
179### variables in .variables dicttionary
180### dimension lengths in .dimensions
181### <variable>.getValue() returns an numpy.ndarray
182### data type in <variable>.getValue().dtype
183### for scalar variables, <variable>.getValue().tolist() returns a scalar.
184###
185  def loadNc__Scientific(self,fpath):
186    self.nc = self.ncdf.NetCDFFile( fpath, 'r' )
187    for k in self.nc.__dict__.keys():
188      self.ga[k] = self.nc.__dict__[k]
189      if type(self.ga[k]) not in [type('x'),type(1),type(1.)] and len(self.ga[k]) == 1:
190        self.ga[k] = self.ga[k][0]
191    for v in self.nc.variables.keys():
192      if v not in self.nc.dimensions.keys():
193        self.va[v] = {}
194        for k in self.nc.variables[v].__dict__.keys():
195          self.va[v][k] = self.nc.variables[v].__dict__[k]
196        self.va[v]['_type'] = tstr( self.nc.variables[v].getValue().dtype )
197        if v in ['plev','plev_bnds','height']:
198        ### Note: returns a scalar if data has a scalar value.
199          x = self.nc.variables[v].getValue().tolist()
200          if type(x) != type([]):
201            x = [x]
202          self.va[v]['_data'] = x
203
204    for v in self.nc.dimensions.keys():
205      self.da[v] = {}
206      if v in self.nc.variables.keys():
207        for k in self.nc.variables[v].__dict__.keys():
208          self.da[v][k] = self.nc.variables[v].__dict__[k]
209        self.da[v]['_type'] = tstr( self.nc.variables[v].getValue().dtype )
210        self.da[v]['_data'] = self.nc.variables[v].getValue().tolist()
211      else:
212        self.da[v]['_type'] = 'index (no data variable)'
213     
214    self.nc.close()
215
216  def loadNc__Netcdf4(self,fpath):
217    self.nc = self.netCDF4.Dataset(fpath, 'r')
218    for k in self.nc.ncattrs():
219      self.ga[k] = self.nc.getncattr(k)
220      if type( self.ga[k] ) in [ type([]),type(()) ]:
221        if len( self.ga[k] ) == 1:
222          self.ga[k] = self.ga[k][0]
223    for v in self.nc.variables.keys():
224      if v not in self.nc.dimensions.keys():
225        self.va[v] = {}
226        for k in self.nc.variables[v].ncattrs():
227          self.va[v][k] = self.nc.variables[v].getncattr(k)
228        try:
229          self.va[v]['_type'] = tstr( self.nc.variables[v].dtype )
230        except:
231          self.va[v]['_type'] = tstr( self.nc.variables[v].datatype )
232        if v in ['plev','plev_bnds','height']:
233          self.va[v]['_data'] = self.nc.variables[v][:].tolist()
234          if type( self.va[v]['_data'] ) != type( [] ):
235            self.va[v]['_data'] = [self.va[v]['_data'],]
236
237    for v in self.nc.dimensions.keys():
238      self.da[v] = {}
239      if v in self.nc.variables.keys():
240        for k in self.nc.variables[v].ncattrs():
241          self.da[v][k] = self.nc.variables[v].getncattr(k)
242        try:
243          self.da[v]['_type'] = tstr( self.nc.variables[v].dtype )
244        except:
245          self.da[v]['_type'] = tstr( self.nc.variables[v].datatype )
246
247        self.da[v]['_data'] = self.nc.variables[v][:].tolist()
248        if type( self.da[v]['_data'] ) != type( [] ):
249            self.da[v]['_data'] = [self.da[v]['_data'],]
250      else:
251        self.da[v]['_type'] = 'index (no data variable)'
252     
253    self.nc.close()
254
255  def makeDummyFileImage(self):
256    for k in range(10):
257      self.ga['ga%s' % k] =  str(k)
258    for v in [self.fparts[0],]:
259      self.va[v] = {}
260      self.va[v]['standard_name'] = 's%s' % v
261      self.va[v]['long_name'] = v
262      self.va[v]['cell_methods'] = 'time: point'
263      self.va[v]['units'] = '1'
264      self.va[v]['_type'] = 'float32'
265
266    for v in ['lat','lon','time']:
267      self.da[v] = {}
268      self.da[v]['_type'] = 'float64'
269      self.da[v]['_data'] = range(5)
270    dlist = ['lat','lon','time']
271    svals = lambda p,q: map( lambda y,z: self.da[y].__setitem__(p, z), dlist, q )
272    svals( 'standard_name', ['latitude', 'longitude','time'] )
273    svals( 'long_name', ['latitude', 'longitude','time'] )
274    svals( 'units', ['degrees_north', 'degrees_east','days since 19590101'] )
275
276  def applyMap( self, mapList, globalAttributesInFn, log=None ):
277    for m in mapList:
278      if m[0] == 'am001':
279        if m[1][0][0] == "@var":
280          if m[1][0][1] in self.va.keys():
281            this = self.va[m[1][0][1]]
282            apThis = True
283            for c in m[1][1:]:
284              if c[0] not in this.keys():
285                apThis = False
286              elif c[1] != this[c[0]]:
287                apThis = False
288            if m[2][0] != '':
289              targ = m[2][0]
290            else:
291              targ = m[1][-1][0]
292            if apThis:
293              if log != None:
294                log.info( 'Setting %s to %s' % (targ,m[2][1]) )
295              ##print 'Setting %s:%s to %s' % (m[1][0][1],targ,m[2][1])
296              thisval = self.va[m[1][0][1]].get( targ, None )
297              self.va[m[1][0][1]][targ] = m[2][1]
298              self.atMapLog.write( '@var:"%s","%s","%s","%s","%s"\n' % (self.fpath, m[1][0][1], targ, thisval, m[2][1] ) )
299
300        elif m[1][0][0] == "@ax":
301          ##print 'checking dimension ',m[1][0][1], self.da.keys()
302          if m[1][0][1] in self.da.keys():
303            ##print 'checking dimension [2]',m[1][0][1]
304            this = self.da[m[1][0][1]]
305            apThis = True
306            for c in m[1][1:]:
307              if c[0] not in this.keys():
308                apThis = False
309              elif c[1] != this[c[0]]:
310                apThis = False
311            if m[2][0] != '':
312              targ = m[2][0]
313            else:
314              targ = m[1][-1][0]
315            if apThis:
316              if log != None:
317                log.info( 'Setting %s to %s' % (targ,m[2][1]) )
318              ##print 'Setting %s:%s to %s' % (m[1][0][1],targ,m[2][1])
319              thisval = self.da[m[1][0][1]].get( targ, None )
320              self.da[m[1][0][1]][targ] = m[2][1]
321              self.atMapLog.write( '@ax:"%s","%s","%s","%s","%s"\n' % (self.fpath, m[1][0][1], targ, thisval, m[2][1]) )
322        elif m[1][0][0] == "@":
323            this = self.ga
324            apThis = True
325## apply change where attribute absent only
326            for c in m[1][1:]:
327              if c[0] not in this.keys():
328                if c[1] != '__absent__':
329                  apThis = False
330              elif c[1] == '__absent__' or c[1] != this[c[0]]:
331                apThis = False
332            if m[2][0] != '':
333              targ = m[2][0]
334            else:
335              targ = m[1][-1][0]
336            if apThis:
337              if log != None:
338                log.info( 'Setting %s to %s' % (targ,m[2][1]) )
339              ##print 'Setting %s to %s' % (targ,m[2][1])
340              thisval = self.ga.get( targ, None )
341              self.ga[targ] = m[2][1]
342              self.atMapLog.write( '@:"%s","%s","%s","%s","%s"\n' % (self.fpath, 'ga', targ, thisval, m[2][1]) )
343##
344              if targ in globalAttributesInFn:
345                i = globalAttributesInFn.index(targ)
346                thisval = self.fparts[ i ]
347                self.fparts[ i ] = m[2][1]
348                self.fn = string.join( self.fparts, '_' ) + '.nc'
349                self.atMapLog.write( '@fn:"%s","%s","%s"\n' % (self.fpath, thisval, m[2][1]) )
350        else:
351          print 'Token %s not recognised' % m[1][0][0]
Note: See TracBrowser for help on using the repository browser.