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

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

work on mip table qc

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