source: CCCC/trunk/utils_c4.py @ 60

Subversion URL: http://proj.badc.rl.ac.uk/svn/exarch/CCCC/trunk/utils_c4.py@60
Revision 60, 24.1 KB checked in by mjuckes, 7 years ago (diff)

adding CCCC code

Line 
1
2import string, re, os, sys
3
4from fcc_utils import mipTableScan
5
6class reportSection:
7
8  def __init__(self,id,cls,parent=None, description=None):
9    self.id = id
10    self.cls = cls
11    self.parent = parent
12    self.description = description
13    self.records = []
14    self.subsections = []
15    self.closed = False
16    self.npass = 0
17    self.fail = 0
18    self.auditDone = True
19
20  def addSubSection( self, id, cls, description=None):
21    assert not self.closed, 'Attempt to add sub-section to closed report section'
22    self.subsections.append( reportSection(id, cls, parent=self, description=description )  )
23    self.auditDone = False
24    return self.subsections[-1]
25
26  def addRecord( self, id, cls, res, msg ):
27    assert not self.closed, 'Attempt to add record to closed report section'
28    self.records.append( (id, cls, res, msg) )
29    self.auditDone = False
30
31  def close(self):
32    self.closed = True
33
34  def reopen(self):
35    self.closed = False
36
37  def audit(self):
38    if self.auditDone:
39      return
40    self.closed = True
41    self.fail = 0
42    self.npass = 0
43    for ss in self.subsections:
44      ss.audit()
45      self.fail += ss.fail
46      self.npass += ss.npass
47
48    for r in self.records:
49      if r[2]:
50        self.npass += 1
51      else:
52        self.fail += 1
53
54class abortChecks(Exception):
55  pass
56class loggedException(Exception):
57  pass
58class baseException(Exception):
59 
60  def __init__(self,msg):
61    self.msg = 'utils_c4:: %s' % msg
62
63  def __str__(self):
64        return unicode(self).encode('utf-8')
65
66  def __unicode__(self):
67        return self.msg % tuple([force_unicode(p, errors='replace')
68                                 for p in self.params])
69class checkSeq:
70  def __init__(self):
71    pass
72
73  def check(self,x):
74    d = map( lambda i: x[i+1] - x[i], range(len(x)-1) )
75    self.delt = sum(d)/len(d)
76    self.dmx = max(d)
77    self.dmn = min(d)
78    return self.dmx - self.dmn < abs(self.delt)*1.e-4
79
80cs = checkSeq()
81
82class checkBase:
83
84  def  __init__(self,cls="CORDEX",reportPass=True,parent=None):
85    self.cls = cls
86    assert cls == 'CORDEX','This version of the checker only supports CORDEX'
87    self.re_isInt = re.compile( '[0-9]+' )
88    self.errorCount = 0
89    self.passCount = 0
90    self.missingValue = 1.e20
91    self.parent = parent
92    self.reportPass=reportPass
93    self.requiredGlobalAttributes = [ 'institute_id', 'contact', 'rcm_version_id', 'product', 'CORDEX_domain', 'creation_date', \
94             'frequency', 'model_id', 'driving_model_id', 'driving_experiment', 'driving_model_ensemble_member', 'experiment_id']
95    self.controlledGlobalAttributes = ['frequency', 'driving_experiment_name', 'project_id', 'CORDEX_domain', 'driving_model_id', 'model_id', 'institute_id','driving_model_ensemble_member','rcm_version_id']
96    self.globalAttributesInFn = [None,'CORDEX_domain','driving_model_id','experiment_id','driving_model_ensemble_member','model_id','rcm_version_id']
97    self.requiredVarAttributes = ['long_name', 'standard_name', 'units', 'missing_value', '_FillValue']
98    self.checks = ()
99    self.drsMappings = {'variable':'@var','institute':'institute_id', 'product':'product', 'experiment':'experiment_id', \
100                        'ensemble':'driving_model_ensemble_member', 'model':'model_id', 'driving_model':'driving_model_id', \
101                        'frequency':'frequency', \
102                        'project':'project_id', 'domain':'CORDEX_domain', 'model_version':'rcm_version_id' }
103    self.init()
104
105  def isInt(self,x):
106    return self.re_isInt.match( x ) != None
107
108  def logMessage(self, msg, error=False ):
109    if self.parent.log != None:
110       if error:
111         self.parent.log.error( msg )
112       else:
113         self.parent.log.info( msg )
114    else:
115       print msg
116
117  def log_exception( self, msg):
118    if self.parent.log != None:
119        self.parent.log.error("Exception has occured" ,exc_info=1)
120    else:
121        traceback.print_exc(file=sys.stdout)
122
123  def log_error( self, msg ):
124    self.lastError = msg
125    self.errorCount += 1
126    self.logMessage( '%s.%s: FAILED:: %s' % (self.id,self.checkId,msg), error=True )
127
128  def log_pass( self ):
129    self.passCount = True
130    if self.reportPass:
131      self.logMessage(  '%s.%s: OK' % (self.id,self.checkId) )
132
133  def log_abort( self ):
134    self.completed = False
135    self.logMessage(   '%s.%s: ABORTED:: Errors too severe to complete further checks in this module' % (self.id,'xxx') )
136    raise abortChecks
137
138  def status(self):
139    return '%s.%s' % (self.id,self.checkId)
140
141  def test(self,res,msg,abort=False,part=False):
142    if res:
143      if not part:
144         self.log_pass()
145    else:
146      self.log_error(msg)
147      if abort:
148        self.log_abort()
149    return res
150
151  def runChecks(self):
152
153    try:
154      for c in self.checks:
155        c()  # run check
156      self.completed = True
157    except abortChecks:
158      ## error logging done before raising this exception
159      return
160    except:
161      self.log_exception( 'Exception caught by runChecks' )
162      raise loggedException
163      ##traceback.print_exc(file=open("errlog.txt","a"))
164      ##logger.error("Exception has occured" ,exc_info=1)
165   
166class checkFileName(checkBase):
167
168  def init(self):
169    self.id = 'C4.001'
170    self.checkId = 'unset'
171    self.step = 'Initialised'
172    self.checks = (self.do_check_fn,)
173####
174
175  def check(self,fn):
176    self.errorCount = 0
177    assert type(fn) in [type('x'),type(u'x')], '1st argument to "check" method of checkGrids shound be a string variable name (not %s)' % type(fn)
178    self.fn = fn
179
180    self.runChecks()
181###
182  def do_check_fn(self):
183    fn = self.fn
184    self.errorCount = 0
185    self.completed = False
186
187## check basic parsing of file name
188    self.checkId = '001'
189    self.test( fn[-3:] == '.nc', 'File name ending ".nc" expected', abort=True, part=True )
190    bits = string.split( fn[:-3], '_' )
191    self.test( len(bits) in [8,9], 'File name not parsed into 8 or 9 elements [%s]' % str(bits), abort=True )
192
193    self.fnParts = bits[:]
194    self.domain = self.fnParts[1]
195    self.freq = self.fnParts[7]
196    self.var = self.fnParts[0]
197
198
199    self.checkId = '002'
200    if len(self.fnParts) == 9:
201
202## test time segment
203      bits = string.split( self.fnParts[-1], '-' )
204      self.test( len(bits) == 2, 'File time segment [%s] will not parse into 2 elements' % (self.fnParts[-1] ), abort=True, part=True )
205
206      self.test(  len(bits[0]) == len(bits[1]), 'Start and end time specified in file name [%s] of unequal length' % (self.fnParts[-1] ), abort=True, part=True  )
207
208      for b in bits:
209        self.test( self.isInt(b), 'Time segment in filename [%s] contains non integer characters' % (self.fnParts[-1] ),  abort=True, part=True  )
210      self.log_pass()
211      self.fnTimeParts = bits[:]
212
213    self.checkId = '003'
214    if len(self.fnParts) == 8:
215      self.test( self.fnParts[7] == 'fx', 'Time range not specified and frequency not fx' )
216
217    self.checkId, ok = ('004',True)
218    if len(self.fnParts) == 9:
219      ltr = { 'mon':6, 'sem':6, 'day':8, '3hr':10, '6hr':10 }
220      ok &=self.test( self.freq in ltr.keys(), 'Frequency [%s] not recognised' % self.freq, part=True )
221      if ok:
222        msg = 'Length of time range parts [%s,%s] not equal to required length [%s] for frequency %s' % (self.fnTimeParts[0],self.fnTimeParts[1],ltr[self.freq],self.freq)
223        ok &= self.test( len(self.fnTimeParts[0]) == ltr[self.freq], msg, part=True )
224
225      if ok:
226        self.log_pass()
227    self.completed = True
228
229class checkGlobalAttributes(checkBase):
230
231  def init(self):
232    self.id = 'C4.002'
233    self.checkId = 'unset'
234    self.step = 'Initialised'
235    self.checks = (self.do_check_ga,)
236
237  def check(self,globalAts, varAts,varName,varGroup, vocabs, fnParts):
238    self.errorCount = 0
239    assert type(varName) in [type('x'),type(u'x')], '1st argument to "check" method of checkGrids shound be a string variable name (not %s)' % type(varName)
240    self.var = varName
241    self.globalAts = globalAts
242    self.varAts = varAts
243    self.varGroup = varGroup
244    self.vocabs = vocabs
245    self.fnParts = fnParts
246    self.runChecks()
247
248  def getDrs( self ):
249    assert self.completed, 'method getDrs should not be called if checks have not been completed successfully'
250    ee = {}
251    for k in self.drsMappings:
252      if self.drsMappings[k] == '@var':
253        ee[k] = self.var
254      else:
255        ee[k] = self.globalAts[ self.drsMappings[k] ]
256
257    for k in ['creation_date','tracking_id']:
258      if k in self.globalAts.keys():
259        ee[k] = self.globalAts[k]
260
261    return ee
262
263  def do_check_ga(self):
264    varName = self.var
265    globalAts = self.globalAts
266    varAts = self.varAts
267    varGroup = self.varGroup
268    vocabs = self.vocabs
269    fnParts = self.fnParts
270
271    self.completed = False
272    self.checkId = '001'
273    m = []
274    for k in self.requiredGlobalAttributes:
275      if not globalAts.has_key(k):
276         m.append(k)
277
278    gaerr = not self.test( len(m)  == 0, 'Required global attributes missing: %s' % str(m) )
279
280    self.checkId = '002'
281
282    self.test( varAts.has_key( varName ), 'Expected variable [%s] not present' % varName, abort=True, part=True )
283    self.test( vocabs['variable'].isInTable( varName, varGroup ), 'Variable %s not in table %s' % (varName,varGroup), abort=True, part=True )
284
285    self.checkId = '003'
286
287    self.test( varAts[varName]['_type'] == "float32", 'Variable [%s] not of type float' % varName )
288
289    self.checkId = '004'
290    m = []
291    reqAts = self.requiredVarAttributes
292    if varGroup != 'fx':
293      reqAts.append( 'cell_methods' )
294    for k in reqAts + vocabs['variable'].lists(varName, 'addRequiredAttributes'):
295      if not varAts[varName].has_key(k):
296         m.append(k)
297    vaerr = not self.test( len(m)  == 0, 'Required variable attributes missing: %s' % str(m) )
298
299    if vaerr or gaerr:
300      self.log_abort()
301
302## need to insert a check that variable is present
303    self.checkId = '005'
304    ok = True
305    msg = 'Variable [%s] has incorrect missing_value attribute' % varName
306    ok &= self.test( varAts[varName]['missing_value'] == self.missingValue, msg, part=True )
307    msg = 'Variable [%s] has incorrect _FillValue attribute' % varName
308    ok &= self.test( varAts[varName]['_FillValue'] == self.missingValue, msg, part=True )
309    mm = []
310   
311    contAts = ['long_name', 'standard_name', 'units']
312    if varGroup != 'fx':
313      contAts.append( 'cell_methods' )
314    for k in contAts + vocabs['variable'].lists(varName,'addControlledAttributes'):
315      if varAts[varName][k] != vocabs['variable'].getAttr( varName, varGroup, k ):
316        mm.append( k )
317
318    ok &= self.test( len(m)  == 0, 'Variable [%s] has incorrect attributes: %s' % (varName, str(mm)), part=True )
319    if ok:
320       self.log_pass()
321
322    if varGroup != 'fx':
323      self.isInstantaneous = string.find( varAts[varName]['cell_methods'], 'time: point' ) != -1
324    else:
325      self.isInstantaneous = True
326
327    self.checkId = '006'
328    m = []
329    for a in self.controlledGlobalAttributes:
330       if not vocabs[a].check( str(globalAts[a]) ):
331          m.append( (a,globalAts[a]) )
332
333    self.test( len(m)  == 0, 'Global attributes do not match constraints: %s' % str(m) )
334
335    self.checkId = '007'
336    m = []
337    for i in range(len(self.globalAttributesInFn)):
338       if self.globalAttributesInFn[i] != None:
339         if globalAts[self.globalAttributesInFn[i]] != fnParts[i]:
340           m.append( (i,self.globalAttributesInFn[i]) )
341
342    self.test( len(m)  == 0,'File name segments do not match corresponding global attributes: %s' % str(m) )
343
344    self.completed = True
345       
346class checkStandardDims(checkBase):
347
348  def init(self):
349    self.id = 'C4.003'
350    self.checkId = 'unset'
351    self.step = 'Initialised'
352
353  def check(self,varName,varGroup, da, va, isInsta):
354    self.errorCount = 0
355    self.completed = False
356    self.checkId = '001'
357    if varGroup != 'fx':
358      ok = True
359      self.test( 'time' in da.keys(), 'Time dimension not found' , abort=True, part=True )
360      if not isInsta:
361         ok &= self.test(  da['time'].get( 'bounds', 'xxx' ) == 'time_bnds', 'Required bounds attribute not present or not correct value', part=True )
362
363## is time zone designator needed?
364      ok &= self.test( da['time'].get( 'units', 'xxx' ) in ["days since 1949-12-01 00:00:00Z", "days since 1949-12-01 00:00:00"], 
365                       'Time units [%s] attribute not set correctly to "days since 1949-12-01 00:00:00Z"' % da['time'].get( 'units', 'xxx' ), part=True )
366
367      ok &= self.test(  da['time'].has_key( 'calendar' ), 'Time: required attibute calendar missing', part=True )
368
369      ok &= self.test( da['time']['_type'] == "float64", 'Time: data type not float64', part=True )
370       
371      if ok:
372        self.log_pass()
373      self.calendar = da['time'].get( 'calendar', 'None' )
374    else:
375      self.calendar = 'None'
376    self.checkId = '002'
377    if varName in self.plevRequired:
378      ok = True
379      self.test( 'plev' in va.keys(), 'plev coordinate not found %s' % str(va.keys()), abort=True, part=True )
380
381      ok &= self.test( int( va['plev']['_data'] ) == self.plevValues[varName],  \
382                  'plev value [%s] does not match required [%s]' % (va['plev']['_data'],self.plevValues[varName] ), part=True )
383     
384      plevAtDict = {'standard_name':"air_pressure", \
385                    'long_name':"pressure", \
386                    'units':"Pa", \
387                    'positive':"down", \
388                    'axis':"Z" }
389
390      if varName in ['clh','clm','cll']:
391        plevAtDict['bounds']= "plev_bnds"
392
393      for k in plevAtDict.keys():
394        ok &= self.test( va['plev'].get( k, None ) == plevAtDict[k], 
395                     'plev attribute %s absent or wrong value (should be %s)' % (k,plevAtDict[k]), part=True )
396
397      if varName in ['clh','clm','cll']:
398         self.test( "plev_bnds" in va.keys(), 'plev_bnds variable not found %s' % str(va.keys()), abort=True, part=True )
399         mm = []
400         for k in plevAtDict.keys():
401            if k != 'bounds' and k in va['plev_bnds'].keys():
402               if va['plev_bnds'][k] != va['plev'][k]:
403                 mm.append(k)
404         ok &= self.test( len(mm) == 0, 'Attributes of plev_bnds do not match those of plev: %s' % str(mm), part=True )
405
406         bndsVals = {'clh':[44000, 0], 'clm':[68000, 44000], 'cll':[100000, 68000] }
407         res = self.test( len( va['plev_bnds']['_data'] ) == 2, 'plev_bnds array is of wrong length', part=True )
408         ok &= res
409         if res:
410            kk = 0
411            for i in [0,1]:
412               if int(va['plev_bnds']['_data'][i]) != bndsVals[varName][i]:
413                  kk+=1
414            ok &= self.test( kk == 0, 'plev_bnds values not correct: should be %s' % str(bndsVals[varName]), part=True )
415
416      if ok:
417        self.log_pass()
418
419    self.checkId = '003'
420    if varName in self.heightRequired:
421      heightAtDict = {'long_name':"height", 'standard_name':"height", 'units':"m", 'positive':"up", 'axis':"Z" }
422      ok = True
423      ok &= self.test( 'height' in va.keys(), 'height coordinate not found %s' % str(va.keys()), abort=True, part=True )
424      ok &= self.test( abs( va['height']['_data'] - self.heightValues[varName]) < 0.001, \
425                'height value [%s] does not match required [%s]' % (va['height']['_data'],self.heightValues[varName] ), part=True )
426     
427      for k in heightAtDict.keys():
428        ok &= self.test( va['height'].get( k, None ) == heightAtDict[k], \
429                         'height attribute %s absent or wrong value (should be %s)' % (k,heightAtDict[k]), part=True )
430
431      if ok:
432        self.log_pass()
433
434    self.completed = True
435
436class checkGrids(checkBase):
437
438  def init(self):
439    self.id = 'C4.004'
440    self.checkId = 'unset'
441    self.step = 'Initialised'
442    self.checks = (self.do_check_rp,self.do_check_intd)
443
444  def check(self,varName, domain, da, va):
445    self.errorCount = 0
446    assert type(varName) in [type('x'),type(u'x')], '1st argument to "check" method of checkGrids shound be a string variable name (not %s)' % type(varName)
447    self.var = varName
448    self.domain = domain
449    self.da = da
450    self.va = va
451
452    self.runChecks()
453    ##for c in self.checks:
454      ##c()
455    ##self.do_check_rp()
456    ##self.do_check_intd()
457
458  def do_check_rp(self):
459    varName = self.var
460    domain = self.domain
461    da = self.da
462    va = self.va
463    if va[varName].get( 'grid_mapping', None ) == "rotated_pole":
464      self.checkId = '001'
465      atDict = { 'grid_mapping_name':'rotated_latitude_longitude' }
466      atDict['grid_north_pole_latitude'] = self.rotatedPoleGrids[domain]['grid_np_lat']
467      if self.rotatedPoleGrids[domain]['grid_np_lon'] != 'N/A':
468        atDict['grid_north_pole_longitude'] = self.rotatedPoleGrids[domain]['grid_np_lon']
469
470      self.checkId = '002'
471      self.test( 'rlat' in da.keys() and 'rlon' in da.keys(), 'rlat and rlon not found (required for grid_mapping = rotated_pole )', abort=True, part=True )
472
473      atDict = {'rlat':{'long_name':"rotated latitude", 'standard_name':"grid_latitude", 'units':"degrees", 'axis':"Y", '_type':'float64'},
474                'rlon':{'long_name':"rotated longitude", 'standard_name':"grid_longitude", 'units':"degrees", 'axis':"X", '_type':'float64'} }
475      mm = []
476      for k in ['rlat','rlon']:
477        for k2 in atDict[k].keys():
478          if atDict[k][k2] != da[k].get(k2, None ):
479            mm.append( (k,k2) )
480      self.test( len(mm) == 0, 'Required attributes of grid coordinate arrays not correct: %s' % str(mm) )
481
482      self.checkId = '003'
483      ok = True
484      for k in ['rlat','rlon']:
485        res = len(da[k]['_data']) == self.rotatedPoleGrids[domain][ {'rlat':'nlat','rlon':'nlon' }[k] ]
486        if not res:
487          self.test( res, 'Size of %s dimension does not match specification (%s,%s)' % (k,a,b), part=True  )
488          ok = False
489
490      a = ( da['rlat']['_data'][0], da['rlat']['_data'][-1], da['rlon']['_data'][0], da['rlon']['_data'][-1] )
491      b = map( lambda x: self.rotatedPoleGrids[domain][x], ['s','n','w','e'] )
492      mm = []
493      for i in range(4):
494        if a[i] != b[i]:
495          mm.append( (a[i],b[i]) )
496
497      ok &= self.test( len(mm) == 0, 'Domain boundaries for rotated pole grid do not match %s' % str(mm), part=True )
498
499      for k in ['rlat','rlon']:
500        ok &= self.test( cs.check( da[k]['_data'] ), '%s values not evenly spaced -- min/max delta = %s, %s' % (k,cs.dmn,cs.dmx), part=True )
501
502      if ok:
503        self.log_pass()
504
505  def do_check_intd(self):
506    varName = self.var
507    domain = self.domain
508    da = self.da
509    va = self.va
510    if domain[-1] == 'i':
511      self.checkId = '002'
512      self.test( 'lat' in da.keys() and 'lon' in da.keys(), 'lat and lon not found (required for interpolated data)', abort=True, part=True )
513
514      atDict = {'lat':{'long_name':"latitude", 'standard_name':"latitude", 'units':"degrees_north", '_type':'float64'},
515                'lon':{'long_name':"longitude", 'standard_name':"longitude", 'units':"degrees_east", '_type':'float64'} }
516      mm = []
517      for k in ['lat','lon']:
518        for k2 in atDict[k].keys():
519          if atDict[k][k2] != da[k].get(k2, None ):
520            mm.append( (k,k2) )
521
522      self.test( len(mm) == 0,  'Required attributes of grid coordinate arrays not correct: %s' % str(mm), part=True )
523
524      ok = True
525      for k in ['lat','lon']:
526        res = len(da[k]['_data']) == self.interpolatedGrids[domain][ {'lat':'nlat','lon':'nlon' }[k] ]
527        if not res:
528          a,b =  len(da[k]['_data']), self.interpolatedGrids[domain][ {'lat':'nlat','lon':'nlon' }[k] ]
529          self.test( res, 'Size of %s dimension does not match specification (%s,%s)' % (k,a,b), part=True )
530          ok = False
531
532      a = ( da['lat']['_data'][0], da['lat']['_data'][-1], da['lon']['_data'][0], da['lon']['_data'][-1] )
533      b = map( lambda x: self.interpolatedGrids[domain][x], ['s','n','w','e'] )
534      mm = []
535      for i in range(4):
536        if a[i] != b[i]:
537          mm.append( (a[i],b[i]) )
538
539      ok &= self.test( len(mm) == 0, 'Domain boundaries for interpolated grid do not match %s' % str(mm), part=True )
540
541      for k in ['lat','lon']:
542        ok &= self.test( cs.check( da[k]['_data'] ), '%s values not evenly spaced -- min/max delta = %s, %s' % (k,cs.dmn,cs.dmx), part=True )
543      if ok:
544        self.log_pass()
545
546class mipVocab:
547
548  def __init__(self):
549     ms = mipTableScan()
550     dir = '/home/martin/2013/mipML/FCC2/trunk/work/cordex_vocabs/mip/'
551     self.varInfo = {}
552     self.varcons = {}
553     for f in ['fx','sem','mon','day','6h','3h']:
554        vg = f
555        if f in ['6h','3h']:
556          vg += 'r'
557        self.varcons[vg] = {}
558        fn = 'CORDEX_%s' % f
559        ll = open( '%s%s' % (dir,fn) ).readlines()
560        ee = ms.scan_table(ll,None,asDict=True)
561        for v in ee.keys():
562          eeee = {}
563          ar = []
564          ac = []
565          for a in ee[v][1].keys():
566            eeee[a] = ee[v][1][a]
567          if 'positive' in eeee.keys():
568            ar.append( 'positive' )
569            ac.append( 'positive' )
570          self.varInfo[v] = {'ar':ar, 'ac':ac }
571          self.varcons[vg][v] = eeee
572           
573  def lists( self, k, k2 ):
574     if k2 == 'addRequiredAttributes':
575       return self.varInfo[k]['ar']
576     elif k2 == 'addControlledAttributes':
577       return self.varInfo[k]['ac']
578     else:
579       raise 'mipVocab.lists called with bad list specifier %s' % k2
580
581  def isInTable( self, v, vg ):
582    assert vg in self.varcons.keys(), '%s not found in  self.varcons.keys()'
583    return (v in self.varcons[vg].keys())
584     
585  def getAttr( self, v, vg, a ):
586    assert vg in self.varcons.keys(), '%s not found in  self.varcons.keys()'
587    assert v in self.varcons[vg].keys(), '%s not found in self.varcons[%s].keys()' % (v,vg)
588     
589    return self.varcons[vg][v][a]
590     
591class patternControl:
592
593  def __init__(self,tag,pattern):
594    try:
595      self.re_pat = re.compile( pattern )
596    except:
597      print "Failed to compile pattern >>%s<< (%s)" % (pattern, tag)
598    self.pattern = pattern
599
600  def check(self,val):
601    return self.re_pat.match( val ) != None
602   
603class listControl:
604  def __init__(self,tag,list):
605    self.list = list
606    self.tag = tag
607
608  def check(self,val):
609    return val in self.list
610
611
612class checkByVar(checkBase):
613
614  def init(self):
615    self.id = 'C5.001'
616    self.checkId = 'unset'
617    self.step = 'Initialised'
618    self.checks = (self.checkTrange,)
619
620  def impt(self,flist):
621    ee = {}
622    for f in flist:
623      fn = string.split(f, '/' )[-1]
624      fnParts = string.split( fn[:-3], '_' )
625      if fnParts[7] == 'fx':
626        trange = None
627      else:
628        trange = string.split( fnParts[8], '-' )
629      group = fnParts[7]
630      var = fnParts[0]
631      if group not in ee.keys():
632        ee[group] = {}
633      if var not in ee[group].keys():
634        ee[group][var] = []
635      ee[group][var].append( (f,fn,fnParts[7],trange) )
636
637    nn = len(flist)
638    n2 = 0
639    for k in ee.keys():
640      for k2 in ee[k].keys():
641        n2 += len( ee[k][k2] )
642
643    assert nn==n2, 'some file lost!!!!!!'
644    print '%s files, %s frequencies' % (nn,len(ee.keys()) )
645    self.ee = ee
646
647  def check(self, recorder=None,calendar='None'):
648    self.errorCount = 0
649    self.recorder=recorder
650    self.calendar=calendar
651    if calendar == '360-day':
652      self.enddec = 30
653    else:
654      self.enddec = 31
655
656    self.runChecks()
657
658  def checkTrange(self):
659    keys = self.ee.keys()
660    keys.sort()
661    for k in keys:
662      if k != 'fx':
663        keys2 = self.ee[k].keys()
664        keys2.sort()
665        for k2 in keys2:
666          self.checkThisTrange( self.ee[k][k2], k, k2 )
667
668  def checkThisTrange( self, tt, group, var):
669    mm = { 'enddec':self.enddec }
670    pats = {'mon':('(?P<d>[0-9]{3})101','(?P<e>[0-9]{3})012'), \
671            'sem':('(?P<d>[0-9]{3})012','(?P<e>[0-9]{3})011'), \
672            'day':('(?P<d>[0-9]{3}[16])0101','(?P<e>[0-9]{3}[50])12%(enddec)s' % mm), \
673            'subd':('(?P<d>[0-9]{4})0101(?P<h1>[0-9]{2})', '(?P<e>[0-9]{4})12%(enddec)s(?P<h2>[0-9]{2})' % mm ), \
674            'subd2':('(?P<d>[0-9]{4})0101(?P<h1>[0-9]{2})', '(?P<e>[0-9]{4})010100' ) }
675
676    if group in ['3hr','6hr']:
677       kg = 'subd'
678    else:
679       kg = group
680    ps = pats[kg]
681    rere = (re.compile( ps[0] ), re.compile( ps[1] ) )
682
683    n = len(tt)
684    for j in range(n):
685      t = tt[j]
686      isFirst = j == 0
687      isLast = j == n-1
688      lok = True
689      for i in [0,1]:
690        if not (i==0 and isFirst or i==1 and isLast):
691          x = rere[i].match( t[3][i] )
692          lok &= self.test( x != None, 'Cannot match time range %s: %s' % (i,t[1]), part=True )
693        if not lok:
694          print 'Cannot match time range %s:' % t[1]
695          if self.recorder != None:
696            self.recorder.modify( t[1], 'ERROR: time range' )
697
698   
Note: See TracBrowser for help on using the repository browser.