ATLAS Offline Software
Loading...
Searching...
No Matches
FourMuonTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// ****************************************************************************
6// ----------------------------------------------------------------------------
7// FourMuonTool
8// James Catmore <James.Catmore@cern.ch>
9// Evelina Bouhova-Thacker <e.bouhova@cern.ch>
10// ----------------------------------------------------------------------------
11// ****************************************************************************
12
13#include "FourMuonTool.h"
14#include "BPhysPVTools.h"
19#include "AthLinks/ElementLink.h"
20
21#include "xAODTracking/Vertex.h"
27
28#include <algorithm>
29
30namespace DerivationFramework {
31
33
34 // retrieving vertex Fitter
35 ATH_CHECK( m_iVertexFitter.retrieve() );
36 ATH_MSG_DEBUG("Retrieved tool " << m_iVertexFitter);
37
38
39 // Get the track selector tool from ToolSvc
40 ATH_CHECK ( m_trkSelector.retrieve() );
41 ATH_MSG_DEBUG("Retrieved tool " << m_trkSelector);
42
43 // Get the beam spot service
44 ATH_CHECK( m_eventInfo_key.initialize() );
45 ATH_CHECK(m_muonCollectionKey.initialize());
47 ATH_CHECK(m_muonIndex.initialize());
48 ATH_MSG_DEBUG("Initialize successful");
49
50 return StatusCode::SUCCESS;
51
52 }
53
54 FourMuonTool::FourMuonTool(const std::string& t, const std::string& n, const IInterface* p) : AthAlgTool(t,n,p)
55 {
56 }
57
59
60 //-------------------------------------------------------------------------------------
61 // Find the candidates
62 //-------------------------------------------------------------------------------------
63 StatusCode FourMuonTool::performSearch(xAOD::VertexContainer* pairVxContainer, xAOD::VertexContainer* quadVxContainer, bool &selectEvent, const EventContext& ctx) const
64 {
65 ATH_MSG_DEBUG( "FourMuonTool::performSearch" );
66 selectEvent = false;
67
68 // Get the muons from StoreGate
70 ATH_CHECK(importedMuonCollection.isValid());
71 ATH_MSG_DEBUG("Muon container size "<<importedMuonCollection->size());
72
73 // Get ID tracks
75 ATH_CHECK(importedTrackCollection.isValid());
76 ATH_MSG_DEBUG("ID TrackParticle container size "<< importedTrackCollection->size());
77
78 // Select the muons
79 std::vector<const xAOD::Muon*> theMuonsAfterSelection;
81 unsigned int nCombMuons = 0;
82 unsigned int nSegmentTaggedMuons = 0;
83
84 for (const auto * muon : *importedMuonCollection) {
85 if ( !muon ) continue;
86 muonDecorator(*muon) = -1; // all muons must be decorated
87 if ( (muon->muonType() != xAOD::Muon::MuonType::Combined ) && (muon->muonType() != xAOD::Muon::MuonType::SegmentTagged ) ) continue;
88 const xAOD::TrackParticle* muonTrk = muon->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
89 if ( !muonTrk ) continue;
90 const xAOD::Vertex* vx{};
91 if ( !m_trkSelector->decision(*muonTrk, vx) ) continue; // all ID tracks must pass basic tracking cuts
92 if ( fabs(muonTrk->pt())<m_ptCut ) continue; // pt cut
93 if ( fabs(muonTrk->eta())>m_etaCut ) continue; // eta cut
94 if ( muon->muonType() == xAOD::Muon::MuonType::Combined ) ++nCombMuons;
95 if ( muon->muonType() == xAOD::Muon::MuonType::SegmentTagged ) ++nSegmentTaggedMuons;
96 theMuonsAfterSelection.push_back(muon);
97 }
98 unsigned int nSelectedMuons = theMuonsAfterSelection.size();
99 ATH_MSG_DEBUG("Number of muons after selection: " << nSelectedMuons);
100 ATH_MSG_DEBUG("of which " << nCombMuons << " are combined");
101 ATH_MSG_DEBUG("and " << nSegmentTaggedMuons << " are segment tagged");
102 if ( (nSelectedMuons < 4) || (nCombMuons < 1) ) {
103 ATH_MSG_DEBUG("Muon criteria not met. Skipping event.");
104 return StatusCode::SUCCESS;
105 }
106 selectEvent = true; // if we got this far we should definitively accept the event
107
108 // Decorators
109 SG::AuxElement::Decorator< std::string > indexDecorator("CombinationCode");
110 SG::AuxElement::Decorator< std::string > chargeDecorator("ChargeCode");
111
112 // Order by pT
113 std::sort(theMuonsAfterSelection.begin(), theMuonsAfterSelection.end(), [](const xAOD::Muon *a, const xAOD::Muon *b) {
114 return b->pt() < a->pt();
115 });
116
117 // Decorate the selected muons (now pT ordered) with their index
118 unsigned int muonIndex(0);
119 for (auto selMuon : theMuonsAfterSelection) {
120 muonDecorator(*selMuon) = muonIndex;
121 ++muonIndex;
122 }
123
124 // Quadruplet combinatorics
125 std::vector<Combination> quadruplets;
126 std::vector<Combination> pairs;
127 buildCombinations(theMuonsAfterSelection,pairs,quadruplets,nSelectedMuons);
128 if (quadruplets.size()==0) {
129 ATH_MSG_DEBUG("No acceptable quadruplets");
130 return StatusCode::SUCCESS;
131 }
132
133 // Get the beam spot (for the vertexing starting point)
135 ATH_CHECK(evt.isValid());
136 const Amg::Vector3D beamSpot(evt->beamPosX(), evt->beamPosY(), evt->beamPosZ());
137
138 // fit pairs
139 ATH_MSG_DEBUG("Successful pairs.....");
140 for (std::vector<Combination>::iterator pairItr = pairs.begin(); pairItr!=pairs.end(); ++pairItr) {
141 std::vector<const xAOD::TrackParticle*> theTracks = (*pairItr).trackParticles("pair1");
142 std::unique_ptr<xAOD::Vertex> pairVxCandidate = fit(ctx,theTracks,importedTrackCollection.get(),beamSpot); // This line actually does the fitting and object making
143 if (pairVxCandidate) {
144 // decorate the candidate with its codes
145 indexDecorator(*pairVxCandidate) = (*pairItr).combinationIndices();
146 chargeDecorator(*pairVxCandidate) = (*pairItr).combinationCharges();
147 // decorate the candidate with refitted tracks and muons via the BPhysHelper
148 xAOD::BPhysHelper helper(pairVxCandidate.get());
149 helper.setRefTrks();
150 std::vector<const xAOD::Muon*> theStoredMuons;
151 theStoredMuons = (*pairItr).muons;
152 helper.setMuons(theStoredMuons,importedMuonCollection.get());
153 ATH_MSG_DEBUG("..... indices: " << (*pairItr).combinationIndices() <<
154 " charges: " << (*pairItr).combinationCharges() <<
155 " chi2: " << pairVxCandidate->chiSquared());
156 // Retain the vertex
157 pairVxContainer->push_back(std::move(pairVxCandidate));
158 } else { // fit failed
159 ATH_MSG_DEBUG("Fitter failed!");
160 }
161 }
162 ATH_MSG_DEBUG("pairContainer size " << pairVxContainer->size());
163
164 // fit quadruplets
165 ATH_MSG_DEBUG("Successful quadruplets.....");
166 for (std::vector<Combination>::iterator quadItr = quadruplets.begin(); quadItr!=quadruplets.end(); ++quadItr) {
167 std::vector<const xAOD::TrackParticle*> theDCTracks; theDCTracks.clear();
168 theDCTracks = (*quadItr).trackParticles("DC");
169 std::unique_ptr<xAOD::Vertex> dcVxCandidate = fit(ctx,theDCTracks,importedTrackCollection.get(), beamSpot);
170 if (dcVxCandidate != 0) {
171 // decorate the candidate with its codes
172 indexDecorator(*dcVxCandidate) = (*quadItr).combinationIndices();
173 chargeDecorator(*dcVxCandidate) = (*quadItr).combinationCharges();
174 // Decorate the DC candidate with the differences between its chi2 and the other
175 double dcChi2 = dcVxCandidate->chiSquared();
176 // decorate the candidate with refitted tracks and muons via the BPhysHelper
177 xAOD::BPhysHelper helper(dcVxCandidate.get());
178 helper.setRefTrks();
179 const std::vector<const xAOD::Muon*> &theStoredMuons = (*quadItr).muons;
180 helper.setMuons(theStoredMuons,importedMuonCollection.get());
181 // Retain the vertex
182 quadVxContainer->push_back(std::move(dcVxCandidate));
183 ATH_MSG_DEBUG("..... indices: " << (*quadItr).combinationIndices() <<
184 " charges: " << (*quadItr).combinationCharges() <<
185 " chi2(DC): " << dcChi2);
186 } else { // fit failed
187 ATH_MSG_DEBUG("Fitter failed!");
188 }
189 }
190 ATH_MSG_DEBUG("quadruplet container size " << quadVxContainer->size());
191 if(quadVxContainer->size() > 500){
192 ATH_MSG_WARNING("Event Run: " << evt->runNumber() << " Event: " << evt->eventNumber() << " quadruplet container size " << quadVxContainer->size());
193 }
194
195 return StatusCode::SUCCESS;;
196 }
197
198 // *********************************************************************************
199
200 // ---------------------------------------------------------------------------------
201 // fit - does the fit
202 // ---------------------------------------------------------------------------------
203
204 std::unique_ptr<xAOD::Vertex> FourMuonTool::fit(const EventContext& ctx,
205 const std::vector<const xAOD::TrackParticle*> &inputTracks,
206 const xAOD::TrackParticleContainer* importedTrackCollection,
207 const Amg::Vector3D &beamSpot) const {
208
209
210 std::unique_ptr<xAOD::Vertex> myVxCandidate = m_iVertexFitter->fit(ctx, inputTracks, beamSpot /*vertex startingPoint*/ );
211
212 if(myVxCandidate) BPhysPVTools::PrepareVertexLinks(myVxCandidate.get(), importedTrackCollection);
213
214 return myVxCandidate;
215
216 } // End of fit method
217
218
219 // *********************************************************************************
220
221 // ---------------------------------------------------------------------------------
222 // getQuadIndices: forms up index lists
223 // ---------------------------------------------------------------------------------
224
225 std::vector<std::vector<unsigned int> > FourMuonTool::getQuadIndices(unsigned int length) {
226
227 std::vector<std::vector<unsigned int> > quadIndices = mFromN(4,length);
228 return(quadIndices);
229 }
230
231
232 // *********************************************************************************
233
234 // ---------------------------------------------------------------------------------
235 // mFromN and combinatorics
236 // ---------------------------------------------------------------------------------
237 std::vector<std::vector<unsigned int> > FourMuonTool::mFromN(unsigned int m, unsigned int N) {
238
239 std::vector<std::vector<unsigned int> > allCombinations;
240 std::vector<unsigned int> mainList;
241 std::vector<unsigned int> combination;
242 for (unsigned int i=0; i<N; ++i) mainList.push_back(i);
243 combinatorics(0,m,combination,mainList,allCombinations);
244 return allCombinations;
245 }
246
247 void FourMuonTool::combinatorics(unsigned int offset,
248 unsigned int k,
249 std::vector<unsigned int> &combination,
250 std::vector<unsigned int> &mainList,
251 std::vector<std::vector<unsigned int> > &allCombinations) {
252 if (k==0) {
253 allCombinations.push_back(combination);
254 return;
255 }
256 if (k>0) {
257 for (unsigned int i=offset; i<=mainList.size()-k; ++i) {
258 combination.push_back(mainList[i]);
259 combinatorics(i+1,k-1,combination,mainList,allCombinations);
260 combination.pop_back();
261 }
262 }
263 }
264
265 // ---------------------------------------------------------------------------------
266 // getPairIndices
267 // ---------------------------------------------------------------------------------
268
269 std::vector<std::pair<unsigned int, unsigned int> > FourMuonTool::getPairIndices(unsigned int length){
270
271 std::vector<std::pair<unsigned int, unsigned int> > uniquePairs;
272 std::vector<std::vector<unsigned int> > doublets = mFromN(2,length);
273 for (std::vector<std::vector<unsigned int> >::iterator it=doublets.begin(); it!=doublets.end(); ++it) {
274 std::pair<unsigned int, unsigned int> tmpPair = std::make_pair((*it).at(0),(*it).at(1));
275 uniquePairs.push_back(tmpPair);
276 }
277
278 return(uniquePairs);
279 }
280
281
282
283 // *********************************************************************************
284
285 // ---------------------------------------------------------------------------------
286 // buildCombinations: forms up the quadruplet of muons/tracks
287 // ---------------------------------------------------------------------------------
288
289 void FourMuonTool::buildCombinations(const std::vector<const xAOD::Muon*> &muonsIn,
290 std::vector<Combination> &pairs,
291 std::vector<Combination> &quadruplets,
292 unsigned int nSelectedMuons) {
293
294 std::vector<std::vector<unsigned int> > quadrupletIndices = getQuadIndices(nSelectedMuons);
295 std::vector<std::pair<unsigned int, unsigned int> > pairIndices = getPairIndices(nSelectedMuons);
296
297 // Quadruplets
298 std::vector<std::vector<unsigned int> >::iterator quadItr;
299 for (quadItr=quadrupletIndices.begin(); quadItr!=quadrupletIndices.end(); ++quadItr) {
300 const std::vector<unsigned int> &quad = (*quadItr);
301 std::vector<const xAOD::Muon*> theMuons = {muonsIn[quad[0]],muonsIn[quad[1]],muonsIn[quad[2]],muonsIn[quad[3]]};
302 if (!passesQuadSelection(theMuons)) continue;
303 Combination tmpQuad;
304 tmpQuad.muons = std::move(theMuons);
305 tmpQuad.quadIndices = quad;
306 quadruplets.emplace_back(std::move(tmpQuad));
307 }
308 if (quadruplets.size() == 0) return;
309
310 // pairs
311 std::vector<std::pair<unsigned int, unsigned int> >::iterator pairItr;
312 for (pairItr=pairIndices.begin(); pairItr!=pairIndices.end(); ++pairItr) {
313 std::pair<unsigned int, unsigned int> pair = (*pairItr);
314 Combination tmpPair;
315 std::vector<const xAOD::Muon*> theMuons = {muonsIn[pair.first],muonsIn[pair.second]};
316 tmpPair.muons = std::move(theMuons);
317 tmpPair.pairIndices = pair;
318 pairs.emplace_back(std::move(tmpPair));
319 }
320
321 return;
322
323 }
324
325 // *********************************************************************************
326
327 // ---------------------------------------------------------------------------------
328 // passesQuadSelection: 4-muon selection
329 // ---------------------------------------------------------------------------------
330
331 bool FourMuonTool::passesQuadSelection(const std::vector<const xAOD::Muon*> &muons) {
332 bool accept(false);
333 bool charges(true);
334 bool quality(false);
335 if (( muons.at(0)->muonType() == xAOD::Muon::MuonType::Combined ) ||
336 ( muons.at(1)->muonType() == xAOD::Muon::MuonType::Combined ) ||
337 ( muons.at(2)->muonType() == xAOD::Muon::MuonType::Combined ) ||
338 ( muons.at(3)->muonType() == xAOD::Muon::MuonType::Combined )
339 ) quality = true;
340 if (charges && quality) accept = true;
341 return accept;
342 }
343
344}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
: B-physics xAOD helpers.
double length(const pvec &v)
static Double_t a
Handle class for adding a decoration to an object.
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
value_type push_back(value_type pElem)
Add an element to the end of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
static void PrepareVertexLinks(xAOD::Vertex *theResult, const xAOD::TrackParticleContainer *importedTrackCollection)
FourMuonTool(const std::string &t, const std::string &n, const IInterface *p)
static void combinatorics(unsigned int offset, unsigned int k, std::vector< unsigned int > &combination, std::vector< unsigned int > &mainList, std::vector< std::vector< unsigned int > > &allCombinations)
static bool passesQuadSelection(const std::vector< const xAOD::Muon * > &muonsIn)
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfo_key
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_TrkParticleCollection
PublicToolHandle< Trk::ITrackSelectorTool > m_trkSelector
PublicToolHandle< Trk::IVertexFitter > m_iVertexFitter
static std::vector< std::vector< unsigned int > > getQuadIndices(unsigned int length)
SG::ReadHandleKey< xAOD::MuonContainer > m_muonCollectionKey
static void buildCombinations(const std::vector< const xAOD::Muon * > &muonsIn, std::vector< Combination > &pairs, std::vector< Combination > &quadruplets, unsigned int nSelectedMuons)
StatusCode performSearch(xAOD::VertexContainer *pairVxContainer, xAOD::VertexContainer *quadVxContainer, bool &acceptEvent, const EventContext &ctx) const
Gaudi::Property< double > m_etaCut
static std::vector< std::pair< unsigned int, unsigned int > > getPairIndices(unsigned int length)
SG::WriteDecorHandleKey< xAOD::MuonContainer > m_muonIndex
Gaudi::Property< double > m_ptCut
static std::vector< std::vector< unsigned int > > mFromN(unsigned int m, unsigned int n)
std::unique_ptr< xAOD::Vertex > fit(const EventContext &ctx, const std::vector< const xAOD::TrackParticle * > &, const xAOD::TrackParticleContainer *importedTrackCollection, const Amg::Vector3D &beamSpot) const
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type get() const
Dereference the pointer, but don't cache anything.
Handle class for adding a decoration to an object.
STL class.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
Eigen::Matrix< double, 3, 1 > Vector3D
THE reconstruction tool.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
Vertex_v1 Vertex
Define the latest version of the vertex class.
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".
Muon_v1 Muon
Reference the current persistent version:
std::vector< const xAOD::Muon * > muons
std::vector< unsigned int > quadIndices
std::pair< unsigned int, unsigned int > pairIndices