source: CMIP6dreqbuild/trunk/src/workbook/importShDreq2.py @ 558

Subversion URL: http://proj.badc.rl.ac.uk/svn/exarch/CMIP6dreqbuild/trunk/src/workbook/importShDreq2.py@558
Revision 558, 101.2 KB checked in by mjuckes, 5 years ago (diff)

Adding hdldemo

Line 
1"""Import data request from shelves and pu onto compliant XML document.
2------------------------------------------------------------------------
3A new uuid is generated for elements of the "revisedtabitem" section/table (because it is not present in the shelve).
4
5NOTES
6-----
7July 27th: there is an unresolved problem about preserving uuids when updates are provided in source format .....
8"""
9
10### Experiment group dictionary added, and experiment set of named tuples -- making it possible to identify experiments in each mip and group.
11### Should be able to use this in review to make reference groups ...
12
13###
14### Appear to be getting core variables into a clean format
15### Some filtering to avoit duplicates arising from two approaches to OMIP, flagged as ERROR.090 in standard output.
16### Corrected by omitting 2nd reference
17###
18
19import xlrd, xml, os, sys, string, shelve
20import utils_wb, uuid
21import xml.dom, xml.dom.minidom
22import collections, string, re
23import choiceCfg
24import importWbMods
25from utils_wb import uniCleanFunc
26import ivg
27reload(ivg)
28
29WbMods = importWbMods.run()
30
31nt__trace = collections.namedtuple( 'trace', ['GROUPITEM_ta','SPATIALSHAPE_01'] )
32trace = nt__trace( False, False )
33
34tableNameMap = {'CMIP5_3hr':'3hr', 'CMIP5_6hrLev':'6hrLev', 'CMIP5_6hrPlev':'6hrPlev', 'CMIP5_Amon':'Amon', 'CMIP5_LImon':'LImon', 'CMIP5_Lmon':'Lmon', 'CMIP5_OImon':'CMIP5_OImon', 'CMIP5_Oclim':'Oclim', 'CMIP5_Omon':'CMIP5_Omon', 'CMIP5_aero':'aero', 'CMIP5_cf3hr':'cf3hr', 'CMIP5_cfDay':'cfDay', 'CMIP5_cfMon':'cfMon', 'CMIP5_cfOff':'cfOff', 'CMIP5_cfSites':'cfsites', 'CMIP5_day':'day', 'CMIP5_fx':'fx', 'OMIP.Omon':'Omon', 'OMIP.Oyr':'Oyr', 'OMIP.day':'Oday', 'OMIP.fx':'Ofx' }
35
36reportedRedundantTables = set()
37redundantTables = ['CMIP5_Oyr','CMIP5_Omon','CMIP5_OImon','CORDEX_3h', 'CORDEX_6h', 'CORDEX_fx', 'CORDEX_mon', 'CORDEX_sem', 'PMIP3_Aclim', 'PMIP3_Amon', 'PMIP3_LIclim', 'PMIP3_LImon', 'PMIP3_Lclim', 'PMIP3_Lmon', 'PMIP3_OIclim', 'PMIP3_OImon', 'PMIP3_Oclim', 'PMIP3_Omon', 'PMIP3_day', 'PMIP3_fx', 'SPECS_6hr', 'SPECS_Lmon', 'SPECS_fx']
38
39## mapping of variable groups representing tables ....
40mappedTables =  {'Omon':'OMIP-Omon', 'OMIP-Oyr':'Oyr', 'OImon':'SIMIP-seaicemon' }
41mappedTables =  {'Omon':'OMIP-Omon', 'CMIP5-Oyr':'OMIP-Oyr', 'OImon':'SIMIP-seaicemon', 'CMIP5-Omon':'OMIP-Omon' }
42
43freqmap = {'daily':'day', 'Annual':'yr', 'Timestep':'subhr',  '1day':'day', '1mon':'mon', 'month':'mon', 'year':'yr', 'monthly':'mon', 'Day':'day', '6h':'6hr', '3 hourly':'3hr', '3 Hourly':'3hr'  }
44
45nt_expt = collections.namedtuple( 'expt', ['uid', 'label', 'mip', 'egid' ] )
46realmdef = { '__all__':['CFMIP [cfMonExtra]', 'PMIP [PMIP-Omon]', 'LS3MIP [LCmon]', 'C4MIP [C_Ocean_T2]', 'C4MIP [C_Ocean_T1]', 'LUMIP [Lyr_Lut]', 'PMIP [PMIP-LIclim]', 'HighResMIP [1hr_strat]', 'SIMIP [seaiceday]', 'C4MIP [C_LandT1]', 'CFMIP [cfDay_2d_new]', 'HighResMIP [6hrPlev_intense]', 'HighResMIP [Amon_diag]', 'DCPP [DCPP-mon]', 'HighResMIP [Amon_conv]', 'SIMIP [seaicemon]', 'DAMIP [new_monthly]', 'FAFMIP [fafOyrB]', 'HighResMIP [Amon_ext]', 'DynVar [DYVR_daily]', 'PMIP [PMIP-Aclim]', 'HighResMIP [3hr_extr]', 'C4MIP [C_Basic]', 'DCPP [DCPP-day]', 'CFMIP [cfMon_3dstd_new]', 'FAFMIP [fafOmon]', 'ISMIP6 [new_fx]', 'LS3MIP [LEday]', 'PMIP [PMIP-aeroclim]', 'PMIP [PMIP-aero]', 'DCPP [DCPP-6hr]', 'DynVar [DYVR_monthly]', 'ISMIP6 [icesheetmon]', 'CFMIP [aeroDay_2d]', 'ISMIP6 [new_LImon]', 'ISMIP6 [new_Omon]', 'CFMIP [cfDayExtra]', 'LS3MIP [LWday]', 'PMIP [PMIP-Oclim]', 'ISMIP6 [icesheetyear]', 'LUMIP [Lmon_Lut]', 'HighResMIP [1ts]', 'PMIP [PMIP-OIclim]', 'HighResMIP [6hrPlev_extr_dr]', 'VolMIP [VIRF]', 'C4MIP [C_LandT2]', 'C4MIP [C_Hist]', 'FAFMIP [fafOmonB]', 'RFMIP [aero_irf]', 'PMIP [PMIP-Lmon]', 'C4MIP [L_day]', 'PMIP [PMIP-Lclim]', 'PMIP [PMIP-Amon]', 'GeoMIP [aeroGeo]', 'HighResMIP [6hrPlev_extr]', 'PMIP [PMIP-day]', 'HighResMIP [Amon_sparc]', 'CFMIP [cfSites_new]', 'CFMIP [cf3hr_sim]'], 
47        'atmos':['CFMIP [cfMonExtra]', 'HighResMIP [1hr_strat]', 'CFMIP [cfDay_2d_new]', 'HighResMIP [6hrPlev_intense]', 'HighResMIP [Amon_diag]', 'DCPP [DCPP-mon]', 'HighResMIP [Amon_conv]', 'DAMIP [new_monthly]', 'HighResMIP [Amon_ext]', 'DynVar [DYVR_daily]', 'PMIP [PMIP-Aclim]', 'HighResMIP [3hr_extr]', 'DCPP [DCPP-day]', 'CFMIP [cfMon_3dstd_new]', 'PMIP [PMIP-aeroclim]', 'PMIP [PMIP-aero]', 'DCPP [DCPP-6hr]', 'DynVar [DYVR_monthly]', 'CFMIP [aeroDay_2d]', 'CFMIP [cfDayExtra]', 'HighResMIP [1ts]', 'HighResMIP [6hrPlev_extr_dr]', 'VolMIP [VIRF]', 'RFMIP [aero_irf]', 'PMIP [PMIP-Amon]', 'GeoMIP [aeroGeo]', 'HighResMIP [6hrPlev_extr]', 'PMIP [PMIP-day]', 'HighResMIP [Amon_sparc]', 'CFMIP [cfSites_new]', 'CFMIP [cf3hr_sim]'],
48        'ocean':['PMIP [PMIP-Omon]', 'C4MIP [C_Ocean_T1]', 'C4MIP [C_Ocean_T2]', 'FAFMIP [fafOyrB]', 'FAFMIP [fafOmon]', 'ISMIP6 [new_Omon]', 'PMIP [PMIP-OIclim]', 'FAFMIP [fafOmonB]', 'PMIP [PMIP-Oclim]'],
49        'land':['LS3MIP [LCmon]', 'C4MIP [C_Hist]', 'C4MIP [L_day]', 'PMIP [PMIP-Lclim]', 'C4MIP [C_Basic]', 'LUMIP [Lmon_Lut]', 'LUMIP [Lyr_Lut]', 'C4MIP [C_LandT1]', 'PMIP [PMIP-Lmon]', 'C4MIP [C_LandT2]'],
50        'seaIce':['SIMIP [seaicemon]', 'SIMIP [seaiceday]' ],
51        'landIce':['ISMIP6 [new_LImon]', 'PMIP [PMIP-LIclim]', 'ISMIP6 [icesheetyear]', 'ISMIP6 [new_fx]', 'ISMIP6 [icesheetmon]'],
52        '__unset__':['LS3MIP [LWday]', 'LS3MIP [LEday]'] }
53
54realmdefix = {}
55for k in realmdef.keys():
56  if k != '__all__':
57    for s in realmdef[k]:
58      assert not realmdefix.has_key(s), 'Duplicate targ value in realmdef: %s [%s]' % (s,k)
59      realmdefix[s] = k
60
61for k in realmdef['__all__']:
62  assert realmdefix.has_key(k), 'Key %s not found in realmdefix' % k
63
64class cls_s1(object):
65  def __init__(self):
66    self.a = collections.defaultdict( list )
67
68def mycc(s):
69      s = string.replace( s, '&', '' )
70      if len(s) > 0 and s[-1] == '+':
71        s = s[:-1] + 'ETC'
72## camelcase the input string
73      s1 = string.lower( string.replace(string.strip(str( s) ), '-', ' ') )
74      return string.replace( string.capwords( s1 ), ' ', '' )
75
76empty=re.compile('^$')
77
78def test( x,m):
79  if not x:
80    print m
81  return x
82
83class lcm(object):
84  def __init__(self,a,b):
85    self.a = {}
86    self.b = {}
87    for i in a:
88      self.a[string.lower(i)] = i
89    for i in b:
90      self.b[string.lower(i)] = i
91
92class main(object):
93
94  def __init__(self,src,rq,doRepl=False,run=False,schemaMode='dreq'):
95    self.schemaMode = schemaMode
96    self.requestlinkuid = set()
97    self.src=src
98    self.vgcheck = {}
99    self.rqlPreset = {}
100    fok = [test(os.path.isfile(src),'%s not found' % src), ]
101    assert all( fok), 'Required input file(s) missing'
102    self.fx = WbMods.fx
103    self.spsh = WbMods.ls
104    self.cmDims = WbMods.cm
105    self.importWbMods = WbMods
106
107    for sh in [rq.expt,rq.exgp,rq.objec,rq.refti, rq.revti, rq.vars, rq.grps, rq.rqvg, rq.rqli, rq.rqit, rq.rqsect]:
108       print sh['__info__']
109
110    self.repl = collections.defaultdict( list )
111    self.err0010 = collections.defaultdict( int )
112    self.replItems = {}
113    self.defaultP = {}
114    self.remo = {}
115    self.upda = {}
116    self.insert = {}
117    self.exptSet = set()
118    self.exptGrpDict = {}
119
120    self.objectives = collections.defaultdict( dict )
121    self.objectiveLinks = collections.defaultdict( cls_s1 )
122    self.experiments = {}
123    self.experimentGrp = {}
124    self.exptPntUid = {}
125    self.exptPnt = collections.defaultdict( list )
126    self.mips = set()
127    self.dsortdd = {}
128
129    if doRepl:
130      self.importRepl()
131      self.importRemove()
132      self.importUpdate()
133      self.importInsert()
134    self.e15_10 = 0
135    self.doc = xml.dom.minidom.parse( self.src  )
136    self.vocabs = xml.dom.minidom.parse( 'vocabs.xml' )
137    self.skey = {'experiment':rq.expt, 'exptgroup':rq.exgp, \
138         'objective':rq.objec, 'var':rq.vars,'ovar':rq.refti, 'groupitem':rq.grps, \
139         'revisedtabitem':rq.revti, 'requestlink':rq.rqli, 'requestitem':rq.rqit, \
140         'requestvargroup':rq.rqvg, 'tablesection':rq.rqsect, 'requestvar':rq.revti}
141
142    self.newImport = False
143    self.prepVar()
144    self.writeTimeSlice()
145    self.writeMip()
146    self.writeSn()
147    self.writeMcfg()
148    self.writeCmDim()
149    self.writeVar()
150    self.prep01()
151    self.prepRequestVarGroup()
152    self.prep(rq)
153    self.addAerChem()
154    self.prepRequestItem()
155    self.reviewExpt()
156    if run:
157      self.run(rq)
158      self.prepRequestLink()
159      self.finishRequestLink()
160      if self.schemaMode == 'dreq2':
161        self.write2()
162      self.finish()
163
164  def writeMcfg(self):
165    self.cfgUids = set()
166    xx = self.vocabs.getElementsByTagName( 'modelConfig' )
167    assert len(xx) == 1, 'Expecting one element named "modelConfig", found %s' % len(xx)
168    iDoc = xx[0]
169## <item id="tmpid.0003" label="C4MIP" status="" title="Coupled Climate Carbon Cycle Model Intercomparison Project" url="http://c4mip.lsce.ipsl.fr/"/>
170    thiss = self.doc.getElementsByTagName( 'modelConfig' )[0]
171    dil = thiss.getElementsByTagName('item')
172    for d in dil:
173      thiss.removeChild(d)
174    for i in iDoc.getElementsByTagName('item'):
175      item = self.doc.createElement( 'item' )
176      thisl = i.getAttribute( 'label' )
177      for k in ['title','MIPs','usage','range','type']:
178        item.setAttribute( k, i.getAttribute( k ) )
179      uid = str( thisl )
180      item.setAttribute( 'uid', uid )
181      item.setAttribute( 'label', uid )
182      self.cfgUids.add( uid )
183      thiss.appendChild( item )
184
185  def writeCmDim(self):
186    thiss = self.doc.getElementsByTagName( 'grids' )[0]
187    dil = thiss.getElementsByTagName('item')
188    for d in dil:
189      thiss.removeChild(d)
190    kk =  ['tables','label','altLabel','description','standardName','title','axis','units','isIndex','coords','bounds','direction','valid_min','valid_max','type','positive','value','boundsValues','requested','boundsRequested','tolRequested','isGrid' ]
191    for j in self.cmDims.ss.keys():
192      item = self.doc.createElement( 'item' )
193      for i in range(len(kk)):
194        if kk[i] in ['valid_min','valid_max']:
195          if str( self.cmDims.ss[j][i] ) != '':
196            item.setAttribute( kk[i], str( self.cmDims.ss[j][i] ) )
197        else:
198          item.setAttribute( kk[i], str( self.cmDims.ss[j][i] ) )
199      uid = 'dim:%s' % str( self.cmDims.ss[j][1] )
200      item.setAttribute( 'uid', uid )
201      thiss.appendChild( item )
202
203  def writeVar(self):
204    thiss = self.doc.getElementsByTagName( 'var' )[0]
205    dil = thiss.getElementsByTagName('item')
206    for d in dil:
207      thiss.removeChild(d)
208#<item description="dummyAt" id="001.001.001" label="example-01" procComment="dummyAt" procnote="dummyAt" prov="dummyAt" provmip="dummyAt" sn="dummyAt" title="dummy title string" uid="fa349c44-9ccb-11e5-8176-5404a60d96b5" units="dummyAt"/>
209    kk= ['label', 'title', 'description', 'procComment', 'procnote', 'prov', 'provmip', 'sn', 'units', 'uid','defaultp']
210    for uid in self.importWbMods.vars.d1:
211      item = self.doc.createElement( 'item' )
212      thisr = self.importWbMods.vars.d1[uid]
213      for i in range( len(kk) -1 ):
214           item.setAttribute( kk[i], thisr[i] )
215      if len( self.importWbMods.vars.c1[ thisr[0] ] ) == 1:
216         id = thisr[0]
217      else:
218         id = '%s.%s' % (thisr[0],self.importWbMods.vars.c1[ thisr[0] ].index( uid ) )
219         print 'INFO.090.00050: setting id for non-unique variable name: %s' % id
220      item.setAttribute( 'id', id )
221      thiss.appendChild( item )
222
223  def writeSn(self):
224    import loadcf
225    cf = loadcf.cf()
226    thiss = self.doc.getElementsByTagName( 'standardname' )[0]
227    dil = thiss.getElementsByTagName('item')
228    for d in dil:
229      thiss.removeChild(d)
230
231    for i in sorted( cf.names.keys() ):
232      item = self.doc.createElement( 'item' )
233      d,u = cf.names[i]
234      uid = str(i)
235      title = string.capwords( string.replace( uid, '_', ' ' ) )
236      label = string.replace( title, ' ', '' )
237      for w in ['Of','In','On','By']:
238        ww = ' %s ' % w
239        title = title.replace( ww, string.lower( ww ) )
240      item.setAttribute( 'uid', uid  )
241      item.setAttribute( 'label', label  )
242      item.setAttribute( 'title', title  )
243      item.setAttribute( 'units', str(u) )
244      item.setAttribute( 'description', str(d) )
245      thiss.appendChild( item )
246
247  def writeTimeSlice(self):
248    xx = self.vocabs.getElementsByTagName( 'timeSlice' )
249    assert len(xx) == 1, 'Expecting one element named "activity", found %s' % len(xx)
250    iDoc = xx[0]
251    thiss = self.doc.getElementsByTagName( 'timeSlice' )[0]
252    dil = thiss.getElementsByTagName('item')
253    for d in dil:
254      thiss.removeChild(d)
255
256    for i in iDoc.getElementsByTagName('item'):
257      item = self.doc.createElement( 'item' )
258      label = i.getAttribute( 'label' )
259      for k in ['label','title','type']:
260        item.setAttribute( k, i.getAttribute( k ) )
261      for k in ['start', 'end', 'step', 'sliceLen', 'nyears']:
262        if i.getAttribute( k ) != '':
263          v = str( int( float( i.getAttribute( k ) ) ) )
264          item.setAttribute( k, v )
265      item.setAttribute( 'uid', '_slice_%s' % label )
266      thiss.appendChild( item )
267
268  def writeMip(self):
269    self.mipUids = set()
270    xx = self.vocabs.getElementsByTagName( 'activity' )
271    assert len(xx) == 1, 'Expecting one element named "activity", found %s' % len(xx)
272    mipDoc = xx[0]
273## <item id="tmpid.0003" label="C4MIP" status="" title="Coupled Climate Carbon Cycle Model Intercomparison Project" url="http://c4mip.lsce.ipsl.fr/"/>
274    thiss = self.doc.getElementsByTagName( 'mip' )[0]
275    dil = thiss.getElementsByTagName('item')
276    for d in dil:
277      thiss.removeChild(d)
278    for i in mipDoc.getElementsByTagName('item'):
279      item = self.doc.createElement( 'item' )
280      mip = i.getAttribute( 'label' )
281      for k in ['title','url']:
282        item.setAttribute( k, i.getAttribute( k ) )
283      uid = string.replace( mip, ' ', '' )
284      item.setAttribute( 'uid', uid )
285      item.setAttribute( 'label', uid )
286      self.mipUids.add( uid )
287      thiss.appendChild( item )
288
289    if "DECK" not in self.mipUids:
290      item = self.doc.createElement( 'item' )
291      item.setAttribute( 'uid', 'DECK' )
292      item.setAttribute( 'url', '' )
293      item.setAttribute( 'label', 'DECK' )
294      item.setAttribute( 'title', 'DECK - set of standard CMIP runs' )
295      self.mipUids.add( "DECK" )
296      thiss.appendChild( item )
297
298  def prepRequestVarGroup(self):
299    self.varGroupByLabel = {}
300    self.varGroupUids = set()
301    nsev = 0
302    ss = set()
303    for k in ['requestvargroup','tablesection']:
304      if k == 'requestvargroup':
305              kk = ['uid', 'mip', 'label', 'title', 'ref', 'refNote']
306              il = 2
307      else:
308              kk = ['uid', 'gpid', 'mip', 'label', 'title', 'ref', 'refNote']
309              il = 3
310      thissh = self.skey[k]
311      for r in thissh:
312        if r[0] != '_':
313          thisl = str( thissh[r][il] )
314          if self.varGroupByLabel.has_key( thisl ):
315            print 'ERROR.090.00012: Duplicate label in variable groups: %s' % thisl
316            nsev += 1
317            ss.add( thisl )
318          self.varGroupByLabel[thisl] = r
319          self.varGroupUids.add( thissh[r][0] )
320
321    for k in self.prqv.exrqvg.keys():
322         ll = self.prqv.exrqvg[k]
323         thisl = string.replace( str( ll[2] ), '.', '-' )
324         if self.varGroupByLabel.has_key( thisl ):
325            print 'ERROR.090.00012: Duplicate label in variable groups: %s' % thisl
326            nsev += 1
327            ss.add( thisl )
328         self.varGroupByLabel[thisl] = k
329         self.varGroupUids.add( ll[0] )
330
331    self.rvgUidMapping = {}
332    for k in mappedTables.keys():
333      assert k not in ss and mappedTables[k] not in ss, 'Ambiguous table mapping because of duplicate variable group labels: %s' % k
334      ##assert self.varGroupByLabel.has_key( k ),'Table mapping key not found: %s' % k
335      assert self.varGroupByLabel.has_key( mappedTables[k] ),'Table mapping target not found: %s [%s]' % (mappedTables[k], str(self.varGroupByLabel.keys()) )
336      if k in mappedTables and k in self.varGroupByLabel:
337        self.rvgUidMapping[self.varGroupByLabel[k]] = self.varGroupByLabel[ mappedTables[k] ]
338        print 'INFO.090.00012: request variable mapping initialised: %s --> %s' % (k,mappedTables[k])
339      else:
340        print 'INFO.090.00011: request variable mapping NOT initialised: %s --> %s' % (k,mappedTables[k])
341     
342    assert nsev < 20, 'Multiple duplicate labels in variable groups: %s' % nsev
343
344  def prepVar(self):
345      thissh = self.skey['var']
346      self.varsxx = None
347      if self.newImport:
348#['label', 'title', 'sn', 'units', 'description', 'procnote', 'procComment', 'prov', 'priority0', 'rlm0']
349        self.vars = collections.defaultdict( list )
350        self.vars1 = collections.defaultdict( list )
351        for k in thissh:
352          if k[0] != '_':
353            ll = thissh[k][:]
354            thisl = str( ll[2] )
355            self.vars[thisl].append( k )
356            self.vars1[str( ll[0] )].append( k )
357      else:
358        self.varsxx = collections.defaultdict( list )
359        for k in thissh:
360          if k[0] != '_':
361            ll = thissh[k][:]
362            thisl = str( ll[2] )
363            self.varsxx[str( ll[0] )].append( k )
364       
365
366  def prepRequestItem(self):
367      thissh = self.skey['requestitem']
368      s1 = collections.defaultdict( set )
369      for k in thissh:
370        if k[0] != '_':
371          ll = thissh[k][:]
372          ku = str(ll[2])
373          s1[ll[0]].add(ll[-1])
374##
375          self.exptPnt[ku].append( str(k) )
376      print 'INFO.dddd: %s: %s' % ('DAMIP',str( s1['DAMIP'] ) )
377      self.tsliceMap = {}
378      self.tsliceMap['DAMIP'] = {'18 (1850, 1860, ..,  2010, 2020)':'DAMIP18', 'all':None, '8\n(2030, 2040, .., 2090, 2100)':'DAMIP8', '61\n(1960-2020)':'DAMIP61', '40\n(2026-2045, 2081-2100)':'DAMIP40', '20\n(2081-2100)':'DAMIP20', '42\n(1979-2020)':'DAMIP42' }
379
380      thissh = self.skey['experiment']
381      for k in thissh:
382        if k[0] != '_':
383          ll = thissh[k][:]
384          thisl = str( ll[2] )
385          self.mips.add( str( ll[4] ) )
386          self.experiments[thisl] = str( ll[0] )
387          self.exptSet.add( nt_expt._make( [str( ll[0] ), thisl, str( ll[4] ), str( ll[1] ) ] ) )
388          ##nt_expt = collections.namedtuple( 'expt', ['uid', 'label', 'mip', 'egid' ] )
389
390      thissh = self.skey['exptgroup']
391      for k in thissh:
392        if k[0] != '_':
393          ll = thissh[k][:]
394          thisl = str( ll[1] )
395          self.exptGrpDict[thisl] = str( ll[1] )
396          self.experimentGrp[thisl] = str( ll[0] )
397
398      mm = []
399      for m in self.mips:
400        if m not in self.mipUids:
401          mm.append(m)
402      assert len(mm) == 0, 'Not all mips found: %s: %s' % (str(mm),str(self.mipUids))
403
404  def prepRequestLink(self):
405      s0 = {' ta, ua, va, zg, hus', 'zg', 'utendogw, utendnogw, vtendogw,vtendnogw', 'tntogw,tntnogw', 'tasmax,tasmin,pr,prc,uas,vas', 'utendogw,utendnogw, and psistar, utendvstarad, utendwstarad', ' ta, ua, va, wap, zg, hus', 'vstar, wstar, fy, fz, utenddivf, utendogw, utendnogw, diabdrag[utenddiabdrag]', 'vmro3', 'tauu,tauv, tauu_pbl, tauv_pbl', 'tauu,tauv, tauu-pbl, tauv-pbl', ' tas, pr, psl', 'vstar, wstar, fy, fz, utenddivf', ' tas, pr, psl, uas', 'zmtnt, tntlw, tntsw', 'pr,prc',
406      'concdust,concaerh2o,reffclwc,emiso4,loadso4,concso2,emidust,emiss,conccmcn,emiso2,concnmcn,concss,reffclws,loadss,conccn',
407      'rsdsdiff,dryso4,wetso2,cldnci,od550lt1aer,reffclwtop,dryss,wetso4,sconcso4,cldncl,abs550aer,wetss,rsdscsdiff,wetdust,ec550aer,cldnvi,dryso2,drydust,od550aer,sconcss,sconcdust',
408      'thkcello,wmo,uo,hfnorth,tos,sos,soga,masscello,hfy,msftmrhoz,masso,pso,mlotst,zos,zostoga,rhopoto,hfydiff,hfbasin,ficeberg2d,thetao,so,zossga,dpco2,msftmyz,tauvo,sfdsi,msftyrhoz,spco2,fddtalk,hfxdiff,omlmax,htovovrt,sltovovrt,vmo,tauuo,volo,zsatarag,fgco2,zosga,wfo,vo,msftyyz,mfo,ficeberg,friver,msftbarot,umo,intpcalcite,intparag,fddtdic,hfx,agessc,hfbasindiff',
409      'difvmo,difvho,difvso' }
410      s1 = {'vstar, wstar, fy, fz, acceldivf[utenddivf], accelogw[utendogw], accelnogw[utendnogw], diabdrag[utenddiabdrag]'}
411      self.varGroupSs2 = collections.defaultdict( cls_s1 )
412      self.varGroupSubset = collections.defaultdict( dict )
413      kk = ['uid', 'mip', 'tab', 'objective', 'grid', 'gridreq', 'comment', 'opt','opar','preset', 'ref', 'refNote', 'refid']
414##
415## preset is in the wrong place here ..... should be on the linked experiment group ...
416## probable better to edit the sheet and create a new group,  but in such a way that this class can generate the links and new variables....
417##
418# create lists of variables wanted from groups, indexed by uid of group and requestLink
419      thissh = self.skey['requestlink']
420      for k in thissh:
421        if k[0] != '_':
422          rr = thissh[k][:]
423          if rr[8] in s0:
424            vl0 = map( string.strip, string.split( rr[8], ',' ) )
425            print 'INFO.077.07060: rr[8] matched .... ', rr[8]
426          elif rr[7] in s0:
427            print 'INFO.077.07070: rr[7] matched .... ', rr[7]
428            vl0 = map( string.strip, string.split( rr[7], ',' ) )
429          elif rr[8] in s1:
430            print 'INFO.077.07071: rr[7] matched .... ', rr[8]
431            vl0 = map( string.strip, string.split( rr[8], ',' ) )
432            ##for i in range( len( vl0) ):
433              ##if string.find( vl0[i], '[' ) != -1:
434                ##a,b = string.split( vl0[i], '[' )
435                ##vl0[i] = (a,b[:-1])
436          else:
437            vl0 = None
438
439          if vl0 != None:
440            vl = set()
441            for v in vl0:
442              if string.find( v, '[' ) != -1:
443                bits = string.split( v, '[' )
444                vl.add( (bits[0],bits[1][:-1]) )
445              else:
446                vl.add(v)
447            m = str(rr[1])
448
449            self.varGroupSubset[str(rr[-1])][rr[0]] = vl
450            self.varGroupSs2[str(rr[-1])].a[(m,tuple(vl))].append(rr[0])
451            print 'INFO.077.07080: ',m,vl, rr[-1]
452
453##
454## not finding new variables .... may be better to redefine the groups ...
455##
456###
457### get full list of variables for each variable group
458###
459      thissh = self.skey['requestvar']
460      kk = ['label', 'table', 'mip', 'vid', 'priority','vgid','title','uid']
461      varGroupFull = collections.defaultdict( dict )
462      for k in thissh:
463        if k[0] != '_':
464          ll = thissh[k][:]
465          vgid = self.prqv.rqv_vg['%s.%s.%s' % (ll[2],ll[1],ll[0])]
466          ##if ll[1][:4] == 'DYVR':
467          print 'INFO.802.00001: ',ll, vgid in self.varGroupSubset.keys()
468          if vgid in self.varGroupSubset.keys():
469             varGroupFull[vgid][ll[0]] = k
470
471      for ll in self.rqv:
472          vgid = ll[  self.rqvinfo.index('gpid') ]
473          if vgid in self.varGroupSubset.keys():
474             varGroupFull[vgid][ll[1]] = ll[0]
475###
476### check that all variable groups covered
477###
478      nf = []
479      for k in self.varGroupSubset.keys():
480       if not (k in varGroupFull):
481         nf.append(k)
482
483      if len(nf) != 0:
484        for k in nf:
485          for k2 in self.varGroupSubset[k].keys():
486            print 'ERROR.080.06000: Variable group not found: ',k,k2,self.varGroupSubset[k][k2]
487##
488## some missing groups ...
489## appear to be missing MIP tables, e.g. CCMI_monthly
490## CCMI_monthly exists, but has no variables linking to it.
491##
492        print 'ERROR.080.06000:  %s %s' % (len(nf),len(varGroupFull.keys()))
493
494
495      shrvg = self.skey['requestvargroup']
496      for k in self.varGroupSs2:
497        if k not in varGroupFull:
498          print 'ERROR.080.06001: not in varGroupFull: %s [%s] %s' % (k,str(self.varGroupSs2[k].a.keys()), str( shrvg[k] ) )
499
500      self.rqvClone = collections.defaultdict( list )
501      self.rqvgrpExtra = []
502      self.rqlRedirect = {}
503      for k in varGroupFull:
504        for m,k2 in self.varGroupSs2[k].a:
505          ok1 = []
506          for i in k2:
507            i1 = i
508            if type(i) in [type(''),type(u'')]:
509              if string.find( i, 'and ' ) != -1:
510                i1 = string.split(i)[-1]
511                print 'INFO.099.09090: split i:',i,i1
512              ok1.append( varGroupFull[k].has_key(i1) )
513            elif type(i) == type( () ) and len(i) == 2:
514              ok1.append( varGroupFull[k].has_key(i[0]) or varGroupFull[k].has_key(i[1]) )
515            else:
516              print 'ERROR.080.06055: skipping unrecogised element: ',i
517              ok1.append( False )
518
519          ok = all( ok1 )
520          if not ok:
521            k2m = [  k2[i]  for i in range(len(k2)) if not ok1[i] ]
522            print 'ERROR.080.06060: not all vars found [%s] %s' % ( k, str(k2m) )
523          else:
524##
525## create new variable group and update link(s)
526##
527            gpid = str( uuid.uuid1() )
528            for rqlid in self.varGroupSs2[k].a[(m,k2)]:
529              self.rqlRedirect[rqlid] = gpid
530              ##kk = ['uid', 'mip', 'label', 'title', 'ref', 'refNote']
531## e.g. ['4db2f616-6d9e-11e5-b29a-ac72891c3257', 'DAMIP', u'DynVar-day', u'DAMIP: DynVar-day', 'new', u'DynVar.DYVR_daily']
532            ll =  rq.rqvg[k][:]
533            ll[0] = gpid
534            ll[2] += '-subset'
535            ll[-1] += ' (subset)'
536            self.rqvgrpExtra.append( ll )
537            print 'INFO.080.06060: subset validated, ', ll
538            for i in k2:
539##
540## set a marker to clone request variable record, with new group id
541##
542              i1 = i
543              if type(i) == type( () ) and len(i) == 2:
544                if varGroupFull[k].has_key(i[0]):
545                  i1 = i[0]
546                else:
547                  i1 = i[1]
548              elif string.find( i, 'and ' ) != -1:
549                i1 = string.split(i)[-1]
550              self.rqvClone[varGroupFull[k][i1]].append( gpid )
551
552  def finishRequestLink(self):
553    this = self.doc.getElementsByTagName('requestVarGroup')[0]
554## e.g. ['4db2f616-6d9e-11e5-b29a-ac72891c3257', 'DAMIP', u'DynVar-day', u'DAMIP: DynVar-day', 'new', u'DynVar.DYVR_daily']
555    kk = ['uid', 'mip', 'label', 'title', 'ref', 'refNote']
556    for ll in self.rqvgrpExtra:
557         item = self.doc.createElement( 'item' )
558         for j in range(len(kk)):
559              if kk[j] == 'refNote':
560                item.setAttribute( kk[j], str( ll[j] ) + '((isd.010))' )
561              else:
562                item.setAttribute( kk[j], str( ll[j] ) )
563         this.appendChild( item )
564##
565
566  def prep01(self):
567#### prepare some links for request variables
568    addex = True
569    self.prqv = ivg.prepRequestVar(addex)
570    self.prqv.run()
571
572  def prep(self,rq):
573## keys here match section element names in schema
574    #for k in [ 'var','ovar','groupitem', 'revisedtabitem']:
575## lists for 3 new sections
576### uuid, spid, tmid, cell_methods, cell_measures, description, procNote, prov
577    structure = [] 
578    self.structInfo = {}
579### uuid, label, dimensions, shape, levels, levelFlag
580    spatialshp = []
581### uuid, label, dimension, tstyle
582    temporalshp = []
583### cmor variables
584    self.cmv = []
585    self.cmvUidByFL = collections.defaultdict( cls_s1 )
586    self.cmvUidByTab = collections.defaultdict( cls_s1 )
587    self.cmvs = set()
588    self.cmvinfo = ('uid','stid','label','title','description','vid', \
589                    'deflate_level', 'shuffle', 'ok_max_mean_abs', 'flag_meanings', 'type', 'ok_min_mean_abs',  \
590                    'deflate', 'valid_min', 'flag_values', 'modeling_realm', 'valid_max', 'positive', 'mipTable', \
591                    'prov', 'provNote', 'frequency', 'rowIndex', 'coordinates','defaultPriority')
592    self.cmvinfo2 = ('uid','stid','label','title','description','vid', \
593                    'deflate_level', 'shuffle', 'ok_max_mean_abs', 'type', 'ok_min_mean_abs',  \
594                    'deflate', 'valid_min', 'modeling_realm', 'valid_max', 'positive', 'mipTable', \
595                    'prov', 'provNote', 'frequency', 'rowIndex', 'defaultPriority')
596    self.rqvinfo = ('uid','label','vid','gpid','priority','mip','table' )
597
598
599    thissh = self.skey['var']
600    self.varUidByName = self.importWbMods.vars.c1
601    ##self.varUidByName = collections.defaultdict( list )
602    if self.newImport:
603      oo = open('refDefaultP.txt', 'w' )
604      for k in thissh:
605         if k[0] != '_':
606##['label', 'title', 'sn', 'units', 'description', 'procnote', 'procComment', 'prov', 'priority0']
607            thisuuid = str(k)
608            self.defaultP[thisuuid] = thissh[k][-1]
609            oo.write( '%s\t%s\t%s\t%s\n' % (k, thissh[k][0], thissh[k][2], thissh[k][-1] ) )
610            ##self.varUidByName[thissh[k][0]].append( thisuuid )
611      oo.close()
612    else:
613      ## ['label', 'title', 'description', 'procComment', 'procnote', 'prov', 'provmip', 'sn', 'units', 'uid','defaultp']
614      self.vars = collections.defaultdict( list )
615      self.vars1 = collections.defaultdict( list )
616      for uid in self.importWbMods.vars.d1:
617        self.defaultP[uid] = self.importWbMods.vars.d1[uid][-1]
618## collection indexed by short_name
619        self.vars1[self.importWbMods.vars.d1[uid][0]].append( uid )
620## collection indexed by standard_name
621        self.vars[self.importWbMods.vars.d1[uid][7]].append( uid )
622
623### request variables
624    self.rqv = []
625    self.realmByVar = collections.defaultdict( list )
626    for ksect in [ 'ovar','groupitem']:
627      thissh = self.skey[ksect]
628      if ksect == 'ovar':
629            setu1 = set()
630            tab2freq = {u'CMIP5_cfOff':'subhr', u'CORDEX_mon':'mon', u'SPECS_day':'day', u'CMIP5_day':'day', \
631                  u'PMIP3_OImon':'mon', u'CORDEX_day':'day', u'CMIP5_LImon':'mon', u'CMIP5_OImon':'mon', \
632                  u'CMIP5_Lmon':'mon', u'CMIP5_3hr':'3hr', u'CMIP5_Omon':'mon', u'PMIP3_OIclim':'monClim', \
633                  u'PMIP3_fx':'fx', u'CORDEX_fx':'fx', u'PMIP3_LImon':'mon', u'CMIP5_6hrPlev':'6hr', u'PMIP3_Lmon':'mon', \
634                  u'PMIP3_Amon':'mon', u'SPECS_Omon':'mon', u'CCMI1_fixed':'fx', u'PMIP3_Aclim':'monClim', u'CMIP5_6hrLev':'6hr', \
635                  u'CMIP5_Oclim':'monClim', u'PMIP3_LIclim':'monClim', u'CCMI1_monthly':'mon', u'CMIP5_fx':'fx', \
636                  u'CMIP5_cfDay':'day', u'CORDEX_6h':'6hr', u'PMIP3_day':'day', u'SPECS_OImon':'mon', u'CMIP5_cfMon':'mon', \
637                  u'CORDEX_sem':'monClim', u'SPECS_6hr':'6hr', u'CMIP5_cfSites':'subhr', u'CCMI1_hourly':'hr', u'CMIP5_aero':'day', \
638                  u'CMIP5_Amon':'mon', u'PMIP3_Omon':'mon', u'CCMI1_daily':'day', u'SPECS_fx':'fx', u'PMIP3_Lclim':'monClim', \
639                  u'PMIP3_Oclim':'monClim', u'SPECS_Amon':'mon', u'SPECS_Lmon':'mon', u'CMIP5_cf3hr':'3hr', u'CORDEX_3h':'3hr', \
640                  u'CCMI1_annual':'yr', u'CMIP5_Oyr':'yr'}
641            kk = ['uid', 'comment', 'deflate_level', 'shuffle', 'ok_max_mean_abs', 'flag_meanings', 'type', 'ok_min_mean_abs', 'sn', 'deflate', 'title', 'valid_min', 'cell_methods', 'flag_values', 'cell_measures', 'out_name', 'modeling_realm', 'units', 'cell_methods_xx', 'valid_max', 'positive', 'var', 'mipTable', 'dimensions', 'vid', 'gpid','rowIndex','ssect', 'priority']
642            id = kk.index('dimensions')
643            ivid = kk.index('vid')
644            thisnt = collections.namedtuple( 'ovar', kk )
645            ov = []
646            dset = set()
647            ds2 = set()
648            ovuu = {}
649            for k in thissh:
650              if k[0] != '_':
651                rr = thissh[k][:]
652                if rr[id] == 's|c|a|l|a|r':
653                  print 'ERROR.060.0001: bad dimension string detected and corrected: %s' % rr[id]
654                  rr[id] = 'scalar'
655                if string.find( rr[23], 'plevs' ) != -1:
656                   print 'INFO.qqqq01: ',rr[21:24]
657                rr[23] = string.replace(rr[23], 'plevs', 'plev17')
658                tt = thisnt._make( rr ) 
659                if tt.uid in setu1:
660                  print 'ERROR.099.0002: duplicate uuid: %s: %s' % (uuid,str(rr))
661                if str(tt.vid) == '__var_not_found_012__':
662                  print 'ERROR.099.00102: bad vid string: %s [%s]' % (tt.vid,tt.out_name)
663                       
664                if str(tt.vid) not in self.importWbMods.vars.d1:
665                  if tt.out_name in self.importWbMods.vars.c1:
666                    if len( self.importWbMods.vars.c1[ tt.out_name ] ) == 1:
667                      rr[ivid] = self.importWbMods.vars.c1[ tt.out_name ][0]
668                      tt = thisnt._make( rr ) 
669                      print 'INFO.099.00103: bad vid string replaced: %s [%s]' % (tt.vid,tt.out_name)
670                    else:
671                      print 'ERROR.099.00104: ambiguous bad vid string: %s [%s]' % (tt.vid,tt.out_name)
672                  else:
673                    print 'ERROR.099.00105: bad vid string: %s [%s]' % (tt.vid,tt.out_name)
674                setu1.add(tt.uid)
675                ov.append( tt )
676                dset.add( ov[-1].dimensions )
677                ds2.add( (tt.dimensions,tt.cell_methods,tt.cell_measures,tt.flag_values, tt.flag_meanings) )
678                ovuu[tt.uid] = tt
679                if rr[22][-3:] in ['mon','day','3hr']:
680                  fr = rr[22][-3:]
681                elif rr[22][-2:] in [ 'yr','fx']:
682                  fr = rr[22][-2:]
683                else:
684                  fr = tab2freq[rr[22]]
685   
686                prov = '%s ((isd.003))' % tt.mipTable
687                if tt.mipTable[:4] == 'OMIP':
688                  prov = 'CMIP6 [OMIP] ((isd.001))'
689                elif string.find( tt.mipTable, '_' ) != -1:
690                  prov = '%s [%s] ((isd.002))' % tuple( string.split( tt.mipTable, '_' ) )
691
692                if tt.var[:5] == 'xx..ccmi_':
693                  pass
694                else:
695                  lab = tt.var
696                  if lab in {'*','include Oyr 3D tracers'}:
697                    lab = '-copy-'
698##
699## insert conditional on redundant tables here ...
700##
701                  if tt.mipTable in redundantTables:
702                    if tt.mipTable not in reportedRedundantTables:
703                      print 'INFO.000.11111: redundant table spotted: ',tt.mipTable
704                      reportedRedundantTables.add( tt.mipTable )
705                  else:
706                    if tt.uid in self.cmvs:
707                       print 'ERROR.090.09010: duplicate cmv uid :',tt.__dict__
708                    self.cmvs.add( tt.uid )
709                    self.cmv.append( (tt.uid, (tt.dimensions,tt.cell_methods,tt.cell_measures,tt.flag_values,tt.flag_meanings), lab, tt.title, tt.comment, tt.vid, \
710                      tt.deflate_level, tt.shuffle, tt.ok_max_mean_abs, tt.flag_meanings, tt.type, tt.ok_min_mean_abs, \
711                      tt.deflate, tt.valid_min, tt.flag_values, tt.modeling_realm, tt.valid_max, tt.positive, tt.mipTable, \
712                      prov, tt.ssect, fr, tt.rowIndex, '',int(tt.priority)) )
713                    self.realmByVar[ lab ].append( tt.modeling_realm )
714                    if string.strip( tt.gpid ) == '':
715                       print 'ERROR.090.0990: blank gpid: ',lab,tt.mipTable
716                    vgid = tt.gpid
717                    if tt.mipTable[:4] == 'OMIP':
718                       m,t = string.split( tt.mipTable, '.' )
719                       vgid = self.prqv.getvgid( [None,t,m] )
720                       if vgid[0] != '_':
721                         if vgid != tt.gpid:
722                           print 'INFO.090.0990: link repare:',tt.gpid,lab,tt.mipTable,vgid
723                    self.rqv.append( (str( uuid.uuid1() ),lab, tt.uid, vgid, tt.priority,tt.mipTable,tt.mipTable) )
724                    if vgid not in self.varGroupUids:
725                      print 'ERROR.099.09901: bad vgid: ',self.rqv[-1]
726    ##self.rqvinfo = ('uid','label','vid','gpid','priority','mip','table' )
727            self.dsort( dset )
728            print self.dsortdd[ksect][0].keys()
729
730      elif ksect == 'groupitem':
731            kk = ['group', 'var', 'table', 'freq', 'descriptionEx', 'shape', 'levels', 'tstyle', 'mask', 'priority', 'mip', 'uid', 'rowIndex', 'new', 'gpid', 'vkey', 'vid']
732            thisnt = collections.namedtuple( 'groupitem', kk + ['cmorv',] )
733            il = kk.index( 'levels' )
734            iu = kk.index( 'uid' )
735            idx = kk.index( 'descriptionEx' )
736            ixvid = kk.index( 'vid' )
737            ixvar = kk.index( 'var' )
738            ixp = kk.index( 'priority' )
739            dset = set()
740            dsgpi = set()
741            gi = []
742            s1 = set()
743            sm = set()
744            varsets = []
745            nov = 0
746            setu = set()
747            for k in thissh.keys():
748              if k[0] != '_':
749                rr = thissh[k][:]
750                if trace.GROUPITEM_ta and rr[ixvar] == 'ta':
751                  print 'INFO.045.00004: groupitem: ',rr
752
753##
754## convert floats back to integer
755##
756                if type(rr[ixp]) == type(1.):
757                  rr[ixp] = int(rr[ixp])
758##
759## split variable, create 2nd record at 23 levels.
760##
761                if rr[iu] in setu:
762                  print 'ERROR.099.0001: duplicate uuid in varGroups ... %s:: %s' % (uuid,str(rr))
763                if rr[iu] in setu1:
764                  print 'ERROR.099.0003: duplicate uuid in varGroups/ovar ... %s:: %s' % (uuid,str(rr))
765                setu.add(rr[iu])
766                if rr[il] in  {u'17 (or 23 )', u'17 (or 23)', u'17 (or23)', u'10/17/23'}:
767                  if rr[il] == u'10/17/23':
768                     lev0 = 10
769                     levsp = [17,23]
770                  else:
771                     lev0 = 17
772                     levsp = [23,]
773                  rr[ixp] = 1
774                  p = 1
775                  for lp in levsp:
776                    p += 1
777                    rr0 = rr + [rr[1] + str(lp),]
778                    rr0[ixp] = p
779                    rr0[il] = lp
780                    rr0[iu] = str( uuid.uuid1() )
781                    tt = thisnt._make( rr0 )
782                    if str(tt.vid) == '__var_not_found_012__':
783                      print 'ERROR.099.00104: bad vid string: %s [%s]' % (tt.vid,tt.var)
784                    gi.append( tt )
785                    varsets.append( (rr0[iu], 2, rr[iu], 1, 'variables at multiple vertical resolutions' ) )
786                  rr[il] = lev0
787                  tt = thisnt._make( rr + [rr[1] + str(lev0),] )
788                elif rr[il] in [u'Model levels or plev_27', u'Model levels or 27Plevs',u'27',27.]:
789                  rr0 = rr + [rr[1] + '27',]
790                  print 'INFO.0088.07007: ',rr0
791                  rr0[il] = 27
792                  rr0[iu] = str( uuid.uuid1() )
793                  if str(rr0[ixvid]) == '__var_not_found_012__':
794                    if str(rr0[ixvar]) in self.varUidByName:
795                      if len( self.varUidByName[rr0[ixvar]] ) == 1:
796                        rr0[ixvid] = self.varUidByName[rr0[ixvar]][0]
797                  tt = thisnt._make( rr0 )
798                  if str(tt.vid) == '__var_not_found_012__':
799                    print 'ERROR.099.00105: bad vid string: %s [%s]' % (tt.vid,tt.var)
800##
801## no longer requesting all option of "all or ..."
802##
803                  ##gi.append( tt )
804                  ##rr[il] = 'all'
805                  ##tt = thisnt._make( rr + [rr[1],] )
806                  varsets.append( (rr0[iu], 0, rr[iu], 0, 'Variables on model levels or 27 pressure levels' ) )
807                elif string.find( rr[idx], '850 hPa' ) != -1:
808                  print 'INFO.0099.0016: ', rr
809                  if rr[1][-3:] != '850':
810                    rr = rr + [rr[1] + '850',]
811                  else:
812                    rr = rr + [rr[1],]
813                  tt = thisnt._make( rr )
814                else:
815##
816## this point ... to mark HighResMIP 7 levels as distinct from CFMIP.
817## enough information in "mip" tag of tt record
818##
819                  if type( rr[il] ) == type(1.):
820                    if rr[il] == 7. and rr[10] == 'HighResMIP':
821                      print 'INFO.qqq03:',rr[il],rr
822                      rr[5] = rr[5] + '*'
823                  if str(rr[ixvid]) == '__var_not_found_012__':
824                    ok = False
825                    if str(rr[ixvar]) in self.varUidByName:
826                      if len( self.varUidByName[rr[ixvar]] ) == 1:
827                        rr[ixvid] = self.varUidByName[rr[ixvar]][0]
828                        print 'INFO.099.00106: correcting vid for %s' % rr[ixvar]
829                        ok = True
830                    if not ok:
831                        print 'WARN.099.00106: error in vid for %s not corrected' % rr[ixvar]
832                  tt = thisnt._make( rr + [rr[1],] )
833                  if str(tt.vid) == '__var_not_found_012__':
834                    print 'ERROR.099.00106: bad vid string: %s [%s]' % (tt.vid,tt.var)
835                 
836                if str(tt.mip) != 'OMIP':
837                  gi.append( tt )
838                  sm.add( tt.mask )
839
840            print '####### masks: ',sm
841            smdd = {}
842            dsn = {'floating ice shelf':u'floating ice sheet', u'ocean':u'sea' }
843            d1 = {u'land':(False,'area: mean where land'), \
844                  u'grounded ice sheet':(True,'area: mean where grounded_ice_sheet'), \
845                  u'ice sheet':(True,'area: mean where ice_sheet'), \
846                  u'floating ice sheet':(True,'area: mean where floating_ice_sheet'), \
847                  u'floating ice shelf':(True,'area: mean where floating_ice_sheet'),
848                  u'sea':(False,'area: mean where sea') }
849            for s in sm:
850              if s in  ['', u'none',u'Southern hemisphere', u'Northern hemisphere']:
851                smdd[s] = (False,'')
852              else:
853                smdd[s] = d1[ dsn.get( s,s ) ]
854
855            setu = set()
856
857            ccchk = ivg.checkCmv(gi)
858            nrep = 0
859
860            for tt in gi:
861                gr = 'a'
862                if tt.mip == 'OMIP' or any( [string.find(tt.table,i) != -1 for i in ['Omon','Oyr','Oclim','OImon','Ocean'] ] ):
863                  gr = 'o'
864                if self.varsxx != None:
865                  if tt.cmorv in self.varsxx:
866                    sss = set()
867                    for k in self.varsxx[tt.cmorv]:
868                      sss.add(self.skey['var'][k][-1] )
869                    sss = list(sss)
870                    if len(sss) == 1:
871                      if sss[0] == 'ocean':
872                        gr = 'o'
873                      elif sss[0] == 'atmos':
874                        gr = 'a'
875                    print 'INFO:lllw:', tt.cmorv, sss, gr
876                if tt.cmorv == 'sltbasin':
877                   print 'INFO.llll: ',tt,gr
878##
879## adding label for mip here messes up referencing later ...
880##
881                dset.add( (tt.shape,tt.levels,tt.tstyle,gr) )
882                dsgpi.add( (tt.shape,tt.levels,tt.tstyle,gr,smdd[tt.mask], 'None', 'None') )
883### need to check where variables are, perhaps, refering to "ovar"
884            ##kk = ['group', 'var', 'table', 'freq', 'descriptionEx', 'shape', 'levels', 'tstyle', 'mask', 'misc', 'mip', 'uid', 'rowIndex', 'new', 'gpid', 'vkey', 'vid']
885                prov = '%s [%s]' % (tt.mip,tt.group)
886                provNote = ''
887                lab = tt.cmorv
888                if lab in {'*','include Oyr 3D tracers'}:
889                  lab = '-copy-'
890                elif lab == 'wap (omega)':
891                  lab = 'wap'
892                  provNote = 'wap (omega)'
893                lab = string.replace( string.strip(lab), '_', '-' )
894                if tt.uid in setu:
895                     print 'SEVERE[1]: duplicate uuid: ',tt.__dict__
896                setu.add( tt.uid )
897                fr = freqmap.get( tt.freq, tt.freq )
898                ntab = 'em%s' % string.capwords( fr )
899               
900                if ovuu.has_key(tt.vid):
901                  tt1 = ovuu[tt.vid]
902                  if tt1.modeling_realm == 'seaIce':
903                    ntab = 'OImon'
904                  if tt.priority in [1,2,3]:
905                    p = tt.priority
906                  else:
907                    p = int(tt1.priority)
908                  thisrealm = tt1.modeling_realm
909                  if gr == 'o' and thisrealm == 'atmos':
910                    thisrealm = 'ocean'
911                  thiscmv = (tt.uid, (tt.shape,tt.levels,tt.tstyle,gr,smdd[tt.mask],tt1.flag_values,tt1.flag_meanings), lab, '__from %s' % tt.table, tt.descriptionEx, tt1.vid, \
912                    tt1.deflate_level, tt1.shuffle, tt1.ok_max_mean_abs, tt1.flag_meanings, tt1.type, tt1.ok_min_mean_abs, \
913                    tt1.deflate, tt1.valid_min, tt1.flag_values, thisrealm, tt1.valid_max, tt1.positive, ntab, \
914                    prov, provNote, tt.freq, tt.rowIndex, '', int(p)) 
915                  self.realmByVar[ lab ].append( thisrealm )
916                  thisrqv = [str( uuid.uuid1() ),lab, tt.uid, tt.gpid, p, tt.mip, tt.group]
917                  nov += 1
918                else:
919                  thisrealm = ''
920                  if realmdefix.has_key( prov ):
921                    thisrealm = realmdefix[prov]
922                  else:
923                    print 'WARN:070.00001: realm not found for %s,%s' % (lab,prov)
924                  if gr == 'o' and thisrealm == 'atmos':
925                    thisrealm = 'ocean'
926
927                  if thisrealm == 'seaIce':
928                    ntab = 'OImon'
929
930                  if tt.priority in [1,2,3]:
931                    p = tt.priority
932                  elif  self.defaultP.get( tt.vid, 102) in [1,2,3]:
933                    p = self.defaultP.get( tt.vid, 102)
934                  else:
935                    p = 1
936                    print 'WARN:070.00002: priority defaulting to 1 for %s,%s' % (lab,prov)
937                  thiscmv = (tt.uid, (tt.shape,tt.levels,tt.tstyle,gr,smdd[tt.mask], 'None', 'None'), lab, '__from %s' % tt.table, tt.descriptionEx, tt.vid, \
938                    0, 0, 0, 0, '', 0, \
939                    0,0,0, thisrealm, 0, '', ntab, \
940                    prov, provNote, tt.freq, tt.rowIndex, '', str(p)) 
941                  self.realmByVar[ lab ].append( thisrealm )
942
943                  thisrqv = [str( uuid.uuid1() ),lab, tt.uid, tt.gpid, p, tt.mip, tt.group] 
944                if trace.GROUPITEM_ta and lab  == 'ta':
945                    print 'INFO.045.00005: groupitem: ',thisrqv
946
947
948                if ccchk.uidReplace.has_key(thiscmv[0]):
949                  nrep += 1
950                  thisrqv[2] = ccchk.uidReplace[thiscmv[0]]
951                else:
952                  self.cmv.append( thiscmv )
953                self.rqv.append( thisrqv )
954                if self.rqv[-1][3] not in self.varGroupUids:
955                      print 'ERROR.099.09902: bad vgid: ',self.rqv[-1]
956## Variables marked with shape '?' from PMIP are actually defined by OMIP ....
957                if tt.shape == '?':
958                  print 'ERROR.801.00001: shape not set: %s, %s, %s' % ( tt.shape,tt.mip,tt.var)
959
960            ##['', u'none', u'land', u'grounded ice sheet', u'floating ice sheet', u'floating ice shelf', u'ocean', u'ice sheet', u'sea', u'Southern hemisphere', u'Northern hemisphere']
961            self.dsort( dset,mode=ksect )
962            print 'INFO.088.00001: nrep=%s' % nrep
963            print 'INFO.088.00002: nov=%s [%s]' % (nov,len(gi))
964
965    for c in self.cmv:
966      u,v,f,t = (c[0],c[2],c[21],c[18])
967      self.cmvUidByFL[f].a[v].append( u ) 
968      self.cmvUidByTab[t].a[v].append( u ) 
969
970#######################################################################################
971#################
972    std = set()
973    ssd = set()
974    etd = {}
975    esd = {}
976    tshp = { 'time':['time-mean','Temporal mean'], 'time1':['time-point','Instantaneous value (i.e. synoptic or time-step value)'], \
977             'time2':['climatoglogy','Climatological mean'], \
978             '':['None','No temporal dimensions ... fixed field'], 'xxxx':['unknown','dimension not recognised'] }
979
980    for ksect in [ 'ovar','groupitem']:
981#### create structure list for spatial and temporal dimensions
982      for t in self.dsortdd[ksect][0].keys():
983        tdim, tt = self.dsort_u1( self.dsortdd[ksect][0][t], self.dsortdd[ksect][1] )
984
985        std.add( tdim )
986        ssd.add( tt )
987        ##ssd.add( (sdim,lfl,nl) )
988
989    for s in std:
990       label, description = tshp.get(s,tshp['xxxx'])
991       u = str( uuid.uuid1() )
992       etd[s] = (u,label,description,s)
993    kk = 0
994    for s in ssd:
995       d,lfl,nl = s
996       u = str( uuid.uuid1() )
997       kk+=1
998       lab = 'ssd-%3.3i' % kk
999       description = 'ssd.%3.3i' % kk
1000       esd[s] = (u,lab,description,d,lfl,nl)
1001
1002    esd['Y-na'] = (str( uuid.uuid1() ),'extra','extra','latitude','false',1)
1003    self.dimsTime = etd
1004    self.dimsTimeInfo = ['uid','label','title','dimensions']
1005    self.dimsSpace = esd
1006    self.dimsSpaceInfo = ['uid','label','title','dimensions','levelFlag','levels']
1007       
1008    sshp = set()
1009    eshp = set()
1010    ll = []
1011    lls = ivg.structureList()
1012    nt_dims = collections.namedtuple( 'dims', ['uid','label','spid','tmid','odims','coords','cell_methods','cell_measures','flag_values','flag_meanings','description','procNote','prov'] )
1013    kk = 0
1014    strdd = {}
1015    ee3 = {}
1016    for dims,cmet,cmea,flgv, flgm in ds2:
1017        tdim, tt = self.dsort_u1( self.dsortdd['ovar'][0][dims], self.dsortdd['ovar'][1] )
1018        d1,odim,d2,crd = self.dsortdd['ovar'][0][dims]
1019        sdim,lfl,nl = tt
1020        u = str( uuid.uuid1() )
1021        spid = esd[tt][0]
1022        tmid = etd[tdim][0]
1023        kk += 1
1024        label = 'str-%3.3i' % kk
1025        proc = ''
1026        prov = 'CMIP5/OMIP'
1027        desc = ''
1028        print 'INFO.zzz01: ',dims
1029        t0 = (dims,cmet,cmea,flgv,flgm)
1030        if cmet == 'None':
1031          cmet = ''
1032        if cmea == 'None':
1033          cmea = ''
1034        if flgv == 'None':
1035          flgv = ''
1036        if flgm == 'None':
1037          flgm = ''
1038        t1 = (dims,cmet,cmea,flgv,flgm)
1039        u = lls.add( [u,label,spid,tmid, odim, crd, cmet, cmea, flgv, flgm, desc, proc, prov] )
1040        self.structInfo[u] = (label,cmet,spid)
1041        strdd[t0] = u
1042        strdd[t1] = u
1043         
1044        ##nt =  nt_dims._make( [u,label,spid,tmid, odim, crd, cmet, cmea, flgv, flgm, desc, proc, prov] )
1045        ##tt = tuple( [nt.__dict__[k] for k in ['spid','tmid','odims','coords','cell_methods','cell_measures','flag_values','flag_meanings','procNote','prov']] )
1046        ##if ee3.has_key( tt ):
1047            ##u = ee3[tt]
1048        ##else:
1049            ##ee3[tt] = u
1050            ##ll.append( nt )
1051        ##ll.append( nt_dims._make( [u,label,spid,tmid, odim, crd, cmet, cmea, flgv, flgm, desc, proc, prov] ) )
1052
1053    ttt = [ {u'Instantaneous (end of year)', 'instantaneous', 'point', 'Synoptic', u'synoptic', u'time: point'},
1054        {'Mean', u'time: mean', u'Time mean', u'daily mean', u'mean', u'time mean', u'time: day', u'time: mean', u'weighted time mean', 'Cumulative annual fraction'}, set(), {''}]
1055    cmetl = ['time: point', 'time: mean', 'time: mean within years time: mean over years ', '']
1056    ee1 = {}
1057    for shp,lvls,sty,gr,tmsk, flgv, flgm in dsgpi:
1058        t = (shp,lvls,sty,gr)
1059        tdim, tt = self.dsort_u1( self.dsortdd['groupitem'][0][t], self.dsortdd['groupitem'][1] )
1060        d1,odim,d2,crd = self.dsortdd['groupitem'][0][t]
1061        print 'INFO.099: ',d1,odim,d2,crd
1062        tflm, msk = tmsk
1063        sdim,lfl,nl = tt
1064        u = str( uuid.uuid1() )
1065        spid = esd[tt][0]
1066        tmid = etd[tdim][0]
1067        cmea = 'area: areacell%s' % gr
1068        cmet = ''
1069        for i in range(4):
1070          if sty in ttt[i]:
1071            cmet = cmetl[i]
1072        if cmet == '':
1073          cmet = msk
1074        elif msk != '':
1075          cmet += ' ' + msk
1076        kk += 1
1077        label = 'str-%3.3i' % kk
1078        proc = ''
1079        prov = 'CMIP5, endorsed MIPs'
1080        desc = ''
1081        dims = tt[0]
1082        if tdim != '':
1083          dims += '|' + tdim
1084        if strdd.has_key( (dims,cmet,cmea,'','') ):
1085          u = strdd[ (dims,cmet,cmea,'','') ]
1086          print 'INFO.zzz03: ',tt, tdim
1087        elif ee1.has_key( (tmid, spid, odim, cmet, cmea, crd) ):
1088          u = ee1[(tmid, spid, odim, cmet, cmea, crd)]
1089          print 'INFO.zzz04: ', tt, tdim
1090        else:
1091          print 'INFO.zzz02: ',tt, tdim
1092          u = lls.add( [u,label,spid,tmid, odim, crd, cmet, cmea, '', '', desc, proc, prov]  )
1093          ##nt =  nt_dims._make( [u,label,spid,tmid, odim, crd, cmet, cmea, '', '', desc, proc, prov] )
1094          ##tt = tuple( [nt.__dict__[k] for k in ['spid','tmid','odims','coords','cell_methods','cell_measures','flag_values','flag_meanings','procNote','prov']] )
1095          ##if ee3.has_key( tt ):
1096            ##u = ee3[tt]
1097          ##else:
1098            ##ee3[tt] = u
1099            ##ll.append( nt )
1100           
1101          ee1[(tmid, spid, odim, cmet, cmea, crd)] = u
1102        strdd[(shp,lvls,sty,gr,tmsk,flgv,flgm)] = u
1103        self.structInfo[u] = (label,cmet,spid)
1104
1105    ##nt_dims = collections.namedtuple( 'dims', ['uid','label','spid','tmid','odims','coords','cell_methods','cell_measures','flag_values','flag_meanings','description','procNote','prov'] )
1106    cc = collections.defaultdict( list )
1107    for nt in lls.ll:
1108      tt = tuple( [nt.__dict__[k] for k in ['spid','tmid','odims','coords','cell_methods','cell_measures','flag_values','flag_meanings','procNote','prov']] )
1109      cc[tt].append( nt.uid )
1110    ks = [k for k in cc.keys() if len( cc[k] ) > 1]
1111    if len( ks ) > 0:
1112      print 'DUPLICATE STRUCTURES'
1113      for k in ks:
1114        print 'DUPLICATE: ',k,len(cc[k])
1115     
1116    self.structList = lls.ll
1117    self.strdd = strdd
1118    oo = open( 'test.csv', 'w' )
1119    for l in ll:
1120      assert l.uid in self.structInfo, 'SEVERE: structure uid not in lookup ... %s' %  str( l.__dict__)
1121      oo.write( '%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,\n' % l )
1122    oo.close()
1123
1124  def addAerChem(self):
1125    import importExtra
1126    lc = importExtra.loadAerChem()
1127    es = {}
1128    et = {}
1129    for l in self.dimsSpace.keys():
1130      print self.dimsSpace[l]
1131      assert self.dimsSpace[l][1] not in es, 'Duplicate spatial dimension label: %s' % self.dimsSpace[l][1]
1132      es[self.dimsSpace[l][1]] = l
1133    for l in self.dimsTime.keys():
1134      print self.dimsTime[l]
1135      assert self.dimsTime[l][1] not in et, 'Duplicate spatial dimension label: %s' % self.dimsTime[l][1]
1136      et[self.dimsTime[l][1]] = l
1137    nt_acv = collections.namedtuple( 'acv', ['sn','title','label', 'units', 'description', 'subsect', 'freq', 'splab', 'tm' ] )
1138    freq_map = {'hourly':'1hr', 'annual':'yr', 'daily':'day', 'fixed':'fx'} 
1139    for t in lc.cc2.keys():
1140      nn = 0
1141      for v in lc.cc2[t].a:
1142        v1 = v
1143        if v not in self.vars1:
1144          print 'INFO.kkkkk: AerChem Var missing: %s, %s' % (t,v)
1145          if string.replace( v, '_', '') in self.vars1:
1146            v1 = string.replace( v, '_', '')
1147            print 'INFO.kkkkk: AerChem %s found' % (v1)
1148        else:
1149          nn += 1
1150        tt = nt_acv._make( lc.cc2[t].a[v][0] )
1151        thisrealm = 'unset'
1152        freq = freq_map.get( tt.freq, tt.freq )
1153        ntab = 'aer%s' % freq
1154        thiscmv = (uuid.uuid1(), (tt.splab,tt.tm), tt.label, 'AerChemMIP', tt.description, self.vars1[v1][0], '','','','','float','','','','',"aero",'','',ntab,'AerChemMIP','',freq, 0, '', 1)
1155        self.cmv.append( thiscmv )
1156      print 'INFO.kkkkk: AerChem Vars found: %s: %s' % (t,nn)
1157                  ##thiscmv = (tt.uid, (tt.shape,tt.levels,tt.tstyle,gr,smdd[tt.mask],tt1.flag_values,tt1.flag_meanings), lab, '__from %s' % tt.table, tt.descriptionEx, tt1.vid, \
1158                    ##tt1.deflate_level, tt1.shuffle, tt1.ok_max_mean_abs, tt1.flag_meanings, tt1.type, tt1.ok_min_mean_abs, \
1159                    ##tt1.deflate, tt1.valid_min, tt1.flag_values, thisrealm, tt1.valid_max, tt1.positive, ntab, \
1160                    ##prov, provNote, tt.freq, tt.rowIndex, '', int(p))
1161
1162  def dsort_u1(self,eed,sde):
1163        tdim = eed[2]
1164        sdim = eed[0]
1165        nl = sde[sdim]
1166        lfl = 'true'
1167        if nl == -1:
1168          lfl = 'false'
1169          nl = 0
1170        elif nl == -2:
1171          nl = 1
1172          pass
1173        return (tdim, (sdim,lfl,nl) )
1174
1175
1176  def dsort( self, dset, mode='ovar' ):
1177      """Sort the dimensions string into spatial, temporal and other sections,
1178       returns a dictionary of tuples: spatial dimensions, other, temporal, coords and a 2nd, keyyed on spatial dimensions with a level count indicator.  """
1179      vdims = {'plev7':7, 'plev':4, 'plevs':17, 'plev3':3,'plev8':8,'alt40':40,'alev1':1, 'alevhalf':-1,'olevel':-1,'rho':-1,'sdepth':-1,'alevel':-1}
1180      odims = {'sza5','vegtype','scatratio','dbze','typepdec','vgidx','tau'}
1181      dl = sorted( list(dset) )
1182      if mode == 'ovar':
1183        eed = {}
1184        sss = [set(),set(),set(),set()]
1185        for s in dl:
1186          if s[:4] == 'time':
1187            bits = ['',s[4:]]
1188          else:
1189            bits = string.split(s, '|time', maxsplit=1 )
1190          if len(bits) == 1:
1191            ts = ''
1192          else:
1193            ts = 'time'
1194
1195          b0 = bits[0]
1196          b1 = ''
1197          bb = string.split(bits[0],'|')
1198          if bb[-1] in odims:
1199            if bb[-1] == 'tauxxx':
1200                b0 = bits[0][:-4]
1201                ts = 'tau|time'
1202            else:
1203              b0 = string.join( bb[:-1], '|' )
1204              b1 = bb[-1]
1205           
1206          if len(bits) == 1:
1207              tup = (b0,b1,'','')
1208          elif len(bits) == 2:
1209              b2 = string.split( bits[1], '|', maxsplit=1 )
1210              if len(b2) == 2:
1211                  tup = (b0,b1, ts + b2[0], b2[1])
1212              else:
1213                  tup = (b0,b1, ts + bits[1], '')
1214          eed[s] = tup
1215          for k in range(4):
1216            sss[k].add(tup[k])
1217
1218        lcount = {}
1219        for s in sss[0]:
1220          bits = string.split( s, '|' )
1221          nl = -2
1222          thisb = None
1223          for b in bits:
1224            if vdims.has_key(b):
1225              assert nl == -2, 'Duplicate vertical level count in %s' % s
1226              nl = vdims[b]
1227              thisb = b
1228          lcount[s] = nl
1229          if nl == -1 and s == 'latitude|basin':
1230            print 'SEVERE: error in level deduction'
1231            print s, bits, nl, thisb
1232            raise
1233      else:
1234        ## input is a set of tuples,  shape, levels, tstyle, o/a
1235        ## aim is to extract spatial, other, temporal dimensions + coords.
1236        sss = [set(),set(),set()]
1237        ttt = [ (u'Instantaneous (end of year)', 'instantaneous', 'point', 'Synoptic', u'synoptic', u'time: point'),
1238        ('Mean', u'time: mean', u'Time mean', u'daily mean', u'mean', u'time mean', u'time: day', u'time: mean', u'weighted time mean', 'Cumulative annual fraction'), (), ('',)]
1239        ttdd = {}
1240        kkk = ['time1','time','time2','']
1241        for i in range(4):
1242          for k in ttt[i]:
1243            ttdd[k] = kkk[i]
1244
1245        ##lll =  {[u'1.0', u'14.0', u'16.0',  u'17.0', u'27.0', u'3.0', u'36.0', u'4.0', u'40.0', u'7.0', ]:'flt', [u'17 (or 23 )', u'17 (or 23)', u'17 (or23)']:'obs', [u'Model levels or 27Plevs', u'all', u'all model levels', u'all model levels above 400hPa', u'all*', u'integrated over depth'], [u'single level',], [u'soil levels',], [u'surface',], [[u'100 m',] }
1246        dds = {'2D':'XYT', 'XY':'XYT', '':'?', '2D ':'XYT', 'XYZ':'XYZT', } 
1247## 'K'?? 'XYK'
1248        dd = {'XKT':('latitude|basin','','time','',False), \
1249             'XYZKT':('longitude|latitude|%s','effectRad','time','',True), \
1250             'XYZT':('longitude|latitude|%s','','time','',True), \
1251             'XYZT*':('longitude|latitude|%st','','time','',True), \
1252              'KZT':('alevel','spectband','time','',False), \
1253              'XYT':('longitude|latitude','','time','',False), \
1254              'XYKT':('longitude|latitude','angle','time','',False), \
1255              'YZT':('latitude|%s','','time','',True), \
1256              'XYK':('longitude|latitude','snowband','time','',False), \
1257              'K':('sistraits','','time','',False), \
1258              'scalar':('','','time','',False), \
1259              'ZST1':('alevel','site','time','',False), \
1260              'BasinYT':('latitude|basin','','time','',False), \
1261              '?':( '?', '?','?','?',False)
1262             }
1263             
1264        for d in dl:
1265          for k in range(3):
1266            sss[k].add( d[k] )
1267        ls0 = set()
1268        ls1 = set()
1269##
1270## sort shapes
1271##
1272        for s in sss[0]:
1273          if not dd.has_key( dds.get(s,s) ):
1274            print 'NO SOLUTION FOUND FOR SHAPE: "%s"' % s
1275          else:
1276            tt = dd[dds.get(s,s)]
1277            if tt[-1]:
1278              ls0.add( s )
1279##
1280## look at shapes which require additional information about vertical coord
1281##
1282        for d in dl:
1283          if d[0] in ls0:
1284             ls1.add( d[1] )
1285
1286        lset = {'soil levels':'sdepth', 'all model levels above 400hPa':'alevel'} 
1287        lsdd = {}
1288        for l in ls1:
1289          ii = 0
1290          if l in ['all','all*','all model levels']:
1291            ii = -1
1292            this = '%slevel' 
1293          elif lset.has_key(l):
1294            ii = -1
1295            this = lset[l]
1296          elif l == '':
1297            ii = -2
1298            this = l
1299          else:
1300            ii = int( float(l) )
1301            if ii in [40,16]:
1302              this = 'alt%s' % ii
1303            elif ii > 1.5:
1304              if ii > 35:
1305                ii = 39
1306##
1307## merge 14 and 17 level specifications to a 19 level coordinate
1308##
1309              if ii in [14,17]:
1310                ii = 19
1311              this = 'plev%s' % ii
1312            else:
1313              this = ''
1314          lsdd[l] = (ii,this)
1315##['', 1.0, u'all', 3.0, 4.0, u'soil levels', 7.0, 40.0, u'all model levels', u'17 (or 23)', u'all*', 14.0, u'Model levels or 27Plevs', 16.0, 17.0, u'all model levels above 400hPa', u'17 (or23)', 36.0, u'17 (or 23 )', 27.0]
1316             
1317        lcount = {}
1318        eed = {}
1319        for d in dl:
1320          s = d[0]
1321          if not dd.has_key( dds.get(s,s) ):
1322            print 'NO SOLUTION FOUND FOR SHAPE: "%s"' % s
1323          else:
1324            tt = dd[dds.get(s,s)]
1325            if tt[-1]:
1326              n,zz = lsdd[d[1]]
1327              if len(zz) > 0 and zz[0] == '%':
1328                zz = zz % d[3]
1329              sc = tt[0] % zz
1330              if sc[-1] == "|":
1331                print 'ERROR.080.05000: Bad dimension found %s [%s] %s %s' % (sc,str(tt), str((n,zz)), str(d)  )
1332            else:
1333              sc = tt[0]
1334              if (string.find( sc, 'alevel' ) != -1) or (string.find( sc, 'olevel' ) != -1):
1335                n = -1
1336              else:
1337                n = -2
1338
1339          lcount[sc] = n
1340          if n == -1 and sc == 'latitude|basin':
1341            print 'SEVERE [2]: error in level deduction'
1342            print sc, tt[0], tt[-1], n
1343            raise
1344          print 'INFO:qqq05: ',d, sc, tt, ttdd[d[2]]
1345          eed[d] = (sc,tt[1],ttdd[d[2]],tt[3])
1346      self.dsortdd[mode] = (eed,lcount)
1347
1348  def run(self,rq):
1349
1350    xx = self.doc.getElementsByTagName( 'main' )
1351    assert len(xx) == 1, 'Expecting one element named "main", found %s' % len(xx)
1352    main = xx[0]
1353    ## main = self.doc.childNodes[0]
1354    xsn = []
1355    ff = {}
1356    for c in main.childNodes:
1357      tag = c.nodeName
1358      if tag != '#text':
1359        xsn.append(tag)
1360        il = []
1361        for i in c.childNodes:
1362          if i.nodeName == 'item':
1363            il.append(i)
1364        xx = dict( il[0].attributes.items() )
1365        ff[string.lower(tag)] = (c,xx)
1366   
1367    print xsn
1368    print ff.keys()
1369    self.ff = ff
1370    ##        il.append(i,k in [ (rq.rqvg[k],k) for k in  rq.rqvg.keys() if k[0] != '_'] + [(exrqvg[k],k) for k in exrqvg.keys()]:
1371        ##kk = ['uid', 'mip', 'tab', 'objective', 'grid', 'gridreq', 'comment', 'ref', 'refNote', 'refid']
1372        ##kk = ['uid', 'mip', 'label', 'title', 'ref', 'refNote']
1373        ##i = rq.rqvg[k]
1374       
1375        ##self.eern[i[ixrn]].append( i[0] )
1376        ##k2 = '%s__%s' % (i[ixrn-1],i[ixrn])
1377        ##if self.eern2.has_key( k2 ):
1378           ##dups.append( (k2,k,self.eern2[k2]) )
1379        ##self.eern2[k2] = i[0]
1380        ##assert i[0] == k, 'Bad key/uuid'
1381
1382    ##assert len( dups ) == 0, 'Duplicate refs: %s, %s' % (str(dups),str(map( lambda x: rq.rqvg[x[1]], dups )) )
1383       
1384## keys here match section element names in schema
1385    sectlist = [ 'experiment','exptgroup','objective','requestlink', 'requestitem','requestvargroup','tablesection' ]
1386    ## dec 2015 -- removing 'var' from this list
1387    if self.schemaMode != 'dreq2':
1388      sectlist = ['ovar','groupitem','revisedtabitem'] + sectlist
1389    else:
1390      sectlist.append( 'requestvar' )
1391
1392    for k in sectlist:
1393      thissh = self.skey[k]
1394## set labmod False for section in which label coercion is not wanted
1395      labmod = True
1396      lll = []
1397      for i in thissh.keys():
1398        if i[0] != '_':
1399          lll.append(i)
1400      idk = 0
1401      if len(lll) > 0:
1402##
1403## remove example items, xcept where this has been done in previous function
1404##
1405        if k not in ['xxxx']:
1406          dil = ff[k][0].getElementsByTagName('item')
1407          for d in dil:
1408            ff[k][0].removeChild(d)
1409
1410        vare = {}
1411        for i in lll:
1412          ll = map( uniCleanFunc, thissh[i] )
1413          assert len(ll) == len( thissh[i] ), 'Lost list elements after uniClean'
1414          idk += 1
1415#################################################################
1416######### NEED TO CLEAN THIS IF ITEMS FROM OTHER SECTIONS ARE FILTERED
1417#######################################################################
1418          dothis = True
1419          if k != 'var':
1420            item = self.doc.createElement( 'item' )
1421
1422          if k == 'objective':
1423 ## - mip; tab; expt; rlid; ny
1424            labmod = False
1425            kk = ['mip', 'label', 'title', 'description']
1426            ##thisl = string.replace(string.strip(str( ll[1] ) ), '-', ' ')
1427## camelcase this label.
1428            ##thisl = string.replace( string.capwords( thisl ), ' ', '' )
1429            thisl = mycc( ll[1] )
1430            mip = str( ll[0] )
1431            self.objectives[mip][thisl] = i
1432            for j in range(len(kk)):
1433                thisv = str( ll[j] )
1434                item.setAttribute( kk[j], thisv )
1435            item.setAttribute( 'uid', str(i) )
1436          elif k == 'experiment':
1437            labmod = False
1438            kk = ['uid','egid','label','description','mip','mcfg','tier','nstart','starty','endy','yps','ensz','ntot','comment']
1439            thisl = str( ll[2] )
1440            ## self.mips.add( str( ll[4] ) )
1441            for j in range(len(kk)):
1442                if kk[j] in ['tier','ensz']:
1443                  if type(ll[j]) == type( 1 ):
1444                    thisv = str( ll[j] )
1445                  else:
1446                    thisv = string.join( [str(x) for x in ll[j]] )
1447                else:
1448                  thisv = str( uniCleanFunc(ll[j]) )
1449                item.setAttribute( kk[j], thisv )
1450          elif k == 'exptgroup':
1451            labmod = False
1452            kk = ['uid','label','tierMin','ntot']
1453            thisl = str( ll[1] )
1454            ##self.exptGrpDict[thisl] = str( ll[1] )
1455            ##self.experimentGrp[thisl] = str( ll[0] )
1456            for j in range(len(kk)):
1457                thisv = str( ll[j] )
1458                item.setAttribute( kk[j], thisv )
1459          elif k == 'var':
1460##- sn; units; description; procnote; procComment; prov
1461##['label', 'title', 'sn', 'units', 'description', 'procnote', 'procComment', 'prov', 'priority0']
1462            thisl = string.replace(string.strip(str( ll[0] ) ), '_', '-' )
1463            thisuuid = str(i)
1464            if not ( self.replItems.has_key( str(i) ) or self.remo.has_key(str(i)) ):
1465              item = self.doc.createElement( 'item' )
1466              item.setAttribute( 'id', 'tmpid.%4.4i' % idk )
1467              item.setAttribute( 'uid', str(i) )
1468              item.setAttribute( 'title', str(ll[1]) )
1469              item.setAttribute( 'sn', str(ll[2]) )
1470              item.setAttribute( 'units', str(ll[3]) )
1471              item.setAttribute( 'description', str(ll[4]) )
1472              item.setAttribute( 'procnote', str(ll[5]) )
1473              item.setAttribute( 'procComment', str(ll[6]) )
1474              item.setAttribute( 'prov', str(ll[7]) )
1475              vare[ll[3]] =  ll[1]
1476              if self.upda.has_key( thisuuid ):
1477                for tag in self.upda[thisuuid]['tags']:
1478                  if tag == 'label':
1479                    thisl = self.upda[thisuuid][tag]
1480                  else:
1481                    item.setAttribute( tag, self.upda[thisuuid][tag] )
1482              if thisl in self.fx.d1:
1483                thisr = self.fx.d1[thisl]
1484                if len(thisr) > 2 and thisr[2] != '':
1485                  item.setAttribute( 'title', str( thisr[2] ) )
1486                if len(thisr) > 3 and thisr[3] != '':
1487                  item.setAttribute( 'description', str( thisr[3] ) )
1488                if thisr[0] != thisl:
1489                  item.setAttribute( 'label', str( thisr[0] ) )
1490                  thisl = str( thisr[0] )
1491                if len(thisr) > 6 and thisr[6] != '':
1492                  item.setAttribute( 'units', str( thisr[6] ) )
1493                print 'INFO.qqq13: updating title and desc %s' % str( thisr )
1494            else: 
1495              print 'Omitting: ',ll
1496              dothis = False
1497          elif k == 'ovar':
1498## 
1499            tab2freq = {u'CMIP5_cfOff':'subhr', u'CORDEX_mon':'mon', u'SPECS_day':'day', u'CMIP5_day':'day', \
1500       u'PMIP3_OImon':'mon', u'CORDEX_day':'day', u'CMIP5_LImon':'mon', u'CMIP5_OImon':'mon', \
1501       u'CMIP5_Lmon':'mon', u'CMIP5_3hr':'3hr', u'CMIP5_Omon':'mon', u'PMIP3_OIclim':'monClim', \
1502       u'PMIP3_fx':'fx', u'CORDEX_fx':'fx', u'PMIP3_LImon':'mon', u'CMIP5_6hrPlev':'6hr', u'PMIP3_Lmon':'mon', \
1503       u'PMIP3_Amon':'mon', u'SPECS_Omon':'mon', u'CCMI1_fixed':'fx', u'PMIP3_Aclim':'monClim', u'CMIP5_6hrLev':'6hr', \
1504       u'CMIP5_Oclim':'monClim', u'PMIP3_LIclim':'monClim', u'CCMI1_monthly':'mon', u'CMIP5_fx':'fx', \
1505       u'CMIP5_cfDay':'day', u'CORDEX_6h':'6hr', u'PMIP3_day':'day', u'SPECS_OImon':'mon', u'CMIP5_cfMon':'mon', \
1506       u'CORDEX_sem':'monClim', u'SPECS_6hr':'6hr', u'CMIP5_cfSites':'subhr', u'CCMI1_hourly':'hr', u'CMIP5_aero':'day', \
1507       u'CMIP5_Amon':'mon', u'PMIP3_Omon':'mon', u'CCMI1_daily':'day', u'SPECS_fx':'fx', u'PMIP3_Lclim':'monClim', \
1508       u'PMIP3_Oclim':'monClim', u'SPECS_Amon':'mon', u'SPECS_Lmon':'mon', u'CMIP5_cf3hr':'3hr', u'CORDEX_3h':'3hr', \
1509       u'CCMI1_annual':'yr', u'CMIP5_Oyr':'yr'}
1510            kk = ['uid', 'comment', 'deflate_level', 'shuffle', 'ok_max_mean_abs', 'flag_meanings', 'type', 'ok_min_mean_abs', 'sn', 'deflate', 'title', 'valid_min', 'cell_methods', 'flag_values', 'cell_measures', 'out_name', 'modeling_realm', 'units', 'cell_methods_xx', 'valid_max', 'positive', 'var', 'mipTable', 'dimensions', 'vid', 'gpid','rowIndex','priority']
1511## uuid; comment; deflate_level; shuffle; ok_max_mean_abs; flag_meanings; type; ok_min_mean_abs; sn; deflate; valid_min; cell_methods; flag_values; cell_measures; out_name; modeling_realm; units; cell_methods_xx; valid_max; positive; var; mipTable; dimensions; vid
1512            ix_gpid = kk.index( 'gpid' )
1513
1514            thisl = string.strip( str( ll[21] ) )
1515            for j in range( min(len(kk),len(ll)) ):
1516              if kk[j] == 'priority':
1517                ll[j] = int(ll[j])
1518               
1519              if j != 21:
1520                item.setAttribute( kk[j], str( ll[j] ) )
1521
1522            if len(ll) < len(kk):
1523              print 'ERROR.015.0001: record length short %s (%s):: %s' % (len(ll),len(kk),ll)
1524
1525            if ll[22][-3:] in ['mon','day','3hr']:
1526              fr = ll[22][-3:]
1527            elif ll[22][-2:] in [ 'yr','fx']:
1528              fr = ll[22][-2:]
1529            else:
1530              fr = tab2freq[ll[22]]
1531   
1532            item.setAttribute( 'frequency', fr )
1533            thisuuid = ll[0]
1534            if self.repl.has_key( thisuuid ):
1535              for tag,old,new in self.repl[thisuuid]:
1536                thisold = item.getAttribute( tag )
1537                assert thisold == old, 'Attempt to replace value which is not present'
1538                item.setAttribute( tag, new )
1539          elif k == 'groupitem':
1540            kk = ['group', 'var', 'table', 'freq', 'descriptionEx', 'shape', 'levels', 'tstyle', 'mask', 'misc', 'mip', 'uid', 'new', 'gpid', 'vkey', 'vid']
1541            assert len(kk) == len(ll), 'length mismatch, %s  %s' % (len(kk),len(ll))
1542# - group;  table; freq; descriptionEx; shape; levels; tstyle; mask; mip; mip2; uuid; new; vid
1543            ix_gpid = kk.index( 'gpid' )
1544            thisl = string.strip(str( ll[1] ) )
1545            for j in range(len(kk)):
1546              if j != 1:
1547                ##item.setAttribute( kk[j], str( ll[j] ) )
1548                if kk[j] == 'misc':
1549                  item.setAttribute( 'priority', str( ll[j] ) )
1550                else:
1551                  item.setAttribute( kk[j], str( ll[j] ) )
1552            item.setAttribute( 'title', thisl )
1553            if string.find(thisl, ' ') != -1:
1554              thisl = string.split(thisl)[0]
1555            thisuuid = ll[11]
1556
1557            gpid = str(ll[ix_gpid])
1558            if not rq.rqvg.has_key(gpid):
1559              print 'ERROR.015.0010: gpid not found %s' % str(ll)
1560              self.e15_10 += 1
1561            if self.repl.has_key( thisuuid ):
1562              for tag,old,new in self.repl[thisuuid]:
1563                thisold = item.getAttribute( tag )
1564                assert thisold == old, 'Attempt to replace value which is not present'
1565                item.setAttribute( tag, new )
1566##################################
1567          elif k in ['revisedtabitem','requestvar']:
1568#### need to fill gaps in variable groups --- or do better job upstream ##########  !!!!!!!!!!!!!!!!
1569## - table; mip; uuid; priority
1570##
1571## variable group ids pulled through via mapping above .. very messy
1572## still missing some OMIP matches .... OMIP revised tables are not explicitly requested anywhere.
1573##
1574            kk = ['var', 'table', 'mip', 'vid', 'priority']
1575    ##self.rqvinfo = ('uid','label','vid','gpid','priority','mip','table' )
1576
1577            vgid = self.prqv.rqv_vg['%s.%s.%s' % (ll[2],ll[1],ll[0])]
1578            thisuuid = str( uuid.uuid1() )
1579            thisl = string.strip(str( ll[0] ) )
1580            for j in range(len(kk)):
1581              if j != 0 and kk[j] != 'table':
1582                item.setAttribute( kk[j], str( ll[j] ) )
1583            item.setAttribute( 'title', thisl + ' ((isd.005))' )
1584            item.setAttribute( 'uid', thisuuid )
1585            item.setAttribute( 'vgid', vgid )
1586            vid = str( ll[3] )
1587            if self.insert.has_key(thisl) and vid == '__new__':
1588                vid = self.insert[thisl]
1589                item.setAttribute( 'vid', self.insert[thisl] )
1590            if vid[0] == '_':
1591              f = {'6hrPlev':'6hr','Omon':'mon','Amon':'mon'}.get( ll[1], '__' )
1592              if f in self.cmvUidByFL and ll[0] in self.cmvUidByFL[f].a:
1593                if len( self.cmvUidByFL[f].a[ll[0]] ) == 1:
1594                  vid = self.cmvUidByFL[f].a[ll[0]][0]
1595                  item.setAttribute( 'vid', vid )
1596                  print 'INFO.090.08801: variable link corrected, %s' % len( self.cmvUidByFL[f].a[ll[0]] )
1597                else:
1598                  print 'WARN.090.08801: multiple options found, %s' % len( self.cmvUidByFL[f].a[ll[0]] )
1599            if vid[0] == '_':
1600              print 'ERROR.090.08801: bad variable ref [%s]' % vid,ll
1601
1602            if vid in self.fx.d2:
1603               if self.fx.d2[vid][3] == u'replace':
1604                 item.setAttribute( 'vid', str( self.fx.d2[vid][4] ) )
1605                 print 'INFO.qqq11: replacing link in requestVar  %s' % str(ll)
1606               else:
1607                 print 'INFO.qqq22: not replacing link in requestVar  %s' % str(ll)
1608            if vid in self.importWbMods.mmsi.ss:
1609              print 'INFO.046.0001: mip map found: ', self.importWbMods.mmsi.ss[vid]
1610              mm = self.importWbMods.mmsi.ss[vid]
1611              self._editRequestVar01( item, mm, ll )
1612               
1613            did = '%s__%s' % (vid,vgid)
1614            if self.vgcheck.has_key(did) and did[0] != '_':
1615              print 'ERROR.090.09001: Duplicate request ....: ',ll,self.vgcheck[did]
1616              dothis = False
1617            else:
1618              self.vgcheck[did] = ll
1619
1620##################################
1621          elif k == 'requestlink':
1622 ## - uuid; mip; tab; objective; grid; gridreq; comment
1623            kk = ['uid', 'mip', 'tab', 'objective', 'grid', 'gridreq', 'comment', 'opt', 'opar', 'preset', 'ref', 'refNote', 'refid']
1624            ##kk = ['uid', 'mip', 'tab', 'objective', 'grid', 'gridreq', 'comment', 'opt','opar','ref', 'refNote', 'refid']
1625            emap = {'uid':'uid'}
1626            mip = string.strip(str( ll[1] ) )
1627            obj = string.strip(str( ll[3] ) )
1628            if mip == "GMMIP":
1629              bits = [ mycc(x) for x in string.split( obj, ' ' ) ]
1630            else:
1631              bits = [ mycc(x) for x in string.split( obj, ',' ) ]
1632            for b in bits:
1633              self.objectiveLinks[mip].a[b].append( str( ll[0] ) )
1634            self.requestlinkuid.add( str(ll[0] ) )
1635            self.rqlPreset[str(ll[0])] = ll[9]
1636            dothis = False
1637       
1638 ##           thisl = string.strip(str( ll[2] ) )
1639##################################
1640          elif k == 'requestitem':
1641 ## - mip; tab; expt; rlid; ny
1642## defer so that cross-check of "expt" can be done .. or scan this earlier ....
1643              kk = ['mip', 'tab', 'expt', 'rlid', 'ny', 'nexmax', 'nenmax', 'nymax','treset','info']
1644              thisl = mycc( '%s %s' % (ll[0],ll[1]) )
1645              if str( ll[3] ) not in self.rqlPreset:
1646                 print 'ERROR.090.02000: requestlink not found .. ',ll
1647                 preset = '-99'
1648              else:
1649                 preset = str( self.rqlPreset[ str( ll[3] ) ] )
1650              if str( ll[3] ) not in self.requestlinkuid:
1651                print 'SEVERE.005.00005: rlid not found: %s' % str(ll)
1652              for j in range(len(kk)-1):
1653                if kk[j] == 'ny':
1654                  if ll[j] == '':
1655                    thisv = 0
1656                  else:
1657                    try:
1658                      thisv = str( int(ll[j]) )
1659                    except:
1660                      print 'SEVERE: failed to set "ny": %s' % str(ll)
1661                      thisv = 999
1662                else:
1663                  thisv = str( ll[j] )
1664                if not (kk[j] == 'treset' and thisv in ['None','']):
1665                  item.setAttribute( kk[j], thisv )
1666              item.setAttribute( 'title', '%s, %s, %s' % (ll[0],ll[1],ll[2]) )
1667              item.setAttribute( 'uid', str(i) )
1668              item.setAttribute( 'preset', preset )
1669              ku = str(ll[2])
1670              item.setAttribute( 'esid', self.exptPntUid[ku][0] )
1671              item.setAttribute( 'esidComment', str(self.exptPntUid[ku]) )
1672              if ll[0] in self.tsliceMap:
1673                if type(ll[-1]) in [type(''), type(u'')]:
1674                  kkk = string.strip( ll[-1] )
1675                  if kkk in self.tsliceMap[ll[0]]:
1676                    v = self.tsliceMap[ll[0]][kkk]
1677                    if v != None:
1678                      item.setAttribute( 'tslice', '_slice_%s' % v )
1679##################################
1680          elif k in ['requestvargroup','tablesection']:
1681            if k == 'requestvargroup':
1682              kk = ['uid', 'mip', 'label', 'title', 'ref', 'refNote']
1683            else:
1684              kk = ['uid', 'gpid', 'mip', 'label', 'title', 'ref', 'refNote']
1685            thisl = string.replace( str( ll[2] ), '.', '-' )
1686            if str(ll[0]) not in self.varGroupUids:
1687              print 'WARN.077.07707: uid not traced: ',ll
1688            else:
1689              print 'INFO.077.07707: uid traced: ',ll
1690            omitrvg = {'C4MIP-Omon','C4MIP-Oclim','HighResMIP-OImon','HighResMIP-Oclim'}
1691            if thisl in omitrvg:
1692              dothis = False
1693            else:
1694              for j in range(len(kk)):
1695                item.setAttribute( kk[j], str( ll[j] ) )
1696####
1697          if dothis:
1698            if labmod:
1699              if string.find( thisl, '_' ) != -1:
1700              #print 'WARNING: underscore in label', ll
1701                thisl = string.replace( thisl, '_', '-' )
1702              if string.find( thisl, '*' ) != -1:
1703                #print 'WARNING: star in label', ll
1704                thisl = string.replace( thisl, '*', '-' )
1705              if string.find( thisl, '!' ) != -1:
1706              #print 'WARNING: exclamation in label', ll
1707                thisl = string.replace( thisl, '!', '-' )
1708              if string.find( thisl, ' ' ) != -1:
1709              #print 'WARNING: space in label', ll
1710                thisl = string.replace( thisl, ' ', '-' )
1711              if string.find( thisl, ':' ) != -1:
1712              #print 'WARNING: colon in label', ll
1713                thisl = string.replace( thisl, ':', '-' )
1714            item.setAttribute( 'label', thisl )
1715            ff[k][0].appendChild( item )
1716           
1717  def write2(self):
1718    """write sections for cmor variable, request variable, structure, spatial and temporal dimensions"""
1719    spsResets = collections.defaultdict(list)
1720    self.spLab2Uid = {}
1721    for ksect in [ u'spatialshape', u'temporalshape', u'cmorvar', u'structure', u'requestvar', u'requestlink']:
1722    ##for ksect in [ u'cmorvar',  u'spatialshape', u'temporalshape', u'structure']:
1723        dil = self.ff[ksect][0].getElementsByTagName('item')
1724        if ksect != 'requestvar':
1725          for d in dil:
1726            self.ff[ksect][0].removeChild(d)
1727        if ksect == u'cmorvar':
1728          ktable = self.cmvinfo.index('mipTable')
1729          kfreq = self.cmvinfo.index('frequency')
1730          kstr = self.cmvinfo.index('stid')
1731            ##self.spatialDims[rr[0]] = rr[3]
1732          s1 = set()
1733          for r in self.cmv:
1734            if r[0] in s1:
1735              print 'ERROR.090.09005: duplicate key at ',r
1736            s1.add( r[0] )
1737            if len( r[1] ) == 2:
1738              spid = self.spLab2Uid[r[1][0]]
1739              print 'INFO.klklkl: AerChemMIP structure .... ',r[1]
1740            else:
1741              try:
1742                stid = self.strdd[r[1]]
1743              except:
1744                print 'ERROR.999.00099: strdd key not found: %s' % str(r[1])
1745                for k in self.strdd.keys():
1746                  if k[0] == r[1][0]:
1747                    print '*** ',k
1748                raise
1749             
1750            if r[0] in self.fx.d2:
1751              print 'INFO.qqq10: omitting record %s' % str( self.fx.d2[r[0]] )
1752            else:
1753              item = self.doc.createElement( 'item' )
1754              for k in range(len(self.cmvinfo)):
1755                n = self.cmvinfo[k]
1756                if n in self.cmvinfo2:
1757                  if n == 'mipTable' and str(r[k]) == 'CMIP5_Oyr':
1758                    print 'ERROR.047.0002: ',r
1759                  if n == "vid":
1760                    if str(r[k]) == '__var_not_found_012__':
1761                      print 'ERROR.099.00202: bad vid string: %s [%s]' % (r[k],str(r[:3]))
1762                    vid = str(r[k])
1763                  if n == "stid":
1764                    item.setAttribute( n, stid )
1765                  elif n == "label":
1766                    thisl = string.replace( r[k], '_', '' )
1767                    item.setAttribute( n, thisl )
1768                  elif n in ["valid_min","valid_max","ok_max_mean_abs","ok_min_mean_abs"]:
1769                    if str(r[k]) != "" and r[k] not in [None, 'None']:
1770                      if str(r[k]) == "None":
1771                        print 'ERROR.8888.00008: bad valid min/max: ',r[k]
1772                      item.setAttribute( n, str(r[k]) )
1773                  elif n == "frequency":
1774                    fr = freqmap.get( str(r[k]), str(r[k]) )
1775                    item.setAttribute( n, fr )
1776                  elif n == "mipTable":
1777                    tn = tableNameMap.get( str(r[k]), str(r[k]) )
1778                    item.setAttribute( n, tn )
1779                  else:
1780                    item.setAttribute( n, str(r[k]) )
1781
1782### reset table name for OImon ... correcting for frequency as well
1783###
1784              mtable = r[ktable]
1785              if r[ktable] == 'OImon':
1786                if r[kfreq] == 'mon':
1787                    mtable = 'SImon'
1788                    #item.setAttribute( 'mipTable', 'SImon' )
1789                else:
1790                    mtable = 'SIday'
1791                    #item.setAttribute( 'mipTable', 'SIday' )
1792              elif r[ktable] in ['em6hr','em3hr','emDay']:
1793                if stid in self.structInfo:
1794                  if string.find( self.structInfo[stid][1], 'time: point' ) != -1:
1795                    mtable += 'pt'
1796                  if string.find( self.spatialDims[ self.structInfo[stid][2] ], 'longitude' ) == -1:
1797                    mtable += 'Z'
1798                else:
1799                    print 'WARN.090.09999: structure uid not found',stid, r
1800              if mtable != r[ktable]:
1801                item.setAttribute( 'mipTable', mtable )
1802              if str(vid) not in self.importWbMods.vars.d1:
1803 
1804                  if thisl in self.importWbMods.vars.c1 or (thisl[-2:] in ['17','23','27'] and thisl[:-2] in self.importWbMods.vars.c1):
1805                    if thisl in self.importWbMods.vars.c1:
1806                      thisn = thisl
1807                    else:
1808                      thisn = thisl[:-2]
1809
1810                    if len( self.importWbMods.vars.c1[ thisn ] ) == 1:
1811                      newvid = self.importWbMods.vars.c1[ thisn ][0]
1812                      item.setAttribute( 'vid', newvid )
1813                      print 'INFO.099.00110: bad vid string replaced: %s [%s]' % (newvid,thisl)
1814                    else:
1815                      print 'ERROR.099.00111: ambiguous bad vid string: %s [%s]' % (vid,thisl)
1816                  else:
1817                    print 'ERROR.099.00112: bad vid string: %s [%s]' % (vid,thisl)
1818              thisuid = r[0]
1819              if self.repl.has_key( thisuid ):
1820                for tag,old,new in self.repl[thisuid]:
1821                  thisold = item.getAttribute( tag )
1822                  if thisold != old:
1823                     ##print 'WARN.yyy: Attempt to replace value which is not present'
1824                    print 'WARN.050.00051: Failed attempt to replace values in cmv: %s old:%s new:%s' % (tag,old,new)
1825                  else:
1826                    if tag == 'vid' and new not in self.importWbMods.vars.d1:
1827                        print 'ERROR.050.00052: Attempt to replave values in cmv with invalid vid: %s old:%s new:%s' % (tag,old,new)
1828                    else:
1829                      item.setAttribute( tag, new )
1830                      print 'INFO.050.00050: replacing values in cmv: %s old:%s new:%s' % (tag,old,new)
1831              self.ff[ksect][0].appendChild( item )
1832        elif ksect == u'structure':
1833          ers = {}
1834          for kk in spsResets:
1835            if len( spsResets[kk] ) > 0:
1836              utarg = spsResets[kk][0][0]
1837              for r in spsResets[kk][1:]:
1838                ers[r[0]] = utarg
1839          flds = self.structList[0]._fields
1840          for nt in self.structList:
1841            item = self.doc.createElement( 'item' )
1842            for f in flds:
1843              if f == 'spid' and nt.__dict__[f] in ers:
1844                item.setAttribute( f, ers[ nt.__dict__[f] ] )
1845                print 'INFO.801.00011: updating target spid .... '
1846              else:
1847                item.setAttribute( f, str( nt.__dict__[f] ) )
1848            self.ff[ksect][0].appendChild( item )
1849        elif ksect == u'spatialshape':
1850
1851     ##    self.dimsSpaceInfo = ['uid','label','title','dimensions','levelFlag','levels']
1852          self.spatialDims = {}
1853          for k in self.dimsSpace.keys():
1854            rr = self.dimsSpace[k]
1855            kk = rr[3]
1856            if kk == '':
1857              kk = 'scalar'
1858              rr = list(rr)
1859              rr[3] = 'scalar'
1860            elif kk == 'longitude|latitude|plev':
1861              kk = 'longitude|latitude|plev4'
1862              rr = list(rr)
1863              rr[3] = kk
1864            self.spatialDims[rr[0]] = rr[3]
1865            if kk not in spsResets:
1866              item = self.doc.createElement( 'item' )
1867              for i in range(len(self.dimsSpaceInfo)):
1868                item.setAttribute( self.dimsSpaceInfo[i], str( rr[i] ) )
1869              if rr[3] in self.spsh.ss:
1870                lab,ttl,lf,li = self.spsh.ss[rr[3]]
1871                if trace.SPATIALSHAPE_01:
1872                  print 'INFO.035.0001: new spatial shape label: %s, %s' % (lab, ttl)
1873                if ttl[:4] != 'ssd.':
1874                  item.setAttribute( 'title', ttl )
1875                if len(lab) < 4 or lab[:4] != 'ssd-':
1876                  item.setAttribute( 'label', lab )
1877                item.setAttribute( 'levels', li )
1878                item.setAttribute( 'levelFlag', string.lower(lf) )
1879              else:
1880                print 'ERROR.055.00001: spatial shape record not recognised: %s' % str(rr)
1881              print 'INFO.801.00120: new shape for %s' % str(rr)
1882              thisl = item.getAttribute( 'label' )
1883              assert thisl not in self.spLab2Uid.keys(), 'Duplicate spatial shape label: %s' % thisl
1884              self.spLab2Uid[thisl] = item.getAttribute( 'uid' )
1885              self.ff[ksect][0].appendChild( item )
1886            else:
1887              print 'INFO.801.00121: duplicate shape for %s' % str(rr)
1888            spsResets[kk].append( rr )
1889
1890        elif ksect == u'temporalshape':
1891          for k in self.dimsTime.keys():
1892            rr = self.dimsTime[k]
1893            item = self.doc.createElement( 'item' )
1894            for i in range(len(self.dimsTimeInfo)):
1895              item.setAttribute( self.dimsTimeInfo[i], str( rr[i] ) )
1896            self.ff[ksect][0].appendChild( item )
1897        elif ksect == u'requestvar':
1898          ##kk = ['var', 'table', 'mip', 'vid', 'priority']
1899          kk = ['label', 'table', 'mip', 'vid', 'priority','vgid','title','uid']
1900          kktr = {'vgid':'gpid', 'title':'label'}
1901    ##self.rqvinfo = ('uid','label','vid','gpid','priority','mip','table' )
1902          kkf = 0
1903          for t in self.rqv:
1904            item = self.doc.createElement( 'item' )
1905            ###assert len(t) == len(kk), 'BAD request variable line: %s' % str(t)
1906            for i in range(len(kk)):
1907              k = kktr.get( kk[i], kk[i] )
1908              v = t[  self.rqvinfo.index(k) ]
1909              if k == 'priority':
1910                item.setAttribute( kk[i], str( int(v) ) )
1911              elif kk[i] == 'label':
1912                thisl = string.replace( v, '_', '' )
1913                item.setAttribute( kk[i], thisl )
1914              elif kk[i] == 'title':
1915                if str(v) == 'bsi':
1916                  print 'INFO.999.09900: ',t
1917                item.setAttribute( kk[i], str( v ) + ' ((isd.006))' )
1918              elif kk[i] == 'table':
1919                pass
1920              else:
1921                item.setAttribute( kk[i], str( v ) )
1922
1923            vid = str( t[2] )
1924            if vid in self.fx.d2:
1925               if self.fx.d2[vid][3] == u'replace':
1926                 item.setAttribute( 'vid', str( self.fx.d2[vid][4] ) )
1927                 print 'INFO.qqq12: replacing link in requestVar  %s' % str(t)
1928            if vid in self.importWbMods.mmsi.ss:
1929              print 'INFO.046.0002: mip map found: ', self.importWbMods.mmsi.ss[vid]
1930              mm = self.importWbMods.mmsi.ss[vid]
1931              self._editRequestVar01( item, mm, t )
1932              ##item.setAttribute( 'vid', mm[0].vid2 )
1933              ##if len( mm ) > 1:
1934                ##assert len( mm ) < 3, 'Unable to deal with triple clone'
1935                ##cln = item.cloneNode(True)
1936                ##cln.setAttribute( 'uid', str( uuid.uuid1() ) )
1937                ##cln.setAttribute( 'vid', mm[1].vid2 )
1938                ##self.ff[ksect][0].appendChild( cln )
1939                ##print 'INFO.046.0003: request variable split:', t[1]
1940             
1941            did = '%s__%s' % (t[2],t[3])
1942            if self.vgcheck.has_key(did):
1943              print 'ERROR.090.09002: Duplicate request ....: ',t,self.vgcheck[did]
1944            else:
1945              self.vgcheck[did] = t
1946              self.ff[ksect][0].appendChild( item )
1947              assert len( self.rqvClone.keys() ) > 5, 'rqvClone does not appear to be initialied: %s' % len( self.rqvClone.keys() )
1948              if self.rqvClone.has_key(t[0]):
1949                kkf += 1
1950                for id in self.rqvClone[t[0]]:
1951                  cln = item.cloneNode(True)
1952                  cln.setAttribute( 'vgid', id )
1953                  cln.setAttribute( 'uid', str( uuid.uuid1() ) )
1954                  self.ff[ksect][0].appendChild( cln )
1955                  print 'INFO.090.01010: request variable cloned:', t[1]
1956##
1957######################################################################################
1958##
1959        elif ksect == u'requestlink':
1960 ## - uuid; mip; tab; objective; grid; gridreq; comment
1961            kk = ['uid', 'mip', 'tab', 'objective', 'grid', 'gridreq', 'comment', 'opt', 'opar', 'preset', 'ref', 'refNote', 'refid']
1962            ##kk = ['uid', 'mip', 'tab', 'objective', 'grid', 'gridreq', 'comment', 'opt','opar','ref', 'refNote', 'refid']
1963       
1964            thissh = self.skey['requestlink']
1965            for k in thissh:
1966              if k[0] != '_':
1967                ll = thissh[k][:]
1968                thisl = string.strip(str( ll[2] ) )
1969                uid = string.strip(str( ll[0] ) )
1970                item = self.doc.createElement( 'item' )
1971                for j in range(len(kk)):
1972                  thiskk = kk[j]
1973## preset mover to request item .... so it can also be used on a per-experiment basis
1974                  if thiskk != 'preset':
1975                    try:
1976                      if kk[j] == 'comment':
1977                        v = utils_wb.uniCleanFunc( v )
1978                      else:
1979                        v = str( ll[j] )
1980                    except:
1981                      print thisl, kk[j]
1982                      print 'ERROR.099.0001: Failed to convert string '
1983                      print ll
1984                      v = '__error_99_1__'
1985
1986### redirect to new variable group if specified in mappings
1987##
1988                    if kk[j] == 'refid' and self.rvgUidMapping.has_key(v):
1989                        v = self.rvgUidMapping[v]
1990                        print 'INFO.090.00200: variable group reference reset in %s [%s]' % (thisl,uid)
1991
1992                    item.setAttribute( thiskk, v )
1993
1994                item.setAttribute( 'title', thisl )
1995                if self.rqlRedirect.has_key( ll[0] ):
1996                   print 'INFO.088.02020: redirect detected ',ll
1997                   item.setAttribute( 'refid', self.rqlRedirect[ ll[0] ] )
1998                self.ff[ksect][0].appendChild( item )
1999##################################
2000               
2001
2002  def _editRequestVar01( self, item, mm, t ):
2003              item.setAttribute( 'vid', mm[0].vid2 )
2004              item.setAttribute( 'label', mm[0].lab2 )
2005              if len( mm ) > 1:
2006                assert len( mm ) < 3, 'Unable to deal with triple clone'
2007                cln = item.cloneNode(True)
2008                cln.setAttribute( 'uid', str( uuid.uuid1() ) )
2009                cln.setAttribute( 'label', mm[1].lab2 )
2010                self.ff['requestvar'][0].appendChild( cln )
2011                print 'INFO.046.0003: request variable split:', t[1]
2012
2013  def finishExptGrp(self):
2014    """finish exptGroup section and create exptgrouplink section"""
2015    this = self.doc.getElementsByTagName('exptGroup')[0]
2016            ### kk = ['uid','label','tierMin','ntot']
2017    for k in self.exptPntUid.keys():
2018      u,typ = self.exptPntUid[k]
2019##      if not isg:
2020        ##item = self.doc.createElement( 'item' )
2021        ##item.setAttribute( uid, u )
2022    ##this = self.doc.getElementsByTagName('exptGroupLink')[0]
2023    ##dil = this.getElementsByTagName('item')
2024    ##for d in dil:
2025          ##this.removeChild(d)
2026    ##this.appendChild( item )
2027
2028  def reviewExpt(self):
2029    """Prepare cross-linking information to populate requestitem, exptgroup and exptgrouplink"""
2030    sh = shelve.open( '../framework/sh_links/exptMappings', 'r' )
2031    extraMappings={ 'LS3MIP-1, LS3MIP-2':['LmipH', 'LmipF'] }
2032    ks = sorted( self.exptPnt.keys() )
2033    self.exptPntMap = collections.defaultdict( list )
2034    self.exptPntUid = {}
2035    ner = 0
2036    ngr = 0
2037    nmr = 0
2038    nuns = 0
2039    nls = 0
2040    for k0 in ks:
2041      k = string.replace( string.replace( k0, '\n', ' ' ), '  ', ' ')
2042      thisl = None
2043      if sh.has_key(k):
2044        thisl = sh[k]
2045      elif extraMappings.has_key(k):
2046        thisl = extraMappings[k]
2047      else:
2048        print 'ERROR.080.00010: no mapping founds for experiment %s' % k
2049     
2050
2051      if thisl != None:
2052        thisu = None
2053        thisls = set( thisl )
2054        linkType = None
2055        for k2 in thisls:
2056          ok = True
2057          if self.experiments.has_key(k2):
2058            ner += 1
2059            linkType = 'expt'
2060            thisu = self.experiments[k2]
2061          elif self.experimentGrp.has_key(k2):
2062            ngr += 1
2063            thisu = self.experimentGrp[k2]
2064            linkType = 'grp'
2065          elif k2 in self.mips:
2066            nmr += 1
2067            thisu = k2
2068            linkType = 'mip'
2069          else:
2070            ok = False
2071            print 'ERROR.080.00999: target experiment not found: %s [%s]' % (k2,k)
2072          if not ok:
2073            self.exptPntMap[k].append( k2 )
2074##
2075## store uid of expt group to be pointed at.
2076##
2077        if len(thisls) == 1 and thisu != None:
2078          self.exptPntUid[k0] = (thisu, linkType, thisls)
2079        else:
2080          self.exptPntUid[k0] = (str( uuid.uuid1() ), 'list', thisls )
2081          nls += 1
2082      else:
2083          nuns += 1
2084          self.exptPntUid[k0] = (None,None)
2085     
2086    sh.close()
2087    print 'INFO.080.00010: Expt refs: %s, Expt group refs: %s, MIP expt set refs: %s, unset: %s, lists: %s' % (ner,ngr,nmr, nuns, nls)
2088
2089  def reviewObj(self):
2090## review objectives
2091##
2092    ol = []
2093    fnd1 = set()
2094    for m in self.objectives.keys():
2095      not_used = []
2096      used = set()
2097      not_found = []
2098      found = []
2099      alist = ['All','All?','all']
2100      aaa = [self.objectiveLinks[m].a.has_key(x) for x in ['All','All?','all'] ]
2101      us1 = set()
2102      for k in self.objectiveLinks[m].a:
2103        x = None
2104        if k == 'AllExceptPaleorcms':
2105          x = self.objectives[m].keys()
2106          x.pop( x.index( 'Paleorcms' ) )
2107        elif k == 'AllExceptNaturalVariability':
2108          x = self.objectives[m].keys()
2109          x.pop( x.index( 'NaturalVariability' ) )
2110
2111        if x != None:
2112          fnd1.add(k)
2113          for i in x:
2114            used.add(i)
2115            us1.add(i)
2116            for u in self.objectiveLinks[m].a[k]:
2117              ol.append( (m,self.objectives[m][i], u ) )
2118         
2119      allused = (m != 'GMMIP') and any( aaa )
2120      for o in self.objectives[m].keys():
2121        if allused or self.objectiveLinks[m].a.has_key(o):
2122          used.add(o)
2123          for u in self.objectiveLinks[m].a[o]:
2124            ol.append( (m,self.objectives[m][o], u ) )
2125          for k in alist:
2126            if self.objectiveLinks[m].a.has_key(k):
2127              for u in self.objectiveLinks[m].a[k]:
2128                ol.append( (m,self.objectives[m][o], u ) )
2129        elif o not in us1:
2130          not_used.append(o)
2131
2132      for o in self.objectiveLinks[m].a.keys():
2133        if (o in {'All','All?'} and len(self.objectives[m].keys()) > 0 ) or self.objectives[m].has_key(o) or o in fnd1:
2134          found.append(o)
2135        else:
2136          not_found.append(o)
2137      if len(not_used) > 0 or len(not_found) > 0:
2138        print 'WARN.080.00002: %s: OK %s: unused: %s: not found:%s' % (m,str(used),str(not_used),str(not_found))
2139      else:
2140        print 'INFO.080.00002: %s: all objectives matched' % m
2141    self.objList = ol
2142
2143
2144  def finish(self):
2145## varChoice section
2146    self.choices()
2147##
2148    self.reviewObj()
2149##
2150##
2151    if len( self.prqv.addExrqvg )  > 0:
2152      this = self.doc.getElementsByTagName('requestVarGroup')[0]
2153      kk = ['uid', 'mip', 'label', 'title', 'ref', 'refNote']
2154      for k in self.prqv.addExrqvg:
2155         item = self.doc.createElement( 'item' )
2156         ll = self.prqv.exrqvg[k]
2157         thisl = string.replace( str( ll[2] ), '.', '-' )
2158         for j in range(len(kk)):
2159              if kk[j] == 'refNote':
2160                item.setAttribute( kk[j], str( ll[j] ) + '((isd.004))' )
2161              else:
2162                item.setAttribute( kk[j], str( ll[j] ) )
2163         this.appendChild( item )
2164##
2165##  objectiveLink
2166##
2167    this = self.doc.getElementsByTagName('objectiveLink')[0]
2168    dil = this.getElementsByTagName('item')
2169    for d in dil:
2170          this.removeChild(d)
2171    for t in self.objList:
2172       item = self.doc.createElement( 'item' )
2173       item.setAttribute( 'label', t[0] )
2174       item.setAttribute( 'oid', t[1] )
2175       item.setAttribute( 'rid', t[2] )
2176       thisuuid = str( uuid.uuid1() )
2177       item.setAttribute( 'uid', thisuuid )
2178       this.appendChild( item )
2179##
2180## remarks
2181##
2182    this = self.doc.getElementsByTagName('remarks')[0]
2183    dil = this.getElementsByTagName('item')
2184    for d in dil:
2185          this.removeChild(d)
2186
2187    txt = self.doc.toprettyxml(indent='\t', newl='\n', encoding=None)
2188    if self.schemaMode == 'dreq2':
2189      ofn = 'trial2_20150831.xml'
2190    else:
2191      ofn = 'trial_20150831.xml'
2192    oo = open( ofn, 'w' )
2193    lines = string.split( txt, '\n' )
2194    for line in lines:
2195      l = utils_wb.uniCleanFunc( string.strip(line) )
2196      if empty.match(l):
2197        continue
2198      else: 
2199        oo.write(l + '\n')
2200    oo.close()
2201
2202  def choices(self):
2203    """Populate the 'varChoice' section, using the information in the 'choices' dictionary in 'choicecfg'"""
2204
2205    ccfg = choiceCfg.choices( self )
2206    self.ccfg = ccfg
2207##
2208##  choices
2209##
2210    this = self.doc.getElementsByTagName('varChoice')[0]
2211    dil = this.getElementsByTagName('item')
2212    for d in dil:
2213          this.removeChild(d)
2214    for k in ccfg.choices.keys():
2215       item = self.doc.createElement( 'item' )
2216       cc = ccfg.choices[k]
2217       for kk in cc.keys():
2218         item.setAttribute( kk, cc[kk] )
2219       this.appendChild( item )
2220       print 'INFO.zzz.00008: Appending ',cc[kk]
2221
2222    this = self.doc.getElementsByTagName('varChoiceLinkR')[0]
2223    dil = this.getElementsByTagName('item')
2224    for d in dil:
2225          this.removeChild(d)
2226    for cc in ccfg.varChoiceLnk:
2227       item = self.doc.createElement( 'item' )
2228       print 'INFO.zzz', cc
2229       for i in range( len( ccfg.varChoiceLnkInfo ) ):
2230         item.setAttribute( ccfg.varChoiceLnkInfo[i], cc[i] )
2231       this.appendChild( item )
2232
2233    this = self.doc.getElementsByTagName('varChoiceLinkC')[0]
2234    dil = this.getElementsByTagName('item')
2235    for d in dil:
2236          this.removeChild(d)
2237    for cc in ccfg.varChoiceLnkCfg:
2238       item = self.doc.createElement( 'item' )
2239       for i in range( len( ccfg.varChoiceLnkCfgInfo ) ):
2240         item.setAttribute( ccfg.varChoiceLnkCfgInfo[i], cc[i] )
2241       this.appendChild( item )
2242
2243    ##self.varChoiceLnkCfgInfo = [ 'uid', 'label', 'title', 'vid', 'cid', 'cfgid', 'cfg'
2244
2245  def importRepl(self,rfile='uuidreplace.csv'):
2246    for l in open(rfile).readlines():
2247      bits = string.split( string.strip(l), '\t' )
2248      assert len(bits) == 7, 'Could not parse item replacement file'
2249      self.repl[ bits[3] ].append( (bits[2],bits[0],bits[1] ) )
2250      self.replItems[bits[0]] = bits[1]
2251
2252  def importRemove(self,rfile='uuidremove.csv'):
2253    for l in open(rfile).readlines():
2254      self.remo[ string.strip(l) ] = 1
2255
2256  def importUpdate(self,rfile='uuidupdate.csv'):
2257    for l in open(rfile).readlines():
2258      bits = string.split( string.strip(l), '\t' )
2259      tgs = string.strip( bits[2] )
2260      if string.find( tgs, ' ' ) == -1:
2261        tags = [tgs,]
2262      else:
2263        tags = string.split( tgs )
2264      self.upda[ bits[0] ] =  {'comment':bits[1], 'tags':tags, 'label':bits[3], 'title':bits[4] }
2265
2266  def importInsert(self,rfile='uuidinsert.csv'):
2267    for l in open(rfile).readlines():
2268      bits = string.split( string.strip(l), '\t' )
2269      if bits[0] == 'unique':
2270         self.insert[bits[1]] = bits[3]
2271
2272mode = 'dreq2'
2273sampleXml = '../framework/out/%sSample.xml' % mode
2274from scansh import rq
2275
2276##cmip5GrpLk = collections.defaultdict( dict )
2277##for k in rq.cmip5Grps.keys():
2278  ##bits = string.split(k,'_')
2279  ##tab = bits[0]
2280  ##for v in rq.cmip5Grps[k]:
2281    ##cmip5GrpLk[tab][v] = k
2282
2283m = main(sampleXml, rq,run=True, schemaMode=mode, doRepl=True)
2284
2285ks = m.prqv.err0010.keys()
2286ks.sort()
2287for k in ks:
2288    print 'ERROR.001.0010: variable group not identified: %s [%s]' % (k,m.prqv.err0010[k])
2289ks = m.prqv.err0020.keys()
2290ks.sort()
2291for k in ks:
2292    print 'ERROR.001.0020: variable group not identified: %s [%s]' % (k,m.prqv.err0020[k])
Note: See TracBrowser for help on using the repository browser.