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

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

new CCMI tables

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( 'config/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.al0 = []
161    self.tl = []
162    self.dl = []
163    self.td = {}
164    self.dd = {}
165    self.helper = helper
166    for mip in mips:
167      self._scan(mip)
168
169  def _scan(self,mip):
170   
171 ## dl = glob.glob( '%s%s' % (mip.dir,mip.pattern) )
172    dl = glob.glob( '%s/%s%s' % (CC_CONFIG_DIR, mip.dir,mip.pattern) )
173    dl.sort()
174    for d in dl:
175     if d[-5:] != 'grids':
176      tab = string.split( d, '/')[-1]
177      isoceanic = tab[:7] == "CMIP5_O"
178      l2 = ms.scan_table( open( d ).readlines(), None, asDict=True, lax=True, tag="x", warn=True)
179      l2k = []
180      usedDims = []
181      for k in l2.keys():
182        if k not in cmip5_ignore:
183          l2k.append(k)
184          if l2[k][0] != 'scalar':
185            usedDims += l2[k][0]
186      l2k.sort()
187      usedDims.sort()
188      usedDims = uniquify( usedDims )
189     
190      ##self.al0 += ms.adict.keys()
191      self.vl0 += l2k
192      self.tl.append( [tab,l2, l2k,isoceanic] )
193      self.td[tab] = l2
194      ##self.dd[tab] = ms.adict.copy()
195      self.dd[tab] = {}
196      for k in ms.adict.keys():
197        if k not in usedDims:
198          print "WARNING[X1]: axis %s declared and not used in table %s" % (k,tab)
199      for u in usedDims:
200        if ms.adict.has_key(u):
201           self.dd[tab][u] = ms.adict[u]
202        else:
203           print 'WARNING[X2]: USED DIMENSION %s not in table %s' % (u,tab)
204      ##self.dl.append( [tab, ms.adict.copy()] )
205      self.dl.append( [tab, self.dd[tab].copy() ] )
206      self.al0 += self.dd[tab].keys()
207
208    self.vl0.sort()
209    self.vl = []
210    self.vl.append( self.vl0[0] )
211    self.vdict = { self.vl[0]:[] }
212    for v in self.vl0[1:]:
213      if v != self.vl[-1]:
214        self.vl.append(v)
215        self.vdict[v] = []
216    self.al0.sort()
217    self.al = [self.al0[0],]
218    self.adict = { self.al[0]:[] }
219    for v in self.al0[1:]:
220      if v != self.al[-1]:
221        self.al.append(v)
222        self.adict[v] = []
223
224    for t in self.tl:
225      for k in t[2]:
226        self.vdict[k].append(t[0])
227
228## create list of tables for each dimension.
229    for a in self.dl:
230      for k in a[1].keys():
231        self.adict[k].append(a[0])
232
233    self.dims = self.adict.keys()
234    self.dims.sort()
235    self.vars = self.vdict.keys()
236    self.vars.sort()
237    ##for v in self.vars:
238      ##l = self.vdict[v]
239      ##l.sort()
240##  print v, l, td[l[0]][v][1].get('standard_name','__NO_STANDARD_NAME__')
241
242class runcheck1:
243  def __init__( self, m, thisatts, isAxes=False):
244    self.errors = []
245    if not isAxes:
246      vars = m.vars
247      vdict = m.vdict
248      td = m.td
249      ix = 1
250      xxx = ''
251    else:
252      vars = m.dims
253      vdict = m.adict
254      td = m.dd
255      ix = 0
256      xxx = 'dim: '
257    vd2 = {}
258    for v in vars:
259     l = vdict[v]
260     l.sort()
261     if len(l) > 1:
262       for att in thisatts:
263        if att != "__name__":
264       ##for att in ['standard_name','units']:
265         if att == '__dimensions__':
266           atl = map( lambda x: string.join( td[x][v][0] ), l )
267         else:
268           atl = map( lambda x: td[x][v][ix].get(att,'__ABSENT__'), l )
269         atl.sort()
270         av = [atl[0],]
271         for a in atl[1:]:
272           if a != av[-1]:
273             av.append(a)
274         if att == 'standard_name':
275           for a in av:
276             if a not in snl and a not in snla:
277               print "ERROR[A1]: ",xxx,"INVALID STANDARD NAME: ",a,v
278               self.errors.append( "INVALID STANDARD NAME: %s [%s]" % (a,v) )
279         if len(av) > 1:
280           ee = {}
281   
282           for a in [True,False]:
283             ee[a] = []
284   
285           isol = []
286           for x in l:
287             a = td[x][v][ix].get(att,'__ABSENT__')
288             try:
289              if att == 'standard_name' or ( att == 'long_name' and vd2[v][0] == 2):
290               iso = x[:7] == 'CMIP5_O'
291               tt = snsubber.isFalseSn( v, a )
292              elif att == 'long_name':
293               tt = snsubber.isFalseLn( v, a )
294               dims = td[x][v][0]
295               iso = 'depth0m' in dims
296              else:
297               iso = False
298               tt = (False,)
299         ##    iso = False
300             except:
301               print att,v
302               raise
303             isol.append((iso,x))
304             if tt[0]:
305               print 'INFO[Y1]: Substituting ',v,a,tt
306               ee[iso].append( tt[1] )
307             else:
308               ee[iso].append( a )
309   
310           for a in [True,False]:
311             ok = True
312             if len(ee[a]) > 1 :
313               for x in ee[a][1:]:
314                 if x != ee[a][0]:
315                   ok = False
316   
317             if not ok:
318                print xxx,'E001: Multiple values : ',att,v,ee
319                for t in isol:
320                  if t[0] == a:
321                    tab = t[1]
322                    if att in ['standard_name','long_name']:
323                      print "E002",xxx,tab,td[tab][v][ix].get('standard_name','__ABSENT__'),td[tab][v][ix].get('long_name','__ABSENT__')
324                    else:
325                      print "E003",xxx,tab,td[tab][v][ix].get(att,'__ABSENT__')
326                   
327           if att == "standard_name":
328             vd2[v] = (2,[ee[True],ee[False]] )
329         else:
330           if att == "standard_name":
331             tt = snsubber.isFalseSn( v, av[0] )
332             if tt[0]:
333               print 'INFO[A2]: Substituting ',v,av[0],tt
334               vd2[v] = (1, tt[1])
335             else:
336               vd2[v] = (1, av)
337     elif len(l) == 1:
338           tab = vdict[v][0]
339           a = td[tab][v][ix].get('standard_name','__ABSENT__')
340           tt = snsubber.isFalseSn( v, a )
341           if tt[0]:
342             print 'INFO[A3]: Substituting ',v,a,tt
343             vd2[v] = (1, tt[1])
344           else:
345             vd2[v] = (1, a)
346           ##print 'MULTIPLE VALUES: ',v,att,av
347     else:
348      print "WARNING[X4]: ",xxx, 'Zero length element: %s' % v
349   
350class typecheck1:
351  def __init__( self, m, thisatts,helper=None):
352    self.type2Atts = ['positive','comment', 'long_name', 'modeling_realm', 'out_name', 'standard_name', 'type', 'units', 'flag_meanings', 'flag_values']
353    self.type3Atts = ['positive','long_name','modeling_realm', 'out_name', 'standard_name', 'type', 'units', 'flag_meanings', 'flag_values']
354    self.type4Atts = ['positive','modeling_realm', 'out_name', 'standard_name', 'type', 'units', 'flag_meanings', 'flag_values']
355    self.type2Atts = ['positive','comment', 'long_name', 'modeling_realm', 'out_name', 'standard_name', 'type', 'units']
356    self.type3Atts = ['positive','long_name','modeling_realm', 'out_name', 'standard_name', 'type', 'units']
357    self.type4Atts = ['positive','modeling_realm', 'out_name', 'standard_name', 'type', 'units']
358    self.m = m
359    vars = m.vars
360    vdict = m.vdict
361    self.helper=helper
362    td = m.td
363    vd2 = {}
364    type1, type2, type3, type4, type5 = [[],[],[],[],[],] 
365    vd2 = {}
366    for v in vars:
367     l = vdict[v]
368     dl = map( lambda x: string.join( td[x][v][0] ), l )
369     vd2[v] = str( uniquify( dl ) )
370    json.dump( vd2, open( 'mipInfo.json', 'w' ) )
371    for v in vars:
372     l = vdict[v]
373     l.sort()
374     if len(l) == 1: 
375       type1.append(v)
376     elif len(l) > 1:
377       adict = {}
378       for att in thisatts:
379         if att == '__dimensions__':
380           atl = map( lambda x: (string.join( td[x][v][0] ),x), l )
381         else:
382           atl = map( lambda x: (td[x][v][1].get(att,'__ABSENT__'),x), l )
383         atl.sort( tupsort(0).cmp )
384         a0 = atl[0][0]
385         if a0 == None:
386           a0 = ""
387         av = [a0,]
388         for a,tab in atl[1:]:
389           if a == None:
390             a = ""
391           if a != av[-1]:
392             if self.helper != None and self.helper.applycv:
393               thisok=False
394               pmatch = False
395               for cond,src,targ in self.helper.canonvar:
396                 if string.find(a,src) != -1 or  string.find(av[-1],src) != -1:
397                   ##print 'Potential match ---- ',a
398                   ##print src,'###',targ
399                   ##print av[-1]
400                   pmatch = True
401                 if self.helper.checkCond( tab, v, cond ):
402                   if self.helper.match(string.replace( a, src, targ ), av[-1]) or self.helper.match(string.replace( av[-1], src, targ ), a):
403                     thisok = True
404               if thisok:
405                 print 'INFO ############### conditional match found', tab, v
406               else:
407                 if pmatch:
408                   ##print '########### no matvh found'
409                   pass
410                 av.append(a)
411             else:
412               av.append(a)
413         adict[att] = av
414         ##if v == "snd":
415           ##print adict
416       
417## check for type 2
418       tval = None
419       ##if adict[ 'positive' ] == ['__ABSENT__']:
420       if all( map( lambda x: len(adict[x]) == 1, self.type2Atts )):
421           tval = 2
422       elif all( map( lambda x: len(adict[x]) == 1, self.type3Atts )):
423           tval = 3
424       elif all( map( lambda x: len(adict[x]) == 1, self.type4Atts )):
425           tval = 4
426       else:
427           l = map( lambda x: '%s:%s, ' % (x,len(adict[x]) ), self.type2Atts )
428       if tval == 2:
429         type2.append( v)
430       elif tval == 3:
431         type3.append( v)
432       elif tval == 4:
433         type4.append( v)
434       else:
435         type5.append(v)
436    xx = float( len(vars) )
437    print "INFO[XXX]", string.join( map( lambda x: '%s (%5.1f%%);' % (x,x/xx*100), [len(type1), len(type2), len(type3), len(type4), len(type5)] ) )
438    self.type1 = type1
439    self.type2 = type2
440    self.type3 = type3
441    self.type4 = type4
442    self.type5 = type5
443
444  def exportHtml( self, typecode ):
445
446    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']
447    fixedType1Tmpl = """:%(standard_name)s [%(units)s]</h3>
448        %(__dimensions__)s<br/>
449        %(long_name)s<br/>
450       realm: %(modeling_realm)s; out_name: %(out_name)s; type: %(type)s, <br/>
451       cell_methods: %(cell_methods)s; comment: %(comment)s<br/>
452"""
453    fixedType2TmplA = """:%(standard_name)s [%(units)s]</h3>
454        %(long_name)s<br/>
455       realm: %(modeling_realm)s; out_name: %(out_name)s; type: %(type)s, <br/>
456       comment: %(comment)s<br/>
457"""
458    fixedType2TmplB = "<li>%s [%s]: %s -- (%s,%s,%s,%s)</li>\n"
459       
460    fixedType3TmplA = """:%(standard_name)s [%(units)s]</h3>
461       realm: %(modeling_realm)s; out_name: %(out_name)s; type: %(type)s <br/>
462"""
463    fixedType3TmplB = "<li>%s [%s]: %s: %s [%s]</li>\n"
464    fixedType4TmplB = "<li>%s [%s]: %s [%s]</li>\n"
465    fixedType5TmplA = """ [%(units)s]</h3>
466       out_name: %(out_name)s; type: %(type)s <br/>
467"""
468    fixedType5TmplB = "<li>%s [%s]: %s, %s [%s]: %s</li>\n"
469       
470    if typecode == 1:
471      oo = open( 'type1.html', 'w' )
472      self.type1.sort()
473      ee = {}
474      for v in self.type1:
475        tab = self.m.vdict[v][0]
476        if not ee.has_key(tab):
477          ee[tab] = []
478        ee[tab].append( v )
479      keys = ee.keys()
480      keys.sort()
481      for k in keys:
482         oo.write( '<h2>Table %s</h2>\n' % k )
483         for v in ee[k]:
484            try:
485              etmp = {}
486              for a in allAtts:
487                etmp[a] = self.m.td[k][v][1].get( a, 'unset' )
488              etmp['__dimensions__'] = string.join( self.m.td[k][v][0] )
489              oo.write( '<h3>' + v + (fixedType1Tmpl % etmp) )
490            except:
491              print k, self.m.td[k][v][1].keys()
492              raise
493      oo.close()
494    elif typecode == 2:
495      oo = open( 'type2.html', 'w' )
496      self.type2.sort()
497      oo.write( '<h2>Variables with fixed attributes</h2>\n' )
498      for v in self.type2:
499            l = self.m.vdict[v]
500            etmp = {}
501            for a in allAtts:
502                etmp[a] = self.m.td[l[0]][v][1].get( a, 'unset' )
503            oo.write( '<h3>' + v + (fixedType2TmplA % etmp) )
504            oo.write( '<ul>\n' )
505            for t in l:
506              dims = string.join( self.m.td[t][v][0] )
507              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'] ) )
508              oo.write( fixedType2TmplB % sa )
509            oo.write( '</ul>\n' )
510      oo.close()
511           
512    elif typecode in [3,4,5]:
513      oo = open( 'type%s.html' % typecode, 'w' )
514      thistype,h2,al,tmplA,tmplB = { 3:(self.type3,"Variables with varying comment",['long_name','comment','cell_methods'], fixedType3TmplA, fixedType3TmplB),
515                      4:(self.type4,"Variables with varying long_name",['long_name','cell_methods'],fixedType3TmplA, fixedType4TmplB),
516                      5:(self.type5,"Remaining variables",['standard_name','long_name','cell_methods','realm'],fixedType5TmplA, fixedType5TmplB) }[typecode]
517      thistype.sort()
518      oo.write( '<h2>%s</h2>\n' % h2 )
519      for v in thistype:
520            l = self.m.vdict[v]
521            etmp = {}
522            for a in allAtts:
523                etmp[a] = self.m.td[l[0]][v][1].get( a, 'unset' )
524            oo.write( '<h3>' + v + (tmplA % etmp) )
525            oo.write( '<ul>\n' )
526            for t in l:
527              dims = string.join( self.m.td[t][v][0] )
528              sa = tuple( [t,dims,] + map( lambda x: self.m.td[t][v][1].get( x, 'unset' ), al ) )
529              oo.write( tmplB % sa )
530            oo.write( '</ul>\n' )
531      oo.close()
532           
533
534mips = ( NT_mip( 'cmip5','cmip5_vocabs/mip/', 'CMIP5_*' ),
535         NT_mip( 'ccmi', 'ccmi_vocabs/mip/', 'CCMI1_*')  )
536cordex_mip = NT_mip( 'cordex', 'cordex_vocabs/mip/', 'CORDEX_*')
537specs_mip = NT_mip( 'specs', 'specs_vocabs/mip/', 'SPECS_*')
538mips = ( cordex_mip, NT_mip( 'ccmi', 'ccmi_vocabs/mip/', 'CCMI1_*'), NT_mip( 'cmip5','cmip5_vocabs/mip/', 'CMIP5_*' ), )
539mips = ( cordex_mip, )
540mips = ( specs_mip, )
541mips = ( NT_mip( 'cmip5','cmip5_vocabs/mip/', 'CMIP5_*' ), )
542mips = ( NT_mip( 'ccmi', 'ccmi_vocabs/mip/', 'CCMI1_*'),  )
543m = mipCo( mips ) 
544h = helper()
545
546keys = m.adict.keys()
547keys.sort()
548fh = open( 'axes_json.txt', 'w' )
549for k in keys:
550  ee = m.dd[m.adict[k][0]][k][0]
551  ee["__name__"] = k
552  fh.write( json.dumps( ee ) + '\n' )
553fh.close()
554
555al = []
556for k0 in m.dd.keys():
557  for k1 in m.dd[k0].keys():
558    al += m.dd[k0][k1][0].keys()
559ald = uniquify( al )
560ald.sort()
561i = ald.index('standard_name')
562ald.pop(i)
563ald = ['standard_name', ] + ald
564
565cmip5AxesAtts = ['axis', 'bounds_values', 'climatology', 'coords_attrib', 'formula', 'index_only', 'long_name', 'must_call_cmor_grid', 'must_have_bounds', 'out_name', 'positive', 'requested', 'requested_bounds', 'standard_name', 'stored_direction', 'tolerance', 'type', 'units', 'valid_max', 'valid_min', 'value', 'z_bounds_factors', 'z_factors']
566
567## check consistency of dimensions
568r = runcheck1( m, ald, isAxes=True )
569for e in r.errors:
570  print ".....",e
571
572allatts = ms.al
573thisatts = ['standard_name','units','long_name','__dimensions__']
574## need to have standard name first.
575for a in allatts:
576  if a not in thisatts:
577    thisatts.append(a)
578s =typecheck1( m, thisatts, helper=h)
579s.exportHtml( 1 )
580s.exportHtml( 2 )
581s.exportHtml( 3 )
582s.exportHtml( 4 )
583s.exportHtml( 5 )
Note: See TracBrowser for help on using the repository browser.