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_']
17 EVENT = [
'GEN_',
'PRW_']
21 """the ConfigBlock for common services
23 The idea here is that all algorithms need some common services, and I should
24 provide configuration blocks for those. For now there is just a single
25 block, but in the future I might break out e.g. the systematics service.
29 super (CommonServicesConfig, self).__init__ ()
30 self.addOption (
'runSystematics',
None, type=bool,
31 info=
"whether to turn on the computation of systematic variations. "
32 "The default is to run them on MC.")
33 self.addOption (
'filterSystematics',
None, type=str,
34 info=
"a regexp string against which the systematics names will be "
35 "matched. Only positive matches are retained and used in the evaluation "
36 "of the various algorithms.")
37 self.addOption (
'onlySystematicsCategories',
None, type=list,
38 info=
"a list of strings defining categories of systematics to enable "
39 "(only recommended for studies / partial ntuple productions). Choose amongst: "
40 "jets, electrons, muons, photons, taus, met, ftag, event. This option is overridden "
41 "by 'filterSystematics'.")
42 self.addOption (
'systematicsHistogram',
None , type=str,
43 info=
"the name (string) of the histogram to which a list of executed "
44 "systematics will be printed. The default is None (don't write out "
49 sysService = config.createService(
'CP::SystematicsSvc',
'SystematicsSvc' )
53 elif config.noSystematics()
is not None :
62 sysService.sigmaRecommended = 1
63 if config.dataType()
is DataType.Data:
68 requested_categories = []
71 category_enum = SystematicsCategories[category_str.upper()]
72 requested_categories += category_enum.value
74 raise ValueError(f
"Invalid systematics category passed to option 'onlySystematicsCategories': {category_str}. Must be one of {', '.join(category.name for category in SystematicsCategories)}")
76 if len(requested_categories):
77 sysService.systematicsRegex =
"^(?=.*(" +
"|".
join(requested_categories) +
")|$).*"
78 if self.filterSystematics
is not None:
79 sysService.systematicsRegex = self.filterSystematics
80 config.createService(
'CP::SelectionNameSvc',
'SelectionNameSvc')
82 if self.systematicsHistogram
is not None:
83 sysDumper = config.createAlgorithm(
'CP::SysListDumperAlg',
'SystematicsPrinter' )
84 sysDumper.histogramName = self.systematicsHistogram
88 """Print what branches are used in analysis"""
92 self.addOption(
"printOption",
"Summary", type=str,
93 info=
'option to pass the standard ROOT printing function. Can be "Summary", "ByEntries" or "ByBytes".')
96 alg = config.createAlgorithm(
'CP::IOStatsAlg',
'IOStatsAlg')
97 alg.printOption = self.printOption
101 """the ConfigBlock for pileup reweighting"""
104 super (PileupReweightingBlock, self).__init__ ()
105 self.addOption (
'campaign',
None, type=
None,
106 info=
"the MC campaign for the PRW auto-configuration.")
107 self.addOption (
'files',
None, type=
None,
108 info=
"the input files being processed (list of strings). "
109 "Alternative to auto-configuration.")
110 self.addOption (
'useDefaultConfig',
True, type=bool,
111 info=
"whether to use the central PRW files. The default is True.")
112 self.addOption (
'userLumicalcFiles',
None, type=
None,
113 info=
"user-provided lumicalc files (list of strings). Alternative "
114 "to auto-configuration.")
115 self.addOption (
'userLumicalcFilesPerCampaign',
None, type=
None,
116 info=
"user-provided lumicalc files (dictionary of list of strings, "
117 "with MC campaigns as the keys). Alternative to auto-configuration.")
118 self.addOption (
'userPileupConfigs',
None, type=
None,
119 info=
"user-provided PRW files (list of strings). Alternative to "
120 "auto-configuration. Alternative to auto-configuration.")
121 self.addOption (
'userPileupConfigsPerCampaign',
None, type=
None,
122 info=
"user-provided PRW files (dictionary of list of strings, with "
123 "MC campaigns as the keys)")
124 self.addOption (
'postfix',
'', type=str,
125 info=
"a postfix to apply to decorations and algorithm names. "
126 "Typically not needed unless several instances of PileupReweighting are scheduled.")
127 self.addOption (
'alternativeConfig',
False, type=bool,
128 info=
"whether this is used as an additional alternative config for PileupReweighting. "
129 "Will only store the alternative pile up weight in that case.")
134 from Campaigns.Utils
import Campaign
137 from AthenaCommon.Logging
import logging
140 log = logging.getLogger(
'makePileupAnalysisSequence')
142 eventInfoVar = [
'runNumber',
'eventNumber',
'actualInteractionsPerCrossing',
'averageInteractionsPerCrossing']
143 if config.dataType()
is not DataType.Data:
144 eventInfoVar += [
'mcChannelNumber']
146 if config.isPhyslite()
and not self.alternativeConfig:
148 log.info(f
'Physlite does not need pileup reweighting. Variables will be copied from input instead. {config.isPhyslite}')
149 for var
in eventInfoVar:
150 config.addOutputVar (
'EventInfo', var, var, noSys=
True)
152 if config.dataType()
is not DataType.Data:
153 config.addOutputVar (
'EventInfo',
'PileupWeight_%SYS%',
'weight_pileup')
154 if config.geometry()
is LHCPeriod.Run2:
155 config.addOutputVar (
'EventInfo',
'beamSpotWeight',
'weight_beamspot', noSys=
True)
159 if self.
files is None and config.autoconfigFlags()
is not None:
160 self.
files = config.autoconfigFlags().Input.Files
162 campaign = self.campaign
165 if config.dataType()
is not DataType.Data
and self.campaign
is None:
167 if config.campaign()
is not None and config.campaign()
is not Campaign.Unknown:
168 campaign = config.campaign()
169 log.info(f
'Auto-configuring campaign for PRW from flags: {campaign.value}')
172 if self.
files is not None:
173 from Campaigns.Utils
import getMCCampaign
175 if campaign
and campaign
is not Campaign.Unknown:
176 log.info(f
'Auto-configuring campaign for PRW from files: {campaign.value}')
178 log.info(
'Campaign could not be determined.')
182 toolLumicalcFiles = []
186 if (config.dataType()
is not DataType.Data
and
187 config.geometry()
is not LHCPeriod.Run4):
189 if self.userPileupConfigs
is not None and self.userPileupConfigsPerCampaign
is not None:
190 raise ValueError(
'Both userPileupConfigs and userPileupConfigsPerCampaign specified, '
191 'use only one of the options!')
192 if self.userPileupConfigsPerCampaign
is not None:
194 raise Exception(
'userPileupConfigsPerCampaign requires campaign to be configured!')
195 if campaign
is Campaign.Unknown:
196 raise Exception(
'userPileupConfigsPerCampaign used, but campaign = Unknown!')
198 toolConfigFiles = self.userPileupConfigsPerCampaign[campaign.value][:]
199 log.info(
'Using user provided per-campaign PRW configuration')
200 except KeyError
as e:
201 raise KeyError(f
'Unconfigured campaign {e} for userPileupConfigsPerCampaign!')
203 elif self.userPileupConfigs
is not None:
204 toolConfigFiles = self.userPileupConfigs[:]
205 log.info(
'Using user provided PRW configuration')
208 if self.useDefaultConfig
and self.
files is None:
209 raise ValueError(
'useDefaultConfig requires files to be configured! '
210 'Either pass them as an option or use flags.')
212 from PileupReweighting.AutoconfigurePRW
import getConfigurationFiles
213 if campaign
and campaign
is not Campaign.Unknown:
216 useDefaultConfig=self.useDefaultConfig,
217 data_type=config.dataType())
218 if self.useDefaultConfig:
219 log.info(
'Auto-configuring universal/default PRW config')
221 log.info(
'Auto-configuring per-sample PRW config files based on input files')
223 log.info(
'No campaign specified, no PRW config files configured')
226 if self.userLumicalcFilesPerCampaign
is not None and self.userLumicalcFiles
is not None:
227 raise ValueError(
'Both userLumicalcFiles and userLumicalcFilesYear specified, '
228 'use only one of the options!')
229 if self.userLumicalcFilesPerCampaign
is not None:
231 toolLumicalcFiles = self.userLumicalcFilesPerCampaign[campaign.value][:]
232 log.info(
'Using user-provided per-campaign lumicalc files')
233 except KeyError
as e:
234 raise KeyError(f
'Unconfigured campaign {e} for userLumicalcFilesPerCampaign!')
235 elif self.userLumicalcFiles
is not None:
236 toolLumicalcFiles = self.userLumicalcFiles[:]
237 log.info(
'Using user-provided lumicalc files')
239 if campaign
and campaign
is not Campaign.Unknown:
240 from PileupReweighting.AutoconfigurePRW
import getLumicalcFiles
242 log.info(
'Using auto-configured lumicalc files')
244 log.info(
'No campaign specified, no lumicalc files configured for PRW')
246 log.info(
'Data needs no lumicalc and PRW configuration files')
249 if config.geometry()
is LHCPeriod.Run4:
250 log.warning (
'Pileup reweighting is not yet supported for Run 4 geometry')
251 alg = config.createAlgorithm(
'CP::EventDecoratorAlg',
'EventDecoratorAlg'+self.postfix )
252 alg.uint32Decorations = {
'RandomRunNumber' :
253 config.autoconfigFlags().Input.RunNumbers[0] }
256 alg = config.createAlgorithm(
'CP::PileupReweightingAlg',
257 'PileupReweightingAlg'+self.postfix )
258 config.addPrivateTool(
'pileupReweightingTool',
'CP::PileupReweightingTool' )
259 alg.pileupReweightingTool.ConfigFiles = toolConfigFiles
260 if not toolConfigFiles
and config.dataType()
is not DataType.Data:
261 log.info(
"No PRW config files provided. Disabling reweighting")
263 alg.pileupWeightDecoration =
""
265 alg.pileupWeightDecoration =
"PileupWeight" + self.postfix +
"_%SYS%"
266 alg.pileupReweightingTool.LumiCalcFiles = toolLumicalcFiles
268 if not self.alternativeConfig:
269 for var
in eventInfoVar:
270 config.addOutputVar (
'EventInfo', var, var, noSys=
True)
272 if config.dataType()
is not DataType.Data
and config.geometry()
is LHCPeriod.Run2:
273 config.addOutputVar (
'EventInfo',
'beamSpotWeight',
'weight_beamspot', noSys=
True)
275 if config.dataType()
is not DataType.Data
and toolConfigFiles:
276 config.addOutputVar (
'EventInfo',
'PileupWeight' + self.postfix +
'_%SYS%',
277 'weight_pileup'+self.postfix)
281 """the ConfigBlock for generator algorithms"""
284 super (GeneratorAnalysisBlock, self).__init__ ()
285 self.addOption (
'saveCutBookkeepers',
True, type=bool,
286 info=
"whether to save the cut bookkeepers information into the "
287 "output file. The default is True.")
288 self.addOption (
'runNumber',
None, type=int,
289 info=
"the MC runNumber (int). The default is None (autoconfigure "
291 self.addOption (
'cutBookkeepersSystematics',
None, type=bool,
292 info=
"whether to also save the cut bookkeepers systematics. The "
293 "default is None (follows the global systematics flag). Set to "
294 "False or True to override.")
295 self.addOption (
'histPattern',
None, type=str,
296 info=
"the histogram name pattern for the cut-bookkeeper histogram names")
297 self.addOption (
'streamName',
'ANALYSIS', type=str,
298 info=
"name of the output stream to save the cut bookkeeper in. "
299 "The default is ANALYSIS.")
303 if config.dataType()
is DataType.Data:
310 if self.saveCutBookkeepers
and not self.
runNumber:
311 raise ValueError (
"invalid run number: " +
str(self.
runNumber))
314 if self.saveCutBookkeepers:
315 alg = config.createAlgorithm(
'CP::AsgCutBookkeeperAlg',
'CutBookkeeperAlg' + self.streamName)
316 alg.RootStreamName = self.streamName
318 if self.cutBookkeepersSystematics:
319 alg.enableSystematics = self.cutBookkeepersSystematics
321 alg.enableSystematics =
not config.noSystematics()
323 alg.histPattern = self.histPattern
324 config.addPrivateTool(
'truthWeightTool',
'PMGTools::PMGTruthWeightTool' )
327 alg = config.createAlgorithm(
'CP::PMGTruthWeightAlg',
'PMGTruthWeightAlg' + self.streamName )
328 config.addPrivateTool(
'truthWeightTool',
'PMGTools::PMGTruthWeightTool' )
329 alg.decoration =
'generatorWeight_%SYS%'
330 config.addOutputVar (
'EventInfo',
'generatorWeight_%SYS%',
'weight_mc')
334 """the ConfigBlock for a pt-eta selection"""
336 def __init__ (self, containerName='', selectionName='') :
337 super (PtEtaSelectionBlock, self).__init__ ()
338 self.addOption (
'containerName', containerName, type=str,
340 info=
"the name of the input container.")
341 self.addOption (
'selectionName', selectionName, type=str,
343 info=
"the name of the selection to append this to. The default is "
344 "'' (empty string), meaning that the cuts are applied to every "
345 "object within the container. Specifying a name (e.g. loose) "
346 "applies the cut only to those object who also pass that selection.")
347 self.addOption (
'minPt',
None, type=float,
348 info=
"minimum pT value to cut on, in MeV. No default value.")
349 self.addOption (
'maxPt',
None, type=float,
350 info=
"maximum pT value to cut on, in MeV. No default value.")
351 self.addOption (
'minEta',
None, type=float,
352 info=
"minimum |eta| value to cut on. No default value.")
353 self.addOption (
'maxEta',
None, type=float,
354 info=
"maximum |eta| value to cut on. No default value.")
355 self.addOption (
'etaGapLow',
None, type=float,
356 info=
"low end of the |eta| gap. No default value.")
357 self.addOption (
'etaGapHigh',
None, type=float,
358 info=
"high end of the |eta| gap. No default value.")
359 self.addOption (
'selectionDecoration',
None, type=str,
360 info=
"the name of the decoration to set. If 'None', will be set "
361 "to 'selectPtEta' followed by the selection name.")
362 self.addOption (
'useClusterEta',
False, type=bool,
363 info=
"whether to use the cluster eta (etaBE(2)) instead of the object "
364 "eta (for electrons and photons). The default is False.")
365 self.addOption (
'useDressedProperties',
False, type=bool,
366 info=
"whether to use the dressed kinematic properties "
367 "(for truth particles only). The default is False.")
372 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'PtEtaSelectionAlg' + self.containerName + self.selectionName )
373 config.addPrivateTool(
'selectionTool',
'CP::AsgPtEtaSelectionTool' )
374 if self.minPt
is not None :
375 alg.selectionTool.minPt = self.minPt
376 if self.maxPt
is not None:
377 alg.selectionTool.maxPt = self.maxPt
378 if self.minEta
is not None:
379 alg.selectionTool.minEta = self.minEta
380 if self.maxEta
is not None :
381 alg.selectionTool.maxEta = self.maxEta
382 if self.etaGapLow
is not None:
383 alg.selectionTool.etaGapLow = self.etaGapLow
384 if self.etaGapHigh
is not None:
385 alg.selectionTool.etaGapHigh = self.etaGapHigh
388 alg.selectionTool.useClusterEta = self.useClusterEta
389 alg.selectionTool.useDressedProperties = self.useDressedProperties
391 alg.particles = config.readName (self.containerName)
392 alg.preselection = config.getPreselection (self.containerName,
'')
393 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration)
398 """the ConfigBlock for an object cutflow"""
400 def __init__ (self, containerName='', selectionName='') :
401 super (ObjectCutFlowBlock, self).__init__ ()
402 self.addOption (
'containerName', containerName, type=str,
404 info=
"the name of the input container.")
405 self.addOption (
'selectionName', selectionName, type=str,
407 info=
"the name of the selection to perform the cutflow for. The "
408 "default is '' (empty string), meaning that the cutflow is "
409 "performed for every object within the container. Specifying a "
410 "name (e.g. loose) generates the cutflow only for those object "
411 "that also pass that selection.")
412 self.addOption (
'forceCutSequence',
False, type=bool,
413 info=
"whether to force the cut sequence and not accept objects "
414 "if previous cuts failed. The default is False.")
418 alg = config.createAlgorithm(
'CP::ObjectCutFlowHistAlg',
'CutFlowDumperAlg_' + self.containerName +
'_' + self.selectionName )
419 alg.histPattern =
'cflow_' + self.containerName +
"_" + self.selectionName +
'_%SYS%'
420 alg.selections = config.getSelectionCutFlow (self.containerName, self.selectionName)
421 alg.input = config.readName (self.containerName)
422 alg.histTitle =
"Object Cutflow: " + self.containerName +
"." + self.selectionName
423 alg.forceCutSequence = self.forceCutSequence
427 """the ConfigBlock for an event-level cutflow"""
429 def __init__ (self, containerName='', selectionName='') :
430 super (EventCutFlowBlock, self).__init__ ()
431 self.addOption (
'containerName', containerName, type=str,
433 info=
"the name of the input container, typically EventInfo.")
434 self.addOption (
'selectionName', selectionName, type=str,
436 info=
"the name of an optional selection decoration to use.")
437 self.addOption (
'customSelections', [], type=
None,
438 info=
"the selections for which to generate cutflow histograms. If "
439 "a single string, corresponding to a particular event selection, "
440 "the event cutflow for that selection will be looked up. If a list "
441 "of strings, will use explicitly those selections. If left blank, "
442 "all selections attached to the container will be looked up.")
443 self.addOption (
'postfix',
'', type=str,
444 info=
"a postfix to apply in the naming of cutflow histograms. Set "
445 "it when defining multiple cutflows.")
449 postfix = self.postfix
450 if postfix !=
'' and postfix[0] !=
'_' :
451 postfix =
'_' + postfix
453 alg = config.createAlgorithm(
'CP::EventCutFlowHistAlg',
'CutFlowDumperAlg_' + self.containerName +
'_' + self.selectionName + postfix )
454 alg.histPattern =
'cflow_' + self.containerName +
"_" + self.selectionName + postfix +
'_%SYS%'
456 if isinstance(self.customSelections, str):
458 alg.selections = config.getEventCutFlow(self.customSelections)
459 elif len(self.customSelections) > 0:
461 alg.selections = self.customSelections
464 alg.selections = config.getSelectionCutFlow (self.containerName, self.selectionName)
465 alg.selections = [sel+
',as_char' for sel
in alg.selections]
466 if self.selectionName:
467 alg.preselection = self.selectionName +
'_%SYS%'
468 alg.eventInfo = config.readName (self.containerName)
469 alg.histTitle =
"Event Cutflow: " + self.containerName +
"." + self.selectionName
473 """the ConfigBlock for output thinning"""
475 def __init__ (self, containerName='', configName='') :
477 super (OutputThinningBlock, self).__init__ ()
478 self.addOption (
'containerName', containerName, type=str,
480 info=
"the name of the input container.")
481 self.addOption (
'postfix',
'', type=str,
482 info=
"a postfix to apply to decorations and algorithm names. "
483 "Typically not needed here.")
484 self.addOption (
'selection',
'', type=str,
485 info=
"the name of an optional selection decoration to use.")
486 self.addOption (
'selectionName',
'', type=str,
487 info=
"the name of the selection to append this to. The default is "
488 "'' (empty string), meaning that the cuts are applied to every "
489 "object within the container. Specifying a name (e.g. loose) "
490 "applies the cut only to those object who also pass that selection.")
491 self.addOption (
'outputName',
None, type=str,
492 info=
"an optional name for the output container.")
494 self.addOption (
'deepCopy',
False, type=bool,
496 self.addOption (
'sortPt',
False, type=bool,
497 info=
"whether to sort objects in pt")
499 self.addOption (
'noUniformSelection',
False, type=bool,
504 postfix = self.postfix
505 if postfix !=
'' and postfix[0] !=
'_' :
506 postfix =
'_' + postfix
508 selection = config.getFullSelection (self.containerName, self.selectionName)
510 selection = self.selection
511 elif self.selection !=
'' :
512 selection = selection +
'&&' + self.selection
514 if selection !=
'' and not self.noUniformSelection :
515 alg = config.createAlgorithm(
'CP::AsgUnionSelectionAlg',
'UnionSelectionAlg' + self.containerName + postfix)
516 alg.preselection = selection
517 alg.particles = config.readName (self.containerName)
518 alg.selectionDecoration =
'outputSelect' + postfix
519 config.addSelection (self.containerName, alg.selectionDecoration, selection)
520 selection =
'outputSelect' + postfix
522 alg = config.createAlgorithm(
'CP::AsgViewFromSelectionAlg',
'DeepCopyAlg' + self.containerName + postfix )
523 alg.input = config.readName (self.containerName)
524 if self.outputName
is not None :
525 alg.output = self.outputName +
'_%SYS%'
526 config.addOutputContainer (self.containerName, self.outputName)
528 alg.output = config.copyName (self.containerName)
530 alg.selection = [selection]
533 alg.deepCopy = self.deepCopy
534 if self.sortPt
and not config.noSystematics() :
535 raise ValueError (
"Sorting by pt is not supported with systematics")
536 alg.sortPt = self.sortPt
540 """the ConfigBlock for the IFF classification of leptons"""
543 super (IFFLeptonDecorationBlock, self).
__init__()
544 self.addOption (
'containerName', containerName, type=str,
546 info=
"the name of the input electron or muon container.")
547 self.addOption (
'separateChargeFlipElectrons',
True, type=bool,
548 info=
"whether to consider charged-flip electrons as a separate class. "
549 "The default is True (recommended).")
550 self.addOption (
'decoration',
'IFFClass_%SYS%', type=str,
551 info=
"the name (str) of the decoration set by the IFF "
552 "TruthClassificationTool. The default is 'IFFClass_%SYS%'.")
554 self.setOptionValue(
'skipOnData',
True)
557 particles = config.readName(self.containerName)
559 alg = config.createAlgorithm(
'CP::AsgClassificationDecorationAlg',
'IFFClassifierAlg' + self.containerName )
561 config.addPrivateTool(
'tool',
'TruthClassificationTool')
563 alg.tool.separateChargeFlipElectrons = self.separateChargeFlipElectrons
564 alg.decoration = self.decoration
565 alg.particles = particles
568 config.addOutputVar(self.containerName, alg.decoration, alg.decoration.split(
"_%SYS%")[0], noSys=
True)
574 super (MCTCLeptonDecorationBlock, self).__init__ ()
576 self.addOption (
"containerName", containerName, type=str,
578 info=
"the input lepton container, with a possible selection, "
579 "in the format container or container.selection.")
580 self.addOption (
"prefix",
'MCTC_', type=str,
581 info=
"the prefix (str) of the decorations based on the MCTC "
582 "classification. The default is 'MCTC_'.")
584 self.setOptionValue(
'skipOnData',
True)
587 particles, selection = config.readNameAndSelection(self.containerName)
589 alg = config.createAlgorithm (
"CP::MCTCDecorationAlg", f
"MCTCDecorationAlg{self.containerName}")
590 alg.particles = particles
591 alg.preselection = selection
592 alg.affectingSystematicsFilter =
'.*'
593 config.addOutputVar (self.containerName,
"MCTC_isPrompt", f
"{self.prefix}isPrompt", noSys=
True)
594 config.addOutputVar (self.containerName,
"MCTC_fromHadron", f
"{self.prefix}fromHadron", noSys=
True)
595 config.addOutputVar (self.containerName,
"MCTC_fromBSM", f
"{self.prefix}fromBSM", noSys=
True)
596 config.addOutputVar (self.containerName,
"MCTC_fromTau", f
"{self.prefix}fromTau", noSys=
True)
600 """the ConfigBlock for the AsgEventScaleFactorAlg"""
603 super(PerEventSFBlock, self).
__init__()
604 self.addOption(
'algoName', algoName, type=str,
606 info=
"unique name given to the underlying algorithm computing the "
607 "per-event scale factors")
608 self.addOption(
'particles',
'', type=str,
609 info=
"the input object container, with a possible selection, in the "
610 "format container or container.selection.")
611 self.addOption(
'objectSF',
'', type=str,
612 info=
"the name of the per-object SF decoration to be used.")
613 self.addOption(
'eventSF',
'', type=str,
614 info=
"the name of the per-event SF decoration.")
617 if config.dataType()
is DataType.Data:
619 particles, selection = config.readNameAndSelection(self.particles)
620 alg = config.createAlgorithm(
'CP::AsgEventScaleFactorAlg', self.algoName)
621 alg.particles = particles
622 alg.preselection = selection
623 alg.scaleFactorInputDecoration = self.objectSF
624 alg.scaleFactorOutputDecoration = self.eventSF
626 config.addOutputVar(
'EventInfo', alg.scaleFactorOutputDecoration,
627 alg.scaleFactorOutputDecoration.split(
"_%SYS%")[0])
631 """the ConfigBlock to add selection decoration to a container"""
634 super (SelectionDecorationBlock, self).__init__ ()
636 self.addOption(
'containers', containers, type=list,
641 for container
in self.containers:
642 originContainerName = config.getOutputContainerOrigin(container)
643 selectionNames = config.getSelectionNames(originContainerName)
644 for selectionName
in selectionNames:
646 if selectionName ==
'':
648 alg = config.createAlgorithm(
649 'CP::AsgSelectionAlg',
650 f
'SelectionDecoration_{originContainerName}_{selectionName}')
651 selectionDecoration = f
'baselineSelection_{selectionName}_%SYS%'
652 alg.selectionDecoration = f
'{selectionDecoration},as_char'
653 alg.particles = config.readName (originContainerName)
654 alg.preselection = config.getFullSelection (originContainerName,
657 originContainerName, selectionDecoration, selectionName)
660 *, postfix=None, selectionName, customSelections=None):
661 """Create an event-level cutflow config
664 containerName -- name of the container
665 postfix -- a postfix to apply to decorations and algorithm names.
666 selectionName -- the name of the selection to do the cutflow for
667 customSelections -- a list of decorations to use in the cutflow, to override the retrieval of all decorations
671 config.setOptionValue(
'postfix', postfix)
672 config.setOptionValue(
'customSelections', customSelections)