Specific TELEMAC Toolbox

Global dictionnaries to avoid having to read these more than once.

The keys are the full path to the dictionnaries and therefore allows for root and version to change


def getDICO(cfg,code):
 
   dicoFile = path.join(cfg['MODULES'][code]['path'],code+'.dico')
   if dicoFile not in DICOS.keys():
      print '    +> register this DICO file: ' + dicoFile
      frgb,dico = scanDICO(dicoFile)
      idico,odico = getIOFilesSubmit(frgb,dico)
      globals()['DICOS'].update({dicoFile:{ 'frgb':frgb, 'dico':dico, 'input':idico, 'output':odico }})
 
   return dicoFile
 
# _____                      _______________________________________
# ____/ General XML Toolbox /______________________________________/
#
"""
   Will read the xml's XML keys based on the template do.
   +: those with None are must have
   +: those without None are optional and reset if there
"""
def getXMLKeys(xml,do):
 
   xcpt = []                            # try all keys for full report
   done = do.copy()                     # shallow copy is here sufficient
   for key in done.keys():
      if not key in xml.keys():
         if done[key] == None:
            xcpt.append({'name':'getXMLKeys','msg':'cannot find the key: '+key})
      else:
         done[key] = xml.attrib[key]
   if xcpt != []: raise Exception(xcpt) # raise full report
 
   return done
 
def setSafe(casFile,cas,idico,odico,safe):
 
   copyFile(casFile,safe)   # TODO: look at relative paths
   wDir = path.dirname(casFile)
 
   # ~~> process sortie files if any
   sacFile = path.join(safe,casFile)
   sortieFiles = getLatestSortieFiles(sacFile)
 
   # ~~> process input / output
   iFS = []; oFS = []
   for k,v in zip(*cas):
      if idico.has_key(k):
         copyFile(path.join(wDir,eval(v[0])),safe)
         ifile = path.join(safe,eval(v[0]))
         iFS.append([k,[ifile],idico[k]])
         #if not path.isfile(ifile):
         #   print '... file does not exist ',ifile
         #   sys.exit()
      if odico.has_key(k):
         ofile = path.join(safe,eval(v[0]))
         oFS.append([k,[ofile],odico[k]])
 
   return sortieFiles,iFS,oFS
 
def findTargets(dido,src):
   layers = {}
   oneFound = False
   for cfg in dido.keys():
      cfgFound = False
      if dido[cfg].has_key(src):
         layers.update({ cfg:[dido[cfg][src],'',src] })
         cfgFound = True
      if not cfgFound and dido[cfg].has_key('input'):
         for i,j,k in dido[cfg]['input']:
            k = k.split(';')
            if src in k[1]:               # filename, fileForm, fileType
               # /!\ Temporary fix because TOMAWAC's IOs names are not yet standard TELEMAC
               if k[5] =='SCAL': k[5] = k[1]
               # \!/
               layers.update({ cfg:[j,k[3],k[5]] })
               cfgFound  = True
      if not cfgFound and dido[cfg].has_key('output'):
         if dido[cfg]['code'] == 'postel3d':
            for file in dido[cfg]['output']:
               if src == path.basename(file) :
                  layers.update({ cfg:[[file],'','SELAFIN'] })
                  cfgFound = True 
         else :
            for i,j,k in dido[cfg]['output']:
               k = k.split(';')
               if src in k[1]:               # filename, fileForm, fileType
                  # /!\ Temporary fix because TOMAWAC's IOs names are not yet standard TELEMAC
                  if k[5] =='SCAL': k[5] = k[1]
                  # \!/
                  layers.update({ cfg:[j,k[3],k[5]] })
                  cfgFound = True
      if not cfgFound and dido[cfg].has_key('type'):
         if dido[cfg]['type'] == src:
            layers.update({ cfg:[[dido[cfg]['target']],'',src] })
            cfgFound = True
      oneFound = oneFound or cfgFound
   if not oneFound:
      raise Exception([{'name':'findTargets','msg':'did not find the file to group: '+src}])
   return layers
 
def findDecos():
   pass
 
# _____                        _____________________________________
# ____/ Primary Class: ACTION /____________________________________/
#
"""
   In the classes below, the double quoted keys refer to the keys
      of the XML file. Contrarily, the single quoted keys in
      because they are internal to the python scripts.
   In the XML file, you can have multiple actions and each action
      will be associated with multiple configurations:
      did.keys() => array [xref] for each action
      did[xref].keys() => array [cfgname] for each possible configuration
      did[xref][cfgname].keys() =>
         - 'target', basename of the CAS file
         - 'cas', scanned CAS file
         - 'code', name of the module
         - 'title', title of the action (xref)
         - 'cmaps', refer to the directory 'ColourMaps' for colour plotting
         - 'deprefs', refer to the files that need copying from path to safe
         - 'outrefs', refer to the files that need copying from safe to path
         - 'where' will not default to xref anymore, allowing files to
      be shared and located at the same place between actions
"""
class ACTION:
 
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   #                                                General Methods
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   availacts = ''
   availkeys = { 'path':'','safe':'','cfg':'',
         "target": '', "xref": '', "do": '', "rank":'',
         "title": '', "deprefs":'', "outrefs":'', "where":'' }
 
   def __init__(self,title='',bypass=True):
      self.active = {}
      if title != '': self.active["title"] = title
      self.bypass = bypass
      self.dids = {}
 
   def addAction(self,actions,rank=''):
      self.active.update(deepcopy(self.availkeys))
      try:
         self.active = getXMLKeys(actions,self.active)
      except Exception as e:
         raise Exception([filterMessage({'name':'ACTION::addACTION'},e,self.bypass)])  # only one item here
      if self.dids.has_key(self.active["xref"]):
         raise Exception([{'name':'ACTION::addACTION','msg':'you are getting me confused, this xref already exists: '+self.active["xref"]}])
      self.dids.update({ self.active["xref"]:{} })
      if self.active["rank"] == '': self.active["rank"] = rank
      if self.active["rank"] == '': self.active["rank"] = '953'
      self.active["rank"] = int(self.active["rank"])
      if isinstance(self.active["deprefs"], StringTypes):
         deprefs = {}
         if self.active["deprefs"] != '':
            for depref in self.active["deprefs"].split(';'):
               if ':' in depref: ref,dep = depref.split(':')
               else: # ref becomes the name itself if no dependencies to other actions
                  ref = depref
                  dep = depref
               deprefs.update({ref:dep})
         self.active["deprefs"] = deprefs
      if isinstance(self.active["outrefs"], StringTypes):
         outrefs = {}
         if self.active["outrefs"] != '':
            for outref in self.active["outrefs"].split(';'):
               ref,out = outref.split(':')
               outrefs.update({ref:out})
         self.active["outrefs"] = outrefs
      return self.active["target"]
 
   def addCFG(self,cfgname,cfg):
      self.active['cfg'] = cfgname
      if self.active["where"] != '':
         self.active['safe'] = path.join( path.join(self.active['path'],self.active["where"]),cfgname )
      else: self.active['safe'] = path.join( path.join(self.active['path'],self.active["xref"]),cfgname )
      self.dids[self.active["xref"]].update( { cfgname: {
         'target': self.active["target"],
         'safe': self.active['safe'],
         'path': self.active['path'],
         'title': self.active["title"],
         'cmaps': path.join(cfg['PWD'],'ColourMaps')
         } } )
 
   def updateCFG(self,d): self.dids[self.active["xref"]][self.active['cfg']].update( d )
 
# _____                        _____________________________________
# ____/ Primary Class: GROUPS /____________________________________/
#
"""
   In the classes below, the double quoted keys refer to the keys
      of the XML file. Contrarily, the single quoted keys in
      because they are internal to the python scripts.
   In the XML file, you can have multiple actions and each action
      will be associated with multiple configurations:
      did.keys() => array [xref] for each action
      did[xref].keys() => array [cfgname] for each possible configuration
      did[xref][cfgname].keys() =>
         - 'target', basename of the CAS file
         - 'cas', scanned CAS file
         - 'code', name of the module
         - 'title', title of the action (xref)
         - 'cmaps', refer to the directory 'ColourMaps' for colour plotting
         - 'deprefs', refer to the files that need copying from path to safe
         - 'outrefs', refer to the files that need copying from safe to path
         - 'where' will not default to xref anymore, allowing files to
      be shared and located at the same place between groups
"""
 
class GROUPS:
 
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   #                                                General Methods
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   availacts = ''
   availkeys = { "xref": None, "deco": '' }
   groupkeys = { }
   avaylkeys = { }
 
   def __init__(self,title='',bypass=True):
      self.active = deepcopy(self.availkeys)
      if title != '': self.active["title"] = title
      self.bypass = bypass
      self.dids = {}
      # those you need to see in the XML file
      self.active["target"] = None
      self.active["code"] = None
      self.active["do"] = None
      self.active["type"] = None
      # additional entities
      self.tasks = {}
 
   def addGroupType(self,group):
      self.dids.update({group:{}})
      self.active['type'] = group
 
   def addGroup(self,group):
      tasks = deepcopy(self.availkeys)
      try:
         self.tasks = getXMLKeys(group,tasks)
      except Exception as e:
         raise Exception([filterMessage({'name':'GROUP::addGroup'},e,self.bypass)])
      self.active['xref'] = self.tasks["xref"]
      if self.dids[self.active['type']].has_key(self.tasks["xref"]):
         raise Exception([{'name':'GROUP::addGroup','msg':'you are getting me confused, this xref already exists: '+self.tasks["xref"]}])
      self.dids[self.active['type']].update({self.tasks["xref"]:self.tasks})
 
   def update(self,d): self.dids[self.active['type']][self.active['xref']].update( d )
 
   def addSubTask(self,layer,nametask='layers'):
      # ~~> set default from the upper grouper
      subtasks = {}
      for k in self.groupkeys: subtasks.update({k:self.tasks[k]})
      for k in self.avaylkeys: subtasks.update({k:self.avaylkeys[k]})
      # ~~> reset from layer
      try:
         subtasks = getXMLKeys(layer,subtasks)
      except Exception as e:
         raise Exception([filterMessage({'name':'GROUP::addSubTask'},e,self.bypass)])
      # ~~> filling-in remaining gaps
      subtasks = self.distributeMeta(subtasks)
      # ~~> adding subtask to the list of tasks
      if self.tasks.has_key(nametask): self.tasks[nametask].append(subtasks)
      else: self.tasks.update({nametask:[subtasks]})
      return len(self.tasks[nametask])-1,nametask
 
   def targetSubTask(self,target,index=0,nametask='layers'):
      self.tasks[nametask][index].update({ 'fileName': target })
      if not self.dids[self.active['type']][self.active['xref']].has_key(nametask): self.dids[self.active['type']][self.active['xref']].update({nametask:[]})
      self.dids[self.active['type']][self.active['xref']][nametask].append(self.tasks[nametask][index])
 
   def distributeMeta(self,subtask): return subtask
 
   def decotasks(self,deco={},index=0,nametask='layers'):
      # ~~> set default
      self.tasks[nametask][index]['deco'] = deco
 
 
# _____                        _____________________________________
# ____/ Secondary Class: META /____________________________________/
#
class groupMETA(GROUPS):
 
   availkeys = deepcopy(GROUPS.availkeys)
   availkeys.update({ "roi":'', "deco": 'line', "size":'[15;10]',
         'outFormat': 'png', 'grid': True })
   groupkeys = deepcopy(GROUPS.groupkeys)
 
   def __init__(self,xmlFile,title='',bypass=True):
      GROUPS.__init__(self,title,bypass)
      # those you reset
      self.active['path'] = path.dirname(xmlFile)
      # those you need to see in the XML file
      self.active["deco"] = {}
 
   def addDraw(self,meta):
      GROUPS.addGroup(self,meta)
 
   def addLookTask(self,layer,nametask='look'):
      #self.avaylkeys = deepcopy(GROUPS.avaylkeys)
      self.avaylkeys = {}
      for key in layer.attrib.keys():
         self.avaylkeys.update({key:layer.attrib[key]})
         if key == 'grid':
            if layer.attrib['grid'] == 'no': layer.attrib['grid'] = False
            else: layer.attrib['grid'] = True
      return GROUPS.addSubTask(self,layer,'look')
 
   def addDataTask(self,layer,nametask='data'):
      self.avaylkeys = deepcopy(GROUPS.avaylkeys)
      self.avaylkeys.update({ "title":'', "contact":'', "author":'' })
      return GROUPS.addSubTask(self,layer,'data')
 
# _____                            __________________________________
# ____/ Secondary Class actionRUN /_________________________________/
#
# actionRUN is to do with the modules of the TELEMAC system and
#    other execution (pre- and post-processes).
#    . It understands what a PRINCI and what a CAS file and will do
#    the necessary steps to run modules accordingly.
#    . It includes specific methods to do with CAS and PRINCI
#    . It will organise the tranfer of files (inputs and outputs)
#
 
class actionRUN(ACTION):
 
   availkeys = deepcopy(ACTION.availkeys)
   availkeys.update({ 'dico':'', "ncsize":'', "code": '' })
 
   def __init__(self,xmlFile,title='',bypass=True):
      ACTION.__init__(self,title,bypass)
      # those you reset
      self.active['path'] = path.dirname(xmlFile)
      # those you need to see in the XML file
      self.active["target"] = None
      self.active["code"] = None
      self.active["xref"] = None
      self.active["do"] = None
 
   def addAction(self,actions,rank=''):
      target = ACTION.addAction(self,actions,rank)
      self.code = self.active["code"]
      return target
 
   def addCFG(self,cfgname,cfg):
      if not ( self.active["code"] == 'exec' or
               self.active["code"] in cfg['MODULES'].keys() ):
         print '... do not know about: ' + self.active["code"] + ' in configuration: ' + cfgname
         sys.exit()
      ACTION.addCFG(self,cfgname,cfg)
      ACTION.updateCFG(self,{ "links": {},
         'code': self.active["code"],
         'deprefs': self.active['deprefs'],
         'outrefs': self.active['outrefs'] })
 
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   #                                            CAS related Methods
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
   # ~~ todo: difference of CAS file with default keys ~~~~~~~~~~~~~
   def diffCAS(self): return
 
   # ~~ Translate the CAS file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   def translateCAS(self,rebuild):
      if not "translate" in self.availacts.split(';'): return
      xref = self.active["xref"]; cfgname = self.active['cfg']
      active = self.dids[xref][cfgname]
      # ~~> principal CAS file
      casFile = path.join(active['path'],active["target"])
      sacFile = path.join(active['safe'],active["target"])
      oneup = path.dirname(active['safe'])            # copied one level up
      if matchSafe(casFile,active["target"]+'.??',oneup,rebuild):
         print '      ~> translate cas file: ' + active["target"]
         casfr,casgb = translateCAS(sacFile,DICOS[active['dico']]['frgb'])  #/!\ removes comments at end of lines
         moveFile(casfr,oneup)
         moveFile(casgb,oneup)
      # ~~> associated CAS files
      for mod in active["links"]:
         link = active["links"][mod]
         casFile = path.join(active['path'],link['target'])
         sacFile = path.join(active['safe'],link['target'])
         if matchSafe(casFile,link['target']+'.??',oneup,rebuild):
            print '      ~> translate cas file: ' + link['target']
            casfr,casgb = translateCAS(sacFile,DICOS[link['dico']]['frgb'])  #/!\ removes comments at end of lines
            moveFile(casfr,oneup)
            moveFile(casgb,oneup)
 
   # ~~ Run the CAS file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   def runCAS(self,options,cfg,rebuild):
      if not "run" in self.availacts.split(';'): return
 
      # ~~> prepare options as if run from command line
      specs = Values()
      setattr(specs,'configName',options.configName)
      setattr(specs,'configFile', options.configFile)
      setattr(specs,'sortieFile',True)
      setattr(specs,'tmpdirectory',True)
      setattr(specs,'rootDir', options.rootDir)
      setattr(specs,'version', options.version)
      setattr(specs,'wDir', options.wDir)
      setattr(specs,'compileonly', False)
      if options.hosts != '': setattr(specs,'hosts', options.hosts)
      else: setattr(specs,'hosts', gethostname().split('.')[0])
      setattr(specs,'split', options.split)
      setattr(specs,'run', options.run)
      setattr(specs,'merge', options.merge)
      if options.ncsize != '' and self.active["ncsize"] != '': self.active["ncsize"] = options.ncsize
      setattr(specs,'ncsize', self.active["ncsize"])
      setattr(specs,'nctile', '1')    # default but should not be used for validation
      setattr(specs,'bypass',self.bypass)
 
      # ~~> check on sorties and run
      casFile = path.join(self.active['path'],self.active["target"])
      sacFile = path.join(self.active['safe'],self.active["target"])
      sortieFiles = getLatestSortieFiles(sacFile)
      outputs = self.dids[self.active["xref"]][self.active['cfg']]['output']
      if matchSafe(casFile,self.active["target"]+'_*??h??min??s*.sortie',self.active['safe'],rebuild):
         print '     +> running cas file: ' + self.active["target"]
         for k in outputs: matchSafe('',path.basename(k[1][0]),self.active['safe'],2)
         try:
            sortieFiles = runCAS(self.active['cfg'],cfg,self.active["code"],sacFile,specs)
         except Exception as e:
            raise Exception([filterMessage({'name':'ACTION::runCAS'},e,self.bypass)])  # only one item here
      if sortieFiles != []: self.updateCFG({ 'sortie': sortieFiles })
 
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   #                                         PRINCI related Methods
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
   # ~~ Highligh user PRINCI differences ~~~~~~~~~~~~~~~~~~~~~~~~~~~
   def diffPRINCI(self,options,cfg,rebuild):
      if not "princi" in self.availacts.split(';'): return
      xref = self.active["xref"]; cfgname = self.active['cfg']
      active = self.dids[xref][cfgname]
      oneup = path.dirname(active['safe'])            # copied one level up
      # ~~> principal PRINCI file
      value,default = getKeyWord('FICHIER FORTRAN',active['cas'],DICOS[active['dico']]['dico'],DICOS[active['dico']]['frgb'])
      princiFile = ''
      if value != []:
         princiFile = path.join(active['path'],eval(value[0]))
         if path.exists(princiFile):
            htmlFile = path.join(oneup,path.splitext(path.basename(princiFile))[0]+'.html')
            if matchSafe(htmlFile,path.basename(htmlFile),oneup,rebuild):
               # ~~> Scans the principal user PRINCI file
               print '      ~> scanning your PRINCI file: ',path.basename(princiFile)
               pFiles = getPrincipalWrapNames(princiFile)
               if pFiles == []:
                  raise Exception([{'name':'ACTION::diffPRINCI','msg':'I could not recognised entities in your PRINCI: '+princiFile}])
               else:
                  print '        +> found:'
                  for pFile in pFiles: print '           - ',pFile
               # ~~> Scans the entire system
               oFiles = {}
               for mod in cfg['MODULES']:
                  for dirpath,dirnames,filenames in walk(cfg['MODULES'][mod]['path']) : break
                  for file in filenames:
                     n,e = path.splitext(file)
                     # Only looking for fortran files
                     if e.lower() not in ['.f','.f90']: continue
                     for pFile in pFiles:
                        if pFile.lower() == n:
                           oFiles.update( filterPrincipalWrapNames( [pFile],[path.join(dirpath,file)] ) )
               if oFiles == {}:
                  raise Exception([{'name':'ACTION::diffPRINCI','msg':'I could not relate your PRINCI with the system: '+princiFile}])
               else:
                  print '        +> found:'
                  for oFile in oFiles: print '           - ',oFile
               # ~~> Save temporarily for subsequent difference
               oriFile = path.splitext(princiFile)[0]+'.original'+path.splitext(princiFile)[1]
               putFileContent(oriFile,[])
               for p in pFiles:
                  if p in oFiles.keys(): addFileContent(oriFile,getFileContent(oFiles[p]))
               # ~~> Process difference and write output into an HTML file
               diff = diffTextFiles(oriFile,princiFile,options)
               remove(oriFile)
               of = open(htmlFile,'wb')
               of.writelines( diff )
               of.close()
               print '       ~> comparison successful ! created: ' + path.basename(htmlFile)
         else:
            raise Exception([{'name':'ACTION::diffPRINCI','msg':'I could not find your PRINCI file: '+princiFile}])
      # ~~> associated PRINCI file
      # TODO: case of coupling with multiple PRINCI files
 
   # ~~ Compile the PRINCI file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   def compilePRINCI(self,cfg,rebuild):
      if not "compile" in self.availacts.split(';'): return
      xref = self.active["xref"]; cfgname = self.active['cfg']
      active = self.dids[xref][cfgname]
      confirmed = False
      # ~~> principal PRINCI file
      value,default = getKeyWord('FICHIER FORTRAN',active['cas'],DICOS[active['dico']]['dico'],DICOS[active['dico']]['frgb'])
      princiFile = ''; princiSafe = ''
      if value != []:       # you do not need to compile the default executable
         princiFile = path.join(active['path'],eval(value[0]))
         if path.exists(princiFile):
            exeFile = path.join(active['safe'],path.splitext(eval(value[0]))[0] + cfg['SYSTEM']['sfx_exe'])
            if not path.exists(exeFile) or cfg['REBUILD'] == 0:
               print '     +> compiling princi file: ' + path.basename(princiFile)
               copyFile(princiFile,active['safe'])
               print '*********copying '+princiFile+' '+active['safe']
               princiSafe = path.join(active['safe'],path.basename(princiFile))
               confirmed = True
         else:
            raise Exception([{'name':'ACTION::compilePRINCI','msg':'I could not find your PRINCI file: '+princiFile}])
      # ~~> associated PRINCI file
      for mod in active["links"]:
         link = active["links"][mod]
         value,default = getKeyWord('FICHIER FORTRAN',link['cas'],DICOS[link['dico']]['dico'],DICOS[link['dico']]['frgb'])
         princiFilePlage = ''
         if value != []:       # you do not need to compile the default executable
            princiFilePlage = path.join(active['path'],eval(value[0]))
            if path.exists(princiFilePlage):
               if princiSafe != '':
                  print '*********adding content of '+path.basename(princiFilePlage)+' to '+princiSafe
                  putFileContent(princiSafe,getFileContent(princiSafe)+['']+getFileContent(princiFilePlage))
               else:
                  print '     +> compiling princi file: ' + path.basename(princiFilePlage)
                  exeFile = path.join(active['safe'],path.splitext(eval(value[0]))[0] + cfg['SYSTEM']['sfx_exe'])
                  princiSafe = path.join(active['safe'],path.basename(princiFilePlage))
                  print '*********copying '+path.basename(princiFilePlage)+ ' ' + active['safe']
                  copyFile(princiFilePlage,active['safe'])
               confirmed = True
            else:
               raise Exception([{'name':'ACTION::compilePRINCI','msg':'I could not find your PRINCI file: '+princiFilePlage}])
      if confirmed:
         try:
            compilePRINCI(princiSafe,active["code"],self.active['cfg'],cfg,self.bypass)
         except Exception as e:
            raise Exception([filterMessage({'name':'ACTION::compilePRINCI'},e,self.bypass)])  # only one item here
         #moveFile(exeFile,active['safe'])
         print '       ~> compilation successful ! created: ' + path.basename(exeFile)
      #else: you may wish to retrieve the executable for later analysis
 
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   #                                              Direct Executions
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
   def runCommand(self,rebuild):
 
      print '    +> executing your command:\n      ', self.active["do"]
      mes = MESSAGES(size=10)
 
      # ~~> copy of inputs
      copyFile(path.join(self.active['path'],self.active["target"]),self.active['safe'])
      for iFile in self.active["deprefs"]: copyFile(path.join(self.active['path'],iFile),self.active['safe'])
 
      # ~~> execute command locally
      os.chdir(self.active['safe'])
      try:
         tail,code = mes.runCmd(self.active["do"],True) #self.bypass)
      except Exception as e:
         raise Exception([filterMessage({'name':'runCommand','msg':'something went wrong when executing you command.'},e,True)])
      if code != 0: raise Exception([{'name':'runCommand','msg':'Could run your command ('+self.active["do"]+').\n      '+tail}])
 
      # ~~> copy of outputs /!\ you are replacing one config by another
      for oFile in self.active["outrefs"]:
         if path.exists(path.join(self.active['safe'],self.active["outrefs"][oFile])):
            try:
               copyFile(path.join(self.active['safe'],self.active["outrefs"][oFile]),self.active['path'])
            except Exception as e:
               raise Exception([filterMessage({'name':'runCommand','msg':'I can see your file '+oFile+': '+self.active["outrefs"][oFile]+'but cannot copy it'},e,True)])
         else: raise Exception([{'name':'runCommand','msg':'I cannot see your output file '+oFile+': '+self.active["outrefs"][oFile]}])
 
# _____                            __________________________________
# ____/ Secondary Class actionGET /_________________________________/
#
# actionGET is to do with loading data in memory for future use.
#
 
class actionGET(ACTION):
 
   availkeys = deepcopy(ACTION.availkeys)
   availkeys.update({ 'type':'' })
 
   def __init__(self,xmlFile,title='',bypass=True):
      ACTION.__init__(self,title,bypass)
      # those you reset
      self.active['path'] = path.dirname(xmlFile)
      # those you need to see in the XML file
      self.active["target"] = None
      self.active["xref"] = None
      self.active["type"] = None
 
   def addCFG(self,cfgname,cfg):
      ACTION.addCFG(self,cfgname,cfg)
      ACTION.updateCFG(self,{ "type": self.active["type"],
         "target":path.join(self.active['path'],self.active["target"]) })
 
# _____                            __________________________________
# ____/ Secondary Class groupPLOT /_________________________________/
#
# groupPLOT is to do with plotting and producing PNG (mainly)
#
 
class groupPLOT(GROUPS):
 
   availkeys = deepcopy(GROUPS.availkeys)
   availkeys.update({ 'path':'','safe':'','cfg':'', "size":'[15;10]',
         "time": '[-1]', "extract": '', "vars": '', 'outFormat': 'png',
         "target": '', "do": '', "rank":'',
         "title": '', "deprefs":'', "outrefs":'', "where":'',
         "type":'', "config": 'distinct' })
   groupkeys = deepcopy(GROUPS.groupkeys)
   groupkeys.update({ "vars":'', "time":'', "extract":'', "config":'' })
   avaylkeys = deepcopy(GROUPS.avaylkeys)
   avaylkeys.update({ "title":'', "target":'', "deco":'' })
 
   def __init__(self,xmlFile,title='',bypass=True):
      GROUPS.__init__(self,title,bypass)
      # those you reset
      self.active['path'] = path.dirname(xmlFile)
 
   def addDraw(self,draw,rank=''):
      GROUPS.addGroup(self,draw)
      if self.dids[self.active['type']][self.tasks["xref"]]['rank'] == '': self.dids[self.active['type']][self.tasks["xref"]]['rank'] = rank
      if self.dids[self.active['type']][self.tasks["xref"]]['rank'] == '': self.dids[self.active['type']][self.tasks["xref"]]['rank'] = '953'
      self.dids[self.active['type']][self.tasks["xref"]]['rank'] = int(self.dids[self.active['type']][self.tasks["xref"]]['rank'])
      #self.active['deco'] = self.tasks["deco"]
 
   def distributeMeta(self,subtask):
      # ~~> distribute decoration
      vars = subtask["vars"].split(';')
      for i in range(len(vars)):
         if ':' not in vars[i]: vars[i] = vars[i] + ':' + self.tasks["deco"]
      subtask["vars"] = ';'.join(vars)
      return subtask
 
   def decolooks(self,deco={},index=0,nametask='layers'):
      # ~~> set default
      GROUPS.decotasks(self,deco,index,nametask)
      # ~~> set the look
      if deco.has_key('look'):
         for key in deco['look'][0].keys():
            self.tasks[nametask][index]['deco'].update({key:deco['look'][0][key]})
 
# _____                           ___________________________________
# ____/ Secondary Class groupGET /__________________________________/
#
class groupGET(GROUPS):
 
   availkeys = deepcopy(GROUPS.availkeys)
   availkeys.update({ 'path':'','safe':'','cfg':'',
         "time": '[-1]', "extract": '', "vars": '',
         'outFormat': 'csv', "target": '', "do": '', "rank":'',
         "title": '', "deprefs":'', "outrefs":'', "where":'',
         "type":'', "config": 'distinct' })
   groupkeys = deepcopy(GROUPS.groupkeys)
   groupkeys.update({ "vars":'', "time":'', "extract":'', "config":'' })
   avaylkeys = deepcopy(GROUPS.avaylkeys)
   avaylkeys.update({ "title":'', "target":'', "deco":'' })
 
   def __init__(self,xmlFile,title='',bypass=True):
      GROUPS.__init__(self,title,bypass)
      # those you reset
      self.active['path'] = path.dirname(xmlFile)
 
   def distributeMeta(self,subtask):
      # ~~> distribute decoration
      vars = subtask["vars"].split(';')
      for i in range(len(vars)):
         if ':' not in vars[i]: vars[i] = vars[i] + ':xyz'   # :xyz is not used
      subtask["vars"] = ';'.join(vars)
      return subtask
 
# _____                           ___________________________________
# ____/ Secondary Class CRITERIA /__________________________________/
#
 
class CRITERIA(GROUPS):
 
   availkeys = deepcopy(GROUPS.availkeys)
   availkeys.update({ 'path':'','safe':'','cfg':'',
         "target": '', "do": '', "rank":'',
         "title": '', "deprefs":'', "outrefs":'', "where":'',
         "type":'', "config": 'distinct' })
   groupkeys = deepcopy(GROUPS.groupkeys)
   groupkeys.update({ "vars":'', "time":'', "extract":'', "config":'' })
   avaylkeys = deepcopy(GROUPS.avaylkeys)
   #avaylkeys.update({ "title":'', "target":'' })
 
   def __init__(self,xmlFile,title='',bypass=True):
      GROUPS.__init__(self,title,bypass)
      # those you reset
      self.active['path'] = path.dirname(xmlFile)
      # ~~~~~~~~~~~~~
      self.variabling = {}; self.conditionning = {}
 
   def addCriteria(self,criteria):
      try:
         i = getXMLKeys(criteria,self.active)
      except Exception as e:
         raise Exception([filterMessage({'name':'ACTION::addCriteria'},e,self.bypass)])  # only one item here
      else:
         self.active = i
      if self.dids.has_key(self.active["xref"]):
         raise Exception([{'name':'CRITERIA::addCriteria','msg':'you are getting me confused, this xref already exists: '+self.active["xref"]}])
      self.dids.update({ self.active["xref"]:{} })
      print '\n    +> Validation Criteria :', self.active["xref"]
      return 
 
   def addCFG(self,cfgname,cfg):
      self.active['cfg'] = cfgname
      self.dids[self.active["xref"]].update( { cfgname: {'variables':{},'condition':{} } } )
 
   def addvariable(self,variable):
      variabling = {"vars": None, "target":None, "path":''}
      cfgname = self.active['cfg']
      try:
         self.variabling = getXMLKeys(variable,variabling)
      except Exception as e:
         raise Exception([filterMessage({'name':'CRITERIA::addvariable'},e,self.bypass)])  # only one item here
 
      self.dids[self.active["xref"]][self.active['cfg']]['variables'].update({self.variabling["vars"]:{}})
      active = self.dids[self.active["xref"]][self.active['cfg']]['variables']
 
      folder,file = self.variabling["target"].split(':')
      pathfolder = path.join(os.getcwd(),folder)
      pathcfg = path.join(pathfolder,cfgname)
      pathfile = path.join(pathcfg,file) 
 
      active[self.variabling["vars"]]['path'] = [pathfile]
      self.variabling['path'] = [pathfile]
      return
 
   def addcondition(self,condition,NBR):
      conditionning = {"do": None, "success":None, "failure":None, "warning":'',
                        "result":[]}
      cfgname = self.active['cfg']
      try:
         self.conditionning = getXMLKeys(condition,conditionning)
      except Exception as e:
         raise Exception([filterMessage({'name':'CRITERIA::addcondition'},e,self.bypass)])  # only one item here
 
      self.dids[self.active["xref"]][self.active['cfg']]['condition'][NBR] = self.conditionning
      return self.conditionning
 
   def updateCFG(self,d): self.dids[self.active["xref"]][self.active['cfg']].update( d )
 
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   #   Available Operations for criteria
   # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
   def compare(self,condition):
      variables = self.dids[self.active["xref"]][self.active['cfg']]['variables']
 
      ######### Success condition ################################
      NameVar1,operator,NameVar2 = condition["success"].split(':')
 
      print '         +> comparing :', NameVar1, '&', NameVar2
 
      if NameVar1.isalpha() == False : var1 = float(NameVar1)
      else :     
         PathVar1 = variables[NameVar1]['path'][0]
         var1 = [] #getVariableCSV(PathVar1,NameVar1)
      if NameVar2.isalpha() == False : var2 = float(NameVar2)
      else :     
         PathVar2 = variables[NameVar2]['path'][0]
         var2 = [] #getVariableCSV(PathVar2,NameVar2)
 
      if operator == 'LE' :
         if var1 <= var2 : condition["result"].append('success')
      elif operator == 'LT' :
         if var1 < var2 : condition["result"].append('success')   
      elif operator == 'GE' :
         if var1 >= var2 : condition["result"].append('success')
      elif operator == 'GT' :
         if var1 > var2 : condition["result"].append('success')
 
 
      ######### Failure condition ################################
      NameVar1,operator,NameVar2 = condition["failure"].split(':')
 
      if NameVar1.isalpha() == False : var1 = float(NameVar1)
      else :     
         PathVar1 = variables[NameVar1]['path'][0]
         var1 = [] #getVariableCSV(PathVar1,NameVar1)
      if NameVar2.isalpha() == False : var2 = float(NameVar2)
      else :     
         PathVar2 = variables[NameVar2]['path'][0]
         var2 = [] #getVariableCSV(PathVar2,NameVar2)
 
      if operator == 'LE' :
         if var1 <= var2 : condition["result"].append('failed')
      elif operator == 'LT' :
         if var1 < var2 : condition["result"].append('failed')   
      elif operator == 'GE' :
         if var1 >= var2 : condition["result"].append('failed')
      elif operator == 'GT' :
         if var1 > var2 : condition["result"].append('failed')   
 
      ######### Warning condition ################################
      if condition["result"] == [] : condition["result"].append('warning')  
 
      return
 
   def CalcL2error(self,task):   
      xref = self.active["xref"]; cfgname = self.active['cfg']
      active = self.dids[xref][cfgname]
      file = self.tasking["target"]
      print '       +> Calculating L2 error :', self.tasking["title"],'\n'
      if self.tasking["reference"] != '':
         file = path.join(self.dids[self.tasking["reference"]][cfgname]['tasks']['safe'],file)
      var1 = self.tasking["ModelData"].lower()
      var2 = self.tasking["ExactData"].lower()
      VarModel,VarExperiment = get2VariablesCSV(file,var1,var2)
      L2error = (la.norm(VarModel-VarExperiment))/(la.norm(VarExperiment))
      columns = [[self.tasking["title"],'None',L2error]]
      file2 = path.join(self.active['safe'], xref +'.csv')
      if path.exists(file2): 
         columns = [[self.tasking["title"],'None',L2error]]
         #addColumnCSV(file2,columns[0])
      else : pass #putDataCSV(file2,columns)
      return


XML Parser Toolbox


def runXML(xmlFile,xmlConfig,bypass):
 
   xcpt = []                            # try all keys for full report
 
   # ~~ Parse xmlFile ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   import xml.etree.ElementTree as XML
   print '... reading XML test specification file: ' + path.basename(xmlFile)
   f = open(xmlFile,'r')
   xmlTree = XML.parse(f)  # may need to try first and report error
   xmlRoot = xmlTree.getroot()
   f.close()
   # ~~ Default Ranking ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   rank = ''
   if "rank" in xmlRoot.keys(): rank = xmlRoot.attrib["rank"]
 
   # ~~ Meta data process ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   #
   #    This needs to be developed further
   #
   title = ""
   dc = groupMETA(xmlFile,title,bypass)
   dc.addGroupType("meta")
   for metaing in xmlRoot.findall("meta"):
 
      # ~~ Step 1. Common check for keys ~~~~~~~~~~~~~~~~~~~~~~~~
      try:
         dc.addGroup(metaing)
      except Exception as e:
         xcpt.append(filterMessage({'name':'runXML','msg':'add meta object to the list'},e,bypass))
         continue   # bypass the rest of the for loop
 
      # ~~ Step 2. Cumul looks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      if len(metaing.findall("look")) > 1:
         xcpt.append({'name':'runXML','msg':'you can only have one look in meta referenced: '+dc.tasks["xref"]})
      if len(metaing.findall("look")) > 0:
         look = metaing.findall("look")[0]
         try:
            dc.addLookTask(look)
         except Exception as e:
            xcpt.append(filterMessage({'name':'runXML','msg':'add look to the list'},e,bypass))
            continue   # bypass the rest of the for loop
      # ~~ Step 2. Cumul metas ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      if len(metaing.findall("data")) > 1:
         xcpt.append({'name':'runXML','msg':'you can only have one data in meta referenced: '+dc.tasks["xref"]})
      if len(metaing.findall("data")) > 0:
         data = metaing.findall("data")[0]
         try:
            dc.addDataTask(data)
         except Exception as e:
            xcpt.append(filterMessage({'name':'runXML','msg':'add meta to the list'},e,bypass))
            continue   # bypass the rest of the for loop
 
      dc.update(dc.tasks)
 
   if xcpt != []: raise Exception({'name':'runXML','msg':'looking at meta in xmlFile: '+xmlFile,'tree':xcpt})
   display = False
 
   # ~~ Main action process ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   #
   #    Whether an action is carried out or not, it is known through:
   #       xmlConfig[cfgname]['options'].todos['act']['todo']
   #    PRINCAS(ACTION) will still be loaded to register various files
   #       for possible subsequent extraction, plotting or analysis
   #    TODO: limit the number of path / safe duplication
   #
   do = actionRUN(xmlFile,title,bypass)
   for action in xmlRoot.findall("action"):
 
      # ~~ Step 1. Common check for keys and driving file ~~~~~~~~~~
      try:
         targetFile = do.addAction(action,rank)
      except Exception as e:
         xcpt.append(filterMessage({'name':'runXML','msg':'add todo to the list'},e,bypass))
         continue    # bypass rest of the loop
      else:
         if not path.isfile(path.join(do.active['path'],targetFile)):
            xcpt.append({'name':'runXML','msg':'could not find your target file'+targetFile})
            continue    # bypass rest of the loop
 
      # ~~ Step 2. Loop over configurations ~~~~~~~~~~~~~~~~~~~~~~~~
      for cfgname in xmlConfig.keys():
         cfg = xmlConfig[cfgname]['cfg']
         do.addCFG(cfgname,cfg) #if not : continue
 
         # ~~> Temper with rank but still gather intelligence
         dodo = True
         rankdo = do.active['rank']
         print '>>',rankdo
         rankdont = xmlConfig[cfgname]['options'].todos['act']['rank']
         if rankdont != rankdo*int( rankdont / rankdo ): dodo = False
         do.updateCFG({'dodo':dodo})
 
         # ~~> Create the safe
         createDirectories(do.active['safe'])
 
         # ~~ Step 3a. Deals with TELEMAC launchers ~~~~~~~~~~~~~~~~
         if do.active["code"] in cfg['MODULES'].keys():
 
            do.availacts = "translate;run;compile;princi"
 
            # ~~> Manage targetFile and other inputs
            casFile = path.join(do.active['path'],targetFile)
            # ~~> Parse DICO File and its IO Files default (only once)
            dicoFile = getDICO(cfg,do.active["code"])
            do.updateCFG({'dico':dicoFile})
            dico = DICOS[dicoFile]['dico']
            frgb = DICOS[dicoFile]['frgb']
            cas = readCAS(scanCAS(casFile),dico,frgb)
            if do.active["ncsize"] != '': cas = setKeyValue('PROCESSEURS PARALLELES',cas,frgb,int(do.active["ncsize"]))
            do.updateCFG({'cas':cas})
            if not checkConsistency(cas,dico,frgb,cfg): continue
            idico = DICOS[dicoFile]['input']
            odico = DICOS[dicoFile]['output']
 
            # ~~> Define config-split storage
            sortieFiles,iFS,oFS = setSafe(casFile,cas,idico,odico,do.active['safe'])   # TODO: look at relative paths
            if sortieFiles != []: do.updateCFG({ 'sortie': sortieFiles })
            do.updateCFG({ 'input':iFS })
            do.updateCFG({ 'output':oFS })
 
            # ~~> Case of coupling
            cplages,defaut = getKeyWord('COUPLING WITH',cas,dico,frgb)
            links = {}
            for cplage in cplages:
               for mod in cfg['MODULES'].keys():
                  if mod in cplage.lower():
                     # ~~> Extract the CAS File name
                     casFilePlage,defaut = getKeyWord(mod.upper()+' STEERING FILE',cas,dico,frgb)
                     if casFilePlage == []: casFilePlage = defaut[0]
                     else: casFilePlage = eval(casFilePlage[0])
                     casFilePlage = path.join(path.dirname(casFile),casFilePlage)
                     if not path.isfile(casFilePlage): raise Exception([{'name':'runCAS','msg':'missing coupling CAS file for '+mod+': '+casFilePlage}])
                     # ~~> Read the DICO File
                     dicoFilePlage = getDICO(cfg,mod)
                     dicoPlage = DICOS[dicoFilePlage]['dico']
                     frgbPlage = DICOS[dicoFilePlage]['frgb']
                     # ~~> Read the coupled CAS File
                     casPlage = readCAS(scanCAS(casFilePlage),dicoPlage,frgbPlage)
                     # ~~> Fill-in the safe
                     idicoPlage = DICOS[dicoFilePlage]['input']
                     odicoPlage = DICOS[dicoFilePlage]['output']
                     sortiePlage,iFSPlage,oFSPlage = setSafe(casFilePlage,casPlage,idicoPlage,odicoPlage,do.active['safe'])   # TODO: look at relative paths
                     links.update({mod:{}})
                     links[mod].update({ 'code':mod, 'target':path.basename(casFilePlage),
                        'cas':casPlage, 'frgb':frgbPlage, 'dico':dicoFilePlage,
                        'iFS':iFSPlage, 'oFS':oFSPlage, 'sortie':sortiePlage })
                     if sortiePlage != []: links[mod].update({ 'sortie':sortiePlage })
            if links != {}: do.updateCFG({ "links":links })
 
            # ~~> Complete all actions
            # options.todos['act']['todo'] takes: translate;run;compile and none
            doable = xmlConfig[cfgname]['options'].todos['act']['todo']
            if doable == '': doable = do.active["do"]
            if doable == '' or doable == 'all': doable = do.availacts
            display = display or xmlConfig[cfgname]['options'].display
 
            # ~~> Action type A. Translate the CAS file
            if "translate" in doable.split(';') and dodo:
               try:
                  # - exchange keywords between dictionaries
                  do.translateCAS(cfg['REBUILD'])
               except Exception as e:
                  xcpt.append(filterMessage({'name':'runXML','msg':'   +> translate'},e,bypass))
 
            # ~~> Action type B. Analysis of the CAS file
            # TODO:
            # - comparison with DEFAULT values of the DICTIONARY
            #if "cas" in doable.split(';') and dodo:
            # - comparison of dictionnaries betwen configurations
            #if "dico" in doable.split(';') and dodo:
 
            # ~~> Action type C. Analysis of the PRINCI file
            if "princi" in doable.split(';') and dodo:
               #try:
                  # - comparison with standard source files
                  specs = Values()
                  setattr(specs,'unified',False)
                  setattr(specs,'ndiff',False)
                  setattr(specs,'html',True)
                  setattr(specs,'ablines',3)
                  setattr(specs,'context',False)
                  do.diffPRINCI(specs,cfg,cfg['REBUILD'])
               #except Exception as e:
               #   xcpt.append(filterMessage({'name':'runXML','msg':'   +> diff(princi)'},e,bypass))
            # TODO: - comparison of subroutines between action items
 
            # ~~> Action type E. Running CAS files
            if "run" in doable.split(';') and dodo:
               try:
                  do.runCAS(xmlConfig[cfgname]['options'],cfg,cfg['REBUILD'])
               except Exception as e:
                  xcpt.append(filterMessage({'name':'runXML','msg':'   +> run'},e,bypass))
 
         # ~~ Step 3b. Deals with execute launchers ~~~~~~~~~~~~~~~~
         elif do.active["code"] == 'exec':
 
            do.availacts = "exec"
 
            # ~~> Complete all actions
            # options.todos['act']['todo'] takes: exec and none
            doable = xmlConfig[cfgname]['options'].todos['act']['todo']
            if doable == '': doable = do.active["code"]
            if doable == '' or doable == 'all': doable = do.availacts
 
            # ~~> Action type E. Running exec
            if "exec" in doable.split(';') and dodo:
               try:
                  # - simply run the exec as stated
                  do.runCommand(cfg['REBUILD'])
               except Exception as e:
                  xcpt.append(filterMessage({'name':'runXML::runCommand','msg':'   +> '+do.active["do"]},e,bypass))
 
   if xcpt != []: raise Exception({'name':'runXML','msg':'looking at actions in xmlFile: '+xmlFile,'tree':xcpt})
 
   # ~~ Load targets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   #
   gt = actionGET(xmlFile,title,bypass)
   for load in xmlRoot.findall("load"):
 
      # ~~ Step 1. Common check for keys and driving file ~~~~~~~~~~
      try:
         targetFile = gt.addAction(load,rank)
      except Exception as e:
         xcpt.append(filterMessage({'name':'runXML','msg':'add load to the list'},e,bypass))
         continue    # bypass rest of the loop
      else:
         if not path.isfile(path.join(gt.active['path'],targetFile)):
            xcpt.append({'name':'runXML','msg':'could not find your target file'+targetFile})
            continue    # bypass rest of the loop
 
      # ~~ Step 2. Loop over configurations ~~~~~~~~~~~~~~~~~~~~~~~~
      for cfgname in xmlConfig.keys():
         cfg = xmlConfig[cfgname]['cfg']
         gt.addCFG(cfgname,cfg)
 
   if xcpt != []: raise Exception({'name':'runXML','msg':'looking at loads in xmlFile: '+xmlFile,'tree':xcpt})
 
   # ~~ Extraction targets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   # did has all the IO references and the latest sortie files
   ex = groupGET(xmlFile,title,bypass)
   for typeSave in ["save1d","save2d","save3d"]:
      ex.addGroupType(typeSave)
      for extracting in xmlRoot.findall(typeSave):
         # ~~ Step 1. Common check for keys ~~~~~~~~~~~~~~~~~~~~~~~~
         try:
            ex.addGroup(extracting)
         except Exception as e:
            xcpt.append(filterMessage({'name':'runXML','msg':'add extract object to the list'},e,bypass))
            continue   # bypass the rest of the for loop
 
         # ~~> Temper with rank but still gather intelligence
         doex = True
         rankdo = ex.dids[typeSave][ex.active['xref']]['rank']
         rankdont = xmlConfig[cfgname]['options'].todos['get']['rank']
         if rankdont != rankdo*int( rankdont / rankdo ): doex = False
         if not doex: continue
 
         # ~~ Step 2. Cumul layers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         for layer in extracting.findall("layer"):
            try:
               index,namex = ex.addSubTask(layer)
               target = ex.tasks[namex][index]["target"]
            except Exception as e:
               xcpt.append(filterMessage({'name':'runXML','msg':'add layer to the list'},e,bypass))
               continue   # bypass the rest of the for loop
 
            # ~~> round up targets and their configurations looking in exes and does
            xref,src = target.split(':')
            if gt.dids.has_key(xref):
               try:
                  findlayer = findTargets(gt.dids[xref],src)
               except Exception as e:
                  xcpt.append(filterMessage({'name':'runXML','msg':'could not find reference to extract within loads: '+xref},e))
                  ex.targetSubTask({},index,namex)
                  continue    # bypass the rest of the for loop
               else : 
                  ex.targetSubTask(findlayer,index,namex)
            elif do.dids.has_key(xref):
               try:
                  findlayer = findTargets(do.dids[xref],src)
               except Exception as e:
                  xcpt.append(filterMessage({'name':'runXML','msg':'could not find reference to extract within actions: '+xref},e))
                  ex.targetSubTask({},index,namex)
                  continue    # bypass the rest of the for loop
               else:
                  ex.targetSubTask(findlayer,index,namex)
            else : xcpt.append({'name':'runXML','msg':'could not find reference to extract the action: '+xref})      
 
         ex.update(ex.tasks)
 
   if xcpt != []: raise Exception({'name':'runXML','msg':'looking at extractions in xmlFile: '+xmlFile,'tree':xcpt})
 
   # ~~ Matrix distribution by extraction types ~~~~~~~~~~~~~~~~~~~~
   for typeSave in ex.dids.keys():
      for xref in ex.dids[typeSave]:
 
         task = ex.dids[typeSave][xref]
         if not task.has_key("layers"): continue
         print '    +> reference: ',xref,' of type ',typeSave
 
         xlayers = ''   # now done with strings as arrays proved to be too challenging
         for layer in task["layers"]:
            if layer['config'] == 'together':
               xys = []
               for x in xlayers.split('|'): xys.append( (x+';'+':'.join( layer['fileName'].keys() )).strip(';') )
               xlayers = '|'.join(xys)
            elif layer['config'] == 'distinct':
               ylayers = layer['fileName'].keys()
               xys = []
               for i in range(len(ylayers)):
                  for x in xlayers.split('|'): xys.append( (x+';'+ylayers[i]).strip(';') )
               xlayers = '|'.join(xys)
            elif layer['config'] == 'oneofall':
               xys = []; cfg = layer['fileName'].keys()[0]     #/!\ you are sure to have at least one (?)
               for x in xlayers.split('|'): xys.append( (x+';'+cfg).strip(';') )
               xlayers = '|'.join(xys)
            else:
               if layer['config'] in layer['fileName'].keys():
                  xys = []
                  for x in xlayers.split('|'): xys.append( (x+';'+layer['config']).strip(';') )
               xlayers = '|'.join(xys)
 
         nbFile = 0; alayers = xlayers.split('|')
         for cfglist in alayers:
            # ~~> Figure name
            if len(alayers) == 1:
               extractName = '.'.join([xref.replace(' ','_'),task['outFormat']])
            else:
               nbFile += 1
               extractName = '.'.join([xref.replace(' ','_'),str(nbFile),task['outFormat']])
            print '       ~> saved as: ',extractName
            extractName = path.join(path.dirname(xmlFile),extractName)
            # ~~> Create Figure
            if typeSave == "save1d": figure = Figure1D(typeSave,task,extractName)
            if typeSave == "save2d": figure = Figure2D(typeSave,task,extractName)
 
            for layer,cfgs in zip(task["layers"],cfglist.split(';')):
               for cfg in cfgs.split(':'):
                  for file in layer['fileName'][cfg][0]:
                     figure.draw( layer['fileName'][cfg][2], { 'file': file,
                        'deco': {},
                        'vars': layer["vars"], 'extract':parseArrayPaires(layer["extract"]),
                        'type': task['type'], 'time':parseArrayPaires(layer["time"])[0] } )
 
            figure.dump()
 
   if xcpt != []: raise Exception({'name':'runXML','msg':'looking at savings in xmlFile: '+xmlFile,'tree':xcpt})
 
   """      if "L2error" in doaddtask["do"]:
               os.chdir(racine)
               try:
                  ex.CalcL2error(doaddtask)
               except Exception as e:
                  xcpt.append(filterMessage({'name':'runXML','msg':'   +> CalcL2error'},e,bypass))"""
 
   # ~~ Gathering targets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   plot = groupPLOT(xmlFile,title,bypass)
   for typePlot in ["plot1d","plot2d","plot3d","plotpv"]:
      plot.addGroupType(typePlot)
      for ploting in xmlRoot.findall(typePlot):
         # ~~ Step 1. Common check for keys ~~~~~~~~~~~~~~~~~~~~~~~~
         try:
            plot.addDraw(ploting,rank)
         except Exception as e:
            xcpt.append(filterMessage({'name':'runXML','msg':'add plot to the list'},e,bypass))
            continue   # bypass the rest of the for loop
 
         # ~~> Temper with rank but still gather intelligence
         doplt = True
         rankdo = plot.dids[typePlot][plot.active['xref']]['rank']
         rankdont = xmlConfig[cfgname]['options'].todos['draw']['rank']
         if rankdont != rankdo*int( rankdont / rankdo ): doplt = False
         if not doplt: continue
 
         # ~~ Step 2. Cumul layers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         for layer in ploting.findall("layer"):
            try:
               index,namex = plot.addSubTask(layer)
               target = plot.tasks[namex][index]["target"]
            except Exception as e:
               xcpt.append(filterMessage({'name':'runXML','msg':'add layer to the list'},e,bypass))
               continue   # bypass the rest of the for loop
 
            # ~~> round up targets and their configurations looking in exes and does
            xref,src = target.split(':')
            if gt.dids.has_key(xref):
               try:
                  findlayer = findTargets(gt.dids[xref],src)
               except Exception as e:
                  xcpt.append(filterMessage({'name':'runXML','msg':'could not find reference to draw the load: '+xref},e))
                  plot.targetSubTask({})
                  continue    # bypass the rest of the for loop
               else : 
                  plot.targetSubTask(findlayer)
            elif ex.dids.has_key(xref):
               try:
                  findlayer = findTargets(ex.dids[xref],src)
               except Exception as e:
                  xcpt.append(filterMessage({'name':'runXML','msg':'could not find reference to draw the extract: '+xref},e))
                  plot.targetSubTask({})
                  continue    # bypass the rest of the for loop
               else : 
                  plot.targetSubTask(findlayer)
            elif do.dids.has_key(xref):
               try:
                  findlayer = findTargets(do.dids[xref],src)
               except Exception as e:
                  xcpt.append(filterMessage({'name':'runXML','msg':'could not find reference to draw the action: '+xref},e))
                  plot.targetSubTask({})
                  continue    # bypass the rest of the for loop
               else:
                  plot.targetSubTask(findlayer)
            else : xcpt.append({'name':'runXML','msg':'could not find reference to draw the action: '+xref})
 
            # ~~> round up decos
            if dc.dids['meta'].has_key(plot.tasks[namex][index]['deco']):
               plot.decolooks(dc.dids['meta'][plot.tasks[namex][index]['deco']],index,namex)
            else: plot.decolooks({},index,namex)
 
         plot.update(plot.tasks)
 
   if xcpt != []: raise Exception({'name':'runXML','msg':'looking at targets in xmlFile: '+xmlFile,'tree':xcpt})
 
   # ~~ Matrix distribution by plot types ~~~~~~~~~~~~~~~~~~~~~~~~~~
   # /!\ configurations cannot be called "together" or "distinct" or "oneofall"
   for typePlot in plot.dids.keys():
 
      for xref in plot.dids[typePlot]:
 
         draw = plot.dids[typePlot][xref]
         if not draw.has_key("layers"): continue
         print '    +> reference: ',xref,' of type ',typePlot
 
         xlayers = ''   # now done with strings as arrays proved to be too challenging
         for layer in draw["layers"]:
            if layer['config'] == 'together':
               xys = []
               for x in xlayers.split('|'): xys.append( (x+';'+':'.join( layer['fileName'].keys() )).strip(';') )
               xlayers = '|'.join(xys)
            elif layer['config'] == 'distinct':
               ylayers = layer['fileName'].keys()
               xys = []
               for i in range(len(ylayers)):
                  for x in xlayers.split('|'): xys.append( (x+';'+ylayers[i]).strip(';') )
               xlayers = '|'.join(xys)
            elif layer['config'] == 'oneofall':
               xys = []; cfg = layer['fileName'].keys()[0]     #/!\ you are sure to have at least one (?)
               for x in xlayers.split('|'): xys.append( (x+';'+cfg).strip(';') )
               xlayers = '|'.join(xys)
            else:
               if layer['config'] in layer['fileName'].keys():
                  xys = []
                  for x in xlayers.split('|'): xys.append( (x+';'+layer['config']).strip(';') )
               xlayers = '|'.join(xys)
         if xlayers == '':
            xcpt.append(filterMessage({'name':'runXML','msg':'could not find reference to draw the action: '+xref},e))
            continue
 
         nbFile = 0; alayers = xlayers.split('|')
         for cfglist in alayers:
            # ~~> Figure name
            if len(alayers) == 1:
               figureName = '.'.join([xref.replace(' ','_'),draw['outFormat']])
            else:
               nbFile += 1
               figureName = '.'.join([xref.replace(' ','_'),str(nbFile),draw['outFormat']])
            print '       ~> saved as: ',figureName
            figureName = path.join(path.dirname(xmlFile),figureName)
            # ~~> Figure size
            draw["size"] = parseArrayPaires(draw["size"])
            # ~~> Create Figure
            if typePlot == "plot1d": figure = Figure1D(typePlot,draw,figureName,display)
            if typePlot == "plot2d": figure = Figure2D(typePlot,draw,figureName,display)
            # ~~> User Deco taken from 'look'
            if layer['deco'].has_key('look'):
               for key in layer['deco']['look'][0]: layer['deco'].update({key:layer['deco']['look'][0][key]})
 
            for layer,cfgs in zip(draw["layers"],cfglist.split(';')):
               for cfg in cfgs.split(':'):
                  for file in layer['fileName'][cfg][0]:
                     figure.draw( layer['fileName'][cfg][2], { 'file': file,
                        'deco': layer["deco"],
                        'vars': layer["vars"], 'extract':parseArrayPaires(layer["extract"]),
                        'type': draw['type'], 'time':parseArrayPaires(layer["time"])[0] } )
 
            figure.show()
 
   if xcpt != []: raise Exception({'name':'runXML','msg':'looking at plotting in xmlFile: '+xmlFile,'tree':xcpt})
 
   # ~~ Validation Criteria ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   #
   racine = path.split(xmlFile)[0]
   os.chdir(racine)
   docriteria = CRITERIA(xmlFile,title,bypass)
   for criteria in xmlRoot.findall("criteria"):
 
  # ~~ Step 1. Common check for keys ~~~~~~~~~~~~~~~~~~~~~~~~~~~
      try:
         doadd = docriteria.addCriteria(criteria)
      except Exception as e:
         xcpt.append(filterMessage({'name':'runXML','msg':'add todo to the list'},e,bypass))
         continue
 
      # ~~> Temper with rank but still gather intelligence
      docrt = True
      rankdo = docriteria.dids['?'][docriteria.active['xref']]['rank']
      rankdont = xmlConfig[cfgname]['options'].todos['test']['rank']
      if rankdont != rankdo*int( rankdont / rankdo ): docrt = False
      if not docrt: continue
 
      for cfgname in xmlConfig.keys():
         criteriacfg = xmlConfig[cfgname]['cfg']
         docriteria.addCFG(cfgname,criteriacfg) #if not : continue
 
         for vars in criteria.findall("variable"):
            try:
               doaddvariable = docriteria.addvariable(vars)
            except Exception as e:
               xcpt.append(filterMessage({'name':'runXML','msg':'add todo to the list'},e,bypass))
               continue
 
         conditionNBR = 1
         for condition in criteria.findall("condition"):               
            try:
               doaddcondition = docriteria.addcondition(condition,conditionNBR)
               conditionNBR += 1
            except Exception as e:
               xcpt.append(filterMessage({'name':'runXML','msg':'add todo to the list'},e,bypass))
               continue  
 
            if "compare" in doaddcondition["do"]:
               try:
                  docriteria.compare(doaddcondition)
               except Exception as e:
                  xcpt.append(filterMessage({'name':'runXML','msg':'   +> compare'},e,bypass))
 
 
      for criteria in docriteria.dids.keys() :        
         for cfg in docriteria.dids[criteria]:
            for NBR in docriteria.dids[criteria][cfg]['condition']:
               if docriteria.dids[criteria][cfg]['condition'][NBR]['result'][0] == 'success' : continue
               else :
                  if docriteria.dids[criteria][cfg]['condition'][NBR]['result'][0] == 'warning' :
                     print '\n!!!!!  Warning about the follwing condition %s !!!!!!!!\n' % docriteria.dids[criteria][cfg]['condition'][NBR]['success']
                  else :
                     #raise Exception([{'name':'CRITERIA','msg':'the following criteria failed: '+criteria}])
                     raise Exception([{'name':'CRITERIA','msg':'the following condition failed: '+docriteria.dids[criteria][cfg]['condition'][NBR]['success']}])
 
 
   # ~~ Error management ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   if xcpt != []:  # raise full report
      raise Exception({'name':'runXML','msg':'in xmlFile: '+xmlFile,'tree':xcpt})
 
   return