ATLAS Offline Software
Loading...
Searching...
No Matches
JpsiFinder.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// JpsiFinder
8// James Catmore <James.Catmore@cern.ch>
9// Evelina Bouhova-Thacker <e.bouhova@cern.ch>
10// Daniel.Scheirich <daniel.scheirich@cern.ch>
11// Migration to xAOD
12// ----------------------------------------------------------------------------
13// ****************************************************************************
14
17#include "HepPDT/ParticleDataTable.hh"
18#include "AthLinks/ElementLink.h"
19#include "xAODTracking/Vertex.h"
26namespace Analysis {
27
29
30 // retrieving vertex Fitter
31 ATH_CHECK(m_iVertexFitter.retrieve());
32
33 // Get the track selector tool from ToolSvc
34 ATH_CHECK(m_trkSelector.retrieve());
35
36 // Get the vertex point estimator tool from ToolSvc
37 ATH_CHECK(m_vertexEstimator.retrieve());
38
39
40 ATH_CHECK(m_muonCollectionKey.initialize());
42 ATH_CHECK(m_MuonTrackKeys.initialize(m_MuonTrackKeys.size() != 0));
43
44 if (m_diMuons) {
45 // Get the Particle Properties Service
46 ATH_CHECK(m_partPropSvc.retrieve());
47 auto particleDataTable = m_partPropSvc->PDT();
48 const HepPDT::ParticleData* pd_mu = particleDataTable->particle(MC::MUON);
49 m_trk1M = pd_mu->mass();
50 m_trk2M = pd_mu->mass();
51 }
52
53 if (m_doTagAndProbe) ATH_MSG_WARNING("You have requested tag and probe mode. Duplicate mu+trk pairs WILL be allowed, charge ordering WILL NOT be done. Tag track will be first in each candidate");
54
55
56// // Check that the user's settings are sensible
57 bool illogicalOptions(false);
58 if ( (m_mumu && m_mutrk) || (m_mumu && m_trktrk) || (m_mutrk && m_trktrk) ) {
59 ATH_MSG_WARNING("You are requesting incompatible combinations of muons and tracks in the pairs. JpsiCandidates will be EMPTY!");
60 illogicalOptions=true;
61 };
63 ATH_MSG_WARNING("You are requesting Tag and Probe analysis but have not requested mu+trk mode. This is impossible. JpsiCandidates will be EMPTY!");
64 illogicalOptions=true;
65 };
66 if ( (m_mutrk || m_trktrk ) && m_useCombMeasurement ) {
67 ATH_MSG_WARNING("You are requesting a combined muon measurement to be used with pairs involving non-muon tracks. Not permitted. JpsiCandidates will be EMPTY!");
68 illogicalOptions=true;
69 };
71 ATH_MSG_WARNING("You are requesting incompatible combinations of combined muons non-combined muons in the pairs. JpsiCandidates will be EMPTY!");
72 illogicalOptions=true;
73 };
75 ATH_MSG_WARNING("You are requesting at least one muon to be combined in a tag and probe analysis. This doesn't make sense. JpsiCandidates will be EMPTY!");
76 illogicalOptions=true;
77 };
79 ATH_MSG_WARNING("You are requesting incompatible combinations of charges in the pairs. JpsiCandidates will be EMPTY!");
80 illogicalOptions=true;
81 };
83 if (!m_forceTagAndProbe){ //if m_forceTagAndProbe=TRUE then T&P will work with any charge combinations
84 ATH_MSG_WARNING("You are requesting same-sign or all-sign combinations in a tag and probe analysis. This doesn't make sense. JpsiCandidates will be EMPTY!");
85 illogicalOptions=true;
86 }
87 }
88 if (illogicalOptions) return StatusCode::FAILURE;;
89
90
91 ATH_MSG_DEBUG("Initialize successful");
92
93 return StatusCode::SUCCESS;
94
95 }
96
97
98 JpsiFinder::JpsiFinder(const std::string& t, const std::string& n, const IInterface* p) : base_class(t,n,p),
99 m_mumu(true),
100 m_mutrk(false),
101 m_trktrk(false),
102 m_allMuons(false),
103 m_combOnly(false),
104 m_atLeastOneComb(true),
106 m_diMuons(true),
107 m_trk1M(ParticleConstants::muonMassInMeV),
108 m_trk2M(ParticleConstants::muonMassInMeV),
109 m_thresholdPt(0.0),
110 m_higherPt(0.0),
111 m_trkThresholdPt(0.0),
112 m_invMassUpper(100000.0),
113 m_invMassLower(0.0),
114 m_collAngleTheta(0.0),
115 m_collAnglePhi(0.0),
116 m_Chi2Cut(50.),
117 m_oppChOnly(true),
118 m_sameChOnly(false),
119 m_allChCombs(false),
120 m_mcpCuts(true),
121 m_doTagAndProbe(false),
122 m_forceTagAndProbe(false) //forcing T&P method for any charge combinations
123
124 {
125 declareProperty("muAndMu",m_mumu);
126 declareProperty("muAndTrack",m_mutrk);
127 declareProperty("TrackAndTrack",m_trktrk);
128 declareProperty("allMuons",m_allMuons);
129 declareProperty("combOnly",m_combOnly);
130 declareProperty("atLeastOneComb",m_atLeastOneComb);
131 declareProperty("useCombinedMeasurement",m_useCombMeasurement);
132 declareProperty("assumeDiMuons",m_diMuons);
133 declareProperty("track1Mass",m_trk1M);
134 declareProperty("track2Mass",m_trk2M);
135 declareProperty("muonThresholdPt",m_thresholdPt);
136 declareProperty("higherPt",m_higherPt);
137 declareProperty("trackThresholdPt",m_trkThresholdPt);
138 declareProperty("invMassUpper",m_invMassUpper);
139 declareProperty("invMassLower",m_invMassLower);
140 declareProperty("collAngleTheta",m_collAngleTheta);
141 declareProperty("collAnglePhi",m_collAnglePhi);
142 declareProperty("Chi2Cut",m_Chi2Cut);
143 declareProperty("oppChargesOnly",m_oppChOnly);
144 declareProperty("sameChargesOnly",m_sameChOnly);
145 declareProperty("allChargeCombinations",m_allChCombs);
146 declareProperty("useMCPCuts",m_mcpCuts);
147 declareProperty("doTagAndProbe",m_doTagAndProbe);
148 declareProperty("forceTagAndProbe",m_forceTagAndProbe);
149 }
150
152
153 //-------------------------------------------------------------------------------------
154 // Find the candidates
155 //-------------------------------------------------------------------------------------
156 StatusCode JpsiFinder::performSearch(const EventContext& ctx, xAOD::VertexContainer& vxContainer) const
157 {
158 ATH_MSG_DEBUG( "JpsiFinder::performSearch" );
159
161 if(!muonhandle.isValid()){
162 ATH_MSG_ERROR("Could not retrieve " << m_muonCollectionKey.key());
163 return StatusCode::FAILURE;
164 }
165 // Get the muons from StoreGate
166 const xAOD::MuonContainer* importedMuonCollection = muonhandle.cptr();
167 ATH_MSG_DEBUG("Muon container size "<<importedMuonCollection->size());
168
169 // Get muon tracks if combined measurement requested
170 std::vector<const xAOD::TrackParticleContainer*> importedMuonTrackCollections;
172
173 for (SG::ReadHandle<xAOD::TrackParticleContainer>& handle: m_MuonTrackKeys.makeHandles(ctx)) {
174 if(!handle.isValid()){
175 ATH_MSG_WARNING("No muon TrackParticle collection with name " << handle.key() << " found in StoreGate!");
176 return StatusCode::FAILURE;
177 } else {
178 ATH_MSG_DEBUG("Found muon TrackParticle collection " << handle.key() << " in StoreGate!");
179 ATH_MSG_DEBUG("Muon TrackParticle container size "<< handle->size());
180 importedMuonTrackCollections.push_back(handle.cptr());
181 }
182 }
183 }
184
185 // Get ID tracks
187 const xAOD::TrackParticleContainer* importedTrackCollection{nullptr};
188 if(!handle.isValid()){
189 ATH_MSG_WARNING("No TrackParticle collection with name " << handle.key() << " found in StoreGate!");
190 return StatusCode::FAILURE;
191 } else {
192 importedTrackCollection = handle.cptr();
193 ATH_MSG_DEBUG("Found TrackParticle collection " << handle.key() << " in StoreGate!");
194 }
195 ATH_MSG_DEBUG("ID TrackParticle container size "<< handle->size());
196
197 // Typedef for vectors of tracks and muons
198 typedef std::vector<const xAOD::TrackParticle*> TrackBag;
199 typedef std::vector<const xAOD::Muon*> MuonBag;
200
201 // Select the inner detector tracks
202 const xAOD::Vertex* vx = nullptr;
203 TrackBag theIDTracksAfterSelection;
204 if (m_trktrk || m_mutrk) {
206 for (trkCItr=importedTrackCollection->begin(); trkCItr!=importedTrackCollection->end(); ++trkCItr) {
207 const xAOD::TrackParticle* TP = (*trkCItr);
208 if ( fabs(TP->pt())<m_trkThresholdPt ) continue;
209 if ( !m_trkSelector->decision(*TP, vx) ) continue;
210 theIDTracksAfterSelection.push_back(TP);
211 }
212 if (theIDTracksAfterSelection.size() == 0) return StatusCode::SUCCESS;;
213 ATH_MSG_DEBUG("Number of tracks after ID track selection: " << theIDTracksAfterSelection.size());
214 }
215
216 // Select the muons
217 MuonBag theMuonsAfterSelection;
218 if (m_mumu || m_mutrk) {
219 for (auto muItr=importedMuonCollection->begin(); muItr!=importedMuonCollection->end(); ++muItr) {
220 if ( *muItr == nullptr ) continue;
221 const xAOD::TrackParticle* muonTrk = (*muItr)->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle);
222 if ( muonTrk==NULL) continue;
223 if ( !m_trkSelector->decision(*muonTrk, vx) ) continue; // all ID tracks must pass basic tracking cuts
224 if ( fabs(muonTrk->pt())<m_thresholdPt ) continue; // higher pt cut if needed
225 if ( m_mcpCuts && !passesMCPCuts(*muItr)) continue; // MCP cuts
226 if ( m_combOnly && (*muItr)->muonType() != xAOD::Muon::MuonType::Combined ) continue; // require combined muons
227 if ( (*muItr)->muonType() == xAOD::Muon::MuonType::SiliconAssociatedForwardMuon && !m_useCombMeasurement) continue;
228 theMuonsAfterSelection.push_back(*muItr);
229 }
230 if (theMuonsAfterSelection.size() == 0) return StatusCode::SUCCESS;;
231 ATH_MSG_DEBUG("Number of muons after selection: " << theMuonsAfterSelection.size());
232 }
233
234 // Sort into pairs - end result will be a vector of JpsiCandidate structs
235 std::vector<JpsiCandidate> jpsiCandidates;
236 if (m_mumu) jpsiCandidates = getPairs(theMuonsAfterSelection);
237 if (m_trktrk) jpsiCandidates = getPairs(theIDTracksAfterSelection);
238 if (m_mutrk) jpsiCandidates = getPairs2Colls(theIDTracksAfterSelection,theMuonsAfterSelection,m_doTagAndProbe);
239
240
241 // (1) Enforce one combined muon
242 if (m_atLeastOneComb) {
243 std::vector<JpsiCandidate> selectCandidates;
244 for(auto &cand : jpsiCandidates) { if(cand.muonTypes!=TT) selectCandidates.push_back(cand); }
245 selectCandidates.swap(jpsiCandidates);
246 ATH_MSG_DEBUG("Number of candidates after requirement of at least 1 combined muon: " << jpsiCandidates.size() );
247 }
248
249 // (2) Establish track content for candidates
250 // and set the appropriate track collections for the combined muon tracks where appropriate (for saving to persistency later)
251
252 // mu+trk or trk+trk - always ID track collection
253 if (m_mutrk || m_trktrk) {
254 for (auto jpsiItr=jpsiCandidates.begin(); jpsiItr!=jpsiCandidates.end(); ++jpsiItr) {
255 (*jpsiItr).collection1 = importedTrackCollection;
256 (*jpsiItr).collection2 = importedTrackCollection;
257 }
258 }
259
260 if (m_mumu) {
261 using enum xAOD::Muon::TrackParticleType;
262 for (auto jpsiItr=jpsiCandidates.begin(); jpsiItr!=jpsiCandidates.end(); ++jpsiItr) {
264 (*jpsiItr).trackParticle1 = (*jpsiItr).muon1->trackParticle(InnerDetectorTrackParticle);
265 (*jpsiItr).trackParticle2 = (*jpsiItr).muon2->trackParticle(InnerDetectorTrackParticle);
266 (*jpsiItr).collection1 = importedTrackCollection;
267 (*jpsiItr).collection2 = importedTrackCollection;
268 }
270 if (!(*jpsiItr).muon1->trackParticle(CombinedTrackParticle)) {
271 (*jpsiItr).trackParticle1 = (*jpsiItr).muon1->trackParticle(InnerDetectorTrackParticle );
272 (*jpsiItr).collection1 = importedTrackCollection;
273 }
274
275 if (!(*jpsiItr).muon2->trackParticle(CombinedTrackParticle)) {
276 (*jpsiItr).trackParticle2 = (*jpsiItr).muon2->trackParticle(InnerDetectorTrackParticle );
277 (*jpsiItr).collection2 = importedTrackCollection;
278 }
279
280 if ((*jpsiItr).muon1->trackParticle(CombinedTrackParticle)) {
281 (*jpsiItr).trackParticle1 = (*jpsiItr).muon1->trackParticle(CombinedTrackParticle);
282 bool foundCollection(false);
283 // Look for correct muon track container
284 for (auto muTrkCollItr=importedMuonTrackCollections.begin(); muTrkCollItr!=importedMuonTrackCollections.end(); ++muTrkCollItr) {
285 if (isContainedIn((*jpsiItr).trackParticle1,*muTrkCollItr)) { (*jpsiItr).collection1 = *muTrkCollItr; foundCollection=true; break;}
286 }
287 if (!foundCollection) { // didn't find the correct muon track container so go back to ID
288 (*jpsiItr).trackParticle1 = (*jpsiItr).muon1->trackParticle( InnerDetectorTrackParticle );
289 (*jpsiItr).collection1 = importedTrackCollection;
290 ATH_MSG_WARNING("Muon track from muon of author " << (*jpsiItr).muon1->author() << " not found in muon track collections you have provided.");
291 ATH_MSG_WARNING("Defaulting to ID track collection - combined measurement will not be used");
292 }
293 }
294
295 if ((*jpsiItr).muon2->trackParticle(CombinedTrackParticle)) {
296 (*jpsiItr).trackParticle2 = (*jpsiItr).muon2->trackParticle(CombinedTrackParticle );
297 bool foundCollection(false);
298 // Look for correct muon track container
299 for (auto muTrkCollItr=importedMuonTrackCollections.begin(); muTrkCollItr!=importedMuonTrackCollections.end(); ++muTrkCollItr) {
300 if (isContainedIn((*jpsiItr).trackParticle2,*muTrkCollItr)) { (*jpsiItr).collection2 = *muTrkCollItr; foundCollection=true; break;}
301 }
302 if (!foundCollection) { // didn't find the correct muon track container so go back to ID
303 (*jpsiItr).trackParticle2 = (*jpsiItr).muon2->trackParticle(InnerDetectorTrackParticle);
304 (*jpsiItr).collection2 = importedTrackCollection;
305 ATH_MSG_WARNING("Muon track from muon of author " << (*jpsiItr).muon2->author() << " not found in muon track collections you have provided.");
306 ATH_MSG_WARNING("Defaulting to ID track collection - combined measurement will not be used");
307 }
308 }
309 } // combined measurement
310 } // iteration over candidates
311 }
312
313
314 // (3) Enforce higher track pt if requested
315 if (m_higherPt>0.0) {
316 std::vector<JpsiCandidate> selectCandidates;
317 for(auto& cand : jpsiCandidates){
318 bool reject = (fabs(cand.trackParticle1->pt()) < m_higherPt) && (fabs(cand.trackParticle2->pt()) < m_higherPt);
319 if(!reject) selectCandidates.push_back(cand);
320 }
321 selectCandidates.swap(jpsiCandidates);
322 ATH_MSG_DEBUG("Number of candidates after higherPt cut: " << jpsiCandidates.size() );
323 }
324
325 // (4) Select all opp/same charged track pairs
326 std::vector<JpsiCandidate> sortedJpsiCandidates;
327 sortedJpsiCandidates = selectCharges(jpsiCandidates);
328
329 ATH_MSG_DEBUG("Number of candidates after charge selection: " << sortedJpsiCandidates.size() );
330
331 // (5) Select for decay angle, if requested
332 if (m_collAnglePhi>0.0 && m_collAngleTheta>0.0) {
333 std::vector<JpsiCandidate> selectCandidates;
334 for(auto& cand : sortedJpsiCandidates){
335 double deltatheta = fabs( cand.trackParticle1->theta() - cand.trackParticle2->theta() );
336 double deltaphi = std::abs(xAOD::P4Helpers::deltaPhi(cand.trackParticle1->phi0() , cand.trackParticle2->phi0()));
337 bool reject = (deltatheta > m_collAngleTheta) || (deltaphi > m_collAnglePhi);
338 if(!reject) selectCandidates.push_back(cand);
339 }
340 sortedJpsiCandidates.swap(selectCandidates);
341 ATH_MSG_DEBUG("Number of collimated candidates: " << sortedJpsiCandidates.size() );
342 }
343
344 // (6) Select for invariant mass, if requested
345 std::array<double,2> trkMasses{m_trk1M, m_trk2M};
346 if ( (m_invMassLower > 0.0) || (m_invMassUpper > 0.0) ) {
347 std::vector<JpsiCandidate> selectCandidates;
348 for(auto& cand : sortedJpsiCandidates){
349 double invMass = getInvariantMass(cand,trkMasses);
350 bool reject = invMass < m_invMassLower || invMass > m_invMassUpper;
351 if(!reject) selectCandidates.push_back(cand);
352 }
353 selectCandidates.swap(sortedJpsiCandidates);
354 ATH_MSG_DEBUG("Number of candidates passing invariant mass selection: " << sortedJpsiCandidates.size() );
355 }
356
357 ATH_MSG_DEBUG("Number of pairs passing all selections and going to vertexing: " << sortedJpsiCandidates.size() );
358 if (sortedJpsiCandidates.size() == 0) return StatusCode::SUCCESS;;
359 std::vector<const xAOD::TrackParticle*> theTracks;
360 std::vector<const xAOD::Muon*> theStoredMuons;
361 // Fit each pair of tracks to a vertex
362 for(auto jpsiItr=sortedJpsiCandidates.begin(); jpsiItr!=sortedJpsiCandidates.end(); ++jpsiItr) {
363 theTracks.clear();
364 theTracks.push_back((*jpsiItr).trackParticle1);
365 theTracks.push_back((*jpsiItr).trackParticle2);
366 std::unique_ptr<xAOD::Vertex> myVxCandidate {fit(ctx, theTracks,importedTrackCollection)}; // This line actually does the fitting and object making
367 if (myVxCandidate) {
368 // Chi2 cut if requested
369 double chi2 = myVxCandidate->chiSquared();
370 ATH_MSG_DEBUG("chi2 is: " << chi2);
371 if (m_Chi2Cut <= 0.0 || chi2 <= m_Chi2Cut) {
372 // decorate the candidate with refitted tracks and muons via the BPhysHelper
373 xAOD::BPhysHelper jpsiHelper(myVxCandidate.get());
374 bool validtrk = jpsiHelper.setRefTrks();
375 if(!validtrk) ATH_MSG_WARNING("Problem setting tracks " << __FILE__ << ':' << __LINE__);
376 if (m_mumu || m_mutrk) {
377 theStoredMuons.clear();
378 theStoredMuons.push_back((*jpsiItr).muon1);
379 if (m_mumu) theStoredMuons.push_back((*jpsiItr).muon2);
380 bool valid = jpsiHelper.setMuons(theStoredMuons,importedMuonCollection);
381 if(!valid) ATH_MSG_WARNING("Problem setting muons " << __FILE__ << ':' << __LINE__);
382 }
383 // Retain the vertex
384 vxContainer.push_back(std::move(myVxCandidate));
385 }
386 } else { // fit failed
387 ATH_MSG_DEBUG("Fitter failed!");
388 // Don't try to delete the object, since we arrived here,
389 // because this pointer is null...
390 }
391 }
392 ATH_MSG_DEBUG("vxContainer size " << vxContainer.size());
393
394 return StatusCode::SUCCESS;;
395 }
396
397 // *********************************************************************************
398
399 // ---------------------------------------------------------------------------------
400 // fit - does the fit
401 // ---------------------------------------------------------------------------------
402
403 std::unique_ptr<xAOD::Vertex> JpsiFinder::fit(const EventContext& ctx,
404 const std::vector<const xAOD::TrackParticle*> &inputTracks,
405 const xAOD::TrackParticleContainer* importedTrackCollection) const {
406
407
408 const Trk::Perigee& aPerigee1 = inputTracks[0]->perigeeParameters();
409 const Trk::Perigee& aPerigee2 = inputTracks[1]->perigeeParameters();
410 int sflag = 0;
411 int errorcode = 0;
412 Amg::Vector3D startingPoint = m_vertexEstimator->getCirclesIntersectionPoint(&aPerigee1,&aPerigee2,sflag,errorcode);
413 if (errorcode != 0) {startingPoint(0) = 0.0; startingPoint(1) = 0.0; startingPoint(2) = 0.0;}
414
415 auto myVxCandidate = m_iVertexFitter->fit(ctx, inputTracks, startingPoint);
416
417 // Added by ASC
418 if(myVxCandidate != 0){
419 std::vector<ElementLink<DataVector<xAOD::TrackParticle> > > newLinkVector;
420 for(unsigned int i=0; i< myVxCandidate->trackParticleLinks().size(); i++)
421 {
422 ElementLink<DataVector<xAOD::TrackParticle> > mylink=myVxCandidate->trackParticleLinks()[i]; //makes a copy (non-const)
423 mylink.setStorableObject(*importedTrackCollection, true);
424 newLinkVector.push_back( std::move(mylink) );
425 }
426 myVxCandidate->clearTracks();
427 myVxCandidate->setTrackParticleLinks( newLinkVector );
428 }
429
430
431 return myVxCandidate;
432
433 } // End of fit method
434
435
436 // *********************************************************************************
437
438 // ---------------------------------------------------------------------------------
439 // getPairs: forms up 2-plets of tracks
440 // ---------------------------------------------------------------------------------
441
442 std::vector<JpsiCandidate> JpsiFinder::getPairs(const std::vector<const xAOD::TrackParticle*> &TracksIn) const {
443
444 std::vector<JpsiCandidate> myPairs;
446 std::vector<const xAOD::TrackParticle*>::const_iterator outerItr;
447 std::vector<const xAOD::TrackParticle*>::const_iterator innerItr;
448
449 if(TracksIn.size()>=2){
450 myPairs.reserve((TracksIn.size() * (TracksIn.size() - 1)) / 2);
451 for(outerItr=TracksIn.begin();outerItr<TracksIn.end();++outerItr){
452 for(innerItr=(outerItr+1);innerItr!=TracksIn.end();++innerItr){
453 pair.trackParticle1 = *innerItr;
454 pair.trackParticle2 = *outerItr;
455 pair.pairType = TRKTRK;
456 myPairs.push_back(pair);
457 }
458 }
459 }
460
461 return(myPairs);
462 }
463
464 // ---------------------------------------------------------------------------------
465 // getPairs: forms up 2-plets of muons
466 // ---------------------------------------------------------------------------------
467
468 std::vector<JpsiCandidate> JpsiFinder::getPairs(const std::vector<const xAOD::Muon*> &muonsIn) const {
469
470 std::vector<JpsiCandidate> myPairs;
472 std::vector<const xAOD::Muon*>::const_iterator outerItr;
473 std::vector<const xAOD::Muon*>::const_iterator innerItr;
474
475 if(muonsIn.size()>=2){
476 myPairs.reserve((muonsIn.size() * (muonsIn.size() - 1)) / 2);
477 for(outerItr=muonsIn.begin();outerItr<muonsIn.end();++outerItr){
478 for(innerItr=(outerItr+1);innerItr!=muonsIn.end();++innerItr){
479 pair.muon1 = *innerItr;
480 pair.muon2 = *outerItr;
481 pair.pairType = MUMU;
482 bool mu1Comb( (*innerItr)->muonType() == xAOD::Muon::MuonType::Combined );
483 bool mu2Comb( (*outerItr)->muonType() == xAOD::Muon::MuonType::Combined );
484 if (mu1Comb && mu2Comb) pair.muonTypes = CC;
485 if ( (mu1Comb && !mu2Comb) || (!mu1Comb && mu2Comb) ) pair.muonTypes = CT;
486 if (!mu1Comb && !mu2Comb) pair.muonTypes = TT;
487 myPairs.push_back(pair);
488 }
489 }
490 }
491
492 return(myPairs);
493 }
494
495 // *********************************************************************************
496
497 // ---------------------------------------------------------------------------------
498 // getPairs2Colls: forms up 2-plets of tracks from two independent collections
499 // ---------------------------------------------------------------------------------
500
501 std::vector<JpsiCandidate> JpsiFinder::getPairs2Colls(const std::vector<const xAOD::TrackParticle*> &tracks, const std::vector<const xAOD::Muon*> &muons, bool tagAndProbe) const {
502
503 std::vector<JpsiCandidate> myPairs;
505
506 // Unless user is running in tag and probe mode, remove tracks which are also identified as muons
507 std::vector<const xAOD::TrackParticle*> tracksToKeep;
508 if (!tagAndProbe) {
509 if(tracks.size()>=1 && muons.size()>=1){
510 for (const xAOD::TrackParticle* trk : tracks) {
511 if (std::find_if(muons.begin(), muons.end(),
512 [trk](const xAOD::Muon* mu) {
513 return mu->trackParticle(xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle) == trk;
514 }) == muons.end()) {
515 tracksToKeep.push_back(trk);
516 }
517 }
518 }
519 } else {tracksToKeep = tracks;}
520
521 if(tracksToKeep.size()>=1 && muons.size()>=1){
522 for (const xAOD::TrackParticle* trk : tracksToKeep) {
523 for (const xAOD::Muon* mu : muons) {
524 pair.muon1 = mu;
525 // Muon track 1st
526 pair.trackParticle1 = mu->trackParticle( xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle );
527 pair.trackParticle2 = trk;
528 pair.pairType = MUTRK;
529 myPairs.push_back(pair);
530 }
531 }
532 }
533
534 return(myPairs);
535 }
536
537
538
539 // *********************************************************************************
540
541 // ---------------------------------------------------------------------------------
542 // getInvariantMass: returns invariant mass
543 // ----------------------------------------------------------getInvariantMass-----------------------
544
545 double JpsiFinder::getInvariantMass(const JpsiCandidate &jpsiIn, std::span<const double> massHypotheses) const {
546
547 // construct 4-vectors from track perigee parameters using given mass hypotheses.
548 // NOTE: in new data model (xAOD) the defining parameters are expressed as perigee parameters w.r.t. the beamspot
549 // NOTE2: TrackParticle::p4() method already returns TLorentzVector, however, we want to enforce our own mass hypothesis
550 auto mu1 = jpsiIn.trackParticle1->genvecP4();
551 auto mu2 = jpsiIn.trackParticle2->genvecP4();
552 mu1.SetM(massHypotheses[0]);
553 mu2.SetM(massHypotheses[1]);
554
555 return (mu1+mu2).M();
556
557 }
558
559 // ---------------------------------------------------------------------------------
560 // selectCharges: selects track pairs with opposite charge / store + before -
561 // Boolean argument is to decide whether to accept oppositely or identically charged
562 // particles (true for oppositely charged)
563 // ---------------------------------------------------------------------------------
564
565 std::vector<JpsiCandidate> JpsiFinder::selectCharges(const std::vector<JpsiCandidate> &jpsisIn) const {
566
567 bool opposite(false),same(false),all(false);
568 opposite=m_oppChOnly;
569 same=m_sameChOnly;
570 all=m_allChCombs;
571
572 JpsiCandidate tmpJpsi;
573 std::vector<JpsiCandidate> jpsis;
574 double qOverP1=0.;
575 double qOverP2=0.;
576 for(auto jpsiItr=jpsisIn.cbegin();jpsiItr!=jpsisIn.cend();jpsiItr++){
577 bool oppCh(false),sameCh(false);
578 tmpJpsi = *jpsiItr;
579 qOverP1=(*jpsiItr).trackParticle1->qOverP();
580 qOverP2=(*jpsiItr).trackParticle2->qOverP();
581 if(qOverP1*qOverP2<0.0) oppCh=true; // product charge < 0
582 if(qOverP1*qOverP2>0.0) sameCh=true; // product charge > 0
583 // +ve should be first so swap
584 // Don't do it for tag and probe analyses (because tag muon must not change position)
585 if (oppCh && qOverP1<0.0 && !m_doTagAndProbe && !m_mutrk) {
586 tmpJpsi.trackParticle1 = (*jpsiItr).trackParticle2;
587 tmpJpsi.trackParticle2 = (*jpsiItr).trackParticle1;
588 tmpJpsi.muon1 = (*jpsiItr).muon2;
589 tmpJpsi.muon2 = (*jpsiItr).muon1;
590 tmpJpsi.collection1 = (*jpsiItr).collection2;
591 tmpJpsi.collection2 = (*jpsiItr).collection1;
592 }
593 if (oppCh && (opposite || all) ) jpsis.push_back(tmpJpsi);
594 if (sameCh && (same || all) ) jpsis.push_back(tmpJpsi);
595
596 } // end of for loop
597
598 return(jpsis);
599 }
600
601 // ---------------------------------------------------------------------------------
602 // Apply the current cuts of the MCP group recommendation.
603 // ---------------------------------------------------------------------------------
604
605 bool JpsiFinder::passesMCPCuts(const xAOD::Muon* muon) const {
606
607 return muon->passesIDCuts();
608
609 }
610
611 // ---------------------------------------------------------------------------------
612 // Checks whether a TPB is in the collection
613 // ---------------------------------------------------------------------------------
614
615 bool JpsiFinder::isContainedIn(const xAOD::TrackParticle* theTrack, const xAOD::TrackParticleContainer* theCollection) const {
616 return std::find(theCollection->begin(), theCollection->end(), theTrack) != theCollection->end();
617 }
618
619}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
: B-physics xAOD helpers.
ATLAS-specific HepMC functions.
A number of constexpr particle constants to avoid hardcoding them directly in various places.
size_t size() const
Number of registered mappings.
SG::ReadHandleKeyArray< xAOD::TrackParticleContainer > m_MuonTrackKeys
Definition JpsiFinder.h:92
PublicToolHandle< InDet::VertexPointEstimator > m_vertexEstimator
Definition JpsiFinder.h:95
std::vector< JpsiCandidate > getPairs(const std::vector< const xAOD::TrackParticle * > &) const
std::vector< JpsiCandidate > getPairs2Colls(const std::vector< const xAOD::TrackParticle * > &, const std::vector< const xAOD::Muon * > &, bool) const
PublicToolHandle< Trk::ITrackSelectorTool > m_trkSelector
Definition JpsiFinder.h:94
bool passesMCPCuts(const xAOD::Muon *) const
std::vector< JpsiCandidate > selectCharges(const std::vector< JpsiCandidate > &) const
JpsiFinder(const std::string &t, const std::string &n, const IInterface *p)
virtual StatusCode performSearch(const EventContext &ctx, xAOD::VertexContainer &vxContainer) const override
virtual StatusCode initialize() override
bool isContainedIn(const xAOD::TrackParticle *, const xAOD::TrackParticleContainer *) const
SG::ReadHandleKey< xAOD::MuonContainer > m_muonCollectionKey
Definition JpsiFinder.h:90
PublicToolHandle< Trk::IVertexFitter > m_iVertexFitter
Definition JpsiFinder.h:93
ServiceHandle< IPartPropSvc > m_partPropSvc
Definition JpsiFinder.h:96
double getInvariantMass(const JpsiCandidate &, std::span< const double >) const
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_TrkParticleCollection
Definition JpsiFinder.h:91
std::unique_ptr< xAOD::Vertex > fit(const EventContext &ctx, const std::vector< const xAOD::TrackParticle * > &, const xAOD::TrackParticleContainer *importedTrackCollection) const
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
value_type push_back(value_type pElem)
Add an element to the end of the collection.
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
STL class.
bool setMuons(const std::vector< const xAOD::Muon * > &muons, const xAOD::MuonContainer *muonContainer)
Set links to muons.
bool setRefTrks(std::vector< float > px, std::vector< float > py, std::vector< float > pz)
Sets refitted track momenta.
float qOverP() 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.
double chi2(TH1 *h0, TH1 *h1)
Eigen::Matrix< double, 3, 1 > Vector3D
The namespace of all packages in PhysicsAnalysis/JetTagging.
static const int MUON
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
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:
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".
const xAOD::TrackParticle * trackParticle1
Definition JpsiFinder.h:37
const xAOD::Muon * muon2
Definition JpsiFinder.h:40
const xAOD::TrackParticleContainer * collection2
Definition JpsiFinder.h:42
const xAOD::TrackParticleContainer * collection1
Definition JpsiFinder.h:41
const xAOD::TrackParticle * trackParticle2
Definition JpsiFinder.h:38
const xAOD::Muon * muon1
Definition JpsiFinder.h:39