ATLAS Offline Software
JetEfficiencyMonitorAlgorithm.py
Go to the documentation of this file.
1 #
2 # Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 #
5  '''Function to configure LVL1 JetEfficiency algorithm in the monitoring system.'''
6 
7  # get the component factory - used for getting the algorithms
8  from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
9  from AthenaConfiguration.ComponentFactory import CompFactory
10  from TrigConfigSvc.TriggerConfigAccess import getL1MenuAccess
11  result = ComponentAccumulator()
12  l1menu = getL1MenuAccess(flags)
13 
14 
15  from AthenaConfiguration.Enums import Format
16 
18  if flags.Input.Format is Format.POOL and not flags.Input.isMC and not any(["AOD" in a for a in flags.Input.ProcessingTags]):
19  from JetRecConfig.JetRecConfig import JetRecCfg
20  from JetRecConfig.StandardSmallRJets import AntiKt4EMPFlow
21  result.merge( JetRecCfg(flags,AntiKt4EMPFlow) )
22 
23  from eflowRec.PFCfg import PFGlobalFlowElementLinkingCfg
24  if flags.DQ.Environment == "AOD":
25  result.merge(PFGlobalFlowElementLinkingCfg(flags, useMuonTopoClusters=True))
26  else:
27  result.merge(PFGlobalFlowElementLinkingCfg(flags))
28  from eflowRec.PFCfg import PFGlobalFlowElementLinkingCfg
29  result.merge(PFGlobalFlowElementLinkingCfg(flags))
30  from METReconstruction.METAssociatorCfg import METAssociatorCfg
31  result.merge(METAssociatorCfg(flags, 'AntiKt4EMPFlow'))
32  from METUtilities.METMakerConfig import getMETMakerAlg
33  metCA=ComponentAccumulator()
34  metCA.addEventAlgo(getMETMakerAlg('AntiKt4EMPFlow'))
35  result.merge(metCA)
36 
37 
38  # make the athena monitoring helper
39  from TrigT1CaloMonitoring.LVL1CaloMonitoringConfig import L1CaloMonitorCfgHelper
40  helper = L1CaloMonitorCfgHelper(flags,CompFactory.JetEfficiencyMonitorAlgorithm,'JetEfficiencyMonAlg')
41  groupName = 'JetEfficiencyMonitor' # the monitoring group name is also used for the package name
42  JetEfficiencyMonAlg = helper.alg
43  JetEfficiencyMonAlg.PackageName = groupName
44 
45 
46 
50 
51  # We can choose if we want to use pass before prescale, or not when defining our trigger efficiency
52  # generally only want to use pass before prescale when considering the efficiency of a trigger for
53  # internal evaluation of how triggers are behaving
54  # the prescaling is an important feature of real utility if a
55  passedb4Prescale = True
56  JetEfficiencyMonAlg.PassedBeforePrescale = passedb4Prescale
57 
58 
62 
63  #define the various reference triggers
64  hltRandom_reference_triggers = ['HLT_j0_perf_L1RD0_FILLED', 'HLT_j0_perf_pf_ftf_L1RD0_FILLED']
65  JetEfficiencyMonAlg.HLTRandomReferenceTriggers = hltRandom_reference_triggers
66 
67  muon_reference_triggers = ["L1_MU14FCH", "L1_MU18VFCH", "L1_2MU8F", "L1_MU8VF_2MU5VF", "L1_3MU3VF", "L1_MU5VF_3MU3VF", "L1_4MU3V", "L1_2MU5VF_3MU3V"]
68  JetEfficiencyMonAlg.MuonReferenceTriggers = muon_reference_triggers
69 
70  JetEfficiencyMonAlg.BootstrapReferenceTrigger='L1_J15'
71 
72  trigPath = 'Developer/JetEfficiency/'
73  ExpertTrigPath = 'Expert/Efficiency/'
74  distributionPath = 'Distributions/'
75  noRefPath = 'NoReferenceTrigger/'
76  muonRefPath = 'MuonReferenceTrigger/'
77  randomRefPath = 'RandomHLTReferenceTrigger/'
78  bsRefPath = 'BootstrapReferenceTrigger/'
79  GeV = 1000
80 
81  # add monitoring algorithm to group, with group name and main directory
82  gfex_SR_triggers = ['L1_gJ20p0ETA25', 'L1_gJ50p0ETA25', 'L1_gJ100p0ETA25', 'L1_gJ400p0ETA25']
83  gfex_LR_triggers = ['L1_gLJ80p0ETA25', 'L1_gLJ100p0ETA25', 'L1_gLJ140p0ETA25', 'L1_gLJ160p0ETA25']
84 
85  jfex_SR_triggers = ['L1_jJ30','L1_jJ40','L1_jJ50', 'L1_jJ60', 'L1_jJ80','L1_jJ90', 'L1_jJ125','L1_jJ140','L1_jJ160', 'L1_jJ180']
86  jfex_LR_triggers = ['L1_SC175-SCjJ10']
87 
88  all_SR_triggers = gfex_SR_triggers + jfex_SR_triggers
89  all_LR_triggers = gfex_LR_triggers + jfex_LR_triggers
90 
91  # if the trigger isnt included in the menu, then we dont actually want to fill anything into the histograms (it looks weird)
92  JetEfficiencyMonAlg.SmallRadiusJetTriggers_phase1 = [trigger for trigger in all_SR_triggers if trigger in l1menu]
93  JetEfficiencyMonAlg.LargeRadiusJetTriggers_phase1 = [trigger for trigger in all_LR_triggers if trigger in l1menu]
94  # if a trigger isnt in the menu, but its a gfex trigger so we can emulate the efficiemcy using the gFEX TOBs
95  JetEfficiencyMonAlg.SmallRadiusJetTriggers_gFEX = [trigger for trigger in gfex_SR_triggers if trigger not in l1menu]
96  JetEfficiencyMonAlg.LargeRadiusJetTriggers_gFEX = [trigger for trigger in gfex_LR_triggers if trigger not in l1menu]
97 
98  # if there are no gFEX triggers in our list that aren't present in the menu, then we don't need to even look at them, so lets just not open them
99  if len(JetEfficiencyMonAlg.SmallRadiusJetTriggers_gFEX ) == 0: JetEfficiencyMonAlg.mygFexSRJetRoIContainer = ""
100  if len(JetEfficiencyMonAlg.LargeRadiusJetTriggers_gFEX ) == 0: JetEfficiencyMonAlg.mygFexLRJetRoIContainer = ""
101 
102 
103  reference_paths = {"Muon" : muonRefPath, "RandomHLT": randomRefPath, "No": noRefPath, "Bootstrap": bsRefPath}
104  references = ["Muon", "No", "Bootstrap"] #"RandomHLT"
105 
106  # if we want to make the eta efficiencies, can add in SReta and LReta
107  sr_props = ["SRpt"] #SReta
108  lr_props = ["LRpt"] #LReta
109  trigger_group_list = {"gfex_SR_triggers" : gfex_SR_triggers,
110  "gfex_LR_triggers" : gfex_LR_triggers,
111  "jfex_SR_triggers" : jfex_SR_triggers,
112  "jfex_LR_triggers" : jfex_LR_triggers }
113  properties_per_trigger_group = {"gfex_SR_triggers" : sr_props, "jfex_SR_triggers" : sr_props,
114  "gfex_LR_triggers" : lr_props, "jfex_LR_triggers" : lr_props }
115  pathadd_per_trigger_group = {"gfex_SR_triggers" : "gFEX/", "jfex_SR_triggers" : "jFEX/",
116  "gfex_LR_triggers" : "gFEX/", "jfex_LR_triggers" : "jFEX/" }
117  trigger_groups = list(trigger_group_list.keys())
118 
119  xlabel_for_prop = { "SRpt" :'pT [MeV]', "SReta" : '#eta', "LRpt" :'pT [MeV]', "LReta" : '#eta'}
120  nbins = {"SRpt": 220, "SReta" :32, "LRpt": 220, "LReta" :32}
121  binmin = {"SRpt": -50, "SReta" :-3.3, "LRpt": -50, "LReta" :-3.3}
122  binmax = {"SRpt": 1800*GeV, "SReta" :3.3, "LRpt": 1800*GeV, "LReta" :3.3}
123 
124 
125  plotDistrubutions = False
126  if plotDistrubutions:
127  helper.defineHistogram('raw_pt',title='pT for all leading offline jets (with no trigger requirments);PT [MeV];Events', fillGroup=groupName, path=trigPath + distributionPath, xbins=nbins["SRpt"], xmin=binmin["SRpt"], xmax=binmax["SRpt"])
128 
129  helper.defineHistogram('raw_eta', title='Eta Distribution for all leading offline jets (with no trigger requirments);#eta; Count', fillGroup=groupName, path=trigPath + distributionPath, xbins=nbins["SReta"], xmin=binmin["SReta"], xmax=binmax["SReta"])
130 
131 
132  for tgroup in trigger_groups: #iterate through the trigger groups (gFEX SR & LR, jFEX SR & LR)
133  for t in trigger_group_list[tgroup]: #iterate through the triggers within subgroups
134  #add algorithm that flags if the efficiency is not reaching 100%
135  # assemble thresholdConfig dict
136  thresholdConfig = {"Plateau":plateau_dict.get(t,[0.99,0.95])}
137  thresholdConfig["Threshold"] = get_or_estimate_thresholds(t)
138  xMaxConfig = min(thresholdConfig["Threshold"][1]*2.5, binmax["SRpt"]) #set the x maximum of the fit to be 6 times the upper limit, to help the fit work better
139  # if t in threshold_dict: thresholdConfig["Threshold"] = threshold_dict[t]
140  helper.defineDQAlgorithm("JetEfficiency_"+t,
141  hanConfig={"libname":"libdqm_algorithms.so","name":"Simple_fermi_Fit_TEff", "xmax":xMaxConfig, "ImproveFit":1}, # this line is always the same
142  thresholdConfig=thresholdConfig
143  )
144  for p in properties_per_trigger_group[tgroup]:
145  for r in references: #iteratate through the refernce trigger options
146 
147  # if trigger not included in the menu, then lets modify the hist title to make that clear!
148  if t in l1menu: eff_plot_title = t+';'+xlabel_for_prop[p]+'; Efficiency '
149  elif t not in l1menu and t in (gfex_SR_triggers + gfex_LR_triggers): eff_plot_title = t+' Emulated;'+xlabel_for_prop[p]+'; Efficiency '
150  else: eff_plot_title = t+' NOT in Menu;'+xlabel_for_prop[p]+'; Efficiency '
151 
152  #Using the muon reference trigger selection, as our least biased trigger selection inside the web displkay. Others still exist in the HIST file for now
153  if r == "Muon" and p in ["SRpt", "LRpt"]:
154  helper.defineHistogram(f"bool_{r}_{t}, val_{p};{p}_{t}", type='TEfficiency', title=eff_plot_title, fillGroup=groupName, path=ExpertTrigPath + pathadd_per_trigger_group[tgroup]+ reference_paths[r], xbins=nbins[p], xmin=binmin[p], xmax=binmax[p], hanConfig={"algorithm":"JetEfficiency_"+t}, opt='kAlwaysCreate')
155  else:
156  helper.defineHistogram(f"bool_{r}_{t}, val_{p};{p}_{t}", type='TEfficiency', title=eff_plot_title, fillGroup=groupName, path=trigPath + pathadd_per_trigger_group[tgroup]+ reference_paths[r], xbins=nbins[p], xmin=binmin[p], xmax=binmax[p], opt='kAlwaysCreate')
157 
158 
159 
160  acc = helper.result()
161  result.merge(acc)
162  print("flags.DQ.Environment = " + flags.DQ.Environment )
163  return result
164 
165 def get_closest_threshold(trigger_value, extracted_values, lower_bounds, upper_bounds):
166  """
167  Finds and returns the threshold values of the closest existing trigger.
168  """
169  import numpy as np
170  closest_index = np.abs(extracted_values - trigger_value).argmin()
171  return [lower_bounds[closest_index], upper_bounds[closest_index]]
172 
173 def estimate_thresold(trigger_name):
174  """
175  Estimates the DQ monitoring threshold range for a given trigger name based on given threshold_dict,
176  treating jet types (gJ, gLJ, jJ, and jLJ) as separate for extrapolation.
177  If interpolation fails, it returns the closest existing trigger values.
178  """
179  import re
180  import numpy as np
181  # Extract the numeric portion and type from the trigger name
182  match = re.search(r'(gJ|gLJ|jJ|jLJ)(\d+)', trigger_name)
183  if not match:
184  return None
185 
186  trigger_type, trigger_value = match.groups()
187  trigger_value = int(trigger_value)
188 
189  # Gather existing numeric values and their thresholds for the same type
190  extracted_values = []
191  lower_bounds = []
192  upper_bounds = []
193 
194  for key, (low, high) in threshold_dict.items():
195  key_match = re.search(r'(gJ|gLJ|jJ|jLJ)(\d+)', key)
196  if key_match and key_match.group(1) == trigger_type:
197  extracted_values.append(int(key_match.group(2)))
198  lower_bounds.append(low)
199  upper_bounds.append(high)
200 
201  if not extracted_values:
202  return None # No matching trigger types found
203 
204  extracted_values = np.array(extracted_values)
205  lower_bounds = np.array(lower_bounds)
206  upper_bounds = np.array(upper_bounds)
207 
208  # Try interpolation/extrapolation
209  lower_pred = np.interp(trigger_value, extracted_values, lower_bounds, left=lower_bounds[0], right=lower_bounds[-1])
210  upper_pred = np.interp(trigger_value, extracted_values, upper_bounds, left=upper_bounds[0], right=upper_bounds[-1])
211 
212  return [lower_pred, upper_pred]
213 
214 def get_or_estimate_thresholds(trigger_name):
215  """
216  Returns the threshold from threshold_dict if it exists.
217  Otherwise, predicts the thresholds using estimate_thresold.
218  """
219  if trigger_name in threshold_dict:
220  return threshold_dict[trigger_name] # Return stored values if available
221  else:
222  print("WARNING, trigger " + trigger_name + " doesn't have predifined thresholds for DQ Algorithm. Estimating thresholds with a fit, or using thresholds from closest exisiting trigger.")
223  print("Please add thresholds to the threshold_dict for trigger " + trigger_name)
224  print(estimate_thresold(trigger_name))
225  return estimate_thresold(trigger_name) # Predict or use closest match
226 
227 
228 plateau_dict = {} #in case there are low stats for some of the triggers, we could modify the threshold ranges for some triggers
229 threshold_dict = {"L1_gJ20p0ETA25" : [55e3, 75e3], #hits 50% at 50 for a good run, 100% around 75
230  "L1_gJ50p0ETA25" : [110e3, 180e3], #hits 50% at 109 for a good run, 100% around 180
231  "L1_gJ100p0ETA25" : [195e3, 3000e3],#hits 50% at 185 for a good run, 100% around 300
232  "L1_gJ400p0ETA25" : [620e3, 900e3],#hits 50% at 611 for a good run, 100% around 900
233  "L1_gLJ80p0ETA25" : [125e3, 200e3],#hits 50% at 113 for a good run, 100% around 200
234  "L1_gLJ100p0ETA25" : [150e3, 240e3],#hits 50% at 137 for a good run, 100% around 240
235  "L1_gLJ140p0ETA25" : [210e3, 315e3],#hits 50% at 197 for a good run, 100% around 315
236  "L1_gLJ160p0ETA25" : [240e3, 260e3],#hits 50% at 225 for a good run, 100% around 350
237  "L1_jJ30" : [50e3, 85e3],#hits 50% at 46 for a good run, 100% around 85
238  "L1_jJ40" : [55e3, 90e3],#hits 50% at 47 for a good run, 100% around 90
239  "L1_jJ50" : [60e3, 100e3],#hits 50% at 53 for a good run, 100% around 100
240  "L1_jJ60" : [90e3, 130e3],#hits 50% at 85 for a good run, 100% around 130
241  "L1_jJ80" : [90e3, 155e3],#hits 50% at 86 for a good run, 100% around 155
242  "L1_jJ90" : [110e3, 185e3],#hits 50% at 105 for a good run, 100% around 185
243  "L1_jJ125" : [145e3, 230e3],#hits 50% at 140 for a good run, 100% around 230
244  "L1_jJ140" : [160e3, 225e3],#hits 50% at 150 for a good run, 100% around 255
245  "L1_jJ160" : [180e3, 260e3],#hits 50% at 170 for a good run, 100% around 260
246  "L1_jJ180" : [235e3, 320e3],#hits 50% at 223 for a good run, 100% around 320
247  "L1_SC175-SCjJ10": [195e3, 300e3],#hits 50% at 190 for a good run, 100% around 300
248 }
249 
250 
251 if __name__=='__main__':
252  # set debug level for whole job
253  from AthenaCommon.Logging import log
254  from AthenaCommon.Constants import INFO #DEBUG
255  log.setLevel(INFO)
256 
257  # set input file and config options
258  from AthenaConfiguration.AllConfigFlags import initConfigFlags
259  flags = initConfigFlags()
260 
261  import glob
262 
263  inputs = glob.glob('/eos/atlas/atlastier0/rucio/data18_13TeV/physics_Main/00354311/data18_13TeV.00354311.physics_Main.recon.ESD.f1129/data18_13TeV.00354311.physics_Main.recon.ESD.f1129._lb0013._SFO-8._0001.1')
264 
265 
266  flags.Input.Files = inputs
267  flags.Output.HISTFileName = 'ExampleMonitorOutput_LVL1.root'
268 
269  flags.lock()
270 
271  flags.dump() # print all the configs
272 
273  from AthenaConfiguration.MainServicesConfig import MainServicesCfg
274  from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
275  cfg = MainServicesCfg(flags)
276  cfg.merge(PoolReadCfg(flags))
277 
278  JetEfficiencyMonitorCfg = JetEfficiencyMonitoringConfig(flags)
279  cfg.merge(JetEfficiencyMonitorCfg)
280 
281 
282  # message level for algorithm
283  JetEfficiencyMonitorCfg.getEventAlgo('JetEfficiencyMonAlg').OutputLevel = 1 # 1/2 INFO/DEBUG
284  # options - print all
python.JetAnalysisCommon.ComponentAccumulator
ComponentAccumulator
Definition: JetAnalysisCommon.py:302
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
METMakerConfig.getMETMakerAlg
def getMETMakerAlg(suffix, jetSelection="Tier0", jetColl="")
Definition: METMakerConfig.py:59
JetEfficiencyMonitorAlgorithm.get_or_estimate_thresholds
def get_or_estimate_thresholds(trigger_name)
Definition: JetEfficiencyMonitorAlgorithm.py:214
JetEfficiencyMonitorAlgorithm.estimate_thresold
def estimate_thresold(trigger_name)
Definition: JetEfficiencyMonitorAlgorithm.py:173
METAssociatorCfg
Definition: METAssociatorCfg.py:1
python.TriggerConfigAccess.getL1MenuAccess
L1MenuAccess getL1MenuAccess(flags=None)
Definition: TriggerConfigAccess.py:129
python.JetRecConfig.JetRecCfg
def JetRecCfg(flags, jetdef, returnConfiguredDef=False)
Top level functions returning ComponentAccumulator out of JetDefinition.
Definition: JetRecConfig.py:36
JetEfficiencyMonitorAlgorithm.get_closest_threshold
def get_closest_threshold(trigger_value, extracted_values, lower_bounds, upper_bounds)
Definition: JetEfficiencyMonitorAlgorithm.py:165
python.MainServicesConfig.MainServicesCfg
def MainServicesCfg(flags, LoopMgr='AthenaEventLoopMgr')
Definition: MainServicesConfig.py:312
Constants
some useful constants -------------------------------------------------—
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
print
void print(char *figname, TCanvas *c1)
Definition: TRTCalib_StrawStatusPlots.cxx:26
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
python.AllConfigFlags.initConfigFlags
def initConfigFlags()
Definition: AllConfigFlags.py:19
python.PoolReadConfig.PoolReadCfg
def PoolReadCfg(flags)
Definition: PoolReadConfig.py:71
JetEfficiencyMonitorAlgorithm.JetEfficiencyMonitoringConfig
def JetEfficiencyMonitoringConfig(flags)
Definition: JetEfficiencyMonitorAlgorithm.py:4
PFCfg.PFGlobalFlowElementLinkingCfg
def PFGlobalFlowElementLinkingCfg(inputFlags, **kwargs)
Definition: PFCfg.py:472