source: CCCC/trunk/ceda_cc/extractMipInfo.py @ 232

Subversion URL: http://proj.badc.rl.ac.uk/svn/exarch/CCCC/trunk/ceda_cc/extractMipInfo.py@232
Revision 232, 17.8 KB checked in by mjuckes, 5 years ago (diff)

bug in CCMI mip table file name pattern

Line 
1
2import collections, glob, string, re, json
3from fcc_utils2 import mipTableScan, snlist, tupsort
4from config_c4 import CC_CONFIG_DIR
5
6def uniquify( ll ):
7  ll.sort()
8  l0 = [ll[0],]
9  for l in ll[1:]:
10    if l != l0[-1]:
11      l0.append(l)
12  return l0
13 
14
15ms = mipTableScan()
16snc = snlist()
17
18snl, snla = snc.gen_sn_list( )
19NT_mip = collections.namedtuple( 'mip',['label','dir','pattern'] )
20NT_canvari = collections.namedtuple( 'canonicalVariation',['conditions','text', 'ref'] )
21vlist = [
22('uas',
23"eastward_wind",
24'Eastward Near-Surface Wind Speed',
25'Eastward Near-Surface Wind',
26'WRONG LONG NAME (*speed* included)'),
27('vas',
28"northward_wind",
29'Northward Near-Surface Wind Speed',
30'Northward Near-Surface Wind',
31'WRONG LONG NAME (*speed* included)'),
32("snc",
33"surface_snow_area_fraction",
34"Snow Area Fraction",
35"Surface Snow Area Fraction",
36"WRONG LONG NAME (*surface* omitted)"),
37("prsn",
38"snowfall_flux", 
39"Solid Precipitation",
40"Snowfall Flux",
41"WRONG LONG NAME"),
42("tntscpbl",
43"tendency_of_air_temperature_due_to_stratiform_cloud_and_precipitation_and_boundary_layer_mixing",
44"Tendency of Air Temperature due to Stratiform Cloud Condensation and Evaporation",
45"Tendency of Air Temperature Due to Stratiform Cloud and Precipitation and Boundary Layer Mixing",
46'WRONG LONG NAME'),
47("tas",
48"air_temperature",
49"Air Temperature",
50"Near-Surface Air Temperature",
51'WRONG LONG NAME'),
52("cfadDbze94",
53"histogram_of_equivalent_reflectivity_factor_over_height_above_reference_ellipsoid",
54"CloudSat Radar Reflectivity CFAD",
55"CloudSat Radar Reflectivity",
56"INCONSISTENT LONG NAME"),
57("cfadLidarsr532",
58"histogram_of_backscattering_ratio_over_height_above_reference_ellipsoid",
59"CALIPSO Scattering Ratio CFAD",
60"CALIPSO Scattering Ratio",
61"INCONSISTENT LONG NAME"),
62("cl",
63"cloud_area_fraction_in_atmosphere_layer",
64"Cloud Area Fraction",
65"Cloud Area Fraction in Atmosphere Layer",
66"INCONSISTENT LONG NAME"),
67("clcalipso",
68"cloud_area_fraction_in_atmosphere_layer",
69"CALIPSO Cloud Fraction",
70"CALIPSO Cloud Area Fraction",
71'WRONG LONG NAME'),
72("cltisccp",
73"cloud_area_fraction",
74"ISCCP Total Total Cloud Fraction",
75"ISCCP Total Cloud Fraction",
76'WRONG LONG NAME'),
77("reffclwc",
78"effective_radius_of_convective_cloud_liquid_water_particle",
79"Convective Cloud Droplet Effective Radius",
80"Hydrometeor Effective Radius of Convective Cloud Liquid Water",
81'INCONSISTENT LONG NAMES'),
82("reffclws",
83"effective_radius_of_stratiform_cloud_liquid_water_particle",
84'Stratiform Cloud Droplet Effective Radius',
85'Hydrometeor Effective Radius of Stratiform Cloud Liquid Water',
86'INCONSISTENT LONG NAMES' ) ]
87
88
89class helper:
90
91  def __init__(self):
92    self.applycv = True
93    self.re1 = re.compile( '"(.*)"=="(.*)"' )
94
95    self.cmip5Tables= ['CMIP5_3hr', 'CMIP5_6hrPlev', 'CMIP5_Amon', 'CMIP5_cfDay', 'CMIP5_cfOff', 'CMIP5_day', 'CMIP5_grids', 'CMIP5_Lmon', 'CMIP5_OImon', 'CMIP5_Oyr',
96  'CMIP5_6hrLev', 'CMIP5_aero', ' CMIP5_cf3hr', 'CMIP5_cfMon', 'CMIP5_cfSites', 'CMIP5_fx', 'CMIP5_LImon', 'CMIP5_Oclim', 'CMIP5_Omon' ]
97    self.cmip5DefPoint = ['CMIP5_3hr', 'CMIP5_6hrPlev', 'CMIP5_cfOff', 'CMIP5_6hrLev', ' CMIP5_cf3hr', 'CMIP5_cfSites' ]
98
99    self.canonvar = [ NT_canvari( (('table','CMIP5_3hr'),), 'This is sampled synoptically.', '' ),
100                      NT_canvari( (), 'The flux is computed as the mass divided by the area of the grid cell.', 'This is calculated as the convective mass flux divided by the area of the whole grid cell (not just the area of the cloud).' ),
101            ]
102
103    self.canonvar = []
104    for l in open( 'canonicalVariations.txt' ).readlines():
105      if l[0] != '#':
106        ix = l.index(':')
107        s = string.strip( l[ix:] )
108        r = self.re1.findall( s )
109        assert len(r) == 1, 'Cannot parse: %s' % s
110        self.canonvar.append( NT_canvari( (), r[0][0], r[0][1] ) )
111
112  def match(self,a,b):
113      if type(a) == type( 'X' ) and type(b) == type( 'X' ):
114        a0,b0 = map( lambda x: string.replace(x, '__ABSENT__',''), [a,b] )
115        return string.strip( string.replace(a0, '  ', ' '), '"') == string.strip( string.replace(b0, '  ', ' '), '"')
116      else:
117        return a == b
118
119  def checkCond( self, table, var, conditions ):
120    val = True
121    for ck, cv in conditions:
122      if ck == 'table':
123        val &= table == cv
124      elif ck == 'var':
125        val &= var == cv
126
127    return val
128       
129     
130
131class snsub:
132
133  def __init__(self):
134    pass
135
136  def isFalseSn(self,var,sn):
137    if sn == 'mole_concentration_of_molecular_oxygen_in_sea_water':
138      return (True,'mole_concentration_of_dissolved_molecular_oxygen_in_sea_water', 'INVALID STANDARD NAME')
139    elif var == 'rldscs' and sn == 'downwelling_longwave_flux_in_air_assuming_clear_sky':
140      return (True,'surface_downwelling_longwave_flux_in_air_assuming_clear_sky','WRONG STANDARD NAME (should be surface)' )
141    elif var == 'clisccp' and sn == 'cloud_area_fraction_in_atmosphere_layer':
142      return (True, 'isccp_cloud_area_fraction', 'WRONG STANDARD NAME (should be isccp)' )
143    return (False,'no match','')
144
145  def isFalseLn(self,var,ln):
146    for tt in vlist:
147       if var == tt[0] and ln == tt[2]:
148         return (True, tt[3], tt[4] )
149    return (False,'no match','')
150
151snsubber = snsub()
152
153
154cmip5_ignore = ['pfull','phalf','depth','depth_c','eta','nsigma','vertices_latitude','vertices_longitude','ztop','ptop','p0','z1','z2','href','k_c','a','a_bnds','ap','ap_bnds','b','b_bnds','sigma','sigma_bnds','zlev','zlev_bnds','zfull','zhalf']
155
156class mipCo:
157
158  def __init__(self,mips,helper=None):
159    self.vl0 = []
160    self.tl = []
161    self.td = {}
162    self.helper = helper
163    for mip in mips:
164      self._scan(mip)
165
166  def _scan(self,mip):
167   
168 ## dl = glob.glob( '%s%s' % (mip.dir,mip.pattern) )
169    dl = glob.glob( '%s/%s%s' % (CC_CONFIG_DIR, mip.dir,mip.pattern) )
170    dl.sort()
171    for d in dl:
172      tab = string.split( d, '/')[-1]
173      isoceanic = tab[:7] == "CMIP5_O"
174      l2 = ms.scan_table( open( d ).readlines(), None, asDict=True, lax=True, tag="x", warn=True)
175      l2k = []
176      for k in l2.keys():
177        if k not in cmip5_ignore:
178          l2k.append(k)
179      l2k.sort()
180      self.vl0 += l2k
181      self.tl.append( [tab,l2, l2k,isoceanic] )
182      self.td[tab] = l2
183
184    self.vl0.sort()
185    self.vl = []
186    self.vl.append( self.vl0[0] )
187    self.vdict = { self.vl[0]:[] }
188    for v in self.vl0[1:]:
189      if v != self.vl[-1]:
190        self.vl.append(v)
191        self.vdict[v] = []
192
193    for t in self.tl:
194      for k in t[2]:
195        self.vdict[k].append(t[0])
196
197    self.vars = self.vdict.keys()
198    self.vars.sort()
199    ##for v in self.vars:
200      ##l = self.vdict[v]
201      ##l.sort()
202##  print v, l, td[l[0]][v][1].get('standard_name','__NO_STANDARD_NAME__')
203
204class runcheck1:
205  def __init__( self, m, thisatts):
206    vars = m.vars
207    vdict = m.vdict
208    td = m.td
209    vd2 = {}
210    for v in vars:
211     l = vdict[v]
212     l.sort()
213     if len(l) > 1:
214       for att in thisatts:
215       ##for att in ['standard_name','units']:
216         if att == '__dimensions__':
217           atl = map( lambda x: string.join( td[x][v][0] ), l )
218         else:
219           atl = map( lambda x: td[x][v][1].get(att,'__ABSENT__'), l )
220         atl.sort()
221         av = [atl[0],]
222         for a in atl[1:]:
223           if a != av[-1]:
224             av.append(a)
225         if att == 'standard_name':
226           for a in av:
227             if a not in snl and a not in snla:
228               print "INVALID STANDARD NAME: ",a
229         if len(av) > 1:
230           ee = {}
231   
232           for a in [True,False]:
233             ee[a] = []
234   
235           isol = []
236           for x in l:
237             a = td[x][v][1].get(att,'__ABSENT__')
238             try:
239              if att == 'standard_name' or ( att == 'long_name' and vd2[v][0] == 2):
240               iso = x[:7] == 'CMIP5_O'
241               tt = snsubber.isFalseSn( v, a )
242              elif att == 'long_name':
243               tt = snsubber.isFalseLn( v, a )
244               dims = td[x][v][0]
245               iso = 'depth0m' in dims
246              else:
247               iso = False
248               tt = (False,)
249         ##    iso = False
250             except:
251               print att,v
252               raise
253             isol.append((iso,x))
254             if tt[0]:
255               print 'Substituting ',v,a,tt
256               ee[iso].append( tt[1] )
257             else:
258               ee[iso].append( a )
259   
260           for a in [True,False]:
261             ok = True
262             if len(ee[a]) > 1 :
263               for x in ee[a][1:]:
264                 if x != ee[a][0]:
265                   ok = False
266   
267             if not ok:
268                print 'E001: Multiple values : ',att,v
269                for t in isol:
270                  if t[0] == a:
271                    tab = t[1]
272                    if att in ['standard_name','long_name']:
273                      print tab,td[tab][v][1].get('standard_name','__ABSENT__'),td[tab][v][1].get('long_name','__ABSENT__')
274                    else:
275                      print tab,td[tab][v][1].get(att,'__ABSENT__')
276                   
277           if att == "standard_name":
278             vd2[v] = (2,[ee[True],ee[False]] )
279         else:
280           if att == "standard_name":
281             tt = snsubber.isFalseSn( v, av[0] )
282             if tt[0]:
283               print 'Substituting ',v,av[0],tt
284               vd2[v] = (1, tt[1])
285             else:
286               vd2[v] = (1, av)
287     elif len(l) == 1:
288           tab = vdict[v][0]
289           a = td[tab][v][1].get('standard_name','__ABSENT__')
290           tt = snsubber.isFalseSn( v, a )
291           if tt[0]:
292             print 'Substituting ',v,a,tt
293             vd2[v] = (1, tt[1])
294           else:
295             vd2[v] = (1, a)
296           ##print 'MULTIPLE VALUES: ',v,att,av
297     else:
298      print 'Zero length element: %s' % v
299     
300   
301class typecheck1:
302  def __init__( self, m, thisatts,helper=None):
303    self.type2Atts = ['positive','comment', 'long_name', 'modeling_realm', 'out_name', 'standard_name', 'type', 'units', 'flag_meanings', 'flag_values']
304    self.type3Atts = ['positive','long_name','modeling_realm', 'out_name', 'standard_name', 'type', 'units', 'flag_meanings', 'flag_values']
305    self.type4Atts = ['positive','modeling_realm', 'out_name', 'standard_name', 'type', 'units', 'flag_meanings', 'flag_values']
306    self.type2Atts = ['positive','comment', 'long_name', 'modeling_realm', 'out_name', 'standard_name', 'type', 'units']
307    self.type3Atts = ['positive','long_name','modeling_realm', 'out_name', 'standard_name', 'type', 'units']
308    self.type4Atts = ['positive','modeling_realm', 'out_name', 'standard_name', 'type', 'units']
309    self.m = m
310    vars = m.vars
311    vdict = m.vdict
312    self.helper=helper
313    td = m.td
314    vd2 = {}
315    type1, type2, type3, type4, type5 = [[],[],[],[],[],] 
316    vd2 = {}
317    for v in vars:
318     l = vdict[v]
319     dl = map( lambda x: string.join( td[x][v][0] ), l )
320     vd2[v] = str( uniquify( dl ) )
321    json.dump( vd2, open( 'mipInfo.json', 'w' ) )
322    for v in vars:
323     l = vdict[v]
324     l.sort()
325     if len(l) == 1: 
326       type1.append(v)
327     elif len(l) > 1:
328       adict = {}
329       for att in thisatts:
330         if att == '__dimensions__':
331           atl = map( lambda x: (string.join( td[x][v][0] ),x), l )
332         else:
333           atl = map( lambda x: (td[x][v][1].get(att,'__ABSENT__'),x), l )
334         atl.sort( tupsort(0).cmp )
335         a0 = atl[0][0]
336         if a0 == None:
337           a0 = ""
338         av = [a0,]
339         for a,tab in atl[1:]:
340           if a == None:
341             a = ""
342           if a != av[-1]:
343             if self.helper != None and self.helper.applycv:
344               thisok=False
345               pmatch = False
346               for cond,src,targ in self.helper.canonvar:
347                 if string.find(a,src) != -1 or  string.find(av[-1],src) != -1:
348                   ##print 'Potential match ---- ',a
349                   ##print src,'###',targ
350                   ##print av[-1]
351                   pmatch = True
352                 if self.helper.checkCond( tab, v, cond ):
353                   if self.helper.match(string.replace( a, src, targ ), av[-1]) or self.helper.match(string.replace( av[-1], src, targ ), a):
354                     thisok = True
355               if thisok:
356                 print '############### conditional match found', tab, v
357               else:
358                 if pmatch:
359                   ##print '########### no matvh found'
360                   pass
361                 av.append(a)
362             else:
363               av.append(a)
364         adict[att] = av
365         if v == "snd":
366           print adict
367       
368## check for type 2
369       tval = None
370       ##if adict[ 'positive' ] == ['__ABSENT__']:
371       if all( map( lambda x: len(adict[x]) == 1, self.type2Atts )):
372           tval = 2
373       elif all( map( lambda x: len(adict[x]) == 1, self.type3Atts )):
374           tval = 3
375       elif all( map( lambda x: len(adict[x]) == 1, self.type4Atts )):
376           tval = 4
377       else:
378           l = map( lambda x: '%s:%s, ' % (x,len(adict[x]) ), self.type2Atts )
379           ## print '%s: t3:: ' % v,string.join(l)
380       if tval == 2:
381         type2.append( v)
382       elif tval == 3:
383         type3.append( v)
384       elif tval == 4:
385         type4.append( v)
386       else:
387         type5.append(v)
388    xx = float( len(vars) )
389    print string.join( map( lambda x: '%s (%5.1f%%);' % (x,x/xx*100), [len(type1), len(type2), len(type3), len(type4), len(type5)] ) )
390    self.type1 = type1
391    self.type2 = type2
392    self.type3 = type3
393    self.type4 = type4
394    self.type5 = type5
395
396  def exportHtml( self, typecode ):
397
398    allAtts = ['__dimensions__', 'cell_methods', 'comment', 'long_name', 'modeling_realm', 'out_name', 'standard_name', 'type', 'units', 'valid_max', 'valid_min', 'positive', 'ok_max_mean_abs', 'ok_min_mean_abs', 'flag_meanings', 'flag_values']
399    fixedType1Tmpl = """:%(standard_name)s [%(units)s]</h3>
400        %(__dimensions__)s<br/>
401        %(long_name)s<br/>
402       realm: %(modeling_realm)s; out_name: %(out_name)s; type: %(type)s, <br/>
403       cell_methods: %(cell_methods)s; comment: %(comment)s<br/>
404"""
405    fixedType2TmplA = """:%(standard_name)s [%(units)s]</h3>
406        %(long_name)s<br/>
407       realm: %(modeling_realm)s; out_name: %(out_name)s; type: %(type)s, <br/>
408       comment: %(comment)s<br/>
409"""
410    fixedType2TmplB = "<li>%s [%s]: %s -- (%s,%s,%s,%s)</li>\n"
411       
412    fixedType3TmplA = """:%(standard_name)s [%(units)s]</h3>
413       realm: %(modeling_realm)s; out_name: %(out_name)s; type: %(type)s <br/>
414"""
415    fixedType3TmplB = "<li>%s [%s]: %s: %s [%s]</li>\n"
416    fixedType4TmplB = "<li>%s [%s]: %s [%s]</li>\n"
417    fixedType5TmplA = """ [%(units)s]</h3>
418       out_name: %(out_name)s; type: %(type)s <br/>
419"""
420    fixedType5TmplB = "<li>%s [%s]: %s, %s [%s]: %s</li>\n"
421       
422    if typecode == 1:
423      oo = open( 'type1.html', 'w' )
424      self.type1.sort()
425      ee = {}
426      for v in self.type1:
427        tab = self.m.vdict[v][0]
428        if not ee.has_key(tab):
429          ee[tab] = []
430        ee[tab].append( v )
431      keys = ee.keys()
432      keys.sort()
433      for k in keys:
434         oo.write( '<h2>Table %s</h2>\n' % k )
435         for v in ee[k]:
436            try:
437              etmp = {}
438              for a in allAtts:
439                etmp[a] = self.m.td[k][v][1].get( a, 'unset' )
440              etmp['__dimensions__'] = string.join( self.m.td[k][v][0] )
441              oo.write( '<h3>' + v + (fixedType1Tmpl % etmp) )
442            except:
443              print k, self.m.td[k][v][1].keys()
444              raise
445      oo.close()
446    elif typecode == 2:
447      oo = open( 'type2.html', 'w' )
448      self.type2.sort()
449      oo.write( '<h2>Variables with fixed attributes</h2>\n' )
450      for v in self.type2:
451            l = self.m.vdict[v]
452            etmp = {}
453            for a in allAtts:
454                etmp[a] = self.m.td[l[0]][v][1].get( a, 'unset' )
455            oo.write( '<h3>' + v + (fixedType2TmplA % etmp) )
456            oo.write( '<ul>\n' )
457            for t in l:
458              dims = string.join( self.m.td[t][v][0] )
459              sa = tuple( [t,dims,] + map( lambda x: self.m.td[t][v][1].get( x, 'unset' ), ['cell_methods','valid_max', 'valid_min', 'ok_max_mean_abs', 'ok_min_mean_abs'] ) )
460              oo.write( fixedType2TmplB % sa )
461            oo.write( '</ul>\n' )
462      oo.close()
463           
464    elif typecode in [3,4,5]:
465      oo = open( 'type%s.html' % typecode, 'w' )
466      thistype,h2,al,tmplA,tmplB = { 3:(self.type3,"Variables with varying comment",['long_name','comment','cell_methods'], fixedType3TmplA, fixedType3TmplB),
467                      4:(self.type4,"Variables with varying long_name",['long_name','cell_methods'],fixedType3TmplA, fixedType4TmplB),
468                      5:(self.type5,"Remaining variables",['standard_name','long_name','cell_methods','realm'],fixedType5TmplA, fixedType5TmplB) }[typecode]
469      thistype.sort()
470      oo.write( '<h2>%s</h2>\n' % h2 )
471      for v in thistype:
472            l = self.m.vdict[v]
473            etmp = {}
474            for a in allAtts:
475                etmp[a] = self.m.td[l[0]][v][1].get( a, 'unset' )
476            oo.write( '<h3>' + v + (tmplA % etmp) )
477            oo.write( '<ul>\n' )
478            for t in l:
479              dims = string.join( self.m.td[t][v][0] )
480              sa = tuple( [t,dims,] + map( lambda x: self.m.td[t][v][1].get( x, 'unset' ), al ) )
481              oo.write( tmplB % sa )
482            oo.write( '</ul>\n' )
483      oo.close()
484           
485
486mips = ( NT_mip( 'cmip5','cmip5_vocabs/mip/', 'CMIP5_*' ),
487         NT_mip( 'ccmi', 'ccmi_vocabs/mip/', 'CCMI1_*')  )
488mips = ( NT_mip( 'ccmi', 'ccmi_vocabs/mip/', 'CCMI1_*'),  )
489cordex_mip = NT_mip( 'cordex', 'cordex_vocabs/mip/', 'CORDEX_*')
490mips = ( cordex_mip, NT_mip( 'ccmi', 'ccmi_vocabs/mip/', 'CCMI1_*'), NT_mip( 'cmip5','cmip5_vocabs/mip/', 'CMIP5_*' ), )
491mips = ( NT_mip( 'cmip5','cmip5_vocabs/mip/', 'CMIP5_*' ), )
492m = mipCo( mips ) 
493h = helper()
494
495allatts = ms.al
496thisatts = ['standard_name','units','long_name','__dimensions__']
497## need to have standard name first.
498for a in allatts:
499  if a not in thisatts:
500    thisatts.append(a)
501s =typecheck1( m, thisatts, helper=h)
502s.exportHtml( 1 )
503s.exportHtml( 2 )
504s.exportHtml( 3 )
505s.exportHtml( 4 )
506s.exportHtml( 5 )
Note: See TracBrowser for help on using the repository browser.