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 (
'metadataHistogram',
None , type=str,
60 info=
"the name (string) of the metadata histogram which contains information about "
61 "data type, campaign, etc. The default is None (don't write out "
63 self.addOption (
'enableExpertMode',
False, type=bool,
64 info=
"allows CP experts and CPAlgorithm devs to use non-recommended configurations. "
65 "DO NOT USE FOR ANALYSIS.")
66 self.addOption (
'streamName',
'ANALYSIS', type=str,
67 info=
"name of the output stream to save the cut bookkeeper in. "
68 "The default is ANALYSIS.")
71 """Return the instance name for this block"""
76 sysService = config.createService(
'CP::SystematicsSvc',
'SystematicsSvc' )
80 elif config.noSystematics()
is not None :
89 sysService.sigmaRecommended = 1
90 if config.dataType()
is DataType.Data:
95 requested_categories = []
98 category_enum = SystematicsCategories[category_str.upper()]
99 requested_categories += category_enum.value
101 raise ValueError(f
"Invalid systematics category passed to option 'onlySystematicsCategories': {category_str}. Must be one of {', '.join(category.name for category in SystematicsCategories)}")
103 if len(requested_categories):
104 sysService.systematicsRegex =
"^(?=.*(" +
"|".
join(requested_categories) +
")|$).*"
105 if self.filterSystematics
is not None:
106 sysService.systematicsRegex = self.filterSystematics
107 config.createService(
'CP::SelectionNameSvc',
'SelectionNameSvc')
109 if self.systematicsHistogram
is not None:
111 allSysDumper = config.createAlgorithm(
'CP::SysListDumperAlg',
'SystematicsPrinter' )
112 allSysDumper.histogramName = self.systematicsHistogram
113 allSysDumper.RootStreamName = self.streamName
115 if self.separateWeightSystematics:
117 weightSysDumper = config.createAlgorithm(
'CP::SysListDumperAlg',
'OnlyWeightSystematicsPrinter' )
118 weightSysDumper.histogramName = f
"{self.systematicsHistogram}OnlyWeights"
119 weightSysDumper.systematicsRegex =
"^(GEN_|EL_EFF_|MUON_EFF_|PH_EFF_|TAUS_TRUEHADTAU_EFF_|FT_EFF_|extrapolation_pt_|JET_.*JvtEfficiency_|PRW_).*"
121 if self.metadataHistogram
is not None:
124 raise ValueError (
"Writing out the metadata histogram requires to pass config flags")
125 metadataHistAlg = config.createAlgorithm(
'CP::MetadataHistAlg',
'MetadataHistAlg' )
126 metadataHistAlg.histogramName = self.metadataHistogram
127 metadataHistAlg.dataType =
str(config.dataType().value)
128 metadataHistAlg.campaign =
str(config.dataYear())
if config.dataType()
is DataType.Data
else str(config.campaign().value)
129 metadataHistAlg.mcChannelNumber =
str(config.dsid())
130 if config.dataType()
is DataType.Data:
133 from AthenaConfiguration.AutoConfigFlags
import GetFileMD
134 metadata =
GetFileMD(config.flags.Input.Files)
135 amiTags = metadata.get(
"AMITag",
"not found!")
136 etag =
str(amiTags.split(
"_")[0])
137 metadataHistAlg.etag = etag
139 if self.enableExpertMode
and config._pass == 0:
141 warnings.simplefilter(
'ignore', ExpertModeWarning)
143 log = logging.getLogger(
'CommonServices')
148 log.warning(red +
r"""
149 ________ _______ ______ _____ _______ __ __ ____ _____ ______ ______ _ _ ____ _ ______ _____
150 | ____\ \ / / __ \| ____| __ \__ __| | \/ |/ __ \| __ \| ____| | ____| \ | | /\ | _ \| | | ____| __ \
151 | |__ \ V /| |__) | |__ | |__) | | | | \ / | | | | | | | |__ | |__ | \| | / \ | |_) | | | |__ | | | |
152 | __| > < | ___/| __| | _ / | | | |\/| | | | | | | | __| | __| | . ` | / /\ \ | _ <| | | __| | | | |
153 | |____ / . \| | | |____| | \ \ | | | | | | |__| | |__| | |____ | |____| |\ |/ ____ \| |_) | |____| |____| |__| |
154 |______/_/ \_\_| |______|_| \_\ |_| |_| |_|\____/|_____/|______| |______|_| \_/_/ \_\____/|______|______|_____/
158 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}")
165 from AsgAnalysisAlgorithms.TruthCollectionsFixerConfig
import TruthCollectionsFixerBlock
166 seq.append(TruthCollectionsFixerBlock())
169 """Print what branches are used in analysis"""
172 super(IOStatsBlock, self).
__init__()
173 self.addOption(
"printOption",
"Summary", type=str,
174 info=
'option to pass the standard ROOT printing function. Can be "Summary", "ByEntries" or "ByBytes".')
177 """Return the instance name for this block"""
181 alg = config.createAlgorithm(
'CP::IOStatsAlg',
'IOStatsAlg')
182 alg.printOption = self.printOption
186 """the ConfigBlock for pileup reweighting"""
189 super (PileupReweightingBlock, self).__init__ ()
190 self.addOption (
'campaign',
None, type=
None,
191 info=
"the MC campaign for the PRW auto-configuration.")
192 self.addOption (
'files',
None, type=
None,
193 info=
"the input files being processed (list of strings). "
194 "Alternative to auto-configuration.")
195 self.addOption (
'useDefaultConfig',
True, type=bool,
196 info=
"whether to use the central PRW files. The default is True.")
197 self.addOption (
'userLumicalcFiles',
None, type=
None,
198 info=
"user-provided lumicalc files (list of strings). Alternative "
199 "to auto-configuration.")
200 self.addOption (
'userLumicalcFilesPerCampaign',
None, type=
None,
201 info=
"user-provided lumicalc files (dictionary of list of strings, "
202 "with MC campaigns as the keys). Alternative to auto-configuration.")
203 self.addOption (
'userPileupConfigs',
None, type=
None,
204 info=
"user-provided PRW files (list of strings). Alternative to "
205 "auto-configuration. Alternative to auto-configuration.")
206 self.addOption (
'userPileupConfigsPerCampaign',
None, type=
None,
207 info=
"user-provided PRW files (dictionary of list of strings, with "
208 "MC campaigns as the keys)")
209 self.addOption (
'postfix',
'', type=str,
210 info=
"a postfix to apply to decorations and algorithm names. "
211 "Typically not needed unless several instances of PileupReweighting are scheduled.")
212 self.addOption (
'alternativeConfig',
False, type=bool,
213 info=
"whether this is used as an additional alternative config for PileupReweighting. "
214 "Will only store the alternative pile up weight in that case.")
215 self.addOption (
'writeColumnarToolVariables',
False, type=bool,
216 info=
"whether to add EventInfo variables needed for running the columnar tool(s) on the output n-tuple. (EXPERIMENTAL)",
220 """Return the instance name for this block"""
225 from Campaigns.Utils
import Campaign
227 log = logging.getLogger(
'makePileupAnalysisSequence')
229 eventInfoVar = [
'runNumber',
'eventNumber',
'actualInteractionsPerCrossing',
'averageInteractionsPerCrossing']
230 if config.dataType()
is not DataType.Data:
231 eventInfoVar += [
'mcChannelNumber']
232 if self.writeColumnarToolVariables:
236 eventInfoVar += [
'eventTypeBitmask']
238 if config.isPhyslite()
and not self.alternativeConfig:
240 log.info(f
'Physlite does not need pileup reweighting. Variables will be copied from input instead. {config.isPhyslite}')
241 for var
in eventInfoVar:
242 config.addOutputVar (
'EventInfo', var, var, noSys=
True)
244 if config.dataType()
is not DataType.Data:
245 config.addOutputVar (
'EventInfo',
'PileupWeight_%SYS%',
'weight_pileup')
246 if config.geometry()
is LHCPeriod.Run2:
247 config.addOutputVar (
'EventInfo',
'beamSpotWeight',
'weight_beamspot', noSys=
True)
251 if self.
files is None and config.flags
is not None:
252 self.
files = config.flags.Input.Files
254 campaign = self.campaign
257 if config.dataType()
is not DataType.Data
and self.campaign
is None:
259 if config.campaign()
is not None and config.campaign()
is not Campaign.Unknown:
260 campaign = config.campaign()
261 log.info(f
'Auto-configuring campaign for PRW from flags: {campaign.value}')
264 if self.
files is not None:
265 from Campaigns.Utils
import getMCCampaign
267 if campaign
and campaign
is not Campaign.Unknown:
268 log.info(f
'Auto-configuring campaign for PRW from files: {campaign.value}')
270 log.info(
'Campaign could not be determined.')
274 toolLumicalcFiles = []
278 if (config.dataType()
is not DataType.Data
and
279 config.geometry()
is not LHCPeriod.Run4):
281 if self.userPileupConfigs
is not None and self.userPileupConfigsPerCampaign
is not None:
282 raise ValueError(
'Both userPileupConfigs and userPileupConfigsPerCampaign specified, '
283 'use only one of the options!')
284 if self.userPileupConfigsPerCampaign
is not None:
286 raise Exception(
'userPileupConfigsPerCampaign requires campaign to be configured!')
287 if campaign
is Campaign.Unknown:
288 raise Exception(
'userPileupConfigsPerCampaign used, but campaign = Unknown!')
290 toolConfigFiles = self.userPileupConfigsPerCampaign[campaign.value][:]
291 log.info(
'Using user provided per-campaign PRW configuration')
292 except KeyError
as e:
293 raise KeyError(f
'Unconfigured campaign {e} for userPileupConfigsPerCampaign!')
295 elif self.userPileupConfigs
is not None:
296 toolConfigFiles = self.userPileupConfigs[:]
297 log.info(
'Using user provided PRW configuration')
300 if self.useDefaultConfig
and self.
files is None:
301 raise ValueError(
'useDefaultConfig requires files to be configured! '
302 'Either pass them as an option or use flags.')
304 from PileupReweighting.AutoconfigurePRW
import getConfigurationFiles
305 if campaign
and campaign
is not Campaign.Unknown:
308 useDefaultConfig=self.useDefaultConfig,
309 data_type=config.dataType())
310 if self.useDefaultConfig:
311 log.info(
'Auto-configuring universal/default PRW config')
313 log.info(
'Auto-configuring per-sample PRW config files based on input files')
315 log.info(
'No campaign specified, no PRW config files configured')
318 if self.userLumicalcFilesPerCampaign
is not None and self.userLumicalcFiles
is not None:
319 raise ValueError(
'Both userLumicalcFiles and userLumicalcFilesYear specified, '
320 'use only one of the options!')
321 if self.userLumicalcFilesPerCampaign
is not None:
323 toolLumicalcFiles = self.userLumicalcFilesPerCampaign[campaign.value][:]
324 log.info(
'Using user-provided per-campaign lumicalc files')
325 except KeyError
as e:
326 raise KeyError(f
'Unconfigured campaign {e} for userLumicalcFilesPerCampaign!')
327 elif self.userLumicalcFiles
is not None:
328 toolLumicalcFiles = self.userLumicalcFiles[:]
329 log.info(
'Using user-provided lumicalc files')
331 if campaign
and campaign
is not Campaign.Unknown:
332 from PileupReweighting.AutoconfigurePRW
import getLumicalcFiles
334 log.info(
'Using auto-configured lumicalc files')
336 log.info(
'No campaign specified, no lumicalc files configured for PRW')
338 log.info(
'Data needs no lumicalc and PRW configuration files')
341 if config.geometry()
is LHCPeriod.Run4:
342 log.warning (
'Pileup reweighting is not yet supported for Run 4 geometry')
343 alg = config.createAlgorithm(
'CP::EventDecoratorAlg',
'EventDecoratorAlg' )
344 alg.uint32Decorations = {
'RandomRunNumber' :
345 config.flags.Input.RunNumbers[0] }
348 alg = config.createAlgorithm(
'CP::PileupReweightingAlg',
349 'PileupReweightingAlg' )
350 config.addPrivateTool(
'pileupReweightingTool',
'CP::PileupReweightingTool' )
351 alg.pileupReweightingTool.ConfigFiles = toolConfigFiles
352 if not toolConfigFiles
and config.dataType()
is not DataType.Data:
353 log.info(
"No PRW config files provided. Disabling reweighting")
355 alg.pileupWeightDecoration =
""
357 alg.pileupWeightDecoration =
"PileupWeight" + self.postfix +
"_%SYS%"
358 alg.pileupReweightingTool.LumiCalcFiles = toolLumicalcFiles
360 if not self.alternativeConfig:
361 for var
in eventInfoVar:
362 config.addOutputVar (
'EventInfo', var, var, noSys=
True)
364 if config.dataType()
is not DataType.Data
and config.geometry()
is LHCPeriod.Run2:
365 config.addOutputVar (
'EventInfo',
'beamSpotWeight',
'weight_beamspot', noSys=
True)
367 if config.dataType()
is not DataType.Data
and toolConfigFiles:
368 config.addOutputVar (
'EventInfo',
'PileupWeight' + self.postfix +
'_%SYS%',
369 'weight_pileup'+self.postfix)
373 """the ConfigBlock for generator algorithms"""
376 super (GeneratorAnalysisBlock, self).__init__ ()
377 self.addOption (
'saveCutBookkeepers',
True, type=bool,
378 info=
"whether to save the cut bookkeepers information into the "
379 "output file. The default is True.")
380 self.addOption (
'runNumber',
None, type=int,
381 info=
"the MC runNumber (int). The default is None (autoconfigure "
383 self.addOption (
'cutBookkeepersSystematics',
None, type=bool,
384 info=
"whether to also save the cut bookkeepers systematics. The "
385 "default is None (follows the global systematics flag). Set to "
386 "False or True to override.")
387 self.addOption (
'histPattern',
None, type=str,
388 info=
"the histogram name pattern for the cut-bookkeeper histogram names")
389 self.addOption (
'streamName',
'ANALYSIS', type=str,
390 info=
"name of the output stream to save the cut bookkeeper in. "
391 "The default is ANALYSIS.")
392 self.addOption (
'detailedPDFinfo',
False, type=bool,
393 info=
"save the necessary information to run the LHAPDF tool offline. "
394 "The default is False.")
395 self.addOption (
'doHFProdFracReweighting',
False, type=bool,
396 info=
"whether to apply HF production fraction reweighting. "
397 "The default is False.")
398 self.addOption (
'truthParticleContainer',
'TruthParticles', type=str,
399 info=
"the name of the truth particle container to use for HF production fraction reweighting. "
400 "The default is 'TruthParticles'. ")
402 """Return the instance name for this block"""
403 return self.streamName
407 if config.dataType()
is DataType.Data:
410 log = logging.getLogger(
'makeGeneratorAnalysisSequence')
415 if self.saveCutBookkeepers
and not self.
runNumber:
416 raise ValueError (
"invalid run number: " +
str(self.
runNumber))
419 if self.saveCutBookkeepers:
420 alg = config.createAlgorithm(
'CP::AsgCutBookkeeperAlg',
'CutBookkeeperAlg')
421 alg.RootStreamName = self.streamName
423 if self.cutBookkeepersSystematics
is None:
424 alg.enableSystematics =
not config.noSystematics()
426 alg.enableSystematics = self.cutBookkeepersSystematics
428 alg.histPattern = self.histPattern
429 config.addPrivateTool(
'truthWeightTool',
'PMGTools::PMGTruthWeightTool' )
432 alg = config.createAlgorithm(
'CP::PMGTruthWeightAlg',
'PMGTruthWeightAlg' )
433 config.addPrivateTool(
'truthWeightTool',
'PMGTools::PMGTruthWeightTool' )
434 alg.decoration =
'generatorWeight_%SYS%'
435 config.addOutputVar (
'EventInfo',
'generatorWeight_%SYS%',
'weight_mc')
437 if self.detailedPDFinfo:
438 alg = config.createAlgorithm(
'CP::PDFinfoAlg',
'PDFinfoAlg', reentrant=
True )
439 for var
in [
"PDFID1",
"PDFID2",
"PDGID1",
"PDGID2",
"Q",
"X1",
"X2",
"XF1",
"XF2"]:
440 config.addOutputVar (
'EventInfo', var,
'PDFinfo_' + var, noSys=
True)
442 if self.doHFProdFracReweighting:
443 generatorInfo = config.flags.Input.GeneratorsInfo
444 log.info(f
"Loaded generator info: {generatorInfo}")
448 if not generatorInfo:
449 log.warning(
"No generator info found.")
451 elif isinstance(generatorInfo, dict):
452 if "Pythia8" in generatorInfo:
454 elif "Sherpa" in generatorInfo
and "2.2.8" in generatorInfo[
"Sherpa"]:
456 elif "Sherpa" in generatorInfo
and "2.2.10" in generatorInfo[
"Sherpa"]:
458 elif "Sherpa" in generatorInfo
and "2.2.11" in generatorInfo[
"Sherpa"]:
459 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.11. Using weights for Sherpa 2.2.10 instead.")
461 elif "Sherpa" in generatorInfo
and "2.2.12" in generatorInfo[
"Sherpa"]:
462 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.12. Using weights for Sherpa 2.2.10 instead.")
464 elif "Sherpa" in generatorInfo
and "2.2.14" in generatorInfo[
"Sherpa"]:
465 log.warning(
"HF production fraction reweighting is not configured for Sherpa 2.2.14. New weights need to be calculated.")
467 elif "Sherpa" in generatorInfo
and "2.2.1" in generatorInfo[
"Sherpa"]:
469 elif "Herwig7" in generatorInfo
and "7.1.3" in generatorInfo[
"Herwig7"]:
471 elif "Herwig7" in generatorInfo
and "7.2.1" in generatorInfo[
"Herwig7"]:
473 elif "Herwig7" in generatorInfo
and "7." in generatorInfo[
"Herwig7"]:
475 elif "amc@NLO" in generatorInfo:
478 log.warning(f
"HF production fraction reweighting is not configured for this generator: {generatorInfo}")
479 log.warning(
"New weights need to be calculated.")
482 log.warning(
"Failed to determine generator from metadata")
485 log.info(f
"Using HF production fraction weights calculated using DSID {DSID}")
487 log.warning(
"HF production fraction reweighting will return dummy weights of 1.0")
489 alg = config.createAlgorithm(
'CP::SysTruthWeightAlg',
'SysTruthWeightAlg' + self.streamName )
490 config.addPrivateTool(
'sysTruthWeightTool',
'PMGTools::PMGHFProductionFractionTool' )
491 alg.decoration =
'prodFracWeight_%SYS%'
492 alg.TruthParticleContainer = self.truthParticleContainer
493 alg.sysTruthWeightTool.ShowerGenerator = DSID
494 config.addOutputVar (
'EventInfo',
'prodFracWeight_%SYS%',
'weight_HF_prod_frac')
497 """the ConfigBlock for a pt-eta selection"""
500 super (PtEtaSelectionBlock, self).__init__ ()
501 self.addOption (
'containerName',
'', type=str,
503 info=
"the name of the input container.")
504 self.addOption (
'selectionName',
'', type=str,
506 info=
"the name of the selection to append this to. The default is "
507 "'' (empty string), meaning that the cuts are applied to every "
508 "object within the container. Specifying a name (e.g. loose) "
509 "applies the cut only to those object who also pass that selection.")
510 self.addOption (
'minPt',
None, type=float,
511 info=
"minimum pT value to cut on, in MeV. No default value.")
512 self.addOption (
'maxPt',
None, type=float,
513 info=
"maximum pT value to cut on, in MeV. No default value.")
514 self.addOption (
'minEta',
None, type=float,
515 info=
"minimum |eta| value to cut on. No default value.")
516 self.addOption (
'maxEta',
None, type=float,
517 info=
"maximum |eta| value to cut on. No default value.")
518 self.addOption (
'maxRapidity',
None, type=float,
519 info=
"maximum rapidity value to cut on. No default value.")
520 self.addOption (
'etaGapLow',
None, type=float,
521 info=
"low end of the |eta| gap. No default value.")
522 self.addOption (
'etaGapHigh',
None, type=float,
523 info=
"high end of the |eta| gap. No default value.")
524 self.addOption (
'selectionDecoration',
None, type=str,
525 info=
"the name of the decoration to set. If 'None', will be set "
526 "to 'selectPtEta' followed by the selection name.")
527 self.addOption (
'useClusterEta',
False, type=bool,
528 info=
"whether to use the cluster eta (etaBE(2)) instead of the object "
529 "eta (for electrons and photons). The default is False.")
530 self.addOption (
'useDressedProperties',
False, type=bool,
531 info=
"whether to use the dressed kinematic properties "
532 "(for truth particles only). The default is False.")
535 """Return the instance name for this block"""
536 return self.containerName +
"_" + self.selectionName
540 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'PtEtaSelectionAlg' )
541 config.addPrivateTool(
'selectionTool',
'CP::AsgPtEtaSelectionTool' )
542 if self.minPt
is not None :
543 alg.selectionTool.minPt = self.minPt
544 if self.maxPt
is not None:
545 alg.selectionTool.maxPt = self.maxPt
546 if self.minEta
is not None:
547 alg.selectionTool.minEta = self.minEta
548 if self.maxEta
is not None :
549 alg.selectionTool.maxEta = self.maxEta
550 if self.maxRapidity
is not None :
551 alg.selectionTool.maxRapidity = self.maxRapidity
552 if self.etaGapLow
is not None:
553 alg.selectionTool.etaGapLow = self.etaGapLow
554 if self.etaGapHigh
is not None:
555 alg.selectionTool.etaGapHigh = self.etaGapHigh
558 alg.selectionTool.useClusterEta = self.useClusterEta
559 alg.selectionTool.useDressedProperties = self.useDressedProperties
561 alg.particles = config.readName (self.containerName)
562 alg.preselection = config.getPreselection (self.containerName,
'')
563 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration)
568 """the ConfigBlock for an object cutflow"""
571 super (ObjectCutFlowBlock, self).__init__ ()
572 self.addOption (
'containerName',
'', type=str,
574 info=
"the name of the input container.")
575 self.addOption (
'selectionName',
'', type=str,
577 info=
"the name of the selection to perform the cutflow for. The "
578 "default is '' (empty string), meaning that the cutflow is "
579 "performed for every object within the container. Specifying a "
580 "name (e.g. loose) generates the cutflow only for those object "
581 "that also pass that selection.")
582 self.addOption (
'forceCutSequence',
False, type=bool,
583 info=
"whether to force the cut sequence and not accept objects "
584 "if previous cuts failed. The default is False.")
587 """Return the instance name for this block"""
588 return self.containerName +
'_' + self.selectionName
592 alg = config.createAlgorithm(
'CP::ObjectCutFlowHistAlg',
'CutFlowDumperAlg' )
593 alg.histPattern =
'cflow_' + self.containerName +
"_" + self.selectionName +
'_%SYS%'
594 alg.selections = config.getSelectionCutFlow (self.containerName, self.selectionName)
595 alg.input = config.readName (self.containerName)
596 alg.histTitle =
"Object Cutflow: " + self.containerName +
"." + self.selectionName
597 alg.forceCutSequence = self.forceCutSequence
601 """the ConfigBlock for an event-level cutflow"""
604 super (EventCutFlowBlock, self).__init__ ()
605 self.addOption (
'containerName',
'', type=str,
607 info=
"the name of the input container, typically EventInfo.")
608 self.addOption (
'selectionName',
'', type=str,
610 info=
"the name of an optional selection decoration to use.")
611 self.addOption (
'customSelections', [], type=
None,
612 info=
"the selections for which to generate cutflow histograms. If "
613 "a single string, corresponding to a particular event selection, "
614 "the event cutflow for that selection will be looked up. If a list "
615 "of strings, will use explicitly those selections. If left blank, "
616 "all selections attached to the container will be looked up.")
617 self.addOption (
'postfix',
'', type=str,
618 info=
"a postfix to apply in the naming of cutflow histograms. Set "
619 "it when defining multiple cutflows.")
622 """Return the instance name for this block"""
623 return self.containerName +
'_' + self.selectionName + self.postfix
627 postfix = self.postfix
628 if postfix !=
'' and postfix[0] !=
'_' :
629 postfix =
'_' + postfix
631 alg = config.createAlgorithm(
'CP::EventCutFlowHistAlg',
'CutFlowDumperAlg' )
632 alg.histPattern =
'cflow_' + self.containerName +
"_" + self.selectionName + postfix +
'_%SYS%'
634 if isinstance(self.customSelections, str):
636 alg.selections = config.getEventCutFlow(self.customSelections)
637 elif len(self.customSelections) > 0:
639 alg.selections = self.customSelections
642 alg.selections = config.getSelectionCutFlow (self.containerName, self.selectionName)
643 alg.selections = [sel+
',as_char' for sel
in alg.selections]
644 if self.selectionName:
645 alg.preselection = self.selectionName +
'_%SYS%'
646 alg.eventInfo = config.readName (self.containerName)
647 alg.histTitle =
"Event Cutflow: " + self.containerName +
"." + self.selectionName
651 """the ConfigBlock for output thinning"""
654 super (OutputThinningBlock, self).__init__ ()
655 self.addOption (
'containerName',
'', type=str,
657 info=
"the name of the input container.")
658 self.addOption (
'postfix',
'', type=str,
659 info=
"a postfix to apply to decorations and algorithm names. "
660 "Typically not needed here.")
661 self.addOption (
'selection',
'', type=str,
662 info=
"the name of an optional selection decoration to use.")
663 self.addOption (
'selectionName',
'', type=str,
664 info=
"the name of the selection to append this to. The default is "
665 "'' (empty string), meaning that the cuts are applied to every "
666 "object within the container. Specifying a name (e.g. loose) "
667 "applies the cut only to those object who also pass that selection.")
668 self.addOption (
'outputName',
None, type=str,
669 info=
"an optional name for the output container.")
671 self.addOption (
'deepCopy',
False, type=bool,
673 self.addOption (
'sortPt',
False, type=bool,
674 info=
"whether to sort objects in pt")
676 self.addOption (
'noUniformSelection',
False, type=bool,
680 """Return the instance name for this block"""
681 return self.containerName +
'_' + self.selectionName + self.postfix
685 postfix = self.postfix
686 if postfix !=
'' and postfix[0] !=
'_' :
687 postfix =
'_' + postfix
689 selection = config.getFullSelection (self.containerName, self.selectionName)
691 selection = self.selection
692 elif self.selection !=
'' :
693 selection = selection +
'&&' + self.selection
695 if selection !=
'' and not self.noUniformSelection :
696 alg = config.createAlgorithm(
'CP::AsgUnionSelectionAlg',
'UnionSelectionAlg')
697 alg.preselection = selection
698 alg.particles = config.readName (self.containerName)
699 alg.selectionDecoration =
'outputSelect' + postfix
700 config.addSelection (self.containerName, alg.selectionDecoration, selection)
701 selection =
'outputSelect' + postfix
703 alg = config.createAlgorithm(
'CP::AsgViewFromSelectionAlg',
'DeepCopyAlg' )
704 alg.input = config.readName (self.containerName)
705 if self.outputName
is not None :
706 alg.output = self.outputName +
'_%SYS%'
707 config.addOutputContainer (self.containerName, self.outputName)
709 alg.output = config.copyName (self.containerName)
711 alg.selection = [selection]
714 alg.deepCopy = self.deepCopy
715 if self.sortPt
and not config.noSystematics() :
716 raise ValueError (
"Sorting by pt is not supported with systematics")
717 alg.sortPt = self.sortPt
721 """the ConfigBlock for the IFF classification of leptons"""
724 super (IFFLeptonDecorationBlock, self).
__init__()
725 self.addOption (
'containerName',
'', type=str,
727 info=
"the name of the input electron or muon container.")
728 self.addOption (
'separateChargeFlipElectrons',
True, type=bool,
729 info=
"whether to consider charged-flip electrons as a separate class. "
730 "The default is True (recommended).")
731 self.addOption (
'decoration',
'IFFClass_%SYS%', type=str,
732 info=
"the name (str) of the decoration set by the IFF "
733 "TruthClassificationTool. The default is 'IFFClass_%SYS%'.")
735 self.setOptionValue(
'skipOnData',
True)
738 """Return the instance name for this block"""
739 return self.containerName
742 particles = config.readName(self.containerName)
744 alg = config.createAlgorithm(
'CP::AsgClassificationDecorationAlg',
'IFFClassifierAlg' )
746 config.addPrivateTool(
'tool',
'TruthClassificationTool')
748 alg.tool.separateChargeFlipElectrons = self.separateChargeFlipElectrons
749 alg.decoration = self.decoration
750 alg.particles = particles
753 config.addOutputVar(self.containerName, alg.decoration, alg.decoration.split(
"_%SYS%")[0], noSys=
True)
759 super (MCTCLeptonDecorationBlock, self).__init__ ()
761 self.addOption (
"containerName",
'', type=str,
763 info=
"the input lepton container, with a possible selection, "
764 "in the format container or container.selection.")
765 self.addOption (
"prefix",
'MCTC_', type=str,
766 info=
"the prefix (str) of the decorations based on the MCTC "
767 "classification. The default is 'MCTC_'.")
769 self.setOptionValue(
'skipOnData',
True)
772 """Return the instance name for this block"""
773 return self.containerName
776 particles, selection = config.readNameAndSelection(self.containerName)
778 alg = config.createAlgorithm (
"CP::MCTCDecorationAlg",
"MCTCDecorationAlg")
779 alg.particles = particles
780 alg.preselection = selection
781 alg.affectingSystematicsFilter =
'.*'
782 config.addOutputVar (self.containerName,
"MCTC_isPrompt", f
"{self.prefix}isPrompt", noSys=
True)
783 config.addOutputVar (self.containerName,
"MCTC_fromHadron", f
"{self.prefix}fromHadron", noSys=
True)
784 config.addOutputVar (self.containerName,
"MCTC_fromBSM", f
"{self.prefix}fromBSM", noSys=
True)
785 config.addOutputVar (self.containerName,
"MCTC_fromTau", f
"{self.prefix}fromTau", noSys=
True)
789 """the ConfigBlock for the AsgEventScaleFactorAlg"""
792 super(PerEventSFBlock, self).
__init__()
793 self.addOption(
'algoName',
None, type=str,
794 info=
"unique name given to the underlying algorithm computing the "
795 "per-event scale factors")
796 self.addOption(
'particles',
'', type=str,
797 info=
"the input object container, with a possible selection, in the "
798 "format container or container.selection.")
799 self.addOption(
'objectSF',
'', type=str,
800 info=
"the name of the per-object SF decoration to be used.")
801 self.addOption(
'eventSF',
'', type=str,
802 info=
"the name of the per-event SF decoration.")
805 """Return the instance name for this block"""
806 return self.particles +
'_' + self.objectSF +
'_' + self.eventSF
809 if config.dataType()
is DataType.Data:
811 particles, selection = config.readNameAndSelection(self.particles)
812 alg = config.createAlgorithm(
'CP::AsgEventScaleFactorAlg', self.algoName
if self.algoName
else 'AsgEventScaleFactorAlg')
813 alg.particles = particles
814 alg.preselection = selection
815 alg.scaleFactorInputDecoration = self.objectSF
816 alg.scaleFactorOutputDecoration = self.eventSF
818 config.addOutputVar(
'EventInfo', alg.scaleFactorOutputDecoration,
819 alg.scaleFactorOutputDecoration.split(
"_%SYS%")[0])
823 """the ConfigBlock to add selection decoration to a container"""
826 super (SelectionDecorationBlock, self).__init__ ()
828 self.addOption(
'containers', [], type=list,
833 """Return the instance name for this block"""
837 for container
in self.containers:
838 originContainerName = config.getOutputContainerOrigin(container)
839 selectionNames = config.getSelectionNames(originContainerName)
840 for selectionName
in selectionNames:
842 if selectionName ==
'':
844 alg = config.createAlgorithm(
845 'CP::AsgSelectionAlg',
846 f
'SelectionDecoration_{originContainerName}_{selectionName}')
847 selectionDecoration = f
'baselineSelection_{selectionName}_%SYS%'
848 alg.selectionDecoration = f
'{selectionDecoration},as_char'
849 alg.particles = config.readName (originContainerName)
850 alg.preselection = config.getFullSelection (originContainerName,
853 originContainerName, selectionDecoration, selectionName)
856 *, postfix=None, selectionName, customSelections=None):
857 """Create an event-level cutflow config
860 containerName -- name of the container
861 postfix -- a postfix to apply to decorations and algorithm names.
862 selectionName -- the name of the selection to do the cutflow for
863 customSelections -- a list of decorations to use in the cutflow, to override the retrieval of all decorations
867 config.setOptionValue(
'containerName', containerName)
868 config.setOptionValue(
'selectionName', selectionName)
869 config.setOptionValue(
'postfix', postfix)
870 config.setOptionValue(
'customSelections', customSelections)