ATLAS Offline Software
Loading...
Searching...
No Matches
TrigMuonEFHypoTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "GaudiKernel/SystemOfUnits.h"
6
10class ISvcLocator;
11TrigMuonEFHypoTool::TrigMuonEFHypoTool(const std::string & type, const std::string & name, const IInterface* parent):
12 AthAlgTool(type, name, parent),
13 m_decisionId(HLT::Identifier::fromToolName(name)){
14}
18
20 if(m_muonSelTool.retrieve().isFailure()) {
21 ATH_MSG_ERROR("Unable to retrieve " << m_muonSelTool);
22 return StatusCode::FAILURE;
23 }
24 } else m_muonSelTool.disable();
25
26 if(m_acceptAll) {
27 ATH_MSG_DEBUG("Accepting all the events!");
28 } else {
29 if(m_ptBins.size()<=0){
30 ATH_MSG_ERROR("Trying to configure hypo with no pT bins. This is probably a configuration mistake.");
31 return StatusCode::FAILURE;
32 }
33 m_bins.resize(m_ptBins.size());
34 for(size_t j=0; j<m_ptBins.size(); j++){
35 m_bins[j] = m_ptBins[j].size() - 1;
36 if (m_bins[j] != m_ptThresholds[j].size()) {
37 ATH_MSG_ERROR("bad thresholds setup .... exiting!");
38 return StatusCode::FAILURE;
39 }
40 if (msgLvl(MSG::DEBUG)) {
41 for (std::vector<float>::size_type i=0; i<m_bins[j];++i) {
42 ATH_MSG_DEBUG( "bin " << m_ptBins[j][i] << " - " << m_ptBins[j][i+1]<<" with Pt Threshold of " << (m_ptThresholds[j][i])/Gaudi::Units::GeV<< " GeV");
43 }
44 }
45 }
46 }
47 // minimum d0 cut for displaced muon triggers
48 if (m_d0min>0.) ATH_MSG_DEBUG( " Rejecting muons with abs(d0) < "<<m_d0min<<" mm");
49
50 if (m_runCommissioningChain) ATH_MSG_INFO("m_runCommissioningChain set to true (for absence of NSW)");
51
52 if ( not m_monTool.name().empty() ) {
53 ATH_CHECK( m_monTool.retrieve() );
54 ATH_MSG_DEBUG("MonTool name: " << m_monTool);
55 }
56
57 if(m_doSA) m_type = xAOD::Muon::TrackParticleType::ExtrapolatedMuonSpectrometerTrackParticle;
58 else m_type = xAOD::Muon::TrackParticleType::CombinedTrackParticle;
59
60 return StatusCode::SUCCESS;
61}
63 ATH_MSG_DEBUG( "deciding...");
64 //Monitored Variables
65 std::vector<float> fexPt, fexEta, fexPhi, selPt, selEta, selPhi;
66 auto muonPtMon = Monitored::Collection("Pt", fexPt);
67 auto muonEtaMon = Monitored::Collection("Eta", fexEta);
68 auto muonPhiMon = Monitored::Collection("Phi", fexPhi);
69 auto muonPtSelMon = Monitored::Collection("Pt_sel", selPt);
70 auto muonEtaSelMon = Monitored::Collection("Eta_sel", selEta);
71 auto muonPhiSelMon = Monitored::Collection("Phi_sel", selPhi);
72 auto monitorIt = Monitored::Group(m_monTool, muonPtMon, muonEtaMon, muonPhiMon, muonPtSelMon, muonEtaSelMon, muonPhiSelMon);
73 bool result = false;
74 //for pass through mode
75 if(m_acceptAll) {
76 result = true;
77 ATH_MSG_DEBUG("Accept property is set: taking all the events");
78 return result;
79 }
80 // decision making
81 //Get xAOD::MuonContainer from hypotool
82 const xAOD::Muon* muon = input.muon;
83 if( !muon ){
84 ATH_MSG_DEBUG("Retrieval of xAOD::MuonContainer failed");
85 return false;
86 }
87
88 if (muon->primaryTrackParticle()) { // was there a muon in this RoI ?
89 const xAOD::TrackParticle* tr = muon->trackParticle(m_type);
90 if (!tr) {
91 ATH_MSG_DEBUG("No TrackParticle found.");
92 } else {
93 ATH_MSG_DEBUG("Retrieved Track track with abs pt "<< (*tr).pt()/Gaudi::Units::GeV << " GeV ");
94 //fill monitored variables
95 fexPt.push_back(tr->pt()/Gaudi::Units::GeV);
96 fexEta.push_back(tr->eta());
97 fexPhi.push_back(tr->phi());
98 //Apply hypo cuts
99 float absEta = std::abs(tr->eta());
100 float threshold = 0;
101 for (std::vector<float>::size_type k=0; k<m_bins[cutIndex]; ++k) {
102 if (absEta > m_ptBins[cutIndex][k] && absEta <= m_ptBins[cutIndex][k+1]) threshold = m_ptThresholds[cutIndex][k];
103 }
104 if (std::abs(tr->pt())/Gaudi::Units::GeV > (threshold/Gaudi::Units::GeV)){
105 result = true;
106 // If trigger path name includes "muonqual", check whether the muon passes those criteria
107 if(m_muonqualityCut == true) result = passedQualityCuts(muon);
108 //cut on Nprecision layers (for 3layerEC msonly triggers)
110 uint8_t nGoodPrcLayers=0;
111 if (!muon->summaryValue(nGoodPrcLayers, xAOD::numberOfGoodPrecisionLayers)){
112 ATH_MSG_DEBUG("No numberOfGoodPrecisionLayers variable found; not passing hypo");
113 result=false;
114 }
115 if(std::abs(muon->eta()) > 1.3) {
117 if(nGoodPrcLayers < 2){
118 ATH_MSG_DEBUG("Muon has less than two GoodPrecisionLayers; not passing hypo (requrement loosend according to absence of NSW)");
119 result=false;
120 }
121 } else {
122 if(nGoodPrcLayers < 3){
123 ATH_MSG_DEBUG("Muon has less than three GoodPrecisionLayers; not passing hypo");
124 result=false;
125 }
126 }
127 } else if (std::abs(muon->eta()) > 1.05) {
128 if(nGoodPrcLayers < 3){
129 ATH_MSG_DEBUG("Muon has less than three GoodPrecisionLayers; not passing hypo");
130 result=false;
131 }
132 }
133 }
134 if (m_d0min>0.) {
135 ATH_MSG_DEBUG("Muon has d0 less than "<<m_d0min<<"mm; not passing hypo");
136 if (std::abs(tr->d0())<m_d0min) result = false;
137 }
138 }
139 if(result == true){
140 selPt.push_back(tr->pt()/Gaudi::Units::GeV);
141 selEta.push_back(tr->eta());
142 selPhi.push_back(tr->phi());
143 }
144 if (m_d0min>0.) {
145 ATH_MSG_DEBUG(" REGTEST muon pt is " << tr->pt()/Gaudi::Units::GeV << " GeV "
146 << " with Charge " << tr->charge()
147 << " and threshold cut is " << threshold/Gaudi::Units::GeV << " GeV"
148 << " so hypothesis is " << (result?"true":"false"));
149 } else {
150 ATH_MSG_DEBUG(" REGTEST muon pt is " << tr->pt()/Gaudi::Units::GeV << " GeV "
151 << " with Charge " << tr->charge()
152 << " and with d0 " << tr->d0()
153 << " the threshold cut is " << threshold/Gaudi::Units::GeV << " GeV"
154 << " and d0min cut is " << m_d0min<<" mm"
155 << " so hypothesis is " << (result?"true":"false"));
156 }
157 }
158 }
159 return result;
160}
161
163 bool passCut = false;
164 const xAOD::TrackParticle* idtrack = muon->trackParticle( xAOD::Muon::InnerDetectorTrackParticle );
165 const xAOD::TrackParticle* metrack = muon->trackParticle( xAOD::Muon::ExtrapolatedMuonSpectrometerTrackParticle );
166 float mePt = -999999., idPt = -999999.;
167
168 float reducedChi2 = -10, qOverPsignif = -10;
169
170 if(idtrack && metrack) {
171 mePt = metrack->pt();
172 idPt = idtrack->pt();
173 float meP = 1.0 / ( sin(metrack->theta()) / mePt);
174 float idP = 1.0 / ( sin(idtrack->theta()) / idPt);
175 qOverPsignif = std::abs( (metrack->charge() / meP) - (idtrack->charge() / idP) ) / sqrt( idtrack->definingParametersCovMatrix()(4,4) + metrack->definingParametersCovMatrix()(4,4) );
176 reducedChi2 = muon->primaryTrackParticle()->chiSquared()/muon->primaryTrackParticle()->numberDoF();
177 // Selection criteria based on the requirements that are part of the muon quality working points (offline)
178 if(std::abs(reducedChi2) < 8.0 && !m_muonSelTool->isBadMuon(*muon) && qOverPsignif<7.0 && muon->author()==xAOD::Muon::MuidCo) passCut = true;
179 }
180
181 return passCut;
182}
183
184StatusCode TrigMuonEFHypoTool::decide(std::vector<MuonEFInfo>& toolInput) const {
185 size_t numTrigger = m_ptBins.size();
186 size_t numMuon=toolInput.size();
187 if(numTrigger==1){
188 ATH_MSG_DEBUG("Applying selection of single << " << m_decisionId);
189 return inclusiveSelection(toolInput);
190 }
191 else{
192 ATH_MSG_DEBUG("Applying selection of multiplicity "<< m_decisionId<<" with nMuons"<<numMuon);
193 return multiplicitySelection(toolInput);
194 }
195 return StatusCode::SUCCESS;
196}
197StatusCode TrigMuonEFHypoTool::inclusiveSelection(std::vector<MuonEFInfo>& toolInput) const{
198 for (uint i=0; i<toolInput.size(); i++){
199 auto& tool = toolInput.at(i);
200 if(TrigCompositeUtils::passed(m_decisionId.numeric(), tool.previousDecisionIDs)){
201 bool overlap = false;
202 if(m_checkOvlp){
203 for(uint j=i+1; j<toolInput.size();j++){
204 auto& tool2 = toolInput.at(j);
205 if(TrigCompositeUtils::passed(m_decisionId.numeric(), tool2.previousDecisionIDs))
206 if(tool2.muon->p4()==tool.muon->p4()) overlap=true;
207 }
208 }
209 if(overlap) continue;
210
211 if(decideOnSingleObject(tool, 0)==true){
212 ATH_MSG_DEBUG("Passes selection");
214 }
215 else ATH_MSG_DEBUG("Does not pass selection");
216 }
217 }
218 return StatusCode::SUCCESS;
219}
220StatusCode TrigMuonEFHypoTool::multiplicitySelection(std::vector<MuonEFInfo>& toolInput) const{
221 HLT::Index2DVec passingSelection(m_ptBins.size());
222 bool passingNscan=false;
223 for(size_t cutIndex=0; cutIndex < m_ptBins.size(); ++cutIndex) {
224 size_t elementIndex{0};
225 for(auto& tool : toolInput){
226 if(TrigCompositeUtils::passed(m_decisionId.numeric(), tool.previousDecisionIDs)){
227 if(decideOnSingleObject(tool, cutIndex)==true){
228 if(m_nscan && cutIndex==0 && (!passingNscan)){
229 ATH_MSG_DEBUG("Applying narrow-scan selection");
230 float deta,dphi=10;
231 unsigned int nInCone=0;
232 float muonR = sqrt( pow(tool.muon->eta(),2) +pow(tool.muon->phi(),2));
233 float coneCheck=m_conesize*muonR;
234 for (auto& tooltmp : toolInput){
235 ATH_MSG_DEBUG(">>Testing Muon with pt: "<<tooltmp.muon->pt()/Gaudi::Units::GeV << "GeV, eta: "
236 << tooltmp.muon->eta() << ", phi: " << tooltmp.muon->phi());
237 if (tooltmp.muon->p4() == tool.muon->p4()) {
238 ATH_MSG_DEBUG("<< same muon, skipping...");
239 }else {
240 deta = std::abs(tooltmp.muon->eta()-tool.muon->eta());
241 dphi = getdphi(tooltmp.muon->phi(),tool.muon->phi());
242 if(deta<coneCheck && dphi<coneCheck){
243 nInCone++;
244 }
245
246 ATH_MSG_DEBUG(">> dPhi is: " << dphi);
247 ATH_MSG_DEBUG(">> dEta is: " << deta);
248 ATH_MSG_DEBUG(">> dR is: " <<sqrt( pow( deta, 2) + pow( dphi, 2) ));
249
250 }
251 }
252 //end test nscan
253
254 if (nInCone > 0) {
255 ATH_MSG_DEBUG("Passes narrow-scan selection Index["<<elementIndex<<"]");
256 passingNscan=true;
257 }else ATH_MSG_DEBUG("Does not pass narrow-scan selection Index["<<elementIndex<<"]");
258 }
259 ATH_MSG_DEBUG("Passing selection "<<m_decisionId << " , Index["<<elementIndex<<"]");
260 passingSelection[cutIndex].push_back(elementIndex);
261 }
262 else ATH_MSG_DEBUG("Not passing selection "<<m_decisionId << " , Index["<<elementIndex<<"]");
263 }
264 else{
265 ATH_MSG_DEBUG("No match for decisionId "<<m_decisionId);
266 }
267 elementIndex++;
268 }
269 if (m_nscan &&(!passingNscan)){
270 ATH_MSG_DEBUG("Narrow-scan is required and no muons passed, all muons will be rejected ");
271 return StatusCode::SUCCESS;
272 }
273 //If nothing passes, then we should stop
274 if(passingSelection[cutIndex].empty()){
275 ATH_MSG_DEBUG("No muons passed the selection "<<cutIndex<<" rejecting...");
276 return StatusCode::SUCCESS;
277 }
278 }
279 std::set<size_t> passingIndices;
280 if(m_decisionPerRoI==true){
281 auto notFromSameRoI = [&](const HLT::Index1DVec& comb){
282 std::set<const xAOD::Muon*> setOfMuons;
283 for (auto index : comb){
284 setOfMuons.insert(toolInput[index].muon);
285 }
286 return setOfMuons.size()==comb.size();
287 };
288
289 HLT::elementsInUniqueCombinations(passingSelection, passingIndices, std::move(notFromSameRoI));
290 }
291 else{
292 HLT::elementsInUniqueCombinations(passingSelection, passingIndices);
293 }
294 if(passingIndices.empty()){
295 ATH_MSG_DEBUG("No muons passed selection "<<m_decisionId);
296 return StatusCode::SUCCESS;
297 }
298 for(auto i : passingIndices){
299 ATH_MSG_DEBUG("Muon["<<i<<"] passes "<<m_decisionId<<" with pT = "<<toolInput[i].muon->pt()/Gaudi::Units::GeV << "GeV");
300 TrigCompositeUtils::addDecisionID(m_decisionId.numeric(), toolInput[i].decision);
301 }
302 return StatusCode::SUCCESS;
303}
304float TrigMuonEFHypoTool::getdphi(float phi1, float phi2) const{
305 float dphi = phi1-phi2;
306 if(dphi > TMath::Pi()) dphi -= TMath::TwoPi();
307 if(dphi < -1*TMath::Pi()) dphi += TMath::TwoPi();
308 return fabs(dphi);
309}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
unsigned int uint
Header file to be included by clients of the Monitored infrastructure.
static const Attributes_t empty
constexpr int pow(int base, int exp) noexcept
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
bool msgLvl(const MSG::Level lvl) const
Group of local monitoring quantities and retain correlation when filling histograms
StatusCode multiplicitySelection(std::vector< TrigMuonEFHypoTool::MuonEFInfo > &toolInput) const
StatusCode decide(std::vector< TrigMuonEFHypoTool::MuonEFInfo > &toolInput) const
Gaudi::Property< bool > m_runCommissioningChain
std::vector< size_t > m_bins
Gaudi::Property< float > m_conesize
bool passedQualityCuts(const xAOD::Muon *muon) const
Gaudi::Property< bool > m_checkOvlp
Gaudi::Property< bool > m_nscan
Gaudi::Property< float > m_d0min
Gaudi::Property< bool > m_acceptAll
Gaudi::Property< bool > m_threeStationCut
float getdphi(float phi1, float phi2) const
Gaudi::Property< std::vector< std::vector< double > > > m_ptThresholds
virtual StatusCode initialize() override
ToolHandle< GenericMonitoringTool > m_monTool
TrigMuonEFHypoTool(const std::string &type, const std::string &name, const IInterface *parent)
Gaudi::Property< bool > m_decisionPerRoI
Gaudi::Property< std::vector< std::vector< double > > > m_ptBins
StatusCode inclusiveSelection(std::vector< TrigMuonEFHypoTool::MuonEFInfo > &toolInput) const
Gaudi::Property< bool > m_muonqualityCut
HLT::Identifier m_decisionId
ToolHandle< CP::IMuonSelectionTool > m_muonSelTool
bool decideOnSingleObject(TrigMuonEFHypoTool::MuonEFInfo &input, size_t cutIndex) const
Gaudi::Property< bool > m_doSA
xAOD::Muon::TrackParticleType m_type
float theta() const
Returns the parameter, which has range 0 to .
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 d0() const
Returns the parameter.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
float charge() const
Returns the charge.
It used to be useful piece of code for replacing actual SG with other store of similar functionality ...
void elementsInUniqueCombinations(const Index2DVec &indices, std::set< size_t > &participants, const std::function< bool(const Index1DVec &)> &filter)
std::vector< Index1DVec > Index2DVec
std::vector< size_t > Index1DVec
Unique combinations for case when one can not repeat the index (i.e.
ValuesCollection< T > Collection(std::string name, const T &collection)
Declare a monitored (double-convertible) collection.
bool passed(DecisionID id, const DecisionIDContainer &idSet)
checks if required decision ID is in the set of IDs in the container
void addDecisionID(DecisionID id, Decision *d)
Appends the decision (given as ID) to the decision object.
Definition index.py:1
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Muon_v1 Muon
Reference the current persistent version:
@ numberOfGoodPrecisionLayers
layers with at least 3 hits that are not deweighted [uint8_t]