4 from AnalysisAlgorithmsConfig.ConfigBlock
import ConfigBlock
5 from AnalysisAlgorithmsConfig.ConfigSequence
import groupBlocks
6 from AthenaConfiguration.Enums
import LHCPeriod
7 from AnalysisAlgorithmsConfig.ConfigAccumulator
import DataType
13 ELECTRONS = [
'EG_',
'EL_']
15 PHOTONS = [
'EG_',
'PH_']
19 EVENT = [
'GEN_',
'PRW_']
23 """the ConfigBlock for common services
25 The idea here is that all algorithms need some common services, and I should
26 provide configuration blocks for those. For now there is just a single
27 block, but in the future I might break out e.g. the systematics service.
31 super (CommonServicesConfig, self).__init__ ()
32 self.addOption (
'runSystematics',
None, type=bool,
33 info=
"whether to turn on the computation of systematic variations. "
34 "The default is to run them on MC.")
35 self.addOption (
'filterSystematics',
None, type=str,
36 info=
"a regexp string against which the systematics names will be "
37 "matched. Only positive matches are retained and used in the evaluation "
38 "of the various algorithms.")
39 self.addOption (
'onlySystematicsCategories',
None, type=list,
40 info=
"a list of strings defining categories of systematics to enable "
41 "(only recommended for studies / partial ntuple productions). Choose amongst: "
42 "jets, electrons, muons, photons, taus, met, tracks, ftag, event. This option is overridden "
43 "by 'filterSystematics'.")
44 self.addOption (
'systematicsHistogram',
None , type=str,
45 info=
"the name (string) of the histogram to which a list of executed "
46 "systematics will be printed. The default is None (don't write out "
48 self.addOption (
'separateWeightSystematics',
False, type=bool,
49 info=
"if 'systematicsHistogram' is enabled, whether to create a separate "
50 "histogram holding only the names of weight-based systematics. This is useful "
51 "to help make histogramming frameworks more efficient by knowing in advance which "
52 "systematics need to recompute the observable and which don't.")
55 """Return the instance name for this block"""
60 sysService = config.createService(
'CP::SystematicsSvc',
'SystematicsSvc' )
64 elif config.noSystematics()
is not None :
73 sysService.sigmaRecommended = 1
74 if config.dataType()
is DataType.Data:
79 requested_categories = []
82 category_enum = SystematicsCategories[category_str.upper()]
83 requested_categories += category_enum.value
85 raise ValueError(f
"Invalid systematics category passed to option 'onlySystematicsCategories': {category_str}. Must be one of {', '.join(category.name for category in SystematicsCategories)}")
87 if len(requested_categories):
88 sysService.systematicsRegex =
"^(?=.*(" +
"|".
join(requested_categories) +
")|$).*"
89 if self.filterSystematics
is not None:
90 sysService.systematicsRegex = self.filterSystematics
91 config.createService(
'CP::SelectionNameSvc',
'SelectionNameSvc')
93 if self.systematicsHistogram
is not None:
95 allSysDumper = config.createAlgorithm(
'CP::SysListDumperAlg',
'SystematicsPrinter' )
96 allSysDumper.histogramName = self.systematicsHistogram
98 if self.separateWeightSystematics:
100 weightSysDumper = config.createAlgorithm(
'CP::SysListDumperAlg',
'OnlyWeightSystematicsPrinter' )
101 weightSysDumper.histogramName = f
"{self.systematicsHistogram}OnlyWeights"
102 weightSysDumper.systematicsRegex =
"^(GEN_|EL_EFF_|MUON_EFF_|PH_EFF_|TAUS_TRUEHADTAU_EFF_|FT_EFF_|extrapolation_pt_|JET_.*JvtEfficiency_|PRW_).*"
108 from AsgAnalysisAlgorithms.TruthCollectionsFixerConfig
import TruthCollectionsFixerBlock
109 seq.append(TruthCollectionsFixerBlock())
112 """Print what branches are used in analysis"""
115 super(IOStatsBlock, self).
__init__()
116 self.addOption(
"printOption",
"Summary", type=str,
117 info=
'option to pass the standard ROOT printing function. Can be "Summary", "ByEntries" or "ByBytes".')
120 """Return the instance name for this block"""
124 alg = config.createAlgorithm(
'CP::IOStatsAlg',
'IOStatsAlg')
125 alg.printOption = self.printOption
129 """the ConfigBlock for pileup reweighting"""
132 super (PileupReweightingBlock, self).__init__ ()
133 self.addOption (
'campaign',
None, type=
None,
134 info=
"the MC campaign for the PRW auto-configuration.")
135 self.addOption (
'files',
None, type=
None,
136 info=
"the input files being processed (list of strings). "
137 "Alternative to auto-configuration.")
138 self.addOption (
'useDefaultConfig',
True, type=bool,
139 info=
"whether to use the central PRW files. The default is True.")
140 self.addOption (
'userLumicalcFiles',
None, type=
None,
141 info=
"user-provided lumicalc files (list of strings). Alternative "
142 "to auto-configuration.")
143 self.addOption (
'userLumicalcFilesPerCampaign',
None, type=
None,
144 info=
"user-provided lumicalc files (dictionary of list of strings, "
145 "with MC campaigns as the keys). Alternative to auto-configuration.")
146 self.addOption (
'userPileupConfigs',
None, type=
None,
147 info=
"user-provided PRW files (list of strings). Alternative to "
148 "auto-configuration. Alternative to auto-configuration.")
149 self.addOption (
'userPileupConfigsPerCampaign',
None, type=
None,
150 info=
"user-provided PRW files (dictionary of list of strings, with "
151 "MC campaigns as the keys)")
152 self.addOption (
'postfix',
'', type=str,
153 info=
"a postfix to apply to decorations and algorithm names. "
154 "Typically not needed unless several instances of PileupReweighting are scheduled.")
155 self.addOption (
'alternativeConfig',
False, type=bool,
156 info=
"whether this is used as an additional alternative config for PileupReweighting. "
157 "Will only store the alternative pile up weight in that case.")
158 self.addOption (
'writeColumnarToolVariables',
False, type=bool,
159 info=
"whether to add EventInfo variables needed for running the columnar tool(s) on the output n-tuple. (EXPERIMENTAL)")
162 """Return the instance name for this block"""
167 from Campaigns.Utils
import Campaign
170 from AthenaCommon.Logging
import logging
173 log = logging.getLogger(
'makePileupAnalysisSequence')
175 eventInfoVar = [
'runNumber',
'eventNumber',
'actualInteractionsPerCrossing',
'averageInteractionsPerCrossing']
176 if config.dataType()
is not DataType.Data:
177 eventInfoVar += [
'mcChannelNumber']
178 if self.writeColumnarToolVariables:
182 eventInfoVar += [
'eventTypeBitmask']
184 if config.isPhyslite()
and not self.alternativeConfig:
186 log.info(f
'Physlite does not need pileup reweighting. Variables will be copied from input instead. {config.isPhyslite}')
187 for var
in eventInfoVar:
188 config.addOutputVar (
'EventInfo', var, var, noSys=
True)
190 if config.dataType()
is not DataType.Data:
191 config.addOutputVar (
'EventInfo',
'PileupWeight_%SYS%',
'weight_pileup')
192 if config.geometry()
is LHCPeriod.Run2:
193 config.addOutputVar (
'EventInfo',
'beamSpotWeight',
'weight_beamspot', noSys=
True)
197 if self.
files is None and config.flags
is not None:
198 self.
files = config.flags.Input.Files
200 campaign = self.campaign
203 if config.dataType()
is not DataType.Data
and self.campaign
is None:
205 if config.campaign()
is not None and config.campaign()
is not Campaign.Unknown:
206 campaign = config.campaign()
207 log.info(f
'Auto-configuring campaign for PRW from flags: {campaign.value}')
210 if self.
files is not None:
211 from Campaigns.Utils
import getMCCampaign
213 if campaign
and campaign
is not Campaign.Unknown:
214 log.info(f
'Auto-configuring campaign for PRW from files: {campaign.value}')
216 log.info(
'Campaign could not be determined.')
220 toolLumicalcFiles = []
224 if (config.dataType()
is not DataType.Data
and
225 config.geometry()
is not LHCPeriod.Run4):
227 if self.userPileupConfigs
is not None and self.userPileupConfigsPerCampaign
is not None:
228 raise ValueError(
'Both userPileupConfigs and userPileupConfigsPerCampaign specified, '
229 'use only one of the options!')
230 if self.userPileupConfigsPerCampaign
is not None:
232 raise Exception(
'userPileupConfigsPerCampaign requires campaign to be configured!')
233 if campaign
is Campaign.Unknown:
234 raise Exception(
'userPileupConfigsPerCampaign used, but campaign = Unknown!')
236 toolConfigFiles = self.userPileupConfigsPerCampaign[campaign.value][:]
237 log.info(
'Using user provided per-campaign PRW configuration')
238 except KeyError
as e:
239 raise KeyError(f
'Unconfigured campaign {e} for userPileupConfigsPerCampaign!')
241 elif self.userPileupConfigs
is not None:
242 toolConfigFiles = self.userPileupConfigs[:]
243 log.info(
'Using user provided PRW configuration')
246 if self.useDefaultConfig
and self.
files is None:
247 raise ValueError(
'useDefaultConfig requires files to be configured! '
248 'Either pass them as an option or use flags.')
250 from PileupReweighting.AutoconfigurePRW
import getConfigurationFiles
251 if campaign
and campaign
is not Campaign.Unknown:
254 useDefaultConfig=self.useDefaultConfig,
255 data_type=config.dataType())
256 if self.useDefaultConfig:
257 log.info(
'Auto-configuring universal/default PRW config')
259 log.info(
'Auto-configuring per-sample PRW config files based on input files')
261 log.info(
'No campaign specified, no PRW config files configured')
264 if self.userLumicalcFilesPerCampaign
is not None and self.userLumicalcFiles
is not None:
265 raise ValueError(
'Both userLumicalcFiles and userLumicalcFilesYear specified, '
266 'use only one of the options!')
267 if self.userLumicalcFilesPerCampaign
is not None:
269 toolLumicalcFiles = self.userLumicalcFilesPerCampaign[campaign.value][:]
270 log.info(
'Using user-provided per-campaign lumicalc files')
271 except KeyError
as e:
272 raise KeyError(f
'Unconfigured campaign {e} for userLumicalcFilesPerCampaign!')
273 elif self.userLumicalcFiles
is not None:
274 toolLumicalcFiles = self.userLumicalcFiles[:]
275 log.info(
'Using user-provided lumicalc files')
277 if campaign
and campaign
is not Campaign.Unknown:
278 from PileupReweighting.AutoconfigurePRW
import getLumicalcFiles
280 log.info(
'Using auto-configured lumicalc files')
282 log.info(
'No campaign specified, no lumicalc files configured for PRW')
284 log.info(
'Data needs no lumicalc and PRW configuration files')
287 if config.geometry()
is LHCPeriod.Run4:
288 log.warning (
'Pileup reweighting is not yet supported for Run 4 geometry')
289 alg = config.createAlgorithm(
'CP::EventDecoratorAlg',
'EventDecoratorAlg' )
290 alg.uint32Decorations = {
'RandomRunNumber' :
291 config.flags.Input.RunNumbers[0] }
294 alg = config.createAlgorithm(
'CP::PileupReweightingAlg',
295 'PileupReweightingAlg' )
296 config.addPrivateTool(
'pileupReweightingTool',
'CP::PileupReweightingTool' )
297 alg.pileupReweightingTool.ConfigFiles = toolConfigFiles
298 if not toolConfigFiles
and config.dataType()
is not DataType.Data:
299 log.info(
"No PRW config files provided. Disabling reweighting")
301 alg.pileupWeightDecoration =
""
303 alg.pileupWeightDecoration =
"PileupWeight" + self.postfix +
"_%SYS%"
304 alg.pileupReweightingTool.LumiCalcFiles = toolLumicalcFiles
306 if not self.alternativeConfig:
307 for var
in eventInfoVar:
308 config.addOutputVar (
'EventInfo', var, var, noSys=
True)
310 if config.dataType()
is not DataType.Data
and config.geometry()
is LHCPeriod.Run2:
311 config.addOutputVar (
'EventInfo',
'beamSpotWeight',
'weight_beamspot', noSys=
True)
313 if config.dataType()
is not DataType.Data
and toolConfigFiles:
314 config.addOutputVar (
'EventInfo',
'PileupWeight' + self.postfix +
'_%SYS%',
315 'weight_pileup'+self.postfix)
319 """the ConfigBlock for generator algorithms"""
322 super (GeneratorAnalysisBlock, self).__init__ ()
323 self.addOption (
'saveCutBookkeepers',
True, type=bool,
324 info=
"whether to save the cut bookkeepers information into the "
325 "output file. The default is True.")
326 self.addOption (
'runNumber',
None, type=int,
327 info=
"the MC runNumber (int). The default is None (autoconfigure "
329 self.addOption (
'cutBookkeepersSystematics',
None, type=bool,
330 info=
"whether to also save the cut bookkeepers systematics. The "
331 "default is None (follows the global systematics flag). Set to "
332 "False or True to override.")
333 self.addOption (
'histPattern',
None, type=str,
334 info=
"the histogram name pattern for the cut-bookkeeper histogram names")
335 self.addOption (
'streamName',
'ANALYSIS', type=str,
336 info=
"name of the output stream to save the cut bookkeeper in. "
337 "The default is ANALYSIS.")
338 self.addOption (
'detailedPDFinfo',
False, type=bool,
339 info=
"save the necessary information to run the LHAPDF tool offline. "
340 "The default is False.")
341 self.addOption (
'doHFProdFracReweighting',
False, type=bool,
342 info=
"whether to apply HF production fraction reweighting. "
343 "The default is False.")
344 self.addOption (
'truthParticleContainer',
'TruthParticles', type=str,
345 info=
"the name of the truth particle container to use for HF production fraction reweighting. "
346 "The default is 'TruthParticles'. ")
348 """Return the instance name for this block"""
349 return self.streamName
353 if config.dataType()
is DataType.Data:
357 from AthenaCommon.Logging
import logging
360 log = logging.getLogger(
'makeGeneratorAnalysisSequence')
365 if self.saveCutBookkeepers
and not self.
runNumber:
366 raise ValueError (
"invalid run number: " +
str(self.
runNumber))
369 if self.saveCutBookkeepers:
370 alg = config.createAlgorithm(
'CP::AsgCutBookkeeperAlg',
'CutBookkeeperAlg')
371 alg.RootStreamName = self.streamName
373 if self.cutBookkeepersSystematics
is None:
374 alg.enableSystematics =
not config.noSystematics()
376 alg.enableSystematics = self.cutBookkeepersSystematics
378 alg.histPattern = self.histPattern
379 config.addPrivateTool(
'truthWeightTool',
'PMGTools::PMGTruthWeightTool' )
382 alg = config.createAlgorithm(
'CP::PMGTruthWeightAlg',
'PMGTruthWeightAlg' )
383 config.addPrivateTool(
'truthWeightTool',
'PMGTools::PMGTruthWeightTool' )
384 alg.decoration =
'generatorWeight_%SYS%'
385 config.addOutputVar (
'EventInfo',
'generatorWeight_%SYS%',
'weight_mc')
387 if self.detailedPDFinfo:
388 alg = config.createAlgorithm(
'CP::PDFinfoAlg',
'PDFinfoAlg', reentrant=
True )
389 for var
in [
"PDFID1",
"PDFID2",
"PDGID1",
"PDGID2",
"Q",
"X1",
"X2",
"XF1",
"XF2"]:
390 config.addOutputVar (
'EventInfo', var,
'PDFinfo_' + var, noSys=
True)
392 if self.doHFProdFracReweighting:
393 generatorInfo = config.flags.Input.GeneratorsInfo
394 log.info(f
"Loaded generator info: {generatorInfo}")
398 if not generatorInfo:
399 log.warning(
"No generator info found.")
401 elif isinstance(generatorInfo, dict):
402 if "Pythia8" in generatorInfo:
404 elif "Sherpa" in generatorInfo
and "2.2.8" in generatorInfo[
"Sherpa"]:
406 elif "Sherpa" in generatorInfo
and "2.2.10" in generatorInfo[
"Sherpa"]:
408 elif "Sherpa" in generatorInfo
and "2.2.11" in generatorInfo[
"Sherpa"]:
409 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.11. Using weights for Sherpa 2.2.10 instead.")
411 elif "Sherpa" in generatorInfo
and "2.2.12" in generatorInfo[
"Sherpa"]:
412 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.12. Using weights for Sherpa 2.2.10 instead.")
414 elif "Sherpa" in generatorInfo
and "2.2.14" in generatorInfo[
"Sherpa"]:
415 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.14. New weights need to be calculated.")
417 elif "Sherpa" in generatorInfo
and "2.2.1" in generatorInfo[
"Sherpa"]:
419 elif "Herwig7" in generatorInfo
and "7.1.3" in generatorInfo[
"Herwig7"]:
421 elif "Herwig7" in generatorInfo
and "7.2.1" in generatorInfo[
"Herwig7"]:
423 elif "Herwig7" in generatorInfo
and "7." in generatorInfo[
"Herwig7"]:
425 elif "amc@NLO" in generatorInfo:
428 log.warning(f
"HF production fraction reweighting is not configured for this generator: {generatorInfo}")
429 log.warning(
"New weights need to be calculated.")
432 log.warning(
"Failed to determine generator from metadata")
435 log.info(f
"Using HF production fraction weights calculated using DSID {DSID}")
437 log.warning(
"HF production fraction reweighting will return dummy weights of 1.0")
439 alg = config.createAlgorithm(
'CP::SysTruthWeightAlg',
'SysTruthWeightAlg' + self.streamName )
440 config.addPrivateTool(
'sysTruthWeightTool',
'PMGTools::PMGHFProductionFractionTool' )
441 alg.decoration =
'prodFracWeight_%SYS%'
442 alg.TruthParticleContainer = self.truthParticleContainer
443 alg.sysTruthWeightTool.ShowerGenerator = DSID
444 config.addOutputVar (
'EventInfo',
'prodFracWeight_%SYS%',
'weight_HF_prod_frac')
447 """the ConfigBlock for a pt-eta selection"""
450 super (PtEtaSelectionBlock, self).__init__ ()
451 self.addOption (
'containerName',
'', type=str,
453 info=
"the name of the input container.")
454 self.addOption (
'selectionName',
'', type=str,
456 info=
"the name of the selection to append this to. The default is "
457 "'' (empty string), meaning that the cuts are applied to every "
458 "object within the container. Specifying a name (e.g. loose) "
459 "applies the cut only to those object who also pass that selection.")
460 self.addOption (
'minPt',
None, type=float,
461 info=
"minimum pT value to cut on, in MeV. No default value.")
462 self.addOption (
'maxPt',
None, type=float,
463 info=
"maximum pT value to cut on, in MeV. No default value.")
464 self.addOption (
'minEta',
None, type=float,
465 info=
"minimum |eta| value to cut on. No default value.")
466 self.addOption (
'maxEta',
None, type=float,
467 info=
"maximum |eta| value to cut on. No default value.")
468 self.addOption (
'maxRapidity',
None, type=float,
469 info=
"maximum rapidity value to cut on. No default value.")
470 self.addOption (
'etaGapLow',
None, type=float,
471 info=
"low end of the |eta| gap. No default value.")
472 self.addOption (
'etaGapHigh',
None, type=float,
473 info=
"high end of the |eta| gap. No default value.")
474 self.addOption (
'selectionDecoration',
None, type=str,
475 info=
"the name of the decoration to set. If 'None', will be set "
476 "to 'selectPtEta' followed by the selection name.")
477 self.addOption (
'useClusterEta',
False, type=bool,
478 info=
"whether to use the cluster eta (etaBE(2)) instead of the object "
479 "eta (for electrons and photons). The default is False.")
480 self.addOption (
'useDressedProperties',
False, type=bool,
481 info=
"whether to use the dressed kinematic properties "
482 "(for truth particles only). The default is False.")
485 """Return the instance name for this block"""
486 return self.containerName +
"_" + self.selectionName
490 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'PtEtaSelectionAlg' )
491 config.addPrivateTool(
'selectionTool',
'CP::AsgPtEtaSelectionTool' )
492 if self.minPt
is not None :
493 alg.selectionTool.minPt = self.minPt
494 if self.maxPt
is not None:
495 alg.selectionTool.maxPt = self.maxPt
496 if self.minEta
is not None:
497 alg.selectionTool.minEta = self.minEta
498 if self.maxEta
is not None :
499 alg.selectionTool.maxEta = self.maxEta
500 if self.maxRapidity
is not None :
501 alg.selectionTool.maxRapidity = self.maxRapidity
502 if self.etaGapLow
is not None:
503 alg.selectionTool.etaGapLow = self.etaGapLow
504 if self.etaGapHigh
is not None:
505 alg.selectionTool.etaGapHigh = self.etaGapHigh
508 alg.selectionTool.useClusterEta = self.useClusterEta
509 alg.selectionTool.useDressedProperties = self.useDressedProperties
511 alg.particles = config.readName (self.containerName)
512 alg.preselection = config.getPreselection (self.containerName,
'')
513 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration)
518 """the ConfigBlock for an object cutflow"""
521 super (ObjectCutFlowBlock, self).__init__ ()
522 self.addOption (
'containerName',
'', type=str,
524 info=
"the name of the input container.")
525 self.addOption (
'selectionName',
'', type=str,
527 info=
"the name of the selection to perform the cutflow for. The "
528 "default is '' (empty string), meaning that the cutflow is "
529 "performed for every object within the container. Specifying a "
530 "name (e.g. loose) generates the cutflow only for those object "
531 "that also pass that selection.")
532 self.addOption (
'forceCutSequence',
False, type=bool,
533 info=
"whether to force the cut sequence and not accept objects "
534 "if previous cuts failed. The default is False.")
537 """Return the instance name for this block"""
538 return self.containerName +
'_' + self.selectionName
542 alg = config.createAlgorithm(
'CP::ObjectCutFlowHistAlg',
'CutFlowDumperAlg' )
543 alg.histPattern =
'cflow_' + self.containerName +
"_" + self.selectionName +
'_%SYS%'
544 alg.selections = config.getSelectionCutFlow (self.containerName, self.selectionName)
545 alg.input = config.readName (self.containerName)
546 alg.histTitle =
"Object Cutflow: " + self.containerName +
"." + self.selectionName
547 alg.forceCutSequence = self.forceCutSequence
551 """the ConfigBlock for an event-level cutflow"""
554 super (EventCutFlowBlock, self).__init__ ()
555 self.addOption (
'containerName',
'', type=str,
557 info=
"the name of the input container, typically EventInfo.")
558 self.addOption (
'selectionName',
'', type=str,
560 info=
"the name of an optional selection decoration to use.")
561 self.addOption (
'customSelections', [], type=
None,
562 info=
"the selections for which to generate cutflow histograms. If "
563 "a single string, corresponding to a particular event selection, "
564 "the event cutflow for that selection will be looked up. If a list "
565 "of strings, will use explicitly those selections. If left blank, "
566 "all selections attached to the container will be looked up.")
567 self.addOption (
'postfix',
'', type=str,
568 info=
"a postfix to apply in the naming of cutflow histograms. Set "
569 "it when defining multiple cutflows.")
572 """Return the instance name for this block"""
573 return self.containerName +
'_' + self.selectionName + self.postfix
577 postfix = self.postfix
578 if postfix !=
'' and postfix[0] !=
'_' :
579 postfix =
'_' + postfix
581 alg = config.createAlgorithm(
'CP::EventCutFlowHistAlg',
'CutFlowDumperAlg' )
582 alg.histPattern =
'cflow_' + self.containerName +
"_" + self.selectionName + postfix +
'_%SYS%'
584 if isinstance(self.customSelections, str):
586 alg.selections = config.getEventCutFlow(self.customSelections)
587 elif len(self.customSelections) > 0:
589 alg.selections = self.customSelections
592 alg.selections = config.getSelectionCutFlow (self.containerName, self.selectionName)
593 alg.selections = [sel+
',as_char' for sel
in alg.selections]
594 if self.selectionName:
595 alg.preselection = self.selectionName +
'_%SYS%'
596 alg.eventInfo = config.readName (self.containerName)
597 alg.histTitle =
"Event Cutflow: " + self.containerName +
"." + self.selectionName
601 """the ConfigBlock for output thinning"""
604 super (OutputThinningBlock, self).__init__ ()
605 self.addOption (
'containerName',
'', type=str,
607 info=
"the name of the input container.")
608 self.addOption (
'postfix',
'', type=str,
609 info=
"a postfix to apply to decorations and algorithm names. "
610 "Typically not needed here.")
611 self.addOption (
'selection',
'', type=str,
612 info=
"the name of an optional selection decoration to use.")
613 self.addOption (
'selectionName',
'', type=str,
614 info=
"the name of the selection to append this to. The default is "
615 "'' (empty string), meaning that the cuts are applied to every "
616 "object within the container. Specifying a name (e.g. loose) "
617 "applies the cut only to those object who also pass that selection.")
618 self.addOption (
'outputName',
None, type=str,
619 info=
"an optional name for the output container.")
621 self.addOption (
'deepCopy',
False, type=bool,
623 self.addOption (
'sortPt',
False, type=bool,
624 info=
"whether to sort objects in pt")
626 self.addOption (
'noUniformSelection',
False, type=bool,
630 """Return the instance name for this block"""
631 return self.containerName +
'_' + self.selectionName + self.postfix
635 postfix = self.postfix
636 if postfix !=
'' and postfix[0] !=
'_' :
637 postfix =
'_' + postfix
639 selection = config.getFullSelection (self.containerName, self.selectionName)
641 selection = self.selection
642 elif self.selection !=
'' :
643 selection = selection +
'&&' + self.selection
645 if selection !=
'' and not self.noUniformSelection :
646 alg = config.createAlgorithm(
'CP::AsgUnionSelectionAlg',
'UnionSelectionAlg')
647 alg.preselection = selection
648 alg.particles = config.readName (self.containerName)
649 alg.selectionDecoration =
'outputSelect' + postfix
650 config.addSelection (self.containerName, alg.selectionDecoration, selection)
651 selection =
'outputSelect' + postfix
653 alg = config.createAlgorithm(
'CP::AsgViewFromSelectionAlg',
'DeepCopyAlg' )
654 alg.input = config.readName (self.containerName)
655 if self.outputName
is not None :
656 alg.output = self.outputName +
'_%SYS%'
657 config.addOutputContainer (self.containerName, self.outputName)
659 alg.output = config.copyName (self.containerName)
661 alg.selection = [selection]
664 alg.deepCopy = self.deepCopy
665 if self.sortPt
and not config.noSystematics() :
666 raise ValueError (
"Sorting by pt is not supported with systematics")
667 alg.sortPt = self.sortPt
671 """the ConfigBlock for the IFF classification of leptons"""
674 super (IFFLeptonDecorationBlock, self).
__init__()
675 self.addOption (
'containerName',
'', type=str,
677 info=
"the name of the input electron or muon container.")
678 self.addOption (
'separateChargeFlipElectrons',
True, type=bool,
679 info=
"whether to consider charged-flip electrons as a separate class. "
680 "The default is True (recommended).")
681 self.addOption (
'decoration',
'IFFClass_%SYS%', type=str,
682 info=
"the name (str) of the decoration set by the IFF "
683 "TruthClassificationTool. The default is 'IFFClass_%SYS%'.")
685 self.setOptionValue(
'skipOnData',
True)
688 """Return the instance name for this block"""
689 return self.containerName
692 particles = config.readName(self.containerName)
694 alg = config.createAlgorithm(
'CP::AsgClassificationDecorationAlg',
'IFFClassifierAlg' )
696 config.addPrivateTool(
'tool',
'TruthClassificationTool')
698 alg.tool.separateChargeFlipElectrons = self.separateChargeFlipElectrons
699 alg.decoration = self.decoration
700 alg.particles = particles
703 config.addOutputVar(self.containerName, alg.decoration, alg.decoration.split(
"_%SYS%")[0], noSys=
True)
709 super (MCTCLeptonDecorationBlock, self).__init__ ()
711 self.addOption (
"containerName",
'', type=str,
713 info=
"the input lepton container, with a possible selection, "
714 "in the format container or container.selection.")
715 self.addOption (
"prefix",
'MCTC_', type=str,
716 info=
"the prefix (str) of the decorations based on the MCTC "
717 "classification. The default is 'MCTC_'.")
719 self.setOptionValue(
'skipOnData',
True)
722 """Return the instance name for this block"""
723 return self.containerName
726 particles, selection = config.readNameAndSelection(self.containerName)
728 alg = config.createAlgorithm (
"CP::MCTCDecorationAlg",
"MCTCDecorationAlg")
729 alg.particles = particles
730 alg.preselection = selection
731 alg.affectingSystematicsFilter =
'.*'
732 config.addOutputVar (self.containerName,
"MCTC_isPrompt", f
"{self.prefix}isPrompt", noSys=
True)
733 config.addOutputVar (self.containerName,
"MCTC_fromHadron", f
"{self.prefix}fromHadron", noSys=
True)
734 config.addOutputVar (self.containerName,
"MCTC_fromBSM", f
"{self.prefix}fromBSM", noSys=
True)
735 config.addOutputVar (self.containerName,
"MCTC_fromTau", f
"{self.prefix}fromTau", noSys=
True)
739 """the ConfigBlock for the AsgEventScaleFactorAlg"""
742 super(PerEventSFBlock, self).
__init__()
743 self.addOption(
'algoName',
None, type=str,
744 info=
"unique name given to the underlying algorithm computing the "
745 "per-event scale factors")
746 self.addOption(
'particles',
'', type=str,
747 info=
"the input object container, with a possible selection, in the "
748 "format container or container.selection.")
749 self.addOption(
'objectSF',
'', type=str,
750 info=
"the name of the per-object SF decoration to be used.")
751 self.addOption(
'eventSF',
'', type=str,
752 info=
"the name of the per-event SF decoration.")
755 """Return the instance name for this block"""
756 return self.particles +
'_' + self.objectSF +
'_' + self.eventSF
759 if config.dataType()
is DataType.Data:
761 particles, selection = config.readNameAndSelection(self.particles)
762 alg = config.createAlgorithm(
'CP::AsgEventScaleFactorAlg', self.algoName
if self.algoName
else 'AsgEventScaleFactorAlg')
763 alg.particles = particles
764 alg.preselection = selection
765 alg.scaleFactorInputDecoration = self.objectSF
766 alg.scaleFactorOutputDecoration = self.eventSF
768 config.addOutputVar(
'EventInfo', alg.scaleFactorOutputDecoration,
769 alg.scaleFactorOutputDecoration.split(
"_%SYS%")[0])
773 """the ConfigBlock to add selection decoration to a container"""
776 super (SelectionDecorationBlock, self).__init__ ()
778 self.addOption(
'containers', [], type=list,
783 """Return the instance name for this block"""
787 for container
in self.containers:
788 originContainerName = config.getOutputContainerOrigin(container)
789 selectionNames = config.getSelectionNames(originContainerName)
790 for selectionName
in selectionNames:
792 if selectionName ==
'':
794 alg = config.createAlgorithm(
795 'CP::AsgSelectionAlg',
796 f
'SelectionDecoration_{originContainerName}_{selectionName}')
797 selectionDecoration = f
'baselineSelection_{selectionName}_%SYS%'
798 alg.selectionDecoration = f
'{selectionDecoration},as_char'
799 alg.particles = config.readName (originContainerName)
800 alg.preselection = config.getFullSelection (originContainerName,
803 originContainerName, selectionDecoration, selectionName)
806 *, postfix=None, selectionName, customSelections=None):
807 """Create an event-level cutflow config
810 containerName -- name of the container
811 postfix -- a postfix to apply to decorations and algorithm names.
812 selectionName -- the name of the selection to do the cutflow for
813 customSelections -- a list of decorations to use in the cutflow, to override the retrieval of all decorations
817 config.setOptionValue(
'containerName', containerName)
818 config.setOptionValue(
'selectionName', selectionName)
819 config.setOptionValue(
'postfix', postfix)
820 config.setOptionValue(
'customSelections', customSelections)