source: CMIP6dreqbuild/trunk/srcMisc/dreq_consol_dreq.py @ 770

Subversion URL: http://proj.badc.rl.ac.uk/svn/exarch/CMIP6dreqbuild/trunk/srcMisc/dreq_consol_dreq.py@1157
Revision 770, 17.5 KB checked in by mjuckes, 4 years ago (diff)

Extended overview tables, corrected content

Line 
1import string, uuid, shelve
2from fcc_utils2 import snlist
3import xlrd, string, shelve, os, re, sys
4import collections
5import xlutils, xlwt
6import xlutils.copy
7import xlutils.styles
8####
9import dreq_cfg
10import dreq_utils
11import utils_wb
12
13class localMaps(object):
14##
15## expand groups in request row ...
16##   .. duplicates all request items
17##
18    groupExpand = {'ISMIP6.icesheetmon':['LImonant','LImongre'],
19                   'ISMIP6.icesheetyear':['LIyrant','LIyrgre'],
20                   'ISMIP6.icesheetfx':['LIfxant','LIfxgre']}
21
22cmip5Vg = ['Omon','fx','Oyr','Oclim','Omon_3d','Omon_oth','Amon','Lmon','LImon','OImon','aero_3d','aero_oth','cfDay_2d','cfDay_3d','cfMon_3dstd','cfMon_3dmod','cfMon_2dmod','cfMon_sim','day_oth','day_ss','cfOff','cfSites','6hrLev','6hrPlev','3hr','cf3hr_grid','cf3hr_sim']
23cmip5Tabs = ['fx','Oyr','Oclim','Omon','Amon','Lmon','LImon','OImon','cfMon','aero','cfDay','day','cfOff','cfSites','6hrLev','6hrPlev','3hr','cf3hr']
24
25nt__deckrq = collections.namedtuple( 'dckrq', ['control','AMIP','abrupt4xCO2','rq_1pctCO2','historical'] )
26dd_rq = collections.defaultdict( dict )
27dd_tbl = collections.defaultdict( int )
28
29class wbcp(object):
30  def __init__( self, inbook=dreq_cfg.rqcfg.tmpl ):
31    self.book = xlrd.open_workbook(inbook,formatting_info=True)
32    self.sns = self.book.sheet_names()
33    self.wb = xlutils.copy.copy(self.book)
34    ##self.book = xlrd.open_workbook(inbook,formatting_info=True)
35    self.plain = xlwt.easyxf('')
36    self.styles = xlutils.styles.Styles(self.book)
37
38  def styleUpdate(self,other):
39    self.styles.cell_styles.update( other.styles.cell_styles )
40  def _getOutCell(self, rowIndex, colIndex,stbk=None):
41    """ HACK: Extract the internal xlwt cell representation. """
42   
43    if stbk == None:
44      this = self
45    else:
46      this = stbk
47    row = this.currentSo._Worksheet__rows.get(rowIndex)
48
49    if not row: return None
50
51    cell = row._Row__cells.get(colIndex)
52    return cell
53
54  def putValue2(self, row, col, value,sti=None,stj=None,stbk=None,style=0):
55    """ Change cell value without changing formatting. """
56    # HACK to retain cell style.
57    if sti == None:
58      sti = col
59    if stj == None:
60      stj = row
61    self.previousCell = self._getOutCell( stj,sti,stbk=stbk )
62    # END HACK, PART I
63
64    if style==0:
65      self.currentSo.write(row, col, value)
66    else:
67      self.currentSo.write(row, col, value,style=style)
68
69    # HACK, PART II
70
71    do_style = False
72    if self.previousCell and style==0 and do_style:
73        self.newCell = self._getOutCell( row, col)
74        if self.newCell:
75          if stbk == None:
76            self.newCell.xf_idx = self.previousCell.xf_idx
77          else:
78            self.newCell.xf_idx = self.previousCell.xf_idx
79            ##nn = len( self.styles.cell_styles.keys() )
80            ##print stj,sti,self.previousCell.xf_idx, nn
81            ##self.styles.cell_styles[nn] = stbk.styles.cell_styles.items()[self.previousCell.xf_idx]
82            ##self.newCell.xf_idx = nn
83    # END HACK
84
85  def focus( self, name ):
86    if name not in self.sns:
87       print '%s not in %s' % (name,str(self.sns) )
88       raise
89    self.currentIndex = self.sns.index(name)
90    if self.currentIndex == -1:
91      self.currentSi = None
92    else:
93      self.currentSi = self.book.sheet_by_name( name )
94      self.currentSo = self.wb.get_sheet( self.currentIndex )
95
96  def putValue(self,i,j,value,sti=None,stj=None):
97    ##self.currentSi.write(i,j,value,self.plain)
98    if sti == None:
99      sti = i
100    if stj == None:
101      stj = j
102    cell_style = self.styles[self.currentSi.cell(sti,stj)]
103    self.currentSo.write(i,j,value,cell_style)
104
105  def write(self,file='output.xls'):
106    self.wb.save( file )
107
108class workbook(object):
109  def __init__(self,file):
110    assert os.path.isfile(file), 'File %s not found' % file
111    self.book = xlrd.open_workbook( file )
112    self.sns = self.book.sheet_names()
113
114kk=3
115
116base = '/home/martin/2014/wip/dreq/'
117dir0 = '/home/martin/2014/wip/dreq/input/'
118file = 'PMIP/CMIP6DataRequestCompilationTemplate_20141218_PMIP_v150228_final.xls'
119file = 'C4MIP/CMIP6DataRequestCompilationTemplate_C4MIP_06March2015_submitted.xls'
120fileTmpl = 'CMIP6DataRequestCompilationTemplate_20141218.xls'
121
122wk0 = wbcp( inbook=base+fileTmpl )
123cfg = dreq_cfg.rqcfg()
124wk0.focus( u'Experiments')
125mlist = collections.defaultdict( list )
126for i in range(2,wk0.currentSi.nrows):
127  mip = str(wk0.currentSi.row(i)[3].value)
128  vals = map( lambda x: x.value, wk0.currentSi.row(i) )
129  if mip != '':
130    mlist[mip].append( vals )
131
132keys = mlist.keys()
133keys.sort()
134print keys
135
136mipTrans ={ 'geoMIP':'GeoMIP' }
137diagMips = ['DynVar','SIMIP','CORDEX']
138k2 = cfg.ee.keys()
139k2.sort()
140nn = 0
141for k in k2:
142  k = mipTrans.get( k,k)
143  if k not in keys and k not in diagMips:
144     print '%s not found' % k
145     nn += 1
146assert nn == 0, 'MIP naming error?'
147
148
149class rqsummary(object):
150  __doc__ = """Create a request summary table, by MIP and variable table.
151Creates a list of default dictionaries, one for each table. An entry for each MIP in each dictionary.
152"""
153
154  def __init__(self,exptInfo=None):
155    self.tablist = []
156    self.tabindx = {}
157    self.mips = collections.defaultdict( int )
158    self.exptInfo = exptInfo
159    self.rowList = []
160    self.records = []
161    self.headers = {}
162
163  def add(self,mip,path):
164    return rq(mip,path,parent=self)
165
166  def addRow( self, mip, tab, obj, grid, gok, comment,opt='',opar='',uid=None, preset=-2 ):
167    if uid == None:
168      k = str( uuid.uuid1() )
169    else:
170      k = uid
171    self.rowList.append( (k,mip,tab, obj, grid, gok, comment, opt, opar, preset) )
172    return k
173
174  def addItem( self, mip, tab, nn, nexmax, nenmax, nymax, expt=None, rid=None, treset=None, info=None ):
175    if not self.tabindx.has_key( tab ):
176      self.tabindx[tab] = len(self.tablist)
177      self.tablist.append( collections.defaultdict( int ) )
178    ix = self.tabindx[tab]
179    self.tablist[ix][mip] = nn
180    self.mips[mip] += 1
181    self.records.append( (mip,tab,expt, rid,nn, nexmax, nenmax, nymax,treset,info) )
182
183  def show(self,oo):
184    mips = self.mips.keys()
185    mips.sort()
186    keys = self.tabindx.keys()
187    keys.sort()
188    oo.write( ',' + string.join(mips, ',') + ',\n' )
189    for k in keys:
190      r = []
191      ix = self.tabindx[k]
192      for m in mips:
193        r.append( self.tablist[ix][m] )
194      print k,r
195      if max(r) > 0:
196        rec = '%s,' % k
197        for i in r:
198          rec += '%s,' %  i
199        oo.write( rec + '\n' )
200
201
202#dd_rq = collections.defaultdict( dict )
203#dd_tbl = collections.defaultdict( int )
204class rq(object):
205
206  def __init__(self, mip,path, parent=None ):
207    self.mip = mip
208    self.wk1 = wbcp( inbook=path )
209    self.pr4 = dreq_utils.pr4()
210    if u'Request scoping' in self.wk1.sns:
211      self.wk1.focus( u'Request scoping')
212
213      self.parent = parent
214      try:
215        self.ok = self.parse02()
216      except:
217        print 'Failed to parse: %s' % path
218        raise
219    else:
220      self.ok = False
221
222  def parse02(self):
223
224    r4 = map( lambda x: x.value, self.wk1.currentSi.row(3) )
225    r3 = map( lambda x: x.value, self.wk1.currentSi.row(2) )
226    self.pr4.parse( self.mip, r4 )
227    ##self.pr4.parse3( self.mip, r3 )
228    self.parent.headers[self.mip] = r4[:]
229    self.ixh = 0
230    self.ixm = 0
231    self.mipl = None
232    self.nbl = None
233    hhref = [u'control', u'AMIP', u'abrupt4xCO2', u'1pctCO2', u'CMIP6 historical']
234##
235## identify key start and end columns
236##
237## NEED to scan and check all expt. names.
238##
239    lega = False
240
241    ##self.opt = 'self'
242    ##self.opt = 'deck'
243    ##self.opt = 'all'
244    r4i = self.pr4.r4info
245    ##for j in self.nbl:
246    grids = set()
247    for j in range(5,self.wk1.currentSi.nrows):
248        rv = map( lambda x: x.value, self.wk1.currentSi.row(j)[:8] )
249        tab = rv[0]
250        if '%s.%s' % (self.mip,tab) in localMaps.groupExpand:
251          tabl = localMaps.groupExpand[ '%s.%s' % (self.mip,tab) ]
252        elif not( len(tab) > 0 and tab[0] == '#'):
253          tabl = [tab,]
254        else:
255          tabl = []
256        for tab in tabl:
257          grid = rv[3]
258          grids.add( grid )
259          gok = rv[r4i.mode-2]
260          comment = rv[r4i.mode-1]
261          obj0 = rv[r4i.mode]
262          bb = string.split(obj0, ':' )
263          if len(bb) > 1:
264            obj = bb[0]
265            preset = int( bb[1] )
266          else:
267            obj = obj0
268            preset = -1
269          opt = rv[1]
270          opar = rv[2]
271          uid = str( uuid.uuid1() )
272          nbl = False
273          if not tab in ['',u'']:
274            ##uid = self.parent.addRow( self.mip, tab, obj, grid, gok, comment, opt=opt, opar=opar )
275            if self.mip != 'DCPP':
276              for je in range(5):
277                j1 = r4i.ixcntl + je*2
278                ok = self.readDeckColPair( j, j1, 160, expt=string.strip(r4[j1]), rid=uid )
279                if ok:
280                  nbl = True
281            for je in r4i.ownix:
282                ok = self.readDeckColPair( j, je, 100, expt=string.strip(r4[je]), rid=uid )
283                if ok:
284                  nbl = True
285            for jei in range( len(r4i.othix) ):
286                je = r4i.othix[jei]
287                tr = r4i.treset[jei]
288                ok = self.readDeckColPair( j, je, 100, expt=string.strip(r4[je+1]), rid=uid,mode=3,treset=tr )
289                if ok:
290                  nbl = True
291### add row if non-blank element found
292          if nbl:
293              uid = self.parent.addRow( self.mip, tab, obj, grid, gok, comment, opt=opt, opar=opar, uid=uid, preset=preset )
294    print 'INFO.100.00001: grids for MIP %s: %s' % (self.mip, str(grids) )
295    return True
296
297  def readDeckColPair( self,j, ix, nydef, expt=None, rid=None, mode=2, treset=None ):
298      assert mode in [2,3], 'Only modes 2,3 supported, not mode=%s' % mode
299      this = map( lambda x: x.value, self.wk1.currentSi.row(j)[ix:ix+mode] )
300##  if this element is empty, return .. nothing to do.
301      if all( [x in {u'','',0,0.0} for x in this] ):
302        return False
303
304      if mode == 2:
305        snens, sny = this
306        cmt = '2:%s:%s:' % (snens,sny)
307      else:
308        snex, snens, sny = this
309        cmt = '3:%s:%s:%s:' % (snex,snens,sny)
310
311      nex = 0
312      nexmax = -999
313      if mode == 3:
314        print '######### MODE = 3: %s' % str(this)
315        if type( snex ) in  {type(u' '),type(' ')}:
316          if snex[:3] in {u'all',u'ALL'}:
317            nex = 5
318            nexmax = -1
319          elif snex[:3] in {u'tbd',u'TBD','tbd','TBD'}:
320            print 'WARN:005.0001: tbd encountered in experiment number'
321            nex = 5
322            cmt += '*'
323          else:
324            print 'ERROR.001.0010: string in experiment number: %s' % snex
325            nex = 0
326            cmt += '*'
327        else:
328          print 'WARN:005.0002: experiment number .... need to check consistency etc: %s' % self.mip
329          nex = int(snex)
330          nexmax = nex
331        if type(nex) not in {type(1.), type(1)}:
332          print 'ERROR.099.0100: non integer nex: %s:: %s:: %s' % (str(this),snex, type(snex))
333          raise
334
335      try:
336        if snens in [ u'all', u'ALL']:
337          nens = 1
338          nenmax = -1
339        elif snens == '':
340          nens = 0
341          nenmax = -999
342        else:
343          nens = int( snens )
344          nenmax = nens
345
346        if sny in [ u'all', u'ALL']:
347          ny = nydef
348          ony = 'all'
349          nymax = -1
350        elif sny == '':
351          ny = 0
352          ony = 0
353          nymax = -999
354        elif type(sny) in [type('x'),type(u'x')]:
355            s = sny
356            if string.find( s, '\n' ) != -1:
357              bits = string.split( s, '\n' )
358              ny = int( bits[0] )
359              nymax = ny
360              cmt += '*'
361              print 'WARN.001.0001: [%s] truncating time period option: %s' % (self.mip, str(s) )
362            else:
363              x = string.split( s )[0]
364              if string.find( x, '-' ) != -1:
365                bb = string.split(x, '-' )
366                ny = int(bb[1])-int(bb[0])
367                print 'WARN.001.0002: [%s] truncating time period option: %s' % (self.mip, str(s) )
368                nymax = ny
369              elif string.find( x, '/' ) != -1:
370                bb = string.split(x, '/' )
371                ny = int(bb[0])
372                print 'WARN.001.0003: [%s] truncating time period option: %s' % (self.mip, str(s) )
373                nymax = ny
374              else:
375                print 'WARN.001.0004: [%s] time period option read as string: %s' % (self.mip, str(s) )
376                ny = int( x )
377                nymax = ny
378        else:
379          ny = sny
380          nymax = ny
381
382        if type( ny ) in [type( 'x' ),type( u'x' )]:
383          bits = string.split(ny) 
384          if bits[1] == u'period':
385            bb = string.split( bits[0], '-' )
386            ny = int(bb[1]) - int(bb[0])
387            raise
388
389        tab = self.wk1.currentSi.row(j)[0].value
390        try:
391          if mode == 2:
392            ntot = nens*ny
393          else:
394            ntot = nex*nens*ny
395          if type(ntot) not in {type(1.), type(1)}:
396            print 'ERROR.099.0101: non integer ntot: %s:: %s' % (str([mode,nex,nens,ny]),str(this))
397            raise
398        except:
399          print self.mip, tab, nens, ny
400          raise
401        if tab in self.wk1.sns:
402          tab = '%s:%s' % (self.mip,tab)
403        elif tab not in cmip5Vg:
404          if not ( tab[:5] == 'SPECS' or tab[:4] == 'CCMI' ):
405            tab = '%s!!%s' % (self.mip,tab)
406
407        self.parent.addItem( self.mip, tab, ntot, nexmax, nenmax, nymax, expt=expt, rid=rid, treset=treset, info=sny )
408        return True
409      except:
410        print 'ERROR.002.0001: Failed trying to scan deck column pair.'
411        print self.mip,expt
412        raise
413
414#https://secure.simplistix.co.uk/svn/xlwt/tags/0.7.2/xlwt/Style.py
415## following style used for a changed cell.
416style_string = "border: top thick, right thick, bottom thick, left thick; pattern: pattern fine_dots, fore_color white, back_color yellow;"
417deltaStyle = xlwt.easyxf(style_string)
418## following style is used in the 1st column if there is a change somewhere in the row and not in 1st column
419style_string = "border: top thick, right thick, bottom thick, left thick; pattern: pattern fine_dots, fore_color white, back_color orange;"
420delta0Style = xlwt.easyxf(style_string)
421style_string = "border: top thin, right thin, bottom thin, left thin; pattern: pattern fine_dots, fore_color white, back_color pale_blue;"
422toggleStyle = xlwt.easyxf(style_string)
423mipPrev=None
424ktog = 0
425jj = 2
426
427wb = utils_wb.workbook( 'CMIP6DataRequest_ConsolidatedExperiments_20160714.xls' )
428sht = wb.book.sheet_by_name( 'Experiments' )
429p = dreq_utils.prconsolexpt()
430p.parse(sht)
431
432rqs= rqsummary()
433
434##for k in keys:
435for k in k2:
436  ktog = 1 - ktog
437  if k in k2:
438    path = '%s%s/%s' % (dir0,k,cfg.ee[k])
439    print path
440    thisrq = rqs.add( k, path )
441    if thisrq.ok:
442      print thisrq.ok, k, thisrq.ixh, thisrq.ixm, thisrq.mipl
443    else:
444      print thisrq.ok, k
445
446oo = open( 'request.csv', 'w' )
447rqs.show( oo )
448oo.close()
449
450##sh = shelve.open( 'dreq_consol_tables_reviewed_b_v20150827', 'r' )
451sh = shelve.open( 'dreq_consol_tables_reviewed_b_v20150907', 'r' )
452revTabIds = sh.keys()[:]
453sh.close()
454odir = 'sh20150708'
455odir = 'sh20150827'
456### need to split this, so that a collection of variables can be used in more than one request row.
457## check for duplicates
458## look to see if a reference to, e.g. Omon is CMIP5 or a revised list ....
459### requestVarGroup = mip, label, title, uuid
460### requestLinks = vgid, objective, grid, gridreq, comment, uuid -- inherits label and title
461sh = shelve.open( '%s/requestVarGroup_tmp' % odir, 'n' )
462sh['__info__'] = { 'label':'requestVarGroup_tmp', 'title':'Identify variable groups' }
463sh['__cols__'] = [ 'uuid', 'mip', 'label','title']
464rvgps = collections.defaultdict( list )
465### need to give temporary labels/titles here and consolidate after all variables have been collated in
466### sx2.
467## rows from "request scoping"
468for i in rqs.rowList:
469  kk ='%s.%s' % (i[1],i[2])
470  rvgps[kk].append(i) 
471
472for k in rvgps.keys():
473  if len(rvgps[k]) > 1:
474    print 'WARN.010.0005: ',k,'############# MULTIPLE ENTRIES'
475    for i in rvgps[k]:
476      print i
477  for i in rvgps[k]:
478    print 'requestVarGroup: %s' % str(i)
479    sh[i[0]] = (i[0],i[1],k,k)
480sh.close()
481
482s1 = set()
483sh = shelve.open( '%s/requestLinks_tmp' % odir, 'n' )
484sh['__info__'] = { 'label':'requestLinks', 'title':'Links from variable groups to a request id' }
485sh['__cols__'] = [ 'uid', 'mip', 'tab','objective','grid','gridreq','comment','opt','opar', 'preset']
486for i in rqs.rowList:
487  sh[i[0]] = i[:]
488  if i[3] in {'',u''}:
489    print 'ERROR.099.0060: Blank objective: %s' % str(i)
490  s1.add( i[0] )
491sh.close()
492sh = shelve.open( '%s/requestItems' % odir, 'n' )
493sh['__info__'] = { 'label':'requestItems', 'title':'Specification for a single experiment' , \
494     'comment':'Currently only has number of years -- need to include more details' }
495sh['__cols__'] = [ 'mip', 'tab', 'expt','rlid','ny', 'nexmax', 'nenmax', 'nymax','treset','info']
496##('AerChemMIP', u'Omon_3d', u'CMIP6 historical', 'ad74be9a-26ef-11e5-8d9b-ac72891c3257', 0.0)
497for i in rqs.records:
498  if type(i[4]) not in ( type(0), type(1.) ):
499      print 'ERROR.099.0001: non-integer ny: %s' % str(i)
500  expt = i[2]
501  if string.find( expt, '(' ) != -1:
502    expt = string.strip( expt[:string.find( expt, '(' )] )
503  if i[3] not in s1:
504    print 'SEVERE.005.00009: bad link ',i
505  if string.find( expt, ',' ) != -1 or (string.find( expt, ' ' ) != -1 and expt != "CMIP6 historical"):
506    bits = map( lambda x: string.strip(x), string.split( expt, ',' ) )
507    print 'INFO.expt.00006: ',i[:3], bits
508    for b in bits:
509      il = list(i)
510      il[2] = b
511      bb = dreq_utils.labcoerce(b)
512      if b not in p.edict and bb not in p.edict:
513        print 'ERROR.expt.00007: experiment %s not found, %s' % (b,str(il))
514      k = str( uuid.uuid1() )
515      sh[k] =  il[:] 
516  else:
517    k = str( uuid.uuid1() )
518    if expt != i[2]:
519      il = list(i)
520      il[2] = expt
521      sh[k] =  il[:] 
522    else:
523      sh[k] =  i[:] 
524sh.close()
Note: See TracBrowser for help on using the repository browser.