13 static constexpr double const MeVtoGeV = 1. / 1000.;
16 std::vector<int> initializeChamberIdxOrder() {
23 const std::vector<ChIdx> orderedChIndices{
24 ChIdx::CSS, ChIdx::CSL, ChIdx::BIS, ChIdx::BIL,
25 ChIdx::BMS, ChIdx::BML, ChIdx::BOS, ChIdx::BOL,
26 ChIdx::BEE, ChIdx::EIS, ChIdx::EIL, ChIdx::EMS,
27 ChIdx::EML, ChIdx::EOS, ChIdx::EOL, ChIdx::EES,
32 std::vector<int> chamberIndexOrder(orderedChIndices.size());
34 for (
unsigned int i = 0;
i < orderedChIndices.size();
i++) {
35 chamberIndexOrder[
toInt(orderedChIndices[i])] =
i;
37 return chamberIndexOrder;
42 static const std::vector<int> chamberIndexOrder = initializeChamberIdxOrder();
43 return (chamberIndexOrder[
toInt(
first->chamberIndex())] <
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.")
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");
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");
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.");
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.");
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");
109 "Invalid quality (i.e. selection WP) set: "
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;
115 ATH_MSG_ERROR(
"Cannot use lowPt working point if allAuthors is not available!");
116 return StatusCode::FAILURE;
120 ATH_MSG_FATAL(
"CaloScoreWP property must be set to 1, 2, 3 or 4");
121 return StatusCode::FAILURE;
125 ATH_MSG_INFO(
"Initialising tight working point histograms...");
126 std::string tightWP_rootFile_fullPath;
131 Form(
"MuonSelectorTools/%s/muonSelection_tightWPHisto.root",
m_calibration_version.value().c_str()));
134 ATH_MSG_INFO(
"Reading muon tight working point histograms from " << tightWP_rootFile_fullPath);
136 std::unique_ptr<TFile>
file(TFile::Open(tightWP_rootFile_fullPath.c_str(),
"READ"));
138 if (!
file->IsOpen()) {
139 ATH_MSG_ERROR(
"Cannot read tight working point file from " << tightWP_rootFile_fullPath);
140 return StatusCode::FAILURE;
154 ATH_MSG_INFO(
"Reading bad muon veto cut functions from " << BMVcutFile_fullPath);
156 std::unique_ptr<TFile> BMVfile(TFile::Open(BMVcutFile_fullPath.c_str(),
"READ"));
158 if (!BMVfile->IsOpen()) {
159 ATH_MSG_ERROR(
"Cannot read bad muon veto cut function file from " << BMVcutFile_fullPath);
160 return StatusCode::FAILURE;
170 return StatusCode::FAILURE;
176 auto loadLowPtMVABDTModel = [&](
const std::string& calibFile,
177 std::unique_ptr<MVAUtils::BDT>& bdt,
178 std::vector<double>& means,
179 std::vector<double>& scales) -> StatusCode {
181 std::unique_ptr<TFile> rootFile(TFile::Open(modelFile.c_str(),
"READ"));
183 if (!rootFile || rootFile->IsZombie()) {
184 ATH_MSG_ERROR(
"Failed to open model file for Run-3 LowPtMVA: " << modelFile);
185 return StatusCode::FAILURE;
189 auto* bdt_tree =
static_cast<TTree*
>(rootFile->Get(
"xgboost"));
190 bdt = std::make_unique<MVAUtils::BDT>(bdt_tree);
193 std::unique_ptr<TTree> scaler_tree(
static_cast<TTree*
>(rootFile->Get(
"scaler")));
194 std::vector<double>* mean_ptr =
nullptr;
195 std::vector<double>* scale_ptr =
nullptr;
196 scaler_tree->SetBranchAddress(
"mean", &mean_ptr);
197 scaler_tree->SetBranchAddress(
"scale", &scale_ptr);
199 for (Long64_t i = 0; i < scaler_tree->GetEntries(); ++i) {
200 scaler_tree->GetEntry(i);
201 for (
size_t j = 0; j < mean_ptr->size(); ++j) {
202 means.push_back((*mean_ptr)[j]);
203 scales.push_back((*scale_ptr)[j]);
206 return StatusCode::SUCCESS;
210 ATH_CHECK(loadLowPtMVABDTModel(
"MuonSelectorTools/260130_LowPtMVA_r24run3/xgb_lowPtMVA_MuidCO_wScaler.root",
214 ATH_CHECK(loadLowPtMVABDTModel(
"MuonSelectorTools/260130_LowPtMVA_r24run3/xgb_lowPtMVA_MuGirl_wScaler.root",
225 auto make_mva_reader = [](TString file_path) {
226 std::vector<std::string> mva_var_names{
"momentumBalanceSignificance",
227 "scatteringCurvatureSignificance",
228 "scatteringNeighbourSignificance",
230 "middleLargeHoles+middleSmallHoles",
231 "muonSegmentDeltaEta",
232 "muonSeg1ChamberIdx",
233 "muonSeg2ChamberIdx"};
234 std::unique_ptr<TMVA::Reader> reader = std::make_unique<TMVA::Reader>(mva_var_names);
235 reader->BookMVA(
"BDTG", file_path);
251 auto make_mva_reader_MuTagIMO = [](TString file_path,
bool useSeg2ChamberIndex) {
252 std::vector<std::string> mva_var_names;
253 if (useSeg2ChamberIndex) mva_var_names.push_back(
"muonSeg2ChamberIndex");
254 mva_var_names.push_back(
"muonSeg1ChamberIndex");
255 mva_var_names.push_back(
"muonSeg1NPrecisionHits");
256 mva_var_names.push_back(
"muonSegmentDeltaEta");
257 mva_var_names.push_back(
"muonSeg1GlobalR");
258 mva_var_names.push_back(
"muonSeg1Chi2OverDoF");
259 mva_var_names.push_back(
"muonSCS");
261 std::unique_ptr<TMVA::Reader> reader = std::make_unique<TMVA::Reader>(mva_var_names);
262 reader->BookMVA(
"BDT", file_path);
277 ATH_MSG_ERROR(
"Cannot calculate TightNNScore: ONNX tool not configured! "
278 "Please set the ORTInferenceTool property to a valid AthOnnx::OnnxRuntimeInferenceTool instance.");
279 return StatusCode::FAILURE;
284 }
else ATH_MSG_INFO(
"ONNX tool not configured — skipping retrieval.");
290 return StatusCode::SUCCESS;
296 ATH_MSG_ERROR(
" getHist(...) TFile is nullptr! Check that the Tight cut map is loaded correctly");
297 return StatusCode::FAILURE;
299 TH1* h_ptr =
nullptr;
300 file->GetObject(histName.c_str(), h_ptr);
305 return StatusCode::FAILURE;
307 hist = std::unique_ptr<TH1>{h_ptr};
308 hist->SetDirectory(
nullptr);
309 ATH_MSG_INFO(
"Successfully read tight working point histogram: " << hist->GetName());
311 return StatusCode::SUCCESS;
326 ATH_MSG_FATAL(
"accept(...) Failed to cast particle to muon");
337 static std::atomic<bool> checkDone{
false};
345 <<
" while on-the fly check for runNumber "<<
getRunNumber(
true)<<
" indicates isRun3Geo="<<
isRun3(
true));
351 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");
355 ATH_MSG_WARNING(
"For Run3, Tight WP is supported only when ExcludeNSWFromPrecisionLayers=False and RecalcPrecisionLayerswNSW=True");
368 if (mu.muonType() == xAOD::Muon::Combined)
370 else if (mu.muonType() == xAOD::Muon::MuonStandAlone)
372 else if (mu.muonType() == xAOD::Muon::SegmentTagged)
374 else if (mu.muonType() == xAOD::Muon::CaloTagged)
376 else if (mu.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon)
387 if (std::abs(mu.eta()) >=
m_maxEta) {
403 if (!passIDCuts || !passMuonCuts) {
return acceptData; }
406 xAOD::Muon::Quality thisMu_quality =
getQuality(mu);
407 bool thisMu_highpt =
false;
409 bool thisMu_lowptE =
false;
412 ATH_MSG_VERBOSE(
"Muon quality: " << thisMu_quality <<
" passes HighPt: " << thisMu_highpt
413 <<
" passes LowPtEfficiency: " << thisMu_lowptE);
415 if (
m_quality == 4 && !thisMu_highpt) {
return acceptData; }
416 if (
m_quality == 5 && !thisMu_lowptE) {
return acceptData; }
427 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
428 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
429 if (!idtrack || !metrack) idPt = mePt = -1.;
431 mePt = metrack->
pt();
432 idPt = idtrack->
pt();
434 if (!mePt_acc.isAvailable(mu) || !idPt_acc.isAvailable(mu)) {
435 ATH_MSG_FATAL(
"The muon with pT " << mu.pt() *
MeVtoGeV <<
" eta: " << mu.eta() <<
", phi:" << mu.phi()
436 <<
" q:" << mu.charge() <<
", author:" << mu.author()
437 <<
" is not decorated with calibrated momenta. Please fix");
438 throw std::runtime_error(
"MuonSelectionTool() - qOverP significance calculation failed");
451 <<
" Momentum dependent cuts are disabled. Return 0.");
455 const xAOD::TrackParticle* metrack =
muon.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
456 if (!idtrack || !metrack) {
457 ATH_MSG_VERBOSE(
"No ID / MS track. Return dummy large value of 1 mio");
460 float mePt{-1.}, idPt{-1.};
463 const float meP = mePt / std::sin(metrack->
theta());
464 const float idP = idPt / std::sin(idtrack->
theta());
467 return std::abs((metrack->
charge() / meP) - (idtrack->
charge() / idP)) / qOverPsigma;
472 <<
"Momentum dependent cuts are disabled. Return 0.");
475 float mePt{-1.}, idPt{-1.};
477 return std::abs(idPt - mePt) /
muon.pt();
482 if (
isRun3() && mu.isAuthor(xAOD::Muon::Author::Commissioning) && !
m_allowComm) {
484 return xAOD::Muon::VeryLoose;
488 if (mu.muonType() == xAOD::Muon::SegmentTagged) {
491 if (std::abs(mu.eta()) < 0.1) {
493 return xAOD::Muon::Loose;
495 ATH_MSG_VERBOSE(
"Do not allow segment-tagged muon at |eta| > 0.1 - return VeryLoose");
496 return xAOD::Muon::VeryLoose;
501 if (mu.muonType() == xAOD::Muon::CaloTagged) {
506 return xAOD::Muon::Loose;
514 if (mu.muonType() == xAOD::Muon::Combined) {
516 if (mu.author() == xAOD::Muon::STACO) {
518 return xAOD::Muon::VeryLoose;
526 ATH_MSG_VERBOSE(
"Muon has out-of-bounds precision hits - return VeryLoose");
527 return xAOD::Muon::VeryLoose;
531 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
532 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
536 const float reducedChi2 = mu.primaryTrackParticle()->chiSquared() / mu.primaryTrackParticle()->numberDoF();
539 ATH_MSG_VERBOSE(
"number of precision layers = " << (
int)summary.nprecisionLayers);
544 if (summary.nprecisionLayers > 1 && reducedChi2 < 8 && std::abs(qOverPsignif) < 7) {
547 return xAOD::Muon::Tight;
551 ATH_MSG_VERBOSE(
"Muon did not pass requirements for tight combined muon");
555 (summary.nprecisionLayers > 1 ||(summary.nprecisionLayers == 1 && summary.nprecisionHoleLayers < 2 && std::abs(mu.eta()) < 0.1))
559 return xAOD::Muon::Medium;
562 ATH_MSG_VERBOSE(
"Muon did not pass requirements for medium combined muon");
568 if ((summary.nprecisionLayers > 1 ||
569 (summary.nprecisionLayers == 1 && summary.nprecisionHoleLayers < 2 && std::abs(mu.eta()) < 0.1))) {
574 return xAOD::Muon::Medium;
577 return xAOD::Muon::Loose;
583 if ((
m_disablePtCuts || mu.pt() *
MeVtoGeV < 7.) && std::abs(mu.eta()) < 1.3 && summary.nprecisionLayers > 0 &&
584 (mu.author() == xAOD::Muon::MuGirl && mu.isAuthor(xAOD::Muon::MuTagIMO))) {
585 ATH_MSG_VERBOSE(
"Muon passed selection for loose working point at low pT");
586 return xAOD::Muon::Loose;
590 ATH_MSG_VERBOSE(
"Did not pass selections for combined muon - returning VeryLoose");
591 return xAOD::Muon::VeryLoose;
595 if (mu.author() == xAOD::Muon::MuidSA) {
598 if (std::abs(mu.eta()) > 2.5) {
599 ATH_MSG_VERBOSE(
"number of precision layers = " << (
int)summary.nprecisionLayers);
602 if (summary.nprecisionLayers > 2 && !
m_toroidOff) {
604 return xAOD::Muon::Medium;
609 ATH_MSG_VERBOSE(
"Muon did not pass selection for medium stand-alone muon - return VeryLoose");
610 return xAOD::Muon::VeryLoose;
614 if (mu.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
618 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
620 if (cbtrack && metrack) {
621 if (std::abs(cbtrack->
eta()) > 2.5) {
622 ATH_MSG_VERBOSE(
"number of precision layers = " << (
int)summary.nprecisionLayers);
624 if (summary.nprecisionLayers > 2 && !
m_toroidOff) {
625 if (mu.trackParticle(xAOD::Muon::Primary) == mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle) &&
628 "SiliconForwardAssociated muon has ID track as primary track particle. "
629 <<
"This is a bug fixed starting with xAODMuon-00-17-07, which should be present in this release. "
630 <<
"Please report this to the Muon CP group!");
633 return xAOD::Muon::Medium;
639 ATH_MSG_VERBOSE(
"Muon did not pass selection for medium silicon-associated forward muon - return VeryLoose");
640 return xAOD::Muon::VeryLoose;
643 ATH_MSG_VERBOSE(
"Muon did not pass selection for loose/medium/tight for any muon type - return VeryLoose");
644 return xAOD::Muon::VeryLoose;
653 if (isLRTmuon(mu))
return true;
657 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
660 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.");
661 throw std::runtime_error(
"MuonSelectionTool() - isLRT decor and patternRecoInfo both unavailable for a muon.");
663 std::bitset<xAOD::NumberOfTrackRecoInfo> patternBitSet(patternAcc(*idtrack));
669 if (mu.author() == xAOD::Muon::MuidSA && std::abs(mu.eta()) > 2.5) {
671 }
else if (mu.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
673 if (cbtrack && std::abs(cbtrack->
eta()) > 2.5) {
return true; }
676 if (mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle))
677 return passedIDCuts(*mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle));
678 else if (mu.primaryTrackParticle())
685 if (mu.muonType() != xAOD::Muon::Combined)
return false;
687 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
688 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
694 bool IsBadMuon =
false;
695 if (idtrack && metrack && cbtrack) {
697 double qOverP_ID = idtrack->
qOverP();
699 double qOverP_ME = metrack->
qOverP();
701 double qOverP_CB = cbtrack->
qOverP();
714 double IdCbRatio = std::abs((qOverPerr_ID / qOverP_ID) / (qOverPerr_CB / qOverP_CB));
715 double MeCbRatio = std::abs((qOverPerr_ME / qOverP_ME) / (qOverPerr_CB / qOverP_CB));
716 IsBadMuon = (IdCbRatio < 0.8 || MeCbRatio < 0.8 || IsBadMuon);
720 double IdCbRatio = std::abs((qOverPerr_ID / qOverP_ID) / (qOverPerr_CB / qOverP_CB));
721 double MeCbRatio = std::abs((qOverPerr_ME / qOverP_ME) / (qOverPerr_CB / qOverP_CB));
722 IsBadMuon = (IdCbRatio < 0.8 || MeCbRatio < 0.8);
731 xAOD::Muon::Quality thisMu_quality =
getQuality(mu);
745 if (mu.muonType() != xAOD::Muon::Combined) {
750 if (mu.muonType() != xAOD::Muon::Combined && mu.muonType() != xAOD::Muon::SegmentTagged) {
751 ATH_MSG_VERBOSE(
"Muon is not combined or segment-tagged - fail low-pT");
758 if (mu.author() != xAOD::Muon::MuGirl && mu.author() != xAOD::Muon::MuidCo) {
763 if (mu.author() != xAOD::Muon::MuGirl && mu.author() != xAOD::Muon::MuidCo && mu.author() != xAOD::Muon::MuTagIMO) {
764 ATH_MSG_VERBOSE(
"Muon is neither MuGirl / MuidCo / MuTagIMO - fail low-pT");
772 if (thisMu_quality <= xAOD::Muon::Medium) {
782 if (!
m_useMVALowPt && std::abs(mu.eta()) > 1.55 && thisMu_quality > xAOD::Muon::Medium) {
783 ATH_MSG_VERBOSE(
"Not using MVA selection, failing low-pT selection due to medium requirement in forward region");
791 ATH_MSG_VERBOSE(
"Muon has out-of-bounds precision hits - fail low-pT");
796 if (mu.muonType() == xAOD::Muon::Combined) {
799 uint nStationsCut = (std::abs(mu.eta()) > 1.3 && std::abs(mu.eta()) < 1.55) ? 2 : 1;
800 if (summary.nprecisionLayers < nStationsCut) {
801 ATH_MSG_VERBOSE(
"number of precision layers = " << (
int)summary.nprecisionLayers <<
" is lower than cut value " << nStationsCut
802 <<
" - fail low-pT");
809 if (mu.author() == xAOD::Muon::MuGirl && !mu.isAuthor(xAOD::Muon::MuTagIMO)) {
810 ATH_MSG_VERBOSE(
"MuGirl muon is not confirmed by MuTagIMO - fail low-pT");
830 float momentumBalanceSignificance{0.}, scatteringCurvatureSignificance{0.}, scatteringNeighbourSignificance{0.};
832 retrieveParam(mu, momentumBalanceSignificance, xAOD::Muon::momentumBalanceSignificance);
833 retrieveParam(mu, scatteringCurvatureSignificance, xAOD::Muon::scatteringCurvatureSignificance);
834 retrieveParam(mu, scatteringNeighbourSignificance, xAOD::Muon::scatteringNeighbourSignificance);
836 ATH_MSG_VERBOSE(
"momentum balance significance: " << momentumBalanceSignificance);
837 ATH_MSG_VERBOSE(
"scattering curvature significance: " << scatteringCurvatureSignificance);
838 ATH_MSG_VERBOSE(
"scattering neighbour significance: " << scatteringNeighbourSignificance);
840 if (std::abs(momentumBalanceSignificance) > 3. || std::abs(scatteringCurvatureSignificance) > 3. ||
841 std::abs(scatteringNeighbourSignificance) > 3.) {
852 std::vector<const xAOD::MuonSegment*> segments_sorted;
853 segments_sorted.reserve(mu.nMuonSegments());
855 for (
unsigned int i = 0; i < mu.nMuonSegments(); i++) {
856 if (!mu.muonSegment(i))
857 ATH_MSG_WARNING(
"The muon reports more segments than are available. Please report this to the muon software community!");
859 segments_sorted.push_back(mu.muonSegment(i));
862 std::sort(segments_sorted.begin(), segments_sorted.end(), chamberIndexCompare);
864 return segments_sorted;
870 ATH_MSG_VERBOSE(
"LowPt WP currently not supported for run3 if not in expert mode");
879 float momentumBalanceSig{-1}, CurvatureSig{-1}, energyLoss{-1}, muonSegmentDeltaEta{-1}, scatteringNeigbour{-1};
880 retrieveParam(mu, momentumBalanceSig, xAOD::Muon::momentumBalanceSignificance);
881 retrieveParam(mu, CurvatureSig, xAOD::Muon::scatteringCurvatureSignificance);
882 retrieveParam(mu, scatteringNeigbour, xAOD::Muon::scatteringNeighbourSignificance);
884 retrieveParam(mu, muonSegmentDeltaEta, xAOD::Muon::segmentDeltaEta);
890 float seg1ChamberIdx{-1.}, seg2ChamberIdx{-1.}, middleHoles{-1.}, seg1NPrecisionHits{-1.}, seg1GlobalR{-1.}, seg1Chi2OverDoF{-1.};
894 if (mu.author() == xAOD::Muon::MuTagIMO && muonSegments.size() == 0)
895 ATH_MSG_WARNING(
"passedLowPtEfficiencyMVACut - found segment-tagged muon with no segments!");
898 seg1ChamberIdx = (!muonSegments.empty()) ?
toInt(muonSegments[0]->chamberIndex()) : -9;
899 seg2ChamberIdx = (muonSegments.size() > 1) ?
toInt(muonSegments[1]->chamberIndex()) : -9;
902 if (mu.author() == xAOD::Muon::MuTagIMO) {
903 seg1NPrecisionHits = (!muonSegments.empty()) ? muonSegments[0]->nPrecisionHits() : -1;
904 seg1GlobalR = (!muonSegments.empty())
905 ? std::hypot(muonSegments[0]->
x(), muonSegments[0]->
y(), muonSegments[0]->
z())
907 seg1Chi2OverDoF = (!muonSegments.empty()) ? muonSegments[0]->chiSquared() / muonSegments[0]->numberDoF() : -1;
920 std::vector<float> var_vector;
921 if (mu.author() == xAOD::Muon::MuidCo || mu.author() == xAOD::Muon::MuGirl) {
922 var_vector = {momentumBalanceSig, CurvatureSig, scatteringNeigbour, energyLoss,
923 middleHoles, muonSegmentDeltaEta, seg1ChamberIdx, seg2ChamberIdx};
925 if (std::abs(mu.eta()) >= 1.3)
926 var_vector = {seg2ChamberIdx, seg1ChamberIdx, seg1NPrecisionHits, muonSegmentDeltaEta,
927 seg1GlobalR, seg1Chi2OverDoF, std::abs(CurvatureSig)};
929 var_vector = {seg1ChamberIdx, seg1NPrecisionHits, muonSegmentDeltaEta,
930 seg1GlobalR, seg1Chi2OverDoF, std::abs(CurvatureSig)};
934 TMVA::Reader *reader_MUID, *reader_MUGIRL;
944 TMVA::Reader* reader_MUTAGIMO;
945 if (std::abs(mu.eta()) < 0.7)
947 else if (std::abs(mu.eta()) < 1.3)
953 float BDTdiscriminant;
955 if (mu.author() == xAOD::Muon::MuidCo)
956 BDTdiscriminant = reader_MUID->EvaluateMVA(var_vector,
"BDTG");
957 else if (mu.author() == xAOD::Muon::MuGirl)
958 BDTdiscriminant = reader_MUGIRL->EvaluateMVA(var_vector,
"BDTG");
960 BDTdiscriminant = reader_MUTAGIMO->EvaluateMVA(var_vector,
"BDT");
962 ATH_MSG_WARNING(
"Invalid author for low-pT MVA, failing selection...");
967 float BDTcut = (mu.author() == xAOD::Muon::MuTagIMO) ? 0.12 : -0.6;
969 if (BDTdiscriminant > BDTcut) {
984 if (mu.author() == xAOD::Muon::MuidCo) {
988 float momentumBalanceSig{-1}, CurvatureSig{-1}, scatteringNeigbour{-1};
989 int CaloMuonIDTag{-1};
990 uint8_t nPixelHits{0}, nTRTOutliers{0};
991 float reducedChi2{-1};
992 float etaBalanceSig{-1}, phiBalanceSig{-1};
993 float seg1ChamberIdx{-1};
995 retrieveParam(mu, momentumBalanceSig, xAOD::Muon::momentumBalanceSignificance);
996 retrieveParam(mu, CurvatureSig, xAOD::Muon::scatteringCurvatureSignificance);
997 retrieveParam(mu, scatteringNeigbour, xAOD::Muon::scatteringNeighbourSignificance);
1002 mu.parameter(CaloMuonIDTag, xAOD::Muon::CaloMuonIDTag);
1004 reducedChi2 = mu.primaryTrackParticle()->chiSquared() / mu.primaryTrackParticle()->numberDoF();
1006 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
1007 const xAOD::TrackParticle* metrk = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
1009 etaBalanceSig = std::abs(idtrack->
eta() - metrk->
eta());
1010 phiBalanceSig = std::abs(idtrack->
phi() - metrk->
phi());
1014 seg1ChamberIdx = (!muonSegments.empty()) ?
toInt(muonSegments[0]->chamberIndex()) : -9;
1020 etaBalanceSig = std::min(etaBalanceSig, 1.0f);
1021 reducedChi2 = std::min(reducedChi2, 100.0f);
1022 CurvatureSig = std::clamp(CurvatureSig, -10.0f, 10.0f);
1023 scatteringNeigbour = std::clamp(scatteringNeigbour, -10.0f, 10.0f);
1026 std::vector<float> muidCO_feature_vector = {
1027 static_cast<float>(nPixelHits),
1028 static_cast<float>(nTRTOutliers),
1029 static_cast<float>(CaloMuonIDTag),
1030 static_cast<float>(mu.energyLossType()),
1033 static_cast<float>(summary.nprecisionLayers),
1042 for (
size_t j=0; j<muidCO_feature_vector.size(); ++j){
1047 float bdt_score =
m_MuidCO->GetClassification(muidCO_feature_vector);
1048 ATH_MSG_VERBOSE(
" Low-pT MVA BDT score (MuidCo, Run-3) : " << bdt_score);
1052 float lowPtMVARun3_MuidCO_cut_value = 0.1300;
1053 return (bdt_score > lowPtMVARun3_MuidCO_cut_value);
1055 }
else if (mu.author() == xAOD::Muon::MuGirl && mu.isAuthor(xAOD::Muon::MuTagIMO)) {
1060 float momentumBalanceSig{-1}, seg1ChamberIdx{-1}, energyLoss{-1};
1061 int CaloMuonIDTag{-1};
1062 float reducedChi2{-1}, etaBalanceSig{-1}, phiBalanceSig{-1};
1063 float segmentDeltaEta{-1}, etaPrime{-1}, innerHits{-1};
1064 float middleHoles{-1}, nGoodPrecLayers{-1};
1065 float nprecisionHoleLayers{-1}, outerHoles{-1};
1067 retrieveParam(mu, momentumBalanceSig, xAOD::Muon::momentumBalanceSignificance);
1068 retrieveParam(mu, segmentDeltaEta, xAOD::Muon::segmentDeltaEta);
1081 mu.parameter(CaloMuonIDTag, xAOD::Muon::CaloMuonIDTag);
1085 reducedChi2 = mu.primaryTrackParticle()->chiSquared() / mu.primaryTrackParticle()->numberDoF();
1087 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
1088 const xAOD::TrackParticle* metrk = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
1090 etaBalanceSig = std::abs(idtrack->
eta() - metrk->
eta());
1091 etaPrime = std::abs((idtrack->
eta() - metrk->
eta())/mu.eta());
1092 phiBalanceSig = std::abs(idtrack->
phi() - metrk->
phi());
1096 seg1ChamberIdx = (!muonSegments.empty()) ?
toInt(muonSegments[0]->chamberIndex()) : -9;
1100 innerHits = summary.innerSmallHits + summary.innerLargeHits;
1101 nGoodPrecLayers = summary.nGoodPrecLayers;
1102 nprecisionHoleLayers = summary.nprecisionHoleLayers;
1105 etaBalanceSig = std::min(etaBalanceSig, 1.0f);
1106 reducedChi2 = std::min(reducedChi2, 100.0f);
1107 etaPrime = std::clamp(etaPrime, -10.0f, 10.0f);
1110 std::vector<float> muGirl_feature_vector = {
1111 static_cast<float>(nTRTOutliers),
1112 static_cast<float>(CaloMuonIDTag),
1121 nprecisionHoleLayers,
1122 static_cast<float>(summary.nprecisionLayers),
1132 for (
size_t j=0; j<muGirl_feature_vector.size(); ++j){
1137 float bdt_score =
m_MuGirl->GetClassification(muGirl_feature_vector);
1138 ATH_MSG_VERBOSE(
" Low-pT MVA BDT score (MuGirl, Run-3) : " << bdt_score);
1142 float lowPtMVARun3_MuGirl_cut_value = 0.1550;
1143 return (bdt_score > lowPtMVARun3_MuGirl_cut_value);
1145 ATH_MSG_WARNING(
"Invalid author for low-pT MVA in Run-3, failing selection...");
1154 if (mu.muonType() != xAOD::Muon::Combined) {
1158 if (mu.author() == xAOD::Muon::STACO) {
1167 ATH_MSG_VERBOSE(
"Muon has out-of-bounds precision hits - fail high-pT");
1176 ATH_MSG_VERBOSE(
"number of precision layers: " << (
int)summary.nprecisionLayers);
1184 const xAOD::TrackParticle* CB_track = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
1185 const xAOD::TrackParticle* MS_track = mu.trackParticle(xAOD::Muon::MuonSpectrometerTrackParticle);
1187 ATH_MSG_VERBOSE(
"passedHighPtCuts - No MS track available for muon. Using combined track.");
1188 MS_track = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
1191 if (MS_track && CB_track) {
1193 float phiMS = MS_track->
phi();
1194 float etaCB = CB_track->
eta();
1197 if (!
isRun3() && (std::abs(
etaMS) > 2.0 || std::abs(etaCB) > 2.0)) {
1198 if (summary.cscUnspoiledEtaHits == 0) {
1205 if (!
isRun3() && mu.eta() < -1.899 && std::abs(mu.phi()) < 0.211) {
1206 ATH_MSG_VERBOSE(
"Muon is in eta/phi region vetoed due to disabled chambers in MC - fail high-pT");
1211 if ((1.01 < std::abs(
etaMS) && std::abs(
etaMS) < 1.1) || (1.01 < std::abs(etaCB) && std::abs(etaCB) < 1.1)) {
1212 ATH_MSG_VERBOSE(
"Muon is in barrel/endcap overlap region - fail high-pT");
1242 if (summary.nprecisionLayers < 4) {
1243 ATH_MSG_VERBOSE(
"Muon is in BEE eta/phi region and does not have 4 precision layers - fail high-pT");
1247 if (std::abs(etaCB) > 1.4) {
1251 if (summary.nprecisionLayers < 4 && (summary.extendedSmallHits > 0 || summary.extendedSmallHoles > 0)) {
1252 ATH_MSG_VERBOSE(
"Muon is in BEE eta/phi region and does not have 4 precision layers - fail high-pT");
1257 ATH_MSG_WARNING(
"passedHighPtCuts - MS or CB track missing in muon! Failing High-pT selection...");
1262 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
1263 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
1268 if (std::abs(qOverPsignif) > 7) {
1280 if (std::abs(mu.eta()) > 1.2 && summary.extendedSmallHits < 3 && summary.extendedLargeHits < 3) {
1288 if (summary.innerLargeHits == 0 && summary.middleLargeHits == 0 && summary.outerLargeHits == 0 &&
1289 summary.extendedLargeHits == 0 && summary.middleSmallHits > 2 &&
1290 (summary.outerSmallHits > 2 || summary.extendedSmallHits > 2)) {
1295 if (summary.innerSmallHits == 0 && summary.middleSmallHits == 0 && summary.outerSmallHits == 0 &&
1296 summary.extendedSmallHits == 0 && summary.middleLargeHits > 2 &&
1297 (summary.outerLargeHits > 2 || summary.extendedLargeHits > 2)) {
1304 if (summary.nprecisionLayers < 3) {
1305 ATH_MSG_VERBOSE(
"Muon has less than 3 precision layers - fail high-pT");
1310 if (summary.isSmallGoodSectors) {
1311 if (!(summary.innerSmallHits > 2 && summary.middleSmallHits > 2 &&
1312 (summary.outerSmallHits > 2 || summary.extendedSmallHits > 2))) {
1313 ATH_MSG_VERBOSE(
"Muon has small/large sectors overlap - fail high-pT");
1317 if (!(summary.innerLargeHits > 2 && summary.middleLargeHits > 2 &&
1318 (summary.outerLargeHits > 2 || summary.extendedLargeHits > 2))) {
1319 ATH_MSG_VERBOSE(
"Muon has small/large sectors overlap - fail high-pT");
1330 if (mu.muonType() != xAOD::Muon::Combined)
return false;
1332 double start_cut = 3.0;
1333 double end_cut = 1.6;
1334 double abs_eta = std::abs(mu.eta());
1337 double p0(8.0), p1(0.), p2(0.);
1344 else if (abs_eta > 1.05 && abs_eta <= 1.3) {
1347 }
else if (abs_eta > 1.3 && abs_eta <= 1.7) {
1350 }
else if (abs_eta > 1.7 && abs_eta <= 2.0) {
1353 }
else if (abs_eta > 2.0) {
1364 else if (abs_eta > 1.05 && abs_eta <= 1.3) {
1367 }
else if (abs_eta > 1.3 && abs_eta <= 1.7) {
1370 }
else if (abs_eta > 1.7 && abs_eta <= 2.0) {
1373 }
else if (abs_eta > 2.0) {
1388 if (abs_eta > 1.05 && abs_eta < 1.3) {
1391 }
else if (abs_eta >= 1.3 && abs_eta < 1.7) {
1394 }
else if (abs_eta >= 1.7 && abs_eta < 2.0) {
1397 }
else if (abs_eta >= 2.0) {
1403 bool passErrorCutCB =
false;
1408 double qOverP_CB = cbtrack->
qOverP();
1411 double sigma = std::sqrt(std::pow(p0 / pt_CB, 2) + std::pow(p1, 2) + std::pow(p2 * pt_CB, 2));
1414 double a = (end_cut - start_cut) / 4000.0;
1415 double b = end_cut -
a * 5000.0;
1416 double coefficient = (pt_CB > 1000.) ? (
a * pt_CB + b) : start_cut;
1417 if (std::abs(qOverPerr_CB / qOverP_CB) < coefficient * sigma) { passErrorCutCB =
true; }
1424 ATH_MSG_DEBUG(
"The current event is a MC event. Use bad muon veto mimic.");
1430 return passErrorCutCB;
1436 if (std::abs(mu.eta()) < 1.05) {
1446 double qOpRelResolution = std::hypot(p1, p2 * mu.primaryTrackParticle()->pt() *
MeVtoGeV);
1448 double qOverPabs_unsmeared = std::abs(mu.primaryTrackParticle()->definingParameters()[4]);
1449 double qOverPabs_smeared = 1.0 / (mu.pt() * std::cosh(mu.eta()));
1451 if ((qOverPabs_smeared - qOverPabs_unsmeared) / (qOpRelResolution * qOverPabs_unsmeared) <
1452 cutFunction->Eval(mu.primaryTrackParticle()->pt() *
MeVtoGeV))
1460 if (mu.muonType() == xAOD::Muon::Combined) {
return mu.author() != xAOD::Muon::STACO; }
1462 if (mu.muonType() == xAOD::Muon::CaloTagged && std::abs(mu.eta()) < 0.105)
1465 if (mu.muonType() == xAOD::Muon::SegmentTagged && (std::abs(mu.eta()) < 0.105 ||
m_useSegmentTaggedLowPt))
return true;
1467 if (mu.author() == xAOD::Muon::MuidSA && std::abs(mu.eta()) > 2.4)
return true;
1469 if (mu.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
1471 return (cbtrack && std::abs(cbtrack->
eta()) > 2.4);
1482 " !! Tool configured with some of the ID hits requirements changed... FOR DEVELOPMENT ONLY: muon efficiency SF won't be "
1487 if ((value1 + value2 == 0) && !
m_PixCutOff)
return false;
1491 if ((value1 + value2 <= 4) && !
m_SctCutOff)
return false;
1498 const float abseta = std::abs(
track.eta());
1502 if (!((0.1 < abseta && abseta <= 1.9 && totTRThits > 5 && value2 < (0.9 * totTRThits)) || (abseta <= 0.1 || abseta > 1.9)))
1513 constexpr float eta_range = 1.;
1517 int CaloMuonIDTag = -20;
1520 bool readID = mu.parameter(CaloMuonIDTag, xAOD::Muon::CaloMuonIDTag);
1522 ATH_MSG_WARNING(
"Unable to read CaloMuonIDTag Quality information! Rejecting the CALO muon!");
1527 return (CaloMuonIDTag > 10);
1536 float CaloMuonScore{-999.0};
1537 retrieveParam(mu, CaloMuonScore, xAOD::Muon::CaloMuonScore);
1547 return (CaloMuonScore >= 0.77);
1552 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));
1553 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));
1563 ATH_MSG_VERBOSE(
"for run3, Tight WP is only supported when ExcludeNSWFromPrecisionLayers=False and RecalcPrecisionLayerswNSW=True");
1566 float symmetric_eta = std::abs(mu.eta());
1571 ATH_MSG_VERBOSE(
"Muon is passing tight WP kinematic cuts with pT,eta " << mu.pt() <<
" , " << mu.eta());
1578 ATH_MSG_VERBOSE(
"Applying tight WP cuts to a low pt muon with (pt,eta) ( " <<
pt <<
" , " << mu.eta() <<
" ) ");
1579 ATH_MSG_VERBOSE(
"Rho value " << rho <<
", required to be less than " << rhoCut);
1580 ATH_MSG_VERBOSE(
"Momentum significance value " << oneOverPSig <<
", required to be less than " << qOverPCut);
1582 if (rho > rhoCut)
return false;
1585 if (oneOverPSig > qOverPCut)
return false;
1586 ATH_MSG_VERBOSE(
"Muon passed tight WP, low pT momentum significance cut");
1594 else if (
pt < 100.0) {
1597 ATH_MSG_VERBOSE(
"Applying tight WP cuts to a medium pt muon with (pt,eta) (" <<
pt <<
"," << mu.eta() <<
")");
1598 ATH_MSG_VERBOSE(
"Rho value " << rho <<
" required to be less than " << rhoCut);
1601 if (rho > rhoCut)
return false;
1609 else if (
pt < 500.0) {
1611 ATH_MSG_VERBOSE(
"Applying tight WP cuts to a high pt muon with (pt,eta) (" <<
pt <<
"," << mu.eta() <<
")");
1614 ATH_MSG_VERBOSE(
"Rho value " << rho <<
", required to be less than " << rhoCut <<
" unless -1, in which no cut is applied");
1616 if (rhoCut < 0.0)
return true;
1617 if (rho > rhoCut)
return false;
1624 ATH_MSG_VERBOSE(
"Not applying any tight WP cuts to a very high pt muon with (pt,eta) (" <<
pt <<
"," << mu.eta() <<
")");
1656 if (std::abs(
muon.eta()) > 2.0) {
1657 ATH_MSG_VERBOSE(
"Recalculating number of precision layers for combined muon");
1658 summary.nprecisionLayers = (summary.innerSmallHits > 1 || summary.innerLargeHits > 1)
1659 + (summary.middleSmallHits > 2 || summary.middleLargeHits > 2)
1660 + (summary.outerSmallHits > 2 || summary.outerLargeHits > 2);
1664 summary.nprecisionLayers = (summary.middleSmallHits > 2 || summary.middleLargeHits > 2)
1665 + (summary.outerSmallHits > 2 || summary.outerLargeHits > 2)
1666 + (summary.extendedSmallHits > 2 || summary.extendedLargeHits > 2);
1670 if (!eta1stgchits_acc.isAvailable(
muon) || !eta2stgchits_acc.isAvailable(
muon) || !mmhits_acc.isAvailable(
muon)) {
1671 ATH_MSG_FATAL(__FILE__ <<
":" << __LINE__ <<
" Failed to retrieve NSW hits!"
1672 <<
" (Please use DxAODs with p-tags >= p5834 OR set ExcludeNSWFromPrecisionLayers to True (tests only)");
1673 throw std::runtime_error(
"Failed to retrieve NSW hits");
1679 summary.nprecisionLayers += ((summary.etaLayer1STGCHits + summary.etaLayer2STGCHits) > 3 || summary.MMHits > 3);
1686 if (!
muon.parameter(value, param)) {
1687 ATH_MSG_FATAL(__FILE__ <<
":" << __LINE__ <<
" Failed to retrieve parameter " << param
1688 <<
" for muon with pT:" <<
muon.pt() *
MeVtoGeV <<
", eta:" <<
muon.eta() <<
", phi: " <<
muon.phi()
1689 <<
", q:" <<
muon.charge() <<
", author: " <<
muon.author());
1690 throw std::runtime_error(
"Failed to retrieve Parameter");
1705 if (summary.nprecisionLayers == 2)
1711 const xAOD::TrackParticle* CB_track = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
1712 const xAOD::TrackParticle* MS_track = mu.trackParticle(xAOD::Muon::MuonSpectrometerTrackParticle);
1714 ATH_MSG_VERBOSE(
"getResolutionCategory - No MS track available for muon. Using combined track.");
1715 MS_track = mu.trackParticle(xAOD::Muon::CombinedTrackParticle);
1719 const float etaMS = MS_track->
eta();
1720 const float etaCB = CB_track->
eta();
1721 const float phiMS = MS_track->
phi();
1725 if ((summary.isSmallGoodSectors && summary.innerSmallHits < 3) || (!summary.isSmallGoodSectors && summary.innerLargeHits < 3))
1728 if ((summary.isSmallGoodSectors && summary.middleSmallHits < 3) || (!summary.isSmallGoodSectors && summary.middleLargeHits < 3))
1731 if ((summary.isSmallGoodSectors && summary.outerSmallHits < 3 && summary.extendedSmallHits < 3) ||
1732 (!summary.isSmallGoodSectors && summary.outerLargeHits < 3 && summary.extendedLargeHits < 3))
1735 if (!
isRun3() && (std::abs(
etaMS) > 2.0 || std::abs(etaCB) > 2.0) && summary.cscUnspoiledEtaHits == 0)
1738 if ((1.01 < std::abs(
etaMS) && std::abs(
etaMS) < 1.1) || (1.01 < std::abs(etaCB) && std::abs(etaCB) < 1.1))
1744 if (
isBEE(
etaMS, phiMS) || (std::abs(etaCB) > 1.4 && (summary.extendedSmallHits > 0 || summary.extendedSmallHoles > 0))) {
1745 if (summary.extendedSmallHits < 3 && summary.middleSmallHits >= 3 && summary.outerSmallHits >= 3)
1750 if (!summary.isSmallGoodSectors)
1767 unsigned int runNumber = 0;
1769 else runNumber = eventInfo->runNumber();
1773 ATH_MSG_DEBUG(
"The current event is a data event. Return runNumber.");
1779 static std::atomic<bool> issuedWarningPRW{
false};
1781 unsigned int rn = acc_rnd(*eventInfo);
1782 if (rn != 0)
return acc_rnd(*eventInfo);
1784 if (!issuedWarningPRW) {
1786 issuedWarningPRW =
true;
1791 if (needOnlyCorrectYear) {
1792 if (runNumber < 300000) {
1793 ATH_MSG_DEBUG(
"Random run number not available and this is mc16a or mc20a, returning dummy 2016 run number.");
1796 }
else if (runNumber < 310000) {
1797 ATH_MSG_DEBUG(
"Random run number not available and this is mc16d or mc20d, returning dummy 2017 run number.");
1800 }
else if (runNumber < 320000) {
1801 ATH_MSG_DEBUG(
"Random run number not available and this is mc16e or mc20e, returning dummy 2018 run number.");
1804 }
else if (runNumber < 600000) {
1805 ATH_MSG_DEBUG(
"Random run number not available and this is mc21/mc23, for the time being we're returing a dummy run number.");
1808 ATH_MSG_DEBUG(
"Detected some run 4 / phase II runnumber "<<runNumber<<
". ");
1812 ATH_MSG_FATAL(
"Random run number not available, fallback option of using runNumber failed since "<<runNumber<<
" cannot be recognised");
1813 throw std::runtime_error(
"MuonSelectionTool() - need RandomRunNumber decoration by the PileupReweightingTool");
1816 ATH_MSG_FATAL(
"Failed to find the RandomRunNumber decoration by the PileupReweightingTool");
1817 throw std::runtime_error(
"MuonSelectionTool() - need RandomRunNumber decoration from PileupReweightingTool");
1823 static constexpr std::array<float, 2> BIS78_eta{1.05, 1.3};
1824 static constexpr std::array<float, 8> BIS78_phi{0.21, 0.57, 1.00, 1.33, 1.78, 2.14, 2.57, 2.93};
1826 float abs_eta = std::abs(
eta);
1827 float abs_phi = std::abs(
phi);
1829 if (abs_eta >= BIS78_eta[0] && abs_eta <= BIS78_eta[1]) {
1830 if ((abs_phi >= BIS78_phi[0] && abs_phi <= BIS78_phi[1]) || (abs_phi >= BIS78_phi[2] && abs_phi <= BIS78_phi[3]) ||
1831 (abs_phi >= BIS78_phi[4] && abs_phi <= BIS78_phi[5]) || (abs_phi >= BIS78_phi[6] && abs_phi <= BIS78_phi[7])) {
1841 static constexpr std::array<float, 2> BEE_eta{1.440, 1.692};
1842 static constexpr std::array<float, 8> BEE_phi{0.301, 0.478, 1.086, 1.263, 1.872, 2.049, 2.657, 2.834};
1844 float abs_eta = std::abs(
eta);
1845 float abs_phi = std::abs(
phi);
1847 if (abs_eta >= BEE_eta[0] && abs_eta <= BEE_eta[1]) {
1848 if ((abs_phi >= BEE_phi[0] && abs_phi <= BEE_phi[1]) || (abs_phi >= BEE_phi[2] && abs_phi <= BEE_phi[3]) ||
1849 (abs_phi >= BEE_phi[4] && abs_phi <= BEE_phi[5]) || (abs_phi >= BEE_phi[6] && abs_phi <= BEE_phi[7])) {
1859 static constexpr std::array<float, 6> BMG_eta{0.35, 0.47, 0.68, 0.80, 0.925, 1.04};
1860 static constexpr std::array<float, 4> BMG_phi{-1.93, -1.765, -1.38, -1.21};
1862 float abs_eta = std::abs(
eta);
1864 if ((abs_eta >= BMG_eta[0] && abs_eta <= BMG_eta[1]) || (abs_eta >= BMG_eta[2] && abs_eta <= BMG_eta[3]) ||
1865 (abs_eta >= BMG_eta[4] && abs_eta <= BMG_eta[5])) {
1866 if ((
phi >= BMG_phi[0] &&
phi <= BMG_phi[1]) || (
phi >= BMG_phi[2] &&
phi <= BMG_phi[3])) {
return true; }
1875 ATH_MSG_ERROR(
"TightNNScore calculation is disabled. Please set the property CalculateTightNNScore to true.");
1876 throw std::runtime_error(
"cannot calculate TightNNScore");
1879 if (mu.muonType() != xAOD::Muon::Combined)
return -999;
1880 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
1881 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle);
1882 if(!idtrack || !metrack)
return -999;
1884 if (
getQuality(mu) > xAOD::Muon::Medium)
return -999;
1886 if (std::abs(mu.eta())>2.5)
return -999;
1887 if(mu.pt()<4000.)
return -999;
1889 std::vector<float> input_features;
1891 int mu_author=mu.author();
1893 float mu_scatteringCurvatureSignificance=0.;
1894 retrieveParam(mu, mu_scatteringCurvatureSignificance, xAOD::Muon::scatteringCurvatureSignificance);
1895 float mu_scatteringNeighbourSignificance=0.;
1896 retrieveParam(mu, mu_scatteringNeighbourSignificance, xAOD::Muon::scatteringNeighbourSignificance);
1897 float mu_momentumBalanceSignificance=0.;
1898 retrieveParam(mu, mu_momentumBalanceSignificance, xAOD::Muon::momentumBalanceSignificance);
1900 float mu_reducedChi2=mu.primaryTrackParticle()->chiSquared() / mu.primaryTrackParticle()->numberDoF();
1903 float mu_spectrometerFieldIntegral=0.;
1904 retrieveParam(mu, mu_spectrometerFieldIntegral, xAOD::Muon::spectrometerFieldIntegral);
1905 float mu_segmentDeltaEta=0;
1906 retrieveParam(mu, mu_segmentDeltaEta, xAOD::Muon::segmentDeltaEta);
1907 uint8_t mu_numberOfPixelHits=0;
1909 uint8_t mu_numberOfPixelDeadSensors=0;
1926 input_features = {(
float)mu_author,
1928 mu_scatteringCurvatureSignificance,
1929 mu_scatteringNeighbourSignificance,
1930 mu_momentumBalanceSignificance,
1931 mu_qOverPSignificance,
1935 mu_spectrometerFieldIntegral,
1937 (
float)mu_numberOfPixelHits,
1938 (
float)mu_numberOfPixelDeadSensors,
1939 (
float)mu_innerLargeHits,
1940 (
float)mu_innerSmallHits,
1941 (
float)mu_middleLargeHits,
1942 (
float)mu_middleSmallHits,
1943 (
float)mu_outerLargeHits,
1944 (
float)mu_outerSmallHits};
1948 uint8_t mu_phiLayer1STGCHits=0;
1950 uint8_t mu_phiLayer2STGCHits=0;
1952 uint8_t mu_etaLayer1STGCHits=0;
1954 uint8_t mu_etaLayer2STGCHits=0;
1958 input_features = {(
float)mu_author,
1960 mu_scatteringCurvatureSignificance,
1961 mu_scatteringNeighbourSignificance,
1962 mu_momentumBalanceSignificance,
1963 mu_qOverPSignificance,
1967 mu_spectrometerFieldIntegral,
1969 (
float)mu_numberOfPixelHits,
1970 (
float)mu_numberOfPixelDeadSensors,
1971 (
float)mu_innerLargeHits,
1972 (
float)mu_innerSmallHits,
1973 (
float)mu_middleLargeHits,
1974 (
float)mu_middleSmallHits,
1975 (
float)mu_outerLargeHits,
1976 (
float)mu_outerSmallHits,
1977 (
float)mu_phiLayer1STGCHits,
1978 (
float)mu_phiLayer2STGCHits,
1979 (
float)mu_etaLayer1STGCHits,
1980 (
float)mu_etaLayer2STGCHits,
1985 std::vector<int64_t> inputShape = {1,
static_cast<int64_t
>(input_features.size())};
1988 inputData[
"flatten_input"] = std::make_pair(
1989 inputShape, std::move(input_features)
1993 outputData[
"sequential"] = std::make_pair(
1994 std::vector<int64_t>{1, 1}, std::vector<float>{}
1997 if (!
m_onnxTool->inference(inputData, outputData).isSuccess()) {
2001 const auto& variant = outputData[
"sequential"].second;
2002 if (std::holds_alternative<std::vector<float>>(variant)) {
2003 const auto&
vec = std::get<std::vector<float>>(variant);
2014 ATH_MSG_DEBUG(
"TightNNScore for muon with pT " << mu.pt() <<
" GeV, eta " << mu.eta() <<
" is " <<
score);
Scalar eta() const
pseudorapidity method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
std::vector< size_t > vec
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
SG::ConstAccessor< T, ALLOC > ConstAccessor
SG::Accessor< T, ALLOC > Accessor
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
void setCutResult(const std::string &cutName, bool cutResult)
Set the result of a cut, based on the cut name (safer)
@ IS_SIMULATION
true: simulation, false: data
Class providing the definition of the 4-vector interface.
float theta() const
Returns the parameter, which has range 0 to .
float numberDoF() const
Returns the number of degrees of freedom of the overall track or vertex fit as float.
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .)
const ParametersCovMatrix_t definingParametersCovMatrix() const
Returns the 5x5 symmetric matrix containing the defining parameters covariance matrix.
float qOverP() const
Returns the parameter.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
float chiSquared() const
Returns the of the overall track fit.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
float charge() const
Returns the charge.
std::map< std::string, InferenceData > OutputDataMap
std::map< std::string, InferenceData > InputDataMap
Select isolated Photons, Electrons and Muons.
Muon::MuonStationIndex::ChIndex ChIdx
constexpr int toInt(const EnumType enumVal)
ChIndex
enum to classify the different chamber layers in the muon spectrometer
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
@ Muon
The object is a muon.
setRcore setEtHad setFside pt
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Muon_v1 Muon
Reference the current persistent version:
MuonSegment_v1 MuonSegment
Reference the current persistent version:
@ numberOfPixelHoles
number of pixel layers on track with absence of hits [unit8_t].
@ numberOfPrecisionLayers
layers with at least 3 hits [unit8_t].
@ numberOfTRTHits
number of TRT hits [unit8_t].
@ numberOfSCTDeadSensors
number of dead SCT sensors crossed [unit8_t].
@ numberOfPrecisionHoleLayers
layers with holes AND no hits [unit8_t].
@ numberOfSCTHits
number of hits in SCT [unit8_t].
@ numberOfGoodPrecisionLayers
layers with at least 3 hits that are not deweighted [uint8_t]
@ numberOfPixelHits
these are the pixel hits, including the b-layer [unit8_t].
@ numberOfTRTOutliers
number of TRT outliers [unit8_t].
@ numberOfPixelDeadSensors
number of dead pixel sensors crossed [unit8_t].
@ numberOfSCTHoles
number of SCT holes [unit8_t].
@ SiSpacePointsSeedMaker_LargeD0
@ middleSmallHoles
number of precision holes in the middle small layer
@ outerSmallHits
number of precision hits in the outer small layer
@ middleSmallHits
number of precision hits in the middle small layer
@ middleClosePrecisionHits
number of close precision hits in the middle layer
@ outerLargeHits
number of precision hits in the outer large layer
@ middleLargeHits
number of precision hits in the middle large layer
@ outerClosePrecisionHits
number of close precision hits in the outer layer
@ isSmallGoodSectors
if non-deweighted track chambers are small
@ extendedSmallHits
number of precision hits in the extended small layer
@ extendedLargeHits
number of precision hits in the extended large layer
@ phiLayer1STGCHits
number of phi hits in the first STGC trigger layer (STGC1)
@ outerLargeHoles
number of precision holes in the outer large layer
@ extendedSmallHoles
number of precision holes in the extended small layer
@ innerLargeHits
number of precision hits in the inner large layer
@ middleLargeHoles
number of precision holes in the middle large layer
@ etaLayer2STGCHits
number of eta hits in the second STGC trigger layer (STGC2)
@ etaLayer1STGCHits
number of eta hits in the first STGC trigger layer (STGC1)
@ phiLayer2STGCHits
number of phi hits in the second STGC trigger layer (STGC2)
@ combinedTrackOutBoundsPrecisionHits
total out-of-bounds hits on the combined track
@ cscUnspoiledEtaHits
number of unspoiled CSC eta clusters on track
@ outerSmallHoles
number of precision holes in the outer small layer
@ innerSmallHits
number of precision hits in the inner small layer
Tell the compiler to optimize assuming that FP may trap.
#define CXXUTILS_TRAPPING_FP