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