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

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

updates

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