source: CMIP6dreqbuild/trunk/src/framework/ingest/util_checkUpd.py @ 861

Subversion URL: http://proj.badc.rl.ac.uk/svn/exarch/CMIP6dreqbuild/trunk/src/framework/ingest/util_checkUpd.py@861
Revision 861, 36.2 KB checked in by mjuckes, 4 years ago (diff)

candidate

Line 
1##
2## this will check for changes cleanly ... need a better view of what dreq_consol_tables is doing before this can be used.
3##
4
5from xceptions import baseException
6import os, stat, shelve, uuid, collections
7import dreq_cfg
8import dreq_utils
9import util_varGroups
10from utils_wb import workbook, uniCleanFunc
11import utils
12import util_gen
13omitThese = {}
14omitThese['CMIP5'] = ['aero','Omon','Oyr','OImon','cfMon','cfDay','cfSites','cf3hr','cfOff']
15
16targTabs = ['CMIP5_cfOff', 'CMIP5_cfMon', 'CMIP5_6hrPlev', 'CMIP5_day', 'OMIP.Oyr', 'CMIP5_cfSites', 'OMIP.Omon', 'CMIP5_aero', 'CMIP5_LImon', 'CMIP5_Amon', 'CMIP5_Oclim', 'CMIP5_6hrLev', 'CMIP5_Lmon', 'CMIP5_3hr', 'CMIP5_fx', 'CMIP5_cfDay', 'CMIP5_cf3hr', 'OMIP.fx', 'OMIP.day']
17targTabs = ['CFMIP.cfOff', 'CFMIP.cfMon', 'CMIP5_6hrPlev', 'CMIP5_day', 'OMIP.Oyr', 'CFMIP.cfSites', 'OMIP.Omon', 'CMIP5_aero', 'CMIP5_LImon', 'CMIP5_Amon', 'CMIP5_Oclim', 'CMIP5_6hrLev', 'CMIP5_Lmon', 'CMIP5_3hr', 'CMIP5_fx', 'CFMIP.cfDay', 'CFMIP.cf3hr', 'OMIP.fx', 'OMIP.day']
18
19nt__grphd = collections.namedtuple( 'grphd', ['withPriority','thisl', 'iv', 'it','start','tv'] )
20nt__grptbl = collections.namedtuple( 'grptbl', ['grp','var','srcTable','freq','description','shape','levels','timeProc','mask','priority','mip','id'] )
21
22class snChange(object):
23  def __init__(self):
24    fn = 'ingest/standardNameChanges.xls'
25    wb = workbook( fn )
26    s1 = wb.book.sheet_by_name(u'Sheet1')
27    self.map = collections.defaultdict(dict)
28    self.omit = collections.defaultdict(set)
29    self.trigger = collections.defaultdict(dict)
30    self.ng = collections.defaultdict(set)
31    for i in range( s1.nrows ):
32      rr = [x.value.strip() for x in s1.row(i)]
33      tab = rr[0]
34      sn0 = rr[3]
35      var = rr[2]
36      if rr[1] == '':
37        sn1 = rr[4]
38        if sn1 == 'xxx':
39          self.omit[tab].add(sn0)
40        elif sn1[0] == '@':
41          self.trigger[tab][sn0] = sn1[1:]
42        else:
43          self.map[tab][sn0] = rr[4:]
44      else:
45        ng = rr[1]
46        self.ng[(tab,ng)].add(sn0)
47
48    for t in self.trigger:
49      for s in self.trigger[t]:
50        assert (t,self.trigger[t][s]) in self.ng, 'snChange: Inconsistent directives in %s' % fn
51
52
53class maps(object):
54  ttranstem  = {'icesheetmon':'LImon','icesheetyear':'LIyr','icesheetfx':'LIfx'}
55
56logFarm = utils.dreqLog('logs')
57log = logFarm.getLog( 'soUpd' )
58
59def getCmip5Sns():
60    ##fname = '/data/work/documents/CMIP5_standard_output.xls'
61    fname = 'ingest/CMIP5_standard_output.xls'
62    wb = workbook( fname )
63    wb.sns.sort()
64    omit1 = [u'dims', u'general', u'other output',u'CFMIP output']
65    sns = []
66    for s in wb.sns:
67      if s not in omit1:
68        sns.append(s)
69
70    return sns
71
72def rval(x):
73  if x.ctype == 1:
74    return x.value.strip()
75  else:
76    return x.value
77
78def cleanStr(x):
79  if x.ctype == 1:
80    return uniCleanFunc(x.value).strip()
81  else:
82    return str(x.value)
83
84def getRowValues( ll, minLen=0, maxLen=0):
85  oo = []
86  for i in ll:
87    oo.append( i.value )
88  if len(oo) >= minLen:
89    return oo[:minLen]
90  for i in range(minLen+1):
91    if len(oo) == minLen:
92      return oo
93    oo.append( '' )
94  if maxLen > 0:
95    return oo[:maxLen]
96  return oo
97
98class templateStat(object):
99  ibase = '/home/martin/2014/wip/dreq/input'
100  def __init__(self,sdir='inSh'):
101    cfg = dreq_cfg.rqcfg()
102    ##cfg.ff['CMIP5'] = ['/data/work/documents/CMIP5_standard_output.xls']
103    cfg.ff['CMIP5'] = ['CMIP5_standard_output.xls']
104    self.changed = []
105    self.new = []
106
107    k2 = cfg.ff.keys()
108    self.sh = shelve.open( '%s/sh__templateStat' % (sdir) )
109    for k in sorted( cfg.ee.keys() ):
110      self.verify( k,[cfg.ee[k],] )
111    for k in sorted( cfg.ff.keys() ):
112      self.verify( k,cfg.ff[k] )
113    self.sh.close()
114
115  def verify( self, k, fl ):
116    for f in fl:
117      fpath = '%s/%s/%s' % (self.ibase,k,f)
118      if not os.path.isfile( fpath ):
119        self.msg( 'ERROR.001.0001: file not found: %s' % fpath )
120        if fpath in self.sh:
121          self.msg( 'ERROR.001.0002: file lost or moved: %s' % fpath )
122      else:
123        stt = os.stat( fpath )
124        self.ctime = stt[stat.ST_CTIME]
125        self.fsize = stt[stat.ST_SIZE]
126        if fpath in self.sh:
127          fhist = self.sh[fpath]
128          if fhist[-1] != (self.ctime,self.fsize):
129            self.msg( 'INFO.001.0002: CHANGED: %s: %s (%s)' % (fpath,self.ctime,self.fsize) )
130            fhist.append( (self.ctime,self.fsize) )
131            self.sh[fpath] = fhist
132            self.changed.append( (k,fpath,self.ctime,self.fsize) )
133          else:
134            self.msg( 'INFO.001.0001: SAME: %s: %s (%s)' % (fpath,self.ctime,self.fsize) )
135        else:
136          self.msg( 'INFO.001.0003: NEW: %s: %s (%s)' % (fpath,self.ctime,self.fsize) )
137          self.new.append( (k,fpath,self.ctime,self.fsize) )
138          self.sh[fpath] = [(self.ctime,self.fsize)]
139
140  def msg(self, txt ):
141    print txt
142
143class varGroups(object):
144  rq = dreq_cfg.rqcfg()
145  freqmap = {'daily':'day', 'Annual':'yr', 'Timestep':'subhr',  '1day':'day', '1mon':'mon', 
146             'month':'mon', 'year':'yr', 'monthly':'mon', 'Day':'day', '6h':'6hr', 
147             '3 hourly':'3hr', '3 Hourly':'3hr'  }
148
149  def __init__(self):
150
151    omit = ['ALL VARIABLES', 'Objectives','Experiments','Experiment Groups','Request scoping','New variables','__lists__','aerchemmip-changelog']
152    self.cmip5sns = getCmip5Sns()
153    keys = sorted( self.rq.ee.keys() )
154    vdate = '20160309'
155##
156## this file has reference uids ... should be redundant ....
157##
158    vkdir = '/data/tmp/svn3/exarch/CMIP6dreqbuild/trunk/srcMisc'
159    self.vark = dreq_utils.varKeys( '%s/dreq_consol_tables_shelve_v%s' % (vkdir,vdate))
160    ee = {}
161    self.nvd = {}
162    self.idx = 0
163    self.shCols = ['Short name of group', 'Variable short name', 'Table', 'Frequency', 'Description extension (optional)', 'Shape', 'Levels', 'Time mean, point or climatology', 'Mask (optional)', 'Priority', 'MIP','uid','Prev. Var Name']
164##
165## array for information and debugging
166##
167    for mip in keys:
168        self.mip = mip
169        self.actions = collections.defaultdict( int )
170        self.shInfo = {'prov': '%s request template' % mip, 'label': mip, 'title': '%s request'}
171        fn = self.rq.ee[mip]
172        path = '%s%s/%s' % (self.rq.dir0,mip,fn)
173        self.path = path
174        stt = os.stat( path )
175        self.ctime = stt[stat.ST_CTIME]
176        self.fsize = stt[stat.ST_SIZE]
177        wb = workbook( path )
178        ss = []
179        for s in wb.sns:
180          if s not in omit:
181            ss.append(s)
182        self.sh = shelve.open( 'inSh/sh__grp_%s' % mip, 'n' )
183        self.sh['__cols__'] = self.shCols
184        self.sh['__info__'] = self.shInfo
185        self.sh['__src__'] = {'path':path, 'size':self.fsize, 'time':self.ctime}
186        ghr = None
187        for s in ss:
188          if s[:5] != 'CMIP5':
189           sh = wb.book.sheet_by_name( s )
190##
191## parse headers of sheet into named tuple "gh"
192##
193           self.gh = self.parseGrpHead(sh,path,mip,s)
194           assert ghr == None or ghr[:5] == self.gh[:5], 'Multiple sheet structures in single workbook .. NOT SUPPORTED: %s\n%s\n%s' % (path,self.gh,ghr)
195           ghr = self.gh
196           self.scanSheet( sh, self.gh, path, mip, s )
197        ee = {}
198        for k in ['withPriority', 'thisl', 'iv', 'it', 'start']:
199          ee = self.gh.__dict__[k]
200        self.sh['__recStr__'] =  ee
201        self.sh.close()
202
203        if 'New variables' in wb.sns:
204           sh = wb.book.sheet_by_name( 'New variables' )
205        self.sh = shelve.open( 'inSh/sh__newVar_%s' % mip, 'n' )
206        self.sh['__cols__'] = ['Short name', 'CF standard_name', 'standard name status', 'Native grid', 'units', 'Long Name', 'description/comments', 'Priority', 'associated observational dataset']
207        self.scanVars(sh)
208
209        self.sh.close()
210
211        for k in sorted( self.actions.keys() ):
212          print 'ACTIONS [%s]: %s (%s)' % (mip,k,self.actions[k])
213
214  def scanVars( self, sh ):
215     rh = [str(x.value) for x in sh.row(2)]
216     mode = 'nominal'
217
218     lumip_variant = ['Short name', 'CF proposed standard name for variable separated by land use type', 'CF standard_name', 'standard name status', 'Native grid', 'units', 'Long Name', 'description/comments', 'Priority', 'associated observational dataset']
219     if len(rh) >=10 and rh[:10] == lumip_variant:
220       mode = 'lumip'
221     elif len(rh) < 9 or rh[:9] != self.sh['__cols__']:
222        print 'ERROR .. change in column headings %s:\n ********** %s\n +++++++++++ %s' % (self.path,str(rh),str( self.sh['__cols__']) )
223
224     for i in range(3,sh.nrows):
225        r = sh.row(i)
226        if r[0].value == "**end**":
227          break
228
229        v = str(r[0].value)
230        l = r[4].value
231        novar = v == '' and l == ''
232        if not novar:
233          rr = [x.value for x in r]
234          assert v not in self.sh, 'duplicate variable definition %s in %s .. %s' % (v,self.path, str(r))
235          nbl = 0
236          for x in rr:
237            if x != '':
238              nbl += 1
239          if nbl < 3:
240            self.actions['Skipping mainly blank new variable record'] += 1
241          else:
242            if v.find('_') != -1:
243              v = v.replace( '_', '')
244              self.actions['Replacing underscore in new variable name'] += 1
245            if mode == 'lumip':
246              rr = rr[0:1] + rr[2:]
247              self.actions['LUMIP new variable adjustment'] += 1
248            self.sh[v] = rr
249             
250  def scanSheet(self, sh, gh, path, k, s ):
251       """Skips efforts to find a priority which were incorporated into the scan in dreq_consol_tables"""
252       irsh = 5
253       cc = collections.defaultdict( list )
254       for i in range(gh.start,sh.nrows):
255         rowIndex = i
256         thisr = sh.row(i)
257         v0 = str( thisr[0].value ) + '__'
258         if v0[0] != '#':
259           lll = getRowValues( thisr, minLen=gh.thisl, maxLen=gh.thisl )
260           if gh.iv == 0:
261                lll = getRowValues( thisr, minLen=gh.thisl, maxLen=gh.thisl )
262                lll[1] = lll[0]
263                lll[0] = gh.tv
264           else:
265                assert gh.iv == 1, 'gh.iv should be 0 or 1: %s' % gh.iv
266
267           if lll[1] == '*':
268              log.info( 'WARN.copy.00002: copy directive found ... copy not implemented: %s,%s:: %s' % (k,s,str(lll)) )
269           else:
270             if gh.thisl == 9:
271               lll.append( 105 )
272
273             assert len(lll) == 10,'bad record length ....'
274###
275### add mip name and space ...
276###
277             lll += [k,'']
278
279             self.ntr = nt__grptbl._make( lll )
280             if lll[2].find( '(' ) != -1:
281               bb = [x.strip() for x in lll[2].split( '(' )]
282               lll[2] = bb[0]
283               oldv = bb[1][:-1]
284             else:
285               oldv = ''
286##
287             if lll[0] in ['icesheetmon','icesheetyear','icesheetfx']:
288               otab = lll[0]
289               oshp = lll[5]
290##
291##  reduce doubly specified variables to single
292##
293               if lll[4] == 'Greenland':
294                 self.actions['skip Greenland'] += 1
295                 break
296               if lll[4] == 'Antarctica':
297                 lll[4] = ''
298##
299##  create two copies of all variables
300##
301               for targ in ['ant','gre']:
302                 lll[0] = maps.ttranstem[otab] + targ
303                 ku = self.vark.lookuprec( lll )
304                 lll[11] = ku
305                 lll[5] = oshp + targ
306                 self.saveRec( ku, lll + [oldv,rowIndex,] )
307               self.actions['duplicate ant/gre record'] += 1
308             else:
309               ku = self.vark.lookuprec( lll )
310               lll[11] = ku
311               self.saveRec( ku, lll + [oldv,rowIndex,] )
312
313  def saveRec( self, key, rr ):
314       nbl = 0
315       for x in rr:
316           if x != '':
317             nbl += 1
318##
319## 3 non-blank elements added above ...
320##
321       if nbl < 5:
322         self.actions['skipped mainly blank record %s' % self.gh.tv] += 1
323       else:
324         freq = self.freqmap.get( rr[3], rr[3] )
325         if freq != rr[3]:
326           self.actions['frequency map'] += 1
327           rr[3] = freq
328         if freq == '':
329           self.actions['blank frequency found in table %s' % self.gh.tv] += 1
330         grp = rr[0]
331         tbl = rr[2]
332         if grp == '':
333           print 'ERROR .. blank group: %s.%s:' % (self.mip,self.gh.tv), rr
334         if tbl == '':
335           print 'ERROR .. blank table: %s.%s:' % (self.mip,self.gh.tv), rr
336         if tbl in ['New Variables','NEW']:
337           rr[2] = 'new'
338           self.actions['table map'] += 1
339         var = rr[1]
340         if var.find('_') != -1:
341           rr[1] = var.replace('_','')
342           self.actions['underscore in variable name removed'] += 1
343         self.sh[key] = tuple( rr )
344
345  def parseGrpHead(self,sh,path,k,s):
346    rh1 = ['Short name', 'Standard Name', 'Table', 'Frequency', 'Description extension (optional)', 'Shape', 'Levels', 'Time mean, point or climatology', 'Mask (optional)']
347    rh2 = ['Short name of group', 'Variable short name', 'Table', 'Frequency', 'Description extension (optional)', 'Shape', 'Levels', 'Time mean, point or climatology', 'Mask (optional)']
348
349##
350## initial loop over rows in variable group sheet
351##
352    ll = []
353    for i in range(sh.nrows):
354             thisr = sh.row(i)
355             tv = thisr[0].value
356             if tv[:10] == 'Short name':
357               ll.append(i)
358
359    assert len(ll) in [1,2], 'Could not parse sheet  %s, %s, %s: %s' % (path,k,s,len(ll))
360    withPriority = False
361    hr = sh.row( ll[-1] )
362    if len(ll) == 1:
363             iv = 1
364             it = 0
365             ok = len( hr ) >= 9 and all( map( lambda x: hr[x].value.strip() == rh2[x], range(9) ) )
366             assert ok, '001: Sheet heading not recognised: %s (%s)' % (str(hr),path)
367             if len(hr) > 9 and hr[9].value == u'Priority':
368               withPriority = True
369               thisl = 10
370             else:
371               thisl = 9
372             tv = s
373    else:
374             ok = len( hr ) >= 9 and all( map( lambda x: hr[x].value.strip() == rh1[x], range(9) ) )
375             assert ok, '002: Sheet heading not recognised: %s' % str(hr)
376             iv = 0
377             it = -1
378             tv = sh.row(2)[1].value
379             thisl = 9
380    if tv == '':
381       print 'ERROR: blank group encountered: %s, %s' % (self.mip,s)
382    return nt__grphd( withPriority, thisl, iv, it, ll[-1]+1, tv)
383
384class stdo(object):
385  rq = dreq_cfg.rqcfg()
386
387  def __init__(self,dq=None):
388    self.actions = collections.defaultdict( int )
389##
390##
391## scanning CMIP5 after OMIP and CFMIP allows CMIP5 records to use variable ids from OMIP and CFMIP records,
392## which then enable subsetting done by other mips using CMIP5 tables to be interpreted
393##
394## BUT need to refer to CMIP5 tables from CFMIP
395##
396## need to redo with double pass here ... first for reference and then for mods.
397##
398    mips = ['OMIP','CFMIP','CMIP5'] + [k for k in self.rq.ff.keys() if k not in ['OMIP','CFMIP'] ]
399    ##self.rq.ff['CMIP5'] = ['/data/work/documents/CMIP5_standard_output.xls']
400    self.rq.ff['CMIP5'] = ['@ingest/CMIP5_standard_output.xls']
401    self.dq = dq
402
403    self.cmip5Tables = {}
404    self.cmip5TableVars = {}
405    self.refCmvSetup()
406    self.tabInfo = util_gen.tableInfo()
407    self.uidLookup = collections.defaultdict(dict)
408    self.uidLookupSn = collections.defaultdict(dict)
409
410    self.snch = snChange()
411
412    for mip in self.refCmv:
413      self.shref = shelve.open( 'inSh/sh__refso_%s' % mip, 'n' )
414      for fn in self.rq.ff[mip]:
415        self.scanFile(mip,fn,refMode=True)
416
417      for snnx in self.uidLookupSn:
418          for t in self.uidLookupSn[ snnx ]:
419            id,v,m = self.uidLookupSn[ snnx ][t]
420            if m == mip:
421              if id not in self.shref:
422                log.info( 'ERROR.lookupsn.0001: %s,%s,%s,%s,%s' % (mip,str(t),id,v,m) )
423               
424      self.shref.close()
425
426    addAerChem = True
427    if addAerChem:
428      self.shref = shelve.open( 'inSh/sh__refso_AerChemMIP', 'n' )
429      self.addAerChem()
430      self.shref.close()
431
432    for mip in mips:
433     for fn in self.rq.ff[mip]:
434       self.scanFile(mip,fn)
435
436    for k in sorted( self.actions.keys() ):
437          print 'ACTIONS: %s (%s)' % (k,self.actions[k])
438
439  def scanFile(self,mip,fn,refMode=False):
440
441## look for names of subsections, for OMIP.
442      if fn in self.rq.fff:
443        self.sss = self.rq.fff[fn]
444      else:
445        self.sss = mip
446
447      self.shInfo = {'prov': '%s standard_output' % mip, 'label': mip, 'title': '%s reviewed CMIP5 tables'}
448      self.shCols = ['priority', 'long name', 'units', 'comment', 'questions & notes', 'output variable name', 'CF Standard name', 'unconfirmed or proposed standard name', 'unformatted units', 'cell_methods', 'valid min', 'valid max', 'mean absolute min', 'mean absolute max', 'positive', 'type', 'CMOR dimensions', 'CMOR variable name', 'realm', 'frequency', 'cell_measures', 'flag_values', 'flag_meanings','empty','pchange','note','table','section','row']
449      self.istnm = self.shCols.index( 'CF Standard name' )
450      self.idims = self.shCols.index( 'CMOR dimensions' )
451
452      if fn[0] == '/':
453        self.fpath = fn
454      if fn[0] == '@':
455        self.fpath = fn[1:]
456      else:
457        self.fpath = '%s%s/%s' % (self.rq.dir0,mip,fn)
458
459      log.info( 'STARTING: %s' % self.fpath ) 
460
461      wb = workbook( self.fpath )
462      if not refMode and mip in self.refCmv:
463        self.sh = shelve.open( 'inSh/sh__so_%s' % mip )
464      else:
465        self.sh = shelve.open( 'inSh/sh__so_%s' % mip, 'n' )
466        self.sh['__cols__'] = self.shCols
467        self.sh['__info__'] = self.shInfo
468      stt = os.stat( self.fpath )
469      self.ctime = stt[stat.ST_CTIME]
470      self.fsize = stt[stat.ST_SIZE]
471      self.sh['__src__'] = {'path':self.fpath, 'size':self.fsize, 'time':self.ctime}
472
473      for sn in wb.sns:
474        if mip == 'OMIP':
475             snn = {'day':'Oday', 'fx':'Ofx'}.get( sn, sn )
476        else:
477             snn = sn
478
479        if sn not in ['general','dims','other output','CFMIP output']:
480          omitOn = False
481          if omitOn and mip in omitThese and sn in omitThese[mip]:
482            pass
483          else:
484            if refMode:
485              doThis = snn in self.refCmv[mip]
486            else:
487              doThis = mip not in self.refCmv or snn not in self.refCmv[mip]
488            if doThis:
489              sht = wb.book.sheet_by_name( sn )
490              self.scanSheet( sht, mip, snn,sn, refMode)
491      self.sh.close()
492
493  def scanSheet(self,sht,mip,snn,sname,refMode):
494      """Scanning CMIP5 style sheets"""
495      kl = []
496      for k in range(min(40,sht.nrows)):
497        if sht.row(k)[0].value == u'priority':
498          kl.append(k)
499         
500      if len(kl) == 0:
501        kk = 0
502        while len(sht.row(kk)) == 0 or sht.row(kk)[0].ctype not in (2,3):
503          kk += 1
504          assert kk < 40, 'No start found in %s %s %s' % (self.fpath,sname,str(kl))
505      else:
506        kk = kl[0] + 1
507
508      s1 = set()
509      thisTab = []
510      kok = 0
511      for k in range(kk,sht.nrows):
512        ok = True
513        rr  = sht.row(k)
514        rrr = [cleanStr(x) for x in rr]
515        for i in range( len(self.shCols) - len( rr) ):
516          rrr.append( '' )
517
518        ll = [x in ['','0.0','42'] for x in rrr]
519        nonblnk = sum( 1 for x in rrr if x not in ['','0.0'] )
520
521        if all( ll[1:6] ) and  all( ll[7:12] ):
522          if not all(ll):
523            log.info( 'INFO.var.0001: %s:%s[%s]: skipping: %s' % (mip,sname,k,str(rrr)) )
524        elif nonblnk < 5:
525            log.info( 'WARN.var.0002: %s:%s[%s]: skipping: %s' % (mip,sname,k,str(rrr)) )
526        else:
527          if rr[17].ctype == 1:
528                  vr = rrr[17]
529          else:
530                  vr = rrr[5]
531          if vr == 'include Amon 2D':
532            log.info( 'WARN.var.0003: %s:%s[%s]: skipping: %s' % (mip,sname,k,str(rrr)) )
533          elif vr == '' and rrr[1][:29] == 'Mole Fraction of Other Radiat':
534            log.info( 'WARN.var.0006: %s:%s[%s]: skipping: %s' % (mip,sname,k,str(rrr)) )
535          else:
536            v1 = rrr[5]
537            rrr[17] = vr
538            if vr == 'CMOR variable name':
539              ok = False
540
541            f1 = v1 in ['','0.0']
542            f2 = vr in ['','0.0']
543            if f1 or f2:
544              log.error( 'ERROR.var.0004: no variable found: [%s.%s] %s' % (mip,sname,str(rrr)) )
545              ok = False
546            v1 = rrr[2]
547            v2 = rrr[8]
548            f1 = v1 in ['','0.0']
549            f2 = v2 in ['','0.0']
550            if f1 and f2:
551              log.error( 'ERROR.var.0005: no units found: [%s.%s] %s' % (mip,sname,str(rrr)) )
552              ok = False
553            elif f1:
554              rrr[2] = v2
555
556            if ok:
557              s1.add( vr )
558              thisTab.append( rrr )
559              kok += 1
560
561      if mip == 'CMIP5':
562          self.cmip5Tables[snn] = tuple( thisTab )
563          self.cmip5TableVars[snn] = list( s1  )
564          toSh = True
565      else:
566          if snn not in self.cmip5Tables:
567             log.info( 'NEW Standard Output sheet name: %s, %s' % (mip,snn) ) 
568             toSh = True
569          elif len(thisTab) == len( self.cmip5Tables[snn] ):
570             nch = 0
571             for k in range(len(thisTab)):
572               if not self.compareMipTabRec( thisTab[k], self.cmip5Tables[snn][k]):
573                 nch += 1
574             if nch > 0:
575               log.info( 'MODIFIED Standard Output sheet: %s, %s: records changed: %s (%s)' % (mip,snn,nch,len( self.cmip5Tables[snn] ) ) ) 
576               toSh = True
577             else:
578               toSh = False
579               log.info( 'UNMODIFIED Standard Output sheet skipped: %s, %s' % (mip,snn )  )
580          else:
581             log.info( 'MODIFIED Standard Output sheet: %s, %s: length: %s (%s)' % (mip,snn,len(thisTab),len( self.cmip5Tables[snn] ) ) ) 
582             d1 = sorted( list (s1.difference( set( self.cmip5TableVars[snn] ) ) ))
583             d2 = sorted( list (set( self.cmip5TableVars[snn] ).difference( s1 ) ))
584             log.info( 'MODIFIED Standard Output sheet (.ctd): %s, %s: only here: %s, only CMIP5: %s' % (mip,snn,str(d1), str(d2) ) ) 
585             toSh = True
586
587      log.info( 'INFO.tosh.00001: %s, %s, %s, %s' % ( mip, sname, kok, toSh ) )
588      if toSh:
589        k = kk
590        for rrr in thisTab:
591          vr = rrr[17]
592          vo = rrr[5]
593          ##snn = {'OImon':'SImon'}.get(snn,snn)
594          ##snn = {'aero':'aermonthly'}.get(snn,snn)
595          if vr == 'cllcalipso':
596             log.info( 'INFO.cllcalipso.0001: %s, %s, %s, %s' % (mip,snn, mip in self.refCmv, snn in self.refCmv[mip]) )
597          omit = False
598          if mip in self.refCmv and snn in self.refCmv[mip]:
599             if mip in omitThese and snn in omitThese[mip]:
600                vid = str( uuid.uuid1() )
601                log.info( 'ERROR.newvid.00001: new vid minted for %s, %s, %s: %s' % (mip,sname,vr,vid) )
602                pass
603             else:
604                if vr in {'*','include Oyr 3D tracers'}:
605                   log.info( 'WARN.copy.00004: copy directive found ... copy not implemented: %s,%s:: %s' % (mip,sname,str(rrr)) )
606                   omit = True
607                   vid, sect = '',None
608                else:
609                  vid,sect = self.makeRefVarRec( rrr, k, snn, mip )
610                  log.info( 'INFO.sect.0005: sect=%s [%s,%s]' % (sect, snn, mip) )
611                if sect == 'Oyr_3dtr':
612                   rrrc = rrr[:]
613                   rrrc[0] = 2
614                   rrrc[16] = 'longitude latitude time depth0m'
615                   rrrc[19] = 'mon'
616                   rrrc[20] = 'area: areacello'
617                   rrrc[4] = 'Concentrations of all 3D tracers in the uppermost ocean layer. See first table in Oyr for a complete list of these tracers.  "Tracer"  concentations should be reported even if they are diagnosed rather than prognostically calculated.'
618                   vid,sect = self.makeRefVarRec( rrrc, 1000 + k, 'Omon', mip )
619                   log.info( 'INFO.copy.0005: copy to Omon of 3d-tracer : %s' % vr )
620                self.uidLookup[ snn ][vr] = vid
621                stnm = rrr[self.istnm]
622                dims = rrr[self.idims]
623                self.uidLookupSn[ snn ][(stnm,dims)] = (vid,vr,mip)
624          elif snn in ['OImon',]:
625                vid = str( uuid.uuid1() )
626                log.info( 'INFO.newvid.00002: new vid minted for %s, %s, %s' % (mip,sname,vr) )
627          else:
628                assert snn in self.uidLookup or snn == 'aero', 'Bad table name; %s; %s:: %s' % (mip,snn, str( self.uidLookup.keys() ) )
629                if vr in {'*','include Oyr 3D tracers'}:
630                   log.info( 'WARN.copy.00001: copy directive found ... copy not implemented: %s,%s:: %s' % (mip,sname,str(rrr)) )
631                   omit = True
632                elif snn == 'aero':
633                  if vr in self.uidLookup['aermonthly']:
634                    vid = self.uidLookup['aermonthly'][vr]
635                  elif vr in self.refUid['aermonthly']:
636                    vid = self.refUid['aermonthly'][vr]
637                    log.info( 'INFO.newvid.00088: vid from refUid for aermonthly %s, %s' % (vr,mip) )
638                  else:
639                    log.info( 'WARN.newvid.00088: new vid for aermonthly %s, %s' % (vr,mip) )
640                    vid = str( uuid.uuid1() )
641                elif vr in self.uidLookup[snn]:
642                  vid = self.uidLookup[snn][vr]
643                else:
644                  stnm = rrr[self.istnm]
645                  dims = rrr[self.idims]
646                  if (stnm,dims) in self.uidLookupSn[ snn ]:
647                    vr0 = vr
648                    vid,vr,mip0 = self.uidLookupSn[ snn ][(stnm,dims)]
649                    if vr != vr0:
650                      log.info( 'INFO.newvr.00001: new var name for %s, %s, %s: %s,%s,%s' % (mip,sname,vr0, vr,vid,mip0) )
651                  else:
652                    if snn in self.snch.omit and stnm in self.snch.omit[snn]:
653                      log.info( 'INFO.omit.00001: %s, %s, %s, %s' % (mip,sname,vr,stnm) )
654                      omit = True
655                    elif snn in self.snch.trigger and stnm in self.snch.trigger[snn]:
656                      log.info( 'INFO.trigger.00001: %s, %s, %s, %s' % (mip,sname,vr,stnm) )
657                      omit = True
658                    elif snn in self.snch.map and stnm in self.snch.map[snn]:
659                      st2 = self.snch.map[snn][stnm][0]
660                      if (st2,dims) in self.uidLookupSn[ snn ]:
661                        vid,vr,mip0 = self.uidLookupSn[ snn ][(st2,dims)]
662                        log.info( 'INFO.vmap.00001: %s, %s, %s, %s,%s' % (mip,sname,vr,stnm,st2) )
663                      else:
664                        log.info( 'INFO.newvid.00005: new vid minted for %s, %s, %s, %s' % (mip,sname,vr,stnm) )
665                        vid = str( uuid.uuid1() )
666                    else:
667                      log.info( 'INFO.newvid.00004: new vid minted for %s, %s, %s, %s' % (mip,sname,vr,stnm) )
668                      vid = str( uuid.uuid1() )
669          uid = str( uuid.uuid1() )
670
671          p = int( float( rrr[0] ) )
672          if rrr[24] != '':
673            prs = int( float( rrr[24] ) )
674            if prs == 0:
675              omit=True
676            elif prs == 2:
677              p=1
678## kk = ['var', 'table', 'mip', 'vid', 'priority']
679         
680          if not omit:
681            assert vo not in {'*','include Oyr 3D tracers'} and vr not in {'*','include Oyr 3D tracers'}, 'Bad vo,vr: %s,%s' % (vo,vr)
682            rec = [vr, '%s-%s' % (mip,snn), mip, str(vid), p  ]
683            self.sh[ uid ] = rec
684            k += 1
685
686  def addAerChem(self):
687    mip = 'AerChemMIP'
688    lc = util_gen.loadAerChem()
689    lsp = util_gen.loadSpatial()
690    self.sh = shelve.open( 'inSh/sh__so_%s' % mip, 'n' )
691    self.sh['__cols__'] = self.shCols
692    self.shInfo = {'prov': '%s request template, request scoping sheet' % mip, 'label': mip, 'title': 'CMIP6 Data Request'}
693    self.sh['__info__'] = self.shInfo
694    dmin = ['minpblz',]
695    dmax = ['maxpblz',]
696
697    self.nnss = 0
698    for tab in lc.cc2.keys():
699      nn = 0
700      for var in lc.cc2[tab].a:
701## ['air_temperature', 'Surface Air Temperature', 'tas', 'K', 'near-surface (usually, 2 meter) air temperature', 'AerChemMIP-Day2d', 'daily', 'XY-na', 'mean']
702        assert len( lc.cc2[tab].a[var] ) == 1, 'Multiple definitions for %s, %s' % (tab,var)
703         
704        sn, ln, v0, units, desc, sect, freq, splab, tlab = lc.cc2[tab].a[var][0]
705        assert splab in lsp.uidByLab, 'Spatial shape label %s not found' % splab
706        spid = lsp.uidByLab[splab]
707        spdims = lsp.ssu[spid][2]
708        assert tlab in ['mean','point'], 'Time dimension label %s not recognised' % tlab
709        tdim, cmet = {'mean':('time','time: mean'), 'point':('time1','')}[tlab]
710        if v0 in dmin:
711          cmet = 'time: minimum'
712        elif v0 in dmax:
713          cmet = 'time: maximum'
714        cmea = 'area: areacella'
715        dims = spdims + ' ' + tdim
716        p = 1
717        vid = '----'
718        gpid = '----'
719        if var not in self.refUid[tab]:
720            self.actions['WARNING: New uid generated for variable in %s %s' % (mip,tab)] += 1
721            uid =  str( uuid.uuid1() )
722            log.warn( 'WARN.uid.0001: new uid for %s (%s, %s): %s' % (var,mip,tab,uid) )
723        else:
724            uid = self.refUid[tab][var]
725        thisrealm = 'unset'
726        rec0 = [uid, desc, '', '', '', '', 'float', '', sn, '', ln, '', cmet, '', cmea, var, 'aerosol', units, '', '', '', var, tab, dims, vid, gpid, sect, p]
727      ##self.shCols = ['priority', 'long name', 'units', 'comment', 'questions & notes', 'output variable name', 'CF Standard name', 'unconfirmed or proposed standard name', 'unformatted units', 'cell_methods', 'valid min', 'valid max', 'mean absolute min', 'mean absolute max', 'positive', 'type', 'CMOR dimensions', 'CMOR variable name', 'realm', 'frequency', 'cell_measures', 'flag_values', 'flag_meanings','table','section','row']
728        rec0 = [p,ln, units, desc, '', var, sn, '', units, cmet, '','','','','','float',dims,var,'aerosol',freq,cmea,'','',tab,sect,-1]
729        rec = [var, tab, mip, str(uid), p  ]
730        self.sh[ uid ] = rec
731
732        nss = None
733        if sect in [u'AerChemMIP-Zonal2d',u'AerChemMIP-Zonal',u'AerChemMIP-Mon2d', u'Monthly-mean 2d', u'Monthly-mean 1d', u'Monthly-mean zonal mean 2d', u'Monthly-mean 2d (T2)', u'Monthly-mean zonal mean 2d (T2)']:
734          print 'INFO.aerchem.00010: ', rec
735          nss = 'aermonthly-oth'
736        elif sect in [ u'AerChemMIP-Mon3d',u'Monthly-mean 3d', u'Monthly-mean 3d (T2)']:
737          print 'INFO.aerchem.00020: ', rec
738          nss = 'aermonthly-3d'
739        if sect == 'Monthly-mean 2dxx':
740          print 'INFO.aerchem.00011: ', rec
741          nss = 'aermonthly-2d'
742        if sect == 'Daily 2d':
743          print 'INFO.aerchem.00021: ', rec
744          nss = 'aerdaily-2d'
745        if nss != None:
746          self.nnss += 1
747          self.sh[ str( uuid.uuid1() ) ] = rec
748          sect = nss
749        if sect in ['AerChemMIP-hr','AerChemMIP-Day2d','fx']:
750          sect = ''
751        else:
752          print 'INFO.aerchem.00050:  unrecognised section', sect, rec
753
754        lset = {'ssect':sect, 'uid':uid, 'rowIndex':-1, 'mipTable':tab}
755        ro = self._getRefRec(rec0,lset)
756        self.shref[uid] = ro
757    self.sh.close()
758
759  def makeRefVarRec( self, rrr, k, snn, mip ):
760    ## ['uuid', 'comment', 'deflate_level', 'shuffle', 'ok_max_mean_abs', 'flag_meanings', \
761     #                     'type', 'ok_min_mean_abs', 'standard_name', 'deflate', 'long_name', 'valid_min',\
762                           #'cell_methods', 'flag_values', 'cell_measures', 'out_name', 'modeling_realm', 'units',\
763                           #'#cell_methods', 'valid_max', 'positive', 'var', 'mipTable','dimensions','vid','gpid','ssect','priority']
764      ##self.shCols = ['priority', 'long name', 'units', 'comment', 'questions & notes', 'output variable name', 'CF Standard name', 'unconfirmed or proposed standard name', 'unformatted units', 'cell_methods', 'valid min', 'valid max', 'mean absolute min', 'mean absolute max', 'positive', 'type', 'CMOR dimensions', 'CMOR variable name', 'realm', 'frequency', 'cell_measures', 'flag_values', 'flag_meanings','table','section','row']
765    tab = self.refCmv[mip][snn]
766    isn = 6
767    var = rrr[17]
768    if var not in self.refUid[tab]:
769        self.actions['WARNING: New uid generated for variable in %s %s' % (mip,tab)] += 1
770        uid =  str( uuid.uuid1() )
771        log.warn( 'WARN.uid.0001: new uid for %s (%s, %s): %s' % (var,mip,tab,uid) )
772    else:
773      uid = self.refUid[tab][var]
774
775    sn = rrr[isn]
776    ln = rrr[1]
777    dims = rrr[16]
778    flg, sect = util_gen.sect(  mip, var, snn, k, dims, ln, isBgc=(self.sss == 'bgc') )
779    if not flg:
780       sect = ''
781
782    lset = {'ssect':sect, 'uid':uid, 'rowIndex':k, 'mipTable':tab}
783    ro = self._getRefRec(rrr,lset)
784    self.shref[uid] = ro
785    return uid,sect
786
787  def _getRefRec(self,rrr,lset):
788    defer = {'gpid','vid'}
789    redundant = {'shuffle','deflate_level', 'cell_methods_xx','deflate'}
790   
791    ro = []
792    for x in self.tabInfo.oh:
793      if x in defer:
794        v = '__deferred__'
795      elif x in lset:
796        v = lset[x]
797      elif x in redundant:
798        v = ''
799      elif x in self.tabInfo.ih:
800        v = rrr[ self.tabInfo.iix[x] ]
801      elif x in self.tabInfo.oix:
802        v = rrr[ self.tabInfo.oix[x] ]
803      else:
804        raise baseException( 'Table heading not found: %s' % x )
805
806      ro.append( v )
807    return ro
808     
809  def refCmvSetup(self, mode='new'):
810    self.refCmv = collections.defaultdict( dict )
811    self.tabMap = {}
812    self.refUid = collections.defaultdict( dict )
813    for x in targTabs:
814      if x[:5] == 'CMIP5':
815        mip,tab = x.split( '_' )
816      else:
817        mip,tab = x.split( '.' )
818      if mip == 'OMIP':
819        tab = {'day':'Oday', 'fx':'Ofx'}.get( tab, tab )
820      self.refCmv[mip][tab] = tab
821      self.tabMap[x] = (mip,tab)
822
823    if mode == 'new':
824      sh = shelve.open( 'inSh/refCmvId', 'r' )
825      for k in sh.keys():
826        tab, lab, ver = sh[k]
827        self.refUid[tab][lab] = k
828    else:
829      for i in self.dq.coll['CMORvar'].items:
830        self.refUid[i.mipTable][i.label] = i.uid
831
832  def compareMipTabRec( self, r1, r2 ):
833    if len(r1) != len(r2):
834      return False
835    return all( [r1[k] == r2[k] for k in [0,1,2,3,4,5,6,9,16,24] ] )
836
837class requestScope(object):
838  rq = dreq_cfg.rqcfg()
839
840  def __init__(self,sdir='inSh'):
841
842    keys = sorted( self.rq.ee.keys() )
843
844    ##self.vgss = util_varGroups.varGroupSs()
845    ##self.vgss.loadGroups()
846    ##self.vgss.setUid()
847##
848    ee = {}
849    self.shCols = ['Short name of group', 'Variable short name', 'Table', 'Frequency', 'Description extension (optional)', 'Shape', 'Levels', 'Time mean, point or climatology', 'Mask (optional)', 'Priority', 'MIP','uid','Prev. Var Name']
850##
851## array for information and debugging
852##
853    self.pr4 = dreq_utils.pr4()
854 
855    eh = {}
856    er = {}
857    for mip in keys:
858        self.mip = mip
859        self.actions = collections.defaultdict( int )
860        self.shInfo = {'prov': '%s request template, request scoping sheet' % mip, 'label': mip, 'title': '%s request'}
861        fn = self.rq.ee[mip]
862        path = '%s%s/%s' % (self.rq.dir0,mip,fn)
863        self.path = path
864        stt = os.stat( path )
865        self.ctime = stt[stat.ST_CTIME]
866        self.fsize = stt[stat.ST_SIZE]
867        wb = workbook( path )
868        if 'Request scoping' in wb.sns:
869          sh = wb.book.sheet_by_name( 'Request scoping' )
870          r4 = map( lambda x: x.value, sh.row(3) )
871          self.pr4.parse( self.mip, r4 )
872          eh[mip] = (list( self.pr4.r4info ), r4)
873          rl = self.scanSheet( sh, self.pr4.r4info )
874          print 'MIP:: %s, %s' % (mip, len(rl))
875          er[mip] = rl
876        else:
877          print 'Skipping ... no request scoping sheet: ',mip
878    sh = shelve.open( '%s/sh__requestScoping' % sdir, 'n' )
879    sh['__headings__'] = eh
880    sh['__records__'] = er
881    sh.close()
882
883  def scanSheet( self,sh, r4info ):
884    rl = []
885    gpmaps = {}
886    gpmaps['ISMIP6'] = {'icesheetfx':['LIfxgre','LIfxant'], 'icesheetyear':['LIyrgre','LIyrant'], 'icesheetmon':['LImongre','LImonant']}
887    gpmaps['VolMIP'] = {'DYVR_monthly':['DYVR_monthly_a','DYVR_monthly_b','DYVR_monthly_c','DYVR_monthly_d']}
888    for i in range(4,sh.nrows):
889      rr = [x.value for x in sh.row(i)]
890      if not (rr[0] in ['',u''] or rr[0][0] == '#'):
891        if self.mip == 'DCPP':
892          j0 = r4info.ownix[0]
893        else:
894          j0 = r4info.ixcntl
895        if all( [x in {u'','',0,0.0} for x in rr[j0:]] ):
896          if rr[1] != 'none':
897            print 'skipping blank line: ',self.mip,rr
898        elif rr[0] == 'Short name of variable group':
899            print 'skipping title line: ',self.mip,rr
900        elif rr[1] == 'none':
901            print 'skipping non-blank line marked as *none*:',self.mip,rr
902        else:
903          if self.mip in gpmaps and rr[0] in gpmaps[self.mip]:
904            rr0 = rr[0]
905            for x in gpmaps[self.mip][rr0]:
906              rr[0] = x
907              rl.append( rr[:] )
908          else:
909            rl.append( rr )
910    return rl
911
912if __name__ == '__main__':
913  #ts = templateStat()
914  rs = requestScope()
915  logFarm.shutdown() 
Note: See TracBrowser for help on using the repository browser.