3 from __future__
import print_function
12 import Alignment.OfflineValidation.TkAlAllInOneTool.configTemplates \
14 import Alignment.OfflineValidation.TkAlAllInOneTool.crabWrapper
as crabWrapper
15 from Alignment.OfflineValidation.TkAlAllInOneTool.TkAlExceptions \
17 from Alignment.OfflineValidation.TkAlAllInOneTool.helperFunctions \
18 import replaceByMap, getCommandOutput2, addIndex
19 from Alignment.OfflineValidation.TkAlAllInOneTool.betterConfigParser \
20 import BetterConfigParser
21 from Alignment.OfflineValidation.TkAlAllInOneTool.alignment
import Alignment
24 import GenericValidation, ParallelValidation, ValidationWithComparison, ValidationWithPlots
25 from Alignment.OfflineValidation.TkAlAllInOneTool.geometryComparison \
26 import GeometryComparison
28 import OfflineValidation, OfflineValidationDQM
29 from Alignment.OfflineValidation.TkAlAllInOneTool.monteCarloValidation \
30 import MonteCarloValidation
32 import TrackSplittingValidation
34 import ZMuMuValidation
36 import PrimaryVertexValidation
37 from Alignment.OfflineValidation.TkAlAllInOneTool.preexistingValidation \
39 from Alignment.OfflineValidation.TkAlAllInOneTool.plottingOptions \
40 import PlottingOptions
41 import Alignment.OfflineValidation.TkAlAllInOneTool.globalDictionaries \
43 from Alignment.OfflineValidation.TkAlAllInOneTool.overlapValidation \
44 import OverlapValidation
54 if isinstance(dependency,list):
55 self.dependencies.extend(dependency)
57 self.dependencies.append(dependency)
60 "commands": config.getGeneral()[
"jobmode"].
split(
",")[1],
62 "logDir": config.getGeneral()[
"logdir"],
64 "bsub":
"/afs/cern.ch/cms/caf/scripts/cmsbsub",
65 "conditions":
'"' +
" && ".
join([
"ended(" + jobId +
")" for jobId
in self.
dependencies]) +
'"' 69 "-o %(logDir)s/%(jobName)s.stdout " 70 "-e %(logDir)s/%(jobName)s.stderr " 83 def __init__( self, validation, config, options ):
85 if validation[1] ==
"":
87 valString = validation[0].
split(
"->" )[0]
88 alignments = validation[0].
split(
"->" )[1]
90 if "->" in validation[0]:
91 msg = (
"Instead of using the intermediate syntax\n'" 92 +valString.strip()+
"-> "+alignments.strip()
93 +
":'\nyou have to use the now fully supported syntax \n'" 94 +valString.strip()+
": " 95 +alignments.strip()+
"'.")
96 raise AllInOneError(msg)
98 valString = validation[0]
99 alignments = validation[1]
100 valString = valString.split()
112 print (
"offlineParallel and offline are now the same. To run an offline parallel validation,\n" 113 "just set parallelJobs to something > 1. There is no reason to call it offlineParallel anymore.")
116 if not self.__config.has_section( section ):
117 raise AllInOneError(
"Validation '%s' of type '%s' is requested in" 118 " '[validation]' section, but is not defined." 119 "\nYou have to add a '[%s]' section." 126 if valType ==
"compare":
127 alignmentsList = alignments.split(
"," )
128 firstAlignList = alignmentsList[0].
split()
129 firstAlignName = firstAlignList[0].
strip()
130 if firstAlignName ==
"IDEAL":
131 raise AllInOneError(
"'IDEAL' has to be the second (reference)" 132 " alignment in 'compare <val_name>: " 133 "<alignment> <reference>'.")
134 if len( firstAlignList ) > 1:
135 firstRun = firstAlignList[1]
137 raise AllInOneError(
"Have to provide a run number for geometry comparison")
139 firstAlignName = firstAlign.name
140 secondAlignList = alignmentsList[1].
split()
141 secondAlignName = secondAlignList[0].
strip()
142 if secondAlignName ==
"IDEAL":
143 secondAlign = secondAlignName
145 if len( secondAlignList ) > 1:
146 secondRun = secondAlignList[1]
148 raise AllInOneError(
"Have to provide a run number for geometry comparison")
151 secondAlignName = secondAlign.name
153 validation = GeometryComparison( name, firstAlign, secondAlign,
155 self.__commandLineOptions.getImages)
156 elif valType ==
"offline":
157 validation = OfflineValidation( name,
159 elif valType ==
"preexistingoffline":
160 validation = PreexistingOfflineValidation(name, self.
__config)
161 elif valType ==
"offlineDQM":
162 validation = OfflineValidationDQM( name,
164 elif valType ==
"mcValidate":
165 validation = MonteCarloValidation( name,
167 elif valType ==
"preexistingmcValidate":
168 validation = PreexistingMonteCarloValidation(name, self.
__config)
169 elif valType ==
"split":
170 validation = TrackSplittingValidation( name,
172 elif valType ==
"preexistingsplit":
173 validation = PreexistingTrackSplittingValidation(name, self.
__config)
174 elif valType ==
"zmumu":
175 validation = ZMuMuValidation( name,
177 elif valType ==
"primaryvertex":
180 elif valType ==
"preexistingprimaryvertex":
181 validation = PreexistingPrimaryVertexValidation(name, self.
__config)
182 elif valType ==
"overlap":
186 raise AllInOneError(
"Unknown validation mode '%s'"%valType)
191 """This private method creates the needed files for the validation job. 193 self.validation.createConfiguration( outpath )
196 self.
__scripts = sum([
addIndex(script, self.validation.NJobs)
for script
in self.validation.createScript( outpath )], [])
197 if jobMode.split(
',' )[0] ==
"crab":
198 self.validation.createCrabCfg( outpath )
202 """This is the method called to create the job files.""" 204 os.path.abspath( self.__commandLineOptions.Name) )
208 if self.validation.jobid:
209 self.batchJobIds.append(self.validation.jobid)
210 log =
"> " + self.validation.name +
" is already validated." 214 if self.validation.jobid:
215 print(
"jobid {} will be ignored, since the validation {} is not preexisting".
format(self.validation.jobid, self.validation.name))
217 general = self.__config.getGeneral()
220 name = os.path.splitext( os.path.basename( script) )[0]
221 ValidationJob.jobCount += 1
222 if self.__commandLineOptions.dryRun:
223 print(
"%s would run: %s"%( name, os.path.basename( script) ))
225 log =
"> Validating "+name
226 print(
"> Validating "+name)
227 if self.validation.jobmode ==
"interactive":
229 ValidationJob.interactCount += 1
230 elif self.validation.jobmode.split(
",")[0] ==
"lxBatch":
232 "commands": self.validation.jobmode.split(
",")[1],
233 "logDir": general[
"logdir"],
236 "bsub":
"/afs/cern.ch/cms/caf/scripts/cmsbsub" 238 for ext
in (
"stdout",
"stderr",
"stdout.gz",
"stderr.gz"):
239 oldlog =
"%(logDir)s/%(jobName)s."%repMap + ext
240 if os.path.exists(oldlog):
244 "-o %(logDir)s/%(jobName)s.stdout " 245 "-e %(logDir)s/%(jobName)s.stderr " 249 jobid=bsubOut.split(
"<")[1].
split(
">")[0]
250 self.JobId.append(jobid)
251 ValidationJob.batchJobIds.append(jobid)
253 ValidationJob.batchCount += 1
254 elif self.validation.jobmode.split(
"," )[0] ==
"crab":
255 os.chdir( general[
"logdir"] )
256 crabName =
"crab." + os.path.basename( script )[:-3]
258 options = {
"-create":
"",
259 "-cfg": crabName +
".cfg",
262 theCrab.run( options )
263 except AllInOneError
as e:
266 ValidationJob.crabCount += 1
269 raise AllInOneError(
"Unknown 'jobmode'!\n" 270 "Please change this parameter either in " 271 "the [general] or in the [" 273 +
"] section to one of the following " 275 "\tinteractive\n\tlxBatch, -q <queue>\n" 276 "\tcrab, -q <queue>")
285 return self.validation.needsproxy
and not self.
__preexisting and not self.__commandLineOptions.dryRun
290 if(len(validations) == 0):
291 raise AllInOneError(
"Cowardly refusing to merge nothing!")
293 config = validations[0].config
294 repMap = config.getGeneral()
297 "CompareAlignments":
"",
298 "RunValidationPlots":
"",
299 "CMSSW_BASE": os.environ[
"CMSSW_BASE"],
300 "SCRAM_ARCH": os.environ[
"SCRAM_ARCH"],
301 "CMSSW_RELEASE_BASE": os.environ[
"CMSSW_RELEASE_BASE"],
305 for validation
in validations:
306 for referenceName
in validation.filesToCompare:
307 validationtype = type(validation)
308 if issubclass(validationtype, PreexistingValidation):
310 for parentclass
in validationtype.mro():
311 if not issubclass(parentclass, PreexistingValidation):
312 validationtype = parentclass
314 key = (validationtype, referenceName)
315 if key
in comparisonLists:
316 comparisonLists[key].
append(validation)
318 comparisonLists[key] = [validation]
322 repMap[
"doMerge"] =
"mergeRetCode=0\n" 323 repMap[
"rmUnmerged"] = (
"if [[ mergeRetCode -eq 0 ]]; then\n" 324 " echo -e \\n\"Merging succeeded, removing original files.\"\n")
325 repMap[
"beforeMerge"] =
"" 326 repMap[
"mergeParallelFilePrefixes"] =
"" 327 repMap[
"createResultsDirectory"]=
"" 334 if options.mergeOfflineParallel:
335 parallelMergeObjects={}
336 for (validationType, referencename), validations
in six.iteritems(comparisonLists):
337 for validation
in validations:
339 if (isinstance(validation, PreexistingValidation)
340 or validation.NJobs == 1
341 or not isinstance(validation, ParallelValidation)):
343 if options.mergeOfflineParallel
and validationType.valType==
'offline' and validation.jobmode.split(
",")[0]==
"lxBatch":
344 repMapTemp=repMap.copy()
345 if validationType
not in anythingToMerge:
346 anythingToMerge += [validationType]
348 fileName=
"TkAlMergeInit" 349 filePath = os.path.join(path, fileName+
".sh")
350 theFile = open( filePath,
"w" )
351 repMapTemp[
"createResultsDirectory"]=
"#!/bin/bash" 352 repMapTemp[
"createResultsDirectory"]+=
replaceByMap(configTemplates.createResultsDirectoryTemplate, repMapTemp)
353 theFile.write(
replaceByMap( configTemplates.createResultsDirectoryTemplate, repMapTemp ) )
355 os.chmod(filePath,0o755)
359 repMapTemp[
"createResultsDirectory"]=
"" 363 repMapTemp[
"beforeMerge"] += validationType.doInitMerge()
364 repMapTemp[
"doMerge"] +=
'\n\n\n\necho -e "\n\nMerging results from %s jobs with alignment %s"\n\n' % (validationType.valType,validation.alignmentToValidate.name)
365 repMapTemp[
"doMerge"] += validation.doMerge()
366 for f
in validation.getRepMap()[
"outputFiles"]:
367 longName = os.path.join(
"/eos/cms/store/group/alca_trackeralign/AlignmentValidation/",
368 validation.getRepMap()[
"eosdir"], f)
369 repMapTemp[
"rmUnmerged"] +=
" rm "+longName+
"\n" 371 repMapTemp[
"rmUnmerged"] += (
"else\n" 372 " echo -e \\n\"WARNING: Merging failed, unmerged" 373 " files won't be deleted.\\n" 374 "(Ignore this warning if merging was done earlier)\"\n" 378 repMapTemp[
"DownloadData"] =
replaceByMap( configTemplates.mergeParallelResults, repMapTemp )
380 repMapTemp[
"RunValidationPlots"] = validationType.doRunPlots(validations)
383 fileName=
"TkAlMergeOfflineValidation"+validation.name+validation.alignmentToValidate.name
384 filePath = os.path.join(path, fileName+
".sh")
385 theFile = open( filePath,
"w" )
386 theFile.write(
replaceByMap( configTemplates.mergeParallelOfflineTemplate, repMapTemp ) )
388 os.chmod(filePath,0o755)
390 if "parallel" in parallelMergeObjects:
398 if validationType
not in anythingToMerge:
399 anythingToMerge += [validationType]
400 repMap[
"doMerge"] +=
'\n\n\n\necho -e "\n\nMerging results from %s jobs"\n\n' % validationType.valType
401 repMap[
"beforeMerge"] += validationType.doInitMerge()
402 repMap[
"doMerge"] += validation.doMerge()
403 for f
in validation.getRepMap()[
"outputFiles"]:
404 longName = os.path.join(
"/eos/cms/store/group/alca_trackeralign/AlignmentValidation/",
405 validation.getRepMap()[
"eosdir"], f)
406 repMap[
"rmUnmerged"] +=
" rm "+longName+
"\n" 410 repMap[
"rmUnmerged"] += (
"else\n" 411 " echo -e \\n\"WARNING: Merging failed, unmerged" 412 " files won't be deleted.\\n" 413 "(Ignore this warning if merging was done earlier)\"\n" 419 repMap[
"DownloadData"] +=
replaceByMap( configTemplates.mergeParallelResults, repMap )
421 repMap[
"DownloadData"] =
"" 423 repMap[
"RunValidationPlots"] =
"" 424 for (validationType, referencename), validations
in six.iteritems(comparisonLists):
425 if issubclass(validationType, ValidationWithPlots):
426 repMap[
"RunValidationPlots"] += validationType.doRunPlots(validations)
428 repMap[
"CompareAlignments"] =
"#run comparisons" 429 for (validationType, referencename), validations
in six.iteritems(comparisonLists):
430 if issubclass(validationType, ValidationWithComparison):
431 repMap[
"CompareAlignments"] += validationType.doComparison(validations)
434 if options.mergeOfflineParallel
and parallelMergeObjects!={}:
435 parallelMergeObjects[
"continue"]=
ParallelMergeJob(
"TkAlMergeFinal",os.path.join(path,
"TkAlMergeFinal.sh"),[])
436 filePath = os.path.join(path,
"TkAlMergeFinal.sh")
439 repMap[
"createResultsDirectory"]=
replaceByMap(configTemplates.createResultsDirectoryTemplate, repMap)
440 filePath = os.path.join(path,
"TkAlMerge.sh")
444 theFile = open( filePath,
"w" )
445 theFile.write(
replaceByMap( configTemplates.mergeTemplate, repMap ) )
447 os.chmod(filePath,0o755)
449 if options.mergeOfflineParallel:
450 return {
'TkAlMerge.sh':filePath,
'parallelMergeObjects':parallelMergeObjects}
455 if config.has_section(
"alternateTemplates"):
456 for templateName
in config.options(
"alternateTemplates"):
457 if templateName ==
"AutoAlternates":
459 newTemplateName = config.get(
"alternateTemplates", templateName )
468 optParser = optparse.OptionParser()
469 optParser.description =
"""All-in-one Alignment Validation. 470 This will run various validation procedures either on batch queues or interactively. 471 If no name is given (-N parameter) a name containing time and date is created automatically. 472 To merge the outcome of all validation procedures run TkAlMerge.sh in your validation's directory. 474 optParser.add_option(
"-n",
"--dryRun", dest=
"dryRun", action=
"store_true", default=
False,
475 help=
"create all scripts and cfg File but do not start jobs (default=False)")
476 optParser.add_option(
"--getImages", dest=
"getImages", action=
"store_true", default=
True,
477 help=
"get all Images created during the process (default= True)")
478 defaultConfig =
"TkAlConfig.ini" 479 optParser.add_option(
"-c",
"--config", dest=
"config", default = defaultConfig,
480 help=
"configuration to use (default TkAlConfig.ini) this can be a comma-seperated list of all .ini file you want to merge", metavar=
"CONFIG")
481 optParser.add_option(
"-N",
"--Name", dest=
"Name",
482 help=
"Name of this validation (default: alignmentValidation_DATE_TIME)", metavar=
"NAME")
483 optParser.add_option(
"-r",
"--restrictTo", dest=
"restrictTo",
484 help=
"restrict validations to given modes (comma seperated) (default: no restriction)", metavar=
"RESTRICTTO")
485 optParser.add_option(
"-s",
"--status", dest=
"crabStatus", action=
"store_true", default =
False,
486 help=
"get the status of the crab jobs", metavar=
"STATUS")
487 optParser.add_option(
"-d",
"--debug", dest=
"debugMode", action=
"store_true",
489 help=
"run the tool to get full traceback of errors",
491 optParser.add_option(
"-m",
"--autoMerge", dest=
"autoMerge", action=
"store_true", default =
False,
492 help=
"submit TkAlMerge.sh to run automatically when all jobs have finished (default=False)." 493 " Works only for batch jobs")
494 optParser.add_option(
"--mergeOfflineParallel", dest=
"mergeOfflineParallel", action=
"store_true", default =
False,
495 help=
"Enable parallel merging of offline data. Best used with -m option. Only works with lxBatch-jobmode", metavar=
"MERGE_PARALLEL")
498 (options, args) = optParser.parse_args(argv)
500 if not options.restrictTo ==
None:
501 options.restrictTo = options.restrictTo.split(
",")
503 options.config = [ os.path.abspath( iniFile )
for iniFile
in \
504 options.config.split(
"," ) ]
505 config = BetterConfigParser()
506 outputIniFileSet = set( config.read( options.config ) )
507 failedIniFiles = [ iniFile
for iniFile
in options.config
if iniFile
not in outputIniFileSet ]
510 if options.config == [ os.path.abspath( defaultConfig ) ]:
511 if (
not options.crabStatus )
and \
512 (
not os.path.exists( defaultConfig ) ):
513 raise AllInOneError(
"Default 'ini' file '%s' not found!\n" 514 "You can specify another name with the " 515 "command line option '-c'/'--config'." 518 for iniFile
in failedIniFiles:
519 if not os.path.exists( iniFile ):
520 raise AllInOneError(
"'%s' does not exist. Please check for " 521 "typos in the filename passed to the " 522 "'-c'/'--config' option!" 525 raise AllInOneError((
"'%s' does exist, but parsing of the " 526 "content failed!" ) % iniFile)
529 if options.Name ==
None:
530 if not options.crabStatus:
531 options.Name =
"alignmentValidation_%s"%(datetime.datetime.now().strftime(
"%y%m%d_%H%M%S"))
533 existingValDirs = fnmatch.filter( os.walk(
'.' ).
next()[1],
534 "alignmentValidation_*" )
535 if len( existingValDirs ) > 0:
536 options.Name = existingValDirs[-1]
538 print(
"Cannot guess last working directory!")
539 print (
"Please use the parameter '-N' or '--Name' to specify " 540 "the task for which you want a status report." )
544 outPath = os.path.abspath( options.Name )
547 if options.crabStatus:
549 crabLogDirs = fnmatch.filter( os.walk(
'.').
next()[1],
"crab.*" )
550 if len( crabLogDirs ) == 0:
551 print(
"Found no crab tasks for job name '%s'"%( options.Name ))
554 for crabLogDir
in crabLogDirs:
556 print(
"*" +
"=" * 78 +
"*")
557 print (
"| Status report and output retrieval for:" 558 +
" " * (77 - len(
"Status report and output retrieval for:" ) )
560 taskName = crabLogDir.replace(
"crab.",
"" )
561 print(
"| " + taskName +
" " * (77 - len( taskName ) ) +
"|")
562 print(
"*" +
"=" * 78 +
"*")
564 crabOptions = {
"-getoutput":
"",
567 theCrab.run( crabOptions )
568 except AllInOneError
as e:
569 print(
"crab: No output retrieved for this task.")
570 crabOptions = {
"-status":
"",
572 theCrab.run( crabOptions )
575 general = config.getGeneral()
576 config.set(
"internals",
"workdir",os.path.join(general[
"workdir"],options.Name) )
577 config.set(
"internals",
"scriptsdir",outPath)
578 config.set(
"general",
"datadir",os.path.join(general[
"datadir"],options.Name) )
579 config.set(
"general",
"logdir",os.path.join(general[
"logdir"],options.Name) )
580 config.set(
"general",
"eosdir",os.path.join(
"AlignmentValidation", general[
"eosdir"], options.Name) )
582 if not os.path.exists( outPath ):
583 os.makedirs( outPath )
584 elif not os.path.isdir( outPath ):
585 raise AllInOneError(
"the file %s is in the way rename the Job or move it away"%outPath)
591 backupConfigFile = open( os.path.join( outPath,
"usedConfiguration.ini" ) ,
"w" )
592 config.write( backupConfigFile )
601 shutil.copyfile(
getCommandOutput2(
"voms-proxy-info --path").
strip(), os.path.join(outPath,
".user_proxy"))
604 for validation
in config.items(
"validation"):
605 alignmentList = [validation[1]]
606 validationsToAdd = [(validation[0],alignment) \
607 for alignment
in alignmentList]
608 validations.extend(validationsToAdd)
610 for validation
in validations ]
612 if job.needsproxy
and not proxyexists:
613 raise AllInOneError(
"At least one job needs a grid proxy, please init one.")
614 map(
lambda job: job.createJob(), jobs )
615 validations = [ job.getValidation()
for job
in jobs ]
617 if options.mergeOfflineParallel:
618 parallelMergeObjects=
createMergeScript(outPath, validations, options)[
'parallelMergeObjects']
624 map(
lambda job: job.runJob(), jobs )
626 if options.autoMerge
and ValidationJob.jobCount == ValidationJob.batchCount
and config.getGeneral()[
"jobmode"].
split(
",")[0] ==
"lxBatch":
627 print(
"> Automatically merging jobs when they have ended")
632 if options.mergeOfflineParallel
and parallelMergeObjects!={}:
633 initID=parallelMergeObjects[
"init"].runJob(config).
split(
"<")[1].
split(
">")[0]
635 for parallelMergeScript
in parallelMergeObjects[
"parallel"]:
636 parallelMergeScript.addDependency(initID)
638 if isinstance(job.validation, OfflineValidation)
and "TkAlMerge"+job.validation.alignmentToValidate.name==parallelMergeScript.name:
639 parallelMergeScript.addDependency(job.JobId)
640 parallelIDs.append(parallelMergeScript.runJob(config).
split(
"<")[1].
split(
">")[0])
641 parallelMergeObjects[
"continue"].addDependency(parallelIDs)
642 parallelMergeObjects[
"continue"].addDependency(ValidationJob.batchJobIds)
643 parallelMergeObjects[
"continue"].runJob(config)
650 "commands": config.getGeneral()[
"jobmode"].
split(
",")[1],
651 "jobName":
"TkAlMerge",
652 "logDir": config.getGeneral()[
"logdir"],
653 "script":
"TkAlMerge.sh",
654 "bsub":
"/afs/cern.ch/cms/caf/scripts/cmsbsub",
655 "conditions":
'"' +
" && ".
join([
"ended(" + jobId +
")" for jobId
in ValidationJob.batchJobIds]) +
'"' 657 for ext
in (
"stdout",
"stderr",
"stdout.gz",
"stderr.gz"):
658 oldlog =
"%(logDir)s/%(jobName)s."%repMap + ext
659 if os.path.exists(oldlog):
664 "-o %(logDir)s/%(jobName)s.stdout " 665 "-e %(logDir)s/%(jobName)s.stderr " 667 "%(logDir)s/%(script)s"%repMap)
669 if __name__ ==
"__main__":
671 if "-d" in sys.argv[1:]
or "--debug" in sys.argv[1:]:
676 except AllInOneError
as e:
def main(argv=None)
— Main —############################
def loadTemplates(config)
def __init__(self, _name, _path, _dependency)
def createMergeScript(path, validations, options)
S & print(S &os, JobReport::InputFile const &f)
def getCommandOutput2(command)
— Classes —############################
def addIndex(filename, njobs, index=None)
def __getValidation(self, valType, name, alignments, config, options)
def replaceByMap(target, the_map)
— Helpers —############################
def __createJob(self, jobMode, outpath)
static std::string join(char **cmd)
def alternateTemplate(templateName, alternateTemplateName)
Alternate Templates ###
def __init__(self, validation, config, options)
def addDependency(self, dependency)