1 from __future__
import print_function
2 from __future__
import absolute_import
3 from builtins
import range
4 from abc
import ABCMeta, abstractmethod, abstractproperty
8 from .
import globalDictionaries
9 from .
import configTemplates
10 from .dataset
import Dataset
11 from .helperFunctions
import replaceByMap, addIndex, getCommandOutput2, boolfromstring, pythonboolstring
12 from .TkAlExceptions
import AllInOneError
13 from six
import with_metaclass
16 sets = [
"mandatories",
"optionals",
"needpackages"]
19 for setname
in cls.
sets:
20 if setname
not in dct: dct[setname] = set()
21 dct[setname] = set.union(dct[setname], *(getattr(base, setname)
for base
in bases
if hasattr(base, setname)))
23 for dictname
in cls.
dicts:
24 if dictname
not in dct: dct[dictname] = {}
26 if not hasattr(base, dictname):
continue
27 newdict = getattr(base, dictname)
28 for key
in set(newdict) & set(dct[dictname]):
29 if newdict[key] != dct[dictname][key]:
30 raise ValueError(
"Inconsistent values of defaults[{}]: {}, {}".
format(key, newdict[key], dct[dictname][key]))
31 dct[dictname].
update(newdict)
33 for setname
in cls.
sets:
35 if "remove"+setname
not in dct: dct[
"remove"+setname] = set()
36 dct[
"remove"+setname] = set.union(dct[
"remove"+setname], *(getattr(base,
"remove"+setname)
for base
in bases
if hasattr(base,
"remove"+setname)))
38 dct[setname] -= dct[
"remove"+setname]
40 return super(ValidationMetaClass, cls).
__new__(cls, clsname, bases, dct)
43 defaultReferenceName =
"DEFAULT"
46 "cmssw": os.environ[
'CMSSW_BASE'],
49 "needsproxy":
"false",
51 needpackages = {
"Alignment/OfflineValidation"}
52 optionals = {
"jobmode"}
54 def __init__(self, valName, alignment, config):
64 theUpdate = config.getResultingSection(self.valType+
":"+self.
name,
74 maximumNumberJobs = 40
75 if self.
NJobs > maximumNumberJobs:
76 msg = (
"Maximum allowed number of parallel jobs "
77 +
str(maximumNumberJobs)+
" exceeded!!!")
79 if self.
NJobs > 1
and not isinstance(self, ParallelValidation):
81 "Please set parallelJobs = 1.".
format(type(self).__name__))
87 if "is not found" in output:
raise RuntimeError
93 for character
in badcharacters:
94 if character
in self.
cmssw:
95 raise AllInOneError(
"The bad characters " + badcharacters +
" are not allowed in the cmssw\n"
96 "path name. If you really have it in such a ridiculously named location,\n"
97 "try making a symbolic link somewhere with a decent name.")
99 os.listdir(self.
cmssw)
103 if self.
cmssw == os.environ[
"CMSSW_BASE"]:
107 command = (
"cd '" + self.
cmssw +
"' && eval `scramv1 ru -sh 2> /dev/null`"
108 ' && echo "$CMSSW_BASE\n$SCRAM_ARCH\n$CMSSW_RELEASE_BASE"')
110 self.
cmssw = commandoutput[0]
117 pkgpath = os.path.join(placetolook,
"src", package)
118 if os.path.exists(pkgpath):
125 if config.has_option(
"alternateTemplates",
"AutoAlternates"):
127 self.
AutoAlternates = json.loads(config.get(
"alternateTemplates",
"AutoAlternates").lower())
129 raise AllInOneError(
"AutoAlternates needs to be true or false, not %s" % config.get(
"alternateTemplates",
"AutoAlternates"))
133 config.checkInput(self.valType+
":"+self.
name,
134 knownSimpleOptions = knownOpts,
135 ignoreOptions = ignoreOpts)
138 from .plottingOptions
import PlottingOptions
139 if alignment ==
None:
145 result.update(alignment.getRepMap())
148 "workdir": os.path.join(self.
general[
"workdir"],
150 "datadir": self.
general[
"datadir"],
151 "logdir": self.
general[
"logdir"],
152 "CommandLineTemplate": (
"#run configfile and post-proccess it\n"
153 "cmsRun %(cfgFile)s\n"
155 "CMSSW_BASE": self.
cmssw,
158 "alignmentName": alignment.name,
159 "condLoad": alignment.getConditions(),
160 "LoadGlobalTagTemplate": configTemplates.loadGlobalTagTemplate,
171 repMap = self.getRepMap().
copy()
172 for validationId
in self.filesToCompare:
173 repMap[
"file"] = self.filesToCompare[ validationId ]
174 if repMap[
"file"].startswith(
"/castor/" ):
175 repMap[
"file"] =
"rfio:%(file)s"%repMap
176 elif repMap[
"file"].startswith(
"/store/" ):
177 repMap[
"file"] =
"root://eoscms.cern.ch//eos/cms%(file)s"%repMap
179 result[validationId]=repMap[
"file"]
181 result[validationId]=
"%(file)s=%(title)s|%(color)s|%(style)s"%repMap
182 if requestId ==
None:
185 if not "." in requestId:
186 requestId +=
".%s"%self.defaultReferenceName
187 if not requestId.split(
".")[-1]
in result:
188 msg = (
"could not find %s in reference Objects!"
189 %requestId.split(
".")[-1])
190 raise AllInOneError(msg)
191 return result[ requestId.split(
".")[-1] ]
193 def createFiles(self, fileContents, path, repMap = None, repMaps = None):
194 """repMap: single map for all files
195 repMaps: a dict, with the filenames as the keys"""
196 if repMap
is not None and repMaps
is not None:
197 raise AllInOneError(
"createFiles can only take repMap or repMaps (or neither), not both")
199 for fileName
in fileContents:
200 filePath = os.path.join(path, fileName)
201 result.append(filePath)
203 for (i, filePathi)
in enumerate(
addIndex(filePath, self.
NJobs)):
204 theFile = open( filePathi,
"w" )
205 fileContentsi = fileContents[ fileName ]
206 if repMaps
is not None:
207 repMap = repMaps[fileName]
208 if repMap
is not None:
209 repMap.update({
"nIndex":
str(i)})
211 theFile.write( fileContentsi )
218 path, repMap = repMap, repMaps = repMaps)
219 if not schedule ==
None:
220 schedule = [os.path.join( path, cfgName)
for cfgName
in schedule]
221 for cfgName
in schedule:
223 msg = (
"scheduled %s missing in generated configfiles: %s"
227 if not cfgName
in schedule:
228 msg = (
"generated configuration %s not scheduled: %s"
229 %(cfgName, schedule))
234 def createScript(self, fileContents, path, downloadFiles=[], repMap = None, repMaps = None):
236 path, repMap = repMap, repMaps = repMaps)
239 os.chmod(scriptwithindex,0o755)
244 msg = (
"jobmode 'crab' not supported for parallel validation."
245 " Please set parallelJobs = 1.")
253 Subclass of `GenericValidation` which is the base for validations using
256 needParentFiles =
False
257 mandatories = {
"dataset",
"maxevents"}
265 "dasinstance":
"prod/global",
266 "ttrhbuilder":
"WithAngleAndTemplate",
267 "usepixelqualityflag":
"True",
269 optionals = {
"magneticfield"}
273 This method adds additional items to the `self.general` dictionary
274 which are only needed for validations using datasets.
277 - `valName`: String which identifies individual validation instances
278 - `alignment`: `Alignment` instance to validate
279 - `config`: `BetterConfigParser` instance which includes the
280 configuration of the validations
283 super(GenericValidationData, self).
__init__(valName, alignment, config)
288 msg = (
"Maximum number of events (maxevents) not specified: "
289 "cannot use parallel jobs.")
292 msg = (
"maxevents has to be divisible by parallelJobs")
295 tryPredefinedFirst = (
not self.
jobmode.
split(
',' )[0] ==
"crab" and self.
general[
"JSON"] ==
""
296 and self.
general[
"firstRun"] ==
"" and self.
general[
"lastRun"] ==
""
299 if self.
general[
"dataset"]
not in globalDictionaries.usedDatasets:
300 globalDictionaries.usedDatasets[self.
general[
"dataset"]] = {}
302 if self.
cmssw not in globalDictionaries.usedDatasets[self.
general[
"dataset"]]:
303 if globalDictionaries.usedDatasets[self.
general[
"dataset"]] != {}:
304 print((
"Warning: you use the same dataset '%s' in multiple cmssw releases.\n"
305 "This is allowed, but make sure it's not a mistake") % self.
general[
"dataset"])
306 globalDictionaries.usedDatasets[self.
general[
"dataset"]][self.
cmssw] = {
False:
None,
True:
None}
308 Bfield = self.
general.get(
"magneticfield",
None)
309 if globalDictionaries.usedDatasets[self.
general[
"dataset"]][self.
cmssw][tryPredefinedFirst]
is None:
311 self.
general[
"dataset"], tryPredefinedFirst = tryPredefinedFirst,
313 dasinstance = self.
general[
"dasinstance"])
314 globalDictionaries.usedDatasets[self.
general[
"dataset"]][self.
cmssw][tryPredefinedFirst] = dataset
315 if tryPredefinedFirst
and not dataset.predefined():
316 globalDictionaries.usedDatasets[self.
general[
"dataset"]][self.
cmssw][
False] = dataset
320 self.
general[
"defaultMagneticField"] =
"MagneticField"
321 if self.
general[
"magneticField"] ==
"unknown":
322 print(
"Could not get the magnetic field for this dataset.")
323 print(
"Using the default: ", self.
general[
"defaultMagneticField"])
324 self.
general[
"magneticField"] =
'.oO[defaultMagneticField]Oo.'
329 jsonPath = self.
general[
"JSON"],
330 firstRun = self.
general[
"firstRun"],
331 lastRun = self.
general[
"lastRun"],
335 except AllInOneError
as e:
336 msg =
"In section [%s:%s]: "%(self.valType, self.
name)
341 msg = (
"For jobmode 'crab' you cannot use predefined datasets "
345 theUpdate = config.getResultingSection(self.valType+
":"+self.
name,
346 demandPars = [
"parallelJobs"])
347 except AllInOneError
as e:
348 msg =
str(e)[:-1]+
" when using 'jobmode: crab'."
356 firstRun = self.
general[
"firstRun"],
357 lastRun = self.
general[
"lastRun"],
361 if self.
general[
"begin"] ==
None:
363 if self.
general[
"end"] ==
None:
367 if (
not self.
general[
"firstRun"] )
and \
371 if (
not self.
general[
"lastRun"] )
and \
377 msg = (
"The lower time/runrange limit ('begin'/'firstRun') "
378 "chosen is greater than the upper time/runrange limit "
379 "('end'/'lastRun').")
382 +
'-' + self.
general[
"lastRun"])
385 jsonPath = self.
general[
"JSON"],
386 firstRun = self.
general[
"firstRun"],
387 lastRun = self.
general[
"lastRun"],
391 except AllInOneError
as e:
392 msg =
"In section [%s:%s]: "%(self.valType, self.
name)
399 result = super(GenericValidationData, self).
getRepMap(alignment)
401 "%s_%s_.oO[name]Oo..root" % (self.outputBaseName, self.
name)
403 resultfile = os.path.expandvars(
replaceByMap((
"/store/group/alca_trackeralign/AlignmentValidation/.oO[eosdir]Oo./" +
404 "%s_%s_.oO[name]Oo..root" % (self.resultBaseName, self.
name))
407 "resultFile":
".oO[resultFiles[.oO[nIndex]Oo.]]Oo.",
409 "finalResultFile": resultfile,
410 "outputFile":
".oO[outputFiles[.oO[nIndex]Oo.]]Oo.",
412 "finalOutputFile": outputfile,
425 return "%s.%s.%s_cfg.py"%( self.configBaseName, self.
name,
433 return configTemplates.cfgTemplate
448 def createScript(self, path, template = configTemplates.scriptTemplate, downloadFiles=[], repMap = None, repMaps = None):
449 scriptName =
"%s.%s.%s.sh"%(self.scriptBaseName, self.
name,
451 if repMap
is None and repMaps
is None:
453 repMap[
"CommandLine"]=
""
455 repMap[
"CommandLine"]+= repMap[
"CommandLineTemplate"]%{
"cfgFile":
addIndex(cfg, self.
NJobs,
".oO[nIndex]Oo."),
458 scripts = {scriptName: template}
459 return super(GenericValidationData, self).
createScript(scripts, path, downloadFiles = downloadFiles,
460 repMap = repMap, repMaps = repMaps)
464 Method which creates a `crab.cfg` for a validation on datasets.
467 - `path`: Path at which the file will be stored.
468 - `crabCfgBaseName`: String which depends on the actual type of
469 validation calling this method.
471 crabCfgName =
"crab.%s.%s.%s.cfg"%( crabCfgBaseName, self.
name,
474 repMap[
"script"] =
"dummy_script.sh"
476 repMap[
"crabWorkingDir"] = crabCfgName.split(
'.cfg' )[0]
478 repMap[
"numberOfJobs"] = self.
general[
"parallelJobs"]
482 repMap[
"McOrData"] =
"events = .oO[nEvents]Oo."
484 repMap[
"McOrData"] =
"lumis = -1"
486 print (
"For jobmode 'crab' the parameter 'maxevents' will be "
487 "ignored and all events will be processed.")
489 raise AllInOneError(
"Unknown data type! Can't run in crab mode")
490 crabCfg = {crabCfgName:
replaceByMap( configTemplates.crabCfgTemplate,
492 return super(GenericValidationData, self).
createCrabCfg( crabCfg, path )
496 return configTemplates.Bookkeeping
499 return configTemplates.LoadBasicModules
505 return configTemplates.FileOutputTemplate
510 class GenericValidationData_CTSR(GenericValidationData):
513 "momentumconstraint":
"None",
514 "openmasswindow":
"False",
515 "cosmicsdecomode":
"True",
516 "removetrackhitfiltercommands":
"",
517 "appendtrackhitfiltercommands":
"",
520 result = super(GenericValidationData_CTSR, self).
getRepMap(alignment)
522 from .trackSplittingValidation
import TrackSplittingValidation
525 "istracksplitting":
str(isinstance(self, TrackSplittingValidation)),
532 for removeorappend
in "remove",
"append":
533 optionname = removeorappend +
"trackhitfiltercommands"
534 if result[optionname]:
535 for command
in result[optionname].
split(
","):
536 command = command.strip()
537 commands.append(
'process.TrackerTrackHitFilter.commands.{}("{}")'.
format(removeorappend, command))
538 result[
"trackhitfiltercommands"] =
"\n".
join(commands)
543 return "Cosmics" not in self.
general[
"trackcollection"]
549 return configTemplates.CommonTrackSelectionRefitting
552 return configTemplates.DefinePath_CommonSelectionRefitting
558 if "Cosmics" not in self.
general[
"trackcollection"]:
return False
559 Bfield = self.
dataset.magneticFieldForRun()
560 if Bfield < 0.5:
return True
561 if isinstance(Bfield, str):
562 if "unknown " in Bfield:
563 msg = Bfield.replace(
"unknown ",
"",1)
564 elif Bfield ==
"unknown":
565 msg =
"Can't get the B field for %s." % self.
dataset.
name()
567 msg =
"B field = {}???".
format(Bfield)
569 "To use this dataset, specify magneticfield = [value] in your .ini config file.")
582 from .plottingOptions
import PlottingOptions
585 if result
and result[-1] !=
"\n": result +=
"\n"
589 if result[-1] !=
"\n": result +=
"\n"
590 result += (
"if [[ tmpMergeRetCode -eq 0 ]]; then\n"
591 " xrdcp -f .oO[finalOutputFile]Oo. root://eoscms//eos/cms.oO[finalResultFile]Oo.\n"
593 "if [[ ${tmpMergeRetCode} -gt ${mergeRetCode} ]]; then\n"
594 " mergeRetCode=${tmpMergeRetCode}\n"
602 return (
"cp .oO[plottingscriptpath]Oo. .\n"
603 "root -x -b -q .oO[plottingscriptname]Oo.++")
609 """override with a classmethod"""
612 """override with a classmethod"""
615 """override with a classmethod"""
619 from .plottingOptions
import PlottingOptions
623 if result
and result[-1] !=
"\n": result +=
"\n"
627 from .plottingOptions
import PlottingOptions
629 filename =
replaceByMap(
".oO[plottingscriptpath]Oo.", repmap)
630 repmap[
"PlottingInstantiation"] =
"\n".
join(
631 replaceByMap(v.appendToPlots(), v.getRepMap()).rstrip(
"\n")
635 with open(filename,
'w')
as f:
636 f.write(plottingscript)
640 def __init__(self, name, values, format=None, latexname=None, latexformat=None):
642 name: name of the summary item, goes on top of the column
643 values: value for each alignment (in order of rows)
644 format: python format string (default: {:.3g}, meaning up to 3 significant digits)
645 latexname: name in latex form, e.g. if name=sigma you might want latexname=\sigma (default: name)
646 latexformat: format for latex (default: format)
648 if format
is None: format =
"{:.3g}"
649 if latexname
is None: latexname = name
650 if latexformat
is None: latexformat = format
669 if re.match(
".*[{][^}]*[fg][}].*", fmt):
671 return fmt.format(value)
678 return self.
values(latex)[i]
682 """override with a classmethod that returns a list of SummaryItems
683 based on the plots saved in folder"""
685 __summaryitems =
None
691 if folder.startswith(
"/castor/" ):
692 folder =
"rfio:%(file)s"%repMap
693 elif folder.startswith(
"/store/" ):
694 folder =
"root://eoscms.cern.ch//eos/cms%(file)s"%repMap
704 size = {len(_.values(latex))
for _
in summaryitems}
706 raise AllInOneError(
"Some summary items have different numbers of values\n{}".
format(size))
710 columnwidths = ([
max(len(_.name(latex))
for _
in summaryitems)]
711 + [
max(len(_.value(i, latex))
for _
in summaryitems)
for i
in range(size)])
713 columnwidths = [
max(len(entry)
for entry
in [_.name(latex)] + _.values(latex))
for _
in summaryitems]
719 row = join.join(
"{{:{}}}".
format(width)
for width
in columnwidths)
722 rows = [row.format(*[_.name(latex)]+_.values(latex))
for _
in summaryitems]
725 rows.append(row.format(*(_.name
for _
in summaryitems)))
726 for i
in range(size):
727 rows.append(row.format(*(_.value(i, latex)
for _
in summaryitems)))
733 result = join.join(rows)
735 result = (
r"\begin{{tabular}}{{{}}}".
format(
"|" +
"|".
join(
"c"*(len(columnwidths))) +
"|") +
"\n"
745 with open(filename,
"w")
as f:
752 with open(os.path.join(folder,
"{}Summary.txt".
format(cls.__name__)))
as f:
754 split = line.rstrip(
"\n").
split(
"\t")
756 for thing
in split[:]:
757 if thing.startswith(
"format="):
758 kwargs[
"format"] = thing.replace(
"format=",
"", 1)
760 if thing.startswith(
"latexname="):
761 kwargs[
"latexname"] = thing.replace(
"latexname=",
"", 1)
763 if thing.startswith(
"latexformat="):
764 kwargs[
"latexformat"] = thing.replace(
"latexformat=",
"", 1)
769 result.append(cls.
SummaryItem(name, values, **kwargs))
775 from .plottingOptions
import PlottingOptions
777 repmap[
"compareStrings"] =
" , ".
join(v.getCompareStrings(
"OfflineValidation")
for v
in validations)
778 repmap[
"compareStringsPlain"] =
" , ".
join(v.getCompareStrings(
"OfflineValidation",
True)
for v
in validations)
784 return configTemplates.compareAlignmentsExecution
787 return ".oO[Alignment/OfflineValidation]Oo./scripts/.oO[compareAlignmentsName]Oo."
792 class ValidationForPresentation(ValidationWithPlots):