ATLAS Offline Software
Loading...
Searching...
No Matches
MuonTriggerSFRootCoreTest.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3 */
4
5// Script for testing MuonTriggerScaleFactors. For example run with following command: MuonTriggerSFRootCoreTest -x AOD.11499205._000007.pool.root.1 -y 2015 -mc mc15a -t HLT_mu24 -r 278727
6
7// System include(s):
8#include <string>
9
10// ROOT include(s):
11#include <TFile.h>
12#include <TError.h>
13#include <TStopwatch.h>
14#include <TString.h>
15
16// Infrastructure include(s):
17#ifdef ROOTCORE
18# include "xAODRootAccess/Init.h"
21# include "AsgMessaging/Check.h"
22#endif // ROOTCORE
23
24// EDM include(s):
27
28// Local include(s):
32
33
34#define CHECK_CPSys(Arg) \
35 if (Arg.isFailure()){ \
36 Warning(#Arg,"Unsupported systematic (in line %i) ",__LINE__); \
37 }
38
39static const std::vector<std::string> qualities { "HighPt", "Tight", "Medium", "Loose", "LowPt" };
40static const std::vector<std::string> binnings { "coarse", "fine" };
41static const std::vector<std::string> types { "data", "mc" };
42
43// Copied from MuonTriggerScaleFactors.cxx
44CP::CorrectionCode getThreshold(Int_t& threshold, const std::string& trigger) {
45 std::size_t index = trigger.find("HLT_mu");
46 if (index != std::string::npos) {
47 std::string rawNumber = trigger.substr(index + 6);
48 if (!rawNumber.empty() && isdigit(rawNumber[0])) {
49 std::stringstream(rawNumber) >> threshold;
50 if (threshold < 10) threshold = 10000;
51 else threshold = (threshold + 1) * 1000;
53 }
54 }
56}
57
59
60public:
61 MuonTriggerSFTester(const char* appName, const std::string& trigger) :
62 m_errorsCount (0),
64 m_systematics (CP::make_systematics_vector(CP::SystematicRegistry::getInstance().recommendedSystematics())),
65 m_appName (appName),
66 m_trigger (trigger)
67 {
68 }
69
70 int initialiseTools(const std::string& customFileName, const std::string& customInputFolder, int year, const std::string& period){
71 for (size_t i = 0; i < qualities.size(); i++) {
72 std::vector<CP::MuonTriggerScaleFactors*> tools{};
73 for (size_t j = 0; j < binnings.size(); j++) {
75 ASG_CHECK_SA(m_appName, tool->setProperty("MuonQuality", qualities[i]));
76 ASG_CHECK_SA(m_appName, tool->setProperty("Binning", binnings[j]));
77 ASG_CHECK_SA(m_appName, tool->setProperty("filename", customFileName));
78 ASG_CHECK_SA(m_appName, tool->setProperty("CustomInputFolder", customInputFolder));
79 ASG_CHECK_SA(m_appName, tool->setProperty("UseExperimental", true));
80 ASG_CHECK_SA(m_appName, tool->setProperty("AllowZeroSF", true));
81 ASG_CHECK_SA(m_appName, tool->setProperty("forceYear", year));
82 ASG_CHECK_SA(m_appName, tool->setProperty("forcePeriod", period));
83
84 tool->msg().setLevel( MSG::WARNING );
85 ASG_CHECK_SA(m_appName, tool->initialize());
86 //CP::CorrectionCode result = tool->setRunNumber(atoi(runNumber));
87 //if (result != CP::CorrectionCode::Ok){
88 // Error(m_appName, "Could not set run number");
89 // return 1;
90 //}
91 tools.push_back(tool);
92 }
93 m_triggerSFTools.push_back(tools);
94 }
95 return 0;
96 }
97
98 int processEvent(xAOD::TEvent& event, int year, const std::string& period){
99 const xAOD::EventInfo* ei = nullptr;
100 RETURN_CHECK(m_appName, event.retrieve(ei, "EventInfo"));
101
102 const xAOD::MuonContainer* muons = nullptr;
103 RETURN_CHECK(m_appName, event.retrieve(muons, "Muons"));
104 if(year == -1 && period == "")
105 static const SG::AuxElement::ConstAccessor<unsigned int> acc_rnd("RandomRunNumber");
106 for (size_t i = 0; i < qualities.size(); i++) {
107 for (size_t j = 0; j < binnings.size(); j++) {
108 for (size_t k = 0; k < m_systematics.size(); k++) {
109 if(m_trigger == "HLT_mu26_ivarmedium" || m_trigger == "HLT_mu50" || m_trigger == "HLT_mu26_ivarmedium_OR_HLT_mu50")
110 checkSingleMuonTrigger(ei, muons, i, j, k);
111 if(muons->size() != 2)
112 continue;
113 if(binnings[j] == "coarse")
114 continue; // not supported right now
115 if(m_trigger == "HLT_2mu14" || m_trigger == "HLT_2mu10"){
116 checkSymDiMuonTrigger(ei, muons, i, j, k);
117 }
118 else{
119 for(auto muon : *muons)
120 checkASymDiMuonTrigger(ei, *muon, i, j, k);
121 }
122 }
123 }
124 }
125 return 0;
126 }
127
128 int checkASymDiMuonTrigger(const xAOD::EventInfo* ei, const xAOD::Muon& muon, unsigned int iquality, unsigned int ibin, unsigned int isystematic){
129 CHECK_CPSys(m_triggerSFTools[iquality][ibin]->applySystematicVariation(m_systematics[isystematic]));
130
131 Int_t threshold = 0;
133 if (result != CP::CorrectionCode::Ok) {
134 Error("MuonTriggerSFRootCoreTest", "Could not extract threshold for trigger %s", m_trigger.c_str());
135 return 1;
136 }
137 if (muon.pt() < threshold or std::abs(muon.eta()) > 2.5)
138 return 1;
139
140 bool displayWarning = false;
141
142
143
144 double efficiencyMC = 0.;
145 double efficiencyData = 0.;
146
147 result = m_triggerSFTools[iquality][ibin]->getTriggerEfficiency(muon,
148 efficiencyMC,
149 m_trigger,
150 false);
151 if (result != CP::CorrectionCode::Ok) {
152 Error(m_appName, "Could not retrieve MC efficeincy. Parameters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s", static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str());
154 }
155
156 result = m_triggerSFTools[iquality][ibin]->getTriggerEfficiency(muon,
157 efficiencyData,
158 m_trigger,
159 true);
160 if (result != CP::CorrectionCode::Ok) {
161 Error(m_appName, "Could not retrieve data efficeincy. Parameters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s", static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str());
163 }
164 auto triggerSF = efficiencyMC/efficiencyData;
165 if (triggerSF < 0.2 || triggerSF > 1.2) {
166 if (displayWarning) {
167 Warning(m_appName, "Retrieved trigger scale factor %.3f is outside of expected range from 0.2 to 1.2. Parameters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s", triggerSF, static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str());
169 }
170 }
171 return 0;
172 }
173
174 int checkSymDiMuonTrigger(const xAOD::EventInfo* ei, const xAOD::MuonContainer* muons, unsigned int iquality, unsigned int ibin, unsigned int isystematic){
175 CHECK_CPSys(m_triggerSFTools[iquality][ibin]->applySystematicVariation(m_systematics[isystematic]));
176 double triggerSF = 0.;
177 CP::CorrectionCode result;
178 result = m_triggerSFTools[iquality][ibin]->getTriggerScaleFactor(*muons, triggerSF, m_trigger);
179 if (result != CP::CorrectionCode::Ok) {
180 Error(m_appName, "Could not retrieve trigger scale factors. Parameters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s", static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str());
182 }
183 if (triggerSF < 0.2 || triggerSF > 1.2) {
184 // Allow scale factor to be outside of this range in case all the muons are below the threshold
185 Int_t threshold = 0;
187 if (result != CP::CorrectionCode::Ok) {
188 Error("MuonTriggerSFRootCoreTest", "Could not extract threshold for trigger %s", m_trigger.c_str());
189 return 1;
190 }
191 bool displayWarning = false;
193 for (xAOD::MuonContainer::const_iterator mu_itr = muons->begin(); mu_itr != mu_end; ++mu_itr) {
194 if ((**mu_itr).pt() >= threshold and std::abs((**mu_itr).eta()) < 2.5) displayWarning = true;
195 }
196
197 if (displayWarning) {
198 Warning(m_appName, "Retrieved trigger scale factor %.3f is outside of expected range from 0.2 to 1.2. Parameters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s", triggerSF, static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str());
200 }
201 }
202
203 return 0;
204 }
205
206
207 int checkSingleMuonTrigger(const xAOD::EventInfo* ei, const xAOD::MuonContainer* muons, unsigned int iquality, unsigned int ibin, unsigned int isystematic){
208
209 CHECK_CPSys(m_triggerSFTools[iquality][ibin]->applySystematicVariation(m_systematics[isystematic]));
210 CP::CorrectionCode result;
212 for (xAOD::MuonContainer::const_iterator mu_itr = muons->begin(); mu_itr != mu_end; ++mu_itr) {
213 for (size_t l = 0; l < types.size(); l++) {
214 if (types[l] != "data" || m_systematics[isystematic].name().find("TrigSystUncertainty") == std::string::npos) {
215 Double_t eff;
216 auto binNumber = m_triggerSFTools[iquality][ibin]->getBinNumber(**mu_itr, m_trigger);
217 result = m_triggerSFTools[iquality][ibin]->getTriggerEfficiency(**mu_itr, eff, m_trigger, types[l] == "data");
218 if (result != CP::CorrectionCode::Ok) {
219 Error(m_appName, "Could not retrieve trigger efficiency. Paramaters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s,\n Type = %s ", static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str(), types[l].c_str());
221 }
222 if (eff < 0 || eff > 1) {
223 Warning(m_appName, "Retrieved trigger efficiency %.3f is outside of expected range from 0 to 1. Paramaters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s", eff, static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str());
225 }
226 if (binNumber < 0 || binNumber > 238) {
227 Warning(m_appName, "Retrieved bin number %.i is outside of expected range from 0 to 238. Paramaters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s", binNumber, static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str());
229 }
230
231 }
232 }
233 }
234
235 double triggerSF = 0.;
236 result = m_triggerSFTools[iquality][ibin]->getTriggerScaleFactor(*muons, triggerSF, m_trigger);
237 if (result != CP::CorrectionCode::Ok) {
238 Error(m_appName, "Could not retrieve trigger scale factors. Parameters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s", static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str());
240 }
241 if (triggerSF < 0.2 || triggerSF > 1.2) {
242 // Allow scale factor to be outside of this range in case all the muons are below the threshold
243 Int_t threshold = 0;
245 if (result != CP::CorrectionCode::Ok) {
246 Error("MuonTriggerSFRootCoreTest", "Could not extract threshold for trigger %s", m_trigger.c_str());
247 return 1;
248 }
249 bool displayWarning = false;
251 for (xAOD::MuonContainer::const_iterator mu_itr = muons->begin(); mu_itr != mu_end; ++mu_itr) {
252 if ((**mu_itr).pt() >= threshold and std::abs((**mu_itr).eta()) < 2.5) displayWarning = true;
253 }
254
255 if (displayWarning) {
256 Warning(m_appName, "Retrieved trigger scale factor %.3f is outside of expected range from 0.2 to 1.2. Parameters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s", triggerSF, static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str());
258 }
259 }
260 double tmpEffData = 1.;
261 double tmpEffMC = 1.;
262 for (auto muon: *muons) {
263 double effData = 0.;
264 double effMC = 0.;
265 double scaleFactor = 0.;
266 if (m_triggerSFTools[iquality][ibin]->getTriggerEfficiency(*muon, effData, m_trigger, true) != CP::CorrectionCode::Ok) {
267 Error("MuonTriggerSFRootCoreTest", "Could not extract data trigger efficiency for %s which is %f. Parameters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s \n muon pt: %f \n eta: %f \n phi: %f", m_trigger.c_str(), scaleFactor, static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str(), muon->pt(), muon->eta(), muon->phi());
268 return 1;
269 }
270 if (m_triggerSFTools[iquality][ibin]->getTriggerEfficiency(*muon, effMC, m_trigger, false) != CP::CorrectionCode::Ok) {
271 Error("MuonTriggerSFRootCoreTest", "Could not extract MC trigger efficiency for %s", m_trigger.c_str());
272 return 1;
273 }
274 if (m_triggerSFTools[iquality][ibin]->getTriggerScaleFactor(*muon, scaleFactor, m_trigger) != CP::CorrectionCode::Ok) {
275 Error("MuonTriggerSFRootCoreTest", "Could not extract MC trigger efficiency for %s", m_trigger.c_str());
276 return 1;
277 }
278 if (scaleFactor < 0.2 || scaleFactor > 1.2 ) {
279 Int_t threshold = 0;
281 Error("MuonTriggerSFRootCoreTest", "Could not extract threshold for trigger %s", m_trigger.c_str());
282 return 1;
283 }
284 if(muon->pt() >= threshold and std::abs(muon->eta()) < 2.5)
285 Warning(m_appName, "Retrieved single muon trigger scale factor %.3f is outside of expected range from 0.2 to 1.2. Parameters:\n Event number = %i,\n Quality = %s,\n Binning = %s,\n Systematic = %s \n muon pt: %f \n eta: %f \n phi: %f", scaleFactor, static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), m_systematics[isystematic].name().c_str(), muon->pt(), muon->eta(), muon->phi());
286 }
287 tmpEffData *= 1.-effData;
288 tmpEffMC *= 1.-effMC;
289 }
290 auto sfSingleCalc = (1. - tmpEffData)/(1. - tmpEffMC);
291 if ( triggerSF > 0.2 && (sfSingleCalc - triggerSF) / triggerSF > 0.02) {
292
293 // Warning(m_appName, "Invalid single muon SF result. Parameters:\n Event number = %i,\n Quality = %s,\n Binning = %s \n Systematic = %s \n single SF: %f \n combined SF %f \n ", static_cast<int>(ei->eventNumber()), qualities[iquality].c_str(), binnings[ibin].c_str(), systematics[isystematic].name().c_str(), sfSingleCalc, triggerSFrSF);
295 }
296 return 0;
297 }
298
299
300public:
303
304private:
305 std::vector<std::vector<CP::MuonTriggerScaleFactors*>> m_triggerSFTools;
306 std::vector<CP::SystematicSet> m_systematics;
307 const char* m_appName;
308 std::string m_trigger;
309
310};
311
312
313int main(int argc, char* argv[]) {
314
315 const char* APP_NAME = argv[0];
317 // Read the config provided by the user
318 const char* xAODFileName = "";
319 std::string customInputFolder = "";
320 std::string customFileName = "";
321 const char* nrOfEntries = "";
322 std::string trigger = "";
323 int year = -1;
324 std::string period = "";
325 for (int i = 1; i < argc - 1; i++) {
326 std::string arg = std::string(argv[i]);
327 if (arg == "-x") {
328 xAODFileName = argv[i + 1];
329 }
330 else if (arg == "-d")
331 customInputFolder = argv[i + 1];
332 else if (arg == "-f")
333 customFileName = argv[i + 1];
334 else if (arg == "-e")
335 nrOfEntries = argv[i + 1];
336 else if (arg == "-t")
337 trigger = argv[i + 1];
338 else if (arg == "-y")
339 year = atoi(argv[i + 1]);
340 else if (arg == "-p")
341 period = argv[i + 1];
342 }
343
344 bool error = false;
345 if (xAODFileName[0] == '\0') {
346 Error(APP_NAME, "xAOD file name missing!");
347 error = true;
348 }
349 if (trigger == "") {
350 Error(APP_NAME, "trigger missing!");
351 error = true;
352 }
353 if (error) {
354 Error(APP_NAME, " Usage: %s -x [xAOD file name] -y [year] -p [period] -t [trigger] -d [custom input folder] -f [custom file name] -e [number of events to process]", APP_NAME);
355 return 1;
356 }
357
359
360 Info(APP_NAME, "Opening file: %s", xAODFileName);
361 std::unique_ptr<TFile> ifile(TFile::Open(xAODFileName, "READ"));
362 if (!ifile.get()) {
363 Error(APP_NAME, " Unable to load xAOD input file");
364 return 1;
365 }
366
367 xAOD::TEvent event;
368 RETURN_CHECK(APP_NAME, event.readFrom(ifile.get(), xAOD::TEvent::kClassAccess));
369 Info(APP_NAME, "Number of events in the file: %i", static_cast<int>(event.getEntries()));
370
371 // Decide how many events to run over:
372 int nrOfEntriesToRunOver = 1000;//event.getEntries();
373 if (!std::string(nrOfEntries).empty()) {
374 int e = atoll(nrOfEntries);
375 if (e < nrOfEntriesToRunOver) {
376 nrOfEntriesToRunOver = e;
377 }
378 }
379
380
381 MuonTriggerSFTester sfChecker(APP_NAME, trigger);
382 sfChecker.initialiseTools(customFileName, customInputFolder, year, period);
383 for(Long64_t entry = 0; entry < nrOfEntriesToRunOver; entry++) {
384 // Tell the object which entry to look at:
385 event.getEntry(entry);
386 sfChecker.processEvent(event, year, period);
387
388 }
389
390 Info(APP_NAME, "%i events successfully processed, %i warnings, %i errors detected.", nrOfEntriesToRunOver, sfChecker.m_warningsCount, sfChecker.m_errorsCount);
391 return 0;
392}
393
#define APP_NAME
#define ASG_CHECK_SA(SOURCE, EXP)
Helper macro for checking the status code of a call outside of an ASG tool.
Definition Check.h:76
static const std::vector< std::string > qualities
static const std::vector< std::string > types
#define CHECK_CPSys(Arg)
static const std::vector< std::string > qualities
static const std::vector< std::string > binnings
CP::CorrectionCode getThreshold(Int_t &threshold, const std::string &trigger)
static const std::vector< std::string > types
#define RETURN_CHECK(CONTEXT, EXP)
Helper macro for checking return codes in a compact form in the code.
Definition ReturnCheck.h:26
static const Attributes_t empty
Return value from object correction CP tools.
@ Error
Some error happened during the object correction.
@ Ok
The correction was done successfully.
static void enableFailure() noexcept
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
int processEvent(xAOD::TEvent &event, int year, const std::string &period)
std::vector< std::vector< CP::MuonTriggerScaleFactors * > > m_triggerSFTools
int initialiseTools(const std::string &customFileName, const std::string &customInputFolder, int year, const std::string &period)
int checkASymDiMuonTrigger(const xAOD::EventInfo *ei, const xAOD::Muon &muon, unsigned int iquality, unsigned int ibin, unsigned int isystematic)
std::vector< CP::SystematicSet > m_systematics
MuonTriggerSFTester(const char *appName, const std::string &trigger)
int checkSymDiMuonTrigger(const xAOD::EventInfo *ei, const xAOD::MuonContainer *muons, unsigned int iquality, unsigned int ibin, unsigned int isystematic)
int checkSingleMuonTrigger(const xAOD::EventInfo *ei, const xAOD::MuonContainer *muons, unsigned int iquality, unsigned int ibin, unsigned int isystematic)
SG::ConstAccessor< T, ALLOC > ConstAccessor
Definition AuxElement.h:570
This module implements the central registry for handling systematic uncertainties with CP tools.
uint64_t eventNumber() const
The current event's event number.
Tool for accessing xAOD files outside of Athena.
@ kClassAccess
Access auxiliary data using the aux containers.
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:138
int main()
Definition hello.cxx:18
Select isolated Photons, Electrons and Muons.
Definition index.py:1
StatusCode Init(const char *appname)
Function initialising ROOT/PyROOT for using the ATLAS EDM.
Definition Init.cxx:31
EventInfo_v1 EventInfo
Definition of the latest event info version.
Muon_v1 Muon
Reference the current persistent version:
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".