4 from AnalysisAlgorithmsConfig.ConfigBlock
import ConfigBlock
5 from AthenaConfiguration.Enums
import LHCPeriod
6 from AnalysisAlgorithmsConfig.ConfigAccumulator
import DataType
12 ELECTRONS = [
'EG_',
'EL_']
14 PHOTONS = [
'EG_',
'PH_']
18 EVENT = [
'GEN_',
'PRW_']
22 """the ConfigBlock for common services
24 The idea here is that all algorithms need some common services, and I should
25 provide configuration blocks for those. For now there is just a single
26 block, but in the future I might break out e.g. the systematics service.
30 super (CommonServicesConfig, self).__init__ ()
31 self.addOption (
'runSystematics',
None, type=bool,
32 info=
"whether to turn on the computation of systematic variations. "
33 "The default is to run them on MC.")
34 self.addOption (
'filterSystematics',
None, type=str,
35 info=
"a regexp string against which the systematics names will be "
36 "matched. Only positive matches are retained and used in the evaluation "
37 "of the various algorithms.")
38 self.addOption (
'onlySystematicsCategories',
None, type=list,
39 info=
"a list of strings defining categories of systematics to enable "
40 "(only recommended for studies / partial ntuple productions). Choose amongst: "
41 "jets, electrons, muons, photons, taus, met, tracks, ftag, event. This option is overridden "
42 "by 'filterSystematics'.")
43 self.addOption (
'systematicsHistogram',
None , type=str,
44 info=
"the name (string) of the histogram to which a list of executed "
45 "systematics will be printed. The default is None (don't write out "
47 self.addOption (
'separateWeightSystematics',
False, type=bool,
48 info=
"if 'systematicsHistogram' is enabled, whether to create a separate "
49 "histogram holding only the names of weight-based systematics. This is useful "
50 "to help make histogramming frameworks more efficient by knowing in advance which "
51 "systematics need to recompute the observable and which don't.")
54 """Return the instance name for this block"""
59 sysService = config.createService(
'CP::SystematicsSvc',
'SystematicsSvc' )
63 elif config.noSystematics()
is not None :
72 sysService.sigmaRecommended = 1
73 if config.dataType()
is DataType.Data:
78 requested_categories = []
81 category_enum = SystematicsCategories[category_str.upper()]
82 requested_categories += category_enum.value
84 raise ValueError(f
"Invalid systematics category passed to option 'onlySystematicsCategories': {category_str}. Must be one of {', '.join(category.name for category in SystematicsCategories)}")
86 if len(requested_categories):
87 sysService.systematicsRegex =
"^(?=.*(" +
"|".
join(requested_categories) +
")|$).*"
88 if self.filterSystematics
is not None:
89 sysService.systematicsRegex = self.filterSystematics
90 config.createService(
'CP::SelectionNameSvc',
'SelectionNameSvc')
92 if self.systematicsHistogram
is not None:
94 allSysDumper = config.createAlgorithm(
'CP::SysListDumperAlg',
'SystematicsPrinter' )
95 allSysDumper.histogramName = self.systematicsHistogram
97 if self.separateWeightSystematics:
99 weightSysDumper = config.createAlgorithm(
'CP::SysListDumperAlg',
'OnlyWeightSystematicsPrinter' )
100 weightSysDumper.histogramName = f
"{self.systematicsHistogram}OnlyWeights"
101 weightSysDumper.systematicsRegex =
"^(GEN_|EL_EFF_|MUON_EFF_|PH_EFF_|TAUS_TRUEHADTAU_EFF_|FT_EFF_|extrapolation_pt_|JET_.*JvtEfficiency_|PRW_).*"
106 """Print what branches are used in analysis"""
109 super(IOStatsBlock, self).
__init__()
110 self.addOption(
"printOption",
"Summary", type=str,
111 info=
'option to pass the standard ROOT printing function. Can be "Summary", "ByEntries" or "ByBytes".')
114 """Return the instance name for this block"""
118 alg = config.createAlgorithm(
'CP::IOStatsAlg',
'IOStatsAlg')
119 alg.printOption = self.printOption
123 """the ConfigBlock for pileup reweighting"""
126 super (PileupReweightingBlock, self).__init__ ()
127 self.addOption (
'campaign',
None, type=
None,
128 info=
"the MC campaign for the PRW auto-configuration.")
129 self.addOption (
'files',
None, type=
None,
130 info=
"the input files being processed (list of strings). "
131 "Alternative to auto-configuration.")
132 self.addOption (
'useDefaultConfig',
True, type=bool,
133 info=
"whether to use the central PRW files. The default is True.")
134 self.addOption (
'userLumicalcFiles',
None, type=
None,
135 info=
"user-provided lumicalc files (list of strings). Alternative "
136 "to auto-configuration.")
137 self.addOption (
'userLumicalcFilesPerCampaign',
None, type=
None,
138 info=
"user-provided lumicalc files (dictionary of list of strings, "
139 "with MC campaigns as the keys). Alternative to auto-configuration.")
140 self.addOption (
'userPileupConfigs',
None, type=
None,
141 info=
"user-provided PRW files (list of strings). Alternative to "
142 "auto-configuration. Alternative to auto-configuration.")
143 self.addOption (
'userPileupConfigsPerCampaign',
None, type=
None,
144 info=
"user-provided PRW files (dictionary of list of strings, with "
145 "MC campaigns as the keys)")
146 self.addOption (
'postfix',
'', type=str,
147 info=
"a postfix to apply to decorations and algorithm names. "
148 "Typically not needed unless several instances of PileupReweighting are scheduled.")
149 self.addOption (
'alternativeConfig',
False, type=bool,
150 info=
"whether this is used as an additional alternative config for PileupReweighting. "
151 "Will only store the alternative pile up weight in that case.")
152 self.addOption (
'writeColumnarToolVariables',
False, type=bool,
153 info=
"whether to add EventInfo variables needed for running the columnar tool(s) on the output n-tuple. (EXPERIMENTAL)")
156 """Return the instance name for this block"""
161 from Campaigns.Utils
import Campaign
164 from AthenaCommon.Logging
import logging
167 log = logging.getLogger(
'makePileupAnalysisSequence')
169 eventInfoVar = [
'runNumber',
'eventNumber',
'actualInteractionsPerCrossing',
'averageInteractionsPerCrossing']
170 if config.dataType()
is not DataType.Data:
171 eventInfoVar += [
'mcChannelNumber']
172 if self.writeColumnarToolVariables:
176 eventInfoVar += [
'eventTypeBitmask']
178 if config.isPhyslite()
and not self.alternativeConfig:
180 log.info(f
'Physlite does not need pileup reweighting. Variables will be copied from input instead. {config.isPhyslite}')
181 for var
in eventInfoVar:
182 config.addOutputVar (
'EventInfo', var, var, noSys=
True)
184 if config.dataType()
is not DataType.Data:
185 config.addOutputVar (
'EventInfo',
'PileupWeight_%SYS%',
'weight_pileup')
186 if config.geometry()
is LHCPeriod.Run2:
187 config.addOutputVar (
'EventInfo',
'beamSpotWeight',
'weight_beamspot', noSys=
True)
191 if self.
files is None and config.flags
is not None:
192 self.
files = config.flags.Input.Files
194 campaign = self.campaign
197 if config.dataType()
is not DataType.Data
and self.campaign
is None:
199 if config.campaign()
is not None and config.campaign()
is not Campaign.Unknown:
200 campaign = config.campaign()
201 log.info(f
'Auto-configuring campaign for PRW from flags: {campaign.value}')
204 if self.
files is not None:
205 from Campaigns.Utils
import getMCCampaign
207 if campaign
and campaign
is not Campaign.Unknown:
208 log.info(f
'Auto-configuring campaign for PRW from files: {campaign.value}')
210 log.info(
'Campaign could not be determined.')
214 toolLumicalcFiles = []
218 if (config.dataType()
is not DataType.Data
and
219 config.geometry()
is not LHCPeriod.Run4):
221 if self.userPileupConfigs
is not None and self.userPileupConfigsPerCampaign
is not None:
222 raise ValueError(
'Both userPileupConfigs and userPileupConfigsPerCampaign specified, '
223 'use only one of the options!')
224 if self.userPileupConfigsPerCampaign
is not None:
226 raise Exception(
'userPileupConfigsPerCampaign requires campaign to be configured!')
227 if campaign
is Campaign.Unknown:
228 raise Exception(
'userPileupConfigsPerCampaign used, but campaign = Unknown!')
230 toolConfigFiles = self.userPileupConfigsPerCampaign[campaign.value][:]
231 log.info(
'Using user provided per-campaign PRW configuration')
232 except KeyError
as e:
233 raise KeyError(f
'Unconfigured campaign {e} for userPileupConfigsPerCampaign!')
235 elif self.userPileupConfigs
is not None:
236 toolConfigFiles = self.userPileupConfigs[:]
237 log.info(
'Using user provided PRW configuration')
240 if self.useDefaultConfig
and self.
files is None:
241 raise ValueError(
'useDefaultConfig requires files to be configured! '
242 'Either pass them as an option or use flags.')
244 from PileupReweighting.AutoconfigurePRW
import getConfigurationFiles
245 if campaign
and campaign
is not Campaign.Unknown:
248 useDefaultConfig=self.useDefaultConfig,
249 data_type=config.dataType())
250 if self.useDefaultConfig:
251 log.info(
'Auto-configuring universal/default PRW config')
253 log.info(
'Auto-configuring per-sample PRW config files based on input files')
255 log.info(
'No campaign specified, no PRW config files configured')
258 if self.userLumicalcFilesPerCampaign
is not None and self.userLumicalcFiles
is not None:
259 raise ValueError(
'Both userLumicalcFiles and userLumicalcFilesYear specified, '
260 'use only one of the options!')
261 if self.userLumicalcFilesPerCampaign
is not None:
263 toolLumicalcFiles = self.userLumicalcFilesPerCampaign[campaign.value][:]
264 log.info(
'Using user-provided per-campaign lumicalc files')
265 except KeyError
as e:
266 raise KeyError(f
'Unconfigured campaign {e} for userLumicalcFilesPerCampaign!')
267 elif self.userLumicalcFiles
is not None:
268 toolLumicalcFiles = self.userLumicalcFiles[:]
269 log.info(
'Using user-provided lumicalc files')
271 if campaign
and campaign
is not Campaign.Unknown:
272 from PileupReweighting.AutoconfigurePRW
import getLumicalcFiles
274 log.info(
'Using auto-configured lumicalc files')
276 log.info(
'No campaign specified, no lumicalc files configured for PRW')
278 log.info(
'Data needs no lumicalc and PRW configuration files')
281 if config.geometry()
is LHCPeriod.Run4:
282 log.warning (
'Pileup reweighting is not yet supported for Run 4 geometry')
283 alg = config.createAlgorithm(
'CP::EventDecoratorAlg',
'EventDecoratorAlg' )
284 alg.uint32Decorations = {
'RandomRunNumber' :
285 config.flags.Input.RunNumbers[0] }
288 alg = config.createAlgorithm(
'CP::PileupReweightingAlg',
289 'PileupReweightingAlg' )
290 config.addPrivateTool(
'pileupReweightingTool',
'CP::PileupReweightingTool' )
291 alg.pileupReweightingTool.ConfigFiles = toolConfigFiles
292 if not toolConfigFiles
and config.dataType()
is not DataType.Data:
293 log.info(
"No PRW config files provided. Disabling reweighting")
295 alg.pileupWeightDecoration =
""
297 alg.pileupWeightDecoration =
"PileupWeight" + self.postfix +
"_%SYS%"
298 alg.pileupReweightingTool.LumiCalcFiles = toolLumicalcFiles
300 if not self.alternativeConfig:
301 for var
in eventInfoVar:
302 config.addOutputVar (
'EventInfo', var, var, noSys=
True)
304 if config.dataType()
is not DataType.Data
and config.geometry()
is LHCPeriod.Run2:
305 config.addOutputVar (
'EventInfo',
'beamSpotWeight',
'weight_beamspot', noSys=
True)
307 if config.dataType()
is not DataType.Data
and toolConfigFiles:
308 config.addOutputVar (
'EventInfo',
'PileupWeight' + self.postfix +
'_%SYS%',
309 'weight_pileup'+self.postfix)
313 """the ConfigBlock for generator algorithms"""
316 super (GeneratorAnalysisBlock, self).__init__ ()
317 self.addOption (
'saveCutBookkeepers',
True, type=bool,
318 info=
"whether to save the cut bookkeepers information into the "
319 "output file. The default is True.")
320 self.addOption (
'runNumber',
None, type=int,
321 info=
"the MC runNumber (int). The default is None (autoconfigure "
323 self.addOption (
'cutBookkeepersSystematics',
None, type=bool,
324 info=
"whether to also save the cut bookkeepers systematics. The "
325 "default is None (follows the global systematics flag). Set to "
326 "False or True to override.")
327 self.addOption (
'histPattern',
None, type=str,
328 info=
"the histogram name pattern for the cut-bookkeeper histogram names")
329 self.addOption (
'streamName',
'ANALYSIS', type=str,
330 info=
"name of the output stream to save the cut bookkeeper in. "
331 "The default is ANALYSIS.")
332 self.addOption (
'detailedPDFinfo',
False, type=bool,
333 info=
"save the necessary information to run the LHAPDF tool offline. "
334 "The default is False.")
335 self.addOption (
'doHFProdFracReweighting',
False, type=bool,
336 info=
"whether to apply HF production fraction reweighting. "
337 "The default is False.")
338 self.addOption (
'truthParticleContainer',
'TruthParticles', type=str,
339 info=
"the name of the truth particle container to use for HF production fraction reweighting. "
340 "The default is 'TruthParticles'. ")
342 """Return the instance name for this block"""
343 return self.streamName
347 if config.dataType()
is DataType.Data:
351 from AthenaCommon.Logging
import logging
354 log = logging.getLogger(
'makeGeneratorAnalysisSequence')
359 if self.saveCutBookkeepers
and not self.
runNumber:
360 raise ValueError (
"invalid run number: " +
str(self.
runNumber))
363 if self.saveCutBookkeepers:
364 alg = config.createAlgorithm(
'CP::AsgCutBookkeeperAlg',
'CutBookkeeperAlg')
365 alg.RootStreamName = self.streamName
367 if self.cutBookkeepersSystematics
is None:
368 alg.enableSystematics =
not config.noSystematics()
370 alg.enableSystematics = self.cutBookkeepersSystematics
372 alg.histPattern = self.histPattern
373 config.addPrivateTool(
'truthWeightTool',
'PMGTools::PMGTruthWeightTool' )
376 alg = config.createAlgorithm(
'CP::PMGTruthWeightAlg',
'PMGTruthWeightAlg' )
377 config.addPrivateTool(
'truthWeightTool',
'PMGTools::PMGTruthWeightTool' )
378 alg.decoration =
'generatorWeight_%SYS%'
379 config.addOutputVar (
'EventInfo',
'generatorWeight_%SYS%',
'weight_mc')
381 if self.detailedPDFinfo:
382 alg = config.createAlgorithm(
'CP::PDFinfoAlg',
'PDFinfoAlg', reentrant=
True )
383 for var
in [
"PDFID1",
"PDFID2",
"PDGID1",
"PDGID2",
"Q",
"X1",
"X2",
"XF1",
"XF2"]:
384 config.addOutputVar (
'EventInfo', var,
'PDFinfo_' + var, noSys=
True)
386 if self.doHFProdFracReweighting:
387 generatorInfo = config.flags.Input.GeneratorsInfo
388 log.info(f
"Loaded generator info: {generatorInfo}")
392 if not generatorInfo:
393 log.warning(
"No generator info found.")
395 elif isinstance(generatorInfo, dict):
396 if "Pythia8" in generatorInfo:
398 elif "Sherpa" in generatorInfo
and "2.2.8" in generatorInfo[
"Sherpa"]:
400 elif "Sherpa" in generatorInfo
and "2.2.10" in generatorInfo[
"Sherpa"]:
402 elif "Sherpa" in generatorInfo
and "2.2.11" in generatorInfo[
"Sherpa"]:
403 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.11. Using weights for Sherpa 2.2.10 instead.")
405 elif "Sherpa" in generatorInfo
and "2.2.12" in generatorInfo[
"Sherpa"]:
406 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.12. Using weights for Sherpa 2.2.10 instead.")
408 elif "Sherpa" in generatorInfo
and "2.2.14" in generatorInfo[
"Sherpa"]:
409 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.14. New weights need to be calculated.")
411 elif "Sherpa" in generatorInfo
and "2.2.1" in generatorInfo[
"Sherpa"]:
413 elif "Herwig7" in generatorInfo
and "7.1.3" in generatorInfo[
"Herwig7"]:
415 elif "Herwig7" in generatorInfo
and "7.2.1" in generatorInfo[
"Herwig7"]:
417 elif "Herwig7" in generatorInfo
and "7." in generatorInfo[
"Herwig7"]:
419 elif "amc@NLO" in generatorInfo:
422 log.warning(f
"HF production fraction reweighting is not configured for this generator: {generatorInfo}")
423 log.warning(
"New weights need to be calculated.")
426 log.warning(
"Failed to determine generator from metadata")
429 log.info(f
"Using HF production fraction weights calculated using DSID {DSID}")
431 log.warning(
"HF production fraction reweighting will return dummy weights of 1.0")
433 alg = config.createAlgorithm(
'CP::SysTruthWeightAlg',
'SysTruthWeightAlg' + self.streamName )
434 config.addPrivateTool(
'sysTruthWeightTool',
'PMGTools::PMGHFProductionFractionTool' )
435 alg.decoration =
'prodFracWeight_%SYS%'
436 alg.TruthParticleContainer = self.truthParticleContainer
437 alg.sysTruthWeightTool.ShowerGenerator = DSID
438 config.addOutputVar (
'EventInfo',
'prodFracWeight_%SYS%',
'weight_HF_prod_frac')
441 """the ConfigBlock for a pt-eta selection"""
444 super (PtEtaSelectionBlock, self).__init__ ()
445 self.addOption (
'containerName',
'', type=str,
447 info=
"the name of the input container.")
448 self.addOption (
'selectionName',
'', type=str,
450 info=
"the name of the selection to append this to. The default is "
451 "'' (empty string), meaning that the cuts are applied to every "
452 "object within the container. Specifying a name (e.g. loose) "
453 "applies the cut only to those object who also pass that selection.")
454 self.addOption (
'minPt',
None, type=float,
455 info=
"minimum pT value to cut on, in MeV. No default value.")
456 self.addOption (
'maxPt',
None, type=float,
457 info=
"maximum pT value to cut on, in MeV. No default value.")
458 self.addOption (
'minEta',
None, type=float,
459 info=
"minimum |eta| value to cut on. No default value.")
460 self.addOption (
'maxEta',
None, type=float,
461 info=
"maximum |eta| value to cut on. No default value.")
462 self.addOption (
'maxRapidity',
None, type=float,
463 info=
"maximum rapidity value to cut on. No default value.")
464 self.addOption (
'etaGapLow',
None, type=float,
465 info=
"low end of the |eta| gap. No default value.")
466 self.addOption (
'etaGapHigh',
None, type=float,
467 info=
"high end of the |eta| gap. No default value.")
468 self.addOption (
'selectionDecoration',
None, type=str,
469 info=
"the name of the decoration to set. If 'None', will be set "
470 "to 'selectPtEta' followed by the selection name.")
471 self.addOption (
'useClusterEta',
False, type=bool,
472 info=
"whether to use the cluster eta (etaBE(2)) instead of the object "
473 "eta (for electrons and photons). The default is False.")
474 self.addOption (
'useDressedProperties',
False, type=bool,
475 info=
"whether to use the dressed kinematic properties "
476 "(for truth particles only). The default is False.")
479 """Return the instance name for this block"""
480 return self.containerName +
"_" + self.selectionName
484 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'PtEtaSelectionAlg' )
485 config.addPrivateTool(
'selectionTool',
'CP::AsgPtEtaSelectionTool' )
486 if self.minPt
is not None :
487 alg.selectionTool.minPt = self.minPt
488 if self.maxPt
is not None:
489 alg.selectionTool.maxPt = self.maxPt
490 if self.minEta
is not None:
491 alg.selectionTool.minEta = self.minEta
492 if self.maxEta
is not None :
493 alg.selectionTool.maxEta = self.maxEta
494 if self.maxRapidity
is not None :
495 alg.selectionTool.maxRapidity = self.maxRapidity
496 if self.etaGapLow
is not None:
497 alg.selectionTool.etaGapLow = self.etaGapLow
498 if self.etaGapHigh
is not None:
499 alg.selectionTool.etaGapHigh = self.etaGapHigh
502 alg.selectionTool.useClusterEta = self.useClusterEta
503 alg.selectionTool.useDressedProperties = self.useDressedProperties
505 alg.particles = config.readName (self.containerName)
506 alg.preselection = config.getPreselection (self.containerName,
'')
507 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration)
512 """the ConfigBlock for an object cutflow"""
515 super (ObjectCutFlowBlock, self).__init__ ()
516 self.addOption (
'containerName',
'', type=str,
518 info=
"the name of the input container.")
519 self.addOption (
'selectionName',
'', type=str,
521 info=
"the name of the selection to perform the cutflow for. The "
522 "default is '' (empty string), meaning that the cutflow is "
523 "performed for every object within the container. Specifying a "
524 "name (e.g. loose) generates the cutflow only for those object "
525 "that also pass that selection.")
526 self.addOption (
'forceCutSequence',
False, type=bool,
527 info=
"whether to force the cut sequence and not accept objects "
528 "if previous cuts failed. The default is False.")
531 """Return the instance name for this block"""
532 return self.containerName +
'_' + self.selectionName
536 alg = config.createAlgorithm(
'CP::ObjectCutFlowHistAlg',
'CutFlowDumperAlg' )
537 alg.histPattern =
'cflow_' + self.containerName +
"_" + self.selectionName +
'_%SYS%'
538 alg.selections = config.getSelectionCutFlow (self.containerName, self.selectionName)
539 alg.input = config.readName (self.containerName)
540 alg.histTitle =
"Object Cutflow: " + self.containerName +
"." + self.selectionName
541 alg.forceCutSequence = self.forceCutSequence
545 """the ConfigBlock for an event-level cutflow"""
548 super (EventCutFlowBlock, self).__init__ ()
549 self.addOption (
'containerName',
'', type=str,
551 info=
"the name of the input container, typically EventInfo.")
552 self.addOption (
'selectionName',
'', type=str,
554 info=
"the name of an optional selection decoration to use.")
555 self.addOption (
'customSelections', [], type=
None,
556 info=
"the selections for which to generate cutflow histograms. If "
557 "a single string, corresponding to a particular event selection, "
558 "the event cutflow for that selection will be looked up. If a list "
559 "of strings, will use explicitly those selections. If left blank, "
560 "all selections attached to the container will be looked up.")
561 self.addOption (
'postfix',
'', type=str,
562 info=
"a postfix to apply in the naming of cutflow histograms. Set "
563 "it when defining multiple cutflows.")
566 """Return the instance name for this block"""
567 return self.containerName +
'_' + self.selectionName + self.postfix
571 postfix = self.postfix
572 if postfix !=
'' and postfix[0] !=
'_' :
573 postfix =
'_' + postfix
575 alg = config.createAlgorithm(
'CP::EventCutFlowHistAlg',
'CutFlowDumperAlg' )
576 alg.histPattern =
'cflow_' + self.containerName +
"_" + self.selectionName + postfix +
'_%SYS%'
578 if isinstance(self.customSelections, str):
580 alg.selections = config.getEventCutFlow(self.customSelections)
581 elif len(self.customSelections) > 0:
583 alg.selections = self.customSelections
586 alg.selections = config.getSelectionCutFlow (self.containerName, self.selectionName)
587 alg.selections = [sel+
',as_char' for sel
in alg.selections]
588 if self.selectionName:
589 alg.preselection = self.selectionName +
'_%SYS%'
590 alg.eventInfo = config.readName (self.containerName)
591 alg.histTitle =
"Event Cutflow: " + self.containerName +
"." + self.selectionName
595 """the ConfigBlock for output thinning"""
598 super (OutputThinningBlock, self).__init__ ()
599 self.addOption (
'containerName',
'', type=str,
601 info=
"the name of the input container.")
602 self.addOption (
'postfix',
'', type=str,
603 info=
"a postfix to apply to decorations and algorithm names. "
604 "Typically not needed here.")
605 self.addOption (
'selection',
'', type=str,
606 info=
"the name of an optional selection decoration to use.")
607 self.addOption (
'selectionName',
'', type=str,
608 info=
"the name of the selection to append this to. The default is "
609 "'' (empty string), meaning that the cuts are applied to every "
610 "object within the container. Specifying a name (e.g. loose) "
611 "applies the cut only to those object who also pass that selection.")
612 self.addOption (
'outputName',
None, type=str,
613 info=
"an optional name for the output container.")
615 self.addOption (
'deepCopy',
False, type=bool,
617 self.addOption (
'sortPt',
False, type=bool,
618 info=
"whether to sort objects in pt")
620 self.addOption (
'noUniformSelection',
False, type=bool,
624 """Return the instance name for this block"""
625 return self.containerName +
'_' + self.selectionName + self.postfix
629 postfix = self.postfix
630 if postfix !=
'' and postfix[0] !=
'_' :
631 postfix =
'_' + postfix
633 selection = config.getFullSelection (self.containerName, self.selectionName)
635 selection = self.selection
636 elif self.selection !=
'' :
637 selection = selection +
'&&' + self.selection
639 if selection !=
'' and not self.noUniformSelection :
640 alg = config.createAlgorithm(
'CP::AsgUnionSelectionAlg',
'UnionSelectionAlg')
641 alg.preselection = selection
642 alg.particles = config.readName (self.containerName)
643 alg.selectionDecoration =
'outputSelect' + postfix
644 config.addSelection (self.containerName, alg.selectionDecoration, selection)
645 selection =
'outputSelect' + postfix
647 alg = config.createAlgorithm(
'CP::AsgViewFromSelectionAlg',
'DeepCopyAlg' )
648 alg.input = config.readName (self.containerName)
649 if self.outputName
is not None :
650 alg.output = self.outputName +
'_%SYS%'
651 config.addOutputContainer (self.containerName, self.outputName)
653 alg.output = config.copyName (self.containerName)
655 alg.selection = [selection]
658 alg.deepCopy = self.deepCopy
659 if self.sortPt
and not config.noSystematics() :
660 raise ValueError (
"Sorting by pt is not supported with systematics")
661 alg.sortPt = self.sortPt
665 """the ConfigBlock for the IFF classification of leptons"""
668 super (IFFLeptonDecorationBlock, self).
__init__()
669 self.addOption (
'containerName',
'', type=str,
671 info=
"the name of the input electron or muon container.")
672 self.addOption (
'separateChargeFlipElectrons',
True, type=bool,
673 info=
"whether to consider charged-flip electrons as a separate class. "
674 "The default is True (recommended).")
675 self.addOption (
'decoration',
'IFFClass_%SYS%', type=str,
676 info=
"the name (str) of the decoration set by the IFF "
677 "TruthClassificationTool. The default is 'IFFClass_%SYS%'.")
679 self.setOptionValue(
'skipOnData',
True)
682 """Return the instance name for this block"""
683 return self.containerName
686 particles = config.readName(self.containerName)
688 alg = config.createAlgorithm(
'CP::AsgClassificationDecorationAlg',
'IFFClassifierAlg' )
690 config.addPrivateTool(
'tool',
'TruthClassificationTool')
692 alg.tool.separateChargeFlipElectrons = self.separateChargeFlipElectrons
693 alg.decoration = self.decoration
694 alg.particles = particles
697 config.addOutputVar(self.containerName, alg.decoration, alg.decoration.split(
"_%SYS%")[0], noSys=
True)
703 super (MCTCLeptonDecorationBlock, self).__init__ ()
705 self.addOption (
"containerName",
'', type=str,
707 info=
"the input lepton container, with a possible selection, "
708 "in the format container or container.selection.")
709 self.addOption (
"prefix",
'MCTC_', type=str,
710 info=
"the prefix (str) of the decorations based on the MCTC "
711 "classification. The default is 'MCTC_'.")
713 self.setOptionValue(
'skipOnData',
True)
716 """Return the instance name for this block"""
717 return self.containerName
720 particles, selection = config.readNameAndSelection(self.containerName)
722 alg = config.createAlgorithm (
"CP::MCTCDecorationAlg",
"MCTCDecorationAlg")
723 alg.particles = particles
724 alg.preselection = selection
725 alg.affectingSystematicsFilter =
'.*'
726 config.addOutputVar (self.containerName,
"MCTC_isPrompt", f
"{self.prefix}isPrompt", noSys=
True)
727 config.addOutputVar (self.containerName,
"MCTC_fromHadron", f
"{self.prefix}fromHadron", noSys=
True)
728 config.addOutputVar (self.containerName,
"MCTC_fromBSM", f
"{self.prefix}fromBSM", noSys=
True)
729 config.addOutputVar (self.containerName,
"MCTC_fromTau", f
"{self.prefix}fromTau", noSys=
True)
733 """the ConfigBlock for the AsgEventScaleFactorAlg"""
736 super(PerEventSFBlock, self).
__init__()
737 self.addOption(
'algoName',
None, type=str,
738 info=
"unique name given to the underlying algorithm computing the "
739 "per-event scale factors")
740 self.addOption(
'particles',
'', type=str,
741 info=
"the input object container, with a possible selection, in the "
742 "format container or container.selection.")
743 self.addOption(
'objectSF',
'', type=str,
744 info=
"the name of the per-object SF decoration to be used.")
745 self.addOption(
'eventSF',
'', type=str,
746 info=
"the name of the per-event SF decoration.")
749 """Return the instance name for this block"""
750 return self.particles +
'_' + self.objectSF +
'_' + self.eventSF
753 if config.dataType()
is DataType.Data:
755 particles, selection = config.readNameAndSelection(self.particles)
756 alg = config.createAlgorithm(
'CP::AsgEventScaleFactorAlg', self.algoName
if self.algoName
else 'AsgEventScaleFactorAlg')
757 alg.particles = particles
758 alg.preselection = selection
759 alg.scaleFactorInputDecoration = self.objectSF
760 alg.scaleFactorOutputDecoration = self.eventSF
762 config.addOutputVar(
'EventInfo', alg.scaleFactorOutputDecoration,
763 alg.scaleFactorOutputDecoration.split(
"_%SYS%")[0])
767 """the ConfigBlock to add selection decoration to a container"""
770 super (SelectionDecorationBlock, self).__init__ ()
772 self.addOption(
'containers', [], type=list,
777 """Return the instance name for this block"""
781 for container
in self.containers:
782 originContainerName = config.getOutputContainerOrigin(container)
783 selectionNames = config.getSelectionNames(originContainerName)
784 for selectionName
in selectionNames:
786 if selectionName ==
'':
788 alg = config.createAlgorithm(
789 'CP::AsgSelectionAlg',
790 f
'SelectionDecoration_{originContainerName}_{selectionName}')
791 selectionDecoration = f
'baselineSelection_{selectionName}_%SYS%'
792 alg.selectionDecoration = f
'{selectionDecoration},as_char'
793 alg.particles = config.readName (originContainerName)
794 alg.preselection = config.getFullSelection (originContainerName,
797 originContainerName, selectionDecoration, selectionName)
800 *, postfix=None, selectionName, customSelections=None):
801 """Create an event-level cutflow config
804 containerName -- name of the container
805 postfix -- a postfix to apply to decorations and algorithm names.
806 selectionName -- the name of the selection to do the cutflow for
807 customSelections -- a list of decorations to use in the cutflow, to override the retrieval of all decorations
811 config.setOptionValue(
'containerName', containerName)
812 config.setOptionValue(
'selectionName', selectionName)
813 config.setOptionValue(
'postfix', postfix)
814 config.setOptionValue(
'customSelections', customSelections)