source: CMIP6dreq/trunk/dreqPy/overviewTabs.py @ 1324

Subversion URL: http://proj.badc.rl.ac.uk/svn/exarch/CMIP6dreq/trunk/dreqPy/overviewTabs.py
Revision 1324, 12.3 KB checked in by mjuckes, 6 months ago (diff)

01.00.31beta

Line 
1import collections, os
2import xlsxwriter
3
4try:
5  import dreq
6  import scope_utils
7  import table_utils
8except:
9  import dreqPy.dreq as dreq
10  import dreqPy.scope_utils as scope_utils
11  import dreqPy.table_utils as table_utils
12
13jsh='''
14<link type="text/css" href="/css/dreq.css" rel="Stylesheet" />
15%s
16''' % dreq.dreqMonitoring
17
18##
19## "T" and "G" used for "TB" and "GB" in order to squeeze table onto one page
20##
21def vfmt( x ):
22            if x < 1.e9:
23              s = '%sM' % int( x*1.e-6 )
24            elif x < 1.e12:
25              s = '%sG' % int( x*1.e-9 )
26            elif x < 1.e13:
27              s = '%3.1fT' % ( x*1.e-12 )
28            elif x < 1.e15:
29              s = '%3iT' % int( x*1.e-12 )
30            elif x < 1.e18:
31              s = '%3iP' % int( x*1.e-15 )
32            else:
33              s = '{:,.2f}B'.format( x*1.e-9 ) 
34            return s
35
36class c1(object):
37  def __init__(self):
38    self.a = collections.defaultdict( int )
39
40class c2(object):
41  def __init__(self):
42    self.a = collections.defaultdict( list )
43
44hmap0 = {'CMIP6':'Historical', 'ScenarioMIP':'\cellcolor{llgray} ScenarioMIP'}
45hmaph0 = {'CMIP6':'Historical', 'ScenarioMIP':'ScenarioMIP'}
46class r1(object):
47  infoLog = collections.defaultdict( list )
48  def __init__(self,sc,mt_tables,tiermax=1,pmax=1,only=False,vols=None,fnm='new',msgLevel=0):
49    self.mt_tables = mt_tables
50    self.msgLevel = msgLevel
51
52    self.fnm = fnm
53    assert vols == None or type(vols) == type( () ), 'vols argument must be none or tuple of length 2: %s' % type(vols)
54    self.dq = sc.dq
55    self.mips = ['CMIP'] + scope_utils.mips
56    self.mipsp = self.mips[:-3]
57    self.mipsp.remove( 'VIACSAB' ) 
58    self.sc = sc
59    self.pmax=pmax
60    self.efnsfx = ''
61    if sc.gridPolicyDefaultNative:
62        self.efnsfx = '_dn'
63    self.cc = collections.defaultdict( c1 )
64    self.ee = {}
65    for m2 in self.mipsp + ['TOTAL',]:
66        xx = [i for i in self.dq.coll['experiment'].items if i.mip == m2]
67        self.ee[m2] = xx
68
69    if vols != None:
70      assert len(vols) == 4, 'vols must be a tuple of length 4 (containing dictionaries ...): %s' % len(vols)
71      self.tiermax = sc.tierMax
72      vmm, vme, vmmt, vue = vols
73      for m in vmm:
74        for m2 in vmm[m]:
75          self.cc[m].a[m2] = vmm[m][m2]
76          if m2 != 'Unique':
77            self.cc[m].a['TOTAL'] += vmm[m][m2]
78
79      for m in vme:
80        for e in vme[m]:
81          i = sc.dq.inx.uid[e]
82          if i._h.label == 'experiment':
83            self.cc[m].a[i.label] = vme[m][e]
84
85      for m in vue:
86        for e in vue[m]:
87          i = sc.dq.inx.uid[e]
88          if i._h.label == 'experiment':
89            self.cc['_%s' % m].a[i.label] = vue[m][e]
90
91      for m in vmmt:
92        for m2,t in vmmt[m]: 
93           self.cc['_%s_%s' % (m,m2)].a[t] = vmmt[m][(m2,t)]
94           if m2 != 'Unique':
95             self.cc['_%s_%s' % (m,'TOTAL')].a[t] += vmmt[m][(m2,t)]
96           self.makeMMhtml(m,m2)
97        self.makeMMhtml(m,'TOTAL')
98
99      self.writeMips(True)
100      return
101    self.mode = 'def'
102
103    self.tiermax=tiermax
104    sc.setTierMax( tiermax )
105    tabs = self.mt_tables( sc )
106
107    mipsToDo = self.mips + ['TOTAL',]
108    assert 'SolarMIP' not in mipsToDo, 'SolarMIP error: %s ' % str(mipsToDo)
109    assert 'SolarMIP' not in self.mipsp, 'SolarMIP error: %s ' % str(self.mipsp)
110    if only != False:
111      mipsToDo = [only,]
112    for m in mipsToDo:
113      if m == 'TOTAL':
114        l1 = sc.rqiByMip( set( self.mips ) )
115      else:
116        l1 = sc.rqiByMip( m )
117
118      self.cc[m].dd = {}
119      tabs.accReset()
120##
121## need to check this option, and add a template for a view summarising the experiments for each mip-mip combinations
122##
123## sss=True not yet tested
124##
125      for m2 in self.mipsp + ['TOTAL',]:
126        sss = True
127        if sss:
128          for i in xx:
129            tabs.doTable(m,l1,i.uid,pmax,self.cc,acc=False)
130          tabs.doTable(m,l1,m2,pmax,self.cc)
131          if only == False:
132            self.makeMMhtml(m,m2)
133        else:
134          tabs.doTable(m,l1,m2,pmax,self.cc)
135
136    if only == False:
137      self.writeMips(sss)
138
139  def makeMMhtml(self,m,m2):
140    """Make a html page for data requested by MIP 'm' from MIP 'm2' experiments"""
141    if self.fnm == 'new':
142      fss = 'expt_%s_%s_%s_%s%s.html' % (m,m2,self.tiermax, self.pmax,self.efnsfx)
143    else:
144      fss = '%s-%s_%s_%s.html' % (m,m2,self.tiermax, self.pmax)
145    kc = '_%s_%s' % (m,m2)
146    self.infoLog[ 'INFO.mmhtml.00001' ].append( ' %s, %s' % (kc,len( self.cc[kc].a.keys() ) ) )
147    ##print ('INFO.mmhtml.00001: %s, %s' % (kc,len( self.cc[kc].a.keys() ) ) )
148    if len( self.cc[kc].a.keys() ) == 0:
149      return
150    if not os.path.isdir( 'html/tabs03' ):
151      print ( 'WARNING.makeMMhtml: creating directory for html files: tabs03' )
152      os.mkdir( 'html/tabs03' )
153    oo = open( 'html/tabs03/%s' % fss, 'w' )
154    ttl = 'Data requested by %s from %s experiments (tier %s, priority %s)' % (m,m2,self.tiermax,self.pmax)
155    jsh = ''
156    pream = '<h1>%s</h1>\n' % ttl
157    if self.efnsfx == '_dn':
158      pream += '<p>Using the native ocean grid when no explicit preference is specified in the request.</p>\n'
159    if self.fnm == 'new':
160      pream += '<p>All variables in one <a href="../data/tabs02/cmvmm_%s_%s_%s_%s%s.xlsx">Excel file</a></p>\n' % (m,m2,self.tiermax, self.pmax,self.efnsfx)
161    else:
162      pream += '<p>All variables in one <a href="../data/tabs02/%s-%s_%s_%s.xlsx">Excel file</a></p>\n' % (m,m2,self.tiermax, self.pmax)
163    pream += '<ul>'
164    kc = '_%s_%s' % (m,m2)
165    for k in sorted( self.cc[kc].a.keys() ):
166      pream += '<li>%s: %s</li>\n' % (k,vfmt(self.cc[kc].a[k]*2.) )
167    pream += '</ul>'
168
169    bdy = pream + '<table>\n'
170    bdy += '<tr><th>Experiment</th><th>Volume (and link to variable lists)</th></tr>\n'
171    thisee = self.cc[m].a
172    pref = 'cmvme'
173    if  m2 in ['TOTAL']:
174      labs = sorted( [x for x in self.cc[m].a.keys() if x in self.sc.exptByLabel] )
175    elif m2 in ['Unique']:
176      labs = sorted( [x for x in self.cc['_%s' % m ].a.keys() if x in self.sc.exptByLabel] )
177      thisee = self.cc['_%s' % m].a
178      pref = 'cmvume'
179    else:
180      try:
181        assert m2 in self.ee, 'Argument m2:%s not in self.ee' % m2
182        assert m in self.cc, 'Argument m:%s not in self.cc' % m
183        labs = sorted( [i.label for i in self.ee[m2] if (i.label in self.cc[m].a and i._h.label == 'experiment')] )
184      except:
185        print ( 'SEVERE: failed to create labs array' )
186        labs = []
187
188    for ilab in labs:
189        x = thisee[ilab]*2.
190        if x > 0:
191          s = vfmt( x )
192          if self.fnm == 'new':
193            bdy += '<tr><td>%s</td><td><a href="../data/tabs02/%s_%s_%s_%s_%s%s.xlsx">%s</a></td></tr>\n' % (ilab,pref,m,ilab,self.tiermax, self.pmax,self.efnsfx,s)
194          else:
195            bdy += '<tr><td>%s</td><td><a href="../data/tabs02/%s-%s_%s_%s.xlsx">%s</a></td></tr>\n' % (ilab,m,ilab,self.tiermax, self.pmax,s)
196
197    bdy += '</table>\n'
198
199    oo.write( self.dq.pageTmpl % (ttl, jsh, '../', '../index.html', bdy ) )
200    oo.close()
201   
202  def writeMips(self,sss=False):
203
204    oo = open( 'tab01_%s_%s.texfrag' % (self.tiermax,self.pmax), 'w' )
205    mmh = []
206    mhdr = [ '\\rot{80}{%s}' % hmap0.get(m,m) for m in self.mipsp + ['TOTAL','Unique']]
207    mhdrh = [ '<th><div><span>%s</span></div></th>' % hmaph0.get(m,m) for m in self.mipsp + ['TOTAL','Unique','CALC']]
208    oo.write( ' & '.join(['',] + mhdr ) + '\\\\ \n\\hline\n' )
209    mmh.append( '<table>\n<tr class="rotate">' + ''.join(['<th></th>',] + mhdrh ) + '</tr>\n' )
210    htmltmpl_head = '<html><body>\n' 
211
212##
213## the "oo1" tables need a little more work to be useful
214## not supported by the "vols" entry option of this class
215##
216    doOo1 = False
217    rows = self.mips + ['TOTAL',]
218    rows.remove( 'ScenarioMIP' )
219
220    for m in rows:
221      if m  == 'TOTAL':
222        ll = ['UNION',]
223        llh = ['UNION',]
224      else:
225        ll = [m,]
226        llh = [m,]
227      ttl = 0.
228      cct = collections.defaultdict( int )
229      xt = 0.
230      for m2 in self.mipsp + ['TOTAL','Unique']:
231       if doOo1:
232         if m2 in self.cc[m].dd:
233           oo1 = open( 'html/tt/rq-%s-expt-%s.html' % (m,m2), 'w' )
234           oo1.write( htmltmpl_head  )
235           oo1.write( '''<div class="demo">\n<div id="tabs">\n<ul>''' )
236           ks = sorted( self.cc[m].dd[m2].keys() )
237           for t in ks:
238              this1 = '<li><a href="#tabs-%s">%s</a></li>' % (t,t )
239              oo1.write( this1 )
240           oo1.write( '</ul>' )
241           for k in ks:
242               oo1.write( '<div id="tabs-%s">\n' % k )
243               oo1.write( '<table><tr>' )
244               for h in ['Frequency','Table','Label','Title','Description','UID' ]:
245                 oo1.write( '<td>%s</td>' % h )
246               for t in self.cc[m].dd[m2][k]:
247                 oo1.write( '\n</tr><tr>\n' )
248                 oo1.write( ''.join( ['<td>%s</td>' % x for x in t ] ) + '\n' )
249               oo1.write( '</tr></table></div>\n' )
250   
251           oo1.write( '</body></html>' )
252           oo1.close()
253       
254       if self.cc[m].a[m2] == 0:
255          ll.append( '' )
256          llh.append( '' )
257       else:
258          try:
259            if m2 == 'TOTAL':
260              x = xt
261            else:
262              x = self.cc[m].a[m2]*2.
263              xt += x
264
265            s = vfmt( x )
266            kc = '_%s_%s' % (m,m2)
267            if m2 == 'TOTAL':
268              sm = '; '.join( ['%s: %s' % (k,vfmt(cct[k]*2.)) for k in sorted( cct ) ] )
269              if self.msgLevel > 1:
270                print ( 'INFO.overviewTabs.01001: %s, %s' % (m,cct) )
271              s1 = '<b><span title="%s">%s</span></b>' % (sm,s)
272              ll.append( '<b>%s</b>' % s )
273            else:
274              for k in self.cc[kc].a.keys():
275                cct[k] += self.cc[kc].a[k]
276              ll.append( s )
277            sm = '; '.join( ['%s: %s' % (k,vfmt(self.cc[kc].a[k]*2.)) for k in sorted( self.cc[kc].a.keys() ) ] )
278
279            if sss:
280              if self.fnm == 'new':
281                fss = 'expt_%s_%s_%s_%s%s.html' % (m,m2,self.tiermax, self.pmax,self.efnsfx)
282              else:
283                fss = '%s-%s_%s_%s.html' % (m,m2,self.tiermax, self.pmax)
284              llh.append( '<a title="By table: %s" href="tabs03/%s">%s</a>' % (sm,fss,s) )
285            else:
286              llh.append( '<a title="By table: %s" href="data/tabs02/%s">%s</a>' % (sm,fn,s) )
287          except:
288            print ( 'Failed to compute element: %s,%s  %s' % (m,m2, str(self.cc[m].a[m2]) ) )
289            raise
290      if m == 'VIACSAB':
291        oo.write( ' & \cellcolor{llgray} '.join(ll ) + '\\\\ \n\\hline\n' )
292      else:
293        this = ll[:]
294        this[2] = '\cellcolor{llgray} ' + this[2]
295        oo.write( ' & '.join(this) + '\\\\ \n\\hline\n' )
296
297      llh.append( '<a href="data/tabs02/requestVol_%s_%s_%s.xlsx">Workings</a>' % (m,self.tiermax, self.pmax) )
298      mmh.append( '<tr>' + ''.join(['<td>%s</td>' % x for x in llh] ) + '</tr>\n' )
299    mmh.append( '</table>' )
300    ttl = 'Data volume overview, upto tier %s and priority %s -- provisional' % (self.tiermax, self.pmax) 
301    if self.sc.gridPolicyDefaultNative:
302      defNat = 'For volume estimation, ocean data is assumed to be on the model native grid unless specifically requested on an interpolated grid'
303    else:
304      defNat = 'For volume estimation, ocean data is assumed to be on a regular 1-degree grid unless specifically requested on another grid (e.g. the native model grid)'
305    bdy = '''<h1>%(ttl)s</h1>
306<p>Data volumes are estimated for nominal model with 1 degree resolution and 40 levels in the atmosphere and 0.5 degrees with 60 levels in the ocean.  The "Requesting MIP" (rows) is the MIP specifying the data required to meet their scientific objectives. The "designing MIP" (columns) is the MIP specifying the experimental design. %(defNat)s <b>The figures below represent work in progress: there are still omissions and flaws, more details are on the
307<a href="https://earthsystemcog.org/projects/wip/CMIP6DataRequest" title="Data Request CoG page">Data Request home page</a>.</b></p>
308''' % {'ttl':ttl, 'defNat':defNat }
309    bdy += '\n'.join( mmh )
310    ooh = open( 'tab01_%s_%s%s.html' % (self.tiermax,self.pmax,self.efnsfx), 'w' )
311    ooh.write( self.dq.pageTmpl % (ttl, jsh, './', './index.html', bdy ) )
312    ooh.close()
313    oo.close()
314
315if __name__ == "__main__":
316  try:
317    import makeTables
318    import scope
319  except:
320    import dreqPy.scope as scope
321    import dreqPy.makeTables as makeTables
322  sc = scope.dreqQuery()
323  r = r1( sc, table_utils.tables, tiermax=1, pmax=1 )
324  r = r1( sc, table_utils.tables, tiermax=3, pmax=3 )
Note: See TracBrowser for help on using the repository browser.