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::Decorator< std::string > indexDecorator("CombinationCode");
110 SG::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 const std::string pairStr{"pair1"};
141 for (std::vector<Combination>::iterator pairItr = pairs.begin(); pairItr!=pairs.end(); ++pairItr) {
142 std::vector<const xAOD::TrackParticle*> theTracks = (*pairItr).trackParticles(pairStr);
143 std::unique_ptr<xAOD::Vertex> pairVxCandidate = fit(ctx,theTracks,importedTrackCollection.get(),beamSpot); // This line actually does the fitting and object making
144 if (pairVxCandidate) {
145 // decorate the candidate with its codes
146 indexDecorator(*pairVxCandidate) = (*pairItr).combinationIndices();
147 chargeDecorator(*pairVxCandidate) = (*pairItr).combinationCharges();
148 // decorate the candidate with refitted tracks and muons via the BPhysHelper
149 xAOD::BPhysHelper helper(pairVxCandidate.get());
150 helper.setRefTrks();
151 std::vector<const xAOD::Muon*> theStoredMuons;
152 theStoredMuons = (*pairItr).muons;
153 helper.setMuons(theStoredMuons,importedMuonCollection.get());
154 ATH_MSG_DEBUG("..... indices: " << (*pairItr).combinationIndices() <<
155 " charges: " << (*pairItr).combinationCharges() <<
156 " chi2: " << pairVxCandidate->chiSquared());
157 // Retain the vertex
158 pairVxContainer->push_back(std::move(pairVxCandidate));
159 } else { // fit failed
160 ATH_MSG_DEBUG("Fitter failed!");
161 }
162 }
163 ATH_MSG_DEBUG("pairContainer size " << pairVxContainer->size());
164
165 // fit quadruplets
166 ATH_MSG_DEBUG("Successful quadruplets.....");
167 const std::string dcStr{"DC"};
168 for (std::vector<Combination>::iterator quadItr = quadruplets.begin(); quadItr!=quadruplets.end(); ++quadItr) {
169 std::vector<const xAOD::TrackParticle*> theDCTracks; theDCTracks.clear();
170 theDCTracks = (*quadItr).trackParticles(dcStr);
171 std::unique_ptr<xAOD::Vertex> dcVxCandidate = fit(ctx,theDCTracks,importedTrackCollection.get(), beamSpot);
172 if (dcVxCandidate != 0) {
173 // decorate the candidate with its codes
174 indexDecorator(*dcVxCandidate) = (*quadItr).combinationIndices();
175 chargeDecorator(*dcVxCandidate) = (*quadItr).combinationCharges();
176 // Decorate the DC candidate with the differences between its chi2 and the other
177 double dcChi2 = dcVxCandidate->chiSquared();
178 // decorate the candidate with refitted tracks and muons via the BPhysHelper
179 xAOD::BPhysHelper helper(dcVxCandidate.get());
180 helper.setRefTrks();
181 const std::vector<const xAOD::Muon*> &theStoredMuons = (*quadItr).muons;
182 helper.setMuons(theStoredMuons,importedMuonCollection.get());
183 // Retain the vertex
184 quadVxContainer->push_back(std::move(dcVxCandidate));
185 ATH_MSG_DEBUG("..... indices: " << (*quadItr).combinationIndices() <<
186 " charges: " << (*quadItr).combinationCharges() <<
187 " chi2(DC): " << dcChi2);
188 } else { // fit failed
189 ATH_MSG_DEBUG("Fitter failed!");
190 }
191 }
192 ATH_MSG_DEBUG("quadruplet container size " << quadVxContainer->size());
193 if(quadVxContainer->size() > 500){
194 ATH_MSG_WARNING("Event Run: " << evt->runNumber() << " Event: " << evt->eventNumber() << " quadruplet container size " << quadVxContainer->size());
195 }
196
197 return StatusCode::SUCCESS;;
198 }
199
200 // *********************************************************************************
201
202 // ---------------------------------------------------------------------------------
203 // fit - does the fit
204 // ---------------------------------------------------------------------------------
205
206 std::unique_ptr<xAOD::Vertex> FourMuonTool::fit(const EventContext& ctx,
207 const std::vector<const xAOD::TrackParticle*> &inputTracks,
208 const xAOD::TrackParticleContainer* importedTrackCollection,
209 const Amg::Vector3D &beamSpot) const {
210
211
212 std::unique_ptr<xAOD::Vertex> myVxCandidate = m_iVertexFitter->fit(ctx, inputTracks, beamSpot /*vertex startingPoint*/ );
213
214 if(myVxCandidate) BPhysPVTools::PrepareVertexLinks(myVxCandidate.get(), importedTrackCollection);
215
216 return myVxCandidate;
217
218 } // End of fit method
219
220
221 // *********************************************************************************
222
223 // ---------------------------------------------------------------------------------
224 // getQuadIndices: forms up index lists
225 // ---------------------------------------------------------------------------------
226
227 std::vector<std::vector<unsigned int> > FourMuonTool::getQuadIndices(unsigned int length) {
228
229 std::vector<std::vector<unsigned int> > quadIndices = mFromN(4,length);
230 return(quadIndices);
231 }
232
233
234 // *********************************************************************************
235
236 // ---------------------------------------------------------------------------------
237 // mFromN and combinatorics
238 // ---------------------------------------------------------------------------------
239 std::vector<std::vector<unsigned int> > FourMuonTool::mFromN(unsigned int m, unsigned int N) {
240
241 std::vector<std::vector<unsigned int> > allCombinations;
242 std::vector<unsigned int> mainList;
243 std::vector<unsigned int> combination;
244 for (unsigned int i=0; i<N; ++i) mainList.push_back(i);
245 combinatorics(0,m,combination,mainList,allCombinations);
246 return allCombinations;
247 }
248
249 void FourMuonTool::combinatorics(unsigned int offset,
250 unsigned int k,
251 std::vector<unsigned int> &combination,
252 std::vector<unsigned int> &mainList,
253 std::vector<std::vector<unsigned int> > &allCombinations) {
254 if (k==0) {
255 allCombinations.push_back(combination);
256 return;
257 }
258 if (k>0) {
259 for (unsigned int i=offset; i<=mainList.size()-k; ++i) {
260 combination.push_back(mainList[i]);
261 combinatorics(i+1,k-1,combination,mainList,allCombinations);
262 combination.pop_back();
263 }
264 }
265 }
266
267 // ---------------------------------------------------------------------------------
268 // getPairIndices
269 // ---------------------------------------------------------------------------------
270
271 std::vector<std::pair<unsigned int, unsigned int> > FourMuonTool::getPairIndices(unsigned int length){
272
273 std::vector<std::pair<unsigned int, unsigned int> > uniquePairs;
274 std::vector<std::vector<unsigned int> > doublets = mFromN(2,length);
275 for (std::vector<std::vector<unsigned int> >::iterator it=doublets.begin(); it!=doublets.end(); ++it) {
276 std::pair<unsigned int, unsigned int> tmpPair = std::make_pair((*it).at(0),(*it).at(1));
277 uniquePairs.push_back(tmpPair);
278 }
279
280 return(uniquePairs);
281 }
282
283
284
285 // *********************************************************************************
286
287 // ---------------------------------------------------------------------------------
288 // buildCombinations: forms up the quadruplet of muons/tracks
289 // ---------------------------------------------------------------------------------
290
291 void FourMuonTool::buildCombinations(const std::vector<const xAOD::Muon*> &muonsIn,
292 std::vector<Combination> &pairs,
293 std::vector<Combination> &quadruplets,
294 unsigned int nSelectedMuons) {
295
296 std::vector<std::vector<unsigned int> > quadrupletIndices = getQuadIndices(nSelectedMuons);
297 std::vector<std::pair<unsigned int, unsigned int> > pairIndices = getPairIndices(nSelectedMuons);
298
299 // Quadruplets
300 std::vector<std::vector<unsigned int> >::iterator quadItr;
301 for (quadItr=quadrupletIndices.begin(); quadItr!=quadrupletIndices.end(); ++quadItr) {
302 const std::vector<unsigned int> &quad = (*quadItr);
303 std::vector<const xAOD::Muon*> theMuons = {muonsIn[quad[0]],muonsIn[quad[1]],muonsIn[quad[2]],muonsIn[quad[3]]};
304 if (!passesQuadSelection(theMuons)) continue;
305 Combination tmpQuad;
306 tmpQuad.muons = std::move(theMuons);
307 tmpQuad.quadIndices = quad;
308 quadruplets.emplace_back(std::move(tmpQuad));
309 }
310 if (quadruplets.size() == 0) return;
311
312 // pairs
313 std::vector<std::pair<unsigned int, unsigned int> >::iterator pairItr;
314 for (pairItr=pairIndices.begin(); pairItr!=pairIndices.end(); ++pairItr) {
315 std::pair<unsigned int, unsigned int> pair = (*pairItr);
316 Combination tmpPair;
317 std::vector<const xAOD::Muon*> theMuons = {muonsIn[pair.first],muonsIn[pair.second]};
318 tmpPair.muons = std::move(theMuons);
319 tmpPair.pairIndices = pair;
320 pairs.emplace_back(std::move(tmpPair));
321 }
322
323 return;
324
325 }
326
327 // *********************************************************************************
328
329 // ---------------------------------------------------------------------------------
330 // passesQuadSelection: 4-muon selection
331 // ---------------------------------------------------------------------------------
332
333 bool FourMuonTool::passesQuadSelection(const std::vector<const xAOD::Muon*> &muons) {
334 bool accept(false);
335 bool charges(true);
336 bool quality(false);
337 if (( muons.at(0)->muonType() == xAOD::Muon::MuonType::Combined ) ||
338 ( muons.at(1)->muonType() == xAOD::Muon::MuonType::Combined ) ||
339 ( muons.at(2)->muonType() == xAOD::Muon::MuonType::Combined ) ||
340 ( muons.at(3)->muonType() == xAOD::Muon::MuonType::Combined )
341 ) quality = true;
342 if (charges && quality) accept = true;
343 return accept;
344 }
345
346}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_WARNING(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.
SG::Decorator< T, ALLOC > Decorator
Helper class to provide type-safe access to aux data, specialized for JaggedVecElt.
Definition AuxElement.h:576
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