source: CMIP6dreqbuild/trunk/src/framework/dreqPy/scope.py @ 895

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

debugging commandline options -- removing hidden settings

Line 
1"""Date Request Scoping module
2------------------------------
3The scope.py module contains the dreqQuery class and a set of ancilliary functions. The dreqQuery class contains methods for analysing the data request.
4"""
5
6try:
7  import dreq
8  imm=1
9except:
10  import dreqPy.dreq  as dreq
11  imm=2
12
13if imm == 1:
14  from utilities import cmvFilter, gridOptionSort
15  import makeTables
16  import fgrid
17  import volsum
18else:
19  import dreqPy.volsum as volsum
20  import dreqPy.fgrid as fgrid
21  from dreqPy.utilities import cmvFilter, gridOptionSort
22  import dreqPy.makeTables as makeTables
23
24import collections, string, operator
25import sys, os
26
27if sys.version_info >= (2,7):
28  oldpython = False
29else:
30  oldpython = True
31
32gridSorter = gridOptionSort( oldpython )
33
34def sortTimeSlice( tsl ):
35 
36  s = set()
37  for ts in tsl:
38    if ts[0] == None:
39      return (1,ts,'Taking unsliced option')
40    s.add( ts[0][1] )
41  if len(s) > 1:
42    return (-1,None,'Multiple slice types')
43  tst = s.pop()
44  if not ( tst == 'simpleRange' or (len(tst) > 13 and tst[:13] == 'branchedYears') ):
45    return (-2,None,'slice type aggregation not supported')
46  if len(tsl) == 2:
47    tsll = list( tsl )
48    sa,ea = tsll[0][0][2:]
49    sb,eb = tsll[1][0][2:]
50    if sa <= sb and ea >= eb:
51      return (1,tsll[0], 'Taking largest slice')
52    if sb <= sa and eb >= ea:
53      return (1,tsll[1], 'Taking largest slice')
54    if ea < sb or eb < sa:
55      return (2,tsll, 'Slices are disjoint')
56    return (-3,None, 'Overlapping slices')
57  else:
58    tsll = sorted( list(tsl), key=lambda x: x[0][3] )
59    if min( [x[0][2] for x in tsll] ) == tsll[-1][0][2]:
60        return (1,tsll[0][-1], 'Taking largest slice')
61    return (-4,None, 'Cannot sort slices')
62
63odsz = {'landUse':(5,'free'), 'tau':7, 'scatratio':15, 'effectRadLi|tau':(28,'query pending'), 'vegtype':(8,'free'), 'sza5':5, 'site':(119,'73 for aquaplanet .. '), 'iceband':(5,'free'), 'dbze':15, 'spectband':(10,'free'), 'misrBands':(7,'query pending'), 'effectRadIc|tau':(28,'query pending')}
64
65python2 = True
66if sys.version_info[0] == 3:
67  python2 = False
68  from functools import reduce
69  try: 
70    from utilP3 import mlog3
71  except:
72    from dreqPy.utilP3 import mlog3
73  mlg = mlog3()
74else:
75  from utilP2 import util
76  mlg = util.mlog()
77
78class c1(object):
79  def __init__(self):
80    self.a = collections.defaultdict( int )
81class c1s(object):
82  def __init__(self):
83    self.a = collections.defaultdict( set )
84
85NT_txtopts = collections.namedtuple( 'txtopts', ['mode'] )
86
87def vfmt(ss):
88  stb = ss*1.e-12
89  if stb < .099:
90    return '%7.2fGb' % (stb*100)
91  else:
92    return '%7.2fTb' % stb
93
94class baseException(Exception):
95  """Basic exception for general use in code."""
96
97  def __init__(self,msg):
98    self.msg = 'scope:: %s' % msg
99
100  def __str__(self):
101    return repr( self.msg )
102
103  def __repr__(self):
104    return self.msg
105
106nt_mcfg = collections.namedtuple( 'mcfg', ['nho','nlo','nha','nla','nlas','nls','nh1'] )
107class cmpd(object):
108  def __init__(self,dct):
109    self.d = dct
110  def cmp(self,x,y,):
111    return cmp( self.d[x], self.d[y] )
112
113
114def filter1( a, b ):
115  if b < 0:
116    return a
117  else:
118    return min( [a,b] )
119
120def filter2( a, b, tt, tm ):
121## largest tier less than or equal to tm
122  ll = [t for t in tt if t <= tm]
123  if len( ll ) > 0:
124    t1 = [t for t in tt if t <= tm][-1]
125    it1 = tt.index(t1)
126    aa = a[it1]
127    if b < 0:
128      return aa
129    else:
130      return min( [aa,b] )
131  else:
132    return 0
133
134npy = {'1hrClimMon':24*12, 'daily':365, u'Annual':1, u'fx':0.01, u'1hr':24*365, u'3hr':8*365,
135       u'monClim':12, u'Timestep':100, u'6hr':4*365, u'day':365, u'1day':365, u'mon':12, u'yr':1,
136       u'1mon':12, 'month':12, 'year':1, 'monthly':12, 'hr':24*365, 'other':24*365,
137        'subhr':24*365, 'Day':365, '6h':4*365, '3 hourly':8*365, '':1, 'dec':0.1 }
138
139## There are 4 cmor variables with blank frequency ....
140
141def vol01( sz, v, npy, freq, inx ):
142  n1 = npy[freq]
143  s = sz[inx.uid[v].stid]
144  assert type(s) == type(1), 'Non-integer size found for %s' % v
145  assert type(n1) in (type(1),type(0.)), 'Non-number "npy" found for %s, [%s]' % (v,freq)
146  return s*n1
147
148class col_list(object):
149  def __init__(self):
150    self.a = collections.defaultdict(list)
151
152class col_count(object):
153  def __init__(self):
154    self.a = collections.defaultdict(int)
155
156class dreqQuery(object):
157  __doc__ = """Methods to analyse the data request, including data volume estimates"""
158  def __init__(self,dq=None,tierMax=1):
159    if dq == None:
160      self.dq = dreq.loadDreq()
161    else:
162      self.dq=dq
163    self.rlu = {}
164    for i in self.dq.coll['objective'].items:
165      k = '%s.%s' % (i.mip,i.label)
166      ##assert not k in self.rlu, 'Duplicate label in objectives: %s' % k
167      if k in self.rlu:
168        print ( 'SEVERE: Duplicate label in objectives: %s' % k )
169      self.rlu[k] = i.uid
170
171    self.odsz = odsz
172    self.npy = npy
173    self.strSz = dict()
174    self.cmvFilter = cmvFilter( self )
175    self.tierMax = tierMax
176    self.gridPolicyDefaultNative = False
177    self.gridOceanStructured = True
178    self.gridPolicyForce = None
179    self.retainRedundantRank = False
180    self.gridPolicyTopOnly = True
181    self.exptFilter = None
182    self.exptFilterBlack = None
183    self.uniqueRequest = False
184
185    self.mips = set( [x.label for x in self.dq.coll['mip'].items ] )
186    self.mips = ['CMIP','AerChemMIP', 'C4MIP', 'CFMIP', 'DAMIP', 'DCPP', 'FAFMIP', 'GeoMIP', 'GMMIP', 'HighResMIP', 'ISMIP6', 'LS3MIP', 'LUMIP', 'OMIP', 'PMIP', 'RFMIP', 'ScenarioMIP', 'VolMIP', 'CORDEX', 'DynVar', 'SIMIP', 'VIACSAB']
187    self.mipsp = self.mips[:-4]
188    self.cmvGridId, i4 = fgrid.fgrid( self.dq )
189    assert len(i4) == 0
190
191    self.experiments = set( [x.uid for x in self.dq.coll['experiment'].items ] )
192    self.exptByLabel = {}
193    for x in self.dq.coll['experiment'].items:
194      if x.label in self.exptByLabel:
195        print ( 'ERROR: experiment label duplicated: %s' % x.label )
196      self.exptByLabel[x.label] = x.uid
197    self.mipls = sorted( list( self.mips ) )
198
199    self.default_mcfg = nt_mcfg._make( [259200,60,64800,40,20,5,100] )
200    self.mcfg = self.default_mcfg._asdict()
201    self.mcfgNote = None
202    self.szcfg()
203    self.requestItemExpAll(  )
204
205  def showOpts(self):
206    print ( ( self.tierMax, self.gridPolicyDefaultNative, self.gridOceanStructured, self.gridPolicyForce,
207    self.retainRedundantRank, self.gridPolicyTopOnly, self.exptFilter, self.exptFilterBlack,
208    self.uniqueRequest ))
209
210  def setMcfg(self, ll, msg=None ):
211    assert len(ll) == 7, 'Model config must be of length 7: %s' % str(ll)
212    assert all( [type(x) == type(1) for x in ll] )
213    self.mcfg = nt_mcfg._make( ll )._asdict()
214    if msg == None:
215      self.mcfgNote = 'User supplied model configuration: %s' % str(ll)
216    else:
217      self.mcfgNote = msg
218    self.szcfg()
219
220  def szcfg(self):
221    szr = {'100km':64800, '1deg':64800, '2deg':16200 }
222    self.szss = {}
223    self.sz = {}
224    self.szg = collections.defaultdict( dict )
225    self.szgss = collections.defaultdict( dict )
226    self.isLatLon = {}
227    self.szSrf = collections.defaultdict( dict )
228    self.szssSrf = collections.defaultdict( dict )
229    for i in self.dq.coll['spatialShape'].items:
230      gtype = 'a'
231      if i.levelFlag == False:
232        ds =  i.dimensions.split( '|' )
233        if ds[-1] in ['site', 'basin']:
234          vd = ds[-2]
235        else:
236          vd = ds[-1]
237 
238        if vd[:4] == 'olev' or vd == 'rho':
239          gtype = 'o'
240          nz = self.mcfg['nlo']
241        elif vd[:4] == 'alev':
242          nz = self.mcfg['nla']
243        elif vd in ['slevel']:
244          nz = self.mcfg['nls']
245        elif vd in ['snowdepth','sdepth']:
246          nz = 5
247        elif vd == 'aslevel':
248          nz = self.mcfg['nlas']
249        else:
250          mlg.prnt( 'Failed to parse dimensions %s' % i.dimensions )
251          raise
252      else:
253        nz = i.levels
254
255      dims = set( i.dimensions.split( '|' ) )
256      if 'latitude' in dims and 'longitude' in dims:
257        if gtype == 'o':
258          nh = self.mcfg['nho']
259          self.isLatLon[i.uid] = 'o'
260        else:
261          nh = self.mcfg['nha']
262          self.isLatLon[i.uid] = 'a'
263      else:
264        nh = 10
265        self.isLatLon[i.uid] = False
266
267      self.szss[i.uid] = nh*nz
268      if self.isLatLon[i.uid] != False and len(dims) == 2:
269        self.szssSrf[i.uid] = { 'a':self.mcfg['nha']*nz, 'o':self.mcfg['nho']*nz }
270
271      for k in szr:
272        if self.isLatLon[i.uid] != False:
273          self.szgss[k][i.uid] = szr[k]*nz
274        else:
275          self.szgss[k][i.uid] = nh*nz
276
277    for i in self.dq.coll['structure'].items:
278      s = 1
279      knownAtmos = False
280      if i.odims != '':
281        if i.odims in odsz:
282           sf = odsz[i.odims]
283        else:
284           ## print 'SEVERE.odims.00001: no information on dimension size: %s' % i.odims
285           sf = 5
286        if type( sf ) == type( () ):
287          sf = sf[0]
288        s = s*sf
289        if i.odims not in ['iceband']:
290          knownAtmos = True
291      if i.spid in self.szss:
292        self.sz[i.uid] = self.szss[i.spid]*s
293
294        if i.uid in self.szssSrf:
295          if knownAtmos:
296            self.sz[i.uid] = self.szssSrf[i.spid]['a']*s
297          else:
298            for k in ['a','o']:
299               self.szSrf[i.uid][k] = self.szssSrf[i.spid][k]*s
300
301        for k in szr:
302          self.szg[k][i.uid] = self.szgss[k][i.spid]*s
303      else:
304        print ('WARNING: spid has no size info: %s [%s]' % (i.spid,i.uid) )
305        self.sz[i.uid] = 0.
306        for k in szr:
307          self.szg[k][i.uid] = 0.
308
309  def getRequestLinkByMip( self, mipSel ):
310    """Return the set of request links which are associated with specified MIP"""
311
312    if type(mipSel) == type( {} ):
313      return self.getRequestLinkByMipObjective(self,mipSel)
314
315    if type(mipSel) == type(''):
316      t1 = lambda x: x == mipSel
317    elif type(mipSel) == type(set()):
318      t1 = lambda x: x in mipSel
319
320    s = set()
321    for i in self.dq.coll['requestLink'].items:
322      if t1(i.mip):
323        if 'requestItem' in self.dq.inx.iref_by_sect[i.uid].a:
324          if any( [ self.rqiExp[x][3] > 0 for  x in self.dq.inx.iref_by_sect[i.uid].a['requestItem'] if x in self.rqiExp ] ):
325            s.add( i )
326
327    self.rqs = list( s )
328    return self.rqs
329
330  def getRequestLinkByMipObjective( self, mipSel ):
331    """Return the set of request links which are associated with specified MIP and its objectives"""
332
333    assert type(mipSel) == type( {} ),'Argument must be a dictionary, listing objectives for each MIP'
334
335    s = set()
336    for i in self.dq.coll['requestLink'].items:
337      if i.mip in mipSel:
338        if len(mipSel[i.mip]) == 0:
339          s.add( i )
340        elif 'objectiveLink' in self.dq.inx.iref_by_sect[i.uid].a:
341          ss = set( [self.dq.inx.uid[k].label for k in self.dq.inx.iref_by_sect[i.uid].a['objectiveLink'] ] )
342          if any( [x in mipSel[i.mip] for x in ss] ):
343            s.add( i )
344##
345## filter requestLinks by tierMax: check to see whether they link to experiments with tier below or equal to tiermax.
346##
347    s1 = set()
348    for i in s:
349      if 'requestItem' in self.dq.inx.iref_by_sect[i.uid].a:
350        if any( [ self.rqiExp[x][-1] > 0 for  x in self.dq.inx.iref_by_sect[i.uid].a['requestItem'] if x in self.rqiExp ] ):
351            s1.add( i )
352
353    self.rqs = list( s1 )
354    return self.rqs
355
356  def varGroupXexpt(self, rqList ):
357    """For a list of request links, return a list of variable group IDs for each experiment"""
358    self.cc = collections.defaultdict( list )
359    ## dummy = {self.cc[i.expt].append(i.rlid) for i in self.dq.coll['requestItem'].items if i.rlid in {j.uid for j in rqList} }
360    return self.cc
361
362  def yearsInRequest(self, rql ):
363    self.ntot = sum( [i.ny for i in self.dq.coll['requestItem'].items if i.rlid == rql.uid] )
364    return self.ntot
365
366  def rqlByExpt( self, l1, ex, pmax=2, expFullEx=False ):
367    """rqlByExpt: return a set of request links for an experiment"""
368##
369    inx = self.dq.inx
370
371    if ex != None:
372   
373      exi = self.dq.inx.uid[ex]
374      if exi._h.label == 'experiment':
375        exset = set( [ex,exi.egid,exi.mip] )
376      else:
377        exset = set( self.esid_to_exptList(ex,deref=False,full=expFullEx) )
378##
379## rql is the set of all request links which are associated with a request item for this experiment set
380##
381   
382      l1p = set()
383      for i in l1:
384        if i.preset < 0 or i.preset <= pmax:
385          if i.esid in exset:
386            l1p.add(i)
387    else:
388      exset = None
389      l1p = l1
390
391    rql0 = set()
392    for i in l1p:
393       rql0.add(i.rlid)
394
395    rqlInv = set()
396    for u in rql0:
397      if inx.uid[u]._h.label == 'remarks':
398        rqlInv.add( u )
399    if len(rqlInv) != 0:
400      mlg.prnt ( 'WARNING.001.00002: %s invalid request links from request items ...' % len(rqlInv) )
401    rql = set()
402    for u in rql0:
403       if inx.uid[u]._h.label != 'remarks':
404         rql.add( u ) 
405
406    return rql, l1p, exset
407
408  def varsByRql( self, rql, pmax=2, intersection=False, asDict=False): 
409      """The complete set of variables associated with a set of request links."""
410      inx = self.dq.inx
411      cc1 = collections.defaultdict( set )
412      for i in rql:
413        o = inx.uid[i]
414        if o.opt == 'priority':
415          p = int( float( o.opar ) )
416          assert p in [1,2,3], 'Priority incorrectly set .. %s, %s, %s' % (o.label,o.title, o.uid)
417          cc1[inx.uid[i].mip].add( (inx.uid[i].refid,p) )
418        else:
419          cc1[inx.uid[i].mip].add( inx.uid[i].refid )
420
421      if intersection:
422        ccv = {}
423#
424# set of request variables for each MIP
425#
426        for k in cc1:
427          thisc = reduce( operator.or_, [set( inx.iref_by_sect[vg].a['requestVar'] ) for vg in cc1[k] ] )
428          rqvgs = collections.defaultdict( set )
429          for x in cc1[k]:
430            if type(x) == type( () ):
431              rqvgs[x[0]].add( x[1] )
432            else:
433              rqvgs[x].add( 3 )
434         
435          s = set()
436          for vg in rqvgs:
437            for l in inx.iref_by_sect[vg].a['requestVar']:
438              if inx.uid[l].priority <= min(pmax,max(rqvgs[vg])):
439                s.add( inx.uid[l].vid )
440          ccv[k] = s
441
442        if len( ccv.keys() ) < len( list(imips) ):
443          vars = set()
444        else:
445          vars =  reduce( operator.and_, [ccv[k] for k in ccv] )
446      else:
447        rqvgs = collections.defaultdict( set )
448        for k in cc1:
449          for x in cc1[k]:
450            if type(x) == type( () ):
451              rqvgs[x[0]].add( x[1] )
452            else:
453              rqvgs[x].add( 3 )
454         
455###To obtain a set of variables associated with this collection of variable groups:
456
457        if asDict:
458          vars = collections.defaultdict( list )
459        else:
460          vars = set()
461        for vg in rqvgs:
462          for l in inx.iref_by_sect[vg].a['requestVar']:
463            if inx.uid[l].priority <= min(pmax,max(rqvgs[vg])):
464               if asDict:
465                 vars[inx.uid[l].vid].append( vg )
466               else:
467                 vars.add(inx.uid[l].vid)
468
469        ##col1 = reduce( operator.or_, [set( inx.iref_by_sect[vg].a['requestVar'] ) for vg in rqvg ] )
470### filter out cases where the request does not point to a CMOR variable.
471    ##vars = {vid for vid in vars if inx.uid[vid][0] == u'CMORvar'}
472
473      if asDict:
474        thisvars = {}
475        for vid in vars:
476           if inx.uid[vid]._h.label == u'CMORvar':
477             thisvars[vid] = vars[vid]
478      else:
479        thisvars = set()
480        for vid in vars:
481           if inx.uid[vid]._h.label == u'CMORvar':
482             thisvars.add(vid)
483
484      return thisvars
485
486  def exptYears( self, rqll, ex=None, exBlack=None):
487    """Parse a set of request links, and get years requested for each (varGroup, expt, grid) tuple """
488     
489    self.tsliceDict = collections.defaultdict( dict )
490    ccts = collections.defaultdict( dict )
491    cc = collections.defaultdict( set )
492    for rl in rqll:
493      if 'requestItem' not in self.dq.inx.iref_by_sect[rl.uid].a:
494        print ( 'WARN.001.00001: no request items for: %s, %s' % (rl.uid, rl.title) )
495      else:
496
497        if self.gridPolicyForce != None:
498          grd = self.gridPolicyForce
499        elif rl.grid in ['1deg','2deg','100km']:
500          if rl.grid == '100km':
501            grd = '1deg'
502          else:
503            grd = rl.grid
504        else:
505          ## note that naming of "gridreq" is unfortunate ... "No" means that native grid is required
506          if rl.gridreq in ['No', 'no']:
507             #or self.gridPolicyDefaultNative:
508            grd = 'native'
509          elif rl.gridreq in ['no*1']:
510             #or self.gridPolicyDefaultNative:
511            grd = 'native:01'
512          else:
513            ## print ( 'INFO.grd.00001: defaulting to grid ..%s, %s, %s' % (rl.label,rl.title, rl.uid) )
514            grd = 'DEF'
515
516        for iu in self.dq.inx.iref_by_sect[rl.uid].a['requestItem']:
517          i = self.dq.inx.uid[iu]
518
519##
520## apply "treset" filter to request items linked to this group.
521##
522          if self.tierMax < 0 or 'treset' not in i.__dict__ or i.treset <= self.tierMax:
523            if iu in self.rqiExp:
524              for e in self.rqiExp[iu][1]:
525                if (ex == None or e in ex) and (exBlack == None or e not in exBlack):
526                  this = self.rqiExp[iu][1][e]
527                  if this != None:
528                    thisns = this[-3]
529                    thisny = this[-2]
530                    thisne = this[-1]
531                    ##cc[ (rl.refid,e,grd) ].add( filter1( thisns*thisny*thisne, i.nymax) )
532                    cc[ (rl.refid,e,grd) ].add( thisns*thisny*thisne )
533                    if self.rqiExp[iu][4] != None:
534                      ccts[(rl.refid,e)][thisns*thisny*thisne] = self.rqiExp[iu][4]
535
536    ee = collections.defaultdict( dict )
537
538    revertToLast = True
539    if revertToLast:
540      for g,e,grd in cc:
541        ee[g][(e,grd)] = max( cc[( g,e,grd) ] )
542        if (g,e) in ccts and ee[g][(e,grd)] in ccts[(g,e)]:
543           self.tsliceDict[g][e] = ccts[(g,e)][ ee[g][(e,grd)] ]
544      return ee
545    ff = collections.defaultdict( dict )
546##
547## this needs to be done separately for ocean and atmosphere, because of the default logic workflow ...
548    for g,e,grd in cc:
549      ee[(g,e)][grd] = max( cc[( g,e,grd) ] )
550
551    xx = collections.defaultdict( dict )
552    for g,e in ee:
553      ddef = ee[(g,e)].get( 'DEF', 0 )
554      for grd in ee[(g,e)]:
555        if grd != 'DEF':
556          xx[(g,'a')][(e, grd)] = ee[(g,e)][grd]
557          xx[(g,'o')][(e, grd)] = ee[(g,e)][grd]
558          xx[(g,'')][(e, grd)] = ee[(g,e)][grd]
559        if grd == 'native' and ddef != 0:
560          xx[(g,'a')][(e, 'native')] = max( [xx[(g,'a')][(e, 'native')],ddef] )
561          xx[(g,'')][(e, 'native')] = max( [xx[(g,'')][(e, 'native')],ddef] )
562        if grd == '1deg' and ddef != 0:
563          xx[(g,'o')][(e, '1deg')] = max( [xx[(g,'o')][(e, '1deg')],ddef] )
564
565    for grp,flg in xx:
566      ff[grp][flg] = xx[(grp,flg)]
567         
568    ## return dict[<variable group>]{dict[<experiment><grid>]{<years>}}
569    ## return dict[<variable group>][grid flag]{dict[<experiment>,<grid>]{<years>}}
570    return ff
571
572  def volByExpt( self, l1, ex, pmax=1, cc=None, intersection=False,expFullEx=False, adsCount=False ):
573    """volByExpt: calculates the total data volume associated with an experiment/experiment group and a list of request items.
574          The calculation has some approximations concerning the number of years in each experiment group.
575          cc: an optional collector, to accumulate indexed volumes. """
576##
577    inx = self.dq.inx
578    imips = set()
579    for i in l1:
580      imips.add(i.mip)
581   
582    rql, l1p, exset = self.rqlByExpt( l1, ex, pmax=pmax, expFullEx=expFullEx )
583    verbose = False
584    if verbose:
585      for i in rql:
586        r = inx.uid[i]
587        print ( '%s, %s, %s' % (r.label, r.title, r.uid) )
588
589    if ex != None:
590     
591      exi = self.dq.inx.uid[ex]
592      if exi._h.label == 'experiment':
593        exset = set( [ex,exi.egid,exi.mip] )
594#####
595    if len( rql ) == 0:
596      self.vars = set()
597      return (0,{},{} )
598
599## The complete set of variables associated with these requests:
600    vars = self.varsByRql( rql, pmax=pmax, intersection=intersection, asDict=True) 
601##
602## filter by configuration option and rank
603##
604    if not self.retainRedundantRank:
605      len1 = len(vars.keys())
606      cmv = self.cmvFilter.filterByChoiceRank(cmv=vars.keys())
607      vars = cmv
608   
609    self.vars = vars
610
611    e = {}
612    for u in rql:
613### for request variables which reference the variable group attached to the link, add the associate CMOR variables, subject to priority
614      i = inx.uid[u]
615      e[i.uid] = set()
616      si = collections.defaultdict( list )
617      for x in inx.iref_by_sect[i.refid].a['requestVar']:
618           if inx.uid[x].priority <= pmax:
619              e[i.uid].add( inx.uid[x].vid )
620
621              if verbose:
622                cmv = inx.uid[inx.uid[x].vid]
623                if cmv._h.label == 'CMORvar':
624                  si[ cmv.mipTable ].append( inx.uid[x].label )
625#
626# for each variable, calculate the maximum number of years across all the request links which reference that variable.
627##
628## for each request item we have nymax, nenmax, nexmax.
629##
630    nymg = collections.defaultdict( dict )
631##
632## if dataset count rather than volume is wanted, use item 3 from rqiExp tuple.
633    if adsCount:
634      irqi = 3
635    else:
636      irqi = 2
637
638    sgg = set()
639    for v in vars:
640      s = set()
641      sg = collections.defaultdict( set )
642      cc2 = collections.defaultdict( set )
643      cc2s = collections.defaultdict( c1s )
644      for i in l1p:
645##################
646        if (exset == None or i.esid in exset) and v in e[i.rlid]:
647          ix = inx.uid[i.esid]
648          rl = inx.uid[i.rlid]
649          sgg.add( rl.grid )
650          if rl.grid in ['100km','1deg','2deg']:
651            grd = rl.grid
652          else:
653            grd = 'native'
654
655          this = None
656          if exset == None:
657            thisz = 100
658##
659## for a single experiment, look up n years, and n ensemble.
660## should have nstart????
661##
662          elif exi._h.label == 'experiment' or ix._h.label == 'experiment':
663            this = None
664            if ex in self.rqiExp[i.uid][1]:
665              this = self.rqiExp[i.uid][1][ex]
666            elif ix.uid in self.rqiExp[i.uid][1]:
667              this = self.rqiExp[i.uid][1][ix.uid]
668            if this != None:
669              thisns = this[-3]
670              thisny = this[-2]
671              thisne = this[-1]
672              cc2s[grd].a[u].add( filter1( thisns*thisny*thisne, i.nymax) )
673          else:
674            thisz = None
675            if 'experiment' in inx.iref_by_sect[i.esid].a:
676              for u in inx.iref_by_sect[i.esid].a['experiment']:
677                if u in self.rqiExp[i.uid][1]:
678                  this = self.rqiExp[i.uid][1][u]
679                  thisns = this[-3]
680                  thisny = this[-2]
681                  thisne = this[-1]
682##
683###   aggregate year count for each experiment and output grid
684## clarify definition and usage of nymax -- should be redundant ... could be replaced by inward references from "timeSlice"
685                  cc2s[grd].a[u].add( filter1( thisns*thisny*thisne, i.nymax) )
686
687          if exset != None:
688            sg[grd].add( self.rqiExp[i.uid][irqi] )
689     
690###
691### sum over experiments of maximum within each experiment
692###
693      for g in sg:
694        nymg[v][g] = sum( [max( cc2s[g].a[k] ) for k in cc2s[g].a] )
695
696    szv = {}
697    ov = []
698    for v in vars:
699      if 'requestVar' not in inx.iref_by_sect[v].a:
700         print ( 'Variable with no request ....: %s, %s' % (inx.uid[v].label, inx.uid[v].mipTable) )
701      try:
702        szv[v] = self.sz[inx.uid[v].stid]*npy[inx.uid[v].frequency]
703      except:
704        if inx.uid[v].stid not in self.sz:
705          print ('ERROR: size not found for stid %s (v=%s, %s)' % (inx.uid[v].stid,v,inx.uid[v].label) )
706        if inx.uid[v].frequency not in npy:
707          print ('ERROR: npy not found for frequency %s (v=%s, %s)' % (inx.uid[v].frequency,v,inx.uid[v].label) )
708        szv[v] = 0
709      ov.append( self.dq.inx.uid[v] )
710
711    ff = {}
712    for v in vars:
713      if adsCount:
714        ff[v] = 1
715      else:
716        if 'native' in nymg[v]:
717          ff[v] = szv[v]
718          ny = nymg[v]['native']
719        else:
720          ks0 = nymg[v].keys()
721          if len(ks0) == 0:
722            ff[v] = 0.
723            ny = 0.
724          else:
725            ks = gridSorter.sort( nymg[v].keys() )[0]
726            ##ks = list( nymg[v].keys() )[0]
727            ny = nymg[v][ks]
728            if inx.uid[v].stid in self.szg[ks]:
729              ff[v] = self.szg[ks][ inx.uid[v].stid ] * npy[inx.uid[v].frequency]
730            else:
731              ff[v] = 0.
732
733        if inx.uid[v].frequency != 'monClim':
734          ff[v] = ff[v]*ny
735
736    ee = self.listIndexDual( ov, 'mipTable', 'label', acount=None, alist=None, cdict=ff, cc=cc )
737    self.ngptot = sum( [  ff[v]  for v in vars] )
738    return (self.ngptot, ee, ff )
739
740  def esid_to_exptList(self,esid,deref=False,full=False):
741    if not esid in self.dq.inx.uid:
742      mlg.prnt ( 'Attempt to dereferece invalid uid: %s' % esid )
743      raise
744
745    if self.dq.inx.uid[esid]._h.label == 'experiment':
746      expts = [esid,]
747    elif self.dq.inx.uid[esid]._h.label != 'remarks':
748      if esid in self.dq.inx.iref_by_sect and 'experiment' in self.dq.inx.iref_by_sect[esid].a:
749        expts = list( self.dq.inx.iref_by_sect[esid].a['experiment'][:] )
750      else:
751        expts = []
752
753## add in groups and mips for completeness
754##
755      if full:
756        if self.dq.inx.uid[esid]._h.label == 'mip':
757          s = set()
758          for e in expts:
759            if self.dq.inx.uid[e]._h.label != 'experiment':
760              mlg.prnt ( 'ERROR: %s, %s, %s ' % (esid,e, self.dq.inx.uid[e].title ) )
761            s.add( self.dq.inx.uid[e].egid )
762          for i in s:
763            expts.append( i )
764        expts.append( esid )
765    else:
766      return None
767
768    if self.tierMax > 0:
769      expts1 = []
770      for i in expts:
771        if self.dq.inx.uid[i]._h.label == 'experiment':
772          if self.dq.inx.uid[i].tier[0] <= self.tierMax:
773            expts1.append( i )
774        elif self.dq.inx.uid[i]._h.label == 'exptgroup':
775          if self.dq.inx.uid[i].tierMin <= self.tierMax:
776            expts1.append( i )
777        else:
778            expts1.append( i )
779    else:
780      expts1 = expts
781
782    if deref:
783      return [self.dq.inx.uid[e] for e in expts1]
784    else:
785      return expts1
786##
787## need to call this on load
788## then use instead of i.ny etc below
789##
790  def requestItemExpAll( self ):
791    self.rqiExp = {}
792    for rqi in self.dq.coll['requestItem'].items:
793      a,b,c,d,e = self.requestItemExp( rqi )
794      if a != None:
795        self.rqiExp[rqi.uid] = (a,b,c,d,e)
796
797  def requestItemExp( self, rqi ):
798    assert rqi._h.label == "requestItem", 'Argument to requestItemExp must be a requestItem'
799    tsl = None
800    if 'tslice' in rqi.__dict__:
801      ts = self.dq.inx.uid[ rqi.tslice ]
802      if ts._h.label == 'timeSlice':
803        if ts.type == 'simpleRange':
804          tsl = (ts.label,'simpleRange', ts.start,ts.end)
805        elif ts.type == 'branchedYears':
806          tsl = (ts.label,'%s:%s' % (ts.type,ts.child), ts.start,ts.end)
807        else:
808          tsl = (ts.label, ts.type, None, None )
809
810     
811    u = rqi.esid
812    if self.dq.inx.uid[u]._h.label == 'experiment':
813      expts = [u,]
814    elif self.dq.inx.uid[u]._h.label != 'remarks':
815      if u in self.dq.inx.iref_by_sect and 'experiment' in self.dq.inx.iref_by_sect[u].a:
816        expts = self.dq.inx.iref_by_sect[u].a['experiment']
817      else:
818        expts = []
819    else:
820      return (None, None, None, None,None)
821
822    if self.tierMax > 0:
823      expts = [i for i in expts if self.dq.inx.uid[i].tier[0] <= self.tierMax]
824
825    self.multiTierOnly = False
826    if self.multiTierOnly:
827      expts = [i for i in expts if len(self.dq.inx.uid[i].tier) > 1]
828      print ('Len expts: %s' % len(expts) )
829
830    if len(expts) > 0:
831      e = [self.dq.inx.uid[i] for i in expts]
832      for i in e:
833        if i._h.label != 'experiment':
834          mlg.prnt ( 'ERROR: %s, %s, %s ' % ( u,i._h.label, i.label, i.title ) )
835      dat2 = {}
836      for i in e:
837        dat2[i.uid] = (i.ntot, i.yps, i.ensz, i.tier, i.nstart, filter1(i.yps,rqi.nymax), filter2(i.ensz,rqi.nenmax,i.tier,self.tierMax) )
838
839      nytot = sum( [dat2[x][-2]*dat2[x][-3] for x in dat2 ] )
840      netot = sum( [dat2[x][-1] for x in dat2 ] )
841    else:
842      dat2 = {}
843      nytot = 0
844      netot = 0
845   
846##
847## to get list of years per expt for each requestLink ... expts is union of all dat2 keys,
848## and want max of dat2[x][0] for each experiment x.
849##
850    return (expts, dat2, nytot, netot, tsl )
851
852  def setTierMax( self, tierMax ):
853    """Set the maxium tier and recompute request sizes"""
854    if tierMax != self.tierMax:
855      self.tierMax = tierMax
856      self.requestItemExpAll(  )
857
858  def summaryByMip( self, pmax=1 ):
859    bytesPerFloat = 2.
860    for m in self.mipls:
861      v = self.volByMip( m, pmax=pmax )
862      mlg.prnt ( '%12.12s: %6.2fTb' % (m,v*bytesPerFloat*1.e-12) )
863
864  def rqlByMip( self, mip):
865    if mip == 'TOTAL':
866        mip = self.mips
867
868    if type(mip) in [type( '' ),type( u'') ]:
869      if mip not in self.mips:
870        mlg.prnt ( self.mips )
871        raise baseException( 'rqiByMip: Name of mip not recognised: %s' % mip )
872      l1 = [i for i in  self.dq.coll['requestLink'].items if i.mip == mip]
873    elif type(mip) in [ type( set()), type( [] ) ]:
874      nf = [ m for m in mip if m not in self.mips]
875      if len(nf) > 0:
876          raise baseException( 'rqlByMip: Name of mip(s) not recognised: %s' % str(nf) )
877      l1 = [i for i in  self.dq.coll['requestLink'].items if i.mip in mip]
878    elif type(mip) == type( dict()):
879      nf = [ m for m in mip if m not in self.mips]
880      if len(nf) > 0:
881        raise baseException( 'rqlByMip: Name of mip(s) not recognised: %s' % str(nf) )
882      l1 = []
883      for i in  self.dq.coll['requestLink'].items:
884        if i.mip in mip:
885          ok = False
886          if len( mip[i.mip] ) == 0:
887            ok = True
888          else:
889            for ol in self.dq.inx.iref_by_sect[i.uid].a['objectiveLink']:
890              o = self.dq.inx.uid[ol]
891              if self.dq.inx.uid[o.oid].label in mip[i.mip]:
892                ok = True
893          if ok:
894              l1.append( i )
895    else:
896      raise baseException( 'rqiByMip: "mip" (1st explicit argument) should be type string or set: %s -- %s' % (mip, type(mip))   )
897
898    return l1
899
900  def rqiByMip( self, mip):
901    l1 = self.rqlByMip( mip )
902    if len(l1) == 0:
903       return []
904    l2 = [] 
905    for i in l1:
906       if 'requestItem' in self.dq.inx.iref_by_sect[i.uid].a:
907          for u in self.dq.inx.iref_by_sect[i.uid].a['requestItem']:
908               l2.append( self.dq.inx.uid[u] )
909
910    l20 = self.rqiByMip0( mip )
911    for i in l20:
912      assert i in l2
913    return l2
914   
915   
916  def rqiByMip0( self, mip):
917
918    if mip == 'TOTAL':
919        mip = self.mips
920    if type(mip) in [type( '' ),type( u'') ]:
921      if mip not in self.mips:
922        mlg.prnt ( self.mips )
923        raise baseException( 'rqiByMip: Name of mip not recognised: %s' % mip )
924      l1 = [i for i in  self.dq.coll['requestItem'].items if i.mip == mip]
925    elif type(mip) in [ type( set()), type( [] ) ]:
926      nf = [ m for m in mip if m not in self.mips]
927      if len(nf) > 0:
928          raise baseException( 'rqiByMip: Name of mip(s) not recognised: %s' % str(nf) )
929      l1 = [i for i in  self.dq.coll['requestItem'].items if i.mip in mip]
930    elif type(mip) == type( dict()):
931      nf = [ m for m in mip if m not in self.mips]
932      if len(nf) > 0:
933        raise baseException( 'rqiByMip: Name of mip(s) not recognised: %s' % str(nf) )
934      l1 = []
935      for i in  self.dq.coll['requestLink'].items:
936        if i.mip in mip:
937          ok = False
938          if len( mip[i.mip] ) == 0:
939            ok = True
940          else:
941            for ol in self.dq.inx.iref_by_sect[i.uid].a['objectiveLink']:
942              o = self.dq.inx.uid[ol]
943              if self.dq.inx.uid[o.oid].label in mip[i.mip]:
944                ok = True
945          if ok:
946              if 'requestItem' in self.dq.inx.iref_by_sect[i.uid].a:
947                for u in self.dq.inx.iref_by_sect[i.uid].a['requestItem']:
948                  l1.append( self.dq.inx.uid[u] )
949    else:
950      raise baseException( 'rqiByMip: "mip" (1st explicit argument) should be type string or set: %s -- %s' % (mip, type(mip))   )
951
952    return l1
953
954  def checkDir(self,odir,msg):
955      if not os.path.isdir( odir ):
956         try:
957            os.mkdir( odir )
958         except:
959            print ('\n\nFailed to make directory "%s" for: %s: make necessary subdirectories or run where you have write access' % (odir,msg) )
960            print ( '\n\n' )
961            raise
962         print ('Created directory %s for: %s' % (odir,msg) )
963
964  def xlsByMipExpt(self,m,ex,pmax,odir='xls',xls=True,txt=False,txtOpts=None):
965    import scope_utils
966    mxls = scope_utils.xlsTabs(self,tiermax=self.tierMax,pmax=pmax,xls=xls, txt=txt, txtOpts=txtOpts,odir=odir)
967    mlab = makeTables.setMlab( m )
968    mxls.run( m, mlab=mlab )
969
970  def cmvByInvMip( self, mip,pmax=1,includeYears=False, exptFilter=None,exptFilterBlack=None ):
971    mips = set( self.mips[:] )
972    if type(mip) == type( '' ):
973        mips.discard( mip )
974    else:
975      for m in mip:
976        mips.discard( m )
977
978    return self.cmvByMip( mips,pmax=pmax,includeYears=includeYears, exptFilter=exptFilter, exptFilterBlack=exptFilterBlack )
979
980  def cmvByMip( self, mip,pmax=1,includeYears=False, exptFilter=None, exptFilterBlack=None ):
981    if exptFilter != None:
982      assert type(exptFilter) == type( set() ), 'Argument exptFilter must be None or a set: %s' % str(exptFilter)
983    if exptFilterBlack != None:
984      assert type(exptFilterBlack) == type( set() ), 'Argument exptFilterBlack must be None or a set: %s' % str(exptFilterBlack)
985      if exptFilter != None:
986        assert len( exptFilter.difference( exptFilterBlack ) ) > 0, 'If exptFilter and exptFilterBlack are both set, exptFilter must have non-black listed elements' 
987
988    l1,ee = self.rvgByMip( mip, includePreset=True, returnLinks=True )
989    if includeYears:
990      expys = self.exptYears( l1, ex=exptFilter, exBlack=exptFilterBlack )
991      cc = collections.defaultdict( set )
992      ccts = collections.defaultdict( set )
993    ss = set()
994    for pr in ee:
995### loop over request  var groups.
996      for i in ee[pr]:
997        if 'requestVar' in self.dq.inx.iref_by_sect[i.uid].a:
998#
999# loop over request vars in group
1000#
1001          for x in self.dq.inx.iref_by_sect[i.uid].a['requestVar']:
1002            i1 = self.dq.inx.uid[x]
1003
1004            thisp = i1.priority
1005            if pr != -1:
1006              thisp = pr
1007             
1008            if thisp <= pmax:
1009              if includeYears and i1.vid in self.cmvGridId:
1010                ##assert i.uid in expys, 'No experiment info found for requestVarGroup: %s' % i.uid
1011                ## may have no entry as a consequence of tierMin being set in the requestLink(s).
1012                assert i1.vid in self.cmvGridId, 'No grid identification lookup found for %s: %s' % (i1.label,i1.vid)
1013                assert self.cmvGridId[i1.vid] in ['a','o','si','li'], 'Unexpected grid id: %s: %s:: %s' % (i1.label,i1.vid, self.cmvGridId[i1.vid])
1014                gflg = {'si':'','li':''}.get( self.cmvGridId[i1.vid], self.cmvGridId[i1.vid] )
1015                rtl = True
1016
1017                if i.uid in expys:
1018                  if rtl:
1019                    for e,grd in expys[i.uid]:
1020                        if exptFilter == None or e in exptFilter:
1021                          if grd == 'DEF':
1022                            if gflg == 'o':
1023                              grd1 = '1deg'
1024                            else:
1025                              grd1 = 'native'
1026                          else:
1027                            grd1 = grd
1028                          cc[(i1.vid,e,grd1)].add( expys[i.uid][e,grd] )
1029                          if i.uid in self.tsliceDict and e in self.tsliceDict[i.uid]:
1030                            ccts[(i1.vid,e)].add( (self.tsliceDict[i.uid][e],thisp) )
1031                          else:
1032                            ccts[(i1.vid,e)].add( (None,thisp) )
1033
1034
1035                  else:
1036
1037                   for gf in expys[i.uid]:
1038                    for e,grd in expys[i.uid][gf]:
1039                      if grd in ["1deg",'2deg'] or gf == gflg:
1040                        if exptFilter == None or e in exptFilter:
1041                          cc[(i1.vid,e,grd)].add( expys[i.uid][gf][e,grd] )
1042              else:
1043                print ( 'SKIPPING %s: %s' % (i1.label,i1.vid) )
1044                ss.add( i1.vid )
1045    if includeYears:
1046      l2 = collections.defaultdict( dict )
1047      l2x = collections.defaultdict( dict )
1048##
1049## this removes lower ranked grids .... but for some groups want different grids for different variable categories
1050##
1051      if self.gridPolicyTopOnly:
1052        for v,e,g in cc:
1053          l2x[(v,e)][g] = max( list( cc[(v,e,g)] ) )
1054        for v,e in l2x:
1055          if len( l2x[(v,e)].keys() ) == 1:
1056             g,val = list( l2x[(v,e)].items() )[0]
1057          else:
1058            kk = gridSorter.sort( l2x[(v,e)].keys() )
1059            gflg = {'si':'','li':''}.get( self.cmvGridId[v], self.cmvGridId[v] )
1060            g = kk[0]
1061            if g not in l2x[(v,e)]:
1062              print '%s not found in %s (%s):' % (g,str(l2x[(v,e)].keys()),str(kk))
1063            val = l2x[(v,e)][g]
1064               
1065          l2[v][(e,g)] = val
1066      else:
1067        for v,e,g in cc:
1068          l2[v][(e,g)] = max( list( cc[(v,e,g)] ) )
1069
1070      l2ts = collections.defaultdict( dict )
1071      for v in l2:
1072        for e,g in l2[v]:
1073          if (v,e) in ccts:
1074            if len( ccts[(v,e)] ) > 1:
1075              rc, ts, msg = sortTimeSlice( ccts[(v,e)] )
1076              if rc == 1:
1077                l2ts[v][e] = ts
1078              elif rc == 2:
1079                yl = range( ts[0][0][2], ts[0][0][3] + 1) + range( ts[0][1][2], ts[0][1][3] + 1)
1080                l2ts[v][e] = ('_union', 'YEARLIST', len(yl), yl, ts[1] )
1081              else:
1082                print ('TIME SLICE MULTIPLE OPTIONS FOR : %s, %s, %s, %s' % (v,e,str(ccts[(v,e)]), msg ) )
1083            else:
1084              a,b = ccts[(v,e)].pop()
1085              if type(a) == type( [] ):
1086                l2ts[v][e] = a + [b,]
1087              elif type(a) == type( () ):
1088                l2ts[v][e] = list(a) + [b,]
1089              elif a == None:
1090                l2ts[v][e] = [None,b]
1091              else:
1092                assert False, 'Bad type for ccts record: %s' % type( a)
1093      return l2, l2ts
1094    else:
1095      l2 = sorted( [i for i in [self.dq.inx.uid[i] for i in ss] if i._h.label != 'remarks'], key=lambda x: x.label )
1096      return l2
1097
1098  def exptFilterList(self,val,option,ret='uid'):
1099    if type( val ) not in [[],()]:
1100      val = [val,]
1101
1102    if option == 'lab':
1103      v0 = val[:]
1104      val = []
1105      mm = []
1106      for v in v0:
1107        if v not in self.exptByLabel:
1108          mm.append( v )
1109        else:
1110          val.append( self.exptByLabel[v] )
1111
1112      assert len(mm) == 0, 'Experiment names not all recognised: %s' % str(mm)
1113
1114    oo = set()
1115    for v in val:
1116      i = self.dq.inx.uid[v]
1117      if i._h.label in ['exptgroup','mip']:
1118        if 'experiment' in self.dq.inx.iref_by_sect[i.uid].a:
1119          for u in self.dq.inx.iref_by_sect[i.uid].a['experiment']:
1120            oo.add( u )
1121      elif i._h.label == 'experiment':
1122            oo.add( i.uid )
1123      else:
1124        print ('WARNING .. skipping request for experiment which links to record of type %s' % i._h.label )
1125    return oo
1126   
1127  def getFreqStrSummary(self,mip,pmax=1):
1128##
1129## get a dictionary keyed on CMORvar uid, containing dictionary keyed on (experiment, grid) with value as number of years.
1130##
1131    if not self.uniqueRequest:
1132      cmv, self.cmvts = self.cmvByMip(mip,pmax=pmax,includeYears=True,exptFilter=self.exptFilter,exptFilterBlack=self.exptFilterBlack)
1133    else:
1134      cmv1, cmvts1 = self.cmvByInvMip(mip,pmax=pmax,includeYears=True,exptFilter=self.exptFilter,exptFilterBlack=self.exptFilterBlack)
1135      cmv2, cmvts2 = self.cmvByMip('TOTAL',pmax=pmax,includeYears=True,exptFilter=self.exptFilter,exptFilterBlack=self.exptFilterBlack)
1136      cmv = self.differenceSelectedCmvDict(  cmv1, cmv2 )
1137
1138    if not self.retainRedundantRank:
1139      len1 = len(cmv)
1140      self.cmvFilter.filterByChoiceRank(cmv=cmv,asDict=True)
1141      len2 = len(cmv)
1142      ##print 'INFO.redundant.0001: length %s --> %s' % (len1,len2)
1143 
1144    self.selectedCmv = cmv
1145    return self.cmvByFreqStr( cmv )
1146
1147  def differenceSelectedCmvDict( self, cmv1, cmv2 ):
1148      """Return the diffence between two dictionaries of cmor variables returned by self.cmvByMip.
1149         The dictionaries contain dictionaries of values. Differences may be subdictionaries not present,
1150         elements of sub-dictionaries not present, or elements of sub-dictionaries present with different values.
1151         A one sided difference is returned."""
1152
1153      cmv = {}
1154      for i in cmv2:
1155        if i not in cmv1:
1156          cmv[i] = cmv2[i]
1157        else:
1158          eei = {}
1159          for t in cmv2[i]:
1160            if t not in cmv1[i]:
1161              eei[t] = cmv2[i][t]
1162            else:
1163              if cmv2[i][t] > cmv1[i][t]:
1164                 eei[t] = cmv2[i][t] - cmv1[i][t]
1165          if len( eei.keys() ) != 0:
1166            cmv[i] = eei
1167      return cmv
1168
1169  def cmvByFreqStr(self,cmv,asDict=True,exptFilter=None,exptFilterBlack=None):
1170    if exptFilter != None:
1171      assert type(exptFilter) == type( set() ), 'Argument exptFilter must be None or a set: %s' % str(exptFilter)
1172    if exptFilterBlack != None:
1173      assert type(exptFilterBlack) == type( set() ), 'Argument exptFilterBlack must be None or a set: %s' % str(exptFilterBlack)
1174      if exptFilter != None:
1175        assert len( exptFilter.difference( exptFilterBlack ) ) > 0, 'If exptFilter and exptFilterBlack are both set, exptFilter must have non-black listed elements' 
1176
1177    cc = collections.defaultdict( list )
1178    for i in cmv:
1179      if asDict:
1180        ii = self.dq.inx.uid[i]
1181        if ii._h.label != 'remarks':
1182          st = self.dq.inx.uid[ ii.stid ]
1183          cc0 = collections.defaultdict( float )
1184          cc1 = collections.defaultdict( int )
1185          se = collections.defaultdict( set )
1186          for e,g in cmv[i]:
1187            cc0[g] += cmv[i][(e,g)]
1188            cc1[g] += 1
1189            se[g].add(e)
1190          for g in cc0:
1191            g1 = g
1192            if self.isLatLon[st.spid] != False:
1193              g1 = g
1194              if g1 == 'DEF' and self.isLatLon[st.spid] == 'o':
1195                  g1 = '1deg'
1196              elif g == 'native:01':
1197                gflg = {'si':'','li':''}.get( self.cmvGridId[i], self.cmvGridId[i] )
1198                if gflg == 'o' and not self.gridOceanStructured:
1199                  g1 = '1deg'
1200                else:
1201                  g1 = 'native'
1202              else:
1203                g1 = 'native'
1204            elif g == 'native:01':
1205                g1 = 'native'
1206
1207            cc[ (st.spid,st.odims,ii.frequency,g1) ].append( (i,cc0[g],cc1[g],se[g]) )
1208
1209      else:
1210        st = self.dq.inx.uid[ i.stid ]
1211        cc[ (st.spid,st.odims,i.frequency) ].append( i.label )
1212
1213    self.thiscmvset = set()
1214    c2 = collections.defaultdict( dict )
1215    sf = set()
1216    if asDict:
1217      for s,o,f,g in cc.keys():
1218        c2[(s,o,g)][f] = cc[ (s,o,f,g) ]
1219        sf.add( f )
1220    else:
1221      for s,o,f in cc.keys():
1222        c2[(s,o)][f] = cc[ (s,o,f) ]
1223        sf.add( f )
1224    lf = sorted( list(sf) )
1225    c3 = collections.defaultdict( dict )
1226
1227    for tt in sorted( c2.keys() ):
1228      if asDict:
1229        s,o,g = tt
1230      else:
1231        s,o = tt
1232        g = 'native'
1233      i = self.dq.inx.uid[ s ]
1234
1235      if asDict:
1236        for f in c2[tt]:
1237            isClim = f.lower().find( 'clim' ) != -1
1238            ny = 0
1239            expts = set()
1240            labs = []
1241            labs = collections.defaultdict( int )
1242            ccx = collections.defaultdict( list )
1243            for cmvi, ny1, ne, eset in c2[tt][f]:
1244              ccx[cmvi].append( (ny1, ne, eset) )
1245            net = 0
1246            for cmvi in ccx:
1247              if len( ccx[cmvi] ) == 1:
1248                 ny1, ne, eset = ccx[cmvi][0]
1249              else:
1250                 ny1, ne, eset = ( 0,0,set() )
1251                 for a,b,s in ccx[cmvi]:
1252                   ny1 += a
1253                   ne += b
1254                   eset = eset.union(  s )
1255             
1256              net += ne
1257              if len(eset) != ne:
1258                print ( 'WARNING: inconsistency in volume estimate ... possible duplication for %s,%s' % (cmvi,f) )
1259              for e in eset:
1260                elab = self.dq.inx.uid[e].label
1261                expts.add(elab)
1262
1263              if exptFilter != None:
1264                expts = exptFilter.intersection( expts )
1265              if exptFilterBlack != None:
1266                expts = expts.difference( exptFilterBlack )
1267
1268              if len(expts) > 0:
1269                lab = self.dq.inx.uid[cmvi].label
1270                self.thiscmvset.add( cmvi )
1271                ny += ny1
1272                labs[cmvi] += ny1
1273            ne = len( expts )
1274            nn = len( labs.keys() )
1275             
1276            if isClim:
1277              ny = net/float(nn)
1278            else:
1279              ny = ny/float(nn)
1280            assert tt[2] in ['native','1deg','2deg','native:01'], 'BAD grid identifier: %s' % str(tt)
1281            c3[tt][f] = (nn,ny,ne, labs,expts)
1282    return (sf,c3)
1283
1284  def getStrSz( self, g, stid=None, s=None, o=None, tt=False, cmv=None ):
1285    assert stid == None or (s==None and o==None), 'Specify either stid or s and o'
1286    assert stid != None or (s!=None and o!=None), 'Specify either stid or s and o'
1287
1288    if stid != None:
1289      st = self.dq.inx.uid[stid]
1290      if st._h.label != 'remarks':
1291        s = st.spid
1292        o = st.odims
1293      else:
1294        self.strSz[ (stid,g) ] = (False,0)
1295        if tt:
1296          return (self.strSz[ (stid,g) ], None)
1297        else:
1298          return self.strSz[ (stid,g) ]
1299
1300    g1 = g
1301    if g1 == 'DEF':
1302          if self.isLatLon[s] == 'o':
1303             g1 = '1deg'
1304          else:
1305             g1 = 'native'
1306    elif g1 == 'native:01':
1307      assert cmv != None, 'Need a valid cmor variable id  .... '
1308      gflg = {'si':'','li':''}.get( self.cmvGridId[cmv], self.cmvGridId[cmv] )
1309      if gflg == 'o' and not self.gridOceanStructured:
1310                  g1 = '1deg'
1311      else:
1312                  g1 = 'native'
1313    if (s,o,g) not in self.strSz:
1314
1315        if o == '':
1316           sf = 1
1317        elif o in self.odsz:
1318           sf = self.odsz[o]
1319        else:
1320           sf = 5
1321
1322        if type( sf ) == type( () ):
1323           sf = sf[0]
1324
1325        try:
1326          if g1 != 'native' and self.isLatLon[s] != False:
1327            szg = self.szgss[g1][s]
1328          else:
1329            szg = self.szss[s]
1330        except:
1331          print ( 'Failed to get size for: %s, %s, %s' % (g,g1,s ) )
1332          raise
1333
1334        szg = szg * sf
1335        self.strSz[ (s,o,g) ] = (True,szg)
1336
1337    if tt:
1338      return (self.strSz[ (s,o,g) ], (s,o,g1) )
1339    else:
1340      return self.strSz[ (s,o,g) ]
1341
1342  def rvgByMip( self, mip, years=False, includePreset=False, returnLinks=False ):
1343    l1 = self.rqlByMip( mip )
1344    if includePreset:
1345      cc = collections.defaultdict( set )
1346      ss = set()
1347      for i in l1:
1348        if 'requestItem' in self.dq.inx.iref_by_sect[i.uid].a:
1349          prs = set()
1350          for x in self.dq.inx.iref_by_sect[i.uid].a['requestItem']:
1351             prs.add(self.dq.inx.uid[x].preset)
1352
1353          for p in prs:
1354            assert p in [-1,1,2,3], 'Bad preset value'
1355            cc[p].add( i.refid )
1356      ee = {}
1357      for p in cc:
1358        l2 = sorted( [self.dq.inx.uid[i] for i in cc[p]], key=lambda x: x.label )
1359        ee[p] = l2
1360      if returnLinks:
1361        return (l1,ee)
1362      else:
1363        return ee
1364    else:
1365      ss = set( [i.refid for i in l1] )
1366      l2 = sorted( [self.dq.inx.uid[i] for i in ss], key=lambda x: x.label )
1367      if returnLinks:
1368        return (l1,l2)
1369      else:
1370        return l2
1371
1372  def volByMip2( self, mip, pmax=2, intersection=False, adsCount=False, exptid=None):
1373      vs = volsum.vsum( self, odsz, npy )
1374      vs.run( mip, 'dummy', pmax=pmax, doxlsx=False ) 
1375      vs.anal(olab='dummy', doUnique=False, mode='short', makeTabs=False)
1376      self.vf = vs.res['vf'].copy()
1377      for f in sorted( vs.res['vf'].keys() ):
1378           mlg.prnt ( 'Frequency: %s: %s' % (f, vs.res['vf'][f]*2.*1.e-12 ) )
1379      ttl = sum( [x for k,x in vs.res['vu'].items()] )
1380      return ttl
1381
1382  def volByMip( self, mip, pmax=2, intersection=False, adsCount=False, exptid=None):
1383
1384    l1 = self.rqiByMip( mip )
1385     
1386    #### The set of experiments/experiment groups:
1387    if exptid == None:
1388      exps = self.experiments
1389    elif type( exptid ) == type(''):
1390      exps = set( [exptid,] )
1391    else:
1392      assert type( exptid ) == type( set() ),'exptid arg to volByMip must be None, string or set: %s' % type( exptid )
1393      exps = exptid
1394   
1395    self.volByE = {}
1396    vtot = 0
1397    cc = collections.defaultdict( col_count )
1398    self.allVars = set()
1399    for e in exps:
1400      expts = self.esid_to_exptList(e,deref=True,full=False)
1401      if expts not in  [None,[]]:
1402        for ei in expts:
1403          self.volByE[ei.label] = self.volByExpt( l1, ei.uid, pmax=pmax, cc=cc, intersection=intersection, adsCount=adsCount )
1404          vtot += self.volByE[ei.label][0]
1405        self.allVars = self.allVars.union( self.vars )
1406    self.indexedVol = cc
1407
1408    return vtot
1409
1410  def listIndexDual(self, ll, a1, a2, acount=None, alist=None, cdict=None, cc=None ):
1411    do_count = acount != None
1412    do_list = alist != None
1413    assert not (do_count and do_list), 'It is an error to request both list and count'
1414    if not (do_count or do_list):
1415      acount = '__number__'
1416      do_count = True
1417
1418    if cc == None:
1419      if do_count:
1420        cc = collections.defaultdict( col_count )
1421      elif do_list:
1422        cc = collections.defaultdict( col_list )
1423
1424    if do_count:
1425      for l in ll:
1426        if cdict != None:
1427          v = cdict[l.uid]
1428        elif acount == '__number__':
1429          v = 1
1430        else:
1431          v = l.__dict__[acount]
1432
1433        cc[ l.__dict__[a1] ].a[ l.__dict__[a2] ] += v
1434    elif do_list:
1435      for l in ll:
1436        if cdict != None:
1437          v = cdict[l.uid]
1438        elif alist == '__item__':
1439          v = l
1440        else:
1441          v = l.__dict__[alist]
1442        cc[ l.__dict__[a1] ].a[ l.__dict__[a2] ].append( v )
1443
1444    od = {}
1445    for k in cc.keys():
1446      d2 = {}
1447      for k2 in cc[k].a.keys():
1448        d2[k2] = cc[k].a[k2]
1449      od[k] = d2
1450    return od
1451
1452class dreqUI(object):
1453  """Data Request Command line.
1454-------------------------
1455      -v : print version and exit;
1456      --unitTest : run some simple tests;
1457      -m <mip>:  MIP of list of MIPs (comma separated; for objective selection see note [1] below);
1458      -l <options>: List for options:
1459              o: objectives
1460              e: experiments
1461      -q <options>: List information about the schema:
1462              s: sections
1463              <section>: attributes for a section
1464              <section:attribute>: definition of an attribute.
1465      -h :       help: print help text;
1466      -e <expt>: experiment;
1467      -t <tier> maxmum tier;
1468      -p <priority>  maximum priority;
1469      --xls : Create Excel file with requested variables;
1470      --sf : Print summary of variable count by structure and frequency [default];
1471      --legacy : Use legacy approach to volume estimation (depricated);
1472      --xfr : Output variable lists in sheets organised by frequency and realm instead of by MIP table;
1473      --SF : Print summary of variable count by structure and frequency for all MIPs;
1474      --grdpol <native|1deg> :  policy for default grid, if MIPs have not expressed a preference;
1475      --grdforce <native|1deg> :  force a specific grid option, independent of individual preferences;
1476      --ogrdunstr : provide volume estimates for unstructured ocean grid (interpolation requirements of OMIP data are different in this case);
1477      --allgrd :  When a variable is requested on multiple grids, archive all grids requested (default: only the finest resolution);
1478      --unique :  List only variables which are requested uniquely by this MIP, for at least one experiment;
1479      --esm :  include ESM experiments (default is to omit esm-hist etc from volume estimates);
1480      --txt : Create text file with requested variables;
1481      --mcfg : Model configuration: 7 integers, comma separated, 'nho','nlo','nha','nla','nlas','nls','nh1'
1482                 default: 259200,60,64800,40,20,5,100
1483      --txtOpts : options for content of text file: (v|c)[(+|-)att1[,att2[...]]]
1484      --xlsDir <directory> : Directory in which to place variable listing [xls];
1485      --printLinesMax <n>  : Maximum number of lines to be printed (default 20)
1486      --printVars    : If present, a summary of the variables (see --printLinesMax) fitting the selection options will be printed
1487      --intersection : Analyse the intersection of requests rather than union.
1488
1489NOTES
1490-----
1491[1] A set of objectives within a MIP can be specified in the command line. The extended syntax of the "-m" argument is:
1492-m <mip>[:objective[.obj2[.obj3 ...]]][,<mip2]...]
1493
1494e.g.
1495drq -m HighResMIP:Ocean.DiurnalCycle
1496"""
1497  def __init__(self,args):
1498    self.adict = {}
1499    self.knownargs = {'-m':('m',True), '-p':('p',True), '-e':('e',True), '-t':('t',True), \
1500                      '-h':('h',False), '--printLinesMax':('plm',True), \
1501                      '-l':('l',True),
1502                      '-q':('q',True),
1503                      '--printVars':('vars',False), '--intersection':('intersection',False), \
1504                      '--count':('count',False), \
1505                      '--txt':('txt',False), \
1506                      '--sf':('sf',False), \
1507                      '--legacy':('legacy',False), \
1508                      '--xfr':('xfr',False), \
1509                      '--SF':('SF',False), \
1510                      '--esm':('esm',False), \
1511                      '--grdpol':('grdpol',True), \
1512                      '--ogrdunstr':('ogrdunstr',False), \
1513                      '--grdforce':('grdforce',True), \
1514                      '--omitCmip':('omitcmip',False), \
1515                      '--allgrd':('allgrd',False), \
1516                      '--unique':('unique',False), \
1517                      '--mcfg':('mcfg',True), \
1518                      '--txtOpts':('txtOpts',True), \
1519                      '--xlsDir':('xlsdir',True), '--xls':('xls',False) \
1520                       } 
1521    aa = args[:]
1522    notKnownArgs = []
1523    while len(aa) > 0:
1524      a = aa.pop(0)
1525      if a in self.knownargs:
1526        b = self.knownargs[a][0]
1527        if self.knownargs[a][1]:
1528          v = aa.pop(0)
1529          self.adict[b] = v
1530        else:
1531          self.adict[b] = True
1532      else:
1533        notKnownArgs.append(a)
1534
1535    assert self.checkArgs( notKnownArgs ), 'FATAL ERROR 001: Arguments not recognised: %s' % (str(notKnownArgs) )
1536
1537    if 'm' in self.adict:
1538      if self.adict['m'] == '_all_':
1539        pass
1540      elif self.adict['m'].find( ':' ) != -1:
1541        ee = {}
1542        for i in self.adict['m'].split(','):
1543          bits =  i.split( ':' )
1544          if len( bits ) == 1:
1545             ee[bits[0]] = []
1546          else:
1547             assert len(bits) == 2, 'Cannot parse %s' % self.adict['m']
1548             ee[bits[0]] = bits[1].split( '.' )
1549        self.adict['m'] = ee
1550      else:
1551        self.adict['m'] = set(self.adict['m'].split(',') )
1552        if 'omitcmip' not in self.adict and 'CMIP' not in self.adict['m']:
1553          self.adict['m'].add( 'CMIP' )
1554
1555    if 'grdpol' in self.adict:
1556      assert self.adict['grdpol'] in ['native','1deg'], 'Grid policy argument --grdpol must be native or 1deg : %s' % self.adict['grdpol']
1557
1558    if 'grdforce' in self.adict:
1559      assert self.adict['grdforce'] in ['native','1deg'], 'Grid policy argument --grdforce must be native or 1deg : %s' % self.adict['grdforce']
1560
1561    integerArgs = set( ['p','t','plm'] )
1562    for i in integerArgs.intersection( self.adict ):
1563      self.adict[i] = int( self.adict[i] )
1564
1565    self.intersection = self.adict.get( 'intersection', False )
1566
1567 
1568  def checkArgs( self, notKnownArgs ):
1569    if len( notKnownArgs ) == 0:
1570      return True
1571    print ('--------------------------------------')
1572    print ('------------  %s Arguments Not Recognised ------------' % len(notKnownArgs) )
1573    k = 0
1574    for x in notKnownArgs:
1575      k += 1
1576      if x[1:] in self.knownargs:
1577        print ( '%s PERHAPS %s instead of %s' % (k, x[1:],x) )
1578      elif '-%s' % x in self.knownargs:
1579        print ( '%s PERHAPS -%s instead of %s' % (k, x,x) )
1580      elif x[0] == '\xe2':
1581        print ( '%s POSSIBLY -- (double hyphen) instead of long dash in %s' % (k, x) )
1582    print ('--------------------------------------')
1583
1584    return len( notKnownArgs ) == 0
1585     
1586  def run(self, dq=None):
1587    if 'h' in self.adict:
1588      mlg.prnt ( self.__doc__ )
1589      return
1590
1591    if 'q' in self.adict:
1592      if dq == None:
1593        dq = dreq.loadDreq(configOnly=True)
1594      s = self.adict['q']
1595      if self.adict['q'] == 's':
1596        ss = sorted( [(i.title,i.label) for i in dq.coll['__sect__'].items] )
1597        for s in ss:
1598          mlg.prnt( '%16s:: %s' % (s[1],s[0]) )
1599      else:
1600        ss = [i.label for i in dq.coll['__sect__'].items]
1601        if s.find( ':' ) != -1:
1602          s,a = s.split( ':' )
1603        else:
1604          a = None
1605        if s not in ss:
1606          mlg.prnt( 'ERROR: option must be a section; use "-q s" to list sections' )
1607        elif a == None:
1608          x = [i for i in dq.coll['__sect__'].items if i.label == s]
1609          s1 = [i for i in  dq.coll['__main__'].items if 'ATTRIBUTE::%s' % s in i.uid]
1610          mlg.prnt( x[0].title )
1611          mlg.prnt( ' '.join( sorted  ([i.label for i in s1] ) ))
1612        else:
1613          x = [i for i in dq.coll['__main__'].items if i.uid == 'ATTRIBUTE::%s.%s' % (s,a) ]
1614          if len(x) == 0:
1615            mlg.prnt( 'ERROR: attribute not found' )
1616            s1 = [i for i in  dq.coll['__main__'].items if 'ATTRIBUTE::%s' % s in i.uid]
1617            mlg.prnt( 'ATTRIBUTES: ' + ' '.join( sorted  ([i.label for i in s1] ) ))
1618          else:
1619            mlg.prnt( 'Section %s, attribute %s' % (s,a) )
1620            mlg.prnt( x[0].title )
1621            mlg.prnt( x[0].description )
1622      return
1623
1624    if not ('m' in self.adict or 'SF' in self.adict):
1625      mlg.prnt ( 'Current version requires -m or --SF argument'  )
1626      mlg.prnt ( self.__doc__ )
1627      sys.exit(0)
1628
1629    if dq == None:
1630      self.dq = dreq.loadDreq()
1631    else:
1632      self.dq = dq
1633
1634    if 'l' in self.adict:
1635      self.printList()
1636      return
1637
1638    if 'mcfg' in self.adict:
1639      ll = string.split( self.adict['mcfg'], ',' )
1640      assert len(ll) == 7, 'Length of model configuration argument must be 7 comma separated integers: %s' %  self.adict['mcfg']
1641      lli = [ int(x) for x in ll]
1642
1643    self.sc = dreqQuery( dq=self.dq )
1644
1645    if 'grdforce' in self.adict:
1646      self.sc.gridPolicyForce = self.adict['grdforce']
1647    if 'grdpol' in self.adict:
1648      self.sc.gridPolicyDefaultNative = self.adict['grdpol'] == 'native'
1649      print ( 'SETTING grid policy: %s' % self.sc.gridPolicyDefaultNative )
1650    if 'allgrd' in self.adict:
1651      self.sc.gridPolicyTopOnly = False
1652      print ( 'SETTING grid policy for multiple preferred grids: %s' % self.sc.gridPolicyTopOnly )
1653    if 'unique' in self.adict:
1654      self.sc.uniqueRequest = True
1655    self.sc.gridOceanStructured = not self.adict.get( 'ogrdunstr', False )
1656
1657    if 'mcfg' in self.adict:
1658      self.sc.setMcfg( lli )
1659
1660    tierMax = self.adict.get( 't', 1 )
1661    self.sc.setTierMax(  tierMax )
1662    pmax = self.adict.get( 'p', 1 )
1663
1664    makeXls = self.adict.get( 'xls', False )
1665    makeTxt = self.adict.get( 'txt', False )
1666    ##doSf = 'SF' in self.adict or 'sf' in self.adict
1667    doSf = 'legacy' not in self.adict
1668    if doSf:
1669      self.adict['sf'] = True
1670    assert not ('legacy' in self.adict and 'sf' in self.adict), "Conflicting command line argument, 'legacy' and 'sf': use only one of these"
1671    if makeXls or makeTxt or doSf:
1672      xlsOdir = self.adict.get( 'xlsdir', 'xls' )
1673      self.sc.checkDir( xlsOdir, 'xls files' )
1674
1675    tabByFreqRealm = self.adict.get( 'xfr', False )
1676    if 'SF' in self.adict:
1677      self.sc.gridPolicyDefaultNative = True
1678      vs = volsum.vsum( self.sc, odsz, npy, makeTab=makeTables.makeTab, tables=makeTables.tables, odir=xlsOdir, tabByFreqRealm=tabByFreqRealm )
1679      vs.analAll(pmax)
1680
1681      self.sc.gridPolicyDefaultNative = False
1682      vs = volsum.vsum( self.sc, odsz, npy, makeTab=makeTables.makeTab, tables=makeTables.tables, odir=xlsOdir, tabByFreqRealm=tabByFreqRealm )
1683      vs.analAll(pmax)
1684
1685      self.sc.setTierMax( 3 )
1686      vs = volsum.vsum( self.sc, odsz, npy, makeTab=makeTables.makeTab, tables=makeTables.tables, odir=xlsOdir, tabByFreqRealm=tabByFreqRealm )
1687      vs.analAll(3)
1688      return
1689
1690    ok = True
1691    if self.adict['m'] == '_all_':
1692      self.adict['m'] = set(self.sc.mips )
1693      mlab = 'TOTAL'
1694    else:
1695      for i in self.adict['m']:
1696        if i not in self.sc.mips:
1697          ok = False
1698          mlg.prnt ( 'NOT FOUND: %s' % i )
1699      mlab = makeTables.setMlab( self.adict['m'] )
1700    assert ok,'Available MIPs: %s' % str(self.sc.mips)
1701
1702    eid = None
1703    ex = None
1704    if 'e' in self.adict:
1705      ex = self.adict['e']
1706      if ex in self.sc.mipsp:
1707        eid = set( self.dq.inx.iref_by_sect[ex].a['experiment'] )
1708        self.sc.exptFilter = eid
1709      else:
1710        for i in self.dq.coll['experiment'].items:
1711          if i.label == self.adict['e']:
1712            eid = i.uid
1713        assert eid != None, 'Experiment/MIP %s not found' % self.adict['e']
1714        self.sc.exptFilter = set( [eid,] )
1715
1716    if not self.adict.get( 'esm', False ):
1717      ss = set()
1718      for e in ['esm-hist','esm-hist-ext','esm-piControl','piControl-spinup','esm-piControl-spinup']:
1719        ss.add( self.sc.exptByLabel[ e ] )
1720      self.sc.exptFilterBlack = ss
1721    makeXls = self.adict.get( 'xls', False )
1722
1723    if 'sf' in self.adict:
1724      vs = volsum.vsum( self.sc, odsz, npy, makeTab=makeTables.makeTab, tables=makeTables.tables, odir=xlsOdir, tabByFreqRealm=tabByFreqRealm )
1725      vs.run( self.adict['m'], '%s/requestVol_%s_%s_%s' % (xlsOdir,mlab,tierMax,pmax), pmax=pmax, doxlsx=makeXls ) 
1726      totalOnly = False
1727      if len( self.adict['m'] ) == 1 or totalOnly:
1728        if makeXls:
1729          vsmode='full'
1730        else:
1731          vsmode='short'
1732        vs.anal(olab=mlab,doUnique=False, mode=vsmode, makeTabs=makeXls)
1733        for f in sorted( vs.res['vf'].keys() ):
1734           mlg.prnt ( 'Frequency: %s: %s' % (f, vs.res['vf'][f]*2.*1.e-12 ) )
1735        ttl = sum( [x for k,x in vs.res['vu'].items()] )*2.*1.e-12
1736        mlg.prnt( 'TOTAL volume: %8.2fTb' % ttl )
1737        return
1738     
1739      mips = self.adict['m']
1740      if type(mips) in [type(set()),type(dict())]:
1741          mips = self.adict['m'].copy()
1742          if len(mips) > 1:
1743            if type(mips) == type(set()):
1744               mips.add( '*TOTAL' )
1745            else:
1746               mips['*TOTAL'] = ''
1747
1748      vs.analAll(pmax,mips=mips,html=False,makeTabs=makeXls)
1749      thisd = {}
1750      for m in sorted( self.adict['m'] ) + ['*TOTAL',]:
1751        for f in sorted( vs.rres[m].keys() ):
1752           mlg.prnt ( '%s:: Frequency: %s: %s' % (m,f, vs.rres[m][f]*2.*1.e-12 ) )
1753      for m in sorted( self.adict['m'] ) + ['*TOTAL',]:
1754        thisd[m] = sum( [x for k,x in vs.rres[m].items()] )
1755        mlg.prnt( '%s:: TOTAL volume: %8.2fTb' % (m, thisd[m]*2.*1.e-12 )  )
1756      return
1757
1758
1759    adsCount = self.adict.get( 'count', False )
1760
1761    self.getVolByMip(pmax,eid,adsCount)
1762    makeTxt = self.adict.get( 'txt', False )
1763    if makeXls or makeTxt:
1764      mips = self.adict['m']
1765
1766      if 'txtOpts' in self.adict:
1767        if self.adict['txtOpts'][0] == 'v':
1768          txtOpts = NT_txtopts( 'var' )
1769        else:
1770          txtOpts = NT_txtopts( 'cmv' )
1771      else:
1772        txtOpts=None
1773
1774      self.sc.xlsByMipExpt(mips,eid,pmax,odir=xlsOdir,xls=makeXls,txt=makeTxt,txtOpts=txtOpts)
1775
1776  def printList(self):
1777    mips = self.adict['m']
1778    ee = {}
1779    for i in self.dq.coll['mip'].items:
1780      if i.label in mips:
1781        ee[i.label] = i
1782    if self.adict['l'] in ['o','e']:
1783      targ = {'o':'objective', 'e':'experiment' }[self.adict['l']]
1784      for k in sorted( ee.keys() ):
1785        if targ in self.dq.inx.iref_by_sect[ee[k].uid].a:
1786          for u in self.dq.inx.iref_by_sect[ee[k].uid].a[targ]:
1787            print ( '%s: %s' % (ee[k].label, self.dq.inx.uid[u].label) )
1788    else:
1789      print ('list objective *%s* not recognised (should be e or o)' % self.adict['l'] )
1790     
1791  def getVolByMip(self,pmax,eid,adsCount):
1792
1793    v0 = self.sc.volByMip( self.adict['m'], pmax=pmax, intersection=self.intersection, adsCount=adsCount, exptid=eid )
1794    mlg.prnt ( 'getVolByMip: %s [%s]' % (v0,makeTables.vfmt(v0*2.)) )
1795    cc = collections.defaultdict( int )
1796    for e in self.sc.volByE:
1797      for v in self.sc.volByE[e][2]:
1798          cc[v] += self.sc.volByE[e][2][v]
1799    x = 0
1800    for v in cc:
1801      x += cc[v]
1802   
1803    if python2:
1804      vl = sorted( cc.keys(), cmp=cmpd(cc).cmp, reverse=True )
1805    else:
1806      vl = sorted( cc.keys(), key=lambda x: cc[x], reverse=True )
1807    if self.adict.get( 'vars', False ):
1808      printLinesMax = self.adict.get( 'plm', 20 )
1809      if printLinesMax > 0:
1810        mx = min( [printLinesMax,len(vl)] )
1811      else:
1812        mx = len(vl)
1813
1814      for v in vl[:mx]:
1815        mlg.prnt ( '%s.%s: %s' % (self.dq.inx.uid[v].mipTable,self.dq.inx.uid[v].label, makeTables.vfmt( cc[v]*2. ) ) )
1816      if mx < len(vl):
1817        mlg.prnt ( '%s variables not listed (use --printLinesMax to print more)' % (len(vl)-mx) )
1818
Note: See TracBrowser for help on using the repository browser.