ATLAS Offline Software
Loading...
Searching...
No Matches
MuonSelectorToolsTester.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
7
8// System include(s):
9#include <cstdlib>
10#include <iomanip>
11#include <map>
12#include <memory>
13#include <string>
14// ROOT include(s):
15#include <TError.h>
16#include <TFile.h>
17#include <TStopwatch.h>
18#include <TString.h>
19
20// Infrastructure include(s):
21#ifdef XAOD_STANDALONE
22#include "xAODRootAccess/Init.h"
24#else
27#endif
28
29// EDM include(s):
35
36// Local include(s):
38
39// Needed for Smart Slimming
42
43// Truth classification
45
47int main(int argc, char* argv[]) {
48 // The application's name:
49 const char* APP_NAME = argv[0];
50
51 // Check if we received a file name:
52 if (argc < 2) {
53 Error(APP_NAME, "No file name received!");
54 Error(APP_NAME, " Usage: %s [xAOD file name] [Nevts to process]", APP_NAME);
55 return 1;
56 }
57
58 // Create a TEvent object:
59#ifdef XAOD_STANDALONE
60 if ( xAOD::Init( APP_NAME ).isFailure() ) {
61 Error( APP_NAME, "Failed to do xAOD::Init!" );
62 return 1;
63 }
65#else
67#endif
68
69 // Open the input file:
70 const TString fileName = argv[1];
71 Info(APP_NAME, "Opening file: %s", fileName.Data());
72 std::unique_ptr<TFile> ifile(TFile::Open(fileName, "READ"));
73 if ( !ifile.get() ) {
74 Error( APP_NAME, "Failed to open input file!" );
75 return 1;
76 }
77
78 //Read from input file with TEvent
79 if ( event.readFrom( ifile.get() ).isFailure() ) {
80 Error( APP_NAME, "Failed to read from input file!" );
81 return 1;
82 }
83 Info(APP_NAME, "Number of events in the file: %i", static_cast<int>(event.getEntries()));
84
85 // Decide how many events to run over:
86 Long64_t entries = event.getEntries();
87 if (argc > 2) {
88 const Long64_t e = atoll(argv[2]);
89 if (e < entries) { entries = e; }
90 }
91
92
93 const int Nwp = 7; // number of working points (tool instances)
94 std::vector<std::string> WPnames = {"Tight", "Medium", "Loose", "VeryLoose", "HighPt", "LowPt", "LowPtMVA"};
95
96
97
98 // done setting up selector tools
99
100 // Create "padding" strings to facilitate easy table view of results
101 std::vector<std::string> padding;
102 padding.clear();
103
104 unsigned int maxNameLength = 0;
105 for (int wp = 0; wp < Nwp; wp++)
106 if (WPnames[wp].size() > maxNameLength) maxNameLength = WPnames[wp].size();
107
108 for (int wp = 0; wp < Nwp; wp++) {
109 std::string pad = "";
110 for (unsigned int i = 0; i < maxNameLength - WPnames[wp].size(); i++) pad += " ";
111
112 padding.push_back(pad);
113 }
114
115 // string with names of working points for selection results display
116 std::string namesString = " ";
117 for (int wp = 0; wp < Nwp; wp++) namesString += WPnames[wp] + " ";
118
119 // Muon counters
120 int allMuons = 0;
121 int nPositive = 0;
122 int nNegative = 0;
123
124 // Summary information - how many muons passed each working point (with and without vetoing bad muons)
125 int selectedMuons[Nwp];
126 for (int wp = 0; wp < Nwp; wp++) selectedMuons[wp] = 0;
127
128 int selectedMuonsNotBad[Nwp];
129 for (int wp = 0; wp < Nwp; wp++) selectedMuonsNotBad[wp] = 0;
130
131 // Obtain summary information also split by muon type
132 const int Ntype = 5;
133
134
135 // Muon counters for each type
136 int allMuonsType[Ntype];
137 for (int type = 0; type < Ntype; type++) allMuonsType[type] = 0;
138
139 // Muon counters for muons of each type passing each working point
140 int selectedMuonsType[Ntype][Nwp];
141 for (int type = 0; type < Ntype; type++)
142 for (int wp = 0; wp < Nwp; wp++) selectedMuonsType[type][wp] = 0;
143
144 int selectedMuonsTypeNotBad[Ntype][Nwp];
145 for (int type = 0; type < Ntype; type++)
146 for (int wp = 0; wp < Nwp; wp++) selectedMuonsTypeNotBad[type][wp] = 0;
147
148
149 // Muon counters for each author
150 constexpr std::size_t nAuthor = static_cast<int>(xAOD::Muon::Author::NumberOfMuonAuthors);
151 std::array<int, nAuthor> allMuonsAuthor{};
152
153 // Muon counters for muons of each author passing each working point
154 std::array<std::array<int, Nwp>, nAuthor> selectedMuonsAuthor{}, selectedMuonsAuthorNotBad{};
155
156
157 // Obtain summary information also split by muon |eta|
158 const int Neta = 4;
159 double etaCuts[Neta - 1] = {1.0, 2.0, 2.5};
160
161 std::string etaRegions = "|eta| < 1.0 1.0 < |eta| < 2.0 2.0 < |eta| < 2.5 |eta| > 2.5";
162
163 // Muon counters for each eta region
164 int allMuonsEta[Neta];
165 for (int eta = 0; eta < Neta; eta++) allMuonsEta[eta] = 0;
166
167 // Muon counters for muons in each eta region passing each working point
168 int selectedMuonsEta[Neta][Nwp];
169 for (int eta = 0; eta < Neta; eta++)
170 for (int wp = 0; wp < Nwp; wp++) selectedMuonsEta[eta][wp] = 0;
171
172 int selectedMuonsEtaNotBad[Neta][Nwp];
173 for (int eta = 0; eta < Neta; eta++)
174 for (int wp = 0; wp < Nwp; wp++) selectedMuonsEtaNotBad[eta][wp] = 0;
175
176 // Obtain summary information also split by muon truth type
177 const int NtruthType = 5;
178
179 std::string truthTypeNames[NtruthType] = {"Prompt", "Non-isolated", "Hadron", "Background", "Other"};
180
181 // Muon counters for each truth type
182 int allMuonsTruthType[NtruthType];
183 for (int truthType = 0; truthType < NtruthType; truthType++) allMuonsTruthType[truthType] = 0;
184
185 // Muon counters for muons of each type passing each working point
186 int selectedMuonsTruthType[NtruthType][Nwp];
187 for (int truthType = 0; truthType < NtruthType; truthType++)
188 for (int wp = 0; wp < Nwp; wp++) selectedMuonsTruthType[truthType][wp] = 0;
189
190 int selectedMuonsTruthTypeNotBad[NtruthType][Nwp];
191 for (int truthType = 0; truthType < NtruthType; truthType++)
192 for (int wp = 0; wp < Nwp; wp++) selectedMuonsTruthTypeNotBad[truthType][wp] = 0;
193
194 //To determine whether to print truth classification table
195 bool isMC = false;
196
197 std::vector<std::unique_ptr<CP::MuonSelectionTool> > selectorTools;
198 selectorTools.clear();
199
200 // Loop over the events:
201 for (Long64_t entry = 0; entry < entries; ++entry) {
202 // Tell the object which entry to look at:
203 event.getEntry(entry);
204
205 // Counters for selected muons within each event
206 int selectedMuonsEvent[Nwp];
207 for (int wp = 0; wp < Nwp; wp++) selectedMuonsEvent[wp] = 0;
208
209 int selectedMuonsEventNotBad[Nwp];
210 for (int wp = 0; wp < Nwp; wp++) selectedMuonsEventNotBad[wp] = 0;
211
212 // Print some event information for fun:
213 const xAOD::EventInfo* ei = 0;
214 if ( event.retrieve( ei, "EventInfo" ).isFailure() ) {
215 Error( APP_NAME, "Failed to read EventInfo!" );
216 return 1;
217 }
218
219 if(entry==0)
220 {
221 bool isRun3=false;
222 if(!ei->eventType(xAOD::EventInfo::IS_SIMULATION) && ei->runNumber()>=400000) isRun3=true; //in data we expect to be in run3 for datasets with runnumber>=400000
223 if(ei->eventType(xAOD::EventInfo::IS_SIMULATION) && ei->runNumber()>=330000) isRun3=true; //in MC run numbers >= 330000 should correspond to mc21
224
225 if(isRun3) Info(APP_NAME, "setting up muon selection tools for Run3 geometry");
226 else Info(APP_NAME, "setting up muon selection tools for Run2 geometry");
227
228 for (int wp = 0; wp < Nwp; wp++) {
229 Info(APP_NAME, "Creating selector tool for working point: %s ...", WPnames[wp].c_str());
230
231 CP::MuonSelectionTool* muonSelection = new CP::MuonSelectionTool("MuonSelection_" + WPnames[wp]);
232 muonSelection->msg().setLevel(MSG::INFO);
233
234 bool failed = false;
235 failed = failed || muonSelection->setProperty("IsRun3Geo",isRun3).isFailure();
236 failed = failed || muonSelection->setProperty("MaxEta", 2.7).isFailure();
237 if (WPnames[wp] == "LowPtMVA") {
238 failed = failed || muonSelection->setProperty( "MuQuality", 5).isFailure();
239 failed = failed || muonSelection->setProperty( "UseMVALowPt", true).isFailure();
240 }
241 else
242 failed = failed || muonSelection->setProperty("MuQuality", wp).isFailure();
243
244 failed = failed || muonSelection->setProperty("TurnOffMomCorr", true).isFailure();
245 failed = failed || muonSelection->initialize().isFailure();
246
247 if (failed) {
248 Error( APP_NAME, "Failed to set up MuonSelectorTool for working point: %s !", WPnames[wp].c_str() );
249 return 1;
250 }
251
252 selectorTools.emplace_back(muonSelection);
253 }
254 }
255
256 Info(APP_NAME,
257 "===>>> start processing event #%i, "
258 "run #%i %i events processed so far <<<===",
259 static_cast<int>(ei->eventNumber()), static_cast<int>(ei->runNumber()), static_cast<int>(entry));
260
261 // Get the Muons from the event:
262 const xAOD::MuonContainer* muons = 0;
263 if ( event.retrieve( muons, "Muons" ).isFailure() ) {
264 Error( APP_NAME, "Failed to read Muons container!" );
265 return 1;
266 }
267 Info(APP_NAME, "Number of muons: %i", static_cast<int>(muons->size()));
268
269 xAOD::Muon::Quality my_quality;
270 bool passesIDRequirements;
271 bool passesPreselectionCuts;
272
273 int muCounter = 0; // muon counter for each event
274
275 // Print their properties, using the tools:
278 for (; mu_itr != mu_end; ++mu_itr) {
279 int etaIndex = Neta - 1;
280 for (int eta = 0; eta < Neta - 1; eta++)
281 if (std::abs((*mu_itr)->eta()) < etaCuts[eta]) {
282 etaIndex = eta;
283 break;
284 }
285
286 allMuons++;
287 allMuonsType[static_cast<int>((*mu_itr)->muonType())]++;
288 allMuonsAuthor[static_cast<int>((*mu_itr)->author())]++;
289 allMuonsEta[etaIndex]++;
290 muCounter++;
291
292 Info(APP_NAME, "===== Muon number: %i", static_cast<int>(muCounter));
293
294 // Check truth origin
296 static const SG::ConstAccessor<int> truthTypeAcc ("truthType");
297 int truthClass = isMC ? truthTypeAcc (**mu_itr) : -999;
298
299 int truthType;
300 if (truthClass == MCTruthPartClassifier::IsoMuon)
301 truthType = 0;
302 else if (truthClass == MCTruthPartClassifier::NonIsoMuon)
303 truthType = 1;
304 else if (truthClass == MCTruthPartClassifier::Hadron)
305 truthType = 2;
306 else if (truthClass == MCTruthPartClassifier::BkgMuon)
307 truthType = 3;
308 else
309 truthType = 4;
310
311 allMuonsTruthType[truthType]++;
312
313 if ((*mu_itr)->charge() > 0)
314 nPositive++;
315 else
316 nNegative++;
317
318 passesIDRequirements = selectorTools[0]->passedIDCuts(**mu_itr);
319 passesPreselectionCuts = selectorTools[0]->passedMuonCuts(**mu_itr);
320 my_quality = selectorTools[0]->getQuality(**mu_itr);
321
322 // Print some general information about the muon
323 if (isMC) Info(APP_NAME, "Muon truthType: %d (%s)", truthClass, truthTypeNames[truthType].c_str());
324 Info(APP_NAME, "Muon pT [GeV]: %g ", std::abs((*mu_itr)->pt()) / 1000.);
325 Info(APP_NAME, "Muon eta, phi: %g, %g ", (*mu_itr)->eta(), (*mu_itr)->phi());
326 {
327 std::stringstream sstr{};
328 sstr<<"Muon muonType: "<<(*mu_itr)->muonType();
329 Info(APP_NAME, "%s", sstr.str().c_str());
330 }
331 {
332 std::stringstream sstr{};
333 sstr<<"Muon primary author: "<<(*mu_itr)->author();
334 Info(APP_NAME, "%s", sstr.str().c_str());
335 }{
336 std::stringstream sstr{};
337 sstr<<"Muon quality (from tool, from xAOD): "<<my_quality<<", "<<(*mu_itr)->quality();
338 Info(APP_NAME, "%s", sstr.str().c_str());
339 }
340 Info(APP_NAME, "Muon passes cuts (ID hits, preselection): %d, %d", passesIDRequirements, passesPreselectionCuts);
341
342
343 // Now, let's check whether the muon passes the different working points and also whether it is flagged as bad
344
345 std::string selectionResults = "Muon selection acceptance: ";
346 std::string badMuonResults = "Bad muon flag: ";
347
348 for (int wp = 0; wp < Nwp; wp++) {
349 if (selectorTools[wp]->accept(*mu_itr)) {
350 selectedMuons[wp]++;
351 selectedMuonsEvent[wp]++;
352 selectedMuonsType[(*mu_itr)->muonType()][wp]++;
353 selectedMuonsAuthor[(*mu_itr)->author()][wp]++;
354 selectedMuonsTruthType[truthType][wp]++;
355 selectedMuonsEta[etaIndex][wp]++;
356 selectionResults += "pass ";
357
358 if (!selectorTools[wp]->isBadMuon(**mu_itr)) {
359 selectedMuonsNotBad[wp]++;
360 selectedMuonsEventNotBad[wp]++;
361 selectedMuonsTypeNotBad[(*mu_itr)->muonType()][wp]++;
362 selectedMuonsAuthorNotBad[(*mu_itr)->author()][wp]++;
363 selectedMuonsTruthTypeNotBad[truthType][wp]++;
364 selectedMuonsEtaNotBad[etaIndex][wp]++;
365 }
366 } else
367 selectionResults += "fail ";
368
369 if (!selectorTools[wp]->isBadMuon(**mu_itr))
370 badMuonResults += "good ";
371 else
372 badMuonResults += "bad ";
373 }
374
375 // Print table of selection results for this muon
376 Info(APP_NAME, "%s", namesString.c_str());
377 Info(APP_NAME, "%s", selectionResults.c_str());
378 Info(APP_NAME, "%s", badMuonResults.c_str());
379
380 } // done loop over muons
381
382 // Print table of number of selected muons in this event
383 std::string NselectedString = "Number of selected muons: ";
384 std::string NselectedStringNotBad = "Including bad muon veto: ";
385 for (int wp = 0; wp < Nwp; wp++) {
386 NselectedString += std::to_string(selectedMuonsEvent[wp]) + " ";
387 NselectedStringNotBad += std::to_string(selectedMuonsEventNotBad[wp]) + " ";
388 }
389
390 Info(APP_NAME, "===== Event summary:");
391 Info(APP_NAME, "%s", namesString.c_str());
392 Info(APP_NAME, "%s", NselectedString.c_str());
393 Info(APP_NAME, "%s", NselectedStringNotBad.c_str());
394
395 // Close with a message:
396 Info(APP_NAME,
397 "===>>> done processing event #%i, "
398 "run #%i %i events processed so far <<<===",
399 static_cast<int>(ei->eventNumber()), static_cast<int>(ei->runNumber()), static_cast<int>(entry + 1));
400
401 } // done loop over events
402
403 // Now, let's summarize all we have found in the processed events
404
405 Info(APP_NAME, "======================================");
406 Info(APP_NAME, "========= Full run summary ===========");
407 Info(APP_NAME, "======================================");
408
409 Info(APP_NAME, "Processed %i events and %i muons", static_cast<int>(entries), allMuons);
410
411 Info(APP_NAME, "%i positive and %i negative muons", nPositive, nNegative);
412
413 Info(APP_NAME, "Selected muons by working point (numbers in parenthesis include bad muon veto):");
414 Info(APP_NAME, "--------------------------");
415 for (int wp = 0; wp < Nwp; wp++)
416 Info(APP_NAME, "%s: %s %i (%i)", WPnames[wp].c_str(), padding[wp].c_str(), selectedMuons[wp], selectedMuonsNotBad[wp]);
417 Info(APP_NAME, "--------------------------");
418
419 // Make table of selected muons by type and working point
420 Info(APP_NAME, "Selected muons by type and working point (numbers in parenthesis include bad muon veto):");
421 Info(APP_NAME, "---------------------------------------------------------------------------------------");
422 for (int l = 0; l < Nwp + 2; l++) {
423 std::stringstream line{};
424 if (l == 0) { // line with type names
425 line << " ";
426 for (int type = 0; type < Ntype; type++) line <<static_cast<xAOD::Muon::MuonType>(type) << " ";
427 } else if (l == 1) { // line for all muons inclusive
428 line << "All muons: ";
429 for (int type = 0; type < Ntype; type++) {
430 line << std::left << std::setw(16) << allMuonsType[type];
431 }
432 } else { // lines for each of the working points
433 int wp = l - 2;
434 line << WPnames[wp] << ":" << padding[wp] << " ";
435 for (int type = 0; type < Ntype; type++) {
436 line << std::left << std::setw(16)
437 << selectedMuonsType[type][wp]<<" ("<<selectedMuonsTypeNotBad[type][wp] << ")";
438 }
439 }
440
441 Info(APP_NAME, "%s", line.str().c_str());
442 }
443 Info(APP_NAME, "---------------------------------------------------------------------------------------");
444
445
446 // Make table of selected muons by author and working point
447 Info(APP_NAME, "Selected muons by primary author and working point (numbers in parenthesis include bad muon veto):");
448 Info(APP_NAME, "---------------------------------------------------------------------------------------");
449 for (int l = 0; l < Nwp + 2; l++) {
450 std::stringstream line{};
451 if (l == 0) { // line with author names
452 line << " ";
453 for (unsigned author = 0; author < nAuthor; author++) {
454
455 //Do not print unrepresented authors, since the table can be quite wide
456 if (allMuonsAuthor[author] == 0) continue;
457
458 line << static_cast<xAOD::Muon::Author>(author);
459 }
460 } else if (l == 1) { // line for all muons inclusive
461 line << "All muons: ";
462 for (unsigned author = 0; author < nAuthor; author++) {
463
464 if (allMuonsAuthor[author] == 0) continue;
465
466 line << std::left << std::setw(16)<<allMuonsAuthor[author];
467 }
468 } else { // lines for each of the working points
469 int wp = l - 2;
470 line << WPnames[wp] << ":"<< padding[wp] << " ";
471 for (unsigned author = 0; author < nAuthor; author++) {
472
473 if (allMuonsAuthor[author] == 0) continue;
474
475 line << std::left << std::setw(16);
476 line << selectedMuonsAuthor[author][wp]<< " ("
477 << selectedMuonsAuthorNotBad[author][wp]<< ")";
478 }
479 }
480
481 Info(APP_NAME, "%s", line.str().c_str());
482 }
483 Info(APP_NAME, "---------------------------------------------------------------------------------------");
484
485
486 // Make table of selected muons by |eta| and working point
487 Info(APP_NAME, "Selected muons by |eta| and working point (numbers in parenthesis include bad muon veto):");
488 Info(APP_NAME, "---------------------------------------------------------------------------------------");
489 for (int l = 0; l < Nwp + 2; l++) {
490 std::string line = "";
491 if (l == 0) { // line with eta regions
492 line += " ";
493 line += etaRegions;
494 } else if (l == 1) { // line for all muons inclusive
495 line += "All muons: ";
496 for (int eta = 0; eta < Neta; eta++) {
497 std::stringstream ss;
498 ss << std::left << std::setw(20) << std::to_string(allMuonsEta[eta]);
499 line += ss.str();
500 }
501 } else { // lines for each of the working points
502 int wp = l - 2;
503 line += WPnames[wp] + ":" + padding[wp] + " ";
504 for (int eta = 0; eta < Neta; eta++) {
505 std::stringstream ss;
506 ss << std::left << std::setw(20)
507 << (std::to_string(selectedMuonsEta[eta][wp]) + " (" + std::to_string(selectedMuonsEtaNotBad[eta][wp]) + ")");
508 line += ss.str();
509 }
510 }
511
512 Info(APP_NAME, "%s", line.c_str());
513 }
514 Info(APP_NAME, "---------------------------------------------------------------------------------------");
515
516 // Make table of selected muons by truth type and working point
517 if (isMC) {
518 Info(APP_NAME, "Selected muons by truth classification and working point (numbers in parenthesis include bad muon veto):");
519 Info(APP_NAME, "---------------------------------------------------------------------------------------");
520 for (int l = 0; l < Nwp + 2; l++) {
521 std::string line = "";
522 if (l == 0) { // line with truth classification labels
523 line += " ";
524 for (int truthType = 0; truthType < NtruthType; truthType++) line += truthTypeNames[truthType] + " ";
525 } else if (l == 1) { // line for all muons inclusive
526 line += "All muons: ";
527 for (int truthType = 0; truthType < NtruthType; truthType++) {
528 std::stringstream ss;
529 ss << std::left << std::setw(16) << std::to_string(allMuonsTruthType[truthType]);
530 line += ss.str();
531 }
532 } else { // lines for each of the working points
533 int wp = l - 2;
534 line += WPnames[wp] + ":" + padding[wp] + " ";
535 for (int truthType = 0; truthType < NtruthType; truthType++) {
536 std::stringstream ss;
537 ss << std::left << std::setw(16)
538 << (std::to_string(selectedMuonsTruthType[truthType][wp]) + " (" +
539 std::to_string(selectedMuonsTruthTypeNotBad[truthType][wp]) + ")");
540 line += ss.str();
541 }
542 }
543
544 Info(APP_NAME, "%s", line.c_str());
545 }
546 Info(APP_NAME, "---------------------------------------------------------------------------------------");
547 }
548
549 // Needed for Smart Slimming
551
552 // Return gracefully:
553 return 0;
554}
Scalar eta() const
pseudorapidity method
#define APP_NAME
Helper class to provide constant type-safe access to aux data.
static Double_t ss
size_t size() const
Number of registered mappings.
MsgStream & msg() const
Implementation of the muon selector tool.
virtual StatusCode initialize() override
Function initialising the tool.
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.
Helper class to provide constant type-safe access to aux data.
bool eventType(EventType type) const
Check for one particular bitmask value.
@ IS_SIMULATION
true: simulation, false: data
uint32_t runNumber() const
The current event's run number.
uint64_t eventNumber() const
The current event's event number.
ReadStats & stats()
Access the object belonging to the current thread.
Definition IOStats.cxx:17
static IOStats & instance()
Singleton object accessor.
Definition IOStats.cxx:11
void printSmartSlimmingBranchList(bool autoIncludeLinks=false) const
Print the accessed variables, formatted for smart slimming.
Tool for accessing xAOD files outside of Athena.
@ kClassAccess
Access auxiliary data using the aux containers.
int main()
Definition hello.cxx:18
double entries
Definition listroot.cxx:49
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.
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".