CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_6_1_1/src/Alignment/OfflineValidation/scripts/validateAlignments.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #test execute: export CMSSW_BASE=/tmp/CMSSW && ./validateAlignments.py -c defaultCRAFTValidation.ini,test.ini -n -N test
00003 import os
00004 import sys
00005 import ConfigParser
00006 import optparse
00007 import datetime
00008 from pprint import pprint
00009 import shutil
00010 
00011 import configTemplates #BETA as configTemplates
00012 
00013 ####################--- Helpers ---############################
00014 #replaces .oO[id]Oo. by map[id] in target
00015 def replaceByMap(target, map):
00016     result = target
00017     for id in map:
00018         #print "  "+id+": "+map[id]
00019         lifeSaver = 10e3
00020         iteration = 0
00021         while ".oO[" in result and "]Oo." in result:
00022             for id in map:
00023                 result = result.replace(".oO["+id+"]Oo.",map[id])
00024                 iteration += 1
00025             if iteration > lifeSaver:
00026                 problematicLines = ""
00027                 print map.keys()
00028                 for line in result.splitlines():
00029                     if  ".oO[" in result and "]Oo." in line:
00030                         problematicLines += "%s\n"%line
00031                 raise StandardError, "Oh Dear, there seems to be an endless loop in replaceByMap!!\n%s\nrepMap"%problematicLines
00032     return result
00033 
00034 #excute [command] and return output
00035 def getCommandOutput2(command):
00036     child = os.popen(command)
00037     data = child.read()
00038     err = child.close()
00039     if err:
00040         raise RuntimeError, '%s failed w/ exit code %d' % (command, err)
00041     return data
00042 
00043 #check if a directory exsits on castor
00044 def castorDirExists(path):
00045     if path[-1] == "/":
00046         path = path[:-1]
00047     containingPath = os.path.join( *path.split("/")[:-1] )
00048     dirInQuestion = path.split("/")[-1]
00049     try:
00050         rawLines =getCommandOutput2("rfdir /"+containingPath).splitlines()
00051     except RuntimeError:
00052         return False
00053     for line in rawLines:
00054         if line.split()[0][0] == "d":
00055             if line.split()[8] == dirInQuestion:
00056                 return True
00057     return False
00058 
00059 ####################--- Classes ---############################
00060 class BetterConfigParser(ConfigParser.ConfigParser):
00061     def optionxform(self, optionstr):
00062         return optionstr
00063     
00064     def exists( self, section, option):
00065         try:
00066             items = self.items(section) 
00067         except ConfigParser.NoSectionError:
00068             return False
00069         for item in items:
00070             if item[0] == option:
00071                 return True
00072         return False
00073         
00074     def __updateDict( self, dictionary, section ):
00075         result = dictionary
00076         try:
00077             for option in self.options( section ):
00078                 result[option] = self.get( section, option )
00079             if "local"+section.title() in self.sections():
00080                 for option in self.options( "local"+section.title() ):
00081                     result[option] = self.get( "local"+section.title(),
00082                                                    option )
00083         except ConfigParser.NoSectionError, section:
00084             raise StandardError, ("%s in configuration files. This section is "
00085                                   "mandatory."
00086                                   %( str( section ).replace( ":", "", 1 ) ) )
00087         return result
00088 
00089     def getResultingSection( self, section, defaultDict = {}, demandPars = [] ):
00090         result = defaultDict
00091         for option in demandPars:
00092             try:
00093                 result[option] = self.get( section, option )
00094             except ConfigParser.NoOptionError, globalSectionError:
00095                 globalSection = str( globalSectionError ).split( "'" )[-2]
00096                 splittedSectionName = section.split( ":" )
00097                 if len( splittedSectionName ) > 1:
00098                     localSection = ("local"+section.split( ":" )[0].title()+":"
00099                                     +section.split(":")[1])
00100                 else:
00101                     localSection = ("local"+section.split( ":" )[0].title())
00102                 if self.has_section( localSection ):
00103                     try:
00104                         result[option] = self.get( localSection, option )
00105                     except ConfigParser.NoOptionError, option:
00106                         raise StandardError, ("%s. This option is mandatory."
00107                                               %( str( option )\
00108                                                  .replace( ":", "", 1 )\
00109                                                  .replace( "section", "section '"\
00110                                                            +globalSection+"' or", 1 )
00111                                                  )
00112                                               )
00113                 else:
00114                     raise StandardError, ("%s. This option is mandatory."
00115                                           %( str( globalSectionError )\
00116                                                  .replace( ":", "", 1 )
00117                                              )
00118                                           )
00119         result = self.__updateDict( result, section )
00120         return result
00121 
00122     def getAlignments( self ):
00123         alignments = []
00124         for section in self.sections():
00125             if "alignment:" in section:
00126                 alignments.append( Alignment( section.split( "alignment:" )[1],
00127                                               self ) )
00128         return alignments
00129 
00130     def getCompares( self ):
00131         compares = {}
00132         for section in self.sections():
00133             if "compare:" in section:
00134                 levels = self.get( section, "levels" )
00135                 dbOutput = self.get( section, "dbOutput" )
00136                 compares[section.split(":")[1]] = ( levels, dbOutput )
00137         return compares
00138 
00139     def getGeneral( self ):
00140         defaults = {
00141             "jobmode":"interactive",
00142             "workdir":os.getcwd(),
00143             "datadir":os.getcwd(),
00144             "logdir":os.getcwd()
00145             }
00146         general = self.getResultingSection( "general", defaultDict = defaults )
00147         return general
00148 
00149 
00150 class Alignment:
00151     def __init__(self, name, config, runGeomComp = "1"):
00152         section = "alignment:%s"%name
00153         if not config.has_section( section ):
00154             raise StandardError, ("section %s not found. Please define the "
00155                                   "alignment!"%section)
00156 
00157         # Check for typos or wrong parameters
00158         knownSimpleParameters = [ 'globaltag', 'style', 'color' ]
00159         knownKeywords = [ 'condition' ]
00160         for option in config.options( section ):
00161             if option in knownSimpleParameters:
00162                 continue
00163             elif option.split()[0] in knownKeywords:
00164                 continue
00165             else:
00166                 raise StandardError, ("Invalid or unknown parameter '%s' in "
00167                                       "section '%s'!")%( option, section )
00168 
00169         self.name = name
00170         self.runGeomComp = runGeomComp
00171         self.globaltag = config.get( section, "globaltag" )
00172         self.conditions = self.__getConditions( config, section )
00173         self.color = config.get(section,"color")
00174         self.style = config.get(section,"style")
00175 
00176         # - removed backward compatibility
00177         # - keep the following lines, until the templates are adjusted
00178         #   to the new syntax
00179         self.dbpath = ""
00180         self.tag = ""
00181         self.errordbpath = "frontier://FrontierProd/CMS_COND_31X_FROM21X"
00182         self.errortag = "TrackerIdealGeometryErrors210_mc"
00183         self.kinksAndBows = ""
00184         self.kbdbpath = ""
00185         self.kbtag = ""
00186         
00187     def __getConditions( self, theConfig, theSection ):
00188         conditions = []
00189         for option in theConfig.options( theSection ):
00190             if option.startswith( "condition " ):
00191                 rcdName = option.split( "condition " )[1]
00192                 condParameters = theConfig.get( theSection, option ).split( "," )
00193                 if len( condParameters ) < 2:
00194                     raise StandardError, ("'%s' is used with too few arguments."
00195                                           "A connect_string and a tag are "
00196                                           "required!"%option)
00197                 if len( condParameters ) < 3:
00198                     condParameters.append( "" )
00199                 conditions.append({"rcdName": rcdName.strip(),
00200                                    "connectString": condParameters[0].strip(),
00201                                    "tagName": condParameters[1].strip(),
00202                                    "labelName": condParameters[2].strip()})
00203         return conditions
00204 
00205     def __testDbExist(self, dbpath):
00206         #FIXME delete return to end train debuging
00207         return
00208         if not dbpath.startswith("sqlite_file:"):
00209             print "WARNING: could not check existence for",dbpath
00210         else:
00211             if not os.path.exists( dbpath.split("sqlite_file:")[1] ):
00212                 raise "could not find file: '%s'"%dbpath.split("sqlite_file:")[1]
00213  
00214     def restrictTo( self, restriction ):
00215         result = []
00216         if not restriction == None:
00217             for mode in self.mode:
00218                 if mode in restriction:
00219                     result.append( mode )
00220             self.mode = result
00221 
00222     def getRepMap( self ):
00223         result = {
00224             "name": self.name,
00225             "dbpath": self.dbpath,
00226             "errordbpath": self.errordbpath,
00227             "tag": self.tag,
00228             "errortag": self.errortag,
00229             "color": self.color,
00230             "style": self.style,
00231             "runGeomComp": self.runGeomComp,
00232             "kinksAndBows": self.kinksAndBows,
00233             "kbdbpath": self.kbdbpath,
00234             "kbtag": self.kbtag,
00235             "GlobalTag": self.globaltag
00236             }
00237         return result  
00238 
00239     def getLoadTemplate(self):
00240         """This function still exists only for historical reasons.
00241            Will be removed, when the templates are adjusted.
00242            """
00243         return ""
00244 
00245     def getAPETemplate(self):
00246         """This function still exists only for historical reasons.
00247            Will be removed, when the templates are adjusted.
00248            """
00249         return ""
00250 
00251     def getConditions(self):
00252         """This function creates the configuration snippet to override
00253            global tag conditions.
00254            """
00255         if len( self.conditions ):
00256             loadCond = ("\nimport CalibTracker.Configuration."
00257                         "Common.PoolDBESSource_cfi\n")
00258             for cond in self.conditions:
00259                 if not cond["labelName"] == "":
00260                     temp = configTemplates.conditionsTemplate.replace(
00261                         "tag = cms.string('.oO[tagName]Oo.')",
00262                         ("tag = cms.string('.oO[tagName]Oo.'),"
00263                          "\nlabel = cms.untracked.string('.oO[labelName]Oo.')"))
00264                 else:    
00265                     temp = configTemplates.conditionsTemplate
00266                 loadCond += replaceByMap( temp, cond )
00267         else:
00268             loadCond = ""
00269         return loadCond
00270 
00271 
00272 class GenericValidation:
00273     defaultReferenceName = "DEFAULT"
00274     def __init__(self, valName, alignment, config):
00275         import random
00276         self.name = valName
00277         self.alignmentToValidate = alignment
00278         self.general = config.getGeneral()
00279         self.randomWorkdirPart = "%0i"%random.randint(1,10e9)
00280         self.configFiles = []
00281         self.filesToCompare = {}
00282         self.jobmode = self.general["jobmode"]
00283 
00284     def getRepMap(self, alignment = None):
00285         if alignment == None:
00286             alignment = self.alignmentToValidate
00287         result = alignment.getRepMap()
00288         result.update( self.general )
00289         result.update({
00290                 "workdir": os.path.join( self.general["workdir"],
00291                                          self.randomWorkdirPart ),
00292                 "datadir": self.general["datadir"],
00293                 "logdir": self.general["logdir"],
00294                 "dbLoad": alignment.getLoadTemplate(),
00295                 "APE": alignment.getAPETemplate(),
00296                 "CommandLineTemplate": ("#run configfile and post-proccess it\n"
00297                                         "cmsRun %(cfgFile)s\n"
00298                                         "%(postProcess)s "),
00299                 "CMSSW_BASE": os.environ['CMSSW_BASE'],
00300                 "SCRAM_ARCH": os.environ['SCRAM_ARCH'],
00301                 "alignmentName": alignment.name,
00302                 "condLoad": alignment.getConditions()
00303                 })
00304         return result
00305 
00306     def getCompareStrings( self, requestId = None ):
00307         result = {}
00308         repMap = self.alignmentToValidate.getRepMap()
00309         for validationId in self.filesToCompare:
00310             repMap["file"] = self.filesToCompare[ validationId ]
00311             if repMap["file"].startswith( "/castor/" ):
00312                 repMap["file"] = "rfio:%(file)s"%repMap
00313             result[ validationId ]=  "%(file)s=%(name)s|%(color)s|%(style)s"%repMap 
00314         if requestId == None:
00315             return result
00316         else:
00317             if not "." in requestId:
00318                 requestId += ".%s"%GenericValidation.defaultReferenceName
00319             if not requestId.split(".")[-1] in result:
00320                 raise StandardError, "could not find %s in reference Objects!"%requestId.split(".")[-1]
00321             return result[ requestId.split(".")[-1] ]
00322 
00323     def createFiles( self, fileContents, path ):
00324         result = []
00325         for fileName in fileContents:
00326             filePath = os.path.join( path, fileName)
00327             theFile = open( filePath, "w" )
00328             theFile.write( fileContents[ fileName ] )
00329             theFile.close()
00330             result.append( filePath )
00331         return result
00332 
00333     def createConfiguration(self, fileContents, path, schedule= None):
00334         self.configFiles = GenericValidation.createFiles( self, fileContents, path ) 
00335         if not schedule == None:
00336             schedule = [  os.path.join( path, cfgName) for cfgName in schedule]
00337             for cfgName in schedule:
00338                 if not cfgName in self.configFiles:
00339                     raise StandardError, "scheduled %s missing in generated configfiles: %s"% (cfgName, self.configFiles)
00340             for cfgName in self.configFiles:
00341                 if not cfgName in schedule:
00342                     raise StandardError, "generated configuration %s not scheduled: %s"% (cfgName, schedule)
00343             self.configFiles = schedule
00344         return self.configFiles
00345 
00346     def createScript(self, fileContents, path, downloadFiles=[] ):        
00347         self.scriptFiles =  GenericValidation.createFiles( self, fileContents, path )
00348         for script in self.scriptFiles:
00349             os.chmod(script,0755)
00350         return self.scriptFiles
00351 
00352     def createCrabCfg(self, fileContents, path ):        
00353         self.crabConfigurationFiles =  GenericValidation.createFiles( self, fileContents, path )
00354         return self.crabConfigurationFiles
00355 
00356     
00357 class GeometryComparison(GenericValidation):
00358     """
00359 object representing a geometry comparison job
00360 alignemnt is the alignment to analyse
00361 config is the overall configuration
00362 copyImages indicates wether plot*.eps files should be copied back from the farm
00363 """
00364     def __init__( self, valName, alignment, referenceAlignment,
00365                   config, copyImages = True, randomWorkdirPart = None):
00366         GenericValidation.__init__(self, valName, alignment, config)
00367         if not randomWorkdirPart == None:
00368             self.randomWorkdirPart = randomWorkdirPart
00369         self.referenceAlignment = referenceAlignment
00370         try:
00371             self.jobmode = config.get( "compare:"+self.name, "jobmode" )
00372         except ConfigParser.NoOptionError:
00373             pass
00374         referenceName = "IDEAL"
00375         if not self.referenceAlignment == "IDEAL":
00376             referenceName = self.referenceAlignment.name
00377 
00378         allCompares = config.getCompares()
00379         self.__compares = {}
00380         if valName in allCompares:
00381             self.__compares[valName] = allCompares[valName]
00382         else:
00383             raise StandardError, "Could not find compare section '%s' in '%s'"%(valName, allCompares)
00384         self.copyImages = copyImages
00385     
00386     def getRepMap(self, alignment = None):
00387         if alignment == None:
00388             alignment = self.alignmentToValidate
00389         repMap = GenericValidation.getRepMap( self, alignment )
00390         referenceName = "IDEAL"
00391         if not self.referenceAlignment == "IDEAL":
00392             referenceName = self.referenceAlignment.name
00393         
00394         repMap.update({
00395             "comparedGeometry": (".oO[workdir]Oo./.oO[alignmentName]Oo."
00396                                  "ROOTGeometry.root"),
00397             "referenceGeometry": "IDEAL", # will be replaced later
00398                                           #  if not compared to IDEAL
00399             "reference": referenceName
00400             })
00401         if not referenceName == "IDEAL":
00402             repMap["referenceGeometry"] = (".oO[workdir]Oo./.oO[reference]Oo."
00403                                            "ROOTGeometry.root")
00404         repMap["name"] += "_vs_.oO[reference]Oo."
00405         return repMap
00406 
00407     def createConfiguration(self, path ):
00408         # self.__compares
00409         repMap = self.getRepMap()
00410         cfgs = { "TkAlCompareToNTuple.%s.%s_cfg.py"%(
00411             self.alignmentToValidate.name, self.randomWorkdirPart ):
00412                 replaceByMap( configTemplates.intoNTuplesTemplate, repMap)}
00413         if not self.referenceAlignment == "IDEAL":
00414             referenceRepMap = self.getRepMap( self.referenceAlignment )
00415             cfgFileName = "TkAlCompareToNTuple.%s.%s_cfg.py"%(
00416                 self.referenceAlignment.name, self.randomWorkdirPart )
00417             cfgs[ cfgFileName ] = replaceByMap( configTemplates.intoNTuplesTemplate, referenceRepMap)
00418 
00419         cfgSchedule = cfgs.keys()
00420         for common in self.__compares:
00421             repMap.update({"common": common,
00422                            "levels": self.__compares[common][0],
00423                            "dbOutput": self.__compares[common][1]
00424                            })
00425             if self.__compares[common][1].split()[0] == "true":
00426                 repMap["dbOutputService"] = configTemplates.dbOutputTemplate
00427             else:
00428                 repMap["dbOutputService"] = ""
00429             cfgName = replaceByMap("TkAlCompareCommon.oO[common]Oo...oO[name]Oo._cfg.py",repMap)
00430             cfgs[ cfgName ] = replaceByMap(configTemplates.compareTemplate, repMap)
00431             
00432             cfgSchedule.append( cfgName )
00433         GenericValidation.createConfiguration(self, cfgs, path, cfgSchedule)
00434 
00435     def createScript(self, path):    
00436         repMap = self.getRepMap()    
00437         repMap["runComparisonScripts"] = ""
00438         scriptName = replaceByMap( "TkAlGeomCompare.%s..oO[name]Oo..sh"%( self.name ),
00439                                    repMap)
00440         for name in self.__compares:
00441             if  '"DetUnit"' in self.__compares[name][0].split(","):
00442                 repMap["runComparisonScripts"] += "root -b -q 'comparisonScript.C(\".oO[workdir]Oo./.oO[name]Oo..Comparison_common"+name+".root\",\".oO[workdir]Oo./\")'\n"
00443                 if  self.copyImages:
00444                    repMap["runComparisonScripts"] += "rfmkdir -p .oO[datadir]Oo./.oO[name]Oo..Comparison_common"+name+"_Images\n"
00445                    repMap["runComparisonScripts"] += "find .oO[workdir]Oo. -maxdepth 1 -name \"plot*.eps\" -print | xargs -I {} bash -c \"rfcp {} .oO[datadir]Oo./.oO[name]Oo..Comparison_common"+name+"_Images/\" \n"
00446                    repMap["runComparisonScripts"] += "find .oO[workdir]Oo. -maxdepth 1 -name \"plot*.pdf\" -print | xargs -I {} bash -c \"rfcp {} .oO[datadir]Oo./.oO[name]Oo..Comparison_common"+name+"_Images/\" \n"
00447                    repMap["runComparisonScripts"] += "rfmkdir -p .oO[workdir]Oo./.oO[name]Oo.."+name+"_ArrowPlots\n"
00448                    repMap["runComparisonScripts"] += "root -b -q 'makeArrowPlots.C(\".oO[workdir]Oo./.oO[name]Oo..Comparison_common"+name+".root\",\".oO[workdir]Oo./.oO[name]Oo.."+name+"_ArrowPlots\")'\n"
00449                    repMap["runComparisonScripts"] += "rfmkdir -p .oO[datadir]Oo./.oO[name]Oo..Comparison_common"+name+"_Images/ArrowPlots\n"
00450                    repMap["runComparisonScripts"] += "find .oO[workdir]Oo./.oO[name]Oo.."+name+"_ArrowPlots -maxdepth 1 -name \"*.png\" -print | xargs -I {} bash -c \"rfcp {} .oO[datadir]Oo./.oO[name]Oo..Comparison_common"+name+"_Images/ArrowPlots\"\n"
00451                    
00452                 resultingFile = replaceByMap(".oO[datadir]Oo./compared%s_.oO[name]Oo..root"%name,repMap)
00453                 resultingFile = os.path.expandvars( resultingFile )
00454                 resultingFile = os.path.abspath( resultingFile )
00455                 repMap["runComparisonScripts"] += "rfcp .oO[workdir]Oo./OUTPUT_comparison.root %s\n"%resultingFile
00456                 self.filesToCompare[ name ] = resultingFile
00457                 
00458         repMap["CommandLine"]=""
00459 
00460         for cfg in self.configFiles:
00461             postProcess = "rfcp .oO[workdir]Oo./*.db .oO[datadir]Oo.\n"
00462             repMap["CommandLine"]+= repMap["CommandLineTemplate"]%{"cfgFile":cfg,
00463                                                                    "postProcess":postProcess
00464                                                                    }
00465         repMap["CommandLine"]+= """# overall postprocessing
00466 cd .oO[CMSSW_BASE]Oo./src/Alignment/OfflineValidation/scripts/
00467 .oO[runComparisonScripts]Oo.
00468 cd .oO[workdir]Oo.
00469 """
00470         scripts = {scriptName: replaceByMap( configTemplates.scriptTemplate, repMap ) }  
00471         return GenericValidation.createScript(self, scripts, path)
00472 
00473     def createCrabCfg( self ):
00474         raise StandardError, ("Parallelization not supported for geometry "
00475                               "comparison. Please choose another 'jobmode'.")
00476 
00477         
00478 class OfflineValidation(GenericValidation):
00479     def __init__(self, valName, alignment,config):
00480         GenericValidation.__init__(self, valName, alignment, config)
00481         defaults = {
00482             "DMRMethod":"median",
00483             "DMRMinimum":"30",
00484             "DMROptions":"",
00485             "offlineModuleLevelHistsTransient":"False",
00486             "offlineModuleLevelProfiles":"False",
00487             "OfflineTreeBaseDir":"TrackHitFilter",
00488             "SurfaceShapes":"none",
00489             "jobmode":self.jobmode,
00490             "runRange":"",
00491             "JSON":""
00492             }
00493         mandatories = [ "dataset", "maxevents", "trackcollection" ]
00494         if not config.has_section( "offline:"+self.name ):
00495             offline = config.getResultingSection( "general",
00496                                                   defaultDict = defaults,
00497                                                   demandPars = mandatories )
00498         else:
00499             offline = config.getResultingSection( "offline:"+self.name, 
00500                                                   defaultDict = defaults,
00501                                                   demandPars = mandatories )
00502         self.general.update( offline )
00503         self.jobmode = self.general["jobmode"]
00504     
00505     def createConfiguration(self, path,
00506                             configBaseName = "TkAlOfflineValidation" ):
00507         cfgName = "%s.%s.%s_cfg.py"%( configBaseName, self.name,
00508                                       self.alignmentToValidate.name )
00509         repMap = self.getRepMap()
00510           
00511         cfgs = {cfgName:replaceByMap( configTemplates.offlineTemplate, repMap)}
00512         self.filesToCompare[
00513             GenericValidation.defaultReferenceName ] = repMap["resultFile"]
00514         GenericValidation.createConfiguration(self, cfgs, path)
00515         
00516     def createScript(self, path, scriptBaseName = "TkAlOfflineValidation"):
00517         scriptName = "%s.%s.%s.sh"%( scriptBaseName, self.name,
00518                                      self.alignmentToValidate.name )
00519         repMap = GenericValidation.getRepMap(self)
00520         repMap["CommandLine"]=""
00521         for cfg in self.configFiles:
00522             repMap["CommandLine"]+= repMap["CommandLineTemplate"]%{"cfgFile":cfg,
00523                                                   "postProcess":""
00524                                                   }
00525         scripts = {scriptName: replaceByMap( configTemplates.scriptTemplate,
00526                                              repMap ) }
00527         return GenericValidation.createScript(self, scripts, path)
00528 
00529     def createCrabCfg( self, path,
00530                        crabCfgBaseName = "TkAlOfflineValidation"  ):
00531         crabCfgName = "crab.%s.%s.%s.cfg"%( crabCfgBaseName, self.name,
00532                                             self.alignmentToValidate.name )
00533         repMap = self.getRepMap()
00534         repMap["script"] = "dummy_script.sh"
00535         repMap["crabOutputDir"] = os.path.basename( path )
00536         repMap["crabWorkingDir"] = crabCfgName.split( '.cfg' )[0]
00537         self.crabWorkingDir = repMap["crabWorkingDir"]
00538         repMap["numberOfJobs"] = self.general["parallelJobs"]
00539         repMap["cfgFile"] = self.configFiles[0]
00540         repMap["queue"] = self.jobmode.split( ',' )[1].split( '-q' )[1]
00541         crabCfg = {crabCfgName: replaceByMap( configTemplates.crabCfgTemplate,
00542                                               repMap ) }
00543         return GenericValidation.createCrabCfg( self, crabCfg, path )
00544 
00545     def getRepMap(self, alignment = None):
00546         repMap = GenericValidation.getRepMap(self, alignment)
00547         repMap.update({
00548             "nEvents": self.general["maxevents"],
00549             "outputFile": replaceByMap( (".oO[workdir]Oo./AlignmentValidation_"
00550                                          + self.name +
00551                                          "_.oO[name]Oo..root"), repMap ),
00552             "resultFile": replaceByMap( (".oO[datadir]Oo./AlignmentValidation_"
00553                                          + self.name +
00554                                          "_.oO[name]Oo..root"), repMap ),
00555             "TrackSelectionTemplate": configTemplates.TrackSelectionTemplate,
00556             "LorentzAngleTemplate": configTemplates.LorentzAngleTemplate,
00557             "offlineValidationMode": "Standalone",
00558             "offlineValidationFileOutput":
00559             configTemplates.offlineStandaloneFileOutputTemplate,
00560             # Keep the following parameters for backward compatibility
00561             "TrackCollection": self.general["trackcollection"]
00562             })
00563         repMap["outputFile"] = os.path.expandvars( repMap["outputFile"] )
00564         repMap["outputFile"] = os.path.abspath( repMap["outputFile"] )
00565         repMap["resultFile"] = os.path.expandvars( repMap["resultFile"] )
00566         repMap["resultFile"] = os.path.abspath( repMap["resultFile"] )
00567         if self.jobmode.split( ',' )[0] == "crab":
00568             repMap["outputFile"] = os.path.basename( repMap["outputFile"] )
00569             repMap["resultFile"] = os.path.basename( repMap["resultFile"] )
00570 
00571         return repMap
00572 
00573     def appendToExtendedValidation( self, validationsSoFar = "" ):
00574         """
00575         if no argument or "" is passed a string with an instantiation is
00576         returned, else the validation is appended to the list
00577         """
00578         repMap = self.getRepMap()
00579         if validationsSoFar == "":
00580             validationsSoFar = ('PlotAlignmentValidation p("%(resultFile)s",'
00581                                 '"%(name)s", %(color)s, %(style)s);\n')%repMap
00582         else:
00583             validationsSoFar += ('p.loadFileList("%(resultFile)s", "%(name)s",'
00584                                  '%(color)s, %(style)s);\n')%repMap
00585         return validationsSoFar
00586 
00587     def appendToMerge( self, mergesSoFar = "" ):
00588         """
00589         append all merges here
00590         """
00591         repMap = self.getRepMap()
00592         mergesSoFar += replaceByMap( configTemplates.mergeOfflineParallelResults, repMap )
00593         return mergesSoFar
00594 
00595 class OfflineValidationParallel(OfflineValidation):
00596     def __init__(self, valName, alignment,config):
00597         OfflineValidation.__init__(self, valName, alignment, config)
00598         defaults = {
00599             "parallelJobs":"1",
00600             "jobmode":self.jobmode
00601             }
00602         if not config.has_section( "offline:"+self.name ):
00603             offline = config.getResultingSection( "general",
00604                                                   defaultDict = defaults )
00605         else:
00606             offline = config.getResultingSection( "offline:"+self.name, 
00607                                                   defaultDict = defaults )
00608         self.general.update( offline )
00609         self.__NJobs = self.general["parallelJobs"]
00610 
00611     def createConfiguration(self, path, configBaseName = "TkAlOfflineValidation" ):
00612         # if offline validation uses N parallel jobs, we create here N cfg files
00613         numberParallelJobs = int( self.general["parallelJobs"] )
00614         # limit maximum number of parallel jobs to 40
00615         # (each output file is approximately 20MB)
00616         maximumNumberJobs = 40
00617         if numberParallelJobs > maximumNumberJobs:
00618             raise StandardError, "Maximum allowed number of parallel jobs "+str(maximumNumberJobs)+" exceeded!!!"
00619         # if maxevents is not specified, cannot calculate number of events for each
00620         # parallel job, and therefore running only a single job
00621         if int( self.general["maxevents"] ) == -1:
00622             raise StandardError, "Maximum number of events (maxevents) not specified: cannot use parallel jobs in offline validation"
00623         if numberParallelJobs > 1:    
00624             if self.general["offlineModuleLevelHistsTransient"] == "True":
00625                 raise StandardError, "To be able to merge results when running parallel jobs, set offlineModuleLevelHistsTransient to false."
00626         for index in range(numberParallelJobs):
00627             cfgName = "%s.%s.%s_%s_cfg.py"%( configBaseName, self.name, self.alignmentToValidate.name, str(index) )
00628             repMap = self.getRepMap()
00629             # in this parallel job, skip index*(maxEvents/nJobs) events from the beginning
00630             # (first index is zero, so no skipping for a single job)
00631             # and use _index_ in the name of the output file
00632             repMap.update({"nIndex": str(index)})
00633             # Create the result file directly to datadir since should not use /tmp/
00634             # see https://cern.service-now.com/service-portal/article.do?n=KB0000484
00635             repMap.update({
00636                 "outputFile": replaceByMap( ".oO[datadir]Oo./AlignmentValidation_"
00637                                             + self.name +
00638                                             "_.oO[name]Oo._.oO[nIndex]Oo..root", repMap )
00639                 })
00640             repMap["outputFile"] = os.path.expandvars( repMap["outputFile"] )
00641             repMap["outputFile"] = os.path.abspath( repMap["outputFile"] )
00642 
00643             cfgs = {cfgName:replaceByMap( configTemplates.offlineParallelTemplate, repMap)}
00644             self.filesToCompare[ GenericValidation.defaultReferenceName ] = repMap["resultFile"] 
00645             GenericValidation.createConfiguration(self, cfgs, path)
00646             # here is a small problem. only the last cfgs is saved
00647             # it requires a bit ugly solution later
00648         
00649     def createScript(self, path, scriptBaseName = "TkAlOfflineValidation"):
00650         # A separate script is created for each parallel jobs.
00651         # Since only one cfg is saved a bit ugly solution is needed in the loop.
00652         returnValue = []
00653         numJobs = int( self.general["parallelJobs"] )
00654         for index in range(numJobs):
00655             scriptName = "%s.%s.%s_%s.sh"%(scriptBaseName, self.name, self.alignmentToValidate.name, str(index) )
00656             repMap = GenericValidation.getRepMap(self)
00657             repMap["nIndex"]=""
00658             repMap["nIndex"]=str(index)
00659             repMap["CommandLine"]=""
00660             for cfg in self.configFiles:
00661                 # The ugly solution here is to change the name for each parallel job 
00662                 cfgtemp = cfg.replace( str(numJobs-1)+"_cfg.py" , str(index)+"_cfg.py" )
00663                 repMap["CommandLine"]+= repMap["CommandLineTemplate"]%{"cfgFile":cfgtemp,
00664                                                                        "postProcess":""
00665                                                                        }
00666                 scripts = {scriptName: replaceByMap( configTemplates.parallelScriptTemplate, repMap ) }
00667                 returnValue.extend( GenericValidation.createScript(self, scripts, path) )
00668         return returnValue
00669 
00670     def getRepMap(self, alignment = None):
00671         repMap = OfflineValidation.getRepMap(self, alignment) 
00672         repMap.update({
00673             "nJobs": self.general["parallelJobs"],
00674             "offlineValidationFileOutput":
00675             configTemplates.offlineParallelFileOutputTemplate,
00676             "nameValidation": self.name
00677             })
00678         # In case maxevents==-1, set number of parallel jobs to 1
00679         # since we cannot calculate number of events for each
00680         # parallel job
00681         if str(self.general["maxevents"]) == "-1":
00682             repMap.update({ "nJobs": "1" })
00683         return repMap
00684 
00685     def appendToMergeParJobs( self, validationsSoFar = "" ):
00686         """
00687         if no argument or "" is passed a string with an instantiation is returned, 
00688         else the validation is appended to the list
00689         """
00690         repMap = self.getRepMap()
00691 
00692         parameters = ""
00693         fileToAdd = ""
00694         for index in range(int(self.__NJobs)):
00695             fileToAdd = '%(resultFile)s'%repMap
00696             fileToAdd = fileToAdd.replace('.root','_'+str(index)+'.root')
00697             if index < int( self.general["parallelJobs"] )-1:
00698                 parameters = parameters+fileToAdd+','
00699             else:
00700                 parameters = parameters+fileToAdd                
00701                 
00702         mergedoutputfile = "AlignmentValidation_" + self.name + "_" + '%(name)s'%repMap + ".root"
00703         validationsSoFar += 'hadd("'+parameters+'","'+mergedoutputfile+'");' + "\n"
00704         return validationsSoFar
00705 
00706     def createCrabCfg( self ):
00707         raise StandardError, ("jobmode 'crab' not supported for "
00708                               "'offlineParallel' validation. "
00709                               "Please choose another 'jobmode'.")
00710 
00711 
00712 class OfflineValidationDQM(OfflineValidation):
00713     def __init__(self, valName, alignment, config):
00714         OfflineValidation.__init__(self, valName, alignment, config)
00715         if not config.has_section("DQM"):
00716             raise StandardError, "You need to have a DQM section in your configfile!"
00717         
00718         self.__PrimaryDataset = config.get("DQM", "primaryDataset")
00719         self.__firstRun = int(config.get("DQM", "firstRun"))
00720         self.__lastRun = int(config.get("DQM", "lastRun"))
00721 
00722     def createConfiguration(self, path):
00723         OfflineValidation.createConfiguration(self, path, "TkAlOfflineValidationDQM")
00724         
00725     def createScript(self, path):
00726         return OfflineValidation.createScript(self, path, "TkAlOfflineValidationDQM")
00727 
00728     def getRepMap(self, alignment = None):
00729         repMap = OfflineValidation.getRepMap(self, alignment)
00730         repMap.update({
00731                 "workdir": os.path.expandvars(repMap["workdir"]),
00732                 "offlineValidationMode": "Dqm",
00733                 "offlineValidationFileOutput": configTemplates.offlineDqmFileOutputTemplate,
00734                 "workflow": "/%s/TkAl%s-.oO[alignmentName]Oo._R%09i_R%09i_ValSkim-v1/ALCARECO"%(self.__PrimaryDataset, datetime.datetime.now().strftime("%y"), self.__firstRun, self.__lastRun),
00735                 "firstRunNumber": "%i"% self.__firstRun
00736                 }
00737             )
00738         if "__" in repMap["workflow"]:
00739             raise StandardError, "the DQM workflow specefication must not contain '__'. it is: %s"%repMap["workflow"]
00740         return repMap
00741 
00742 class MonteCarloValidation(GenericValidation):
00743     def __init__(self, valName, alignment, config):
00744         GenericValidation.__init__(self, valName, alignment, config)
00745         defaults = {
00746             "jobmode":self.jobmode,
00747             "runRange":"",
00748             "JSON":""
00749             }
00750         mandatories = [ "relvalsample", "maxevents" ]
00751         if not config.has_section( "mcValidate:"+self.name ):
00752             mcValidate = config.getResultingSection( "general",
00753                                                      defaultDict = defaults,
00754                                                      demandPars = mandatories )
00755         else:
00756             mcValidate = config.getResultingSection( "mcValidate:"+self.name, 
00757                                                      defaultDict = defaults,
00758                                                      demandPars = mandatories )
00759         self.general.update( mcValidate )
00760         self.jobmode = self.general["jobmode"]
00761 
00762     def createConfiguration(self, path ):
00763         cfgName = "TkAlMcValidation.%s.%s_cfg.py"%( self.name,
00764                                                     self.alignmentToValidate.name )
00765         repMap = self.getRepMap()
00766         repMap.update({
00767                 "outputFile": replaceByMap( (".oO[workdir]Oo./McValidation_"
00768                                              + self.name +
00769                                              "_.oO[name]Oo..root"),
00770                                             repMap )
00771                 })
00772         repMap["outputFile"] = os.path.expandvars( repMap["outputFile"] )
00773         repMap["outputFile"] = os.path.abspath( repMap["outputFile"] )
00774         cfgs = {cfgName:replaceByMap( configTemplates.mcValidateTemplate, repMap)}
00775         self.filesToCompare[ GenericValidation.defaultReferenceName ] = repMap["outputFile"]
00776         GenericValidation.createConfiguration(self, cfgs, path)
00777 
00778     def createScript(self, path):
00779         scriptName = "TkAlMcValidate.%s.%s.sh"%( self.name,
00780                                                  self.alignmentToValidate.name )
00781         repMap = self.getRepMap()
00782         repMap["CommandLine"]=""
00783         for cfg in self.configFiles:
00784             repMap["CommandLine"]+= repMap["CommandLineTemplate"]%{"cfgFile":cfg,
00785                                                   "postProcess":""
00786                                                   }
00787 
00788         scripts = {scriptName: replaceByMap( configTemplates.scriptTemplate, repMap ) }
00789         return GenericValidation.createScript(self, scripts, path)
00790 
00791     def createCrabCfg( self, path,
00792                        crabCfgBaseName = "TkAlMcValidate"  ):
00793         crabCfgName = "crab.%s.%s.%s.cfg"%( crabCfgBaseName, self.name,
00794                                             self.alignmentToValidate.name )
00795         repMap = self.getRepMap()
00796         repMap["script"] = "dummy_script.sh"
00797         repMap["crabOutputDir"] = os.path.basename( path )
00798         repMap["crabWorkingDir"] = crabCfgName.split( '.cfg' )[0]
00799         self.crabWorkingDir = repMap["crabWorkingDir"]
00800         repMap["numberOfJobs"] = self.general["parallelJobs"]
00801         repMap["cfgFile"] = self.configFiles[0]
00802         repMap["queue"] = self.jobmode.split( ',' )[1].split( '-q' )[1]
00803         crabCfg = {crabCfgName: replaceByMap( configTemplates.crabCfgTemplate,
00804                                               repMap ) }
00805         return GenericValidation.createCrabCfg( self, crabCfg, path )
00806 
00807     def getRepMap( self, alignment = None ):
00808         repMap = GenericValidation.getRepMap(self, alignment)
00809         repMap.update({ 
00810             "nEvents": self.general["maxevents"],
00811             # Keep the following parameters for backward compatibility
00812             "RelValSample": self.general["relvalsample"]
00813 
00814             })
00815         return repMap
00816 
00817 
00818 class TrackSplittingValidation(GenericValidation):
00819     def __init__(self, valName, alignment, config):
00820         GenericValidation.__init__(self, valName, alignment, config)
00821         defaults = {
00822             "jobmode":self.jobmode,
00823             "runRange":"",
00824             "JSON":""
00825             }
00826         mandatories = [ "trackcollection", "maxevents" ]
00827         if not config.has_section( "split:"+self.name ):
00828             split = config.getResultingSection( "general",
00829                                                 defaultDict = defaults,
00830                                                 demandPars = mandatories )
00831         else:
00832             split = config.getResultingSection( "split:"+self.name, 
00833                                                 defaultDict = defaults,
00834                                                 demandPars = mandatories )
00835         self.general.update( split )
00836         self.jobmode = self.general["jobmode"]
00837 
00838 
00839     def createConfiguration(self, path ):
00840         cfgName = "TkAlTrackSplitting.%s.%s_cfg.py"%( self.name,
00841                                                       self.alignmentToValidate.name )
00842         repMap = self.getRepMap()
00843         repMap.update({
00844                 "outputFile": replaceByMap( (".oO[workdir]Oo./TrackSplitting_"
00845                                              + self.name +
00846                                              "_.oO[name]Oo..root"),
00847                                             repMap )
00848                 })
00849         repMap["outputFile"] = os.path.expandvars( repMap["outputFile"] )
00850         repMap["outputFile"] = os.path.abspath( repMap["outputFile"] )
00851         cfgs = {cfgName:replaceByMap( configTemplates.TrackSplittingTemplate, repMap)}
00852         self.filesToCompare[ GenericValidation.defaultReferenceName ] = repMap["outputFile"]
00853         GenericValidation.createConfiguration(self, cfgs, path)
00854 
00855     def createScript(self, path):
00856         scriptName = "TkAlTrackSplitting.%s.%s.sh"%( self.name,
00857                                                      self.alignmentToValidate.name )
00858         repMap = self.getRepMap()
00859         repMap["CommandLine"]=""
00860         for cfg in self.configFiles:
00861             repMap["CommandLine"]+= repMap["CommandLineTemplate"]%{"cfgFile":cfg,
00862                                                   "postProcess":""
00863                                                   }
00864 
00865         scripts = {scriptName: replaceByMap( configTemplates.scriptTemplate, repMap ) }
00866         return GenericValidation.createScript(self, scripts, path)
00867 
00868     def createCrabCfg( self, path,
00869                        crabCfgBaseName = "TkAlTrackSplitting"  ):
00870         crabCfgName = "crab.%s.%s.%s.cfg"%( crabCfgBaseName, self.name,
00871                                             self.alignmentToValidate.name )
00872         repMap = self.getRepMap()
00873         repMap["script"] = "dummy_script.sh"
00874         repMap["crabOutputDir"] = os.path.basename( path )
00875         repMap["crabWorkingDir"] = crabCfgName.split( '.cfg' )[0]
00876         self.crabWorkingDir = repMap["crabWorkingDir"]
00877         repMap["numberOfJobs"] = self.general["parallelJobs"]
00878         repMap["cfgFile"] = self.configFiles[0]
00879         repMap["queue"] = self.jobmode.split( ',' )[1].split( '-q' )[1]
00880         crabCfg = {crabCfgName: replaceByMap( configTemplates.crabCfgTemplate,
00881                                               repMap ) }
00882         return GenericValidation.createCrabCfg( self, crabCfg, path )
00883 
00884     def getRepMap( self, alignment = None ):
00885         repMap = GenericValidation.getRepMap(self)
00886         # repMap = self.getRepMap()
00887         repMap.update({ 
00888             "nEvents": self.general["maxevents"],
00889             # Keep the following parameters for backward compatibility
00890             "TrackCollection": self.general["trackcollection"]
00891             })
00892         return repMap
00893     
00894     
00895 class ZMuMuValidation(GenericValidation):
00896     def __init__(self, valName, alignment,config):
00897         GenericValidation.__init__(self, valName, alignment, config)
00898         defaults = {
00899             "zmumureference": ("/afs/cern.ch/cms/CAF/CMSALCA/ALCA_TRACKERALIGN2"
00900                                "/TMP_EM/ZMuMu/data/MC/BiasCheck_DYToMuMu_Summer"
00901                                "11_TkAlZMuMu_IDEAL.root"),
00902             "jobmode":self.jobmode,
00903             "runRange":"",
00904             "JSON":""
00905             }
00906         mandatories = [ "dataset", "maxevents", "etamax1", "etamin1", "etamax2",
00907                         "etamin2" ]
00908         if not config.has_section( "zmumu:"+self.name ):
00909             zmumu = config.getResultingSection( "general",
00910                                                   defaultDict = defaults,
00911                                                   demandPars = mandatories )
00912         else:
00913             zmumu = config.getResultingSection( "zmumu:"+self.name, 
00914                                                   defaultDict = defaults,
00915                                                   demandPars = mandatories )
00916         self.general.update( zmumu )
00917         self.jobmode = self.general["jobmode"]
00918     
00919     def createConfiguration(self, path, configBaseName = "TkAlZMuMuValidation" ):
00920         cfgName = "%s.%s.%s_cfg.py"%( configBaseName, self.name,
00921                                       self.alignmentToValidate.name )
00922         repMap = self.getRepMap()
00923         cfgs = {cfgName:replaceByMap( configTemplates.ZMuMuValidationTemplate, repMap)}
00924         GenericValidation.createConfiguration(self, cfgs, path)
00925         
00926     def createScript(self, path, scriptBaseName = "TkAlZMuMuValidation"):
00927         scriptName = "%s.%s.%s.sh"%(scriptBaseName, self.name,
00928                                     self.alignmentToValidate.name )
00929         repMap = self.getRepMap()
00930         repMap["CommandLine"]=""
00931         for cfg in self.configFiles:
00932             repMap["CommandLine"]+= repMap["CommandLineTemplate"]%{"cfgFile":cfg,
00933                                                   "postProcess":""
00934                                                   }
00935         scripts = {scriptName: replaceByMap( configTemplates.zMuMuScriptTemplate, repMap ) }
00936         return GenericValidation.createScript(self, scripts, path)
00937 
00938     def createCrabCfg( self, path,
00939                        crabCfgBaseName = "TkAlZMuMuValidation"  ):
00940         crabCfgName = "crab.%s.%s.%s.cfg"%( crabCfgBaseName, self.name,
00941                                             self.alignmentToValidate.name )
00942         repMap = self.getRepMap()
00943         repMap["script"] = "dummy_script.sh"
00944         repMap["crabOutputDir"] = os.path.basename( path )
00945         repMap["crabWorkingDir"] = crabCfgName.split( '.cfg' )[0]
00946         self.crabWorkingDir = repMap["crabWorkingDir"]
00947         repMap["numberOfJobs"] = self.general["parallelJobs"]
00948         repMap["cfgFile"] = self.configFiles[0]
00949         repMap["queue"] = self.jobmode.split( ',' )[1].split( '-q' )[1]
00950         crabCfg = {crabCfgName: replaceByMap( configTemplates.crabCfgTemplate,
00951                                               repMap ) }
00952         return GenericValidation.createCrabCfg( self, crabCfg, path )
00953 
00954     def getRepMap(self, alignment = None):
00955         repMap = GenericValidation.getRepMap(self, alignment) 
00956         repMap.update({
00957             "nEvents": self.general["maxevents"]
00958                 })
00959         return repMap
00960 
00961 # Needed for more than one geometry comparison for one alignment
00962 alignRandDict = {}
00963 
00964 class ValidationJob:
00965     def __init__( self, validation, config, options ):
00966         if validation[1] == "":
00967             # new intermediate syntax
00968             valString = validation[0].split( "->" )[0]
00969             alignments = validation[0].split( "->" )[1]
00970         else:
00971             # old syntax
00972             valString = validation[0]
00973             alignments = validation[1]
00974         valString = valString.split()
00975         self.__valType = valString[0]
00976         self.__valName = valString[1]
00977         self.__commandLineOptions = options
00978         self.__config = config
00979         # workaround for intermediate parallel version
00980         if self.__valType == "offlineParallel":
00981             section = "offline" + ":" + self.__valName
00982         else:
00983             section = self.__valType + ":" + self.__valName
00984         if not self.__config.has_section( section ):
00985             raise StandardError, ("Validation '%s' of type '%s' is requested in"
00986                                   " '[validation]' section, but is not defined."
00987                                   "\nYou have to add a '[%s]' section."
00988                                   %( self.__valName, self.__valType, section ))
00989         self.validation = self.__getValidation( self.__valType, self.__valName,
00990                                                 alignments, self.__config,
00991                                                 options )
00992 
00993     def __getValidation( self, valType, name, alignments, config, options ):
00994         if valType == "compare":
00995             alignmentsList = alignments.split( "," )
00996             firstAlignList = alignmentsList[0].split()
00997             firstAlignName = firstAlignList[0].strip()
00998             if firstAlignName == "IDEAL":
00999                 raise StandardError, ("'IDEAL' has to be the second (reference)"
01000                                       " alignment in 'compare <val_name>: "
01001                                       "<alignment> <reference>'.")
01002             if len( firstAlignList ) > 1:
01003                 firstRun = firstAlignList[1]
01004             else:
01005                 firstRun = "1"
01006             firstAlign = Alignment( firstAlignName, self.__config, firstRun )
01007             secondAlignList = alignmentsList[1].split()
01008             secondAlignName = secondAlignList[0].strip()
01009             if len( secondAlignList ) > 1:
01010                 secondRun = secondAlignList[1]
01011             else:
01012                 secondRun = "1"
01013             if secondAlignName == "IDEAL":
01014                 secondAlign = secondAlignName
01015             else:
01016                 secondAlign = Alignment( secondAlignName, self.__config,
01017                                          secondRun )
01018             # check if alignment was already compared previously
01019             try:
01020                 randomWorkdirPart = alignRandDict[firstAlignName]
01021             except KeyError:
01022                 randomWorkdirPart = None
01023                 
01024             validation = GeometryComparison( name, firstAlign, secondAlign,
01025                                              self.__config,
01026                                              self.__commandLineOptions.getImages,
01027                                              randomWorkdirPart )
01028             alignRandDict[firstAlignName] = validation.randomWorkdirPart
01029             if not secondAlignName == "IDEAL":
01030                 alignRandDict[secondAlignName] = validation.randomWorkdirPart
01031         elif valType == "offline":
01032             validation = OfflineValidation( name, 
01033                 Alignment( alignments.strip(), self.__config ), self.__config )
01034         elif valType == "offlineDQM":
01035             validation = OfflineValidationDQM( name, 
01036                 Alignment( alignments.strip(), self.__config ), self.__config )
01037         elif valType == "offlineParallel":
01038             validation = OfflineValidationParallel( name, 
01039                 Alignment( alignments.strip(), self.__config ), self.__config )
01040         elif valType == "mcValidate":
01041             validation = MonteCarloValidation( name, 
01042                 Alignment( alignments.strip(), self.__config ), self.__config )
01043         elif valType == "split":
01044             validation = TrackSplittingValidation( name, 
01045                 Alignment( alignments.strip(), self.__config ), self.__config )
01046         elif valType == "zmumu":
01047             validation = ZMuMuValidation( name, 
01048                 Alignment( alignments.strip(), self.__config ), self.__config )
01049         else:
01050             raise StandardError, "Unknown validation mode '%s'"%valType
01051         return validation
01052 
01053     def __createJob( self, jobMode, outpath ):
01054         """This private method creates the needed files for the validation job.
01055            """
01056         self.validation.createConfiguration( outpath )
01057         self.__scripts = self.validation.createScript( outpath )
01058         if jobMode.split( ',' )[0] == "crab":
01059             self.validation.createCrabCfg( outpath )
01060         return None
01061 
01062     def createJob(self):
01063         """This is the method called to create the job files."""
01064         self.__createJob( self.validation.jobmode,
01065                           os.path.abspath( self.__commandLineOptions.Name) )
01066 
01067     def runJob( self ):
01068         general = self.__config.getGeneral()
01069         log = ""
01070         for script in self.__scripts:
01071             name = os.path.splitext( os.path.basename( script) )[0]
01072             if self.__commandLineOptions.dryRun:
01073                 print "%s would run: %s"%( name, os.path.basename( script) )
01074                 continue
01075             log = ">             Validating "+name
01076             print ">             Validating "+name
01077             if self.validation.jobmode == "interactive":
01078                 log += getCommandOutput2( script )
01079             elif self.validation.jobmode.split(",")[0] == "lxBatch":
01080                 repMap = { 
01081                     "commands": self.validation.jobmode.split(",")[1],
01082                     "logDir": general["logdir"],
01083                     "jobName": name,
01084                     "script": script,
01085                     "bsub": "/afs/cern.ch/cms/caf/scripts/cmsbsub"
01086                     }
01087                 log+=getCommandOutput2("%(bsub)s %(commands)s -J %(jobName)s "
01088                                        "-o %(logDir)s/%(jobName)s.stdout -e "
01089                                        "%(logDir)s/%(jobName)s.stderr "
01090                                        "%(script)s"%repMap)
01091             elif self.validation.jobmode.split( "," )[0] == "crab":
01092                 pass
01093             else:
01094                 raise StandardError, ("Unknown 'jobmode'!\n"
01095                                       "Please change this parameter either in "
01096                                       "the [general] or in the ["
01097                                       + self.__valType + ":" + self.__valName
01098                                       + "] section to one of the following "
01099                                       "values:\n"
01100                                       "\tinteractive\n\tlxBatch, -q <queue>\n"
01101                                       "\tcrab, -q <queue>")
01102         return log
01103 
01104     def getValidation( self ):
01105         return self.validation
01106 
01107 
01108 def createCrabScript( path, validations ):
01109     repMap = {"crabCommand": "",
01110               "crabBaseDir": path,
01111               "useCshell": ""
01112               }
01113     for validation in validations:
01114         if validation.jobmode.split( ',' )[0] == 'crab':
01115             valRepMap = {"crabWorkingDir": validation.crabWorkingDir,
01116                          "crabCfgName": validation.crabWorkingDir + ".cfg"
01117                       }
01118             repMap["crabCommand"] += replaceByMap( configTemplates.crabCommandTemplate,
01119                                                    valRepMap )
01120     if len( repMap["crabCommand"] ) == 0:
01121         return None
01122     crabShScriptPath = os.path.join( path, 'TkAlRunCrab.sh' )
01123     crabShScript = open( crabShScriptPath, 'w' )
01124     crabShScript.write( replaceByMap( configTemplates.crabShellScriptTemplate,
01125                                       repMap ) )
01126     crabShScript.close()
01127     repMap["useCshell"] = "c"
01128     crabCshScriptPath = os.path.join( path, 'TkAlRunCrab.csh' )
01129     crabCshScript = open( crabCshScriptPath, 'w' )
01130     crabCshScript.write( replaceByMap( configTemplates.crabShellScriptTemplate,
01131                                        repMap ) )
01132     crabCshScript.close()
01133     return crabShScriptPath, crabCshScriptPath
01134 
01135 def createOfflineJobsMergeScript(offlineValidationList, outFilePath):
01136     repMap = offlineValidationList[0].getRepMap() # bit ugly since some special features are filled
01137     repMap[ "mergeOfflinParJobsInstantiation" ] = "" #give it a "" at first in order to get the initialisation back
01138 
01139     for validation in offlineValidationList:
01140         repMap[ "mergeOfflinParJobsInstantiation" ] = validation.appendToMergeParJobs( repMap[ "mergeOfflinParJobsInstantiation" ] )
01141 #                    validationsSoFar = 'PlotAlignmentValidation p("%(resultFile)s", "%(name)s", %(color)s, %(style)s);\n'%repMap
01142     
01143     theFile = open( outFilePath, "w" )
01144     theFile.write( replaceByMap( configTemplates.mergeOfflineParJobsTemplate ,repMap ) )
01145     theFile.close()
01146 
01147 def createExtendedValidationScript(offlineValidationList, outFilePath):
01148     repMap = offlineValidationList[0].getRepMap() # bit ugly since some special features are filled
01149     repMap[ "extendedInstantiation" ] = "" #give it a "" at first in order to get the initialisation back
01150 
01151     for validation in offlineValidationList:
01152         repMap[ "extendedInstantiation" ] = validation.appendToExtendedValidation( repMap[ "extendedInstantiation" ] )
01153     
01154     theFile = open( outFilePath, "w" )
01155     theFile.write( replaceByMap( configTemplates.extendedValidationTemplate ,repMap ) )
01156     theFile.close()
01157     
01158 def createMergeScript( path, validations ):
01159     if( len(validations) == 0 ):
01160         raise StandardError, "cowardly refusing to merge nothing!"
01161 
01162     repMap = validations[0].getRepMap() #FIXME - not nice this way
01163     repMap.update({
01164             "DownloadData":"",
01165             "CompareAllignments":"",
01166             "RunExtendedOfflineValidation":""
01167             })
01168 
01169     comparisonLists = {} # directory of lists containing the validations that are comparable
01170     for validation in validations:
01171         for referenceName in validation.filesToCompare:
01172             validationName = "%s.%s"%(validation.__class__.__name__, referenceName)
01173             validationName = validationName.split(".%s"%GenericValidation.defaultReferenceName )[0]
01174             if validationName in comparisonLists:
01175                 comparisonLists[ validationName ].append( validation )
01176             else:
01177                 comparisonLists[ validationName ] = [ validation ]
01178 
01179     if "OfflineValidation" in comparisonLists:
01180         repMap["extendeValScriptPath"] = os.path.join(path, "TkAlExtendedOfflineValidation.C")
01181         createExtendedValidationScript( comparisonLists["OfflineValidation"], repMap["extendeValScriptPath"] )
01182         repMap["RunExtendedOfflineValidation"] = replaceByMap(configTemplates.extendedValidationExecution, repMap)
01183 
01184     repMap["CompareAllignments"] = "#run comparisons"
01185     for validationId in comparisonLists:
01186         compareStrings = [ val.getCompareStrings(validationId) for val in comparisonLists[validationId] ]
01187             
01188         repMap.update({"validationId": validationId,
01189                        "compareStrings": " , ".join(compareStrings) })
01190         
01191         repMap["CompareAllignments"] += replaceByMap( configTemplates.compareAlignmentsExecution, repMap )
01192       
01193     filePath = os.path.join(path, "TkAlMerge.sh")
01194     theFile = open( filePath, "w" )
01195     theFile.write( replaceByMap( configTemplates.mergeTemplate, repMap ) )
01196     theFile.close()
01197     os.chmod(filePath,0755)
01198     
01199     return filePath
01200     
01201 def createParallelMergeScript( path, validations ):
01202     if( len(validations) == 0 ):
01203         raise StandardError, "cowardly refusing to merge nothing!"
01204 
01205     repMap = validations[0].getRepMap() #FIXME - not nice this way
01206     repMap.update({
01207             "DownloadData":"",
01208             "CompareAllignments":"",
01209             "RunExtendedOfflineValidation":""
01210             })
01211 
01212     comparisonLists = {} # directory of lists containing the validations that are comparable
01213     for validation in validations:
01214         for referenceName in validation.filesToCompare:    
01215             validationName = "%s.%s"%(validation.__class__.__name__, referenceName)
01216             validationName = validationName.split(".%s"%GenericValidation.defaultReferenceName )[0]
01217             if validationName in comparisonLists:
01218                 comparisonLists[ validationName ].append( validation )
01219             else:
01220                 comparisonLists[ validationName ] = [ validation ]
01221 
01222     if "OfflineValidationParallel" in comparisonLists:
01223         repMap["extendeValScriptPath"] = os.path.join(path, "TkAlExtendedOfflineValidation.C")
01224         createExtendedValidationScript( comparisonLists["OfflineValidationParallel"], repMap["extendeValScriptPath"] )
01225         repMap["mergeOfflineParJobsScriptPath"] = os.path.join(path, "TkAlOfflineJobsMerge.C")
01226         createOfflineJobsMergeScript( comparisonLists["OfflineValidationParallel"], repMap["mergeOfflineParJobsScriptPath"] )
01227         repMap["RunExtendedOfflineValidation"] = replaceByMap(configTemplates.extendedValidationExecution, repMap)
01228         # DownloadData is the section which merges output files from parallel jobs
01229         # it uses the file TkAlOfflineJobsMerge.C
01230         repMap["DownloadData"] += replaceByMap( configTemplates.mergeOfflineParallelResults, repMap )
01231 
01232     repMap["CompareAllignments"] = "#run comparisons"
01233     for validationId in comparisonLists:
01234         compareStrings = [ val.getCompareStrings(validationId) for val in comparisonLists[validationId] ]
01235             
01236         repMap.update({"validationId": validationId,
01237                        "compareStrings": " , ".join(compareStrings) })
01238         
01239         repMap["CompareAllignments"] += replaceByMap( configTemplates.compareAlignmentsExecution, repMap )
01240       
01241     filePath = os.path.join(path, "TkAlMerge.sh")
01242     theFile = open( filePath, "w" )
01243     theFile.write( replaceByMap( configTemplates.mergeTemplate, repMap ) )
01244     theFile.close()
01245     os.chmod(filePath,0755)
01246     
01247     return filePath
01248     
01249 def loadTemplates( config ):
01250     if config.has_section("alternateTemplates"):
01251         for templateName in config.options("alternateTemplates"):
01252             newTemplateName = config.get("alternateTemplates", templateName )
01253             #print "replacing default %s template by %s"%( templateName, newTemplateName)
01254             configTemplates.alternateTemplate(templateName, newTemplateName)
01255     
01256 ####################--- Main ---############################
01257 def main(argv = None):
01258     if argv == None:
01259        argv = sys.argv[1:]
01260     optParser = optparse.OptionParser()
01261     optParser.description = """ all-in-one alignment Validation 
01262     This will run various validation procedures either on batch queues or interactviely. 
01263     
01264     If no name is given (-N parameter) a name containing time and date is created automatically
01265     
01266     To merge the outcome of all validation procedures run TkAlMerge.sh in your validation's directory.
01267     """
01268     optParser.add_option("-n", "--dryRun", dest="dryRun", action="store_true", default=False,
01269                          help="create all scripts and cfg File but do not start jobs (default=False)")
01270     optParser.add_option( "--getImages", dest="getImages", action="store_true", default=False,
01271                           help="get all Images created during the process (default= False)")
01272     optParser.add_option("-c", "--config", dest="config",
01273                          help="configuration to use (default compareConfig.ini) this can be a comma-seperated list of all .ini file you want to merge", metavar="CONFIG")
01274     optParser.add_option("-N", "--Name", dest="Name",
01275                          help="Name of this validation (default: alignmentValidation_DATE_TIME)", metavar="NAME")
01276     optParser.add_option("-r", "--restrictTo", dest="restrictTo",
01277                          help="restrict validations to given modes (comma seperated) (default: no restriction)", metavar="RESTRICTTO")
01278 
01279     (options, args) = optParser.parse_args(argv)
01280 
01281     if not options.restrictTo == None:
01282         options.restrictTo = options.restrictTo.split(",")
01283     if options.config == None:
01284         options.config = "compareConfig.ini"
01285     else:
01286         options.config = options.config.split(",")
01287         result = []
01288         for iniFile in options.config:
01289             result.append( os.path.abspath(iniFile) )
01290         options.config = result
01291     config = BetterConfigParser()
01292     config.read( options.config )
01293 
01294     if options.Name == None:
01295         options.Name = "alignmentValidation_%s"%(datetime.datetime.now().strftime("%y%m%d_%H%M%S"))
01296 
01297     outPath = os.path.abspath( options.Name )
01298     general = config.getGeneral()
01299     config.set("general","workdir",os.path.join(general["workdir"],options.Name) )
01300     config.set("general","datadir",os.path.join(general["datadir"],options.Name) )
01301     config.set("general","logdir",os.path.join(general["logdir"],options.Name) )
01302 
01303     # clean up of log directory to avoid cluttering with files with different
01304     # random numbers for geometry comparison
01305     if os.path.isdir( config.getGeneral()["logdir"] ):
01306         shutil.rmtree( config.getGeneral()["logdir"] )
01307     
01308     if not os.path.exists( outPath ):
01309         os.makedirs( outPath )
01310     elif not os.path.isdir( outPath ):
01311         raise StandardError,"the file %s is in the way rename the Job or move it away"%outPath
01312 
01313     #replace default templates by the once specified in the "alternateTemplates" section
01314     loadTemplates( config )
01315 
01316     #save backup configuration file
01317     backupConfigFile = open( os.path.join( outPath, "usedConfiguration.ini" ) , "w"  )
01318     config.write( backupConfigFile )
01319 
01320     jobs = [ ValidationJob( validation, config, options) \
01321                  for validation in config.items( "validation" ) ]
01322     map( lambda job: job.createJob(), jobs )
01323     validations = [ job.getValidation() for job in jobs ]
01324 
01325     if "OfflineValidationParallel" not in [val.__class__.__name__ for val in validations]:
01326         createMergeScript( outPath, validations )
01327     else:
01328         createParallelMergeScript( outPath, validations )
01329     crabScript = createCrabScript( outPath, validations )
01330     
01331     map( lambda job: job.runJob(), jobs )
01332     if crabScript != None:
01333         print
01334         print "="*80
01335         print "To start parallel validation please type:"
01336         print "source "+outPath+"/TkAlRunCrab.sh"
01337         print "\t<or>"
01338         print "source "+outPath+"/TkAlRunCrab.csh"
01339         print "="*80
01340         print
01341     
01342 
01343 if __name__ == "__main__":        
01344    # main(["-n","-N","test","-c","defaultCRAFTValidation.ini,latestObjects.ini","--getImages"])
01345    main()
01346