ATLAS Offline Software
Loading...
Searching...
No Matches
FourMuonTool.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// 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 // retrieving V0 Fitter
39 ATH_CHECK( m_iV0VertexFitter.retrieve(DisableTool{!m_useV0Fitter}));
40
41 // Get the track selector tool from ToolSvc
42 ATH_CHECK ( m_trkSelector.retrieve() );
43 ATH_MSG_DEBUG("Retrieved tool " << m_trkSelector);
44
45 // Get the beam spot service
46 ATH_CHECK( m_eventInfo_key.initialize() );
47 ATH_CHECK(m_muonCollectionKey.initialize());
49 ATH_CHECK(m_muonIndex.initialize());
50 ATH_MSG_DEBUG("Initialize successful");
51
52 return StatusCode::SUCCESS;
53
54 }
55
56 FourMuonTool::FourMuonTool(const std::string& t, const std::string& n, const IInterface* p) : AthAlgTool(t,n,p)
57 {
58 }
59
61
62 //-------------------------------------------------------------------------------------
63 // Find the candidates
64 //-------------------------------------------------------------------------------------
65 StatusCode FourMuonTool::performSearch(xAOD::VertexContainer* pairVxContainer, xAOD::VertexContainer* quadVxContainer, bool &selectEvent, const EventContext& ctx) const
66 {
67 ATH_MSG_DEBUG( "FourMuonTool::performSearch" );
68 selectEvent = false;
69
70 // Get the muons from StoreGate
72 ATH_CHECK(importedMuonCollection.isValid());
73 ATH_MSG_DEBUG("Muon container size "<<importedMuonCollection->size());
74
75 // Get ID tracks
77 ATH_CHECK(importedTrackCollection.isValid());
78 ATH_MSG_DEBUG("ID TrackParticle container size "<< importedTrackCollection->size());
79
80 // Select the muons
81 std::vector<const xAOD::Muon*> theMuonsAfterSelection;
83 unsigned int nCombMuons = 0;
84 unsigned int nSegmentTaggedMuons = 0;
85
86 for (const auto * muon : *importedMuonCollection) {
87 if ( !muon ) continue;
88 muonDecorator(*muon) = -1; // all muons must be decorated
89 if ( (muon->muonType() != xAOD::Muon::Combined ) && (muon->muonType() != xAOD::Muon::SegmentTagged ) ) continue;
90 if (!muon->inDetTrackParticleLink().isValid()) continue; // No muons without ID tracks
91 auto& link = muon->inDetTrackParticleLink();
92 const xAOD::TrackParticle* muonTrk = *link;
93 if ( !muonTrk ) continue;
94 const xAOD::Vertex* vx{};
95 if ( !m_trkSelector->decision(*muonTrk, vx) ) continue; // all ID tracks must pass basic tracking cuts
96 if ( fabs(muonTrk->pt())<m_ptCut ) continue; // pt cut
97 if ( fabs(muonTrk->eta())>m_etaCut ) continue; // eta cut
98 if ( muon->muonType() == xAOD::Muon::Combined ) ++nCombMuons;
99 if ( muon->muonType() == xAOD::Muon::SegmentTagged ) ++nSegmentTaggedMuons;
100 theMuonsAfterSelection.push_back(muon);
101 }
102 unsigned int nSelectedMuons = theMuonsAfterSelection.size();
103 ATH_MSG_DEBUG("Number of muons after selection: " << nSelectedMuons);
104 ATH_MSG_DEBUG("of which " << nCombMuons << " are combined");
105 ATH_MSG_DEBUG("and " << nSegmentTaggedMuons << " are segment tagged");
106 if ( (nSelectedMuons < 4) || (nCombMuons < 1) ) {
107 ATH_MSG_DEBUG("Muon criteria not met. Skipping event.");
108 return StatusCode::SUCCESS;
109 }
110 selectEvent = true; // if we got this far we should definitively accept the event
111
112 // Decorators
113 SG::AuxElement::Decorator< std::string > indexDecorator("CombinationCode");
114 SG::AuxElement::Decorator< std::string > chargeDecorator("ChargeCode");
115
116 // Order by pT
117 std::sort(theMuonsAfterSelection.begin(), theMuonsAfterSelection.end(), [](const xAOD::Muon *a, const xAOD::Muon *b) {
118 return b->pt() < a->pt();
119 });
120
121 // Decorate the selected muons (now pT ordered) with their index
122 unsigned int muonIndex(0);
123 for (auto selMuon : theMuonsAfterSelection) {
124 muonDecorator(*selMuon) = muonIndex;
125 ++muonIndex;
126 }
127
128 // Quadruplet combinatorics
129 std::vector<Combination> quadruplets;
130 std::vector<Combination> pairs;
131 buildCombinations(theMuonsAfterSelection,pairs,quadruplets,nSelectedMuons);
132 if (quadruplets.size()==0) {
133 ATH_MSG_DEBUG("No acceptable quadruplets");
134 return StatusCode::SUCCESS;
135 }
136
137 // Get the beam spot (for the vertexing starting point)
139 ATH_CHECK(evt.isValid());
140 const Amg::Vector3D beamSpot(evt->beamPosX(), evt->beamPosY(), evt->beamPosZ());
141
142 // fit pairs
143 ATH_MSG_DEBUG("Successful pairs.....");
144 for (std::vector<Combination>::iterator pairItr = pairs.begin(); pairItr!=pairs.end(); ++pairItr) {
145 std::vector<const xAOD::TrackParticle*> theTracks = (*pairItr).trackParticles("pair1");
146 xAOD::Vertex* pairVxCandidate = fit(theTracks,importedTrackCollection.get(),beamSpot); // This line actually does the fitting and object making
147 if (pairVxCandidate) {
148 // decorate the candidate with its codes
149 indexDecorator(*pairVxCandidate) = (*pairItr).combinationIndices();
150 chargeDecorator(*pairVxCandidate) = (*pairItr).combinationCharges();
151 // decorate the candidate with refitted tracks and muons via the BPhysHelper
152 xAOD::BPhysHelper helper(pairVxCandidate);
153 helper.setRefTrks();
154 std::vector<const xAOD::Muon*> theStoredMuons;
155 theStoredMuons = (*pairItr).muons;
156 helper.setMuons(theStoredMuons,importedMuonCollection.get());
157 // Retain the vertex
158 pairVxContainer->push_back(pairVxCandidate);
159 ATH_MSG_DEBUG("..... indices: " << (*pairItr).combinationIndices() <<
160 " charges: " << (*pairItr).combinationCharges() <<
161 " chi2: " << pairVxCandidate->chiSquared());
162 } else { // fit failed
163 ATH_MSG_DEBUG("Fitter failed!");
164 }
165 }
166 ATH_MSG_DEBUG("pairContainer size " << pairVxContainer->size());
167
168 // fit quadruplets
169 ATH_MSG_DEBUG("Successful quadruplets.....");
170 for (std::vector<Combination>::iterator quadItr = quadruplets.begin(); quadItr!=quadruplets.end(); ++quadItr) {
171 std::vector<const xAOD::TrackParticle*> theDCTracks; theDCTracks.clear();
172 theDCTracks = (*quadItr).trackParticles("DC");
173 xAOD::Vertex* dcVxCandidate = fit(theDCTracks,importedTrackCollection.get(), beamSpot);
174 if (dcVxCandidate != 0) {
175 // decorate the candidate with its codes
176 indexDecorator(*dcVxCandidate) = (*quadItr).combinationIndices();
177 chargeDecorator(*dcVxCandidate) = (*quadItr).combinationCharges();
178 // Decorate the DC candidate with the differences between its chi2 and the other
179 double dcChi2 = dcVxCandidate->chiSquared();
180 // decorate the candidate with refitted tracks and muons via the BPhysHelper
181 xAOD::BPhysHelper helper(dcVxCandidate);
182 helper.setRefTrks();
183 const std::vector<const xAOD::Muon*> &theStoredMuons = (*quadItr).muons;
184 helper.setMuons(theStoredMuons,importedMuonCollection.get());
185 // Retain the vertex
186 quadVxContainer->push_back(dcVxCandidate);
187 ATH_MSG_DEBUG("..... indices: " << (*quadItr).combinationIndices() <<
188 " charges: " << (*quadItr).combinationCharges() <<
189 " chi2(DC): " << dcChi2);
190 } else { // fit failed
191 ATH_MSG_DEBUG("Fitter failed!");
192 }
193 }
194 ATH_MSG_DEBUG("quadruplet container size " << quadVxContainer->size());
195
196 return StatusCode::SUCCESS;;
197 }
198
199 // *********************************************************************************
200
201 // ---------------------------------------------------------------------------------
202 // fit - does the fit
203 // ---------------------------------------------------------------------------------
204
205 xAOD::Vertex* FourMuonTool::fit(const std::vector<const xAOD::TrackParticle*> &inputTracks,
206 const xAOD::TrackParticleContainer* importedTrackCollection,
207 const Amg::Vector3D &beamSpot) const {
208
209 const Trk::TrkV0VertexFitter* concreteVertexFitter=0;
210 if (m_useV0Fitter) {
211 // making a concrete fitter for the V0Fitter
212 concreteVertexFitter = dynamic_cast<const Trk::TrkV0VertexFitter * >(&(*m_iV0VertexFitter));
213 if(concreteVertexFitter == 0) {
214 ATH_MSG_FATAL("The vertex fitter passed is not a V0 Vertex Fitter");
215 return nullptr;
216 }
217 }
218
219 xAOD::Vertex* myVxCandidate{};
220 if (m_useV0Fitter) {
221 myVxCandidate = concreteVertexFitter->fit(inputTracks, beamSpot /*vertex startingPoint*/ );
222 } else {
223 myVxCandidate = m_iVertexFitter->fit(inputTracks, beamSpot /*vertex startingPoint*/ );
224 }
225
226 if(myVxCandidate) BPhysPVTools::PrepareVertexLinks(myVxCandidate, importedTrackCollection);
227
228 return myVxCandidate;
229
230 } // End of fit method
231
232
233 // *********************************************************************************
234
235 // ---------------------------------------------------------------------------------
236 // getQuadIndices: forms up index lists
237 // ---------------------------------------------------------------------------------
238
239 std::vector<std::vector<unsigned int> > FourMuonTool::getQuadIndices(unsigned int length) {
240
241 std::vector<std::vector<unsigned int> > quadIndices = mFromN(4,length);
242 return(quadIndices);
243 }
244
245
246 // *********************************************************************************
247
248 // ---------------------------------------------------------------------------------
249 // mFromN and combinatorics
250 // ---------------------------------------------------------------------------------
251 std::vector<std::vector<unsigned int> > FourMuonTool::mFromN(unsigned int m, unsigned int N) {
252
253 std::vector<std::vector<unsigned int> > allCombinations;
254 std::vector<unsigned int> mainList;
255 std::vector<unsigned int> combination;
256 for (unsigned int i=0; i<N; ++i) mainList.push_back(i);
257 combinatorics(0,m,combination,mainList,allCombinations);
258 return allCombinations;
259 }
260
261 void FourMuonTool::combinatorics(unsigned int offset,
262 unsigned int k,
263 std::vector<unsigned int> &combination,
264 std::vector<unsigned int> &mainList,
265 std::vector<std::vector<unsigned int> > &allCombinations) {
266 if (k==0) {
267 allCombinations.push_back(combination);
268 return;
269 }
270 if (k>0) {
271 for (unsigned int i=offset; i<=mainList.size()-k; ++i) {
272 combination.push_back(mainList[i]);
273 combinatorics(i+1,k-1,combination,mainList,allCombinations);
274 combination.pop_back();
275 }
276 }
277 }
278
279 // ---------------------------------------------------------------------------------
280 // getPairIndices
281 // ---------------------------------------------------------------------------------
282
283 std::vector<std::pair<unsigned int, unsigned int> > FourMuonTool::getPairIndices(unsigned int length){
284
285 std::vector<std::pair<unsigned int, unsigned int> > uniquePairs;
286 std::vector<std::vector<unsigned int> > doublets = mFromN(2,length);
287 for (std::vector<std::vector<unsigned int> >::iterator it=doublets.begin(); it!=doublets.end(); ++it) {
288 std::pair<unsigned int, unsigned int> tmpPair = std::make_pair((*it).at(0),(*it).at(1));
289 uniquePairs.push_back(tmpPair);
290 }
291
292 return(uniquePairs);
293 }
294
295
296
297 // *********************************************************************************
298
299 // ---------------------------------------------------------------------------------
300 // buildCombinations: forms up the quadruplet of muons/tracks
301 // ---------------------------------------------------------------------------------
302
303 void FourMuonTool::buildCombinations(const std::vector<const xAOD::Muon*> &muonsIn,
304 std::vector<Combination> &pairs,
305 std::vector<Combination> &quadruplets,
306 unsigned int nSelectedMuons) {
307
308 std::vector<std::vector<unsigned int> > quadrupletIndices = getQuadIndices(nSelectedMuons);
309 std::vector<std::pair<unsigned int, unsigned int> > pairIndices = getPairIndices(nSelectedMuons);
310
311 // Quadruplets
312 std::vector<std::vector<unsigned int> >::iterator quadItr;
313 for (quadItr=quadrupletIndices.begin(); quadItr!=quadrupletIndices.end(); ++quadItr) {
314 const std::vector<unsigned int> &quad = (*quadItr);
315 std::vector<const xAOD::Muon*> theMuons = {muonsIn[quad[0]],muonsIn[quad[1]],muonsIn[quad[2]],muonsIn[quad[3]]};
316 if (!passesQuadSelection(theMuons)) continue;
317 Combination tmpQuad;
318 tmpQuad.muons = std::move(theMuons);
319 tmpQuad.quadIndices = quad;
320 quadruplets.emplace_back(std::move(tmpQuad));
321 }
322 if (quadruplets.size() == 0) return;
323
324 // pairs
325 std::vector<std::pair<unsigned int, unsigned int> >::iterator pairItr;
326 for (pairItr=pairIndices.begin(); pairItr!=pairIndices.end(); ++pairItr) {
327 std::pair<unsigned int, unsigned int> pair = (*pairItr);
328 Combination tmpPair;
329 std::vector<const xAOD::Muon*> theMuons = {muonsIn[pair.first],muonsIn[pair.second]};
330 tmpPair.muons = std::move(theMuons);
331 tmpPair.pairIndices = pair;
332 pairs.emplace_back(std::move(tmpPair));
333 }
334
335 return;
336
337 }
338
339 // *********************************************************************************
340
341 // ---------------------------------------------------------------------------------
342 // passesQuadSelection: 4-muon selection
343 // ---------------------------------------------------------------------------------
344
345 bool FourMuonTool::passesQuadSelection(const std::vector<const xAOD::Muon*> &muons) {
346 bool accept(false);
347 bool charges(true);
348 bool quality(false);
349 if (( muons.at(0)->muonType() == xAOD::Muon::Combined ) ||
350 ( muons.at(1)->muonType() == xAOD::Muon::Combined ) ||
351 ( muons.at(2)->muonType() == xAOD::Muon::Combined ) ||
352 ( muons.at(3)->muonType() == xAOD::Muon::Combined )
353 ) quality = true;
354 if (charges && quality) accept = true;
355 return accept;
356 }
357
358}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(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
xAOD::Vertex * fit(const std::vector< const xAOD::TrackParticle * > &, const xAOD::TrackParticleContainer *importedTrackCollection, const Amg::Vector3D &beamSpot) const
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
Gaudi::Property< bool > m_useV0Fitter
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)
PublicToolHandle< Trk::IVertexFitter > m_iV0VertexFitter
SG::Decorator< T, ALLOC > Decorator
Definition AuxElement.h:575
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.
This class implements a vertex fitting algorithm optimised for V0 finding.
virtual xAOD::Vertex * fit(const std::vector< const xAOD::TrackParticle * > &vectorTrk, const Amg::Vector3D &startingPoint) const override
Interface for xAOD::TrackParticle with Amg::Vector3D starting point.
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.
float chiSquared() const
Returns the of the vertex fit as float.
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