ATLAS Offline Software
Loading...
Searching...
No Matches
JetEfficiencyMonitorAlgorithm.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
12
13#include <cstdlib>
14
15using Athena::Units::GeV;
16
17static const std::map<std::string, int> l1_trigger_flatline_vals = {
18 {"L1_gLJ80p0ETA25", 175*GeV}, {"L1_gLJ100p0ETA25", 200*GeV},
19 {"L1_gLJ140p0ETA25", 270*GeV}, {"L1_gLJ160p0ETA25", 270*GeV},
20 {"L1_SC175-SCjJ10", 270*GeV}, {"L1_gJ20p0ETA25", 40*GeV},
21 {"L1_gJ50p0ETA25", 80*GeV}, {"L1_gJ100p0ETA25", 200*GeV},
22 {"L1_gJ400p0ETA25", 800*GeV}, {"L1_jJ30", 50*GeV},
23 {"L1_jJ40", 60*GeV}, {"L1_jJ50", 70*GeV},
24 {"L1_jJ60", 80*GeV}, {"L1_jJ80", 100*GeV},
25 {"L1_jJ90", 110*GeV}, {"L1_jJ125", 135*GeV},
26 {"L1_jJ140", 160*GeV}, {"L1_jJ160", 180*GeV},
27 {"L1_jJ180", 200*GeV}
28};
29
30// Define gFEX_trigger_thresholds as a static const map
31// can add triggers and their corresponding threshold value as: {"L1_gLJ80p0ETA25", 100 * GeV}
32// if the value is easily extracted from the trigger name, then just use the trigger name
33// use trigger name from the function extractgFEXThresholdValue
34static const std::map<std::string, int> gFEX_trigger_thresholds = {};
36 std::regex pattern(R"(L1_g(?:LJ|J)(\d+)(?:p0ETA25)?)");
37 std::smatch match;
38 if (std::regex_search(key, match, pattern)) {
39 int threshold = std::stoi(match[1]) * GeV;
40 if (key.find("gLJ") != std::string::npos) { //the gLJ threshold is actually 30 GeV less than the threshold in the name
41 threshold -= 30 * GeV;
42 }
43 if (threshold < 0) {
44 ATH_MSG_WARNING("Extracted threshold for " << key << " is negative!");
45 }
46 ATH_MSG_DEBUG("Trigger " << key << ": extracted threshold " << threshold );
47 return threshold;
48 } else {
49 ATH_MSG_WARNING("Trigger " << key << " threshold not extracted!");
50 return -1; // Error indicator
51 }
52}
53
54
55
56JetEfficiencyMonitorAlgorithm::JetEfficiencyMonitorAlgorithm( const std::string& name, ISvcLocator* pSvcLocator )
57 : AthMonitorAlgorithm(name,pSvcLocator)
58{
59}
60
62 ATH_MSG_DEBUG("JetEfficiencyMonitorAlgorith::initialize");
63 ATH_MSG_DEBUG("Package Name "<< m_packageName);
64
65 // we initialise all the containers that we need
66 ATH_CHECK(m_jetKey.initialize() ); //initialize offline SR jets
67 ATH_CHECK(m_LRjetKey.initialize() ); //initialize offline LR jets
68 ATH_CHECK(m_gFexLRJetContainerKey.initialize(SG::AllowEmpty)); //initizlize gfex lr jets
69 ATH_CHECK(m_gFexSRJetContainerKey.initialize(SG::AllowEmpty)); //initizlize gfex sr jets
70
72}
73
74StatusCode JetEfficiencyMonitorAlgorithm::fillHistograms( const EventContext& ctx ) const {
75 ATH_MSG_DEBUG("JetEfficiencyMonitorAlgorithm::fillHistograms");
76 std::vector<std::reference_wrapper<Monitored::IMonitoredVariable>> variables;
77
78 // Retrieve Offline Jets from SG
80 if(!jets.isValid()){
81 ATH_MSG_WARNING("Failed to retrieve Offline Small Radius Jet Container " << m_jetKey<< ". Will be skipped!");
82 }
83 // Retrieve Offline LR Jets from SG
85 if(!LRjets.isValid()){
86 ATH_MSG_WARNING("Failed to retrieve Offline Large Radius Jet Container "<<m_LRjetKey<< ". Will be skipped!");
87 }
88
89 // reterive the gFEX Jets from SG, only if we plan on accessing them!
90 // Declare the map of gFEX contianers
91 std::map<std::string, SG::ReadHandle<xAOD::gFexJetRoIContainer>> gFEX_Container;
92
93 // Retrieve gFex SR Jets from SG
94 if (!m_gFexSRJetContainerKey.empty()) {
96 if (!gFexSRJetContainer.isValid()) {
97 ATH_MSG_WARNING("No gFex Small Radius Jet container found in storegate " << m_gFexSRJetContainerKey);
98 } else {
99 gFEX_Container.emplace("leadingGfex_SmallRadiusTOB", gFexSRJetContainer);
100 }
101 }
102
103 // Retrieve gFex LR Jets from SG
104 if (!m_gFexLRJetContainerKey.empty()) {
106 if (!gFexLRJetContainer.isValid()) {
107 ATH_MSG_WARNING("No gFex Large Radius Jet container found in storegate " << m_gFexLRJetContainerKey);
108 } else {
109 gFEX_Container.emplace("leadingGfex_LargeRadiusTOB", gFexLRJetContainer);
110 }
111 }
112
113
116 //DEFINITIONS and extracting variables from the python config file!
117 bool use_passed_before_prescale = m_passedb4Prescale;
118 const std::string& bootstrap_trigger = m_bootstrap_reference_trigger.value();
119 const std::vector<std::string>& muon_triggers = m_muon_reference_triggers.value();
120 const std::vector<std::string>& HLTrandom_triggers = m_HLTrandom_reference_triggers.value();
121 std::vector<std::string> gFex_types {"leadingGfex_SmallRadiusTOB", "leadingGfex_LargeRadiusTOB"};
122
123
124 //Define the various reference vector things!
125 std::vector<std::string> reference_trigger_options {"Bootstrap", "RandomHLT", "No", "Muon"};
126
127 bool bootstrap_ref_decision = false; //bootstrap trigger decision
128 bool random_ref_decision = false; //random reference triggers decision
129 bool muon_ref_decision = false; //muon reference triggers decision
130
131
132
133 bootstrap_ref_decision = AthMonitorAlgorithm::getTrigDecisionTool()->isPassed(bootstrap_trigger);
134 for (auto & u : muon_triggers) {
135 if (AthMonitorAlgorithm::getTrigDecisionTool()->isPassed(u)) {muon_ref_decision = true;}
136 } //close iterating through the muon triggers
137
138 //then for the HLT decision chains, we always want to use the traditional way of getting our trigger deicsion
139 for (auto & u : HLTrandom_triggers) {
140 if (AthMonitorAlgorithm::getTrigDecisionTool()->isPassed(u)) {random_ref_decision = true;}
141 } //close iterating through the HLT random chains
142
143
144 std::map<std::string, bool> reference_trigger_decision {
145 {"Bootstrap", bootstrap_ref_decision },
146 {"RandomHLT", random_ref_decision},
147 {"No", true},
148 {"Muon", muon_ref_decision}
149 };
150
151
152 //definition of variables for the offlineSRJet_maxEta_minPt_requirement and offlineLRJet_maxEta_minPt_requirement
153 //these just force us to have a minimum pt, and limited eta region for our efficiency checks
154 constexpr int minPt = 10*GeV;
155 constexpr float maxEta = 2.5;
156
157 //fill maps that allow us to keep track of variables according to the different containers
158 float offline_SR_pt = 0, offline_LR_pt = 0, gfex_SR_pt = 0, gfex_LR_pt=0;
159 std::map<std::string, float> jet_pt {
160 {"leadingOffline_SmallRadiusJet", offline_SR_pt},
161 {"leadingOffline_LargeRadiusJet", offline_LR_pt},
162 {"leadingGfex_SmallRadiusTOB", gfex_SR_pt},
163 {"leadingGfex_LargeRadiusTOB", gfex_LR_pt}
164 };
165
166 float offline_SR_eta = 0, offline_LR_eta = 0, gfex_SR_eta = 0, gfex_LR_eta=0;
167 std::map<std::string, float> jet_eta {
168 {"leadingOffline_SmallRadiusJet", offline_SR_eta},
169 {"leadingOffline_LargeRadiusJet", offline_LR_eta},
170 {"leadingGfex_SmallRadiusTOB", gfex_SR_eta},
171 {"leadingGfex_LargeRadiusTOB", gfex_LR_eta}
172 };
173
174 float offline_SR_phi = 0, offline_LR_phi = 0, gfex_SR_phi = 0, gfex_LR_phi=0;
175 std::map<std::string, float> jet_phi {
176 {"leadingOffline_SmallRadiusJet", offline_SR_phi},
177 {"leadingOffline_LargeRadiusJet", offline_LR_phi},
178 {"leadingGfex_SmallRadiusTOB", gfex_SR_phi},
179 {"leadingGfex_LargeRadiusTOB", gfex_LR_phi}
180 };
181
182
185 // Fill pt, eta and phi vals for all the containers!
186 //offline jet containers
187 if (jets.isValid()){
188 if (!jets->empty()) { //check that there are jets before accessing the container
189 xAOD::JetContainer::const_iterator leading_offline_SR_jet = jets->begin(); //the first jet in the contianer is the leading jet
190 jet_pt["leadingOffline_SmallRadiusJet"] = (*leading_offline_SR_jet)->pt();
191 jet_eta["leadingOffline_SmallRadiusJet"] = (*leading_offline_SR_jet)->eta();
192 jet_phi["leadingOffline_SmallRadiusJet"] = (*leading_offline_SR_jet)->phi();
193 }
194 } //(close IF) jets size > 0 loop
195 //LR jet containers
196 if (LRjets.isValid()){
197 if (!LRjets->empty()) { //check that there are jets before accessing the container
198 xAOD::JetContainer::const_iterator leading_offline_LR_jet = LRjets->begin(); //the first jet in the contianer is the leading jet
199 jet_pt["leadingOffline_LargeRadiusJet"] = (*leading_offline_LR_jet)->pt();
200 jet_eta["leadingOffline_LargeRadiusJet"] = (*leading_offline_LR_jet)->eta();
201 jet_phi["leadingOffline_LargeRadiusJet"] = (*leading_offline_LR_jet)->phi();
202 } //(close IF) LRjets size > 0 loop
203 }
204 // gFex SR and LR TOB containers
205 // when we emulate the gfex trigger decision, we just want to find the leading gFEX TOB
206 // its not gaurenteed that these TOBs are pt ordered, so well iterate through them
207 float max_gfex_pt = -1.0; // Track max pt
208 const xAOD::gFexJetRoI* most_energetic_gfex_jet = nullptr;
209
210 for (auto & g : gFex_types) { // Iterate through SR and LR gFex jets
211 if(auto itr = gFEX_Container.find(g); itr != gFEX_Container.end() ) { //check that we were able to access the contianer
212 for (const auto* gfex_jet : *(itr->second)) {// Iterate through gFex jets
213 float gfex_pt = gfex_jet->et();
214 if (gfex_pt > max_gfex_pt && std::abs(gfex_jet->eta()) < maxEta) { // Track highest pt jet
215 max_gfex_pt = gfex_pt;
216 most_energetic_gfex_jet = gfex_jet;
217 }
218 }
219 if(most_energetic_gfex_jet) {
220 jet_eta[g] = most_energetic_gfex_jet->eta();
221 jet_phi[g] = most_energetic_gfex_jet->phi();
222 jet_pt[g] = most_energetic_gfex_jet->et();
223 }
224 }
225 }
226
227 // #####################
228 // #####################
229 //Physical cuts applied to all events on the offline jets
230 //requring a minimum pt threshold
231 //and maximum eta threshold
232
233 //offline SR Jet requriment
234 bool offlineSRJet_maxEta_minPt_requirement = false;
235 if(std::abs(jet_eta["leadingOffline_SmallRadiusJet"])<=maxEta && (jet_pt["leadingOffline_SmallRadiusJet"] >= minPt)) {
236 offlineSRJet_maxEta_minPt_requirement = true;
237 }
238
239 // offline LR Jet requriment
240 bool offlineLRJet_maxEta_minPt_requirement = false;
241 if(std::abs(jet_eta["leadingOffline_LargeRadiusJet"])<=maxEta && (jet_pt["leadingOffline_LargeRadiusJet"] >= minPt)) {
242 offlineLRJet_maxEta_minPt_requirement = true;
243 }
244
245 // #####################
246 // #####################
247 // Fill sample histograms of the pt and eta of leading SR jet
248 if (offlineSRJet_maxEta_minPt_requirement ) {
249 auto raw_pt = Monitored::Scalar<float>("raw_pt", jet_pt["leadingOffline_SmallRadiusJet"]);
250 auto raw_eta = Monitored::Scalar<float>("raw_eta", jet_eta["leadingOffline_SmallRadiusJet"]);
251 fill(m_packageName, raw_pt, raw_eta);
252 }
253 // #####################
254 // #####################
255
256
257 // FILL EFFIENCY HISTOGRAMS INVOLVING SMALL RADIUS OFFLINE JETS
258 for (auto & r : reference_trigger_options){ //iterate through the refernce triggers
259 if (offlineSRJet_maxEta_minPt_requirement && reference_trigger_decision[r]) { //check that the physical cuts and reference trigger is passed
260 //get the pt of leading jet
261 auto pt_ref = Monitored::Scalar<float>("val_SRpt", jet_pt["leadingOffline_SmallRadiusJet"]);
262
263 for (const auto& trigger_name : m_SmallRadiusJetTriggers_phase1){
264 bool trig_of_interest_decision = false; //default definition of the trigger of interest decison to be false,
265 if (use_passed_before_prescale) {
266 //We can choose if we want to use pass before prescale, or not when defining our trigger efficiency
267 //this boolean is defiend in the jeteffmonalg.py file
268 const unsigned int bits = AthMonitorAlgorithm::getTrigDecisionTool()->isPassedBits(trigger_name);
269 trig_of_interest_decision = bits & TrigDefs::L1_isPassedBeforePrescale;
270 } else { trig_of_interest_decision = AthMonitorAlgorithm::getTrigDecisionTool()->isPassed(trigger_name); }
271
272 //get values and fill the histogram of offline jet pt and boolean of trigger passing
273 auto passed_pt_bool = Monitored::Scalar<bool>("bool_"+r+"_"+trigger_name, trig_of_interest_decision);
274 fill(m_packageName, pt_ref, passed_pt_bool);
275
276 //filling histograms that are effiency curves as a funciton of eta
277 //in order to ensure that we are isolating only the eta behavior, we have a
278 // flatline value where the pt effiencies aproximtley flatten out to 1
279 //these are hard coded, and saved for only a few of the triggers!
280 auto l1_trigger_flat_val = l1_trigger_flatline_vals.find(trigger_name);
281 if (l1_trigger_flat_val != l1_trigger_flatline_vals.end()) {
282 if(jet_pt["leadingOffline_SmallRadiusJet"]>l1_trigger_flat_val->second) { //is jet pt greater than the flatline value?
283 //get value of eta, and histogram passing boolean and fill
284 auto eta_ref = Monitored::Scalar<float>("val_SReta", jet_eta["leadingOffline_SmallRadiusJet"]);
285 auto passed_eta = Monitored::Scalar<bool>("bool_" + r + "_" + trigger_name, trig_of_interest_decision);
286 fill(m_packageName, eta_ref, passed_eta);
287 //if the trigger passes, we can also add the eta value to a stand alone histogram
288 } //(close IF) jet pt is greater than pt flatline vlaue loop
289 } //(close IF) loop that checks if the trigger of interest is in list of flatline trigger vals
290 } //(close FOR) loop that iterates through all of L1 single jet triggers we make effiency curves for
291
292 // if a gFEX trigger is not defined in the menu, then we populate the turn on curve using TOBs
293 // check the map to see if there is a predefined
294 for (const auto& trigger_name : m_SmallRadiusJetTriggers_gFEX) {
295 bool trig_of_interest_decision = false; // Default to false
296 int gFEX_threshold = -1; // Default invalid threshold value
297 // Check if the trigger name exists in the map first
298 auto gFEX_threshold_it = gFEX_trigger_thresholds.find(trigger_name);
299 if (gFEX_threshold_it != gFEX_trigger_thresholds.end()) {
300 gFEX_threshold = gFEX_threshold_it->second;
301 ATH_MSG_DEBUG("gfex threshold in map! "<< gFEX_threshold);
302 } else {
303 // If not found in the map, extract the threshold dynamically
304 gFEX_threshold = extractgFEXThresholdValue(trigger_name);
305 }
306 ATH_MSG_DEBUG("gfex threshold used: "<< gFEX_threshold);
307 // Proceed only if a valid threshold was obtained
308 if (gFEX_threshold != -1) {
309 if (jet_pt["leadingGfex_SmallRadiusTOB"] >= gFEX_threshold) {
310 trig_of_interest_decision = true;
311 }
312 }
313 // Get values and fill the histogram of offline jet pt and boolean of trigger passing
314 auto passed_pt_bool_gFEX = Monitored::Scalar<bool>("bool_" + r + "_" + trigger_name, trig_of_interest_decision);
315 fill(m_packageName, pt_ref, passed_pt_bool_gFEX);
316 }
317
318 } //(close IF) loop that checks if the reference trigger and physical property pass is passed
319 } //(close FOR) the iteration that fills effiency histogram for 4 different kinds of refernce triggers
320
323 //FILL EFFIENCY HISTOGRAMS INVOLVING LARGE RADIUS OFFLINE JETS
324
325 for (auto & r : reference_trigger_options){ //iterate through the reference triggers
326 if ( offlineLRJet_maxEta_minPt_requirement && reference_trigger_decision[r]) { //check that the physical cuts and reference trigger is passed
327 auto pt_ref = Monitored::Scalar<float>("val_LRpt", jet_pt["leadingOffline_LargeRadiusJet"]);
328
329 for (const auto& trigger_name : m_LargeRadiusJetTriggers_phase1){
330 bool trig_of_interest_decision = false;
331 if (use_passed_before_prescale) {
332 const unsigned int bits = AthMonitorAlgorithm::getTrigDecisionTool()->isPassedBits(trigger_name);
333 trig_of_interest_decision = bits & TrigDefs::L1_isPassedBeforePrescale;
334 } else { trig_of_interest_decision = AthMonitorAlgorithm::getTrigDecisionTool()->isPassed(trigger_name); }
335
336
337 auto passed_pt_bool = Monitored::Scalar<bool>("bool_"+r+"_"+trigger_name, trig_of_interest_decision);
338 fill(m_packageName, pt_ref, passed_pt_bool);
339
340
341 //filling histograms that are effiency curves as a funciton of eta
342 auto l1_trigger_flat_val = l1_trigger_flatline_vals.find(trigger_name);
343 if (l1_trigger_flat_val != l1_trigger_flatline_vals.end()) {
344 if(jet_pt["leadingOffline_LargelRadiusJet"]>l1_trigger_flat_val->second) { //is jet pt greater than the flatline value?
345 //get value of eta, and histogram passing boolean and fill
346 auto eta_ref = Monitored::Scalar<float>("val_LReta", jet_eta["leadingOffline_LargeRadiusJet"]);
347 auto passed_eta = Monitored::Scalar<bool>("bool_" + r + "_" + trigger_name, trig_of_interest_decision);
348 fill(m_packageName, eta_ref, passed_eta);
349 //if the trigger passes, we can also add the eta value to a stand alone histogram
350 } //(close IF) jet pt is greater than pt flatline vlaue loop
351 } //(close IF) loop that checks if the trigger of interest is in list of flatline trigger vals
352 for (const auto& trigger_name : m_LargeRadiusJetTriggers_gFEX) {
353 bool trig_of_interest_decision = false; // Default to false
354 int gFEX_threshold = -1; // Default invalid threshold value
355 // Check if the trigger name exists in the map first
356 auto gFEX_threshold_it = gFEX_trigger_thresholds.find(trigger_name);
357 if (gFEX_threshold_it != gFEX_trigger_thresholds.end()) {
358 gFEX_threshold = gFEX_threshold_it->second;
359 } else {
360 // If not found in the map, extract the threshold dynamically
361 gFEX_threshold = extractgFEXThresholdValue(trigger_name);
362 }
363 // Proceed only if a valid threshold was obtained
364 if (gFEX_threshold != -1) {
365 if (jet_pt["leadingGfex_LargeRadiusTOB"] >= gFEX_threshold) {
366 trig_of_interest_decision = true;
367 }
368 }
369 // Get values and fill the histogram of offline jet pt and boolean of trigger passing
370 auto passed_pt_bool_gFEX = Monitored::Scalar<bool>("bool_" + r + "_" + trigger_name, trig_of_interest_decision);
371 fill(m_packageName, pt_ref, passed_pt_bool_gFEX);
372 }
373 } //(close FOR) loop that iterates through all of the triggers we make effiency curves for
374 } //(close FOR) the iteration that fills effiency histogram for 4 different kinds of refernce triggers
375 } //(close IF) loop that checks if the physical properties were passed for the jet
376
377 variables.clear();
378 return StatusCode::SUCCESS;
379}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
static const std::map< std::string, int > l1_trigger_flatline_vals
static const std::map< std::string, int > gFEX_trigger_thresholds
Header file to be included by clients of the Monitored infrastructure.
Property holding a SG store/key/clid from which a ReadHandle is made.
virtual StatusCode initialize() override
initialize
const ToolHandle< Trig::TrigDecisionTool > & getTrigDecisionTool() const
Get the trigger decision tool member.
AthMonitorAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
JetEfficiencyMonitorAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
int extractgFEXThresholdValue(const std::string &key) const
Gaudi::Property< std::vector< std::string > > m_LargeRadiusJetTriggers_gFEX
SG::ReadHandleKey< xAOD::gFexJetRoIContainer > m_gFexLRJetContainerKey
Gaudi::Property< std::vector< std::string > > m_SmallRadiusJetTriggers_gFEX
SG::ReadHandleKey< xAOD::JetContainer > m_jetKey
Gaudi::Property< std::vector< std::string > > m_SmallRadiusJetTriggers_phase1
Gaudi::Property< std::vector< std::string > > m_LargeRadiusJetTriggers_phase1
virtual StatusCode fillHistograms(const EventContext &ctx) const override
adds event to the monitoring histograms
Gaudi::Property< std::vector< std::string > > m_HLTrandom_reference_triggers
Gaudi::Property< std::vector< std::string > > m_muon_reference_triggers
SG::ReadHandleKey< xAOD::JetContainer > m_LRjetKey
virtual StatusCode initialize() override
initialize
SG::ReadHandleKey< xAOD::gFexJetRoIContainer > m_gFexSRJetContainerKey
Declare a monitored scalar variable.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
float phi() const
High value of phi corresponding to phi index (using gFex convention, phi in [0, 2pi]).
float eta() const
retrieves the Eta index from the 32-bit word
float et() const
retrieves the Et index from the 32-bit word
int r
Definition globals.cxx:22
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357
gFexJetRoI_v1 gFexJetRoI
Define the latest version of the gFexJetRoI class.
Definition gFexJetRoI.h:16
void fill(H5::Group &out_file, size_t iterations)