ATLAS Offline Software
Loading...
Searching...
No Matches
TrigMultiTrkComboHypoTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5/**************************************************************************
6 **
7 ** File: Trigger/TrigHypothesis/TrigBPhysHypo/TrigMultiTrkHypoTool.cxx
8 **
9 ** Description: multi-track hypothesis tool for bphys triggers
10 **
11 ** Author: Heather Russell
12 **
13 **************************************************************************/
14
16
17#include <numeric>
18#include <vector>
19#include <iterator>
20#include <algorithm>
21#include "Math/GenVector/VectorUtil.h"
22
25
26
27TrigMultiTrkComboHypoTool::TrigMultiTrkComboHypoTool(const std::string& type, const std::string& name, const IInterface* parent)
28 : ComboHypoToolBase(type, name, parent) {}
29
30
32 ATH_MSG_DEBUG( "configuration for '" << this->name() << "'" << endmsg <<
33 " AcceptAll = " << (m_acceptAll ? "True" : "False") << endmsg <<
34 " isCombinedChain = " << (m_isCombinedChain ? "True" : "False") << endmsg <<
35 " isMergedElectronChain = " << (m_isMergedElectronChain ? "True" : "False") << endmsg <<
36 " mass range: ( " << m_massRange.value().first << ", " << m_massRange.value().second << " )" << endmsg <<
37 " chi2 cut: " << m_chi2 << endmsg <<
38 " " << (m_totalCharge < 0 ? "total charge cut is disabled" : "total charge cut: only right charge combinations") << endmsg <<
39 " LxyCut: > " << m_LxyCut.value() << endmsg <<
40 " sigmaLxyCut: > " << m_sigmaLxyCut.value() );
41
42 ATH_CHECK( m_nTrk >= 2 );
44
46 if ( m_legMultiplicities.size() > 1 ) { // chain with asymmetric legs, as HLT_mu6_2mu4_bDimu_L1MU6_3MU4
47 // here we consider each decision as an individual object, i.e. for HLT_mu6_2mu4_bDimu_L1MU6_3MU4 we use
48 // m_legDecisionIDs = {createLegName("HLT_mu6_2mu4_bDimu_L1MU6_3MU4", 0),
49 // createLegName("HLT_mu6_2mu4_bDimu_L1MU6_3MU4", 1),
50 // createLegName("HLT_mu6_2mu4_bDimu_L1MU6_3MU4", 1)};
51 for (size_t legIndex = 0; legIndex < m_legMultiplicities.size(); ++legIndex) {
52 // can not use legDecisionId(legIndex) at initialize() step, use TrigCompositeUtils::createLegName() instead
53 auto legId = TrigCompositeUtils::createLegName(decisionId(), legIndex);
54 m_legDecisionIDs.insert(m_legDecisionIDs.end(), m_legMultiplicities[legIndex], legId.numeric());
55 }
56 }
57 else { // chain with symmetric legs, as HLT_2mu4_bDimu_L12MU4
59 }
61 ATH_CHECK( m_trkPt.size() == 2 || !m_isMuonTrkPEB );
62
63 if (!m_monTool.empty()) {
64 ATH_CHECK( m_monTool.retrieve() );
65 ATH_MSG_DEBUG( "GenericMonitoringTool name:" << m_monTool );
66 }
67 else {
68 ATH_MSG_DEBUG( "No GenericMonitoringTool configured: no monitoring histograms will be available" );
69 }
70
71 return StatusCode::SUCCESS;
72}
73
74
76 ATH_MSG_DEBUG( "TrigMultiTrkComboHypoTool::passed()" );
77
78 auto mon_totalCharge = Monitored::Scalar<int>("totalCharge", -100);
79 auto mon_chi2 = Monitored::Scalar<float>("chi2", -1.);
80 auto mon_mass = Monitored::Scalar<float>("mass", -1.);
81 auto mon_pT_trk1 = Monitored::Scalar<float>("pT_trk1", -1.);
82 auto mon_pT_trk2 = Monitored::Scalar<float>("pT_trk2", -1.);
83 auto mon_D0_trk1 = Monitored::Scalar<float>("d0_trk1", -1.);
84 auto mon_D0_trk2 = Monitored::Scalar<float>("d0_trk2", -1.);
85 auto mon_Lxy = Monitored::Scalar<float>("Lxy", -1.);
86 auto mon_Eta1 = Monitored::Scalar<float>("eta_trk1", -100.);
87 auto mon_Eta2 = Monitored::Scalar<float>("eta_trk2", -100.);
88
89 auto mon = Monitored::Group( m_monTool, mon_totalCharge, mon_chi2, mon_mass, mon_pT_trk1, mon_pT_trk2, mon_Lxy, mon_D0_trk1, mon_D0_trk2, mon_Eta1, mon_Eta2);
90
91 if (m_acceptAll || (trigBphys->nTrackParticles() == m_nTrk &&
92 isInMassRange(trigBphys->mass()) &&
93 passedChi2Cut(trigBphys->fitchi2()) &&
94 passedChargeCut(totalCharge(trigBphys)) &&
96 (m_sigmaLxyCut < 0. || (trigBphys->lxyError() != 0. && trigBphys->lxy() / trigBphys->lxyError() > m_sigmaLxyCut)) &&
97 passedDeltaRcut(trigBphys) &&
98 passedPtCut(trigBphys))) {
99 mon_Lxy = trigBphys->lxy();
100 mon_totalCharge = totalCharge(trigBphys);
101 mon_chi2 = trigBphys->fitchi2();
102 mon_mass = 0.001 * trigBphys->mass();
103 mon_pT_trk1 = 0.001 * trigBphys->trackParticle(0)->pt();
104 mon_pT_trk2 = 0.001 * trigBphys->trackParticle(1)->pt();
105 mon_D0_trk1 = trigBphys->trackParticle(0)->d0();
106 mon_D0_trk2 = trigBphys->trackParticle(1)->d0();
107 mon_Eta1 = trigBphys->trackParticle(0)->eta();
108 mon_Eta2 = trigBphys->trackParticle(1)->eta();
109 ATH_MSG_DEBUG( "accepting event" );
110 return true;
111 }
112
113 ATH_MSG_DEBUG( "reject event" );
114 return false;
115}
116
117
118StatusCode TrigMultiTrkComboHypoTool::decideOnSingleObject(Decision* decision, const std::vector<const DecisionIDContainer*>& previousDecisionIDs) const {
119 ATH_MSG_DEBUG( "decideOnSingleObject trigger tool: " << decisionId() );
121
123 ATH_CHECK( trigBphysEL.isValid() );
124
125 if (previousDecisionIDs.size() != (m_isMergedElectronChain || m_isMuonTrkPEB ? 1 : m_nTrk.value())) {
126 return StatusCode::SUCCESS;
127 }
128
129 if (!checkPreviousDecisionIDs(previousDecisionIDs)) {
130 return StatusCode::SUCCESS;
131 }
132
133 if (m_acceptAll || passed(*trigBphysEL)) {
135 if (m_isCombinedChain) {
136 for (size_t i = 0; i < m_nTrk; ++i) {
138 }
139 }
140 }
141
142 return StatusCode::SUCCESS;
143}
144
145
146bool TrigMultiTrkComboHypoTool::checkPreviousDecisionIDs(const std::vector<const DecisionIDContainer*>& previousDecisionIDs) const {
147
148 // the default ComboHypoTool is used at the previous step (muEFCB) to check the number of muons is sufficient to fire the BLS trigger
149 // now we should only check the muons fitted to the common vertex are marked as passed the corresponding trigger
150 // trigger with asymmetric legs (like HLT_mu6_2mu4_bDimu_L1MU6_3MU4) is treated in a specific way:
151 // all 6 possible combinations should be checked: {leg0, leg1}, {leg0, leg2}, {leg1, leg0}, {leg1, leg2}, {leg2, leg0}, {leg2, leg1}
152
154 if (!TrigCompositeUtils::passed(m_legDecisionIDs.at(0), *previousDecisionIDs[0])) {
155 ATH_MSG_DEBUG( "Trigger for " << (m_isMergedElectronChain ? "close-by electrons" : "muon+track") << " didn't pass previous decision" );
156 return false;
157 }
158 return true;
159 }
160 else if (decisionId() == legDecisionId(0)) { // trigger with symmetric legs like HLT_3mu6_bDimu_L13MU6
161 for (size_t i = 0; i < m_nTrk; ++i) {
162 if (!TrigCompositeUtils::passed(decisionId().numeric(), *previousDecisionIDs[i])) {
163 ATH_MSG_DEBUG( "Trigger with symmetric legs didn't pass previous decision" );
164 return false;
165 }
166 }
167 ATH_MSG_DEBUG( "Trigger with symmetric legs passed previous decision" );
168 return true;
169 }
170 else { // trigger with asymmetric legs like HLT_mu6_2mu4_bDimu_L1MU6_3MU4
171
172 std::vector<size_t> a(m_legDecisionIDs.size());
173 std::iota(a.begin(), a.end(), 0); // {0, 1, 2, .., m_legDecisionIDs().size() - 1}
174 int i = 1;
175 bool result = true;
176 do {
177 result = true;
178 for (size_t k = 0; k < m_nTrk; ++k) {
179 result = result && TrigCompositeUtils::passed(m_legDecisionIDs.at(a[k]), *previousDecisionIDs[k]);
180 }
181 if (msgLvl(MSG::DEBUG)) {
182 msg() << "combination #" << i++ << ": { ";
183 std::copy(a.begin(), a.begin() + m_nTrk, std::ostream_iterator<int>(msg().stream(), " "));
184 msg() << "} " << (result ? " passed" : "didn't pass") << endmsg;
185 }
186 if (result) break;
187 } while (std::next_permutation(a.begin(), a.end()));
188 ATH_MSG_DEBUG( "Trigger with asymmetric legs " << (result ? "passed" : "didn't pass") << " previous decision" );
189 return result;
190 }
191 return true;
192}
193
194
196
197 const auto& range = m_massRange.value();
198 if ( range.first > 0. && mass < range.first ) return false;
199 if ( range.second > 0. && mass > range.second ) return false;
200 return true;
201}
202
204 if (m_deltaRMax == std::numeric_limits<float>::max() && m_deltaRMin == std::numeric_limits<float>::lowest()) { // Cut disabled
205 return true;
206 }
207 size_t N = trigBphys->nTrackParticles();
208 for (size_t i = 0 ; i < N; i++) {
209 auto p1 = trigBphys->trackParticle(i)->genvecP4();
210 for (size_t j = i + 1; j < N; j++) {
211 auto p2 = trigBphys->trackParticle(j)->genvecP4();
212 double deltaR = ROOT::Math::VectorUtil::DeltaR(p1, p2);
213 if (deltaR > m_deltaRMax || deltaR < m_deltaRMin) return false;
214 }
215 }
216 return true;
217}
218
220 if (!m_isMuonTrkPEB) return true;
221
222 size_t N = trigBphys->nTrackParticles();
223 for (size_t i = 0 ; i < N; ++i) {
224 if (m_trkPt[i] > 0. && trigBphys->trackParticle(i)->pt() < m_trkPt[i]) return false;
225 }
226 return true;
227}
228
230
231 int charge = 0;
232 for (size_t i = 0; i < trigBphys->nTrackParticles(); ++i) {
233 charge += static_cast<int>(trigBphys->trackParticle(i)->charge());
234 }
235 return charge;
236}
237
238
239bool TrigMultiTrkComboHypoTool::executeAlg(const std::vector<Combo::LegDecision>&, const EventContext&) const {
240 ATH_MSG_ERROR( "executeAlg() is not supported by TrigMultiTrkComboHypoTool" );
241 return true;
242}
Scalar deltaR(const MatrixBase< Derived > &vec) const
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_DEBUG(x)
double charge(const T &p)
Definition AtlasPID.h:997
static Double_t a
HLT::Identifier legDecisionId(size_t i) const
Retrieves this ComboHypoTool's chain's decision ID for a given leg.
ComboHypoToolBase(const std::string &type, const std::string &name, const IInterface *parent)
virtual HLT::Identifier decisionId() const
retrieves this ComboHypoTool's chain's decision ID
Group of local monitoring quantities and retain correlation when filling histograms
Declare a monitored scalar variable.
Gaudi::Property< float > m_LxyCut
virtual bool executeAlg(const std::vector< Combo::LegDecision > &, const EventContext &) const override
Only a dummy implementation exists in ComboHypoToolBase.
int totalCharge(const xAOD::TrigBphys *) const
bool passedDeltaRcut(const xAOD::TrigBphys *) const
ToolHandle< GenericMonitoringTool > m_monTool
Gaudi::Property< float > m_chi2
virtual StatusCode decideOnSingleObject(TrigCompositeUtils::Decision *, const std::vector< const TrigCompositeUtils::DecisionIDContainer * > &) const override
Alternate method called by BPhysics ComboHypoAlgs instead of the base method decide(....
bool checkPreviousDecisionIDs(const std::vector< const TrigCompositeUtils::DecisionIDContainer * > &) const
Gaudi::Property< std::pair< double, double > > m_massRange
Gaudi::Property< float > m_sigmaLxyCut
Gaudi::Property< bool > m_isMergedElectronChain
Gaudi::Property< bool > m_acceptAll
Gaudi::Property< unsigned int > m_nTrk
Gaudi::Property< float > m_deltaRMax
Gaudi::Property< std::vector< unsigned int > > m_legMultiplicities
bool passedPtCut(const xAOD::TrigBphys *) const
Gaudi::Property< float > m_deltaRMin
TrigMultiTrkComboHypoTool(const std::string &type, const std::string &name, const IInterface *parent)
Gaudi::Property< std::vector< double > > m_trkPt
Gaudi::Property< bool > m_isCombinedChain
bool passedChargeCut(int charge) const
Gaudi::Property< int > m_totalCharge
virtual StatusCode initialize() override
Gaudi::Property< bool > m_isMuonTrkPEB
bool passed(const xAOD::TrigBphys *) const
std::vector< TrigCompositeUtils::DecisionID > m_legDecisionIDs
float d0() const
Returns the parameter.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
GenVecFourMom_t genvecP4() const
The full 4-momentum of the particle : GenVector form.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
size_t nTrackParticles() const
Number of tracks used to make particle.
const xAOD::TrackParticle * trackParticle(size_t i) const
Get the Nth track's pointer.
float fitchi2() const
accessor method: chi2 from vertex fit
float lxy() const
accessor method: lxy
float lxyError() const
accessor method: lxy uncertainty
float mass() const
accessor method: mass
bool hasObjectLink(const std::string &name, const CLID clid=CLID_NULL) const
Check if a link to an object with a given name and type exists. CLID_NULL to not check type.
ElementLink< CONTAINER > objectLink(const std::string &name) const
Get the link with the requested name.
HLT::Identifier createLegName(const HLT::Identifier &chainIdentifier, size_t counter)
Generate the HLT::Identifier which corresponds to a specific leg of a given chain.
const std::string & featureString()
bool passed(DecisionID id, const DecisionIDContainer &idSet)
checks if required decision ID is in the set of IDs in the container
std::set< DecisionID > DecisionIDContainer
void addDecisionID(DecisionID id, Decision *d)
Appends the decision (given as ID) to the decision object.
TrigBphys_v1 TrigBphys
Definition TrigBphys.h:18
TrigBphysContainer_v1 TrigBphysContainer
MsgStream & msg
Definition testRead.cxx:32