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())] <
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");
66 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.")
78 "Not using allAuthors variable as currently missing in many derivations; LowPtEfficiency working point will always return "
79 "false, but this is expected at the moment. Have a look here: "
80 "https://twiki.cern.ch/twiki/bin/view/Atlas/MuonSelectionToolR21#New_LowPtEfficiency_working_poin");
84 ATH_MSG_INFO(
"You have opted to select only 3-station muons in the high-pT selection! "
85 <<
"Please feed 'HighPt3Layers' to the 'WorkingPoint' property to retrieve the appropriate scale-factors");
89 ATH_MSG_WARNING(
"No cut-based selection is defined for segment-tagged muons in the Low-pT working point. "
90 <<
"Please set UseMVALowPt=true if you want to try the UseSegmentTaggedLowPt=true option.");
94 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).");
95 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 m_acceptInfo.addCut(
"Eta",
"Selection of muons according to their pseudorapidity");
100 m_acceptInfo.addCut(
"IDHits",
"Selection of muons according to whether they passed the MCP ID Hit cuts");
101 m_acceptInfo.addCut(
"Preselection",
"Selection of muons according to their type/author");
102 m_acceptInfo.addCut(
"Quality",
"Selection of muons according to their tightness");
106 "Invalid quality (i.e. selection WP) set: "
108 <<
" - it must be an integer between 0 and 5! (0=Tight, 1=Medium, 2=Loose, 3=Veryloose, 4=HighPt, 5=LowPtEfficiency)");
109 return StatusCode::FAILURE;
112 ATH_MSG_ERROR(
"Cannot use lowPt working point if allAuthors is not available!");
113 return StatusCode::FAILURE;
117 ATH_MSG_FATAL(
"CaloScoreWP property must be set to 1, 2, 3 or 4");
118 return StatusCode::FAILURE;
122 ATH_MSG_INFO(
"Initialising tight working point histograms...");
123 std::string tightWP_rootFile_fullPath;
128 Form(
"MuonSelectorTools/%s/muonSelection_tightWPHisto.root",
m_calibration_version.value().c_str()));
131 ATH_MSG_INFO(
"Reading muon tight working point histograms from " << tightWP_rootFile_fullPath);
133 std::unique_ptr<TFile>
file(TFile::Open(tightWP_rootFile_fullPath.c_str(),
"READ"));
135 if (!
file->IsOpen()) {
136 ATH_MSG_ERROR(
"Cannot read tight working point file from " << tightWP_rootFile_fullPath);
137 return StatusCode::FAILURE;
151 ATH_MSG_INFO(
"Reading bad muon veto cut functions from " << BMVcutFile_fullPath);
153 std::unique_ptr<TFile> BMVfile(TFile::Open(BMVcutFile_fullPath.c_str(),
"READ"));
155 if (!BMVfile->IsOpen()) {
156 ATH_MSG_ERROR(
"Cannot read bad muon veto cut function file from " << BMVcutFile_fullPath);
157 return StatusCode::FAILURE;
167 return StatusCode::FAILURE;
173 auto loadLowPtMVABDTModel = [&](
const std::string& calibFile,
174 std::unique_ptr<MVAUtils::BDT>& bdt,
175 std::vector<double>& means,
176 std::vector<double>& scales) -> StatusCode {
178 std::unique_ptr<TFile> rootFile(TFile::Open(modelFile.c_str(),
"READ"));
180 if (!rootFile || rootFile->IsZombie()) {
181 ATH_MSG_ERROR(
"Failed to open model file for Run-3 LowPtMVA: " << modelFile);
182 return StatusCode::FAILURE;
186 auto* bdt_tree =
static_cast<TTree*
>(rootFile->Get(
"xgboost"));
187 bdt = std::make_unique<MVAUtils::BDT>(bdt_tree);
190 std::unique_ptr<TTree> scaler_tree(
static_cast<TTree*
>(rootFile->Get(
"scaler")));
191 std::vector<double>* mean_ptr =
nullptr;
192 std::vector<double>* scale_ptr =
nullptr;
193 scaler_tree->SetBranchAddress(
"mean", &mean_ptr);
194 scaler_tree->SetBranchAddress(
"scale", &scale_ptr);
196 for (Long64_t i = 0; i < scaler_tree->GetEntries(); ++i) {
197 scaler_tree->GetEntry(i);
198 for (
size_t j = 0; j < mean_ptr->size(); ++j) {
199 means.push_back((*mean_ptr)[j]);
200 scales.push_back((*scale_ptr)[j]);
203 return StatusCode::SUCCESS;
207 ATH_CHECK(loadLowPtMVABDTModel(
"MuonSelectorTools/260130_LowPtMVA_r24run3/xgb_lowPtMVA_MuidCO_wScaler.root",
211 ATH_CHECK(loadLowPtMVABDTModel(
"MuonSelectorTools/260130_LowPtMVA_r24run3/xgb_lowPtMVA_MuGirl_wScaler.root",
222 auto make_mva_reader = [](TString file_path) {
223 std::vector<std::string> mva_var_names{
"momentumBalanceSignificance",
224 "scatteringCurvatureSignificance",
225 "scatteringNeighbourSignificance",
227 "middleLargeHoles+middleSmallHoles",
228 "muonSegmentDeltaEta",
229 "muonSeg1ChamberIdx",
230 "muonSeg2ChamberIdx"};
231 std::unique_ptr<TMVA::Reader> reader = std::make_unique<TMVA::Reader>(mva_var_names);
232 reader->BookMVA(
"BDTG", file_path);
248 auto make_mva_reader_MuTagIMO = [](TString file_path,
bool useSeg2ChamberIndex) {
249 std::vector<std::string> mva_var_names;
250 if (useSeg2ChamberIndex) mva_var_names.push_back(
"muonSeg2ChamberIndex");
251 mva_var_names.push_back(
"muonSeg1ChamberIndex");
252 mva_var_names.push_back(
"muonSeg1NPrecisionHits");
253 mva_var_names.push_back(
"muonSegmentDeltaEta");
254 mva_var_names.push_back(
"muonSeg1GlobalR");
255 mva_var_names.push_back(
"muonSeg1Chi2OverDoF");
256 mva_var_names.push_back(
"muonSCS");
258 std::unique_ptr<TMVA::Reader> reader = std::make_unique<TMVA::Reader>(mva_var_names);
259 reader->BookMVA(
"BDT", file_path);
280 return StatusCode::SUCCESS;
286 ATH_MSG_ERROR(
" getHist(...) TFile is nullptr! Check that the Tight cut map is loaded correctly");
287 return StatusCode::FAILURE;
289 TH1* h_ptr =
nullptr;
290 file->GetObject(histName.c_str(), h_ptr);
295 return StatusCode::FAILURE;
297 hist = std::unique_ptr<TH1>{h_ptr};
298 hist->SetDirectory(
nullptr);
299 ATH_MSG_INFO(
"Successfully read tight working point histogram: " << hist->GetName());
301 return StatusCode::SUCCESS;
316 ATH_MSG_FATAL(
"accept(...) Failed to cast particle to muon");
327 static std::atomic<bool> checkDone{
false};
335 <<
" while on-the fly check for runNumber "<<
getRunNumber(
true)<<
" indicates isRun3Geo="<<
isRun3(
true));
341 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");
345 ATH_MSG_WARNING(
"For Run3, Tight WP is supported only when ExcludeNSWFromPrecisionLayers=False and RecalcPrecisionLayerswNSW=True");
358 if (mu.muonType() == xAOD::Muon::MuonType::Combined)
360 else if (mu.muonType() == xAOD::Muon::MuonType::MuonStandAlone)
362 else if (mu.muonType() == xAOD::Muon::MuonType::SegmentTagged)
364 else if (mu.muonType() == xAOD::Muon::MuonType::CaloTagged)
366 else if (mu.muonType() == xAOD::Muon::MuonType::SiliconAssociatedForwardMuon)
377 if (std::abs(mu.eta()) >=
m_maxEta) {
393 if (!passIDCuts || !passMuonCuts) {
return acceptData; }
396 xAOD::Muon::Quality thisMu_quality =
getQuality(mu);
397 bool thisMu_highpt =
false;
399 bool thisMu_lowptE =
false;
402 ATH_MSG_VERBOSE(
"Muon quality: " << thisMu_quality <<
" passes HighPt: " << thisMu_highpt
403 <<
" passes LowPtEfficiency: " << thisMu_lowptE);
405 if (
m_quality == 4 && !thisMu_highpt) {
return acceptData; }
406 if (
m_quality == 5 && !thisMu_lowptE) {
return acceptData; }
417 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
418 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::TrackParticleType::ExtrapolatedMuonSpectrometerTrackParticle);
419 if (!idtrack || !metrack) idPt = mePt = -1.;
421 mePt = metrack->
pt();
422 idPt = idtrack->
pt();
424 if (!mePt_acc.isAvailable(mu) || !idPt_acc.isAvailable(mu)) {
425 ATH_MSG_FATAL(
"The muon with pT " << mu.pt() *
MeVtoGeV <<
" eta: " << mu.eta() <<
", phi:" << mu.phi()
426 <<
" q:" << mu.charge() <<
", author:" << mu.author()
427 <<
" is not decorated with calibrated momenta. Please fix");
428 throw std::runtime_error(
"MuonSelectionTool() - qOverP significance calculation failed");
441 <<
" Momentum dependent cuts are disabled. Return 0.");
444 const xAOD::TrackParticle* idtrack =
muon.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
445 const xAOD::TrackParticle* metrack =
muon.trackParticle(xAOD::Muon::TrackParticleType::ExtrapolatedMuonSpectrometerTrackParticle);
446 if (!idtrack || !metrack) {
447 ATH_MSG_VERBOSE(
"No ID / MS track. Return dummy large value of 1 mio");
450 float mePt{-1.}, idPt{-1.};
453 const float meP = mePt / std::sin(metrack->
theta());
454 const float idP = idPt / std::sin(idtrack->
theta());
457 return std::abs((metrack->
charge() / meP) - (idtrack->
charge() / idP)) / qOverPsigma;
462 <<
"Momentum dependent cuts are disabled. Return 0.");
465 float mePt{-1.}, idPt{-1.};
467 return std::abs(idPt - mePt) /
muon.pt();
473 if (mu.muonType() == xAOD::Muon::MuonType::SegmentTagged) {
476 if (std::abs(mu.eta()) < 0.1) {
478 return xAOD::Muon::Quality::Loose;
480 ATH_MSG_VERBOSE(
"Do not allow segment-tagged muon at |eta| > 0.1 - return VeryLoose");
481 return xAOD::Muon::Quality::VeryLoose;
486 if (mu.muonType() == xAOD::Muon::MuonType::CaloTagged) {
491 return xAOD::Muon::Quality::Loose;
499 if (mu.muonType() == xAOD::Muon::MuonType::Combined) {
501 if (mu.author() == xAOD::Muon::Author::STACO) {
503 return xAOD::Muon::Quality::VeryLoose;
511 ATH_MSG_VERBOSE(
"Muon has out-of-bounds precision hits - return VeryLoose");
512 return xAOD::Muon::Quality::VeryLoose;
516 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
517 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::TrackParticleType::ExtrapolatedMuonSpectrometerTrackParticle);
521 const float reducedChi2 = mu.primaryTrackParticle()->chiSquared() / mu.primaryTrackParticle()->numberDoF();
524 ATH_MSG_VERBOSE(
"number of precision layers = " << (
int)summary.nprecisionLayers);
529 if (summary.nprecisionLayers > 1 && reducedChi2 < 8 && std::abs(qOverPsignif) < 7) {
532 return xAOD::Muon::Quality::Tight;
536 ATH_MSG_VERBOSE(
"Muon did not pass requirements for tight combined muon");
540 (summary.nprecisionLayers > 1 ||(summary.nprecisionLayers == 1 && summary.nprecisionHoleLayers < 2 && std::abs(mu.eta()) < 0.1))
544 return xAOD::Muon::Quality::Medium;
547 ATH_MSG_VERBOSE(
"Muon did not pass requirements for medium combined muon");
553 if ((summary.nprecisionLayers > 1 ||
554 (summary.nprecisionLayers == 1 && summary.nprecisionHoleLayers < 2 && std::abs(mu.eta()) < 0.1))) {
559 return xAOD::Muon::Quality::Medium;
562 return xAOD::Muon::Quality::Loose;
568 if ((
m_disablePtCuts || mu.pt() *
MeVtoGeV < 7.) && std::abs(mu.eta()) < 1.3 && summary.nprecisionLayers > 0 &&
569 (mu.author() == xAOD::Muon::Author::MuGirl && mu.isAuthor(xAOD::Muon::Author::MuTagIMO))) {
570 ATH_MSG_VERBOSE(
"Muon passed selection for loose working point at low pT");
571 return xAOD::Muon::Quality::Loose;
575 ATH_MSG_VERBOSE(
"Did not pass selections for combined muon - returning VeryLoose");
576 return xAOD::Muon::Quality::VeryLoose;
580 if (mu.author() == xAOD::Muon::Author::MuidSA) {
583 if (std::abs(mu.eta()) > 2.5) {
584 ATH_MSG_VERBOSE(
"number of precision layers = " << (
int)summary.nprecisionLayers);
587 if (summary.nprecisionLayers > 2 && !
m_toroidOff) {
589 return xAOD::Muon::Quality::Medium;
594 ATH_MSG_VERBOSE(
"Muon did not pass selection for medium stand-alone muon - return VeryLoose");
595 return xAOD::Muon::Quality::VeryLoose;
599 if (mu.muonType() == xAOD::Muon::MuonType::SiliconAssociatedForwardMuon) {
602 const xAOD::TrackParticle* cbtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
603 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::TrackParticleType::ExtrapolatedMuonSpectrometerTrackParticle);
605 if (cbtrack && metrack) {
606 if (std::abs(cbtrack->
eta()) > 2.5) {
607 ATH_MSG_VERBOSE(
"number of precision layers = " << (
int)summary.nprecisionLayers);
609 if (summary.nprecisionLayers > 2 && !
m_toroidOff) {
610 if (mu.trackParticle(xAOD::Muon::TrackParticleType::Primary) == mu.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle) &&
613 "SiliconForwardAssociated muon has ID track as primary track particle. "
614 <<
"This is a bug fixed starting with xAODMuon-00-17-07, which should be present in this release. "
615 <<
"Please report this to the Muon CP group!");
618 return xAOD::Muon::Quality::Medium;
624 ATH_MSG_VERBOSE(
"Muon did not pass selection for medium silicon-associated forward muon - return VeryLoose");
625 return xAOD::Muon::Quality::VeryLoose;
628 ATH_MSG_VERBOSE(
"Muon did not pass selection for loose/medium/tight for any muon type - return VeryLoose");
629 return xAOD::Muon::Quality::VeryLoose;
636 static const SG::AuxElement::Accessor<char> isLRTmuon(
"isLRT");
637 if (isLRTmuon.isAvailable(mu)) {
638 if (isLRTmuon(mu))
return true;
641 static const SG::AuxElement::Accessor<uint64_t> patternAcc(
"patternRecoInfo");
642 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
644 if(!patternAcc.isAvailable(*idtrack)) {
645 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.");
646 throw std::runtime_error(
"MuonSelectionTool() - isLRT decor and patternRecoInfo both unavailable for a muon.");
648 std::bitset<xAOD::NumberOfTrackRecoInfo> patternBitSet(patternAcc(*idtrack));
654 if (mu.author() == xAOD::Muon::Author::MuidSA && std::abs(mu.eta()) > 2.5) {
656 }
else if (mu.muonType() == xAOD::Muon::MuonType::SiliconAssociatedForwardMuon) {
657 const xAOD::TrackParticle* cbtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
658 if (cbtrack && std::abs(cbtrack->
eta()) > 2.5) {
return true; }
661 if (mu.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle))
662 return passedIDCuts(*mu.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle));
663 else if (mu.primaryTrackParticle())
670 if (mu.muonType() != xAOD::Muon::MuonType::Combined)
return false;
672 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
673 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::TrackParticleType::ExtrapolatedMuonSpectrometerTrackParticle);
674 const xAOD::TrackParticle* cbtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
679 bool IsBadMuon =
false;
680 if (idtrack && metrack && cbtrack) {
682 double qOverP_ID = idtrack->
qOverP();
684 double qOverP_ME = metrack->
qOverP();
686 double qOverP_CB = cbtrack->
qOverP();
699 double IdCbRatio = std::abs((qOverPerr_ID / qOverP_ID) / (qOverPerr_CB / qOverP_CB));
700 double MeCbRatio = std::abs((qOverPerr_ME / qOverP_ME) / (qOverPerr_CB / qOverP_CB));
701 IsBadMuon = (IdCbRatio < 0.8 || MeCbRatio < 0.8 || IsBadMuon);
705 double IdCbRatio = std::abs((qOverPerr_ID / qOverP_ID) / (qOverPerr_CB / qOverP_CB));
706 double MeCbRatio = std::abs((qOverPerr_ME / qOverP_ME) / (qOverPerr_CB / qOverP_CB));
707 IsBadMuon = (IdCbRatio < 0.8 || MeCbRatio < 0.8);
716 xAOD::Muon::Quality thisMu_quality =
getQuality(mu);
730 if (mu.muonType() != xAOD::Muon::MuonType::Combined) {
735 if (mu.muonType() != xAOD::Muon::MuonType::Combined && mu.muonType() != xAOD::Muon::MuonType::SegmentTagged) {
736 ATH_MSG_VERBOSE(
"Muon is not combined or segment-tagged - fail low-pT");
743 if (mu.author() != xAOD::Muon::Author::MuGirl && mu.author() != xAOD::Muon::Author::MuidCo) {
748 if (mu.author() != xAOD::Muon::Author::MuGirl && mu.author() != xAOD::Muon::Author::MuidCo && mu.author() != xAOD::Muon::Author::MuTagIMO) {
749 ATH_MSG_VERBOSE(
"Muon is neither MuGirl / MuidCo / MuTagIMO - fail low-pT");
757 if (thisMu_quality <= xAOD::Muon::Quality::Medium) {
767 if (!
m_useMVALowPt && std::abs(mu.eta()) > 1.55 && thisMu_quality > xAOD::Muon::Quality::Medium) {
768 ATH_MSG_VERBOSE(
"Not using MVA selection, failing low-pT selection due to medium requirement in forward region");
776 ATH_MSG_VERBOSE(
"Muon has out-of-bounds precision hits - fail low-pT");
781 if (mu.muonType() == xAOD::Muon::MuonType::Combined) {
784 uint nStationsCut = (std::abs(mu.eta()) > 1.3 && std::abs(mu.eta()) < 1.55) ? 2 : 1;
785 if (summary.nprecisionLayers < nStationsCut) {
786 ATH_MSG_VERBOSE(
"number of precision layers = " << (
int)summary.nprecisionLayers <<
" is lower than cut value " << nStationsCut
787 <<
" - fail low-pT");
794 if (mu.author() == xAOD::Muon::Author::MuGirl && !mu.isAuthor(xAOD::Muon::Author::MuTagIMO)) {
795 ATH_MSG_VERBOSE(
"MuGirl muon is not confirmed by MuTagIMO - fail low-pT");
815 float momentumBalanceSignificance{0.}, scatteringCurvatureSignificance{0.}, scatteringNeighbourSignificance{0.};
817 retrieveParam(mu, momentumBalanceSignificance, xAOD::Muon::ParamDef::momentumBalanceSignificance);
818 retrieveParam(mu, scatteringCurvatureSignificance, xAOD::Muon::ParamDef::scatteringCurvatureSignificance);
819 retrieveParam(mu, scatteringNeighbourSignificance, xAOD::Muon::ParamDef::scatteringNeighbourSignificance);
821 ATH_MSG_VERBOSE(
"momentum balance significance: " << momentumBalanceSignificance);
822 ATH_MSG_VERBOSE(
"scattering curvature significance: " << scatteringCurvatureSignificance);
823 ATH_MSG_VERBOSE(
"scattering neighbour significance: " << scatteringNeighbourSignificance);
825 if (std::abs(momentumBalanceSignificance) > 3. || std::abs(scatteringCurvatureSignificance) > 3. ||
826 std::abs(scatteringNeighbourSignificance) > 3.) {
837 std::vector<const xAOD::MuonSegment*> segments_sorted;
838 segments_sorted.reserve(mu.nMuonSegments());
840 for (
unsigned int i = 0; i < mu.nMuonSegments(); i++) {
841 if (!mu.muonSegment(i))
842 ATH_MSG_WARNING(
"The muon reports more segments than are available. Please report this to the muon software community!");
844 segments_sorted.push_back(mu.muonSegment(i));
847 std::sort(segments_sorted.begin(), segments_sorted.end(), chamberIndexCompare);
849 return segments_sorted;
855 ATH_MSG_VERBOSE(
"LowPt WP currently not supported for run3 if not in expert mode");
864 float momentumBalanceSig{-1}, CurvatureSig{-1}, energyLoss{-1}, muonSegmentDeltaEta{-1}, scatteringNeigbour{-1};
865 retrieveParam(mu, momentumBalanceSig, xAOD::Muon::ParamDef::momentumBalanceSignificance);
866 retrieveParam(mu, CurvatureSig, xAOD::Muon::ParamDef::scatteringCurvatureSignificance);
867 retrieveParam(mu, scatteringNeigbour, xAOD::Muon::ParamDef::scatteringNeighbourSignificance);
868 retrieveParam(mu, energyLoss, xAOD::Muon::ParamDef::EnergyLoss);
869 retrieveParam(mu, muonSegmentDeltaEta, xAOD::Muon::ParamDef::segmentDeltaEta);
875 float seg1ChamberIdx{-1.}, seg2ChamberIdx{-1.}, middleHoles{-1.}, seg1NPrecisionHits{-1.}, seg1GlobalR{-1.}, seg1Chi2OverDoF{-1.};
879 if (mu.author() == xAOD::Muon::Author::MuTagIMO && muonSegments.size() == 0)
880 ATH_MSG_WARNING(
"passedLowPtEfficiencyMVACut - found segment-tagged muon with no segments!");
883 seg1ChamberIdx = (!muonSegments.empty()) ?
toInt(muonSegments[0]->chamberIndex()) : -9;
884 seg2ChamberIdx = (muonSegments.size() > 1) ?
toInt(muonSegments[1]->chamberIndex()) : -9;
887 if (mu.author() == xAOD::Muon::Author::MuTagIMO) {
888 seg1NPrecisionHits = (!muonSegments.empty()) ? muonSegments[0]->nPrecisionHits() : -1;
889 seg1GlobalR = (!muonSegments.empty())
890 ? std::hypot(muonSegments[0]->
x(), muonSegments[0]->
y(), muonSegments[0]->
z())
892 seg1Chi2OverDoF = (!muonSegments.empty()) ? muonSegments[0]->chiSquared() / muonSegments[0]->numberDoF() : -1;
905 std::vector<float> var_vector;
906 if (mu.author() == xAOD::Muon::Author::MuidCo || mu.author() == xAOD::Muon::Author::MuGirl) {
907 var_vector = {momentumBalanceSig, CurvatureSig, scatteringNeigbour, energyLoss,
908 middleHoles, muonSegmentDeltaEta, seg1ChamberIdx, seg2ChamberIdx};
910 if (std::abs(mu.eta()) >= 1.3)
911 var_vector = {seg2ChamberIdx, seg1ChamberIdx, seg1NPrecisionHits, muonSegmentDeltaEta,
912 seg1GlobalR, seg1Chi2OverDoF, std::abs(CurvatureSig)};
914 var_vector = {seg1ChamberIdx, seg1NPrecisionHits, muonSegmentDeltaEta,
915 seg1GlobalR, seg1Chi2OverDoF, std::abs(CurvatureSig)};
919 TMVA::Reader *reader_MUID, *reader_MUGIRL;
929 TMVA::Reader* reader_MUTAGIMO;
930 if (std::abs(mu.eta()) < 0.7)
932 else if (std::abs(mu.eta()) < 1.3)
938 float BDTdiscriminant;
940 if (mu.author() == xAOD::Muon::Author::MuidCo)
941 BDTdiscriminant = reader_MUID->EvaluateMVA(var_vector,
"BDTG");
942 else if (mu.author() == xAOD::Muon::Author::MuGirl)
943 BDTdiscriminant = reader_MUGIRL->EvaluateMVA(var_vector,
"BDTG");
945 BDTdiscriminant = reader_MUTAGIMO->EvaluateMVA(var_vector,
"BDT");
947 ATH_MSG_WARNING(
"Invalid author for low-pT MVA, failing selection...");
952 float BDTcut = (mu.author() == xAOD::Muon::Author::MuTagIMO) ? 0.12 : -0.6;
954 if (BDTdiscriminant > BDTcut) {
970 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
971 const xAOD::TrackParticle* metrk = mu.trackParticle(xAOD::Muon::TrackParticleType::ExtrapolatedMuonSpectrometerTrackParticle);
973 if (!primary || !idtrack || !metrk) {
974 ATH_MSG_VERBOSE(
"Missing primary, ID, or extrapolated MS track for Run-3 low-pT MVA; failing selection");
978 if (mu.author() == xAOD::Muon::Author::MuidCo) {
982 float momentumBalanceSig{-1}, CurvatureSig{-1}, scatteringNeigbour{-1};
983 int CaloMuonIDTag{-1};
984 uint8_t nPixelHits{0}, nTRTOutliers{0};
985 float reducedChi2{-1};
986 float etaBalanceSig{-1}, phiBalanceSig{-1};
987 float seg1ChamberIdx{-1};
989 retrieveParam(mu, momentumBalanceSig, xAOD::Muon::ParamDef::momentumBalanceSignificance);
990 retrieveParam(mu, CurvatureSig, xAOD::Muon::ParamDef::scatteringCurvatureSignificance);
991 retrieveParam(mu, scatteringNeigbour, xAOD::Muon::ParamDef::scatteringNeighbourSignificance);
996 mu.parameter(CaloMuonIDTag, xAOD::Muon::ParamDef::CaloMuonIDTag);
998 reducedChi2 = primary->chiSquared() / primary->numberDoF();
999 etaBalanceSig = std::abs(idtrack->
eta() - metrk->
eta());
1000 phiBalanceSig = std::abs(idtrack->
phi() - metrk->
phi());
1004 seg1ChamberIdx = (!muonSegments.empty()) ?
toInt(muonSegments[0]->chamberIndex()) : -9;
1010 etaBalanceSig = std::min(etaBalanceSig, 1.0f);
1011 reducedChi2 = std::min(reducedChi2, 100.0f);
1012 CurvatureSig = std::clamp(CurvatureSig, -10.0f, 10.0f);
1013 scatteringNeigbour = std::clamp(scatteringNeigbour, -10.0f, 10.0f);
1016 std::vector<float> muidCO_feature_vector = {
1017 static_cast<float>(nPixelHits),
1018 static_cast<float>(nTRTOutliers),
1019 static_cast<float>(CaloMuonIDTag),
1020 static_cast<float>(mu.energyLossType()),
1023 static_cast<float>(summary.nprecisionLayers),
1032 for (
size_t j=0; j<muidCO_feature_vector.size(); ++j){
1037 float bdt_score =
m_MuidCO->GetClassification(muidCO_feature_vector);
1038 ATH_MSG_VERBOSE(
" Low-pT MVA BDT score (MuidCo, Run-3) : " << bdt_score);
1042 float lowPtMVARun3_MuidCO_cut_value = 0.1300;
1043 return (bdt_score > lowPtMVARun3_MuidCO_cut_value);
1045 }
else if (mu.author() == xAOD::Muon::Author::MuGirl && mu.isAuthor(xAOD::Muon::Author::MuTagIMO)) {
1050 float momentumBalanceSig{-1}, seg1ChamberIdx{-1}, energyLoss{-1};
1051 int CaloMuonIDTag{-1};
1052 float reducedChi2{-1}, etaBalanceSig{-1}, phiBalanceSig{-1};
1053 float segmentDeltaEta{-1}, etaPrime{-1}, innerHits{-1};
1054 float middleHoles{-1}, nGoodPrecLayers{-1};
1055 float nprecisionHoleLayers{-1}, outerHoles{-1};
1057 retrieveParam(mu, momentumBalanceSig, xAOD::Muon::ParamDef::momentumBalanceSignificance);
1058 retrieveParam(mu, segmentDeltaEta, xAOD::Muon::ParamDef::segmentDeltaEta);
1059 retrieveParam(mu, energyLoss, xAOD::Muon::ParamDef::EnergyLoss);
1071 mu.parameter(CaloMuonIDTag, xAOD::Muon::ParamDef::CaloMuonIDTag);
1075 reducedChi2 = primary->chiSquared() / primary->numberDoF();
1076 etaBalanceSig = std::abs(idtrack->
eta() - metrk->
eta());
1077 etaPrime = std::abs((idtrack->
eta() - metrk->
eta())/mu.eta());
1078 phiBalanceSig = std::abs(idtrack->
phi() - metrk->
phi());
1082 seg1ChamberIdx = (!muonSegments.empty()) ?
toInt(muonSegments[0]->chamberIndex()) : -9;
1086 innerHits = summary.innerSmallHits + summary.innerLargeHits;
1087 nGoodPrecLayers = summary.nGoodPrecLayers;
1088 nprecisionHoleLayers = summary.nprecisionHoleLayers;
1091 etaBalanceSig = std::min(etaBalanceSig, 1.0f);
1092 reducedChi2 = std::min(reducedChi2, 100.0f);
1093 etaPrime = std::clamp(etaPrime, -10.0f, 10.0f);
1096 std::vector<float> muGirl_feature_vector = {
1097 static_cast<float>(nTRTOutliers),
1098 static_cast<float>(CaloMuonIDTag),
1107 nprecisionHoleLayers,
1108 static_cast<float>(summary.nprecisionLayers),
1118 for (
size_t j=0; j<muGirl_feature_vector.size(); ++j){
1123 float bdt_score =
m_MuGirl->GetClassification(muGirl_feature_vector);
1124 ATH_MSG_VERBOSE(
" Low-pT MVA BDT score (MuGirl, Run-3) : " << bdt_score);
1128 float lowPtMVARun3_MuGirl_cut_value = 0.1550;
1129 return (bdt_score > lowPtMVARun3_MuGirl_cut_value);
1131 ATH_MSG_WARNING(
"Invalid author for low-pT MVA in Run-3, failing selection...");
1140 if (mu.muonType() != xAOD::Muon::MuonType::Combined) {
1144 if (mu.author() == xAOD::Muon::Author::STACO) {
1153 ATH_MSG_VERBOSE(
"Muon has out-of-bounds precision hits - fail high-pT");
1162 ATH_MSG_VERBOSE(
"number of precision layers: " << (
int)summary.nprecisionLayers);
1170 const xAOD::TrackParticle* CB_track = mu.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
1171 const xAOD::TrackParticle* MS_track = mu.trackParticle(xAOD::Muon::TrackParticleType::MuonSpectrometerTrackParticle);
1173 ATH_MSG_VERBOSE(
"passedHighPtCuts - No MS track available for muon. Using combined track.");
1174 MS_track = mu.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
1177 if (MS_track && CB_track) {
1179 float phiMS = MS_track->
phi();
1180 float etaCB = CB_track->
eta();
1183 if (!
isRun3() && (std::abs(
etaMS) > 2.0 || std::abs(etaCB) > 2.0)) {
1184 if (summary.cscUnspoiledEtaHits == 0) {
1191 if (!
isRun3() && mu.eta() < -1.899 && std::abs(mu.phi()) < 0.211) {
1192 ATH_MSG_VERBOSE(
"Muon is in eta/phi region vetoed due to disabled chambers in MC - fail high-pT");
1197 if ((1.01 < std::abs(
etaMS) && std::abs(
etaMS) < 1.1) || (1.01 < std::abs(etaCB) && std::abs(etaCB) < 1.1)) {
1198 ATH_MSG_VERBOSE(
"Muon is in barrel/endcap overlap region - fail high-pT");
1228 if (summary.nprecisionLayers < 4) {
1229 ATH_MSG_VERBOSE(
"Muon is in BEE eta/phi region and does not have 4 precision layers - fail high-pT");
1233 if (std::abs(etaCB) > 1.4) {
1237 if (summary.nprecisionLayers < 4 && (summary.extendedSmallHits > 0 || summary.extendedSmallHoles > 0)) {
1238 ATH_MSG_VERBOSE(
"Muon is in BEE eta/phi region and does not have 4 precision layers - fail high-pT");
1243 ATH_MSG_WARNING(
"passedHighPtCuts - MS or CB track missing in muon! Failing High-pT selection...");
1248 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
1249 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::TrackParticleType::ExtrapolatedMuonSpectrometerTrackParticle);
1254 if (std::abs(qOverPsignif) > 7) {
1266 if (std::abs(mu.eta()) > 1.2 && summary.extendedSmallHits < 3 && summary.extendedLargeHits < 3) {
1274 if (summary.innerLargeHits == 0 && summary.middleLargeHits == 0 && summary.outerLargeHits == 0 &&
1275 summary.extendedLargeHits == 0 && summary.middleSmallHits > 2 &&
1276 (summary.outerSmallHits > 2 || summary.extendedSmallHits > 2)) {
1281 if (summary.innerSmallHits == 0 && summary.middleSmallHits == 0 && summary.outerSmallHits == 0 &&
1282 summary.extendedSmallHits == 0 && summary.middleLargeHits > 2 &&
1283 (summary.outerLargeHits > 2 || summary.extendedLargeHits > 2)) {
1290 if (summary.nprecisionLayers < 3) {
1291 ATH_MSG_VERBOSE(
"Muon has less than 3 precision layers - fail high-pT");
1296 if (summary.isSmallGoodSectors) {
1297 if (!(summary.innerSmallHits > 2 && summary.middleSmallHits > 2 &&
1298 (summary.outerSmallHits > 2 || summary.extendedSmallHits > 2))) {
1299 ATH_MSG_VERBOSE(
"Muon has small/large sectors overlap - fail high-pT");
1303 if (!(summary.innerLargeHits > 2 && summary.middleLargeHits > 2 &&
1304 (summary.outerLargeHits > 2 || summary.extendedLargeHits > 2))) {
1305 ATH_MSG_VERBOSE(
"Muon has small/large sectors overlap - fail high-pT");
1316 if (mu.muonType() != xAOD::Muon::MuonType::Combined)
return false;
1318 double start_cut = 3.0;
1319 double end_cut = 1.6;
1320 double abs_eta = std::abs(mu.eta());
1323 double p0(8.0), p1(0.), p2(0.);
1330 else if (abs_eta > 1.05 && abs_eta <= 1.3) {
1333 }
else if (abs_eta > 1.3 && abs_eta <= 1.7) {
1336 }
else if (abs_eta > 1.7 && abs_eta <= 2.0) {
1339 }
else if (abs_eta > 2.0) {
1350 else if (abs_eta > 1.05 && abs_eta <= 1.3) {
1353 }
else if (abs_eta > 1.3 && abs_eta <= 1.7) {
1356 }
else if (abs_eta > 1.7 && abs_eta <= 2.0) {
1359 }
else if (abs_eta > 2.0) {
1374 if (abs_eta > 1.05 && abs_eta < 1.3) {
1377 }
else if (abs_eta >= 1.3 && abs_eta < 1.7) {
1380 }
else if (abs_eta >= 1.7 && abs_eta < 2.0) {
1383 }
else if (abs_eta >= 2.0) {
1389 bool passErrorCutCB =
false;
1390 const xAOD::TrackParticle* cbtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
1394 double qOverP_CB = cbtrack->
qOverP();
1397 double sigma = std::sqrt(std::pow(p0 / pt_CB, 2) + std::pow(p1, 2) + std::pow(p2 * pt_CB, 2));
1400 double a = (end_cut - start_cut) / 4000.0;
1401 double b = end_cut -
a * 5000.0;
1402 double coefficient = (pt_CB > 1000.) ? (
a * pt_CB + b) : start_cut;
1403 if (std::abs(qOverPerr_CB / qOverP_CB) < coefficient * sigma) { passErrorCutCB =
true; }
1410 ATH_MSG_DEBUG(
"The current event is a MC event. Use bad muon veto mimic.");
1416 return passErrorCutCB;
1422 if (std::abs(mu.eta()) < 1.05) {
1432 double qOpRelResolution = std::hypot(p1, p2 * mu.primaryTrackParticle()->pt() *
MeVtoGeV);
1434 double qOverPabs_unsmeared = std::abs(mu.primaryTrackParticle()->definingParameters()[4]);
1435 double qOverPabs_smeared = 1.0 / (mu.pt() * std::cosh(mu.eta()));
1437 if ((qOverPabs_smeared - qOverPabs_unsmeared) / (qOpRelResolution * qOverPabs_unsmeared) <
1438 cutFunction->Eval(mu.primaryTrackParticle()->pt() *
MeVtoGeV))
1446 if (mu.muonType() == xAOD::Muon::MuonType::Combined) {
return mu.author() != xAOD::Muon::Author::STACO; }
1448 if (mu.muonType() == xAOD::Muon::MuonType::CaloTagged && std::abs(mu.eta()) < 0.105)
1451 if (mu.muonType() == xAOD::Muon::MuonType::SegmentTagged && (std::abs(mu.eta()) < 0.105 ||
m_useSegmentTaggedLowPt))
return true;
1453 if (mu.author() == xAOD::Muon::Author::MuidSA && std::abs(mu.eta()) > 2.4)
return true;
1455 if (mu.muonType() == xAOD::Muon::MuonType::SiliconAssociatedForwardMuon) {
1456 const xAOD::TrackParticle* cbtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
1457 return (cbtrack && std::abs(cbtrack->
eta()) > 2.4);
1468 " !! Tool configured with some of the ID hits requirements changed... FOR DEVELOPMENT ONLY: muon efficiency SF won't be "
1473 if ((value1 + value2 == 0) && !
m_PixCutOff)
return false;
1477 if ((value1 + value2 <= 4) && !
m_SctCutOff)
return false;
1484 const float abseta = std::abs(
track.eta());
1488 if (!((0.1 < abseta && abseta <= 1.9 && totTRThits > 5 && value2 < (0.9 * totTRThits)) || (abseta <= 0.1 || abseta > 1.9)))
1499 constexpr float eta_range = 1.;
1503 int CaloMuonIDTag = -20;
1506 bool readID = mu.parameter(CaloMuonIDTag, xAOD::Muon::ParamDef::CaloMuonIDTag);
1508 ATH_MSG_WARNING(
"Unable to read CaloMuonIDTag Quality information! Rejecting the CALO muon!");
1513 return (CaloMuonIDTag > 10);
1522 float CaloMuonScore{-999.0};
1523 retrieveParam(mu, CaloMuonScore, xAOD::Muon::ParamDef::CaloMuonScore);
1533 return (CaloMuonScore >= 0.77);
1538 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));
1539 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));
1549 ATH_MSG_VERBOSE(
"for run3, Tight WP is only supported when ExcludeNSWFromPrecisionLayers=False and RecalcPrecisionLayerswNSW=True");
1552 float symmetric_eta = std::abs(mu.eta());
1557 ATH_MSG_VERBOSE(
"Muon is passing tight WP kinematic cuts with pT,eta " << mu.pt() <<
" , " << mu.eta());
1564 ATH_MSG_VERBOSE(
"Applying tight WP cuts to a low pt muon with (pt,eta) ( " <<
pt <<
" , " << mu.eta() <<
" ) ");
1565 ATH_MSG_VERBOSE(
"Rho value " << rho <<
", required to be less than " << rhoCut);
1566 ATH_MSG_VERBOSE(
"Momentum significance value " << oneOverPSig <<
", required to be less than " << qOverPCut);
1568 if (rho > rhoCut)
return false;
1571 if (oneOverPSig > qOverPCut)
return false;
1572 ATH_MSG_VERBOSE(
"Muon passed tight WP, low pT momentum significance cut");
1580 else if (
pt < 100.0) {
1583 ATH_MSG_VERBOSE(
"Applying tight WP cuts to a medium pt muon with (pt,eta) (" <<
pt <<
"," << mu.eta() <<
")");
1584 ATH_MSG_VERBOSE(
"Rho value " << rho <<
" required to be less than " << rhoCut);
1587 if (rho > rhoCut)
return false;
1595 else if (
pt < 500.0) {
1597 ATH_MSG_VERBOSE(
"Applying tight WP cuts to a high pt muon with (pt,eta) (" <<
pt <<
"," << mu.eta() <<
")");
1600 ATH_MSG_VERBOSE(
"Rho value " << rho <<
", required to be less than " << rhoCut <<
" unless -1, in which no cut is applied");
1602 if (rhoCut < 0.0)
return true;
1603 if (rho > rhoCut)
return false;
1610 ATH_MSG_VERBOSE(
"Not applying any tight WP cuts to a very high pt muon with (pt,eta) (" <<
pt <<
"," << mu.eta() <<
")");
1642 if (std::abs(
muon.eta()) > 2.0) {
1643 ATH_MSG_VERBOSE(
"Recalculating number of precision layers for combined muon");
1644 summary.nprecisionLayers = (summary.innerSmallHits > 1 || summary.innerLargeHits > 1)
1645 + (summary.middleSmallHits > 2 || summary.middleLargeHits > 2)
1646 + (summary.outerSmallHits > 2 || summary.outerLargeHits > 2);
1650 summary.nprecisionLayers = (summary.middleSmallHits > 2 || summary.middleLargeHits > 2)
1651 + (summary.outerSmallHits > 2 || summary.outerLargeHits > 2)
1652 + (summary.extendedSmallHits > 2 || summary.extendedLargeHits > 2);
1656 if (!eta1stgchits_acc.isAvailable(
muon) || !eta2stgchits_acc.isAvailable(
muon) || !mmhits_acc.isAvailable(
muon)) {
1657 ATH_MSG_FATAL(__FILE__ <<
":" << __LINE__ <<
" Failed to retrieve NSW hits!"
1658 <<
" (Please use DxAODs with p-tags >= p5834 OR set ExcludeNSWFromPrecisionLayers to True (tests only)");
1659 throw std::runtime_error(
"Failed to retrieve NSW hits");
1665 summary.nprecisionLayers += ((summary.etaLayer1STGCHits + summary.etaLayer2STGCHits) > 3 || summary.MMHits > 3);
1672 if (!
muon.parameter(value, param)) {
1673 ATH_MSG_FATAL(__FILE__ <<
":" << __LINE__ <<
" Failed to retrieve parameter " << param
1674 <<
" for muon with pT:" <<
muon.pt() *
MeVtoGeV <<
", eta:" <<
muon.eta() <<
", phi: " <<
muon.phi()
1675 <<
", q:" <<
muon.charge() <<
", author: " <<
muon.author());
1676 throw std::runtime_error(
"Failed to retrieve Parameter");
1691 if (summary.nprecisionLayers == 2)
1697 const xAOD::TrackParticle* CB_track = mu.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
1698 const xAOD::TrackParticle* MS_track = mu.trackParticle(xAOD::Muon::TrackParticleType::MuonSpectrometerTrackParticle);
1700 ATH_MSG_VERBOSE(
"getResolutionCategory - No MS track available for muon. Using combined track.");
1701 MS_track = mu.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
1705 const float etaMS = MS_track->
eta();
1706 const float etaCB = CB_track->
eta();
1707 const float phiMS = MS_track->
phi();
1711 if ((summary.isSmallGoodSectors && summary.innerSmallHits < 3) || (!summary.isSmallGoodSectors && summary.innerLargeHits < 3))
1714 if ((summary.isSmallGoodSectors && summary.middleSmallHits < 3) || (!summary.isSmallGoodSectors && summary.middleLargeHits < 3))
1717 if ((summary.isSmallGoodSectors && summary.outerSmallHits < 3 && summary.extendedSmallHits < 3) ||
1718 (!summary.isSmallGoodSectors && summary.outerLargeHits < 3 && summary.extendedLargeHits < 3))
1721 if (!
isRun3() && (std::abs(
etaMS) > 2.0 || std::abs(etaCB) > 2.0) && summary.cscUnspoiledEtaHits == 0)
1724 if ((1.01 < std::abs(
etaMS) && std::abs(
etaMS) < 1.1) || (1.01 < std::abs(etaCB) && std::abs(etaCB) < 1.1))
1730 if (
isBEE(
etaMS, phiMS) || (std::abs(etaCB) > 1.4 && (summary.extendedSmallHits > 0 || summary.extendedSmallHoles > 0))) {
1731 if (summary.extendedSmallHits < 3 && summary.middleSmallHits >= 3 && summary.outerSmallHits >= 3)
1736 if (!summary.isSmallGoodSectors)
1749 static const SG::AuxElement::ConstAccessor<unsigned int> acc_rnd(
"RandomRunNumber");
1753 unsigned int runNumber = 0;
1755 else runNumber = eventInfo->runNumber();
1759 ATH_MSG_DEBUG(
"The current event is a data event. Return runNumber.");
1765 static std::atomic<bool> issuedWarningPRW{
false};
1766 if (acc_rnd.isAvailable(*eventInfo)) {
1767 unsigned int rn = acc_rnd(*eventInfo);
1768 if (rn != 0)
return acc_rnd(*eventInfo);
1770 if (!issuedWarningPRW) {
1772 issuedWarningPRW =
true;
1777 if (needOnlyCorrectYear) {
1778 if (runNumber < 300000) {
1779 ATH_MSG_DEBUG(
"Random run number not available and this is mc16a or mc20a, returning dummy 2016 run number.");
1782 }
else if (runNumber < 310000) {
1783 ATH_MSG_DEBUG(
"Random run number not available and this is mc16d or mc20d, returning dummy 2017 run number.");
1786 }
else if (runNumber < 320000) {
1787 ATH_MSG_DEBUG(
"Random run number not available and this is mc16e or mc20e, returning dummy 2018 run number.");
1790 }
else if (runNumber < 600000) {
1791 ATH_MSG_DEBUG(
"Random run number not available and this is mc21/mc23, for the time being we're returing a dummy run number.");
1794 ATH_MSG_DEBUG(
"Detected some run 4 / phase II runnumber "<<runNumber<<
". ");
1798 ATH_MSG_FATAL(
"Random run number not available, fallback option of using runNumber failed since "<<runNumber<<
" cannot be recognised");
1799 throw std::runtime_error(
"MuonSelectionTool() - need RandomRunNumber decoration by the PileupReweightingTool");
1802 ATH_MSG_FATAL(
"Failed to find the RandomRunNumber decoration by the PileupReweightingTool");
1803 throw std::runtime_error(
"MuonSelectionTool() - need RandomRunNumber decoration from PileupReweightingTool");
1809 static constexpr std::array<float, 2> BIS78_eta{1.05, 1.3};
1810 static constexpr std::array<float, 8> BIS78_phi{0.21, 0.57, 1.00, 1.33, 1.78, 2.14, 2.57, 2.93};
1812 float abs_eta = std::abs(
eta);
1813 float abs_phi = std::abs(
phi);
1815 if (abs_eta >= BIS78_eta[0] && abs_eta <= BIS78_eta[1]) {
1816 if ((abs_phi >= BIS78_phi[0] && abs_phi <= BIS78_phi[1]) || (abs_phi >= BIS78_phi[2] && abs_phi <= BIS78_phi[3]) ||
1817 (abs_phi >= BIS78_phi[4] && abs_phi <= BIS78_phi[5]) || (abs_phi >= BIS78_phi[6] && abs_phi <= BIS78_phi[7])) {
1827 static constexpr std::array<float, 2> BEE_eta{1.440, 1.692};
1828 static constexpr std::array<float, 8> BEE_phi{0.301, 0.478, 1.086, 1.263, 1.872, 2.049, 2.657, 2.834};
1830 float abs_eta = std::abs(
eta);
1831 float abs_phi = std::abs(
phi);
1833 if (abs_eta >= BEE_eta[0] && abs_eta <= BEE_eta[1]) {
1834 if ((abs_phi >= BEE_phi[0] && abs_phi <= BEE_phi[1]) || (abs_phi >= BEE_phi[2] && abs_phi <= BEE_phi[3]) ||
1835 (abs_phi >= BEE_phi[4] && abs_phi <= BEE_phi[5]) || (abs_phi >= BEE_phi[6] && abs_phi <= BEE_phi[7])) {
1845 static constexpr std::array<float, 6> BMG_eta{0.35, 0.47, 0.68, 0.80, 0.925, 1.04};
1846 static constexpr std::array<float, 4> BMG_phi{-1.93, -1.765, -1.38, -1.21};
1848 float abs_eta = std::abs(
eta);
1850 if ((abs_eta >= BMG_eta[0] && abs_eta <= BMG_eta[1]) || (abs_eta >= BMG_eta[2] && abs_eta <= BMG_eta[3]) ||
1851 (abs_eta >= BMG_eta[4] && abs_eta <= BMG_eta[5])) {
1852 if ((
phi >= BMG_phi[0] &&
phi <= BMG_phi[1]) || (
phi >= BMG_phi[2] &&
phi <= BMG_phi[3])) {
return true; }
1861 ATH_MSG_ERROR(
"TightNNScore calculation is disabled. Please set the property CalculateTightNNScore to true.");
1862 throw std::runtime_error(
"cannot calculate TightNNScore");
1865 if (mu.muonType() != xAOD::Muon::MuonType::Combined)
return -999;
1866 const xAOD::TrackParticle* idtrack = mu.trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
1867 const xAOD::TrackParticle* metrack = mu.trackParticle(xAOD::Muon::TrackParticleType::ExtrapolatedMuonSpectrometerTrackParticle);
1868 if(!idtrack || !metrack)
return -999;
1870 if (
getQuality(mu) > xAOD::Muon::Quality::Medium)
return -999;
1872 if (std::abs(mu.eta())>2.5)
return -999;
1873 if(mu.pt()<4000.)
return -999;
1875 std::vector<float> input_features;
1877 int mu_author=
static_cast<int>(mu.author());
1879 float mu_scatteringCurvatureSignificance=0.;
1880 retrieveParam(mu, mu_scatteringCurvatureSignificance, xAOD::Muon::ParamDef::scatteringCurvatureSignificance);
1881 float mu_scatteringNeighbourSignificance=0.;
1882 retrieveParam(mu, mu_scatteringNeighbourSignificance, xAOD::Muon::ParamDef::scatteringNeighbourSignificance);
1883 float mu_momentumBalanceSignificance=0.;
1884 retrieveParam(mu, mu_momentumBalanceSignificance, xAOD::Muon::ParamDef::momentumBalanceSignificance);
1886 float mu_reducedChi2=mu.primaryTrackParticle()->chiSquared() / mu.primaryTrackParticle()->numberDoF();
1889 float mu_spectrometerFieldIntegral=0.;
1890 retrieveParam(mu, mu_spectrometerFieldIntegral, xAOD::Muon::ParamDef::spectrometerFieldIntegral);
1891 float mu_segmentDeltaEta=0;
1892 retrieveParam(mu, mu_segmentDeltaEta, xAOD::Muon::ParamDef::segmentDeltaEta);
1893 uint8_t mu_numberOfPixelHits=0;
1895 uint8_t mu_numberOfPixelDeadSensors=0;
1912 input_features = {(
float)mu_author,
1914 mu_scatteringCurvatureSignificance,
1915 mu_scatteringNeighbourSignificance,
1916 mu_momentumBalanceSignificance,
1917 mu_qOverPSignificance,
1921 mu_spectrometerFieldIntegral,
1923 (
float)mu_numberOfPixelHits,
1924 (
float)mu_numberOfPixelDeadSensors,
1925 (
float)mu_innerLargeHits,
1926 (
float)mu_innerSmallHits,
1927 (
float)mu_middleLargeHits,
1928 (
float)mu_middleSmallHits,
1929 (
float)mu_outerLargeHits,
1930 (
float)mu_outerSmallHits};
1934 uint8_t mu_phiLayer1STGCHits=0;
1936 uint8_t mu_phiLayer2STGCHits=0;
1938 uint8_t mu_etaLayer1STGCHits=0;
1940 uint8_t mu_etaLayer2STGCHits=0;
1944 input_features = {(
float)mu_author,
1946 mu_scatteringCurvatureSignificance,
1947 mu_scatteringNeighbourSignificance,
1948 mu_momentumBalanceSignificance,
1949 mu_qOverPSignificance,
1953 mu_spectrometerFieldIntegral,
1955 (
float)mu_numberOfPixelHits,
1956 (
float)mu_numberOfPixelDeadSensors,
1957 (
float)mu_innerLargeHits,
1958 (
float)mu_innerSmallHits,
1959 (
float)mu_middleLargeHits,
1960 (
float)mu_middleSmallHits,
1961 (
float)mu_outerLargeHits,
1962 (
float)mu_outerSmallHits,
1963 (
float)mu_phiLayer1STGCHits,
1964 (
float)mu_phiLayer2STGCHits,
1965 (
float)mu_etaLayer1STGCHits,
1966 (
float)mu_etaLayer2STGCHits,
1971 std::vector<int64_t> inputShape = {1,
static_cast<int64_t
>(input_features.size())};
1974 inputData[
"flatten_input"] = std::make_pair(
1975 inputShape, std::move(input_features)
1979 outputData[
"sequential"] = std::make_pair(
1980 std::vector<int64_t>{1, 1}, std::vector<float>{}
1983 if (!
m_onnxTool->inference(inputData, outputData).isSuccess()) {
1987 const auto& variant = outputData[
"sequential"].second;
1988 if (std::holds_alternative<std::vector<float>>(variant)) {
1989 const auto&
vec = std::get<std::vector<float>>(variant);
2000 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)
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