4 from AnalysisAlgorithmsConfig.ConfigBlock
import ConfigBlock
5 from AnalysisAlgorithmsConfig.ConfigSequence
import groupBlocks
6 from AthenaConfiguration.Enums
import LHCPeriod
7 from AnalysisAlgorithmsConfig.ConfigAccumulator
import DataType, ExpertModeWarning
12 from AthenaCommon.Logging
import logging
19 ELECTRONS = [
'EG_',
'EL_']
21 PHOTONS = [
'EG_',
'PH_']
25 EVENT = [
'GEN_',
'PRW_']
29 """the ConfigBlock for common services
31 The idea here is that all algorithms need some common services, and I should
32 provide configuration blocks for those. For now there is just a single
33 block, but in the future I might break out e.g. the systematics service.
37 super (CommonServicesConfig, self).__init__ ()
38 self.addOption (
'runSystematics',
None, type=bool,
39 info=
"whether to turn on the computation of systematic variations. "
40 "The default is to run them on MC.")
41 self.addOption (
'filterSystematics',
None, type=str,
42 info=
"a regexp string against which the systematics names will be "
43 "matched. Only positive matches are retained and used in the evaluation "
44 "of the various algorithms.")
45 self.addOption (
'onlySystematicsCategories',
None, type=list,
46 info=
"a list of strings defining categories of systematics to enable "
47 "(only recommended for studies / partial ntuple productions). Choose amongst: "
48 "jets, electrons, muons, photons, taus, met, tracks, ftag, event. This option is overridden "
49 "by 'filterSystematics'.")
50 self.addOption (
'systematicsHistogram',
None , type=str,
51 info=
"the name (string) of the histogram to which a list of executed "
52 "systematics will be printed. The default is None (don't write out "
54 self.addOption (
'separateWeightSystematics',
False, type=bool,
55 info=
"if 'systematicsHistogram' is enabled, whether to create a separate "
56 "histogram holding only the names of weight-based systematics. This is useful "
57 "to help make histogramming frameworks more efficient by knowing in advance which "
58 "systematics need to recompute the observable and which don't.")
59 self.addOption (
'enableExpertMode',
False, type=bool,
60 info=
"allows CP experts and CPAlgorithm devs to use non-recommended configurations. "
61 "DO NOT USE FOR ANALYSIS.")
64 """Return the instance name for this block"""
69 sysService = config.createService(
'CP::SystematicsSvc',
'SystematicsSvc' )
73 elif config.noSystematics()
is not None :
82 sysService.sigmaRecommended = 1
83 if config.dataType()
is DataType.Data:
88 requested_categories = []
91 category_enum = SystematicsCategories[category_str.upper()]
92 requested_categories += category_enum.value
94 raise ValueError(f
"Invalid systematics category passed to option 'onlySystematicsCategories': {category_str}. Must be one of {', '.join(category.name for category in SystematicsCategories)}")
96 if len(requested_categories):
97 sysService.systematicsRegex =
"^(?=.*(" +
"|".
join(requested_categories) +
")|$).*"
98 if self.filterSystematics
is not None:
99 sysService.systematicsRegex = self.filterSystematics
100 config.createService(
'CP::SelectionNameSvc',
'SelectionNameSvc')
102 if self.systematicsHistogram
is not None:
104 allSysDumper = config.createAlgorithm(
'CP::SysListDumperAlg',
'SystematicsPrinter' )
105 allSysDumper.histogramName = self.systematicsHistogram
107 if self.separateWeightSystematics:
109 weightSysDumper = config.createAlgorithm(
'CP::SysListDumperAlg',
'OnlyWeightSystematicsPrinter' )
110 weightSysDumper.histogramName = f
"{self.systematicsHistogram}OnlyWeights"
111 weightSysDumper.systematicsRegex =
"^(GEN_|EL_EFF_|MUON_EFF_|PH_EFF_|TAUS_TRUEHADTAU_EFF_|FT_EFF_|extrapolation_pt_|JET_.*JvtEfficiency_|PRW_).*"
113 if self.enableExpertMode
and config._pass == 0:
115 warnings.simplefilter(
'ignore', ExpertModeWarning)
117 log = logging.getLogger(
'CommonServices')
122 log.warning(red +
r"""
123 ________ _______ ______ _____ _______ __ __ ____ _____ ______ ______ _ _ ____ _ ______ _____
124 | ____\ \ / / __ \| ____| __ \__ __| | \/ |/ __ \| __ \| ____| | ____| \ | | /\ | _ \| | | ____| __ \
125 | |__ \ V /| |__) | |__ | |__) | | | | \ / | | | | | | | |__ | |__ | \| | / \ | |_) | | | |__ | | | |
126 | __| > < | ___/| __| | _ / | | | |\/| | | | | | | | __| | __| | . ` | / /\ \ | _ <| | | __| | | | |
127 | |____ / . \| | | |____| | \ \ | | | | | | |__| | |__| | |____ | |____| |\ |/ ____ \| |_) | |____| |____| |__| |
128 |______/_/ \_\_| |______|_| \_\ |_| |_| |_|\____/|_____/|______| |______|_| \_/_/ \_\____/|______|______|_____/
132 log.warning(f
"{bold}{yellow}These settings are not recommended for analysis. Make sure you know what you're doing, or disable them with `enableExpertMode: False` in `CommonServices`.{reset}")
141 from AsgAnalysisAlgorithms.TruthCollectionsFixerConfig
import TruthCollectionsFixerBlock
142 seq.append(TruthCollectionsFixerBlock())
145 """Print what branches are used in analysis"""
148 super(IOStatsBlock, self).
__init__()
149 self.addOption(
"printOption",
"Summary", type=str,
150 info=
'option to pass the standard ROOT printing function. Can be "Summary", "ByEntries" or "ByBytes".')
153 """Return the instance name for this block"""
157 alg = config.createAlgorithm(
'CP::IOStatsAlg',
'IOStatsAlg')
158 alg.printOption = self.printOption
162 """the ConfigBlock for pileup reweighting"""
165 super (PileupReweightingBlock, self).__init__ ()
166 self.addOption (
'campaign',
None, type=
None,
167 info=
"the MC campaign for the PRW auto-configuration.")
168 self.addOption (
'files',
None, type=
None,
169 info=
"the input files being processed (list of strings). "
170 "Alternative to auto-configuration.")
171 self.addOption (
'useDefaultConfig',
True, type=bool,
172 info=
"whether to use the central PRW files. The default is True.")
173 self.addOption (
'userLumicalcFiles',
None, type=
None,
174 info=
"user-provided lumicalc files (list of strings). Alternative "
175 "to auto-configuration.")
176 self.addOption (
'userLumicalcFilesPerCampaign',
None, type=
None,
177 info=
"user-provided lumicalc files (dictionary of list of strings, "
178 "with MC campaigns as the keys). Alternative to auto-configuration.")
179 self.addOption (
'userPileupConfigs',
None, type=
None,
180 info=
"user-provided PRW files (list of strings). Alternative to "
181 "auto-configuration. Alternative to auto-configuration.")
182 self.addOption (
'userPileupConfigsPerCampaign',
None, type=
None,
183 info=
"user-provided PRW files (dictionary of list of strings, with "
184 "MC campaigns as the keys)")
185 self.addOption (
'postfix',
'', type=str,
186 info=
"a postfix to apply to decorations and algorithm names. "
187 "Typically not needed unless several instances of PileupReweighting are scheduled.")
188 self.addOption (
'alternativeConfig',
False, type=bool,
189 info=
"whether this is used as an additional alternative config for PileupReweighting. "
190 "Will only store the alternative pile up weight in that case.")
191 self.addOption (
'writeColumnarToolVariables',
False, type=bool,
192 info=
"whether to add EventInfo variables needed for running the columnar tool(s) on the output n-tuple. (EXPERIMENTAL)",
196 """Return the instance name for this block"""
201 from Campaigns.Utils
import Campaign
203 log = logging.getLogger(
'makePileupAnalysisSequence')
205 eventInfoVar = [
'runNumber',
'eventNumber',
'actualInteractionsPerCrossing',
'averageInteractionsPerCrossing']
206 if config.dataType()
is not DataType.Data:
207 eventInfoVar += [
'mcChannelNumber']
208 if self.writeColumnarToolVariables:
212 eventInfoVar += [
'eventTypeBitmask']
214 if config.isPhyslite()
and not self.alternativeConfig:
216 log.info(f
'Physlite does not need pileup reweighting. Variables will be copied from input instead. {config.isPhyslite}')
217 for var
in eventInfoVar:
218 config.addOutputVar (
'EventInfo', var, var, noSys=
True)
220 if config.dataType()
is not DataType.Data:
221 config.addOutputVar (
'EventInfo',
'PileupWeight_%SYS%',
'weight_pileup')
222 if config.geometry()
is LHCPeriod.Run2:
223 config.addOutputVar (
'EventInfo',
'beamSpotWeight',
'weight_beamspot', noSys=
True)
227 if self.
files is None and config.flags
is not None:
228 self.
files = config.flags.Input.Files
230 campaign = self.campaign
233 if config.dataType()
is not DataType.Data
and self.campaign
is None:
235 if config.campaign()
is not None and config.campaign()
is not Campaign.Unknown:
236 campaign = config.campaign()
237 log.info(f
'Auto-configuring campaign for PRW from flags: {campaign.value}')
240 if self.
files is not None:
241 from Campaigns.Utils
import getMCCampaign
243 if campaign
and campaign
is not Campaign.Unknown:
244 log.info(f
'Auto-configuring campaign for PRW from files: {campaign.value}')
246 log.info(
'Campaign could not be determined.')
250 toolLumicalcFiles = []
254 if (config.dataType()
is not DataType.Data
and
255 config.geometry()
is not LHCPeriod.Run4):
257 if self.userPileupConfigs
is not None and self.userPileupConfigsPerCampaign
is not None:
258 raise ValueError(
'Both userPileupConfigs and userPileupConfigsPerCampaign specified, '
259 'use only one of the options!')
260 if self.userPileupConfigsPerCampaign
is not None:
262 raise Exception(
'userPileupConfigsPerCampaign requires campaign to be configured!')
263 if campaign
is Campaign.Unknown:
264 raise Exception(
'userPileupConfigsPerCampaign used, but campaign = Unknown!')
266 toolConfigFiles = self.userPileupConfigsPerCampaign[campaign.value][:]
267 log.info(
'Using user provided per-campaign PRW configuration')
268 except KeyError
as e:
269 raise KeyError(f
'Unconfigured campaign {e} for userPileupConfigsPerCampaign!')
271 elif self.userPileupConfigs
is not None:
272 toolConfigFiles = self.userPileupConfigs[:]
273 log.info(
'Using user provided PRW configuration')
276 if self.useDefaultConfig
and self.
files is None:
277 raise ValueError(
'useDefaultConfig requires files to be configured! '
278 'Either pass them as an option or use flags.')
280 from PileupReweighting.AutoconfigurePRW
import getConfigurationFiles
281 if campaign
and campaign
is not Campaign.Unknown:
284 useDefaultConfig=self.useDefaultConfig,
285 data_type=config.dataType())
286 if self.useDefaultConfig:
287 log.info(
'Auto-configuring universal/default PRW config')
289 log.info(
'Auto-configuring per-sample PRW config files based on input files')
291 log.info(
'No campaign specified, no PRW config files configured')
294 if self.userLumicalcFilesPerCampaign
is not None and self.userLumicalcFiles
is not None:
295 raise ValueError(
'Both userLumicalcFiles and userLumicalcFilesYear specified, '
296 'use only one of the options!')
297 if self.userLumicalcFilesPerCampaign
is not None:
299 toolLumicalcFiles = self.userLumicalcFilesPerCampaign[campaign.value][:]
300 log.info(
'Using user-provided per-campaign lumicalc files')
301 except KeyError
as e:
302 raise KeyError(f
'Unconfigured campaign {e} for userLumicalcFilesPerCampaign!')
303 elif self.userLumicalcFiles
is not None:
304 toolLumicalcFiles = self.userLumicalcFiles[:]
305 log.info(
'Using user-provided lumicalc files')
307 if campaign
and campaign
is not Campaign.Unknown:
308 from PileupReweighting.AutoconfigurePRW
import getLumicalcFiles
310 log.info(
'Using auto-configured lumicalc files')
312 log.info(
'No campaign specified, no lumicalc files configured for PRW')
314 log.info(
'Data needs no lumicalc and PRW configuration files')
317 if config.geometry()
is LHCPeriod.Run4:
318 log.warning (
'Pileup reweighting is not yet supported for Run 4 geometry')
319 alg = config.createAlgorithm(
'CP::EventDecoratorAlg',
'EventDecoratorAlg' )
320 alg.uint32Decorations = {
'RandomRunNumber' :
321 config.flags.Input.RunNumbers[0] }
324 alg = config.createAlgorithm(
'CP::PileupReweightingAlg',
325 'PileupReweightingAlg' )
326 config.addPrivateTool(
'pileupReweightingTool',
'CP::PileupReweightingTool' )
327 alg.pileupReweightingTool.ConfigFiles = toolConfigFiles
328 if not toolConfigFiles
and config.dataType()
is not DataType.Data:
329 log.info(
"No PRW config files provided. Disabling reweighting")
331 alg.pileupWeightDecoration =
""
333 alg.pileupWeightDecoration =
"PileupWeight" + self.postfix +
"_%SYS%"
334 alg.pileupReweightingTool.LumiCalcFiles = toolLumicalcFiles
336 if not self.alternativeConfig:
337 for var
in eventInfoVar:
338 config.addOutputVar (
'EventInfo', var, var, noSys=
True)
340 if config.dataType()
is not DataType.Data
and config.geometry()
is LHCPeriod.Run2:
341 config.addOutputVar (
'EventInfo',
'beamSpotWeight',
'weight_beamspot', noSys=
True)
343 if config.dataType()
is not DataType.Data
and toolConfigFiles:
344 config.addOutputVar (
'EventInfo',
'PileupWeight' + self.postfix +
'_%SYS%',
345 'weight_pileup'+self.postfix)
349 """the ConfigBlock for generator algorithms"""
352 super (GeneratorAnalysisBlock, self).__init__ ()
353 self.addOption (
'saveCutBookkeepers',
True, type=bool,
354 info=
"whether to save the cut bookkeepers information into the "
355 "output file. The default is True.")
356 self.addOption (
'runNumber',
None, type=int,
357 info=
"the MC runNumber (int). The default is None (autoconfigure "
359 self.addOption (
'cutBookkeepersSystematics',
None, type=bool,
360 info=
"whether to also save the cut bookkeepers systematics. The "
361 "default is None (follows the global systematics flag). Set to "
362 "False or True to override.")
363 self.addOption (
'histPattern',
None, type=str,
364 info=
"the histogram name pattern for the cut-bookkeeper histogram names")
365 self.addOption (
'streamName',
'ANALYSIS', type=str,
366 info=
"name of the output stream to save the cut bookkeeper in. "
367 "The default is ANALYSIS.")
368 self.addOption (
'detailedPDFinfo',
False, type=bool,
369 info=
"save the necessary information to run the LHAPDF tool offline. "
370 "The default is False.")
371 self.addOption (
'doHFProdFracReweighting',
False, type=bool,
372 info=
"whether to apply HF production fraction reweighting. "
373 "The default is False.")
374 self.addOption (
'truthParticleContainer',
'TruthParticles', type=str,
375 info=
"the name of the truth particle container to use for HF production fraction reweighting. "
376 "The default is 'TruthParticles'. ")
378 """Return the instance name for this block"""
379 return self.streamName
383 if config.dataType()
is DataType.Data:
386 log = logging.getLogger(
'makeGeneratorAnalysisSequence')
391 if self.saveCutBookkeepers
and not self.
runNumber:
392 raise ValueError (
"invalid run number: " +
str(self.
runNumber))
395 if self.saveCutBookkeepers:
396 alg = config.createAlgorithm(
'CP::AsgCutBookkeeperAlg',
'CutBookkeeperAlg')
397 alg.RootStreamName = self.streamName
399 if self.cutBookkeepersSystematics
is None:
400 alg.enableSystematics =
not config.noSystematics()
402 alg.enableSystematics = self.cutBookkeepersSystematics
404 alg.histPattern = self.histPattern
405 config.addPrivateTool(
'truthWeightTool',
'PMGTools::PMGTruthWeightTool' )
408 alg = config.createAlgorithm(
'CP::PMGTruthWeightAlg',
'PMGTruthWeightAlg' )
409 config.addPrivateTool(
'truthWeightTool',
'PMGTools::PMGTruthWeightTool' )
410 alg.decoration =
'generatorWeight_%SYS%'
411 config.addOutputVar (
'EventInfo',
'generatorWeight_%SYS%',
'weight_mc')
413 if self.detailedPDFinfo:
414 alg = config.createAlgorithm(
'CP::PDFinfoAlg',
'PDFinfoAlg', reentrant=
True )
415 for var
in [
"PDFID1",
"PDFID2",
"PDGID1",
"PDGID2",
"Q",
"X1",
"X2",
"XF1",
"XF2"]:
416 config.addOutputVar (
'EventInfo', var,
'PDFinfo_' + var, noSys=
True)
418 if self.doHFProdFracReweighting:
419 generatorInfo = config.flags.Input.GeneratorsInfo
420 log.info(f
"Loaded generator info: {generatorInfo}")
424 if not generatorInfo:
425 log.warning(
"No generator info found.")
427 elif isinstance(generatorInfo, dict):
428 if "Pythia8" in generatorInfo:
430 elif "Sherpa" in generatorInfo
and "2.2.8" in generatorInfo[
"Sherpa"]:
432 elif "Sherpa" in generatorInfo
and "2.2.10" in generatorInfo[
"Sherpa"]:
434 elif "Sherpa" in generatorInfo
and "2.2.11" in generatorInfo[
"Sherpa"]:
435 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.11. Using weights for Sherpa 2.2.10 instead.")
437 elif "Sherpa" in generatorInfo
and "2.2.12" in generatorInfo[
"Sherpa"]:
438 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.12. Using weights for Sherpa 2.2.10 instead.")
440 elif "Sherpa" in generatorInfo
and "2.2.14" in generatorInfo[
"Sherpa"]:
441 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.14. New weights need to be calculated.")
443 elif "Sherpa" in generatorInfo
and "2.2.1" in generatorInfo[
"Sherpa"]:
445 elif "Herwig7" in generatorInfo
and "7.1.3" in generatorInfo[
"Herwig7"]:
447 elif "Herwig7" in generatorInfo
and "7.2.1" in generatorInfo[
"Herwig7"]:
449 elif "Herwig7" in generatorInfo
and "7." in generatorInfo[
"Herwig7"]:
451 elif "amc@NLO" in generatorInfo:
454 log.warning(f
"HF production fraction reweighting is not configured for this generator: {generatorInfo}")
455 log.warning(
"New weights need to be calculated.")
458 log.warning(
"Failed to determine generator from metadata")
461 log.info(f
"Using HF production fraction weights calculated using DSID {DSID}")
463 log.warning(
"HF production fraction reweighting will return dummy weights of 1.0")
465 alg = config.createAlgorithm(
'CP::SysTruthWeightAlg',
'SysTruthWeightAlg' + self.streamName )
466 config.addPrivateTool(
'sysTruthWeightTool',
'PMGTools::PMGHFProductionFractionTool' )
467 alg.decoration =
'prodFracWeight_%SYS%'
468 alg.TruthParticleContainer = self.truthParticleContainer
469 alg.sysTruthWeightTool.ShowerGenerator = DSID
470 config.addOutputVar (
'EventInfo',
'prodFracWeight_%SYS%',
'weight_HF_prod_frac')
473 """the ConfigBlock for a pt-eta selection"""
476 super (PtEtaSelectionBlock, self).__init__ ()
477 self.addOption (
'containerName',
'', type=str,
479 info=
"the name of the input container.")
480 self.addOption (
'selectionName',
'', type=str,
482 info=
"the name of the selection to append this to. The default is "
483 "'' (empty string), meaning that the cuts are applied to every "
484 "object within the container. Specifying a name (e.g. loose) "
485 "applies the cut only to those object who also pass that selection.")
486 self.addOption (
'minPt',
None, type=float,
487 info=
"minimum pT value to cut on, in MeV. No default value.")
488 self.addOption (
'maxPt',
None, type=float,
489 info=
"maximum pT value to cut on, in MeV. No default value.")
490 self.addOption (
'minEta',
None, type=float,
491 info=
"minimum |eta| value to cut on. No default value.")
492 self.addOption (
'maxEta',
None, type=float,
493 info=
"maximum |eta| value to cut on. No default value.")
494 self.addOption (
'maxRapidity',
None, type=float,
495 info=
"maximum rapidity value to cut on. No default value.")
496 self.addOption (
'etaGapLow',
None, type=float,
497 info=
"low end of the |eta| gap. No default value.")
498 self.addOption (
'etaGapHigh',
None, type=float,
499 info=
"high end of the |eta| gap. No default value.")
500 self.addOption (
'selectionDecoration',
None, type=str,
501 info=
"the name of the decoration to set. If 'None', will be set "
502 "to 'selectPtEta' followed by the selection name.")
503 self.addOption (
'useClusterEta',
False, type=bool,
504 info=
"whether to use the cluster eta (etaBE(2)) instead of the object "
505 "eta (for electrons and photons). The default is False.")
506 self.addOption (
'useDressedProperties',
False, type=bool,
507 info=
"whether to use the dressed kinematic properties "
508 "(for truth particles only). The default is False.")
511 """Return the instance name for this block"""
512 return self.containerName +
"_" + self.selectionName
516 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'PtEtaSelectionAlg' )
517 config.addPrivateTool(
'selectionTool',
'CP::AsgPtEtaSelectionTool' )
518 if self.minPt
is not None :
519 alg.selectionTool.minPt = self.minPt
520 if self.maxPt
is not None:
521 alg.selectionTool.maxPt = self.maxPt
522 if self.minEta
is not None:
523 alg.selectionTool.minEta = self.minEta
524 if self.maxEta
is not None :
525 alg.selectionTool.maxEta = self.maxEta
526 if self.maxRapidity
is not None :
527 alg.selectionTool.maxRapidity = self.maxRapidity
528 if self.etaGapLow
is not None:
529 alg.selectionTool.etaGapLow = self.etaGapLow
530 if self.etaGapHigh
is not None:
531 alg.selectionTool.etaGapHigh = self.etaGapHigh
534 alg.selectionTool.useClusterEta = self.useClusterEta
535 alg.selectionTool.useDressedProperties = self.useDressedProperties
537 alg.particles = config.readName (self.containerName)
538 alg.preselection = config.getPreselection (self.containerName,
'')
539 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration)
544 """the ConfigBlock for an object cutflow"""
547 super (ObjectCutFlowBlock, self).__init__ ()
548 self.addOption (
'containerName',
'', type=str,
550 info=
"the name of the input container.")
551 self.addOption (
'selectionName',
'', type=str,
553 info=
"the name of the selection to perform the cutflow for. The "
554 "default is '' (empty string), meaning that the cutflow is "
555 "performed for every object within the container. Specifying a "
556 "name (e.g. loose) generates the cutflow only for those object "
557 "that also pass that selection.")
558 self.addOption (
'forceCutSequence',
False, type=bool,
559 info=
"whether to force the cut sequence and not accept objects "
560 "if previous cuts failed. The default is False.")
563 """Return the instance name for this block"""
564 return self.containerName +
'_' + self.selectionName
568 alg = config.createAlgorithm(
'CP::ObjectCutFlowHistAlg',
'CutFlowDumperAlg' )
569 alg.histPattern =
'cflow_' + self.containerName +
"_" + self.selectionName +
'_%SYS%'
570 alg.selections = config.getSelectionCutFlow (self.containerName, self.selectionName)
571 alg.input = config.readName (self.containerName)
572 alg.histTitle =
"Object Cutflow: " + self.containerName +
"." + self.selectionName
573 alg.forceCutSequence = self.forceCutSequence
577 """the ConfigBlock for an event-level cutflow"""
580 super (EventCutFlowBlock, self).__init__ ()
581 self.addOption (
'containerName',
'', type=str,
583 info=
"the name of the input container, typically EventInfo.")
584 self.addOption (
'selectionName',
'', type=str,
586 info=
"the name of an optional selection decoration to use.")
587 self.addOption (
'customSelections', [], type=
None,
588 info=
"the selections for which to generate cutflow histograms. If "
589 "a single string, corresponding to a particular event selection, "
590 "the event cutflow for that selection will be looked up. If a list "
591 "of strings, will use explicitly those selections. If left blank, "
592 "all selections attached to the container will be looked up.")
593 self.addOption (
'postfix',
'', type=str,
594 info=
"a postfix to apply in the naming of cutflow histograms. Set "
595 "it when defining multiple cutflows.")
598 """Return the instance name for this block"""
599 return self.containerName +
'_' + self.selectionName + self.postfix
603 postfix = self.postfix
604 if postfix !=
'' and postfix[0] !=
'_' :
605 postfix =
'_' + postfix
607 alg = config.createAlgorithm(
'CP::EventCutFlowHistAlg',
'CutFlowDumperAlg' )
608 alg.histPattern =
'cflow_' + self.containerName +
"_" + self.selectionName + postfix +
'_%SYS%'
610 if isinstance(self.customSelections, str):
612 alg.selections = config.getEventCutFlow(self.customSelections)
613 elif len(self.customSelections) > 0:
615 alg.selections = self.customSelections
618 alg.selections = config.getSelectionCutFlow (self.containerName, self.selectionName)
619 alg.selections = [sel+
',as_char' for sel
in alg.selections]
620 if self.selectionName:
621 alg.preselection = self.selectionName +
'_%SYS%'
622 alg.eventInfo = config.readName (self.containerName)
623 alg.histTitle =
"Event Cutflow: " + self.containerName +
"." + self.selectionName
627 """the ConfigBlock for output thinning"""
630 super (OutputThinningBlock, self).__init__ ()
631 self.addOption (
'containerName',
'', type=str,
633 info=
"the name of the input container.")
634 self.addOption (
'postfix',
'', type=str,
635 info=
"a postfix to apply to decorations and algorithm names. "
636 "Typically not needed here.")
637 self.addOption (
'selection',
'', type=str,
638 info=
"the name of an optional selection decoration to use.")
639 self.addOption (
'selectionName',
'', type=str,
640 info=
"the name of the selection to append this to. The default is "
641 "'' (empty string), meaning that the cuts are applied to every "
642 "object within the container. Specifying a name (e.g. loose) "
643 "applies the cut only to those object who also pass that selection.")
644 self.addOption (
'outputName',
None, type=str,
645 info=
"an optional name for the output container.")
647 self.addOption (
'deepCopy',
False, type=bool,
649 self.addOption (
'sortPt',
False, type=bool,
650 info=
"whether to sort objects in pt")
652 self.addOption (
'noUniformSelection',
False, type=bool,
656 """Return the instance name for this block"""
657 return self.containerName +
'_' + self.selectionName + self.postfix
661 postfix = self.postfix
662 if postfix !=
'' and postfix[0] !=
'_' :
663 postfix =
'_' + postfix
665 selection = config.getFullSelection (self.containerName, self.selectionName)
667 selection = self.selection
668 elif self.selection !=
'' :
669 selection = selection +
'&&' + self.selection
671 if selection !=
'' and not self.noUniformSelection :
672 alg = config.createAlgorithm(
'CP::AsgUnionSelectionAlg',
'UnionSelectionAlg')
673 alg.preselection = selection
674 alg.particles = config.readName (self.containerName)
675 alg.selectionDecoration =
'outputSelect' + postfix
676 config.addSelection (self.containerName, alg.selectionDecoration, selection)
677 selection =
'outputSelect' + postfix
679 alg = config.createAlgorithm(
'CP::AsgViewFromSelectionAlg',
'DeepCopyAlg' )
680 alg.input = config.readName (self.containerName)
681 if self.outputName
is not None :
682 alg.output = self.outputName +
'_%SYS%'
683 config.addOutputContainer (self.containerName, self.outputName)
685 alg.output = config.copyName (self.containerName)
687 alg.selection = [selection]
690 alg.deepCopy = self.deepCopy
691 if self.sortPt
and not config.noSystematics() :
692 raise ValueError (
"Sorting by pt is not supported with systematics")
693 alg.sortPt = self.sortPt
697 """the ConfigBlock for the IFF classification of leptons"""
700 super (IFFLeptonDecorationBlock, self).
__init__()
701 self.addOption (
'containerName',
'', type=str,
703 info=
"the name of the input electron or muon container.")
704 self.addOption (
'separateChargeFlipElectrons',
True, type=bool,
705 info=
"whether to consider charged-flip electrons as a separate class. "
706 "The default is True (recommended).")
707 self.addOption (
'decoration',
'IFFClass_%SYS%', type=str,
708 info=
"the name (str) of the decoration set by the IFF "
709 "TruthClassificationTool. The default is 'IFFClass_%SYS%'.")
711 self.setOptionValue(
'skipOnData',
True)
714 """Return the instance name for this block"""
715 return self.containerName
718 particles = config.readName(self.containerName)
720 alg = config.createAlgorithm(
'CP::AsgClassificationDecorationAlg',
'IFFClassifierAlg' )
722 config.addPrivateTool(
'tool',
'TruthClassificationTool')
724 alg.tool.separateChargeFlipElectrons = self.separateChargeFlipElectrons
725 alg.decoration = self.decoration
726 alg.particles = particles
729 config.addOutputVar(self.containerName, alg.decoration, alg.decoration.split(
"_%SYS%")[0], noSys=
True)
735 super (MCTCLeptonDecorationBlock, self).__init__ ()
737 self.addOption (
"containerName",
'', type=str,
739 info=
"the input lepton container, with a possible selection, "
740 "in the format container or container.selection.")
741 self.addOption (
"prefix",
'MCTC_', type=str,
742 info=
"the prefix (str) of the decorations based on the MCTC "
743 "classification. The default is 'MCTC_'.")
745 self.setOptionValue(
'skipOnData',
True)
748 """Return the instance name for this block"""
749 return self.containerName
752 particles, selection = config.readNameAndSelection(self.containerName)
754 alg = config.createAlgorithm (
"CP::MCTCDecorationAlg",
"MCTCDecorationAlg")
755 alg.particles = particles
756 alg.preselection = selection
757 alg.affectingSystematicsFilter =
'.*'
758 config.addOutputVar (self.containerName,
"MCTC_isPrompt", f
"{self.prefix}isPrompt", noSys=
True)
759 config.addOutputVar (self.containerName,
"MCTC_fromHadron", f
"{self.prefix}fromHadron", noSys=
True)
760 config.addOutputVar (self.containerName,
"MCTC_fromBSM", f
"{self.prefix}fromBSM", noSys=
True)
761 config.addOutputVar (self.containerName,
"MCTC_fromTau", f
"{self.prefix}fromTau", noSys=
True)
765 """the ConfigBlock for the AsgEventScaleFactorAlg"""
768 super(PerEventSFBlock, self).
__init__()
769 self.addOption(
'algoName',
None, type=str,
770 info=
"unique name given to the underlying algorithm computing the "
771 "per-event scale factors")
772 self.addOption(
'particles',
'', type=str,
773 info=
"the input object container, with a possible selection, in the "
774 "format container or container.selection.")
775 self.addOption(
'objectSF',
'', type=str,
776 info=
"the name of the per-object SF decoration to be used.")
777 self.addOption(
'eventSF',
'', type=str,
778 info=
"the name of the per-event SF decoration.")
781 """Return the instance name for this block"""
782 return self.particles +
'_' + self.objectSF +
'_' + self.eventSF
785 if config.dataType()
is DataType.Data:
787 particles, selection = config.readNameAndSelection(self.particles)
788 alg = config.createAlgorithm(
'CP::AsgEventScaleFactorAlg', self.algoName
if self.algoName
else 'AsgEventScaleFactorAlg')
789 alg.particles = particles
790 alg.preselection = selection
791 alg.scaleFactorInputDecoration = self.objectSF
792 alg.scaleFactorOutputDecoration = self.eventSF
794 config.addOutputVar(
'EventInfo', alg.scaleFactorOutputDecoration,
795 alg.scaleFactorOutputDecoration.split(
"_%SYS%")[0])
799 """the ConfigBlock to add selection decoration to a container"""
802 super (SelectionDecorationBlock, self).__init__ ()
804 self.addOption(
'containers', [], type=list,
809 """Return the instance name for this block"""
813 for container
in self.containers:
814 originContainerName = config.getOutputContainerOrigin(container)
815 selectionNames = config.getSelectionNames(originContainerName)
816 for selectionName
in selectionNames:
818 if selectionName ==
'':
820 alg = config.createAlgorithm(
821 'CP::AsgSelectionAlg',
822 f
'SelectionDecoration_{originContainerName}_{selectionName}')
823 selectionDecoration = f
'baselineSelection_{selectionName}_%SYS%'
824 alg.selectionDecoration = f
'{selectionDecoration},as_char'
825 alg.particles = config.readName (originContainerName)
826 alg.preselection = config.getFullSelection (originContainerName,
829 originContainerName, selectionDecoration, selectionName)
832 *, postfix=None, selectionName, customSelections=None):
833 """Create an event-level cutflow config
836 containerName -- name of the container
837 postfix -- a postfix to apply to decorations and algorithm names.
838 selectionName -- the name of the selection to do the cutflow for
839 customSelections -- a list of decorations to use in the cutflow, to override the retrieval of all decorations
843 config.setOptionValue(
'containerName', containerName)
844 config.setOptionValue(
'selectionName', selectionName)
845 config.setOptionValue(
'postfix', postfix)
846 config.setOptionValue(
'customSelections', customSelections)