ATLAS Offline Software
MuonSelectionTool.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 
10 #include "CxxUtils/trapping_fp.h"
11 
12 namespace {
13  static constexpr double const MeVtoGeV = 1. / 1000.;
14  // This function defines the order of chamber indices for the low-pT MVA,
15  // i.e. defining the meaning of "the first two segments", which are used in the BDT
16  std::vector<int> initializeChamberIdxOrder() {
17  // This vector defines the order. The current order follows the order of the enum "ChIndex"
18  // except for the CSCs, which appear first. Since the order is not strictly innermost-to-outermost,
19  // a reordering could be considered for a rel. 22 retuning, which can then easily be achieved by
20  // swapping around the elements in the below initialization.
22  using namespace Muon::MuonStationIndex;
23  const std::vector<ChIdx> orderedChIndices{
28  ChIdx::EEL};
29 
30  // This vector will hold the equivalent information in a form that can be efficiently accessed in the
31  // below function "chamberIndexCompare", using the chamber index as the vector index
32  std::vector<int> chamberIndexOrder(orderedChIndices.size());
33 
34  for (unsigned int i = 0; i < orderedChIndices.size(); i++) {
35  chamberIndexOrder[toInt(orderedChIndices[i])] = i;
36  }
37  return chamberIndexOrder;
38  }
39 
40  // This is the comparison function for the sorting of segments according to the chamber index
41  bool chamberIndexCompare(const xAOD::MuonSegment* first, const xAOD::MuonSegment* second) {
42  static const std::vector<int> chamberIndexOrder = initializeChamberIdxOrder();
43  return (chamberIndexOrder[toInt(first->chamberIndex())] <
44  chamberIndexOrder[toInt(second->chamberIndex())]);
45  }
46 
47  static const SG::AuxElement::Accessor<float> mePt_acc("MuonSpectrometerPt");
48  static const SG::AuxElement::Accessor<float> idPt_acc("InnerDetectorPt");
49  static const SG::AuxElement::Accessor<uint8_t> eta1stgchits_acc("etaLayer1STGCHits");
50  static const SG::AuxElement::Accessor<uint8_t> eta2stgchits_acc("etaLayer2STGCHits");
51  static const SG::AuxElement::Accessor<uint8_t> mmhits_acc("MMHits");
52 } // namespace
53 
54 namespace CP {
55 
56  MuonSelectionTool::MuonSelectionTool(const std::string& tool_name) : asg::AsgTool(tool_name), m_acceptInfo("MuonSelection"){
57 
58  if (!m_calculateTightNNScore) m_onnxTool.setTypeAndName("");
59 
60  }
61 
63 
65 
66  // Greet the user:
67  ATH_MSG_INFO("Initialising...");
68 
69  m_geoOnTheFly ? ATH_MSG_INFO("Is Run-3 geometry: On-the-fly determination. THIS OPTION IS DEPRECATED AND WILL BE REMOVED SOON. Use IsRun3Geo property instead.")
70  : ATH_MSG_INFO("Is Run-3 geometry: " << m_isRun3.value());
71  ATH_MSG_INFO("Maximum muon |eta|: " << m_maxEta.value());
72  ATH_MSG_INFO("Muon quality: "<< m_quality.value());
73  if (m_toroidOff) ATH_MSG_INFO("!! CONFIGURED FOR TOROID-OFF COLLISIONS !!");
74  if (m_SctCutOff) ATH_MSG_WARNING("!! SWITCHING SCT REQUIREMENTS OFF !! FOR DEVELOPMENT USE ONLY !!");
75  if (m_PixCutOff) ATH_MSG_WARNING("!! SWITCHING PIXEL REQUIREMENTS OFF !! FOR DEVELOPMENT USE ONLY !!");
76  if (m_SiHolesCutOff) ATH_MSG_WARNING("!! SWITCHING SILICON HOLES REQUIREMENTS OFF !! FOR DEVELOPMENT USE ONLY !!");
77  if (m_custom_dir != "")
78  ATH_MSG_WARNING("!! SETTING UP WITH USER SPECIFIED INPUT LOCATION \"" << m_custom_dir << "\"!! FOR DEVELOPMENT USE ONLY !! ");
79  if (!m_useAllAuthors)
81  "Not using allAuthors variable as currently missing in many derivations; LowPtEfficiency working point will always return "
82  "false, but this is expected at the moment. Have a look here: "
83  "https://twiki.cern.ch/twiki/bin/view/Atlas/MuonSelectionToolR21#New_LowPtEfficiency_working_poin");
84 
85  // Print message to ensure that users excluding 2-station muons in the high-pT selection are aware of this
87  ATH_MSG_INFO("You have opted to select only 3-station muons in the high-pT selection! "
88  << "Please feed 'HighPt3Layers' to the 'WorkingPoint' property to retrieve the appropriate scale-factors");
89 
90  // Only an MVA-based selection is defined for segment-tagged muons for the Low-pT working point
92  ATH_MSG_WARNING("No cut-based selection is defined for segment-tagged muons in the Low-pT working point. "
93  << "Please set UseMVALowPt=true if you want to try the UseSegmentTaggedLowPt=true option.");
95  }
96  if (m_useLRT) {
97  ATH_MSG_INFO("MuonSelectionTool will assume both Standard and LRT Muons are being used, and that the necessary information is available to identify the type (standard or LRT).");
98  if (m_quality!=1) ATH_MSG_WARNING("Currently, only Medium quality is supported for LRT muons. Your chosen WP will be applied (w/o ID cuts), but no recommendations are available for this quality.");
99  }
100 
101  // Set up the TAccept object:
102  m_acceptInfo.addCut("Eta", "Selection of muons according to their pseudorapidity");
103  m_acceptInfo.addCut("IDHits", "Selection of muons according to whether they passed the MCP ID Hit cuts");
104  m_acceptInfo.addCut("Preselection", "Selection of muons according to their type/author");
105  m_acceptInfo.addCut("Quality", "Selection of muons according to their tightness");
106  // Sanity check
107  if (m_quality > 5) {
109  "Invalid quality (i.e. selection WP) set: "
110  << m_quality
111  << " - it must be an integer between 0 and 5! (0=Tight, 1=Medium, 2=Loose, 3=Veryloose, 4=HighPt, 5=LowPtEfficiency)");
112  return StatusCode::FAILURE;
113  }
114  if (m_quality == 5 && !m_useAllAuthors) {
115  ATH_MSG_ERROR("Cannot use lowPt working point if allAuthors is not available!");
116  return StatusCode::FAILURE;
117  }
118 
119  if(m_caloScoreWP<1 || m_caloScoreWP>4){
120  ATH_MSG_FATAL("CaloScoreWP property must be set to 1, 2, 3 or 4");
121  return StatusCode::FAILURE;
122  }
123 
124  // Load Tight WP cut-map
125  ATH_MSG_INFO("Initialising tight working point histograms...");
126  std::string tightWP_rootFile_fullPath;
127  if (!m_custom_dir.empty()) {
128  tightWP_rootFile_fullPath = PathResolverFindCalibFile(m_custom_dir + "/muonSelection_tightWPHisto.root");
129  } else {
130  tightWP_rootFile_fullPath = PathResolverFindCalibFile(
131  Form("MuonSelectorTools/%s/muonSelection_tightWPHisto.root", m_calibration_version.value().c_str()));
132  }
133 
134  ATH_MSG_INFO("Reading muon tight working point histograms from " << tightWP_rootFile_fullPath);
135  //
136  std::unique_ptr<TFile> file(TFile::Open(tightWP_rootFile_fullPath.c_str(), "READ"));
137 
138  if (!file->IsOpen()) {
139  ATH_MSG_ERROR("Cannot read tight working point file from " << tightWP_rootFile_fullPath);
140  return StatusCode::FAILURE;
141  }
142 
143  // Retrieve all the relevant histograms
144  ATH_CHECK(getHist(file.get(), "tightWP_lowPt_rhoCuts", m_tightWP_lowPt_rhoCuts));
145  ATH_CHECK(getHist(file.get(), "tightWP_lowPt_qOverPCuts", m_tightWP_lowPt_qOverPCuts));
146  ATH_CHECK(getHist(file.get(), "tightWP_mediumPt_rhoCuts", m_tightWP_mediumPt_rhoCuts));
147  ATH_CHECK(getHist(file.get(), "tightWP_highPt_rhoCuts", m_tightWP_highPt_rhoCuts));
148  //
149  file->Close();
150 
151  // Read bad muon veto efficiency histograms
152  std::string BMVcutFile_fullPath = PathResolverFindCalibFile(m_BMVcutFile);
153 
154  ATH_MSG_INFO("Reading bad muon veto cut functions from " << BMVcutFile_fullPath);
155  //
156  std::unique_ptr<TFile> BMVfile(TFile::Open(BMVcutFile_fullPath.c_str(), "READ"));
157 
158  if (!BMVfile->IsOpen()) {
159  ATH_MSG_ERROR("Cannot read bad muon veto cut function file from " << BMVcutFile_fullPath);
160  return StatusCode::FAILURE;
161  }
162 
163  m_BMVcutFunction_barrel = std::unique_ptr<TF1>((TF1*)BMVfile->Get("BMVcutFunction_barrel"));
164  m_BMVcutFunction_endcap = std::unique_ptr<TF1>((TF1*)BMVfile->Get("BMVcutFunction_endcap"));
165 
166  BMVfile->Close();
167 
169  ATH_MSG_ERROR("Cannot read bad muon veto cut functions");
170  return StatusCode::FAILURE;
171  }
172 
173  if (m_useMVALowPt) {
174  // Set up TMVA readers for MVA-based low-pT working point
175  // E and O refer to even and odd event numbers to avoid applying the MVA on events used for training
176  TString weightPath_EVEN_MuidCB = PathResolverFindCalibFile(m_MVAreaderFile_EVEN_MuidCB);
177  TString weightPath_ODD_MuidCB = PathResolverFindCalibFile(m_MVAreaderFile_ODD_MuidCB);
178  TString weightPath_EVEN_MuGirl = PathResolverFindCalibFile(m_MVAreaderFile_EVEN_MuGirl);
179  TString weightPath_ODD_MuGirl = PathResolverFindCalibFile(m_MVAreaderFile_ODD_MuGirl);
180 
181  auto make_mva_reader = [](TString file_path) {
182  std::vector<std::string> mva_var_names{"momentumBalanceSignificance",
183  "scatteringCurvatureSignificance",
184  "scatteringNeighbourSignificance",
185  "EnergyLoss",
186  "middleLargeHoles+middleSmallHoles",
187  "muonSegmentDeltaEta",
188  "muonSeg1ChamberIdx",
189  "muonSeg2ChamberIdx"};
190  std::unique_ptr<TMVA::Reader> reader = std::make_unique<TMVA::Reader>(mva_var_names);
191  reader->BookMVA("BDTG", file_path);
192  return reader;
193  };
194  m_readerE_MUID = make_mva_reader(weightPath_EVEN_MuidCB);
195 
196  m_readerO_MUID = make_mva_reader(weightPath_ODD_MuidCB);
197 
198  m_readerE_MUGIRL = make_mva_reader(weightPath_EVEN_MuGirl);
199 
200  m_readerO_MUGIRL = make_mva_reader(weightPath_ODD_MuGirl);
201 
203  TString weightPath_MuTagIMO_etaBin1 = PathResolverFindCalibFile(m_MVAreaderFile_MuTagIMO_etaBin1);
204  TString weightPath_MuTagIMO_etaBin2 = PathResolverFindCalibFile(m_MVAreaderFile_MuTagIMO_etaBin2);
205  TString weightPath_MuTagIMO_etaBin3 = PathResolverFindCalibFile(m_MVAreaderFile_MuTagIMO_etaBin3);
206 
207  auto make_mva_reader_MuTagIMO = [](TString file_path, bool useSeg2ChamberIndex) {
208  std::vector<std::string> mva_var_names;
209  if (useSeg2ChamberIndex) mva_var_names.push_back("muonSeg2ChamberIndex");
210  mva_var_names.push_back("muonSeg1ChamberIndex");
211  mva_var_names.push_back("muonSeg1NPrecisionHits");
212  mva_var_names.push_back("muonSegmentDeltaEta");
213  mva_var_names.push_back("muonSeg1GlobalR");
214  mva_var_names.push_back("muonSeg1Chi2OverDoF");
215  mva_var_names.push_back("muonSCS");
216 
217  std::unique_ptr<TMVA::Reader> reader = std::make_unique<TMVA::Reader>(mva_var_names);
218  reader->BookMVA("BDT", file_path);
219  return reader;
220  };
221 
222  m_reader_MUTAGIMO_etaBin1 = make_mva_reader_MuTagIMO(weightPath_MuTagIMO_etaBin1, false);
223  m_reader_MUTAGIMO_etaBin2 = make_mva_reader_MuTagIMO(weightPath_MuTagIMO_etaBin2, false);
224  m_reader_MUTAGIMO_etaBin3 = make_mva_reader_MuTagIMO(weightPath_MuTagIMO_etaBin3, true);
225  }
226  }
227 
228  ATH_MSG_INFO("TightNNScore calculation is " << (m_calculateTightNNScore ? "enabled." : "disabled."));
229 
231  if (m_onnxTool.empty()) {
232  ATH_MSG_ERROR("Cannot calculate TightNNScore: ONNX tool not configured! "
233  "Please set the ORTInferenceTool property to a valid AthOnnx::OnnxRuntimeInferenceTool instance.");
234  return StatusCode::FAILURE;
235  }
236 
237  ATH_MSG_INFO("Retrieving ONNX tool: " << m_onnxTool.name());
238  ATH_CHECK(m_onnxTool.retrieve());
239  } else ATH_MSG_INFO("ONNX tool not configured — skipping retrieval.");
240 
241  ATH_MSG_INFO("Finished ONNX tool setup");
242 
244  // Return gracefully:
245  return StatusCode::SUCCESS;
246  }
247 
248  StatusCode MuonSelectionTool::getHist(TFile* file, const std::string& histName, std::unique_ptr<TH1>& hist) const {
249  //
250  if (!file) {
251  ATH_MSG_ERROR(" getHist(...) TFile is nullptr! Check that the Tight cut map is loaded correctly");
252  return StatusCode::FAILURE;
253  }
254  TH1* h_ptr = nullptr;
255  file->GetObject(histName.c_str(), h_ptr);
256  //
257  //
258  if (!h_ptr) {
259  ATH_MSG_ERROR("Cannot retrieve histogram " << histName);
260  return StatusCode::FAILURE;
261  }
262  hist = std::unique_ptr<TH1>{h_ptr};
263  hist->SetDirectory(nullptr);
264  ATH_MSG_INFO("Successfully read tight working point histogram: " << hist->GetName());
265  //
266  return StatusCode::SUCCESS;
267  }
268 
270 
272  // Check if this is a muon:
273  if (p->type() != xAOD::Type::Muon) {
274  ATH_MSG_ERROR("accept(...) Function received a non-muon");
275  return asg::AcceptData(&m_acceptInfo);
276  }
277 
278  // Cast it to a muon:
279  const xAOD::Muon* mu = dynamic_cast<const xAOD::Muon*>(p);
280  if (!mu) {
281  ATH_MSG_FATAL("accept(...) Failed to cast particle to muon");
282  return asg::AcceptData(&m_acceptInfo);
283  }
284 
285  // Let the specific function do the work:
286  return accept(*mu);
287  }
288 
289  //============================================================================
291 
292  static std::atomic<bool> checkDone{false};
293 
294  if(!checkDone) {
295  // Check that the user either set the correct geometry or enabled on-the-fly determination
296  // This can happen intentionally in developer mode. In any case don't throw an exception
297  // (we should either trust the user or ignore in the first place and force on-the-fly determination).
298  if (isRun3() != isRun3(true)) {
299  ATH_MSG_WARNING("MuonSelectionTool is configured with isRun3Geo="<<isRun3()
300  <<" while on-the fly check for runNumber "<<getRunNumber(true)<<" indicates isRun3Geo="<<isRun3(true));
301  }
302 
303  // Check that the requested WP is currently supported by the MCP group.
304  if (isRun3()) {
305  if(m_quality!=0 && m_quality!=1 && m_quality!=2 && m_quality!=4 && m_quality!=5) {
306  ATH_MSG_WARNING("MuonSelectionTool currently supports Loose, Medium, Tight, HighPt, and LowPtEfficiency WPs for Run3; all other WPs can only be used in ExpertDevelopMode mode");
307  }
308 
310  ATH_MSG_WARNING("For Run3, Tight WP is supported only when ExcludeNSWFromPrecisionLayers=False and RecalcPrecisionLayerswNSW=True");
311  }
312  }
313 
314  checkDone = true;
315  }
316  }
317 
318  //============================================================================
320  // Verbose information
321  ATH_MSG_VERBOSE("-----------------------------------");
322  ATH_MSG_VERBOSE("New muon passed to accept function:");
323  if (mu.muonType() == xAOD::Muon::Combined)
324  ATH_MSG_VERBOSE("Muon type: combined");
325  else if (mu.muonType() == xAOD::Muon::MuonStandAlone)
326  ATH_MSG_VERBOSE("Muon type: stand-alone");
327  else if (mu.muonType() == xAOD::Muon::SegmentTagged)
328  ATH_MSG_VERBOSE("Muon type: segment-tagged");
329  else if (mu.muonType() == xAOD::Muon::CaloTagged)
330  ATH_MSG_VERBOSE("Muon type: calorimeter-tagged");
331  else if (mu.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon)
332  ATH_MSG_VERBOSE("Muon type: silicon-associated forward");
333  ATH_MSG_VERBOSE("Muon pT [GeV]: " << mu.pt() * MeVtoGeV);
334  ATH_MSG_VERBOSE("Muon eta: " << mu.eta());
335  ATH_MSG_VERBOSE("Muon phi: " << mu.phi());
336 
337  checkSanity();
338 
339  asg::AcceptData acceptData(&m_acceptInfo);
340 
341  // Do the eta cut:
342  if (std::abs(mu.eta()) >= m_maxEta) {
343  ATH_MSG_VERBOSE("Failed eta cut");
344  return acceptData;
345  }
346  acceptData.setCutResult("Eta", true);
347 
348  // Passes ID hit cuts
349  bool passIDCuts = passedIDCuts(mu);
350  ATH_MSG_VERBOSE("Passes ID Hit cuts " << passIDCuts);
351  acceptData.setCutResult("IDHits", passIDCuts);
352 
353  // passes muon preselection
354  bool passMuonCuts = passedMuonCuts(mu);
355  ATH_MSG_VERBOSE("Passes preselection cuts " << passMuonCuts);
356  acceptData.setCutResult("Preselection", passMuonCuts);
357 
358  if (!passIDCuts || !passMuonCuts) { return acceptData; }
359 
360  // Passes quality requirements
361  xAOD::Muon::Quality thisMu_quality = getQuality(mu);
362  bool thisMu_highpt = false;
363  thisMu_highpt = passedHighPtCuts(mu);
364  bool thisMu_lowptE = false;
365  thisMu_lowptE = passedLowPtEfficiencyCuts(mu, thisMu_quality);
366  ATH_MSG_VERBOSE("Summary of quality information for this muon: ");
367  ATH_MSG_VERBOSE("Muon quality: " << thisMu_quality << " passes HighPt: " << thisMu_highpt
368  << " passes LowPtEfficiency: " << thisMu_lowptE);
369  if (m_quality < 4 && thisMu_quality > m_quality) { return acceptData; }
370  if (m_quality == 4 && !thisMu_highpt) { return acceptData; }
371  if (m_quality == 5 && !thisMu_lowptE) { return acceptData; }
372  acceptData.setCutResult("Quality", true);
373  // Return the result:
374  return acceptData;
375  }
376 
378  mu.setQuality(getQuality(mu));
379  return;
380  }
381  void MuonSelectionTool::IdMsPt(const xAOD::Muon& mu, float& idPt, float& mePt) const {
382  const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
383  const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
384  if (!idtrack || !metrack) idPt = mePt = -1.;
385  else if (m_turnOffMomCorr) {
386  mePt = metrack->pt();
387  idPt = idtrack->pt();
388  } else {
389  if (!mePt_acc.isAvailable(mu) || !idPt_acc.isAvailable(mu)) {
390  ATH_MSG_FATAL("The muon with pT " << mu.pt() * MeVtoGeV << " eta: " << mu.eta() << ", phi:" << mu.phi()
391  << " q:" << mu.charge() << ", author:" << mu.author()
392  << " is not decorated with calibrated momenta. Please fix");
393  throw std::runtime_error("MuonSelectionTool() - qOverP significance calculation failed");
394  }
395  mePt = mePt_acc(mu);
396  idPt = idPt_acc(mu);
397  }
398  }
399 
401  // Avoid spurious FPEs in the clang build.
403 
404  if (m_disablePtCuts) {
405  ATH_MSG_VERBOSE(__FILE__ << ":"<<__LINE__
406  << " Momentum dependent cuts are disabled. Return 0.");
407  return 0.;
408  }
409  const xAOD::TrackParticle* idtrack = muon.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
410  const xAOD::TrackParticle* metrack = muon.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
411  if (!idtrack || !metrack) {
412  ATH_MSG_VERBOSE("No ID / MS track. Return dummy large value of 1 mio");
413  return 1.e6;
414  }
415  float mePt{-1.}, idPt{-1.};
416  IdMsPt(muon, idPt, mePt);
417 
418  const float meP = mePt / std::sin(metrack->theta());
419  const float idP = idPt / std::sin(idtrack->theta());
420 
421  float qOverPsigma = std::sqrt(idtrack->definingParametersCovMatrix()(4, 4) + metrack->definingParametersCovMatrix()(4, 4));
422  return std::abs((metrack->charge() / meP) - (idtrack->charge() / idP)) / qOverPsigma;
423  }
425  if (m_disablePtCuts) {
426  ATH_MSG_VERBOSE(__FILE__ << ":"<<__LINE__
427  << "Momentum dependent cuts are disabled. Return 0.");
428  return 0.;
429  }
430  float mePt{-1.}, idPt{-1.};
431  IdMsPt(muon, idPt, mePt);
432  return std::abs(idPt - mePt) / muon.pt();
433  }
434 
435  xAOD::Muon::Quality MuonSelectionTool::getQuality(const xAOD::Muon& mu) const {
436  ATH_MSG_VERBOSE("Evaluating muon quality...");
437  if (isRun3() && mu.isAuthor(xAOD::Muon::Author::Commissioning) && !m_allowComm) {
438  ATH_MSG_VERBOSE("Reject authors from the commissioning chain");
439  return xAOD::Muon::VeryLoose;
440  }
441 
442  // SegmentTagged muons
443  if (mu.muonType() == xAOD::Muon::SegmentTagged) {
444  ATH_MSG_VERBOSE("Muon is segment-tagged");
445 
446  if (std::abs(mu.eta()) < 0.1) {
447  ATH_MSG_VERBOSE("Muon is loose");
448  return xAOD::Muon::Loose;
449  } else {
450  ATH_MSG_VERBOSE("Do not allow segment-tagged muon at |eta| > 0.1 - return VeryLoose");
451  return xAOD::Muon::VeryLoose;
452  }
453  }
454 
455  // CaloTagged muons
456  if (mu.muonType() == xAOD::Muon::CaloTagged) {
457  ATH_MSG_VERBOSE("Muon is calorimeter-tagged");
458 
459  if (std::abs(mu.eta()) < 0.1 && passedCaloTagQuality(mu)) {
460  ATH_MSG_VERBOSE("Muon is loose");
461  return xAOD::Muon::Loose;
462  }
463  }
464 
465  // Combined muons
468 
469  if (mu.muonType() == xAOD::Muon::Combined) {
470  ATH_MSG_VERBOSE("Muon is combined");
471  if (mu.author() == xAOD::Muon::STACO) {
472  ATH_MSG_VERBOSE("Muon is STACO - return VeryLoose");
473  return xAOD::Muon::VeryLoose;
474  }
475 
476  // rejection muons with out-of-bounds hits
479 
481  ATH_MSG_VERBOSE("Muon has out-of-bounds precision hits - return VeryLoose");
482  return xAOD::Muon::VeryLoose;
483  }
484 
485  // LOOSE / MEDIUM / TIGHT WP
486  const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
487  const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
488  if (idtrack && metrack && metrack->definingParametersCovMatrix()(4, 4) > 0) {
489  const float qOverPsignif = qOverPsignificance(mu);
490  const float rho = rhoPrime(mu);
491  const float reducedChi2 = mu.primaryTrackParticle()->chiSquared() / mu.primaryTrackParticle()->numberDoF();
492 
493  ATH_MSG_VERBOSE("Relevant cut variables:");
494  ATH_MSG_VERBOSE("number of precision layers = " << (int)summary.nprecisionLayers);
495  ATH_MSG_VERBOSE("reduced Chi2 = " << reducedChi2);
496  ATH_MSG_VERBOSE("qOverP significance = " << qOverPsignif);
497 
498  // NEW TIGHT WP
499  if (summary.nprecisionLayers > 1 && reducedChi2 < 8 && std::abs(qOverPsignif) < 7) {
500  if (passTight(mu, rho, qOverPsignif)) {
501  ATH_MSG_VERBOSE("Muon is tight");
502  return xAOD::Muon::Tight;
503  }
504  }
505 
506  ATH_MSG_VERBOSE("Muon did not pass requirements for tight combined muon");
507 
508  // MEDIUM WP
509  if ((std::abs(qOverPsignif) < 7 || m_toroidOff) &&
510  (summary.nprecisionLayers > 1 ||(summary.nprecisionLayers == 1 && summary.nprecisionHoleLayers < 2 && std::abs(mu.eta()) < 0.1))
511 
512  ) {
513  ATH_MSG_VERBOSE("Muon is medium");
514  return xAOD::Muon::Medium;
515  }
516 
517  ATH_MSG_VERBOSE("Muon did not pass requirements for medium combined muon");
518 
519  } else {
520  ATH_MSG_VERBOSE("Muon is missing the ID and/or ME tracks...");
521 
522  // CB muons with missing ID or ME track
523  if ((summary.nprecisionLayers > 1 ||
524  (summary.nprecisionLayers == 1 && summary.nprecisionHoleLayers < 2 && std::abs(mu.eta()) < 0.1))) {
525  // In toroid-off data ME/MS tracks often missing - need special treatment => flagging as "Medium"
526  // In toroid-on data ME/MS tracks missing only for <1% of CB muons, mostly MuGirl (to be fixed) => flagging as "Loose"
527  if (m_toroidOff) {
528  ATH_MSG_VERBOSE("...this is toroid-off data - returning medium");
529  return xAOD::Muon::Medium;
530  } else {
531  ATH_MSG_VERBOSE("...this is not toroid-off data - returning loose");
532  return xAOD::Muon::Loose;
533  }
534  }
535  }
536 
537  // Improvement for Loose targeting low-pT muons (pt<7 GeV)
538  if ((m_disablePtCuts || mu.pt() * MeVtoGeV < 7.) && std::abs(mu.eta()) < 1.3 && summary.nprecisionLayers > 0 &&
539  (mu.author() == xAOD::Muon::MuGirl && mu.isAuthor(xAOD::Muon::MuTagIMO))) {
540  ATH_MSG_VERBOSE("Muon passed selection for loose working point at low pT");
541  return xAOD::Muon::Loose;
542  }
543 
544  // didn't pass the set of requirements for a medium or tight combined muon
545  ATH_MSG_VERBOSE("Did not pass selections for combined muon - returning VeryLoose");
546  return xAOD::Muon::VeryLoose;
547  }
548 
549  // SA muons
550  if (mu.author() == xAOD::Muon::MuidSA) {
551  ATH_MSG_VERBOSE("Muon is stand-alone");
552 
553  if(isRun3() && !m_developMode){
554  ATH_MSG_VERBOSE("Standalone muons currently only used when in expert mode for run3");
555  return xAOD::Muon::VeryLoose; //SA muons currently disabled for run3
556  }
557 
558  if (std::abs(mu.eta()) > 2.5) {
559  ATH_MSG_VERBOSE("number of precision layers = " << (int)summary.nprecisionLayers);
560 
561  // 3 station requirement for medium
562  if (summary.nprecisionLayers > 2 && !m_toroidOff) {
563  ATH_MSG_VERBOSE("Muon is medium");
564  return xAOD::Muon::Medium;
565  }
566  }
567 
568  // didn't pass the set of requirements for a medium SA muon
569  ATH_MSG_VERBOSE("Muon did not pass selection for medium stand-alone muon - return VeryLoose");
570  return xAOD::Muon::VeryLoose;
571  }
572 
573  // SiliconAssociatedForward (SAF) muons
574  if (mu.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
575  ATH_MSG_VERBOSE("Muon is silicon-associated forward muon");
576 
577  if(isRun3() && !m_developMode){
578  ATH_MSG_VERBOSE("Silicon-associated forward muon muons currently only used when in expert mode for run3");
579  return xAOD::Muon::VeryLoose; //SAF muons currently disabled for run3
580  }
581 
582  const xAOD::TrackParticle* cbtrack = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
583  const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
584 
585  if (cbtrack && metrack) {
586  if (std::abs(cbtrack->eta()) > 2.5) {
587  ATH_MSG_VERBOSE("number of precision layers = " << (int)summary.nprecisionLayers);
588 
589  if (summary.nprecisionLayers > 2 && !m_toroidOff) {
590  if (mu.trackParticle(xAOD::Muon::Primary) == mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle) &&
591  !m_developMode) {
593  "SiliconForwardAssociated muon has ID track as primary track particle. "
594  << "This is a bug fixed starting with xAODMuon-00-17-07, which should be present in this release. "
595  << "Please report this to the Muon CP group!");
596  }
597  ATH_MSG_VERBOSE("Muon is medium");
598  return xAOD::Muon::Medium;
599  }
600  }
601  }
602 
603  // didn't pass the set of requirements for a medium SAF muon
604  ATH_MSG_VERBOSE("Muon did not pass selection for medium silicon-associated forward muon - return VeryLoose");
605  return xAOD::Muon::VeryLoose;
606  }
607 
608  ATH_MSG_VERBOSE("Muon did not pass selection for loose/medium/tight for any muon type - return VeryLoose");
609  return xAOD::Muon::VeryLoose;
610  }
611 
612  void MuonSelectionTool::setPassesIDCuts(xAOD::Muon& mu) const { mu.setPassesIDCuts(passedIDCuts(mu)); }
613 
615  if (m_useLRT) {
616  static const SG::AuxElement::Accessor<char> isLRTmuon("isLRT");
617  if (isLRTmuon.isAvailable(mu)) {
618  if (isLRTmuon(mu)) return true;
619  }
620  else {
621  static const SG::AuxElement::Accessor<uint64_t> patternAcc("patternRecoInfo");
622  const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
623  if(idtrack) {
624  if(!patternAcc.isAvailable(*idtrack)) {
625  ATH_MSG_FATAL("No information available to tell if the muon is LRT or standard. Either run MuonLRTMergingAlg to decorate with `isLRT` flag, or supply the patternRecoInfo for the original ID track.");
626  throw std::runtime_error("MuonSelectionTool() - isLRT decor and patternRecoInfo both unavailable for a muon.");
627  }
628  std::bitset<xAOD::NumberOfTrackRecoInfo> patternBitSet(patternAcc(*idtrack));
629  if (patternBitSet.test(xAOD::SiSpacePointsSeedMaker_LargeD0)) return true;
630  }
631  }
632  }
633  // do not apply the ID hit requirements for SA muons for |eta| > 2.5
634  if (mu.author() == xAOD::Muon::MuidSA && std::abs(mu.eta()) > 2.5) {
635  return true;
636  } else if (mu.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
637  const xAOD::TrackParticle* cbtrack = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
638  if (cbtrack && std::abs(cbtrack->eta()) > 2.5) { return true; }
639  return false;
640  } else {
641  if (mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle))
642  return passedIDCuts(*mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle));
643  else if (mu.primaryTrackParticle())
644  return passedIDCuts(*mu.primaryTrackParticle());
645  }
646  return false;
647  }
648 
650  if (mu.muonType() != xAOD::Muon::Combined) return false;
651  // ::
652  const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
653  const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
654  const xAOD::TrackParticle* cbtrack = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
655  // ::
656  // Some spurious muons are found to have negative ME track fit covariance, and are typically poorly reconstructed
657  if (metrack && metrack->definingParametersCovMatrix()(4, 4) < 0.0) return true;
658  // ::
659  bool IsBadMuon = false;
660  if (idtrack && metrack && cbtrack) {
661  // ::
662  double qOverP_ID = idtrack->qOverP();
663  double qOverPerr_ID = std::sqrt(idtrack->definingParametersCovMatrix()(4, 4));
664  double qOverP_ME = metrack->qOverP();
665  double qOverPerr_ME = std::sqrt(metrack->definingParametersCovMatrix()(4, 4));
666  double qOverP_CB = cbtrack->qOverP();
667  double qOverPerr_CB = std::sqrt(cbtrack->definingParametersCovMatrix()(4, 4));
668  // ::
669  if (m_quality == 4) {
670  // recipe for high-pt selection
671  IsBadMuon = !passedErrorCutCB(mu);
672 
675 
676  // temporarily apply same recipe as for other working points in addition to CB error
677  // cut for 2-station muons, pending better treatment of ID/MS misalignments
678  if (m_use2stationMuonsHighPt && summary.nprecisionLayers == 2) {
679  double IdCbRatio = std::abs((qOverPerr_ID / qOverP_ID) / (qOverPerr_CB / qOverP_CB));
680  double MeCbRatio = std::abs((qOverPerr_ME / qOverP_ME) / (qOverPerr_CB / qOverP_CB));
681  IsBadMuon = (IdCbRatio < 0.8 || MeCbRatio < 0.8 || IsBadMuon);
682  }
683  } else {
684  // recipe for other WP
685  double IdCbRatio = std::abs((qOverPerr_ID / qOverP_ID) / (qOverPerr_CB / qOverP_CB));
686  double MeCbRatio = std::abs((qOverPerr_ME / qOverP_ME) / (qOverPerr_CB / qOverP_CB));
687  IsBadMuon = (IdCbRatio < 0.8 || MeCbRatio < 0.8);
688  }
689  } else {
690  return true;
691  }
692  return IsBadMuon;
693  }
694 
696  xAOD::Muon::Quality thisMu_quality = getQuality(mu);
697  return passedLowPtEfficiencyCuts(mu, thisMu_quality);
698  }
699 
700  bool MuonSelectionTool::passedLowPtEfficiencyCuts(const xAOD::Muon& mu, xAOD::Muon::Quality thisMu_quality) const {
701  ATH_MSG_VERBOSE("Checking whether muon passes low-pT selection...");
702 
703  //LowPt Not supported in run3 for the time being
704  if(isRun3() && !m_developMode){
705  ATH_MSG_VERBOSE("LowPt WP currently not supported for run3 if not in expert mode");
706  return false;
707  }
708  if (!m_useAllAuthors) { // no allAuthors, always fail the WP
709  ATH_MSG_VERBOSE("Do not have allAuthors variable - fail low-pT");
710  return false;
711  }
712 
713  // requiring combined muons, unless segment-tags are included
715  if (mu.muonType() != xAOD::Muon::Combined) {
716  ATH_MSG_VERBOSE("Muon is not combined - fail low-pT");
717  return false;
718  }
719  } else {
720  if (mu.muonType() != xAOD::Muon::Combined && mu.muonType() != xAOD::Muon::SegmentTagged) {
721  ATH_MSG_VERBOSE("Muon is not combined or segment-tagged - fail low-pT");
722  return false;
723  }
724  }
725 
726  // author check
728  if (mu.author() != xAOD::Muon::MuGirl && mu.author() != xAOD::Muon::MuidCo) {
729  ATH_MSG_VERBOSE("Muon is neither MuGirl nor MuidCo - fail low-pT");
730  return false;
731  }
732  } else {
733  if (mu.author() != xAOD::Muon::MuGirl && mu.author() != xAOD::Muon::MuidCo && mu.author() != xAOD::Muon::MuTagIMO) {
734  ATH_MSG_VERBOSE("Muon is neither MuGirl / MuidCo / MuTagIMO - fail low-pT");
735  return false;
736  }
737  }
738 
739  // applying Medium selection above pT = 18 GeV
740  if (mu.pt() * MeVtoGeV > 18.) {
741  ATH_MSG_VERBOSE("pT > 18 GeV - apply medium selection");
742  if (thisMu_quality <= xAOD::Muon::Medium) {
743  ATH_MSG_VERBOSE("Muon passed low-pT selection");
744  return true;
745  } else {
746  ATH_MSG_VERBOSE("Muon failed low-pT selection");
747  return false;
748  }
749  }
750 
751  // requiring Medium in forward regions
752  if (!m_useMVALowPt && std::abs(mu.eta()) > 1.55 && thisMu_quality > xAOD::Muon::Medium) {
753  ATH_MSG_VERBOSE("Not using MVA selection, failing low-pT selection due to medium requirement in forward region");
754  return false;
755  }
756 
757  // rejection of muons with out-of-bounds hits
761  ATH_MSG_VERBOSE("Muon has out-of-bounds precision hits - fail low-pT");
762  return false;
763  }
764 
765  // requiring explicitely >=1 station (2 in the |eta|>1.3 region when Medium selection is not explicitely required)
766  if (mu.muonType() == xAOD::Muon::Combined) {
769  uint nStationsCut = (std::abs(mu.eta()) > 1.3 && std::abs(mu.eta()) < 1.55) ? 2 : 1;
770  if (summary.nprecisionLayers < nStationsCut) {
771  ATH_MSG_VERBOSE("number of precision layers = " << (int)summary.nprecisionLayers << " is lower than cut value " << nStationsCut
772  << " - fail low-pT");
773  return false;
774  }
775  }
776 
777  // reject MuGirl muon if not found also by MuTagIMO
778  if (m_useAllAuthors) {
779  if (mu.author() == xAOD::Muon::MuGirl && !mu.isAuthor(xAOD::Muon::MuTagIMO)) {
780  ATH_MSG_VERBOSE("MuGirl muon is not confirmed by MuTagIMO - fail low-pT");
781  return false;
782  }
783  } else
784  return false;
785 
786  if (m_useMVALowPt) {
787  ATH_MSG_VERBOSE("Applying MVA-based selection");
789  }
790 
791  ATH_MSG_VERBOSE("Applying cut-based selection");
792 
793  // apply some loose quality requirements
795 
799 
800  ATH_MSG_VERBOSE("momentum balance significance: " << momentumBalanceSignificance);
801  ATH_MSG_VERBOSE("scattering curvature significance: " << scatteringCurvatureSignificance);
802  ATH_MSG_VERBOSE("scattering neighbour significance: " << scatteringNeighbourSignificance);
803 
804  if (std::abs(momentumBalanceSignificance) > 3. || std::abs(scatteringCurvatureSignificance) > 3. ||
805  std::abs(scatteringNeighbourSignificance) > 3.) {
806  ATH_MSG_VERBOSE("Muon failed cut-based low-pT selection");
807  return false;
808  }
809 
810  // passed low pt selection
811  ATH_MSG_VERBOSE("Muon passed cut-based low-pT selection");
812  return true;
813  }
814 
815  std::vector<const xAOD::MuonSegment*> MuonSelectionTool::getSegmentsSorted(const xAOD::Muon& mu) const {
816  std::vector<const xAOD::MuonSegment*> segments_sorted;
817  segments_sorted.reserve(mu.nMuonSegments());
818 
819  for (unsigned int i = 0; i < mu.nMuonSegments(); i++) {
820  if (!mu.muonSegment(i))
821  ATH_MSG_WARNING("The muon reports more segments than are available. Please report this to the muon software community!");
822  else
823  segments_sorted.push_back(mu.muonSegment(i));
824  }
825 
826  std::sort(segments_sorted.begin(), segments_sorted.end(), chamberIndexCompare);
827 
828  return segments_sorted;
829  }
830 
832  //LowPt Not supported in run3 for the time being
833  if(isRun3() && !m_developMode){
834  ATH_MSG_VERBOSE("LowPt WP currently not supported for run3 if not in expert mode");
835  return false;
836  }
837  if (!m_useMVALowPt) {
838  ATH_MSG_DEBUG("Low pt MVA disabled. Return... ");
839  return false;
840  }
841  std::lock_guard<std::mutex> guard(m_low_pt_mva_mutex);
842  // set values for all BDT input variables from the muon in question
843  float momentumBalanceSig{-1}, CurvatureSig{-1}, energyLoss{-1}, muonSegmentDeltaEta{-1}, scatteringNeigbour{-1};
847  retrieveParam(mu, energyLoss, xAOD::Muon::EnergyLoss);
848  retrieveParam(mu, muonSegmentDeltaEta, xAOD::Muon::segmentDeltaEta);
849 
853 
854  float seg1ChamberIdx{-1.}, seg2ChamberIdx{-1.}, middleHoles{-1.}, seg1NPrecisionHits{-1.}, seg1GlobalR{-1.}, seg1Chi2OverDoF{-1.};
855 
856  std::vector<const xAOD::MuonSegment*> muonSegments = getSegmentsSorted(mu);
857 
858  if (mu.author() == xAOD::Muon::MuTagIMO && muonSegments.size() == 0)
859  ATH_MSG_WARNING("passedLowPtEfficiencyMVACut - found segment-tagged muon with no segments!");
860 
861  using namespace Muon::MuonStationIndex;
862  seg1ChamberIdx = (!muonSegments.empty()) ? toInt(muonSegments[0]->chamberIndex()) : -9;
863  seg2ChamberIdx = (muonSegments.size() > 1) ? toInt(muonSegments[1]->chamberIndex()) : -9;
864 
865  // these variables are only used for MuTagIMO
866  if (mu.author() == xAOD::Muon::MuTagIMO) {
867  seg1NPrecisionHits = (!muonSegments.empty()) ? muonSegments[0]->nPrecisionHits() : -1;
868  seg1GlobalR = (!muonSegments.empty())
869  ? std::hypot(muonSegments[0]->x(), muonSegments[0]->y(), muonSegments[0]->z())
870  : 0;
871  seg1Chi2OverDoF = (!muonSegments.empty()) ? muonSegments[0]->chiSquared() / muonSegments[0]->numberDoF() : -1;
872  }
873 
874  middleHoles = middleSmallHoles + middleLargeHoles;
875 
876  // get event number from event info
878 
879  // variables for the BDT
880  std::vector<float> var_vector;
881  if (mu.author() == xAOD::Muon::MuidCo || mu.author() == xAOD::Muon::MuGirl) {
882  var_vector = {momentumBalanceSig, CurvatureSig, scatteringNeigbour, energyLoss,
883  middleHoles, muonSegmentDeltaEta, seg1ChamberIdx, seg2ChamberIdx};
884  } else {
885  if (std::abs(mu.eta()) >= 1.3)
886  var_vector = {seg2ChamberIdx, seg1ChamberIdx, seg1NPrecisionHits, muonSegmentDeltaEta,
887  seg1GlobalR, seg1Chi2OverDoF, std::abs(CurvatureSig)};
888  else
889  var_vector = {seg1ChamberIdx, seg1NPrecisionHits, muonSegmentDeltaEta,
890  seg1GlobalR, seg1Chi2OverDoF, std::abs(CurvatureSig)};
891  }
892 
893  // use different trainings for even/odd numbered events
894  TMVA::Reader *reader_MUID, *reader_MUGIRL;
895  if (eventInfo->eventNumber() % 2 == 1) {
896  reader_MUID = m_readerE_MUID.get();
897  reader_MUGIRL = m_readerE_MUGIRL.get();
898  } else {
899  reader_MUID = m_readerO_MUID.get();
900  reader_MUGIRL = m_readerO_MUGIRL.get();
901  }
902 
903  // BDT for MuTagIMO is binned in |eta|
904  TMVA::Reader* reader_MUTAGIMO;
905  if (std::abs(mu.eta()) < 0.7)
906  reader_MUTAGIMO = m_reader_MUTAGIMO_etaBin1.get();
907  else if (std::abs(mu.eta()) < 1.3)
908  reader_MUTAGIMO = m_reader_MUTAGIMO_etaBin2.get();
909  else
910  reader_MUTAGIMO = m_reader_MUTAGIMO_etaBin3.get();
911 
912  // get the BDT discriminant response
913  float BDTdiscriminant;
914 
915  if (mu.author() == xAOD::Muon::MuidCo)
916  BDTdiscriminant = reader_MUID->EvaluateMVA(var_vector, "BDTG");
917  else if (mu.author() == xAOD::Muon::MuGirl)
918  BDTdiscriminant = reader_MUGIRL->EvaluateMVA(var_vector, "BDTG");
919  else if (mu.author() == xAOD::Muon::MuTagIMO && m_useSegmentTaggedLowPt)
920  BDTdiscriminant = reader_MUTAGIMO->EvaluateMVA(var_vector, "BDT");
921  else {
922  ATH_MSG_WARNING("Invalid author for low-pT MVA, failing selection...");
923  return false;
924  }
925 
926  // cut on dicriminant
927  float BDTcut = (mu.author() == xAOD::Muon::MuTagIMO) ? 0.12 : -0.6;
928 
929  if (BDTdiscriminant > BDTcut) {
930  ATH_MSG_VERBOSE("Passed low-pT MVA cut");
931  return true;
932  } else {
933  ATH_MSG_VERBOSE("Failed low-pT MVA cut");
934  return false;
935  }
936  }
937 
939  ATH_MSG_VERBOSE("Checking whether muon passes high-pT selection...");
940 
941  // :: Request combined muons
942  if (mu.muonType() != xAOD::Muon::Combined) {
943  ATH_MSG_VERBOSE("Muon is not combined - fail high-pT");
944  return false;
945  }
946  if (mu.author() == xAOD::Muon::STACO) {
947  ATH_MSG_VERBOSE("Muon is STACO - fail high-pT");
948  return false;
949  }
950 
951  // :: Reject muons with out-of-bounds hits
955  ATH_MSG_VERBOSE("Muon has out-of-bounds precision hits - fail high-pT");
956  return false;
957  }
958 
959  // :: Access MS hits information
962 
963 
964  ATH_MSG_VERBOSE("number of precision layers: " << (int)summary.nprecisionLayers);
965 
966  //::: Apply MS Chamber Vetoes
967  // Given according to their eta-phi locations in the muon spectrometer
968  // FORM: CHAMBERNAME[ array of four values ] = { eta 1, eta 2, phi 1, phi 2}
969  // The vetoes are applied based on the MS track if available. If the MS track is not available,
970  // the vetoes are applied according to the combined track, and runtime warning is printed to
971  // the command line.
972  const xAOD::TrackParticle* CB_track = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
973  const xAOD::TrackParticle* MS_track = mu.trackParticle(xAOD::Muon::MuonSpectrometerTrackParticle);
974  if (!MS_track) {
975  ATH_MSG_VERBOSE("passedHighPtCuts - No MS track available for muon. Using combined track.");
976  MS_track = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
977  }
978 
979  if (MS_track && CB_track) {
980  float etaMS = MS_track->eta();
981  float phiMS = MS_track->phi();
982  float etaCB = CB_track->eta();
983 
984  //::: no unspoiled clusters in CSC
985  if (!isRun3() && (std::abs(etaMS) > 2.0 || std::abs(etaCB) > 2.0)) {
986  if (summary.cscUnspoiledEtaHits == 0) {
987  ATH_MSG_VERBOSE("Muon has only spoiled CSC clusters - fail high-pT");
988  return false;
989  }
990  }
991 
992  // veto bad CSC giving troubles with scale factors
993  if (!isRun3() && mu.eta() < -1.899 && std::abs(mu.phi()) < 0.211) {
994  ATH_MSG_VERBOSE("Muon is in eta/phi region vetoed due to disabled chambers in MC - fail high-pT");
995  return false;
996  }
997 
998  //::: Barrel/Endcap overlap region
999  if ((1.01 < std::abs(etaMS) && std::abs(etaMS) < 1.1) || (1.01 < std::abs(etaCB) && std::abs(etaCB) < 1.1)) {
1000  ATH_MSG_VERBOSE("Muon is in barrel/endcap overlap region - fail high-pT");
1001  return false;
1002  }
1003 
1004  //::: BIS78
1005  if (isBIS78(etaMS, phiMS)) {
1006  if (!isRun3() || !m_useBEEBISInHighPtRun3) {
1007  ATH_MSG_VERBOSE("Muon is in BIS7/8 eta/phi region - fail high-pT");
1008  return false;
1009  }
1010  }
1011 
1014  //if (getRunNumber(true) >= 324320) {
1015  //if (isBMG(etaMS, phiMS)) {
1016  //ATH_MSG_VERBOSE("Muon is in BMG eta/phi region - fail high-pT");
1017  //return false;
1018  //}
1019  //}
1020 
1021  //::: BEE
1022  if (isBEE(etaMS, phiMS)) {
1023  // in Run3, large mis-alignment on the BEE chamber was found. temporarily mask the BEE region
1024  if (isRun3() && !m_useBEEBISInHighPtRun3) {
1025  ATH_MSG_VERBOSE("Muon is in BEE eta/phi region - fail high-pT");
1026  return false;
1027  }
1028  // Muon falls in the BEE eta-phi region: asking for 4 good precision layers
1029  // if( nGoodPrecLayers < 4 ) return false; // postponed (further studies needed)
1030  if (summary.nprecisionLayers < 4) {
1031  ATH_MSG_VERBOSE("Muon is in BEE eta/phi region and does not have 4 precision layers - fail high-pT");
1032  return false;
1033  }
1034  }
1035  if (std::abs(etaCB) > 1.4) {
1036  // Veto residual 3-station muons in BEE region due to MS eta/phi resolution effects
1037  // if( nGoodPrecLayers<4 && (extendedSmallHits>0||extendedSmallHoles>0) ) return false; // postponed (further studies
1038  // needed)
1039  if (summary.nprecisionLayers < 4 && (summary.extendedSmallHits > 0 || summary.extendedSmallHoles > 0)) {
1040  ATH_MSG_VERBOSE("Muon is in BEE eta/phi region and does not have 4 precision layers - fail high-pT");
1041  return false;
1042  }
1043  }
1044  } else {
1045  ATH_MSG_WARNING("passedHighPtCuts - MS or CB track missing in muon! Failing High-pT selection...");
1046  return false;
1047  }
1048 
1049  //::: Apply 1/p significance cut
1050  const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
1051  const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
1052  if (idtrack && metrack && metrack->definingParametersCovMatrix()(4, 4) > 0) { const float qOverPsignif = qOverPsignificance(mu);
1053 
1054  ATH_MSG_VERBOSE("qOverP significance: " << qOverPsignif);
1055 
1056  if (std::abs(qOverPsignif) > 7) {
1057  ATH_MSG_VERBOSE("Muon failed qOverP significance cut");
1058  return false;
1059  }
1060  } else {
1061  ATH_MSG_VERBOSE("Muon missing ID or ME tracks - fail high-pT");
1062  return false;
1063  }
1064 
1065  // Accept good 2-station muons if the user has opted to include these
1066  if (m_use2stationMuonsHighPt && summary.nprecisionLayers == 2) {
1067  // should not accept EM+EO muons due to ID/MS alignment issues
1068  if (std::abs(mu.eta()) > 1.2 && summary.extendedSmallHits < 3 && summary.extendedLargeHits < 3) {
1069  ATH_MSG_VERBOSE("2-station muon with EM+EO - fail high-pT");
1070  return false;
1071  }
1072 
1073  // only select muons missing the inner precision layer
1074  // apply strict veto on overlap between small and large sectors
1075 
1076  if (summary.innerLargeHits == 0 && summary.middleLargeHits == 0 && summary.outerLargeHits == 0 &&
1077  summary.extendedLargeHits == 0 && summary.middleSmallHits > 2 &&
1078  (summary.outerSmallHits > 2 || summary.extendedSmallHits > 2)) {
1079  ATH_MSG_VERBOSE("Accepted 2-station muon in small sector");
1080  return true;
1081  }
1082 
1083  if (summary.innerSmallHits == 0 && summary.middleSmallHits == 0 && summary.outerSmallHits == 0 &&
1084  summary.extendedSmallHits == 0 && summary.middleLargeHits > 2 &&
1085  (summary.outerLargeHits > 2 || summary.extendedLargeHits > 2)) {
1086  ATH_MSG_VERBOSE("Accepted 2-station muon in large sector");
1087  return true;
1088  }
1089  }
1090 
1091  //::: Require 3 (good) station muons
1092  if (summary.nprecisionLayers < 3) {
1093  ATH_MSG_VERBOSE("Muon has less than 3 precision layers - fail high-pT");
1094  return false;
1095  }
1096 
1097  // Remove 3-station muons with small-large sectors overlap
1098  if (summary.isSmallGoodSectors) {
1099  if (!(summary.innerSmallHits > 2 && summary.middleSmallHits > 2 &&
1100  (summary.outerSmallHits > 2 || summary.extendedSmallHits > 2))) {
1101  ATH_MSG_VERBOSE("Muon has small/large sectors overlap - fail high-pT");
1102  return false;
1103  }
1104  } else {
1105  if (!(summary.innerLargeHits > 2 && summary.middleLargeHits > 2 &&
1106  (summary.outerLargeHits > 2 || summary.extendedLargeHits > 2))) {
1107  ATH_MSG_VERBOSE("Muon has small/large sectors overlap - fail high-pT");
1108  return false;
1109  }
1110  }
1111 
1112  ATH_MSG_VERBOSE("Muon passed high-pT selection");
1113  return true;
1114  }
1115 
1117  // ::
1118  if (mu.muonType() != xAOD::Muon::Combined) return false;
1119  // ::
1120  double start_cut = 3.0;
1121  double end_cut = 1.6;
1122  double abs_eta = std::abs(mu.eta());
1123 
1124  // parametrization of expected q/p error as function of pT
1125  double p0(8.0), p1(0.), p2(0.);
1126  if(isRun3()) //MC21 optimization
1127  {
1128  if(abs_eta<=1.05){
1129  p1=0.046;
1130  p2=0.00005;
1131  }
1132  else if (abs_eta > 1.05 && abs_eta <= 1.3) {
1133  p1 = 0.052;
1134  p2 = 0.00008;
1135  } else if (abs_eta > 1.3 && abs_eta <= 1.7) {
1136  p1 = 0.068;
1137  p2 = 0.00006;
1138  } else if (abs_eta > 1.7 && abs_eta <= 2.0) {
1139  p1 = 0.048;
1140  p2 = 0.00006;
1141  } else if (abs_eta > 2.0) {
1142  p1 = 0.037;
1143  p2 = 0.00006;
1144  }
1145  }
1146  else
1147  {
1148  if(abs_eta<=1.05){
1149  p1=0.039;
1150  p2=0.00006;
1151  }
1152  else if (abs_eta > 1.05 && abs_eta <= 1.3) {
1153  p1 = 0.040;
1154  p2 = 0.00009;
1155  } else if (abs_eta > 1.3 && abs_eta <= 1.7) {
1156  p1 = 0.056;
1157  p2 = 0.00008;
1158  } else if (abs_eta > 1.7 && abs_eta <= 2.0) {
1159  p1 = 0.041;
1160  p2 = 0.00006;
1161  } else if (abs_eta > 2.0) {
1162  p1 = 0.031;
1163  p2 = 0.00006;
1164  }
1165  }
1166  // ::
1167  hitSummary summary{};
1169 
1170  // independent parametrization for 2-station muons
1171  if (m_use2stationMuonsHighPt && summary.nprecisionLayers == 2) {
1172  start_cut = 1.1;
1173  end_cut=0.7;
1174  p1 = 0.0739568;
1175  p2 = 0.00012443;
1176  if (abs_eta > 1.05 && abs_eta < 1.3) {
1177  p1 = 0.0674484;
1178  p2 = 0.000119879;
1179  } else if (abs_eta >= 1.3 && abs_eta < 1.7) {
1180  p1 = 0.041669;
1181  p2 = 0.000178349;
1182  } else if (abs_eta >= 1.7 && abs_eta < 2.0) {
1183  p1 = 0.0488664;
1184  p2 = 0.000137648;
1185  } else if (abs_eta >= 2.0) {
1186  p1 = 0.028077;
1187  p2 = 0.000152707;
1188  }
1189  }
1190  // ::
1191  bool passErrorCutCB = false;
1192  const xAOD::TrackParticle* cbtrack = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
1193  if (cbtrack) {
1194  // ::
1195  double pt_CB = (cbtrack->pt() * MeVtoGeV < 5000.) ? cbtrack->pt() * MeVtoGeV : 5000.; // GeV
1196  double qOverP_CB = cbtrack->qOverP();
1197  double qOverPerr_CB = std::sqrt(cbtrack->definingParametersCovMatrix()(4, 4));
1198  // sigma represents the average expected error at the muon's pt/eta
1199  double sigma = std::sqrt(std::pow(p0 / pt_CB, 2) + std::pow(p1, 2) + std::pow(p2 * pt_CB, 2));
1200  // cutting at start_cut*sigma for pt <=1 TeV depending on eta region,
1201  // then linearly tightening until end_cut*sigma is reached at pt >= 5TeV.
1202  double a = (end_cut - start_cut) / 4000.0;
1203  double b = end_cut - a * 5000.0;
1204  double coefficient = (pt_CB > 1000.) ? (a * pt_CB + b) : start_cut;
1205  if (std::abs(qOverPerr_CB / qOverP_CB) < coefficient * sigma) { passErrorCutCB = true; }
1206  }
1207  // ::
1208  if (m_use2stationMuonsHighPt && m_doBadMuonVetoMimic && summary.nprecisionLayers == 2) {
1210 
1211  if (eventInfo->eventType(xAOD::EventInfo::IS_SIMULATION)) {
1212  ATH_MSG_DEBUG("The current event is a MC event. Use bad muon veto mimic.");
1213  return passErrorCutCB && passedBMVmimicCut(mu);
1214  }
1215  }
1216 
1217  // ::
1218  return passErrorCutCB;
1219  }
1220 
1222  TF1* cutFunction;
1223  double p1, p2;
1224  if (std::abs(mu.eta()) < 1.05) {
1225  cutFunction = m_BMVcutFunction_barrel.get();
1226  p1 = 0.066265;
1227  p2 = 0.000210047;
1228  } else {
1229  cutFunction = m_BMVcutFunction_endcap.get();
1230  p1 = 0.0629747;
1231  p2 = 0.000196466;
1232  }
1233 
1234  double qOpRelResolution = std::hypot(p1, p2 * mu.primaryTrackParticle()->pt() * MeVtoGeV);
1235 
1236  double qOverPabs_unsmeared = std::abs(mu.primaryTrackParticle()->definingParameters()[4]);
1237  double qOverPabs_smeared = 1.0 / (mu.pt() * std::cosh(mu.eta()));
1238 
1239  if ((qOverPabs_smeared - qOverPabs_unsmeared) / (qOpRelResolution * qOverPabs_unsmeared) <
1240  cutFunction->Eval(mu.primaryTrackParticle()->pt() * MeVtoGeV))
1241  return false;
1242  else
1243  return true;
1244  }
1245 
1247  // ::
1248  if (mu.muonType() == xAOD::Muon::Combined) { return mu.author() != xAOD::Muon::STACO; }
1249  // ::
1250  if (mu.muonType() == xAOD::Muon::CaloTagged && std::abs(mu.eta()) < 0.105)
1251  return passedCaloTagQuality(mu);
1252  // ::
1253  if (mu.muonType() == xAOD::Muon::SegmentTagged && (std::abs(mu.eta()) < 0.105 || m_useSegmentTaggedLowPt)) return true;
1254  // ::
1255  if (mu.author() == xAOD::Muon::MuidSA && std::abs(mu.eta()) > 2.4) return true;
1256  // ::
1257  if (mu.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
1258  const xAOD::TrackParticle* cbtrack = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
1259  return (cbtrack && std::abs(cbtrack->eta()) > 2.4);
1260  }
1261  // ::
1262  return false;
1263  }
1264 
1266  uint8_t value1{0}, value2{0};
1267 
1270  " !! Tool configured with some of the ID hits requirements changed... FOR DEVELOPMENT ONLY: muon efficiency SF won't be "
1271  "valid !! ");
1272 
1275  if ((value1 + value2 == 0) && !m_PixCutOff) return false;
1276 
1279  if ((value1 + value2 <= 4) && !m_SctCutOff) return false;
1280 
1283  if ((value1 + value2 >= 3) && !m_SiHolesCutOff) return false;
1284 
1285  if (!m_TrtCutOff) {
1286  const float abseta = std::abs(track.eta());
1289  const uint8_t totTRThits = value1 + value2;
1290  if (!((0.1 < abseta && abseta <= 1.9 && totTRThits > 5 && value2 < (0.9 * totTRThits)) || (abseta <= 0.1 || abseta > 1.9)))
1291  return false;
1292  }
1293  // Reached end - all ID hit cuts are passed.
1294  return true;
1295  } // passedIDCuts
1296 
1298  // Use CaloScore variable based on Neural Network if enabled
1299  // The neural network is only trained until eta = 1
1300  // cf. https://cds.cern.ch/record/2802605/files/CERN-THESIS-2021-290.pdf
1301  constexpr float eta_range = 1.;
1302  if (std::abs(mu.eta()) < eta_range && m_useCaloScore) return passedCaloScore(mu);
1303 
1304  // Otherwise we use CaloMuonIDTag
1305  int CaloMuonIDTag = -20;
1306 
1307  // Extract CaloMuonIDTag variable
1308  bool readID = mu.parameter(CaloMuonIDTag, xAOD::Muon::CaloMuonIDTag);
1309  if (!readID) {
1310  ATH_MSG_WARNING("Unable to read CaloMuonIDTag Quality information! Rejecting the CALO muon!");
1311  return false;
1312  }
1313 
1314  // Cut on CaloMuonIDTag variable
1315  return (CaloMuonIDTag > 10);
1316  }
1317 
1319  // We use a working point with a pT-dependent cut on the NN discriminant, designed to achieve a constant
1320  // fakes rejection as function of pT in Z->mumu MC
1321 
1322  // Extract the relevant score variable (NN discriminant)
1323 
1324  float CaloMuonScore{-999.0};
1325  retrieveParam(mu, CaloMuonScore, xAOD::Muon::CaloMuonScore);
1326 
1327  if(m_caloScoreWP==1) return (CaloMuonScore >= 0.92);
1328  if(m_caloScoreWP==2) return (CaloMuonScore >= 0.56);
1329  else if(m_caloScoreWP==3 || m_caloScoreWP==4)
1330  {
1331  // Cut on the score variable
1332  float pT = mu.pt() * MeVtoGeV; // GeV
1333 
1334  if (pT > 20.0) // constant cut above 20 GeV
1335  return (CaloMuonScore >= 0.77);
1336  else {
1337  // pT-dependent cut below 20 GeV
1338  // The pT-dependent cut is based on a fit of a third-degree polynomial, with coefficients as given below
1339 
1340  if(m_caloScoreWP==3) return (CaloMuonScore >= (-1.98e-4 * std::pow(pT, 3) +6.04e-3 * std::pow(pT, 2) -6.13e-2 * pT + 1.16));
1341  if(m_caloScoreWP==4) return (CaloMuonScore >= (-1.80e-4 * std::pow(pT, 3) +5.02e-3 * std::pow(pT, 2) -4.62e-2 * pT + 1.12));
1342  }
1343  }
1344 
1345  return false;
1346  }
1347 
1348  bool MuonSelectionTool::passTight(const xAOD::Muon& mu, float rho, float oneOverPSig) const {
1349 
1351  ATH_MSG_VERBOSE("for run3, Tight WP is only supported when ExcludeNSWFromPrecisionLayers=False and RecalcPrecisionLayerswNSW=True");
1352  return false;
1353  }
1354  float symmetric_eta = std::abs(mu.eta());
1355  float pt = mu.pt() * MeVtoGeV; // GeV
1356 
1357  // Impose pT and eta cuts; the bounds of the cut maps
1358  if (pt < 4.0 || symmetric_eta >= 2.5) return false;
1359  ATH_MSG_VERBOSE("Muon is passing tight WP kinematic cuts with pT,eta " << mu.pt() << " , " << mu.eta());
1360 
1361  // ** Low pT specific cuts ** //
1362  if (pt < 20.0) {
1363  double rhoCut = m_tightWP_lowPt_rhoCuts->Interpolate(pt, symmetric_eta);
1364  double qOverPCut = m_tightWP_lowPt_qOverPCuts->Interpolate(pt, symmetric_eta);
1365 
1366  ATH_MSG_VERBOSE("Applying tight WP cuts to a low pt muon with (pt,eta) ( " << pt << " , " << mu.eta() << " ) ");
1367  ATH_MSG_VERBOSE("Rho value " << rho << ", required to be less than " << rhoCut);
1368  ATH_MSG_VERBOSE("Momentum significance value " << oneOverPSig << ", required to be less than " << qOverPCut);
1369 
1370  if (rho > rhoCut) return false;
1371  ATH_MSG_VERBOSE("Muon passed tight WP, low pT rho cut!");
1372 
1373  if (oneOverPSig > qOverPCut) return false;
1374  ATH_MSG_VERBOSE("Muon passed tight WP, low pT momentum significance cut");
1375 
1376  // Tight muon!
1377  return true;
1378 
1379  }
1380 
1381  // ** Medium pT specific cuts ** //
1382  else if (pt < 100.0) {
1383  double rhoCut = m_tightWP_mediumPt_rhoCuts->Interpolate(pt, symmetric_eta);
1384  //
1385  ATH_MSG_VERBOSE("Applying tight WP cuts to a medium pt muon with (pt,eta) (" << pt << "," << mu.eta() << ")");
1386  ATH_MSG_VERBOSE("Rho value " << rho << " required to be less than " << rhoCut);
1387 
1388  // Apply cut
1389  if (rho > rhoCut) return false;
1390  ATH_MSG_VERBOSE("Muon passed tight WP, medium pT rho cut!");
1391 
1392  // Tight muon!
1393  return true;
1394  }
1395 
1396  // ** High pT specific cuts
1397  else if (pt < 500.0) {
1398  //
1399  ATH_MSG_VERBOSE("Applying tight WP cuts to a high pt muon with (pt,eta) (" << pt << "," << mu.eta() << ")");
1400  // No interpolation, since bins with -1 mean we should cut really loose
1401  double rhoCut = m_tightWP_highPt_rhoCuts->GetBinContent(m_tightWP_highPt_rhoCuts->FindFixBin(pt, symmetric_eta));
1402  ATH_MSG_VERBOSE("Rho value " << rho << ", required to be less than " << rhoCut << " unless -1, in which no cut is applied");
1403  //
1404  if (rhoCut < 0.0) return true;
1405  if (rho > rhoCut) return false;
1406  ATH_MSG_VERBOSE("Muon passed tight WP, high pT rho cut!");
1407 
1408  return true;
1409  }
1410  // For muons with pT > 500 GeV, no extra cuts
1411  else {
1412  ATH_MSG_VERBOSE("Not applying any tight WP cuts to a very high pt muon with (pt,eta) (" << pt << "," << mu.eta() << ")");
1413  return true;
1414  }
1415 
1416  // you should never reach this point
1417  return false;
1418  }
1419 
1420  //============================================================================
1422 
1423  checkSanity();
1424 
1438 
1439  if (!isRun3()) {
1440  // ignore missing of cscUnspoiledEtaHits in case we are running in expert developer mode
1441  // e.g. for when we want to apply Run2 WPs in Run3
1443 
1444  if (std::abs(muon.eta()) > 2.0) {
1445  ATH_MSG_VERBOSE("Recalculating number of precision layers for combined muon");
1446  summary.nprecisionLayers = (summary.innerSmallHits > 1 || summary.innerLargeHits > 1)
1447  + (summary.middleSmallHits > 2 || summary.middleLargeHits > 2)
1448  + (summary.outerSmallHits > 2 || summary.outerLargeHits > 2);
1449  }
1450 
1451  } else if (std::abs(muon.eta()) > 1.3 && (m_excludeNSWFromPrecisionLayers || m_recalcPrecisionLayerswNSW)) {
1452  summary.nprecisionLayers = (summary.middleSmallHits > 2 || summary.middleLargeHits > 2)
1453  + (summary.outerSmallHits > 2 || summary.outerLargeHits > 2)
1454  + (summary.extendedSmallHits > 2 || summary.extendedLargeHits > 2);
1455 
1457 
1458  if (!eta1stgchits_acc.isAvailable(muon) || !eta2stgchits_acc.isAvailable(muon) || !mmhits_acc.isAvailable(muon)) {
1459  ATH_MSG_FATAL(__FILE__ << ":" << __LINE__ << " Failed to retrieve NSW hits!"
1460  << " (Please use DxAODs with p-tags >= p5834 OR set ExcludeNSWFromPrecisionLayers to True (tests only)");
1461  throw std::runtime_error("Failed to retrieve NSW hits");
1462  }
1463 
1467  summary.nprecisionLayers += ((summary.etaLayer1STGCHits + summary.etaLayer2STGCHits) > 3 || summary.MMHits > 3);
1468  }
1469  }
1470  }
1471 
1472 
1474  if (!muon.parameter(value, param)) {
1475  ATH_MSG_FATAL(__FILE__ << ":" << __LINE__ << " Failed to retrieve parameter " << param
1476  << " for muon with pT:" << muon.pt() * MeVtoGeV << ", eta:" << muon.eta() << ", phi: " << muon.phi()
1477  << ", q:" << muon.charge() << ", author: " << muon.author());
1478  throw std::runtime_error("Failed to retrieve Parameter");
1479  }
1480  }
1481 
1482  // Returns an integer corresponding to categorization of muons with different resolutions
1484  // Resolutions have only been evaluated for medium combined muons
1486 
1487  // :: Access MS hits information
1488  hitSummary summary{};
1490 
1491  // For muons passing the high-pT working point, distinguish between 2-station tracks and the rest
1492  if (passedHighPtCuts(mu)) {
1493  if (summary.nprecisionLayers == 2)
1494  return ResolutionCategory::highPt2station;
1495  else
1497  }
1498 
1499  const xAOD::TrackParticle* CB_track = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
1500  const xAOD::TrackParticle* MS_track = mu.trackParticle(xAOD::Muon::MuonSpectrometerTrackParticle);
1501  if (!MS_track) {
1502  ATH_MSG_VERBOSE("getResolutionCategory - No MS track available for muon. Using combined track.");
1503  MS_track = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
1504  }
1505 
1506  if (!MS_track || !CB_track) return ResolutionCategory::unclassified;
1507  const float etaMS = MS_track->eta();
1508  const float etaCB = CB_track->eta();
1509  const float phiMS = MS_track->phi();
1510 
1512 
1513  if ((summary.isSmallGoodSectors && summary.innerSmallHits < 3) || (!summary.isSmallGoodSectors && summary.innerLargeHits < 3))
1514  category = ResolutionCategory::missingInner; // missing-inner
1515 
1516  if ((summary.isSmallGoodSectors && summary.middleSmallHits < 3) || (!summary.isSmallGoodSectors && summary.middleLargeHits < 3))
1517  category = ResolutionCategory::missingMiddle; // missing-middle
1518 
1519  if ((summary.isSmallGoodSectors && summary.outerSmallHits < 3 && summary.extendedSmallHits < 3) ||
1520  (!summary.isSmallGoodSectors && summary.outerLargeHits < 3 && summary.extendedLargeHits < 3))
1521  category = ResolutionCategory::missingOuter; // missing-outer
1522 
1523  if (!isRun3() && (std::abs(etaMS) > 2.0 || std::abs(etaCB) > 2.0) && summary.cscUnspoiledEtaHits == 0)
1524  category = ResolutionCategory::spoiledCSC; // spoiled CSC
1525 
1526  if ((1.01 < std::abs(etaMS) && std::abs(etaMS) < 1.1) || (1.01 < std::abs(etaCB) && std::abs(etaCB) < 1.1))
1527  category = ResolutionCategory::BEoverlap; // barrel-end-cap overlap
1528 
1529  if (isBIS78(etaMS, phiMS)) category = ResolutionCategory::BIS78; // BIS7/8
1530 
1531  //::: BEE
1532  if (isBEE(etaMS, phiMS) || (std::abs(etaCB) > 1.4 && (summary.extendedSmallHits > 0 || summary.extendedSmallHoles > 0))) {
1533  if (summary.extendedSmallHits < 3 && summary.middleSmallHits >= 3 && summary.outerSmallHits >= 3)
1534  category = ResolutionCategory::missingBEE; // missing-BEE
1535 
1536  if (summary.extendedSmallHits >= 3 && summary.outerSmallHits < 3) category = ResolutionCategory::missingOuter; // missing-outer
1537 
1538  if (!summary.isSmallGoodSectors)
1539  category = ResolutionCategory::unclassified; // ambiguity due to eta/phi differences between MS and CB track
1540  }
1541 
1542  if (summary.nprecisionLayers == 1) category = ResolutionCategory::oneStation; // one-station track
1543 
1544  return category;
1545  }
1546 
1547  //============================================================================
1548  // need run number (or random run number) to apply period-dependent selections
1549  unsigned int MuonSelectionTool::getRunNumber(bool needOnlyCorrectYear /*=false*/) const {
1550 
1551  static const SG::AuxElement::ConstAccessor<unsigned int> acc_rnd("RandomRunNumber");
1552 
1554 
1555  // Case of data
1556  if (!eventInfo->eventType(xAOD::EventInfo::IS_SIMULATION)) {
1557  ATH_MSG_DEBUG("The current event is a data event. Return runNumber.");
1558  return eventInfo->runNumber();
1559  }
1560 
1561  // Case of MC
1562  // attempt to get the run number assigned by the PRW tool
1563  static std::atomic<bool> issuedWarningPRW{false};
1564  if (acc_rnd.isAvailable(*eventInfo)) {
1565  unsigned int rn = acc_rnd(*eventInfo);
1566  if (rn != 0) return acc_rnd(*eventInfo);
1567 
1568  if (!issuedWarningPRW) {
1569  ATH_MSG_WARNING("Pile up tool has assigned runNumber = 0");
1570  issuedWarningPRW = true;
1571  }
1572  }
1573 
1574  // otherwise return a dummy run number
1575  if (needOnlyCorrectYear) {
1576  if (eventInfo->runNumber() < 300000) { // mc16a (2016): 284500
1577  ATH_MSG_DEBUG("Random run number not available and this is mc16a or mc20a, returning dummy 2016 run number.");
1578  return 311071;
1579 
1580  } else if (eventInfo->runNumber() < 310000) { // mc16d (2017): 300000
1581  ATH_MSG_DEBUG("Random run number not available and this is mc16d or mc20d, returning dummy 2017 run number.");
1582  return 340072;
1583 
1584  } else if (eventInfo->runNumber() < 320000) { // mc16e (2018): 310000
1585  ATH_MSG_DEBUG("Random run number not available and this is mc16e or mc20e, returning dummy 2018 run number.");
1586  return 351359;
1587 
1588  } else if (eventInfo->runNumber() < 600000) { //mc21: 330000, mc23a: 410000, mc23c: 450000
1589  ATH_MSG_DEBUG("Random run number not available and this is mc21/mc23, for the time being we're returing a dummy run number.");
1590  return 399999;
1591  } else {
1592  ATH_MSG_DEBUG("Detected some run 4 / phase II runnumber "<<eventInfo->runNumber()<<". ");
1593  return 666666;
1594  }
1595 
1596  ATH_MSG_FATAL("Random run number not available, fallback option of using runNumber failed since "<<eventInfo->runNumber()<<" cannot be recognised");
1597  throw std::runtime_error("MuonSelectionTool() - need RandomRunNumber decoration by the PileupReweightingTool");
1598  }
1599 
1600  ATH_MSG_FATAL("Failed to find the RandomRunNumber decoration by the PileupReweightingTool");
1601  throw std::runtime_error("MuonSelectionTool() - need RandomRunNumber decoration from PileupReweightingTool");
1602  }
1603 
1604 
1605  // Check if eta/phi coordinates correspond to BIS7/8 chambers
1606  bool MuonSelectionTool::isBIS78(const float eta, const float phi) const {
1607  static constexpr std::array<float, 2> BIS78_eta{1.05, 1.3};
1608  static constexpr std::array<float, 8> BIS78_phi{0.21, 0.57, 1.00, 1.33, 1.78, 2.14, 2.57, 2.93};
1609 
1610  float abs_eta = std::abs(eta);
1611  float abs_phi = std::abs(phi);
1612 
1613  if (abs_eta >= BIS78_eta[0] && abs_eta <= BIS78_eta[1]) {
1614  if ((abs_phi >= BIS78_phi[0] && abs_phi <= BIS78_phi[1]) || (abs_phi >= BIS78_phi[2] && abs_phi <= BIS78_phi[3]) ||
1615  (abs_phi >= BIS78_phi[4] && abs_phi <= BIS78_phi[5]) || (abs_phi >= BIS78_phi[6] && abs_phi <= BIS78_phi[7])) {
1616  return true;
1617  }
1618  }
1619 
1620  return false;
1621  }
1622 
1623  // Check if eta/phi coordinates correspond to BEE chambers
1624  bool MuonSelectionTool::isBEE(const float eta, const float phi) const {
1625  static constexpr std::array<float, 2> BEE_eta{1.440, 1.692};
1626  static constexpr std::array<float, 8> BEE_phi{0.301, 0.478, 1.086, 1.263, 1.872, 2.049, 2.657, 2.834};
1627 
1628  float abs_eta = std::abs(eta);
1629  float abs_phi = std::abs(phi);
1630 
1631  if (abs_eta >= BEE_eta[0] && abs_eta <= BEE_eta[1]) {
1632  if ((abs_phi >= BEE_phi[0] && abs_phi <= BEE_phi[1]) || (abs_phi >= BEE_phi[2] && abs_phi <= BEE_phi[3]) ||
1633  (abs_phi >= BEE_phi[4] && abs_phi <= BEE_phi[5]) || (abs_phi >= BEE_phi[6] && abs_phi <= BEE_phi[7])) {
1634  return true;
1635  }
1636  }
1637 
1638  return false;
1639  }
1640 
1641  // Check if eta/phi coordinates correspond to BMG chambers
1642  bool MuonSelectionTool::isBMG(const float eta, const float phi) const {
1643  static constexpr std::array<float, 6> BMG_eta{0.35, 0.47, 0.68, 0.80, 0.925, 1.04};
1644  static constexpr std::array<float, 4> BMG_phi{-1.93, -1.765, -1.38, -1.21};
1645 
1646  float abs_eta = std::abs(eta);
1647 
1648  if ((abs_eta >= BMG_eta[0] && abs_eta <= BMG_eta[1]) || (abs_eta >= BMG_eta[2] && abs_eta <= BMG_eta[3]) ||
1649  (abs_eta >= BMG_eta[4] && abs_eta <= BMG_eta[5])) {
1650  if ((phi >= BMG_phi[0] && phi <= BMG_phi[1]) || (phi >= BMG_phi[2] && phi <= BMG_phi[3])) { return true; }
1651  }
1652 
1653  return false;
1654  }
1655 
1658  {
1659  ATH_MSG_ERROR("TightNNScore calculation is disabled. Please set the property CalculateTightNNScore to true.");
1660  throw std::runtime_error("cannot calculate TightNNScore");
1661  }
1662  //this score currently only can be calculated for combined muons
1663  if (mu.muonType() != xAOD::Muon::Combined) return -999;
1664  const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
1665  const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
1666  if(!idtrack || !metrack) return -999;
1667  //the score is only calculated for muons which pass the Medium WP
1668  if (getQuality(mu) > xAOD::Muon::Medium) return -999;
1669  //only muons with pt > 4 GeV and |eta|<2.5 are considered
1670  if (std::abs(mu.eta())>2.5) return -999;
1671  if(mu.pt()<4000.) return -999;
1672 
1673  std::vector<float> input_features;
1674  // 1. Fill input features
1675  int mu_author=mu.author();
1676  float mu_rhoPrime=rhoPrime(mu);
1677  float mu_scatteringCurvatureSignificance=0.;
1678  retrieveParam(mu, mu_scatteringCurvatureSignificance, xAOD::Muon::scatteringCurvatureSignificance);
1679  float mu_scatteringNeighbourSignificance=0.;
1680  retrieveParam(mu, mu_scatteringNeighbourSignificance, xAOD::Muon::scatteringNeighbourSignificance);
1681  float mu_momentumBalanceSignificance=0.;
1682  retrieveParam(mu, mu_momentumBalanceSignificance, xAOD::Muon::momentumBalanceSignificance);
1683  float mu_qOverPSignificance=qOverPsignificance(mu);
1684  float mu_reducedChi2=mu.primaryTrackParticle()->chiSquared() / mu.primaryTrackParticle()->numberDoF();
1685  float mu_reducedChi2_ID=idtrack->chiSquared() / idtrack->numberDoF();
1686  float mu_reducedChi2_ME=metrack->chiSquared() / metrack->numberDoF();
1687  float mu_spectrometerFieldIntegral=0.;
1688  retrieveParam(mu, mu_spectrometerFieldIntegral, xAOD::Muon::spectrometerFieldIntegral);
1689  float mu_segmentDeltaEta=0;
1690  retrieveParam(mu, mu_segmentDeltaEta, xAOD::Muon::segmentDeltaEta);
1691  uint8_t mu_numberOfPixelHits=0;
1693  uint8_t mu_numberOfPixelDeadSensors=0;
1695  uint8_t mu_innerLargeHits=0;
1697  uint8_t mu_innerSmallHits=0;
1699  uint8_t mu_middleLargeHits=0;
1701  uint8_t mu_middleSmallHits=0;
1703  uint8_t mu_outerLargeHits=0;
1705  uint8_t mu_outerSmallHits=0;
1707 
1708  if(!isRun3())
1709  {
1710  input_features = {(float)mu_author,
1711  mu_rhoPrime,
1712  mu_scatteringCurvatureSignificance,
1713  mu_scatteringNeighbourSignificance,
1714  mu_momentumBalanceSignificance,
1715  mu_qOverPSignificance,
1716  mu_reducedChi2,
1717  mu_reducedChi2_ID,
1718  mu_reducedChi2_ME,
1719  mu_spectrometerFieldIntegral,
1720  mu_segmentDeltaEta,
1721  (float)mu_numberOfPixelHits,
1722  (float)mu_numberOfPixelDeadSensors,
1723  (float)mu_innerLargeHits,
1724  (float)mu_innerSmallHits,
1725  (float)mu_middleLargeHits,
1726  (float)mu_middleSmallHits,
1727  (float)mu_outerLargeHits,
1728  (float)mu_outerSmallHits};
1729  }
1730  else
1731  {
1732  uint8_t mu_phiLayer1STGCHits=0;
1734  uint8_t mu_phiLayer2STGCHits=0;
1736  uint8_t mu_etaLayer1STGCHits=0;
1738  uint8_t mu_etaLayer2STGCHits=0;
1740  uint8_t mu_MMHits=0;
1742  input_features = {(float)mu_author,
1743  mu_rhoPrime,
1744  mu_scatteringCurvatureSignificance,
1745  mu_scatteringNeighbourSignificance,
1746  mu_momentumBalanceSignificance,
1747  mu_qOverPSignificance,
1748  mu_reducedChi2,
1749  mu_reducedChi2_ID,
1750  mu_reducedChi2_ME,
1751  mu_spectrometerFieldIntegral,
1752  mu_segmentDeltaEta,
1753  (float)mu_numberOfPixelHits,
1754  (float)mu_numberOfPixelDeadSensors,
1755  (float)mu_innerLargeHits,
1756  (float)mu_innerSmallHits,
1757  (float)mu_middleLargeHits,
1758  (float)mu_middleSmallHits,
1759  (float)mu_outerLargeHits,
1760  (float)mu_outerSmallHits,
1761  (float)mu_phiLayer1STGCHits,
1762  (float)mu_phiLayer2STGCHits,
1763  (float)mu_etaLayer1STGCHits,
1764  (float)mu_etaLayer2STGCHits,
1765  (float)mu_MMHits};
1766  }
1767 
1768  float score=-999.;
1769  std::vector<int64_t> inputShape = {1, static_cast<int64_t>(input_features.size())};
1770 
1771  AthInfer::InputDataMap inputData;
1772  inputData["flatten_input"] = std::make_pair(
1773  inputShape, std::move(input_features)
1774  );
1775 
1776  AthInfer::OutputDataMap outputData;
1777  outputData["TightNNScore"] = std::make_pair(
1778  std::vector<int64_t>{1, 1}, std::vector<float>{}
1779  );
1780 
1781  if (!m_onnxTool->inference(inputData, outputData).isSuccess()) {
1782  ATH_MSG_WARNING("ONNX inference failed!");
1783  return -999.;
1784  }
1785  const auto& variant = outputData["TightNNScore"].second;
1786  if (std::holds_alternative<std::vector<float>>(variant)) {
1787  const auto& vec = std::get<std::vector<float>>(variant);
1788  if (!vec.empty()) score = vec[0];
1789  else {
1790  ATH_MSG_WARNING("ONNX output vector is empty!");
1791  return -999.;
1792  }
1793  } else {
1794  ATH_MSG_WARNING("ONNX output is not a float vector!");
1795  return -999.;
1796  }
1797 
1798  ATH_MSG_DEBUG("TightNNScore for muon with pT " << mu.pt() << " GeV, eta " << mu.eta() << " is " << score);
1799 
1800  return score;
1801  }
1802 
1803 } // namespace CP
xAOD::TrackParticle_v1::pt
virtual double pt() const override final
The transverse momentum ( ) of the particle.
Definition: TrackParticle_v1.cxx:74
AllowedVariables::e
e
Definition: AsgElectronSelectorTool.cxx:37
xAOD::numberOfPixelHoles
@ numberOfPixelHoles
number of pixel layers on track with absence of hits [unit8_t].
Definition: TrackingPrimitives.h:262
LikeEnum::Loose
@ Loose
Definition: LikelihoodEnums.h:12
CXXUTILS_TRAPPING_FP
#define CXXUTILS_TRAPPING_FP
Definition: trapping_fp.h:24
xAOD::phiLayer2STGCHits
@ phiLayer2STGCHits
number of phi hits in the second STGC trigger layer (STGC2)
Definition: TrackingPrimitives.h:426
CalculateHighPtTerm.pT
pT
Definition: ICHEP2016/CalculateHighPtTerm.py:57
xAOD::muon
@ muon
Definition: TrackingPrimitives.h:196
CP::MuonSelectionTool::m_MVAreaderFile_MuTagIMO_etaBin2
Gaudi::Property< std::string > m_MVAreaderFile_MuTagIMO_etaBin2
Definition: MuonSelectionTool.h:224
CP::MuonSelectionTool::passTight
bool passTight(const xAOD::Muon &mu, float rho, float oneOverPSig) const
Returns true if the muon passed the tight working point cuts.
Definition: MuonSelectionTool.cxx:1348
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
CP::MuonSelectionTool::m_acceptInfo
asg::AcceptInfo m_acceptInfo
Store selection information.
Definition: MuonSelectionTool.h:176
pdg_comparison.sigma
sigma
Definition: pdg_comparison.py:324
xAOD::MuGirl
@ MuGirl
MuGirl.
Definition: TrackingPrimitives.h:142
LikeEnum::VeryLoose
@ VeryLoose
Definition: LikelihoodEnums.h:11
CP::MuonSelectionTool::m_use2stationMuonsHighPt
Gaudi::Property< bool > m_use2stationMuonsHighPt
Definition: MuonSelectionTool.h:197
xAOD::numberOfPrecisionHoleLayers
@ numberOfPrecisionHoleLayers
layers with holes AND no hits [unit8_t].
Definition: TrackingPrimitives.h:290
CP::MuonSelectionTool::m_quality
Gaudi::Property< int > m_quality
Definition: MuonSelectionTool.h:179
AddEmptyComponent.histName
string histName
Definition: AddEmptyComponent.py:64
CP::MuonSelectionTool::m_custom_dir
Gaudi::Property< std::string > m_custom_dir
Definition: MuonSelectionTool.h:233
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
xAOD::uint8_t
uint8_t
Definition: Muon_v1.cxx:558
xAOD::EventInfo_v1::eventNumber
uint64_t eventNumber() const
The current event's event number.
CP::MuonSelectionTool::passedCaloTagQuality
virtual bool passedCaloTagQuality(const xAOD::Muon &mu) const override
Returns true if the muon passed additional calo-tag quality cuts.
Definition: MuonSelectionTool.cxx:1297
CP::MuonSelectionTool::m_MVAreaderFile_MuTagIMO_etaBin3
Gaudi::Property< std::string > m_MVAreaderFile_MuTagIMO_etaBin3
Definition: MuonSelectionTool.h:226
xAOD::etaMS
setSAddress etaMS
Definition: L2StandAloneMuon_v1.cxx:117
CP::MuonSelectionTool::getQuality
virtual xAOD::Muon::Quality getQuality(const xAOD::Muon &mu) const override
Returns the quality of the muon. To set the value on the muon, instead call setQuality(xAOD::Muon&) c...
Definition: MuonSelectionTool.cxx:435
Muon::MuonStationIndex::ChIndex::EEL
@ EEL
SG::Accessor
Helper class to provide type-safe access to aux data.
Definition: Control/AthContainers/AthContainers/Accessor.h:68
CP::MuonSelectionTool::m_MVAreaderFile_EVEN_MuidCB
Gaudi::Property< std::string > m_MVAreaderFile_EVEN_MuidCB
Definition: MuonSelectionTool.h:208
Muon::MuonStationIndex
Definition: MuonStationIndex.h:13
Muon::MuonStationIndex::ChIndex::EML
@ EML
xAOD::TrackParticle_v1::charge
float charge() const
Returns the charge.
Definition: TrackParticle_v1.cxx:151
Muon::MuonStationIndex::ChIndex::EOS
@ EOS
CP::MuonSelectionTool::m_useAllAuthors
Gaudi::Property< bool > m_useAllAuthors
Definition: MuonSelectionTool.h:196
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:67
CP::MuonSelectionTool::m_reader_MUTAGIMO_etaBin3
std::unique_ptr< TMVA::Reader > m_reader_MUTAGIMO_etaBin3
Definition: MuonSelectionTool.h:264
CP::MuonSelectionTool::m_disablePtCuts
Gaudi::Property< bool > m_disablePtCuts
Definition: MuonSelectionTool.h:190
xAOD::TrackParticle_v1::eta
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
Definition: TrackParticle_v1.cxx:78
CP::MuonSelectionTool::m_readerE_MUID
std::unique_ptr< TMVA::Reader > m_readerE_MUID
Definition: MuonSelectionTool.h:257
CP::MuonSelectionTool::m_calculateTightNNScore
Gaudi::Property< bool > m_calculateTightNNScore
Definition: MuonSelectionTool.h:282
plotmaker.hist
hist
Definition: plotmaker.py:148
Muon::MuonStationIndex::ChIndex::BIL
@ BIL
xAOD::extendedSmallHoles
@ extendedSmallHoles
number of precision holes in the extended small layer
Definition: TrackingPrimitives.h:346
CP::MuonSelectionTool::passedIDCuts
virtual bool passedIDCuts(const xAOD::Muon &) const override
Returns true if the muon passes the standard MCP ID cuts.
Definition: MuonSelectionTool.cxx:614
CP::MuonSelectionTool::m_BMVcutFunction_barrel
std::unique_ptr< TF1 > m_BMVcutFunction_barrel
Definition: MuonSelectionTool.h:247
CP::MuonSelectionTool::isBEE
bool isBEE(const float eta, const float phi) const
Check if muon eta/phi falls in BEE chambers.
Definition: MuonSelectionTool.cxx:1624
TRTCalib_cfilter.p1
p1
Definition: TRTCalib_cfilter.py:130
CP::MuonSelectionTool::m_readerE_MUGIRL
std::unique_ptr< TMVA::Reader > m_readerE_MUGIRL
Definition: MuonSelectionTool.h:259
python.SystemOfUnits.second
float second
Definition: SystemOfUnits.py:135
MuonParameters::scatteringNeighbourSignificance
@ scatteringNeighbourSignificance
Definition: MuonParamDefs.h:135
asg
Definition: DataHandleTestTool.h:28
test_pyathena.pt
pt
Definition: test_pyathena.py:11
CP::MeVtoGeV
constexpr float MeVtoGeV
Definition: IsolationCloseByCorrectionTool.cxx:38
CP::MuonSelectionTool::m_turnOffMomCorr
Gaudi::Property< bool > m_turnOffMomCorr
Definition: MuonSelectionTool.h:189
xAOD::TrackParticle_v1::chiSquared
float chiSquared() const
Returns the of the overall track fit.
xAOD::MuonSegment_v1
Class describing a MuonSegment.
Definition: MuonSegment_v1.h:33
CP::MuonSelectionTool::m_tightWP_highPt_rhoCuts
std::unique_ptr< TH1 > m_tightWP_highPt_rhoCuts
Definition: MuonSelectionTool.h:245
CP::MuonSelectionTool::getHist
StatusCode getHist(TFile *file, const std::string &histName, std::unique_ptr< TH1 > &hist) const
Checks for each histogram.
Definition: MuonSelectionTool.cxx:248
egammaParameters::ParamDef
ParamDef
Definition: egammaParamDefs.h:99
athena.value
value
Definition: athena.py:124
xAOD::numberOfPixelHits
@ numberOfPixelHits
these are the pixel hits, including the b-layer [unit8_t].
Definition: TrackingPrimitives.h:260
CP::MuonSelectionTool::passedLowPtEfficiencyCuts
virtual bool passedLowPtEfficiencyCuts(const xAOD::Muon &) const override
Returns true if the muon passes the standard MCP low pt cuts.
Definition: MuonSelectionTool.cxx:695
CP::MuonSelectionTool::m_PixCutOff
Gaudi::Property< bool > m_PixCutOff
Definition: MuonSelectionTool.h:194
CP::MuonSelectionTool::setPassesIDCuts
virtual void setPassesIDCuts(xAOD::Muon &) const override
set the passes ID cuts variable of the muon
Definition: MuonSelectionTool.cxx:612
xAOD::numberOfTRTHits
@ numberOfTRTHits
number of TRT hits [unit8_t].
Definition: TrackingPrimitives.h:276
xAOD::middleLargeHoles
@ middleLargeHoles
number of precision holes in the middle large layer
Definition: TrackingPrimitives.h:343
CP::MuonSelectionTool::m_readerO_MUGIRL
std::unique_ptr< TMVA::Reader > m_readerO_MUGIRL
Definition: MuonSelectionTool.h:260
vec
std::vector< size_t > vec
Definition: CombinationsGeneratorTest.cxx:9
SG::ConstAccessor
Helper class to provide constant type-safe access to aux data.
Definition: ConstAccessor.h:55
CP::MuonSelectionTool::getTightNNScore
virtual float getTightNNScore(const xAOD::Muon &muon) const override
Returns the TightNNscore of the muon, an experimental ML-based score for the identification of muons ...
Definition: MuonSelectionTool.cxx:1656
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
Muon::MuonStationIndex::ChIndex::EIS
@ EIS
CP::MuonSelectionTool::retrieveParam
void retrieveParam(const xAOD::Muon &muon, float &value, const xAOD::Muon::ParamDef param) const
Definition: MuonSelectionTool.cxx:1473
CP::MuonSelectionTool::passedCaloScore
virtual bool passedCaloScore(const xAOD::Muon &mu) const override
Returns true if the muon passed the CaloScore calo-tag working point.
Definition: MuonSelectionTool.cxx:1318
xAOD::IParticle
Class providing the definition of the 4-vector interface.
Definition: Event/xAOD/xAODBase/xAODBase/IParticle.h:41
CP::MuonSelectionTool::m_isRun3
Gaudi::Property< bool > m_isRun3
Definition: MuonSelectionTool.h:181
xAOD::EventInfo_v1::IS_SIMULATION
@ IS_SIMULATION
true: simulation, false: data
Definition: EventInfo_v1.h:151
x
#define x
CP::MuonSelectionTool::m_MVAreaderFile_ODD_MuGirl
Gaudi::Property< std::string > m_MVAreaderFile_ODD_MuGirl
Definition: MuonSelectionTool.h:218
CP
Select isolated Photons, Electrons and Muons.
Definition: Control/xAODRootAccess/xAODRootAccess/TEvent.h:49
CP::MuonSelectionTool::m_toroidOff
Gaudi::Property< bool > m_toroidOff
Definition: MuonSelectionTool.h:180
xAOD::Muon_v1
Class describing a Muon.
Definition: Muon_v1.h:38
CP::MuonSelectionTool::passedHighPtCuts
virtual bool passedHighPtCuts(const xAOD::Muon &) const override
Returns true if the muon passes the standard MCP High Pt cuts.
Definition: MuonSelectionTool.cxx:938
xAOD::EventInfo_v1::runNumber
uint32_t runNumber() const
The current event's run number.
Muon::MuonStationIndex::ChIndex::CSL
@ CSL
xAOD::innerLargeHits
@ innerLargeHits
number of precision hits in the inner large layer
Definition: TrackingPrimitives.h:332
CP::MuonSelectionTool::m_BMVcutFile
Gaudi::Property< std::string > m_BMVcutFile
file for bad muon veto mimic cut functions
Definition: MuonSelectionTool.h:236
CP::MuonSelectionTool::m_useMVALowPt
Gaudi::Property< bool > m_useMVALowPt
Definition: MuonSelectionTool.h:198
CP::MuonSelectionTool::m_BMVcutFunction_endcap
std::unique_ptr< TF1 > m_BMVcutFunction_endcap
Definition: MuonSelectionTool.h:248
MuonParameters::MuTagIMO
@ MuTagIMO
Definition: MuonParamDefs.h:66
xAOD::cscUnspoiledEtaHits
@ cscUnspoiledEtaHits
number of unspoiled CSC eta clusters on track
Definition: TrackingPrimitives.h:451
CP::MuonSelectionTool::m_recalcPrecisionLayerswNSW
Gaudi::Property< bool > m_recalcPrecisionLayerswNSW
Definition: MuonSelectionTool.h:183
MuonParameters::momentumBalanceSignificance
@ momentumBalanceSignificance
Definition: MuonParamDefs.h:136
CP::MuonSelectionTool::m_developMode
Gaudi::Property< bool > m_developMode
Definition: MuonSelectionTool.h:191
CP::MuonSelectionTool::passedErrorCutCB
virtual bool passedErrorCutCB(const xAOD::Muon &) const override
Returns true if a CB muon passes a pt- and eta-dependent cut on the relative CB q/p error.
Definition: MuonSelectionTool.cxx:1116
xAOD::middleLargeHits
@ middleLargeHits
number of precision hits in the middle large layer
Definition: TrackingPrimitives.h:334
xAOD::phi
setEt phi
Definition: TrigEMCluster_v1.cxx:29
InDet::ExclusiveOrigin::Primary
@ Primary
Definition: InDetTrackTruthOriginDefs.h:163
MuonParameters::highPt
@ highPt
Definition: MuonParamDefs.h:51
Muon::MuonStationIndex::ChIndex::EIL
@ EIL
CP::MuonSelectionTool::setQuality
virtual void setQuality(xAOD::Muon &mu) const override
set the passes low pT cuts variable of the muon
Definition: MuonSelectionTool.cxx:377
CP::MuonSelectionTool::m_doBadMuonVetoMimic
Gaudi::Property< bool > m_doBadMuonVetoMimic
Definition: MuonSelectionTool.h:201
CP::MuonSelectionTool::m_eventInfo
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfo
Definition: MuonSelectionTool.h:205
uint
unsigned int uint
Definition: LArOFPhaseFill.cxx:20
TRTCalib_cfilter.p2
p2
Definition: TRTCalib_cfilter.py:131
CP::MuonSelectionTool::passedBMVmimicCut
bool passedBMVmimicCut(const xAOD::Muon &) const
Returns true if the muon passes a cut which mimics the effect of the combined error cut This is neces...
Definition: MuonSelectionTool.cxx:1221
CP::MuonSelectionTool::qOverPsignificance
float qOverPsignificance(const xAOD::Muon &muon) const
Returns q/p significance of the muon (see definition in https://cds.cern.ch/record/2665711 )
Definition: MuonSelectionTool.cxx:400
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
CP::MuonSelectionTool::passedMuonCuts
virtual bool passedMuonCuts(const xAOD::Muon &) const override
Returns true if the muon passes a standardized loose preselection.
Definition: MuonSelectionTool.cxx:1246
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
asg::AcceptInfo
Definition: AcceptInfo.h:28
CP::MuonSelectionTool::hitSummary
struct to handle easily number of hits in different parts of the MS
Definition: MuonSelectionTool.h:131
Muon::MuonStationIndex::ChIndex::BIS
@ BIS
lumiFormat.i
int i
Definition: lumiFormat.py:85
xAOD::extendedLargeHits
@ extendedLargeHits
number of precision hits in the extended large layer
Definition: TrackingPrimitives.h:338
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
CP::MuonSelectionTool::isBMG
bool isBMG(const float eta, const float phi) const
Check if muon eta/phi falls in BMG chambers.
Definition: MuonSelectionTool.cxx:1642
ReweightUtils.category
category
Definition: ReweightUtils.py:15
CP::MuonSelectionTool::isBIS78
bool isBIS78(const float eta, const float phi) const
Check if muon eta/phi falls in BIS7/8 chambers.
Definition: MuonSelectionTool.cxx:1606
CP::MuonSelectionTool::m_useLRT
Gaudi::Property< bool > m_useLRT
Definition: MuonSelectionTool.h:186
AthInfer::OutputDataMap
std::map< std::string, InferenceData > OutputDataMap
Definition: IAthInferenceTool.h:17
xAOD::MMHits
@ MMHits
Definition: TrackingPrimitives.h:438
WriteLumiToCool.value2
value2
Definition: WriteLumiToCool.py:50
CP::MuonSelectionTool::m_caloScoreWP
Gaudi::Property< int > m_caloScoreWP
Definition: MuonSelectionTool.h:185
LHEF::Reader
Pythia8::Reader Reader
Definition: Prophecy4fMerger.cxx:11
MuonParameters::segmentDeltaEta
@ segmentDeltaEta
MuTag parameters.
Definition: MuonParamDefs.h:139
athena.file_path
file_path
Definition: athena.py:94
CP::MuonSelectionTool::getAcceptInfo
virtual const asg::AcceptInfo & getAcceptInfo() const override
Get an object describing the "selection steps" of the tool.
Definition: MuonSelectionTool.cxx:269
Muon::MuonStationIndex::ChIndex::BML
@ BML
file
TFile * file
Definition: tile_monitor.h:29
python.BunchSpacingUtils.rn
rn
Definition: BunchSpacingUtils.py:85
xAOD::middleSmallHoles
@ middleSmallHoles
number of precision holes in the middle small layer
Definition: TrackingPrimitives.h:342
xAOD::combinedTrackOutBoundsPrecisionHits
@ combinedTrackOutBoundsPrecisionHits
total out-of-bounds hits on the combined track
Definition: TrackingPrimitives.h:378
Muon::MuonStationIndex::ChIndex::CSS
@ CSS
CP::MuonSelectionTool::m_useSegmentTaggedLowPt
Gaudi::Property< bool > m_useSegmentTaggedLowPt
Definition: MuonSelectionTool.h:199
Muon::MuonStationIndex::ChIndex::BOS
@ BOS
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
MuonSelectionTool.h
CP::MuonSelectionTool::getSegmentsSorted
std::vector< const xAOD::MuonSegment * > getSegmentsSorted(const xAOD::Muon &mu) const
Returns a vector of the muon's segments, sorted according to chamber index.
Definition: MuonSelectionTool.cxx:815
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
CP::MuonSelectionTool::m_calibration_version
Gaudi::Property< std::string > m_calibration_version
Definition: MuonSelectionTool.h:230
CP::MuonSelectionTool::m_excludeNSWFromPrecisionLayers
Gaudi::Property< bool > m_excludeNSWFromPrecisionLayers
Definition: MuonSelectionTool.h:182
xAOD::numberOfSCTHoles
@ numberOfSCTHoles
number of SCT holes [unit8_t].
Definition: TrackingPrimitives.h:271
xAOD::isSmallGoodSectors
@ isSmallGoodSectors
if non-deweighted track chambers are small
Definition: TrackingPrimitives.h:381
xAOD::SiSpacePointsSeedMaker_LargeD0
@ SiSpacePointsSeedMaker_LargeD0
Definition: TrackingPrimitives.h:184
Muon::MuonStationIndex::ChIndex::EES
@ EES
CP::MuonSelectionTool::getRunNumber
unsigned int getRunNumber(bool needOnlyCorrectYear=false) const
Definition: MuonSelectionTool.cxx:1549
xAOD::etaLayer2STGCHits
@ etaLayer2STGCHits
number of eta hits in the second STGC trigger layer (STGC2)
Definition: TrackingPrimitives.h:429
Trk::Combined
@ Combined
Definition: TrackSummaryTool.h:32
Muon::MuonStationIndex::ChIndex::BEE
@ BEE
LikeEnum::Tight
@ Tight
Definition: LikelihoodEnums.h:15
trapping_fp.h
Tell the compiler to optimize assuming that FP may trap.
Muon::MuonStationIndex::ChIndex::BMS
@ BMS
MuonParameters::scatteringCurvatureSignificance
@ scatteringCurvatureSignificance
Definition: MuonParamDefs.h:134
xAOD::TrackParticle_v1::qOverP
float qOverP() const
Returns the parameter.
PathResolver.h
CP::MuonSelectionTool::m_low_pt_mva_mutex
std::mutex m_low_pt_mva_mutex
Definition: MuonSelectionTool.h:267
xAOD::TrackParticle_v1::definingParametersCovMatrix
const ParametersCovMatrix_t definingParametersCovMatrix() const
Returns the 5x5 symmetric matrix containing the defining parameters covariance matrix.
Definition: TrackParticle_v1.cxx:247
xAOD::middleSmallHits
@ middleSmallHits
number of precision hits in the middle small layer
Definition: TrackingPrimitives.h:333
CP::MuonSelectionTool::accept
virtual asg::AcceptData accept(const xAOD::IParticle *p) const override
Get the decision using a generic IParticle pointer.
Definition: MuonSelectionTool.cxx:271
CP::MuonSelectionTool::m_useBEEBISInHighPtRun3
Gaudi::Property< bool > m_useBEEBISInHighPtRun3
Definition: MuonSelectionTool.h:203
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:76
CP::MuonSelectionTool::m_reader_MUTAGIMO_etaBin1
std::unique_ptr< TMVA::Reader > m_reader_MUTAGIMO_etaBin1
Definition: MuonSelectionTool.h:262
ReadHandle.h
Handle class for reading from StoreGate.
MuonR4::SegmentFit::toInt
constexpr int toInt(const ParamDefs p)
Definition: MuonHoughDefs.h:42
CP::MuonSelectionTool::m_tightWP_mediumPt_rhoCuts
std::unique_ptr< TH1 > m_tightWP_mediumPt_rhoCuts
Definition: MuonSelectionTool.h:244
CP::MuonSelectionTool::m_readerO_MUID
std::unique_ptr< TMVA::Reader > m_readerO_MUID
Definition: MuonSelectionTool.h:258
CP::MuonSelectionTool::m_useCaloScore
Gaudi::Property< bool > m_useCaloScore
Definition: MuonSelectionTool.h:184
CP::MuonSelectionTool::checkSanity
void checkSanity() const
Definition: MuonSelectionTool.cxx:290
MuonParameters::MuidSA
@ MuidSA
Definition: MuonParamDefs.h:59
MuonHough::ChIdx
Muon::MuonStationIndex::ChIndex ChIdx
Definition: MuonRegionHough.cxx:9
xAOD::outerSmallHits
@ outerSmallHits
number of precision hits in the outer small layer
Definition: TrackingPrimitives.h:335
CP::MuonSelectionTool::m_SiHolesCutOff
Gaudi::Property< bool > m_SiHolesCutOff
Definition: MuonSelectionTool.h:195
CP::MuonSelectionTool::m_MVAreaderFile_MuTagIMO_etaBin1
Gaudi::Property< std::string > m_MVAreaderFile_MuTagIMO_etaBin1
Definition: MuonSelectionTool.h:222
IDTPM::chiSquared
float chiSquared(const U &p)
Definition: TrackParametersHelper.h:128
CP::MuonSelectionTool::m_tightWP_lowPt_qOverPCuts
std::unique_ptr< TH1 > m_tightWP_lowPt_qOverPCuts
Definition: MuonSelectionTool.h:243
PathResolverFindCalibFile
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
Definition: PathResolver.cxx:283
Muon
struct TBPatternUnitContext Muon
CP::MuonSelectionTool::initialize
virtual StatusCode initialize() override
Function initialising the tool.
Definition: MuonSelectionTool.cxx:64
CP::MuonSelectionTool::isBadMuon
virtual bool isBadMuon(const xAOD::Muon &) const override
Returns true if a CB muon fails some loose quaility requirements designed to remove pathological trac...
Definition: MuonSelectionTool.cxx:649
CP::MuonSelectionTool::m_reader_MUTAGIMO_etaBin2
std::unique_ptr< TMVA::Reader > m_reader_MUTAGIMO_etaBin2
Definition: MuonSelectionTool.h:263
xAOD::score
@ score
Definition: TrackingPrimitives.h:514
CP::MuonSelectionTool::m_tightWP_lowPt_rhoCuts
std::unique_ptr< TH1 > m_tightWP_lowPt_rhoCuts
Definition: MuonSelectionTool.h:242
CP::MuonSelectionTool::MuonSelectionTool
MuonSelectionTool(const std::string &name="MuonSelection")
Create a proper constructor for Athena.
Definition: MuonSelectionTool.cxx:56
xAOD::numberOfTRTOutliers
@ numberOfTRTOutliers
number of TRT outliers [unit8_t].
Definition: TrackingPrimitives.h:277
CP::MuonSelectionTool::isRun3
bool isRun3(bool forceOnTheFly=false) const
Definition: MuonSelectionTool.h:273
MuonParameters::MuidCo
@ MuidCo
Definition: MuonParamDefs.h:60
xAOD::outerLargeHits
@ outerLargeHits
number of precision hits in the outer large layer
Definition: TrackingPrimitives.h:336
a
TList * a
Definition: liststreamerinfos.cxx:10
CP::MuonSelectionTool::m_maxEta
Gaudi::Property< double > m_maxEta
Definition: MuonSelectionTool.h:178
asg::AcceptData::setCutResult
void setCutResult(const std::string &cutName, bool cutResult)
Set the result of a cut, based on the cut name (safer)
Definition: AcceptData.h:134
LikeEnum::Medium
@ Medium
Definition: LikelihoodEnums.h:14
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
xAOD::numberOfSCTDeadSensors
@ numberOfSCTDeadSensors
number of dead SCT sensors crossed [unit8_t].
Definition: TrackingPrimitives.h:274
CP::MuonSelectionTool::m_onnxTool
ToolHandle< AthInfer::IAthInferenceTool > m_onnxTool
Definition: MuonSelectionTool.h:283
DeMoScan.first
bool first
Definition: DeMoScan.py:534
CP::MuonSelectionTool::m_TrtCutOff
Gaudi::Property< bool > m_TrtCutOff
Definition: MuonSelectionTool.h:192
xAOD::etaLayer1STGCHits
@ etaLayer1STGCHits
number of eta hits in the first STGC trigger layer (STGC1)
Definition: TrackingPrimitives.h:428
xAOD::numberOfGoodPrecisionLayers
@ numberOfGoodPrecisionLayers
layers with at least 3 hits that are not deweighted [uint8_t]
Definition: TrackingPrimitives.h:295
CP::MuonSelectionTool::IdMsPt
void IdMsPt(const xAOD::Muon &muon, float &idPt, float &msPt) const
Definition: MuonSelectionTool.cxx:381
Muon::MuonStationIndex::ChIndex::EOL
@ EOL
CP::MuonSelectionTool::retrieveSummaryValue
void retrieveSummaryValue(const P &muon, T &value, const S type, bool ignoreMissing=false) const
helper function to retrieve a hitSummary value
Definition: MuonSelectionTool.h:152
CP::MuonSelectionTool::m_geoOnTheFly
Gaudi::Property< bool > m_geoOnTheFly
Definition: MuonSelectionTool.h:200
xAOD::numberOfSCTHits
@ numberOfSCTHits
number of hits in SCT [unit8_t].
Definition: TrackingPrimitives.h:269
CP::MuonSelectionTool::~MuonSelectionTool
virtual ~MuonSelectionTool()
SG::ConstAccessor< T, AuxAllocator_t< T > >::isAvailable
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
xAOD::TrackParticle_v1::numberDoF
float numberDoF() const
Returns the number of degrees of freedom of the overall track or vertex fit as float.
CP::MuonSelectionTool::m_allowComm
Gaudi::Property< bool > m_allowComm
Definition: MuonSelectionTool.h:202
xAOD::STACO
@ STACO
Tracks produced by STACO.
Definition: TrackingPrimitives.h:100
xAOD::numberOfPixelDeadSensors
@ numberOfPixelDeadSensors
number of dead pixel sensors crossed [unit8_t].
Definition: TrackingPrimitives.h:267
Muon::MuonStationIndex::ChIndex
ChIndex
enum to classify the different chamber layers in the muon spectrometer
Definition: MuonStationIndex.h:15
xAOD::phiLayer1STGCHits
@ phiLayer1STGCHits
number of phi hits in the first STGC trigger layer (STGC1)
Definition: TrackingPrimitives.h:425
xAOD::track
@ track
Definition: TrackingPrimitives.h:513
xAOD::TrackParticle_v1
Class describing a TrackParticle.
Definition: TrackParticle_v1.h:43
xAOD::extendedSmallHits
@ extendedSmallHits
number of precision hits in the extended small layer
Definition: TrackingPrimitives.h:337
CP::MuonSelectionTool::m_MVAreaderFile_ODD_MuidCB
Gaudi::Property< std::string > m_MVAreaderFile_ODD_MuidCB
Definition: MuonSelectionTool.h:211
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
collisions.reader
reader
read the goodrunslist xml file(s)
Definition: collisions.py:22
Muon::MuonStationIndex::ChIndex::EMS
@ EMS
xAOD::innerSmallHits
@ innerSmallHits
number of precision hits in the inner small layer
Definition: TrackingPrimitives.h:331
CP::MuonSelectionTool::passedLowPtEfficiencyMVACut
bool passedLowPtEfficiencyMVACut(const xAOD::Muon &) const
Definition: MuonSelectionTool.cxx:831
asg::AcceptData
Definition: AcceptData.h:30
CP::MuonSelectionTool::fillSummary
void fillSummary(const xAOD::Muon &muon, hitSummary &summary) const
functions that fills a hitSummary for a muon
Definition: MuonSelectionTool.cxx:1421
CaloNoise_fillDB.mu
mu
Definition: CaloNoise_fillDB.py:51
pow
constexpr int pow(int base, int exp) noexcept
Definition: ap_fixedTest.cxx:15
AthInfer::InputDataMap
std::map< std::string, InferenceData > InputDataMap
Definition: IAthInferenceTool.h:16
CP::MuonSelectionTool::getResolutionCategory
virtual int getResolutionCategory(const xAOD::Muon &) const override
Returns an integer corresponding to categorization of muons with different resolutions.
Definition: MuonSelectionTool.cxx:1483
xAOD::TrackParticle_v1::theta
float theta() const
Returns the parameter, which has range 0 to .
CP::MuonSelectionTool::m_SctCutOff
Gaudi::Property< bool > m_SctCutOff
Definition: MuonSelectionTool.h:193
TrackingPrimitives.h
CP::MuonSelectionTool::m_MVAreaderFile_EVEN_MuGirl
Gaudi::Property< std::string > m_MVAreaderFile_EVEN_MuGirl
Definition: MuonSelectionTool.h:215
MuonParameters::spectrometerFieldIntegral
@ spectrometerFieldIntegral
Discriminators and further variables.
Definition: MuonParamDefs.h:133
fitman.rho
rho
Definition: fitman.py:532
TRTCalib_cfilter.p0
p0
Definition: TRTCalib_cfilter.py:129
xAOD::TrackParticle_v1::phi
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .)
xAOD::EventInfo_v1::eventType
bool eventType(EventType type) const
Check for one particular bitmask value.
GlobalVariables.eta_range
eta_range
Definition: GlobalVariables.py:358
Muon::MuonStationIndex::toInt
constexpr int toInt(const EnumType enumVal)
Definition: MuonStationIndex.h:61
asg::AcceptInfo::addCut
int addCut(const std::string &cutName, const std::string &cutDescription)
Add a cut; returning the cut position.
Definition: AcceptInfo.h:53
xAOD::TauJetParameters::unclassified
@ unclassified
Definition: TauDefs.h:410
python.LArMinBiasAlgConfig.float
float
Definition: LArMinBiasAlgConfig.py:65
CP::MuonSelectionTool::rhoPrime
float rhoPrime(const xAOD::Muon &muon) const
Returns rhoPrime of the muon (see definition in https://cds.cern.ch/record/2665711 )
Definition: MuonSelectionTool.cxx:424
Muon::MuonStationIndex::ChIndex::BOL
@ BOL
xAOD::numberOfPrecisionLayers
@ numberOfPrecisionLayers
layers with at least 3 hits [unit8_t].
Definition: TrackingPrimitives.h:289
SCT_Monitoring::summary
@ summary
Definition: SCT_MonitoringNumbers.h:65