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
74 //for pass through mode
75 if(m_acceptAll) {
76 ATH_MSG_DEBUG("Accept property is set: taking all the events");
77 return true;
78 }
79 // decision making
80 //Get xAOD::MuonContainer from hypotool
81 const xAOD::Muon* muon = input.muon;
82 if( !muon ){
83 ATH_MSG_DEBUG("Retrieval of xAOD::MuonContainer failed");
84 return false;
85 }
86 if (!m_isFastReco && !muon->trackParticle(xAOD::Muon::TrackParticleType::Primary)) {
87 ATH_MSG_DEBUG("No TrackParticle of type Primary found.");
88 return false;
89 }
90
91 const xAOD::TrackParticle* tr {nullptr};
92 double pt{0.}, eta{0.}, phi{0.};
93 if (m_isFastReco) {
94 pt = muon->pt();
95 eta = muon->eta();
96 phi = muon->phi();
97 } else {
98 tr = muon->trackParticle(m_type);
99 if (!tr) {
100 ATH_MSG_DEBUG("No TrackParticle found.");
101 return false;
102 }
103 pt = tr->pt();
104 eta = tr->eta();
105 phi = tr->phi();
106 }
107
108 ATH_MSG_DEBUG("Retrieved Track track with abs pt "<< pt/Gaudi::Units::GeV << " GeV ");
109 //fill monitored variables
110 fexPt.push_back(pt/Gaudi::Units::GeV);
111 fexEta.push_back(eta);
112 fexPhi.push_back(phi);
113
114 // Check pt thresholds
115 bool result = false;
116 float absEta = std::abs(eta);
117 float threshold = 0;
118 for (std::vector<float>::size_type k=0; k<m_bins[cutIndex]; ++k) {
119 if (absEta > m_ptBins[cutIndex][k] && absEta <= m_ptBins[cutIndex][k+1]) threshold = m_ptThresholds[cutIndex][k];
120 }
121 if (std::abs(pt) > threshold){
122 result = true;
123 }
124
125 if (result == true && !m_isFastReco) {
126 // If trigger path name includes "muonqual", check whether the muon passes those criteria
127 if(m_muonqualityCut == true) result = passedQualityCuts(muon);
128 //cut on Nprecision layers (for 3layerEC msonly triggers)
130 uint8_t nGoodPrcLayers=0;
131 if (!muon->summaryValue(nGoodPrcLayers, xAOD::numberOfGoodPrecisionLayers)){
132 ATH_MSG_DEBUG("No numberOfGoodPrecisionLayers variable found; not passing hypo");
133 result=false;
134 }
135 if(std::abs(eta) > 1.3) {
137 if(nGoodPrcLayers < 2){
138 ATH_MSG_DEBUG("Muon has less than two GoodPrecisionLayers; not passing hypo (requrement loosend according to absence of NSW)");
139 result=false;
140 }
141 } else {
142 if(nGoodPrcLayers < 3){
143 ATH_MSG_DEBUG("Muon has less than three GoodPrecisionLayers; not passing hypo");
144 result=false;
145 }
146 }
147 } else if (std::abs(eta) > 1.05) {
148 if(nGoodPrcLayers < 3){
149 ATH_MSG_DEBUG("Muon has less than three GoodPrecisionLayers; not passing hypo");
150 result=false;
151 }
152 }
153 }
154 //cut on d0 for displaced muon triggers
155 if (m_d0min > 0. && std::abs(tr->d0()) < m_d0min) {
156 ATH_MSG_DEBUG("Muon has d0 less than "<<m_d0min<<"mm; not passing hypo");
157 result = false;
158 }
159 }
160
161 if(result == true){
162 selPt.push_back(pt/Gaudi::Units::GeV);
163 selEta.push_back(eta);
164 selPhi.push_back(phi);
165 }
166 const double charge = m_isFastReco ? muon->charge() : tr->charge();
167 if (!m_isFastReco && m_d0min > 0.) {
168 ATH_MSG_DEBUG(" REGTEST muon pt is " << pt/Gaudi::Units::GeV << " GeV "
169 << " with Charge " << charge
170 << " and with d0 " << tr->d0()
171 << " the threshold cut is " << threshold/Gaudi::Units::GeV << " GeV"
172 << " and d0min cut is " << m_d0min<<" mm"
173 << " so hypothesis is " << (result?"true":"false"));
174 } else {
175 ATH_MSG_DEBUG(" REGTEST muon pt is " << pt/Gaudi::Units::GeV << " GeV "
176 << " with Charge " << charge
177 << " and threshold cut is " << threshold/Gaudi::Units::GeV << " GeV"
178 << " so hypothesis is " << (result?"true":"false"));
179 }
180 return result;
181}
182
184 bool passCut = false;
185 const xAOD::TrackParticle* idtrack = muon->trackParticle( xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle );
186 const xAOD::TrackParticle* metrack = muon->trackParticle( xAOD::Muon::TrackParticleType::ExtrapolatedMuonSpectrometerTrackParticle );
187 float mePt = -999999., idPt = -999999.;
188
189 float reducedChi2 = -10, qOverPsignif = -10;
190
191 if(idtrack && metrack) {
192 mePt = metrack->pt();
193 idPt = idtrack->pt();
194 float meP = 1.0 / ( sin(metrack->theta()) / mePt);
195 float idP = 1.0 / ( sin(idtrack->theta()) / idPt);
196 qOverPsignif = std::abs( (metrack->charge() / meP) - (idtrack->charge() / idP) ) / sqrt( idtrack->definingParametersCovMatrix()(4,4) + metrack->definingParametersCovMatrix()(4,4) );
197 reducedChi2 = muon->trackParticle(xAOD::Muon::TrackParticleType::Primary)->chiSquared()/muon->trackParticle(xAOD::Muon::TrackParticleType::Primary)->numberDoF();
198 // Selection criteria based on the requirements that are part of the muon quality working points (offline)
199 if(std::abs(reducedChi2) < 8.0 && !m_muonSelTool->isBadMuon(*muon) && qOverPsignif<7.0 && muon->author()==xAOD::Muon::Author::MuidCo) passCut = true;
200 }
201
202 return passCut;
203}
204
205StatusCode TrigMuonEFHypoTool::decide(std::vector<MuonEFInfo>& toolInput) const {
206 size_t numTrigger = m_ptBins.size();
207 size_t numMuon=toolInput.size();
208 if(numTrigger==1){
209 ATH_MSG_DEBUG("Applying selection of single << " << m_decisionId);
210 return inclusiveSelection(toolInput);
211 }
212 else{
213 ATH_MSG_DEBUG("Applying selection of multiplicity "<< m_decisionId<<" with nMuons"<<numMuon);
214 return multiplicitySelection(toolInput);
215 }
216 return StatusCode::SUCCESS;
217}
218StatusCode TrigMuonEFHypoTool::inclusiveSelection(std::vector<MuonEFInfo>& toolInput) const{
219 for (uint i=0; i<toolInput.size(); i++){
220 auto& tool = toolInput.at(i);
221 if(TrigCompositeUtils::passed(m_decisionId.numeric(), tool.previousDecisionIDs)){
222 bool overlap = false;
223 if(m_checkOvlp){
224 for(uint j=i+1; j<toolInput.size();j++){
225 auto& tool2 = toolInput.at(j);
226 if(TrigCompositeUtils::passed(m_decisionId.numeric(), tool2.previousDecisionIDs))
227 if(tool2.muon->p4()==tool.muon->p4()) overlap=true;
228 }
229 }
230 if(overlap) continue;
231
232 if(decideOnSingleObject(tool, 0)==true){
233 ATH_MSG_DEBUG("Passes selection");
235 }
236 else ATH_MSG_DEBUG("Does not pass selection");
237 }
238 }
239 return StatusCode::SUCCESS;
240}
241StatusCode TrigMuonEFHypoTool::multiplicitySelection(std::vector<MuonEFInfo>& toolInput) const{
242 HLT::Index2DVec passingSelection(m_ptBins.size());
243 bool passingNscan=false;
244 for(size_t cutIndex=0; cutIndex < m_ptBins.size(); ++cutIndex) {
245 size_t elementIndex{0};
246 for(auto& tool : toolInput){
247 if(TrigCompositeUtils::passed(m_decisionId.numeric(), tool.previousDecisionIDs)){
248 if(decideOnSingleObject(tool, cutIndex)==true){
249 if(m_nscan && cutIndex==0 && (!passingNscan)){
250 ATH_MSG_DEBUG("Applying narrow-scan selection");
251 float deta,dphi=10;
252 unsigned int nInCone=0;
253 float muonR = sqrt( pow(tool.muon->eta(),2) +pow(tool.muon->phi(),2));
254 float coneCheck=m_conesize*muonR;
255 for (auto& tooltmp : toolInput){
256 ATH_MSG_DEBUG(">>Testing Muon with pt: "<<tooltmp.muon->pt()/Gaudi::Units::GeV << "GeV, eta: "
257 << tooltmp.muon->eta() << ", phi: " << tooltmp.muon->phi());
258 if (tooltmp.muon->p4() == tool.muon->p4()) {
259 ATH_MSG_DEBUG("<< same muon, skipping...");
260 }else {
261 deta = std::abs(tooltmp.muon->eta()-tool.muon->eta());
262 dphi = getdphi(tooltmp.muon->phi(),tool.muon->phi());
263 if(deta<coneCheck && dphi<coneCheck){
264 nInCone++;
265 }
266
267 ATH_MSG_DEBUG(">> dPhi is: " << dphi);
268 ATH_MSG_DEBUG(">> dEta is: " << deta);
269 ATH_MSG_DEBUG(">> dR is: " <<sqrt( pow( deta, 2) + pow( dphi, 2) ));
270
271 }
272 }
273 //end test nscan
274
275 if (nInCone > 0) {
276 ATH_MSG_DEBUG("Passes narrow-scan selection Index["<<elementIndex<<"]");
277 passingNscan=true;
278 }else ATH_MSG_DEBUG("Does not pass narrow-scan selection Index["<<elementIndex<<"]");
279 }
280 ATH_MSG_DEBUG("Passing selection "<<m_decisionId << " , Index["<<elementIndex<<"]");
281 passingSelection[cutIndex].push_back(elementIndex);
282 }
283 else ATH_MSG_DEBUG("Not passing selection "<<m_decisionId << " , Index["<<elementIndex<<"]");
284 }
285 else{
286 ATH_MSG_DEBUG("No match for decisionId "<<m_decisionId);
287 }
288 elementIndex++;
289 }
290 if (m_nscan &&(!passingNscan)){
291 ATH_MSG_DEBUG("Narrow-scan is required and no muons passed, all muons will be rejected ");
292 return StatusCode::SUCCESS;
293 }
294 //If nothing passes, then we should stop
295 if(passingSelection[cutIndex].empty()){
296 ATH_MSG_DEBUG("No muons passed the selection "<<cutIndex<<" rejecting...");
297 return StatusCode::SUCCESS;
298 }
299 }
300 std::set<size_t> passingIndices;
301 if(m_decisionPerRoI==true){
302 auto notFromSameRoI = [&](const HLT::Index1DVec& comb){
303 std::set<const xAOD::Muon*> setOfMuons;
304 for (auto index : comb){
305 setOfMuons.insert(toolInput[index].muon);
306 }
307 return setOfMuons.size()==comb.size();
308 };
309
310 HLT::elementsInUniqueCombinations(passingSelection, passingIndices, std::move(notFromSameRoI));
311 }
312 else{
313 HLT::elementsInUniqueCombinations(passingSelection, passingIndices);
314 }
315 if(passingIndices.empty()){
316 ATH_MSG_DEBUG("No muons passed selection "<<m_decisionId);
317 return StatusCode::SUCCESS;
318 }
319 for(auto i : passingIndices){
320 ATH_MSG_DEBUG("Muon["<<i<<"] passes "<<m_decisionId<<" with pT = "<<toolInput[i].muon->pt()/Gaudi::Units::GeV << "GeV");
321 TrigCompositeUtils::addDecisionID(m_decisionId.numeric(), toolInput[i].decision);
322 }
323 return StatusCode::SUCCESS;
324}
325float TrigMuonEFHypoTool::getdphi(float phi1, float phi2) const{
326 float dphi = phi1-phi2;
327 if(dphi > TMath::Pi()) dphi -= TMath::TwoPi();
328 if(dphi < -1*TMath::Pi()) dphi += TMath::TwoPi();
329 return fabs(dphi);
330}
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#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)
double charge(const T &p)
Definition AtlasPID.h:997
unsigned int uint
Header file to be included by clients of the Monitored infrastructure.
size_t size() const
Number of registered mappings.
static const Attributes_t empty
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
Gaudi::Property< bool > m_isFastReco
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]