Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
TriggerAnalysisConfig.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2 
3 from AnalysisAlgorithmsConfig.ConfigBlock import ConfigBlock
4 from AnalysisAlgorithmsConfig.ConfigSequence import groupBlocks
5 from AnalysisAlgorithmsConfig.ConfigAccumulator import DataType
6 from AthenaConfiguration.Enums import LHCPeriod
7 
8 
9 class TriggerAnalysisBlock (ConfigBlock):
10  """the ConfigBlock for trigger analysis"""
11 
12  # configName is not used
13  def __init__ (self, configName='') :
14  super (TriggerAnalysisBlock, self).__init__ ()
15  self.addOption ('triggerChainsPerYear', {}, type=None,
16  info="a dictionary with key (string) the year and value (list of "
17  "strings) the trigger chains. You can also use || within a string "
18  "to enforce an OR of triggers without looking up the individual "
19  "triggers. Used for both trigger selection and SFs. "
20  "The default is {} (empty dictionary).")
21  self.addOption ('multiTriggerChainsPerYear', {}, type=None,
22  info="a dictionary with key (string) a trigger set name and value a "
23  "triggerChainsPerYear dictionary, following the previous convention. "
24  "Relevant for analyses using different triggers in different categories, "
25  "where the trigger global scale factors shouldn't be combined. "
26  "The default is {} (empty dictionary).")
27  self.addOption ('triggerChainsForSelection', [], type=None,
28  info="a list of trigger chains (list of strings) to be used for "
29  "trigger selection. Only set it if you need a different setup "
30  "than for trigger SFs. The default is [] (empty list).")
31  self.addOption ('triggerChainsForDecoration', [], type=None,
32  info="a list of trigger chains (list of strings) to be used for "
33  "trigger decoration, if it needs to be different from the selection one. "
34  "The default is [] (empty list).")
35  self.addOption ('prescaleDecoration', 'prescale', type=str,
36  info="name (prefix) of decoration for trigger prescales.")
37  self.addOption ('prescaleLumiCalcFiles', [], type=None,
38  info="a list of lumical files (list of strings) to calculate "
39  "trigger prescales. The default is [] (empty list). Mutually "
40  "exclusive with prescaleLumiCalcFilesPerYear")
41  self.addOption ('prescaleLumiCalcFilesPerYear', {}, type=None,
42  info="a dicrionary with key (string) the year and value (list of "
43  "strings) the list of lumicalc files to calculate trigger prescales "
44  "for an individual data year. The default is {} (empty dictionary). "
45  "Mutually exclusive with prescaleLumiCalcFiles")
46  self.addOption ('prescaleTriggersFormula', '', type=str,
47  info="a formula used in (un)prescaling, producing overall prescale "
48  "factor instead of prescale per trigger.")
49  self.addOption ('prescaleMC', False, type=bool,
50  info="ouput trigger prescales when running on MC. The default is False.")
51  self.addOption ('unprescaleData', False, type=bool,
52  info="ouput trigger prescales when running on Data. The default is False.")
53  self.addOption ('prescaleIncludeAllYears', False, type=bool,
54  info="if True, trigger prescales will include all configured years "
55  "from prescaleLumiCalcFilesPerYear in all jobs. The default is False.")
56  self.addOption ('noFilter', False, type=bool,
57  info="do not apply an event filter. The default is False, i.e. "
58  "remove events not passing trigger selection and matching.")
59  # TODO: add info string
60  self.addOption ('noL1', False, type=bool,
61  info="")
62 
63  @staticmethod
65  # Might have already been added
66  toolName = "TrigDecisionTool"
67  if toolName in config._algorithms:
68  return config._algorithms[toolName]
69 
70  # Create public trigger tools
71  xAODConfTool = config.createPublicTool("TrigConf::xAODConfigTool", "xAODConfigTool")
72  decisionTool = config.createPublicTool("Trig::TrigDecisionTool", toolName)
73  decisionTool.ConfigTool = f"{xAODConfTool.getType()}/{xAODConfTool.getName()}"
74  decisionTool.HLTSummary = config.hltSummary()
75  if config.geometry() is LHCPeriod.Run3:
76  # Read Run 3 navigation
77  # (options are "TrigComposite" for R3 or "TriggElement" for R2,
78  # R2 navigation is not kept in most DAODs)
79  decisionTool.NavigationFormat = "TrigComposite"
80 
81  return decisionTool
82 
83  @staticmethod
84  def makeTriggerMatchingTool(config, decisionTool):
85  # Might have already been added
86  toolName = "TrigMatchingTool"
87  if toolName in config._algorithms:
88  return config._algorithms[toolName]
89 
90  # Create public trigger tools
91  if config.geometry() is LHCPeriod.Run3:
92  drScoringTool = config.createPublicTool("Trig::DRScoringTool", "DRScoringTool")
93  matchingTool = config.createPublicTool("Trig::R3MatchingTool", toolName)
94  matchingTool.ScoringTool = f"{drScoringTool.getType()}/{drScoringTool.getName()}"
95  matchingTool.TrigDecisionTool = f"{decisionTool.getType()}/{decisionTool.getName()}"
96  else:
97  matchingTool = config.createPublicTool("Trig::MatchFromCompositeTool", toolName)
98  if config.isPhyslite():
99  matchingTool.InputPrefix = "AnalysisTrigMatch_"
100  return matchingTool
101 
102  @staticmethod
103  def _get_lumicalc_triggers(lumicalc_files: list[str]) -> list[str]:
104  return [lumicalc.split(":")[-1] for lumicalc in lumicalc_files if ":" in lumicalc]
105 
106  def makeTriggerSelectionAlg(self, config, decisionTool):
107 
108  # Set up the trigger selection:
109  alg = config.createAlgorithm( 'CP::TrigEventSelectionAlg', 'TrigEventSelectionAlg' )
110  alg.tool = '%s/%s' % \
111  ( decisionTool.getType(), decisionTool.getName() )
112  alg.triggers = self.triggerChainsForSelection
113  alg.selectionDecoration = 'trigPassed'
114  alg.noFilter = self.noFilter
115  alg.noL1 = self.noL1
116 
117  for t in self.triggerChainsForSelection :
118  t = t.replace(".", "p").replace("-", "_")
119  config.addOutputVar ('EventInfo', 'trigPassed_' + t, 'trigPassed_' + t, noSys=True)
120 
121  # for decoration, make sure we only get the triggers not already in the selection list
122  triggerChainsForDeco = list(set(self.triggerChainsForDecoration) - set(self.triggerChainsForSelection))
123  if triggerChainsForDeco :
124  alg = config.createAlgorithm( 'CP::TrigEventSelectionAlg', 'TrigEventSelectionAlgDeco' )
125  alg.tool = '%s/%s' % \
126  ( decisionTool.getType(), decisionTool.getName() )
127  alg.triggers = triggerChainsForDeco
128  alg.selectionDecoration = 'trigPassed'
129  alg.noFilter = True
130  alg.noL1 = self.noL1
131 
132  for t in triggerChainsForDeco :
133  t = t.replace(".", "p").replace("-", "_")
134  config.addOutputVar ('EventInfo', 'trigPassed_' + t, 'trigPassed_' + t, noSys=True)
135 
136  # Calculate trigger prescales
137  if (self.prescaleLumiCalcFiles or self.prescaleLumiCalcFilesPerYear) and (
138  self.unprescaleData if config.dataType() is DataType.Data else self.prescaleMC
139  ):
140 
141  lumicalc_files = []
142  if self.prescaleLumiCalcFiles:
143  lumicalc_files = self.prescaleLumiCalcFiles
144  elif self.prescaleLumiCalcFilesPerYear:
145  from TriggerAnalysisAlgorithms.TriggerAnalysisSFConfig import get_input_years, get_year_data
146 
147  years = get_input_years(config)
148  for year in years:
149  lumicalc_files.extend(get_year_data(self.prescaleLumiCalcFilesPerYear, year))
150 
151  alg = config.createAlgorithm( 'CP::TrigPrescalesAlg', 'TrigPrescalesAlg' )
152  config.addPrivateTool( 'pileupReweightingTool', 'CP::PileupReweightingTool' )
153  alg.pileupReweightingTool.LumiCalcFiles = lumicalc_files
154  alg.selectionDecoration = 'trigPassed'
155  alg.prescaleMC = config.dataType() is not DataType.Data
156  alg.prescaleDecoration = self.prescaleDecoration
157  if self.prescaleTriggersFormula != '':
158  alg.prescaleTriggersFormula = self.prescaleTriggersFormula
159  config.addOutputVar("EventInfo", alg.prescaleDecoration, alg.prescaleDecoration, noSys=True)
160  else:
161  alg.triggers = self._get_lumicalc_triggers(lumicalc_files)
162  alg.triggersAll = self.triggerChainsForSelection
163 
164  # Schedule trigger prescale output branches
165  triggers_output = set(alg.triggers)
166  if self.prescaleIncludeAllYears and self.prescaleLumiCalcFilesPerYear:
167  all_lumicalc_files = [
168  lumicalc
169  for lumicalc_year in self.prescaleLumiCalcFilesPerYear.values()
170  for lumicalc in lumicalc_year
171  ]
172  triggers_output.update(self._get_lumicalc_triggers(all_lumicalc_files))
173  for trigger in triggers_output:
174  trigger = trigger.replace("-", "_")
175  config.addOutputVar(
176  "EventInfo",
177  alg.prescaleDecoration + "_" + trigger,
178  alg.prescaleDecoration + "_" + trigger,
179  noSys=True,
180  )
181 
182  return
183 
184 
185  def makeAlgs (self, config) :
186 
187  if (self.multiTriggerChainsPerYear and self.triggerChainsPerYear and
188  self.triggerChainsPerYear is not self.multiTriggerChainsPerYear.get('')):
189  raise Exception('multiTriggerChainsPerYear and triggerChainsPerYear cannot be configured at the same time!')
190 
191  if self.prescaleLumiCalcFiles and self.prescaleLumiCalcFilesPerYear:
192  raise Exception('prescaleLumiCalcFiles and prescaleLumiCalcFilesPerYear cannot be configured at the same time!')
193 
194  if self.prescaleIncludeAllYears and not self.prescaleLumiCalcFilesPerYear:
195  raise Exception('prescaleIncludeAllYears requires prescaleLumiCalcFilesPerYear to be configured!')
196 
197  if (self.prescaleLumiCalcFiles or self.prescaleLumiCalcFilesPerYear) and not (
198  self.unprescaleData or self.prescaleMC
199  ):
200  raise Exception('Lumicalc files are provided but no trigger prescale output is configured! Specify output with "unprescaleData" and/or "prescaleMC".')
201 
202  if self.triggerChainsPerYear and not self.multiTriggerChainsPerYear:
203  self.multiTriggerChainsPerYear = {'': self.triggerChainsPerYear}
204 
205  # if we are only given the trigger dictionary, we fill the selection list automatically
206  if self.triggerChainsPerYear and not self.triggerChainsForSelection:
207  triggers = set()
208  for trigger_chains in self.multiTriggerChainsPerYear.values():
209  for chain_list in self.triggerChainsPerYear.values():
210  for chain in chain_list:
211  if '||' in chain:
212  chains = chain.split('||')
213  triggers.update(map(str.strip, chains))
214  else:
215  triggers.add(chain.strip())
217 
218  # Create the decision algorithm, keeping track of the decision tool for later
219  decisionTool = self.makeTriggerDecisionTool(config)
220 
222  self.makeTriggerSelectionAlg(config, decisionTool)
223 
224  return
225 
226 
227 
228 @groupBlocks
229 def Trigger(seq):
230  seq.append(TriggerAnalysisBlock())
231  from TriggerAnalysisAlgorithms.TriggerAnalysisSFConfig import TriggerAnalysisSFBlock
232  seq.append(TriggerAnalysisSFBlock())
replace
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition: hcg.cxx:307
python.TriggerAnalysisConfig.TriggerAnalysisBlock.makeTriggerDecisionTool
def makeTriggerDecisionTool(config)
Definition: TriggerAnalysisConfig.py:64
python.TriggerAnalysisConfig.TriggerAnalysisBlock.makeAlgs
def makeAlgs(self, config)
Definition: TriggerAnalysisConfig.py:185
python.Bindings.values
values
Definition: Control/AthenaPython/python/Bindings.py:805
python.TriggerAnalysisSFConfig.get_year_data
list get_year_data(dict dictionary, int|str year)
Definition: TriggerAnalysisSFConfig.py:28
python.TriggerAnalysisConfig.TriggerAnalysisBlock.multiTriggerChainsPerYear
multiTriggerChainsPerYear
Definition: TriggerAnalysisConfig.py:203
python.TriggerAnalysisSFConfig.get_input_years
list[int] get_input_years(ConfigAccumulator config)
Definition: TriggerAnalysisSFConfig.py:35
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
python.TriggerAnalysisConfig.Trigger
def Trigger(seq)
Definition: TriggerAnalysisConfig.py:229
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
python.TriggerAnalysisConfig.TriggerAnalysisBlock.makeTriggerSelectionAlg
def makeTriggerSelectionAlg(self, config, decisionTool)
Definition: TriggerAnalysisConfig.py:106
python.TriggerAnalysisConfig.TriggerAnalysisBlock.__init__
def __init__(self, configName='')
Definition: TriggerAnalysisConfig.py:13
python.TriggerAnalysisConfig.TriggerAnalysisBlock
Definition: TriggerAnalysisConfig.py:9
python.TriggerAnalysisConfig.TriggerAnalysisBlock.triggerChainsForSelection
triggerChainsForSelection
Definition: TriggerAnalysisConfig.py:216
python.TriggerAnalysisConfig.TriggerAnalysisBlock._get_lumicalc_triggers
list[str] _get_lumicalc_triggers(list[str] lumicalc_files)
Definition: TriggerAnalysisConfig.py:103
get
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition: hcg.cxx:127
python.TriggerAnalysisConfig.TriggerAnalysisBlock.makeTriggerMatchingTool
def makeTriggerMatchingTool(config, decisionTool)
Definition: TriggerAnalysisConfig.py:84