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