1 from abc
import ABCMeta, abstractmethod, abstractproperty
5 import globalDictionaries
7 from dataset
import Dataset
8 from helperFunctions
import replaceByMap, addIndex, getCommandOutput2, boolfromstring, pythonboolstring
9 from TkAlExceptions
import AllInOneError
12 sets = [
"mandatories",
"optionals",
"needpackages"]
15 for setname
in cls.
sets:
16 if setname
not in dct: dct[setname] = set()
17 dct[setname] = set.union(dct[setname], *(getattr(base, setname)
for base
in bases
if hasattr(base, setname)))
19 for dictname
in cls.
dicts:
20 if dictname
not in dct: dct[dictname] = {}
22 if not hasattr(base, dictname):
continue 23 newdict = getattr(base, dictname)
24 for key
in set(newdict) & set(dct[dictname]):
25 if newdict[key] != dct[dictname][key]:
26 raise ValueError(
"Inconsistent values of defaults[{}]: {}, {}".
format(key, newdict[key], dct[dictname][key]))
27 dct[dictname].
update(newdict)
29 for setname
in cls.
sets:
31 if "remove"+setname
not in dct: dct[
"remove"+setname] = set()
32 dct[
"remove"+setname] = set.union(dct[
"remove"+setname], *(getattr(base,
"remove"+setname)
for base
in bases
if hasattr(base,
"remove"+setname)))
34 dct[setname] -= dct[
"remove"+setname]
36 return super(ValidationMetaClass, cls).
__new__(cls, clsname, bases, dct)
39 __metaclass__ = ValidationMetaClass
40 defaultReferenceName =
"DEFAULT" 43 "cmssw": os.environ[
'CMSSW_BASE'],
46 "needsproxy":
"false",
48 needpackages = {
"Alignment/OfflineValidation"}
49 optionals = {
"jobmode"}
51 def __init__(self, valName, alignment, config):
61 theUpdate = config.getResultingSection(self.valType+
":"+self.
name,
64 self.general.update(theUpdate)
71 maximumNumberJobs = 40
72 if self.
NJobs > maximumNumberJobs:
73 msg = (
"Maximum allowed number of parallel jobs " 74 +
str(maximumNumberJobs)+
" exceeded!!!")
76 if self.
NJobs > 1
and not isinstance(self, ParallelValidation):
78 "Please set parallelJobs = 1.".
format(type(self).__name__))
84 if "is not found" in output:
raise RuntimeError
90 for character
in badcharacters:
91 if character
in self.
cmssw:
92 raise AllInOneError(
"The bad characters " + badcharacters +
" are not allowed in the cmssw\n" 93 "path name. If you really have it in such a ridiculously named location,\n" 94 "try making a symbolic link somewhere with a decent name.")
96 os.listdir(self.
cmssw)
100 if self.
cmssw == os.environ[
"CMSSW_BASE"]:
104 command = (
"cd '" + self.
cmssw +
"' && eval `scramv1 ru -sh 2> /dev/null`" 105 ' && echo "$CMSSW_BASE\n$SCRAM_ARCH\n$CMSSW_RELEASE_BASE"')
107 self.
cmssw = commandoutput[0]
114 pkgpath = os.path.join(placetolook,
"src", package)
115 if os.path.exists(pkgpath):
122 if config.has_option(
"alternateTemplates",
"AutoAlternates"):
124 self.
AutoAlternates = json.loads(config.get(
"alternateTemplates",
"AutoAlternates").lower())
126 raise AllInOneError(
"AutoAlternates needs to be true or false, not %s" % config.get(
"alternateTemplates",
"AutoAlternates"))
130 config.checkInput(self.valType+
":"+self.
name,
131 knownSimpleOptions = knownOpts,
132 ignoreOptions = ignoreOpts)
135 from plottingOptions
import PlottingOptions
136 if alignment ==
None:
142 result.update(alignment.getRepMap())
145 "workdir": os.path.join(self.
general[
"workdir"],
147 "datadir": self.
general[
"datadir"],
148 "logdir": self.
general[
"logdir"],
149 "CommandLineTemplate": (
"#run configfile and post-proccess it\n" 150 "cmsRun %(cfgFile)s\n" 152 "CMSSW_BASE": self.
cmssw,
155 "alignmentName": alignment.name,
156 "condLoad": alignment.getConditions(),
157 "LoadGlobalTagTemplate": configTemplates.loadGlobalTagTemplate,
168 repMap = self.getRepMap().
copy()
169 for validationId
in self.filesToCompare:
170 repMap[
"file"] = self.filesToCompare[ validationId ]
171 if repMap[
"file"].startswith(
"/castor/" ):
172 repMap[
"file"] =
"rfio:%(file)s"%repMap
173 elif repMap[
"file"].startswith(
"/store/" ):
174 repMap[
"file"] =
"root://eoscms.cern.ch//eos/cms%(file)s"%repMap
176 result[validationId]=repMap[
"file"]
178 result[validationId]=
"%(file)s=%(title)s|%(color)s|%(style)s"%repMap
179 if requestId ==
None:
182 if not "." in requestId:
183 requestId +=
".%s"%self.defaultReferenceName
184 if not requestId.split(
".")[-1]
in result:
185 msg = (
"could not find %s in reference Objects!" 186 %requestId.split(
".")[-1])
187 raise AllInOneError(msg)
188 return result[ requestId.split(
".")[-1] ]
190 def createFiles(self, fileContents, path, repMap = None, repMaps = None):
191 """repMap: single map for all files 192 repMaps: a dict, with the filenames as the keys""" 193 if repMap
is not None and repMaps
is not None:
194 raise AllInOneError(
"createFiles can only take repMap or repMaps (or neither), not both")
196 for fileName
in fileContents:
197 filePath = os.path.join(path, fileName)
198 result.append(filePath)
200 for (i, filePathi)
in enumerate(
addIndex(filePath, self.
NJobs)):
201 theFile = open( filePathi,
"w" )
202 fileContentsi = fileContents[ fileName ]
203 if repMaps
is not None:
204 repMap = repMaps[fileName]
205 if repMap
is not None:
206 repMap.update({
"nIndex":
str(i)})
208 theFile.write( fileContentsi )
215 path, repMap = repMap, repMaps = repMaps)
216 if not schedule ==
None:
217 schedule = [os.path.join( path, cfgName)
for cfgName
in schedule]
218 for cfgName
in schedule:
220 msg = (
"scheduled %s missing in generated configfiles: %s" 224 if not cfgName
in schedule:
225 msg = (
"generated configuration %s not scheduled: %s" 226 %(cfgName, schedule))
231 def createScript(self, fileContents, path, downloadFiles=[], repMap = None, repMaps = None):
233 path, repMap = repMap, repMaps = repMaps)
236 os.chmod(scriptwithindex,0o755)
241 msg = (
"jobmode 'crab' not supported for parallel validation." 242 " Please set parallelJobs = 1.")
250 Subclass of `GenericValidation` which is the base for validations using 253 needParentFiles =
False 254 mandatories = {
"dataset",
"maxevents"}
262 "dasinstance":
"prod/global",
263 "ttrhbuilder":
"WithAngleAndTemplate",
264 "usepixelqualityflag":
"True",
266 optionals = {
"magneticfield"}
270 This method adds additional items to the `self.general` dictionary 271 which are only needed for validations using datasets. 274 - `valName`: String which identifies individual validation instances 275 - `alignment`: `Alignment` instance to validate 276 - `config`: `BetterConfigParser` instance which includes the 277 configuration of the validations 280 super(GenericValidationData, self).
__init__(valName, alignment, config)
285 msg = (
"Maximum number of events (maxevents) not specified: " 286 "cannot use parallel jobs.")
289 msg = (
"maxevents has to be divisible by parallelJobs")
292 tryPredefinedFirst = (
not self.jobmode.split(
',' )[0] ==
"crab" and self.
general[
"JSON"] ==
"" 293 and self.
general[
"firstRun"] ==
"" and self.
general[
"lastRun"] ==
"" 296 if self.
general[
"dataset"]
not in globalDictionaries.usedDatasets:
297 globalDictionaries.usedDatasets[self.
general[
"dataset"]] = {}
299 if self.
cmssw not in globalDictionaries.usedDatasets[self.
general[
"dataset"]]:
300 if globalDictionaries.usedDatasets[self.
general[
"dataset"]] != {}:
301 print (
"Warning: you use the same dataset '%s' in multiple cmssw releases.\n" 302 "This is allowed, but make sure it's not a mistake") % self.
general[
"dataset"]
303 globalDictionaries.usedDatasets[self.
general[
"dataset"]][self.
cmssw] = {
False:
None,
True:
None}
305 Bfield = self.general.get(
"magneticfield",
None)
306 if globalDictionaries.usedDatasets[self.
general[
"dataset"]][self.
cmssw][tryPredefinedFirst]
is None:
308 self.
general[
"dataset"], tryPredefinedFirst = tryPredefinedFirst,
310 dasinstance = self.
general[
"dasinstance"])
311 globalDictionaries.usedDatasets[self.
general[
"dataset"]][self.
cmssw][tryPredefinedFirst] = dataset
312 if tryPredefinedFirst
and not dataset.predefined():
313 globalDictionaries.usedDatasets[self.
general[
"dataset"]][self.
cmssw][
False] = dataset
316 self.
general[
"magneticField"] = self.dataset.magneticField()
317 self.
general[
"defaultMagneticField"] =
"MagneticField" 318 if self.
general[
"magneticField"] ==
"unknown":
319 print "Could not get the magnetic field for this dataset." 320 print "Using the default: ", self.
general[
"defaultMagneticField"]
321 self.
general[
"magneticField"] =
'.oO[defaultMagneticField]Oo.' 323 if not self.jobmode.split(
',' )[0] ==
"crab":
325 self.
general[
"datasetDefinition"] = self.dataset.datasetSnippet(
326 jsonPath = self.
general[
"JSON"],
327 firstRun = self.
general[
"firstRun"],
328 lastRun = self.
general[
"lastRun"],
332 except AllInOneError
as e:
333 msg =
"In section [%s:%s]: "%(self.valType, self.
name)
337 if self.dataset.predefined():
338 msg = (
"For jobmode 'crab' you cannot use predefined datasets " 339 "(in your case: '%s')."%( self.dataset.name() ))
342 theUpdate = config.getResultingSection(self.valType+
":"+self.
name,
343 demandPars = [
"parallelJobs"])
344 except AllInOneError
as e:
345 msg =
str(e)[:-1]+
" when using 'jobmode: crab'." 347 self.general.update(theUpdate)
352 self.
general[
"lastRun"] ) = self.dataset.convertTimeToRun(
353 firstRun = self.
general[
"firstRun"],
354 lastRun = self.
general[
"lastRun"],
358 if self.
general[
"begin"] ==
None:
360 if self.
general[
"end"] ==
None:
364 if (
not self.
general[
"firstRun"] )
and \
367 self.dataset.runList()[0][
"run_number"])
368 if (
not self.
general[
"lastRun"] )
and \
371 self.dataset.runList()[-1][
"run_number"])
374 msg = (
"The lower time/runrange limit ('begin'/'firstRun') " 375 "chosen is greater than the upper time/runrange limit " 376 "('end'/'lastRun').")
379 +
'-' + self.
general[
"lastRun"])
381 self.
general[
"datasetDefinition"] = self.dataset.datasetSnippet(
382 jsonPath = self.
general[
"JSON"],
383 firstRun = self.
general[
"firstRun"],
384 lastRun = self.
general[
"lastRun"],
388 except AllInOneError
as e:
389 msg =
"In section [%s:%s]: "%(self.valType, self.
name)
396 result = super(GenericValidationData, self).
getRepMap(alignment)
398 "%s_%s_.oO[name]Oo..root" % (self.outputBaseName, self.
name)
400 resultfile = os.path.expandvars(
replaceByMap((
"/store/caf/user/$USER/.oO[eosdir]Oo./" +
401 "%s_%s_.oO[name]Oo..root" % (self.resultBaseName, self.
name))
404 "resultFile":
".oO[resultFiles[.oO[nIndex]Oo.]]Oo.",
406 "finalResultFile": resultfile,
407 "outputFile":
".oO[outputFiles[.oO[nIndex]Oo.]]Oo.",
409 "finalOutputFile": outputfile,
422 return "%s.%s.%s_cfg.py"%( self.configBaseName, self.
name,
423 self.alignmentToValidate.name )
430 return configTemplates.cfgTemplate
445 def createScript(self, path, template = configTemplates.scriptTemplate, downloadFiles=[], repMap = None, repMaps = None):
446 scriptName =
"%s.%s.%s.sh"%(self.scriptBaseName, self.
name,
447 self.alignmentToValidate.name )
448 if repMap
is None and repMaps
is None:
450 repMap[
"CommandLine"]=
"" 452 repMap[
"CommandLine"]+= repMap[
"CommandLineTemplate"]%{
"cfgFile":
addIndex(cfg, self.
NJobs,
".oO[nIndex]Oo."),
455 scripts = {scriptName: template}
456 return super(GenericValidationData, self).
createScript(scripts, path, downloadFiles = downloadFiles,
457 repMap = repMap, repMaps = repMaps)
461 Method which creates a `crab.cfg` for a validation on datasets. 464 - `path`: Path at which the file will be stored. 465 - `crabCfgBaseName`: String which depends on the actual type of 466 validation calling this method. 468 crabCfgName =
"crab.%s.%s.%s.cfg"%( crabCfgBaseName, self.
name,
469 self.alignmentToValidate.name )
471 repMap[
"script"] =
"dummy_script.sh" 473 repMap[
"crabWorkingDir"] = crabCfgName.split(
'.cfg' )[0]
475 repMap[
"numberOfJobs"] = self.
general[
"parallelJobs"]
477 repMap[
"queue"] = self.jobmode.split(
',' )[1].
split(
'-q' )[1]
478 if self.dataset.dataType() ==
"mc":
479 repMap[
"McOrData"] =
"events = .oO[nEvents]Oo." 480 elif self.dataset.dataType() ==
"data":
481 repMap[
"McOrData"] =
"lumis = -1" 482 if self.jobmode.split(
',' )[0] ==
"crab":
483 print (
"For jobmode 'crab' the parameter 'maxevents' will be " 484 "ignored and all events will be processed.")
486 raise AllInOneError(
"Unknown data type! Can't run in crab mode")
487 crabCfg = {crabCfgName:
replaceByMap( configTemplates.crabCfgTemplate,
489 return super(GenericValidationData, self).
createCrabCfg( crabCfg, path )
493 return configTemplates.Bookkeeping
496 return configTemplates.LoadBasicModules
502 return configTemplates.FileOutputTemplate
507 class GenericValidationData_CTSR(GenericValidationData):
510 "momentumconstraint":
"None",
511 "openmasswindow":
"False",
512 "cosmicsdecomode":
"True",
513 "removetrackhitfiltercommands":
"",
514 "appendtrackhitfiltercommands":
"",
517 result = super(GenericValidationData_CTSR, self).
getRepMap(alignment)
519 from trackSplittingValidation
import TrackSplittingValidation
522 "istracksplitting":
str(isinstance(self, TrackSplittingValidation)),
529 for removeorappend
in "remove",
"append":
530 optionname = removeorappend +
"trackhitfiltercommands" 531 if result[optionname]:
532 for command
in result[optionname].
split(
","):
533 command = command.strip()
534 commands.append(
'process.TrackerTrackHitFilter.commands.{}("{}")'.
format(removeorappend, command))
535 result[
"trackhitfiltercommands"] =
"\n".
join(commands)
540 return "Cosmics" not in self.
general[
"trackcollection"]
546 return configTemplates.CommonTrackSelectionRefitting
549 return configTemplates.DefinePath_CommonSelectionRefitting
555 if "Cosmics" not in self.
general[
"trackcollection"]:
return False 556 Bfield = self.dataset.magneticFieldForRun()
557 if Bfield < 0.5:
return True 558 if isinstance(Bfield, str):
559 if "unknown " in Bfield:
560 msg = Bfield.replace(
"unknown ",
"",1)
561 elif Bfield ==
"unknown":
562 msg =
"Can't get the B field for %s." % self.dataset.name()
564 msg =
"B field = {}???".
format(Bfield)
566 "To use this dataset, specify magneticfield = [value] in your .ini config file.")
579 from plottingOptions
import PlottingOptions
582 if result
and result[-1] !=
"\n": result +=
"\n" 586 if result[-1] !=
"\n": result +=
"\n" 587 result += (
"if [[ tmpMergeRetCode -eq 0 ]]; then\n" 588 " xrdcp -f .oO[finalOutputFile]Oo. root://eoscms//eos/cms.oO[finalResultFile]Oo.\n" 590 "if [[ ${tmpMergeRetCode} -gt ${mergeRetCode} ]]; then\n" 591 " mergeRetCode=${tmpMergeRetCode}\n" 599 return (
"rfcp .oO[plottingscriptpath]Oo. .\n" 600 "root -x -b -q .oO[plottingscriptname]Oo.++")
606 """override with a classmethod""" 609 """override with a classmethod""" 612 """override with a classmethod""" 616 from plottingOptions
import PlottingOptions
620 if result
and result[-1] !=
"\n": result +=
"\n" 624 from plottingOptions
import PlottingOptions
626 filename =
replaceByMap(
".oO[plottingscriptpath]Oo.", repmap)
627 repmap[
"PlottingInstantiation"] =
"\n".
join(
628 replaceByMap(v.appendToPlots(), v.getRepMap()).rstrip(
"\n")
632 with open(filename,
'w')
as f:
633 f.write(plottingscript)
637 def __init__(self, name, values, format=None, latexname=None, latexformat=None):
639 name: name of the summary item, goes on top of the column 640 values: value for each alignment (in order of rows) 641 format: python format string (default: {:.3g}, meaning up to 3 significant digits) 642 latexname: name in latex form, e.g. if name=sigma you might want latexname=\sigma (default: name) 643 latexformat: format for latex (default: format) 645 if format
is None: format =
"{:.3g}" 646 if latexname
is None: latexname = name
647 if latexformat
is None: latexformat = format
666 if re.match(
".*[{][^}]*[fg][}].*", fmt):
668 return fmt.format(value)
675 return self.
values(latex)[i]
679 """override with a classmethod that returns a list of SummaryItems 680 based on the plots saved in folder""" 682 __summaryitems =
None 688 if folder.startswith(
"/castor/" ):
689 folder =
"rfio:%(file)s"%repMap
690 elif folder.startswith(
"/store/" ):
691 folder =
"root://eoscms.cern.ch//eos/cms%(file)s"%repMap
701 size = {len(_.values(latex))
for _
in summaryitems}
703 raise AllInOneError(
"Some summary items have different numbers of values\n{}".
format(size))
707 columnwidths = ([
max(len(_.name(latex))
for _
in summaryitems)]
708 + [
max(len(_.value(i, latex))
for _
in summaryitems)
for i
in range(size)])
710 columnwidths = [
max(len(entry)
for entry
in [_.name(latex)] + _.values(latex))
for _
in summaryitems]
716 row = join.join(
"{{:{}}}".
format(width)
for width
in columnwidths)
719 rows = [row.format(*[_.name(latex)]+_.values(latex))
for _
in summaryitems]
722 rows.append(row.format(*(_.name
for _
in summaryitems)))
723 for i
in range(size):
724 rows.append(row.format(*(_.value(i, latex)
for _
in summaryitems)))
730 result = join.join(rows)
732 result = (
r"\begin{{tabular}}{{{}}}".
format(
"|" +
"|".
join(
"c"*(len(columnwidths))) +
"|") +
"\n" 742 with open(filename,
"w")
as f:
749 with open(os.path.join(folder,
"{}Summary.txt".
format(cls.__name__)))
as f:
751 split = line.rstrip(
"\n").
split(
"\t")
753 for thing
in split[:]:
754 if thing.startswith(
"format="):
755 kwargs[
"format"] = thing.replace(
"format=",
"", 1)
757 if thing.startswith(
"latexname="):
758 kwargs[
"latexname"] = thing.replace(
"latexname=",
"", 1)
760 if thing.startswith(
"latexformat="):
761 kwargs[
"latexformat"] = thing.replace(
"latexformat=",
"", 1)
766 result.append(cls.
SummaryItem(name, values, **kwargs))
772 from plottingOptions
import PlottingOptions
774 repmap[
"compareStrings"] =
" , ".
join(v.getCompareStrings(
"OfflineValidation")
for v
in validations)
775 repmap[
"compareStringsPlain"] =
" , ".
join(v.getCompareStrings(
"OfflineValidation",
True)
for v
in validations)
781 return configTemplates.compareAlignmentsExecution
784 return ".oO[Alignment/OfflineValidation]Oo./scripts/.oO[compareAlignmentsName]Oo." 789 class ValidationForPresentation(ValidationWithPlots):
def createPlottingScript(cls, validations)
def format(self, value, latex=False)
def __init__(self, valName, alignment, config)
def pythonboolstring(string, name)
def TrackSelectionRefitting(self)
def printsummaryitems(cls, args, kwargs)
def comparealignmentspath(cls)
def getRepMap(self, alignment=None)
def LoadBasicModules(self)
def createConfiguration(self, fileContents, path, schedule=None, repMap=None, repMaps=None)
def createConfiguration(self, path)
def ValidationTemplate(self)
def plottingscripttemplate(cls)
def getCommandOutput2(command)
def createScript(self, fileContents, path, downloadFiles=[], repMap=None, repMaps=None)
def writesummaryitems(cls, filename, args, kwargs)
def __init__(self, valName, alignment, config)
def plottingscriptname(cls)
def TrackSelectionRefitting(self)
def FileOutputTemplate(self)
def name(self, latex=False)
def ValidationSequence(self)
def addIndex(filename, njobs, index=None)
def createCrabCfg(self, path, crabCfgBaseName)
def doRunPlots(cls, validations)
def doComparison(cls, validations)
def runPlots(cls, validations)
def value(self, i, latex)
def getRepMap(self, alignment=None)
def comparisontemplate(cls)
def summaryitemsstring(cls, folder=None, latex=False, transpose=True)
def PlottingOptions(config, valType)
def replaceByMap(target, the_map)
— Helpers —############################
def values(self, latex=False)
def createFiles(self, fileContents, path, repMap=None, repMaps=None)
static std::string join(char **cmd)
string defaultReferenceName
def __init__(self, name, values, format=None, latexname=None, latexformat=None)
def boolfromstring(string, name)
def createScript(self, path, template=configTemplates.scriptTemplate, downloadFiles=[], repMap=None, repMaps=None)
def createCrabCfg(self, fileContents, path)
def getRepMap(self, alignment=None)
def presentationsubsections(cls)
def getCompareStrings(self, requestId=None, plain=False)
def getsummaryitems(cls, folder)
def getsummaryitems(cls, folder)
def comparealignmentsname(cls)