ATLAS Offline Software
Loading...
Searching...
No Matches
JpsiPlus2Tracks.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// JpsiPlus2Tracks
8// James Catmore <James.Catmore@cern.ch>
9// Results returned as a vector of xAOD::Vertex
10// ----------------------------------------------------------------------------
11// ****************************************************************************
12
19#include "xAODTracking/Vertex.h"
21#include "AthLinks/ElementLink.h"
23#include <memory>
26#include <limits>
27
28namespace Analysis {
29
30 // Set masses
35
37
38 // retrieving vertex Fitter
39 ATH_CHECK(m_iVertexFitter.retrieve());
40 m_VKVFitter = dynamic_cast<Trk::TrkVKalVrtFitter*>(&(*m_iVertexFitter));
41
42 // Get the track selector tool from ToolSvc
43 ATH_CHECK(m_trkSelector.retrieve());
44
45
46 ATH_CHECK(m_jpsiCollectionKey.initialize());
49 if(m_MuonsUsedInJpsi.key() == "NONE") m_MuonsUsedInJpsi = "";
50 ATH_CHECK(m_MuonsUsedInJpsi.initialize(!m_MuonsUsedInJpsi.key().empty()));
51
52 if(!m_manualMassHypo.empty() && m_manualMassHypo.size() !=4){
53 ATH_MSG_FATAL("Invalid number of elements given for manualMass hypothesis - needs 4");
54 return StatusCode::FAILURE;
55 }
56 if(!m_manualMassHypo.empty()){
57 ATH_MSG_DEBUG("manual mass hypo " << m_manualMassHypo[0] <<
58 ',' << m_manualMassHypo[1] << ',' << m_manualMassHypo[2] << ',' << m_manualMassHypo[3]);
59 }
61 ATH_MSG_FATAL("Invalid configuration");
62 return StatusCode::FAILURE;
63 }
65 ATH_MSG_FATAL("Invalid configuration");
66 return StatusCode::FAILURE;
67 }
68
69 if(m_altMassMuonTracks.empty()){
70 m_altMassMuonTracks.assign(2, muMass); //Default to muon mass
71 }
72
79 m_useGSFTrack.reset();
80 for(int i : m_useGSFTrackIndices) m_useGSFTrack.set(i, true);
81
82 ATH_MSG_DEBUG("Initialize successful");
83
84 return StatusCode::SUCCESS;
85
86 }
87
88 JpsiPlus2Tracks::JpsiPlus2Tracks(const std::string& t, const std::string& n, const IInterface* p) : AthAlgTool(t,n,p),
89 m_pipiMassHyp(true),
90 m_kkMassHyp(true),
91 m_kpiMassHyp(true),
92 m_kpMassHyp(false),
93 m_oppChargesOnly(true),
94 m_sameChargesOnly(false),
96 m_trkMaxEta(102.5),
97 m_BThresholdPt(0.0),
98 m_BMassUpper(0.0),
99 m_BMassLower(0.0),
100 m_jpsiCollectionKey("JpsiCandidates"),
101 m_jpsiMassUpper(0.0),
102 m_jpsiMassLower(0.0),
103 m_TrkParticleCollection("InDetTrackParticles"),
104 m_TrkParticleGSFCollection("GSFTrackParticles"),
108 m_iVertexFitter("Trk::TrkVKalVrtFitter"),
109 m_trkSelector("InDet::TrackSelectorTool"),
110 m_useMassConst(true),
111 m_altMassConst(-1.0),
112 m_diTrackMassUpper(-1.0),
113 m_diTrackMassLower(-1.0),
114 m_chi2cut(-1.0),
115 m_diTrackPt(-1.0),
118 m_trkQuadrupletPt(-1.0),
121 m_finalDiTrackPt(-1.0),
122 m_trkDeltaZ(-1.0),
124 m_candidateLimit(std::numeric_limits<size_t>::max())
125 {
126 declareInterface<JpsiPlus2Tracks>(this);
127 declareProperty("pionpionHypothesis",m_pipiMassHyp);
128 declareProperty("kaonkaonHypothesis",m_kkMassHyp);
129 declareProperty("kaonpionHypothesis",m_kpiMassHyp);
130 declareProperty("kaonprotonHypothesis",m_kpMassHyp);
131 declareProperty("oppChargesOnly",m_oppChargesOnly);
132 declareProperty("SameChargesOnly",m_sameChargesOnly);
133 declareProperty("trkThresholdPt",m_trkThresholdPt);
134 declareProperty("trkMaxEta",m_trkMaxEta);
135 declareProperty("BThresholdPt",m_BThresholdPt);
136 declareProperty("BMassUpper",m_BMassUpper);
137 declareProperty("BMassLower",m_BMassLower);
138 declareProperty("JpsiContainerKey",m_jpsiCollectionKey);
139 declareProperty("JpsiMassUpper",m_jpsiMassUpper);
140 declareProperty("JpsiMassLower",m_jpsiMassLower);
141 declareProperty("TrackParticleCollection",m_TrkParticleCollection);
142 declareProperty("MuonsUsedInJpsi",m_MuonsUsedInJpsi);
143 declareProperty("ExcludeJpsiMuonsOnly",m_excludeJpsiMuonsOnly);
144 declareProperty("ExcludeCrossJpsiTracks",m_excludeCrossJpsiTracks); //Essential when trying to make vertices out of multiple muons (set to false)
145 declareProperty("TrkVertexFitterTool",m_iVertexFitter);
146 declareProperty("TrackSelectorTool",m_trkSelector);
147 declareProperty("UseMassConstraint", m_useMassConst);
148 declareProperty("AlternativeMassConstraint",m_altMassConst);
149 declareProperty("DiTrackMassUpper",m_diTrackMassUpper);
150 declareProperty("DiTrackMassLower",m_diTrackMassLower);
151 // additional cuts by Daniel Scheirich
152 declareProperty("Chi2Cut",m_chi2cut);
153 declareProperty("DiTrackPt",m_diTrackPt);
154 declareProperty("TrkQuadrupletMassUpper",m_trkQuadrupletMassUpper);
155 declareProperty("TrkQuadrupletMassLower",m_trkQuadrupletMassLower);
156 declareProperty("TrkQuadrupletPt" ,m_trkQuadrupletPt );
157 declareProperty("FinalDiTrackMassUpper" ,m_finalDiTrackMassUpper );
158 declareProperty("FinalDiTrackMassLower" ,m_finalDiTrackMassLower );
159 declareProperty("FinalDiTrackPt" ,m_finalDiTrackPt );
160 declareProperty("TrkDeltaZ" ,m_trkDeltaZ );
161 declareProperty("ManualMassHypo", m_manualMassHypo);
162 declareProperty("RequireNMuonTracks", m_requiredNMuons);
163 declareProperty("AlternativeMassConstraintTrack", m_altMassMuonTracks);
164 declareProperty("UseGSFTrackIndices", m_useGSFTrackIndices);
166 declareProperty("CandidateLimit", m_candidateLimit);
167 }
168
170
171
172 //-------------------------------------------------------------------------------------
173 // Find the candidates
174 //-------------------------------------------------------------------------------------
175 StatusCode JpsiPlus2Tracks::performSearch(const EventContext& ctx, xAOD::VertexContainer& bContainer) const
176 {
177 ATH_MSG_DEBUG( "JpsiPlus2Tracks::performSearch" );
178
179 // Get the J/psis from StoreGate
180 const xAOD::VertexContainer* importedJpsiCollection{nullptr};
182 if(!jpsihandle.isValid()){
183 ATH_MSG_ERROR("No VertexContainer with key " << m_jpsiCollectionKey.key() << " found in StoreGate. BCandidates will be EMPTY!");
184 return StatusCode::FAILURE;
185 }else{
186 importedJpsiCollection = jpsihandle.cptr();
187 ATH_MSG_DEBUG("Found VxCandidate container with key "<<m_jpsiCollectionKey.key());
188 }
189 ATH_MSG_DEBUG("VxCandidate container size " << importedJpsiCollection->size());
190
191 // Get tracks
192 const xAOD::TrackParticleContainer* importedTrackCollection{nullptr};
194 if(!trackshandle.isValid()){
195 ATH_MSG_ERROR("No track particle collection with name " << m_TrkParticleCollection.key() << " found in StoreGate!");
196 return StatusCode::FAILURE;
197 } else {
198 importedTrackCollection = trackshandle.cptr();
199 ATH_MSG_DEBUG("Found track particle collection " << m_TrkParticleCollection.key() << " in StoreGate!");
200 }
201 ATH_MSG_DEBUG("Track container size "<< importedTrackCollection->size());
202
203 const xAOD::TrackParticleContainer* importedGSFTrackCollection(nullptr);
204 if(m_useGSFTrack.any() && !m_TrkParticleGSFCollection.key().empty()){
206 ATH_CHECK(h.isValid());
207 importedGSFTrackCollection = h.cptr();
208 }
209
210 // Get the muon collection used to build the J/psis
211 const xAOD::MuonContainer* importedMuonCollection{nullptr};
212 if (!m_MuonsUsedInJpsi.key().empty()) {
214 if (!h.isValid()){
215 ATH_MSG_ERROR("No muon collection with name " << m_MuonsUsedInJpsi.key() << " found in StoreGate!");
216 return StatusCode::FAILURE;
217 } else {
218 importedMuonCollection = h.cptr();
219 ATH_MSG_DEBUG("Found muon collection " << m_MuonsUsedInJpsi.key() << " in StoreGate!");
220 }
221 ATH_MSG_DEBUG("Muon container size "<< importedMuonCollection->size());
222 }
223
224 // Typedef for vectors of tracks and VxCandidates
225 typedef std::vector<const xAOD::TrackParticle*> TrackBag;
226
227 // Select the inner detector tracks
228 TrackBag theIDTracksAfterSelection;
229 for (auto trkPBItr=importedTrackCollection->cbegin(); trkPBItr!=importedTrackCollection->cend(); ++trkPBItr) {
230 const xAOD::TrackParticle* tp (*trkPBItr);
231 if ( tp->pt()<m_trkThresholdPt ) continue;
232 if ( std::abs(tp->eta())>m_trkMaxEta ) continue;
233 if (importedMuonCollection!=NULL && !m_excludeJpsiMuonsOnly) {
234 if (JpsiUpsilonCommon::isContainedIn(tp,importedMuonCollection)) continue;
235 }
236 if ( m_trkSelector->decision(*tp, NULL) ) theIDTracksAfterSelection.push_back(tp);
237 }
238 if (theIDTracksAfterSelection.size() == 0) return StatusCode::SUCCESS;
239 ATH_MSG_DEBUG("Number of tracks after ID trkSelector: " << theIDTracksAfterSelection.size());
240
241 // Loop over J/psi candidates, select, collect up tracks used to build a J/psi
242 std::vector<const xAOD::Vertex*> selectedJpsiCandidates;
243 std::vector<const xAOD::TrackParticle*> jpsiTracks;
244 for(auto vxcItr=importedJpsiCollection->cbegin(); vxcItr!=importedJpsiCollection->cend(); ++vxcItr) {
245 // Check J/psi candidate invariant mass and skip if need be
246
247 if (m_jpsiMassUpper>0.0 || m_jpsiMassLower > 0.0) {
248 xAOD::BPhysHelper jpsiCandidate(*vxcItr);
249 double jpsiMass = jpsiCandidate.totalP(m_altMassMuonTracks).M();
251 if (!pass) continue;
252 }
253 selectedJpsiCandidates.push_back(*vxcItr);
254
255 // Collect up tracks
257 // Extract tracks from J/psi
258 const xAOD::TrackParticle* jpsiTP1 = (*vxcItr)->trackParticle(0);
259 const xAOD::TrackParticle* jpsiTP2 = (*vxcItr)->trackParticle(1);
260 jpsiTracks.push_back(jpsiTP1);
261 jpsiTracks.push_back(jpsiTP2);
262 }
263 }
264 ATH_MSG_DEBUG("selectedJpsiCandidates: " << selectedJpsiCandidates.size());
265
266
267
268
269 // Attempt to fit each track with the two tracks from the J/psi candidates
270 // Loop over J/psis
271 std::vector<const xAOD::TrackParticle*> QuadletTracks(4, nullptr);//Initialise as 4 nulls
272
273 std::vector<double> massCuts;
274
275 TrackBag muonTracks;
276 if (importedMuonCollection != NULL && m_excludeJpsiMuonsOnly) {
277 for(auto muon : *importedMuonCollection){
278 auto track = muon->trackParticle( xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle );
279 if(track==nullptr) continue;
280 if(!JpsiUpsilonCommon::isContainedIn(track, theIDTracksAfterSelection)) continue;
281 muonTracks.push_back(track);
282 }
283 }
284
285 for(auto jpsiItr=selectedJpsiCandidates.begin(); jpsiItr!=selectedJpsiCandidates.end(); ++jpsiItr) {
286
287 // Extract tracks from J/psi
288 const xAOD::TrackParticle* jpsiTP1 = (*jpsiItr)->trackParticle(0);
289 const xAOD::TrackParticle* jpsiTP2 = (*jpsiItr)->trackParticle(1);
290 QuadletTracks[0] = jpsiTP1;
291 QuadletTracks[1] = jpsiTP2;
292
293 //If requested, only exclude duplicates in the same tripplet
295 jpsiTracks.resize(2);
296 jpsiTracks[0] = jpsiTP1;
297 jpsiTracks[1] = jpsiTP2;
298 }
299
300 // Loop over ID tracks, call vertexing
301 for (TrackBag::iterator trkItr1=theIDTracksAfterSelection.begin(); trkItr1<theIDTracksAfterSelection.end(); ++trkItr1) { // outer loop
302 if (!m_excludeJpsiMuonsOnly && JpsiUpsilonCommon::isContainedIn(*trkItr1,jpsiTracks)) continue; // remove tracks which were used to build J/psi
303 int linkedMuonTrk1 = 0;
305 linkedMuonTrk1 = JpsiUpsilonCommon::isContainedIn(*trkItr1, muonTracks);
306 if (linkedMuonTrk1) ATH_MSG_DEBUG("This id track 1 is muon track!");
307
308 if (JpsiUpsilonCommon::isContainedIn(*trkItr1,jpsiTracks)) {
309 if (linkedMuonTrk1) ATH_MSG_DEBUG("ID track 1 removed: id track is selected to build Jpsi!");
310 continue; // remove tracks which were used to build J/psi
311 }
312 }
313
314 // Daniel Scheirich: remove track too far from the Jpsi vertex (DeltaZ cut)
315 if(m_trkDeltaZ>0 &&
316 std::abs((*trkItr1)->z0() + (*trkItr1)->vz() - (*jpsiItr)->z()) > m_trkDeltaZ )
317 continue;
318
319 for (TrackBag::iterator trkItr2=trkItr1+1; trkItr2!=theIDTracksAfterSelection.end(); ++trkItr2) { // inner loop
320 if(bContainer.size() >= m_candidateLimit ){
321 ATH_MSG_WARNING("Hard Limit exceeded N=" << bContainer.size());
322 return StatusCode::SUCCESS;
323 }
324 if (!m_excludeJpsiMuonsOnly && JpsiUpsilonCommon::isContainedIn(*trkItr2,jpsiTracks)) continue; // remove tracks which were used to build J/psi
325
327 int linkedMuonTrk2 = JpsiUpsilonCommon::isContainedIn(*trkItr2, muonTracks);
328 if (linkedMuonTrk2) ATH_MSG_DEBUG("This id track 2 is muon track!");
329 if (JpsiUpsilonCommon::isContainedIn(*trkItr2,jpsiTracks)) {
330 if (linkedMuonTrk2) ATH_MSG_DEBUG("ID track 2 removed: id track is selected to build Jpsi Vtx!");
331 continue; // remove tracks which were used to build J/psi
332 }
333 if( (linkedMuonTrk1+ linkedMuonTrk2) < m_requiredNMuons) {
334 ATH_MSG_DEBUG("Skipping Tracks with Muons " << linkedMuonTrk1 + linkedMuonTrk2 << " Limited to " << m_requiredNMuons);
335 continue;
336 }
337 }
338
339 // Daniel Scheirich: remove track too far from the Jpsi vertex (DeltaZ cut)
340 if(m_trkDeltaZ>0 &&
341 std::abs((*trkItr2)->z0() + (*trkItr2)->vz() - (*jpsiItr)->z()) > m_trkDeltaZ )
342 continue;
343
344 if (m_oppChargesOnly && !oppositeCharges(*trkItr1,*trkItr2)) continue; //enforce opposite charges
345 if (m_sameChargesOnly && oppositeCharges(*trkItr1,*trkItr2)) continue; //enforce same charges
346
347 if (m_diTrackPt>0 && JpsiUpsilonCommon::getPt(*trkItr1,*trkItr2) < m_diTrackPt ) continue; // track pair pT cut (daniel Scheirich)
348
349 // sort the track by charge, putting the positive track first
350 if((*trkItr2)->qOverP()>0) {
351 QuadletTracks[2] = *trkItr2;
352 QuadletTracks[3] = *trkItr1;
353 }else{
354 QuadletTracks[2] = *trkItr1;
355 QuadletTracks[3] = *trkItr2;
356 }
357
358 if (m_trkQuadrupletPt>0 && JpsiUpsilonCommon::getPt(QuadletTracks[0], QuadletTracks[1], *trkItr1,*trkItr2) < m_trkQuadrupletPt ) continue; // track quadruplet pT cut (daniel Scheirich)
359
360 // apply mass cut on track pair (non muon) if requested
361 bool passesDiTrack(true);
362 if (m_diTrackMassUpper>0.0 || m_diTrackMassLower>0.0) {
363 massCuts.clear();
364 if(m_kkMassHyp) massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(*trkItr1,kMass,*trkItr2,kMass));
365 if(m_pipiMassHyp) massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(*trkItr1,piMass,*trkItr2,piMass));
366 if(m_kpiMassHyp){
367 massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(*trkItr1,kMass,*trkItr2,piMass));
368 massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(*trkItr1,piMass,*trkItr2,kMass));
369 }
370 if(m_kpMassHyp){
371 massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(*trkItr1,kMass,*trkItr2,piMass));
372 massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(*trkItr1,piMass,*trkItr2,kMass));
373 }
374 if(!m_manualMassHypo.empty()) massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(*trkItr1, m_manualMassHypo[2], *trkItr2, m_manualMassHypo[3]));
376
377 }
378 if (!passesDiTrack) continue;
379
380 // apply mass cut on track quadruplet if requested
381 bool passes4TrackMass(true);
383 massCuts.clear();
384
385 if(m_kkMassHyp) massCuts.push_back( JpsiUpsilonCommon::getInvariantMass(QuadletTracks, m_mumukkMasses) );
386 if(m_pipiMassHyp) massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(QuadletTracks, m_mumupipiMasses));
387 if(m_kpiMassHyp){
388 massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(QuadletTracks, m_mumukpiMasses));
389 massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(QuadletTracks, m_mumupikMasses));
390 }
391 if(m_kpMassHyp){
392 massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(QuadletTracks, m_mumukpMasses));
393 massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(QuadletTracks, m_mumupkMasses));
394 }
395 if(!m_manualMassHypo.empty()) massCuts.push_back(JpsiUpsilonCommon::getInvariantMass(QuadletTracks, m_manualMassHypo));
396
398 }
399 if (!passes4TrackMass) continue;
400
401 //Managed pointer, "release" if you don't want it deleted. Automatically deleted otherwise
402 std::unique_ptr<xAOD::Vertex> bVertex (fit(ctx, QuadletTracks, importedTrackCollection, importedGSFTrackCollection)); // do vertexing
403 if(!bVertex) continue;
404 double bChi2DOF = bVertex->chiSquared()/bVertex->numberDoF();
405 ATH_MSG_DEBUG("Candidate chi2/DOF is " << bChi2DOF);
406 bool chi2CutPassed = (m_chi2cut <= 0.0 || bChi2DOF < m_chi2cut);
407 if(!chi2CutPassed) { ATH_MSG_DEBUG("Chi Cut failed!"); continue; }
408 xAOD::BPhysHelper bHelper(bVertex.get());//"get" does not "release" still automatically deleted
409 bHelper.setRefTrks();
410 bool passesCuts = vertexCuts(bHelper);
411 if(!passesCuts) continue;
412 // Saving successful candidates
413 // Set links to J/psi
414 std::vector<const xAOD::Vertex*> theJpsiPreceding;
415 theJpsiPreceding.push_back(*jpsiItr);
416 bHelper.setPrecedingVertices(theJpsiPreceding, importedJpsiCollection);
417 bContainer.push_back(bVertex.release());//ptr is released preventing deletion
418
419 } // End of inner loop over tracks
420 } // End of outer loop over tracks
421 } // End of loop over J/spi
422 ATH_MSG_DEBUG("bContainer size " << bContainer.size());
423 return StatusCode::SUCCESS;
424
425 }
426
427 // *********************************************************************************
428
429 // ---------------------------------------------------------------------------------
430 // fit - does the fit
431 // ---------------------------------------------------------------------------------
432
433 std::unique_ptr<xAOD::Vertex> JpsiPlus2Tracks::fit(const EventContext& ctx,
434 const std::vector<const xAOD::TrackParticle*> &inputTracks,
435 const xAOD::TrackParticleContainer* importedTrackCollection,
436 const xAOD::TrackParticleContainer* gsfCollection) const {
437
438 std::unique_ptr<Trk::IVKalState> state = m_VKVFitter->makeState(ctx);
439
440
441
442
443 // Set the mass constraint if requested by user (default=true)
444 // Can be set by user (m_altMassConstraint) - default is -1.0.
445 // If < 0.0, uses J/psi (default)
446 // If > 0.0, uses the value provided
447
448
449 if (m_useMassConst) {
450 constexpr double jpsiTableMass = ParticleConstants::JpsiMassInMeV;
451 m_VKVFitter->setMassInputParticles(m_altMassMuonTracks,*state);
452 std::array<int,2> indices= {1, 2};
453 if (m_altMassConst<0.0) m_VKVFitter->setMassForConstraint(jpsiTableMass,indices,*state);
454 if (m_altMassConst>0.0) m_VKVFitter->setMassForConstraint(m_altMassConst,indices,*state);
455 }
456
457 // Do the fit itself.......
458 // Starting point (use the J/psi position)
459 Amg::Vector3D startingPoint(0,0,0);
460 StatusCode sc=m_VKVFitter->VKalVrtFitFast(inputTracks, startingPoint, *state);
461 if(sc.isFailure()){
462 startingPoint = Amg::Vector3D(0,0,0);
463 }
464 std::unique_ptr<xAOD::Vertex> theResult = m_VKVFitter->fit(inputTracks, startingPoint, *state);
465
466 // Added by ASC
467 if(theResult){
468 std::vector<ElementLink<DataVector<xAOD::TrackParticle> > > newLinkVector;
469 for(unsigned int i=0; i< theResult->trackParticleLinks().size(); i++)
470 {
471 ElementLink<DataVector<xAOD::TrackParticle> > mylink=theResult->trackParticleLinks()[i]; //makes a copy (non-const)
472 mylink.setStorableObject( m_useGSFTrack[i] ? *gsfCollection : *importedTrackCollection, true);
473 newLinkVector.push_back( mylink );
474 }
475 theResult->clearTracks();
476 theResult->setTrackParticleLinks( newLinkVector );
477 }
478
479 return theResult;
480
481 }
482
483
484
485 // *********************************************************************************
486
487 // oppositeCharges: true if the two tracks are oppositely charged
489 double qOverP1=trk1->qOverP();
490 double qOverP2=trk2->qOverP();
491 bool opposite = (qOverP1*qOverP2<0.0);
492 return opposite;
493 }
494
495
496 bool JpsiPlus2Tracks::passCuts(xAOD::BPhysHelper &bHelper, std::span<const double> masses, std::string_view str) const{
497
498 TLorentzVector bMomentum = bHelper.totalP(masses);
499// ATH_MSG_DEBUG(bMomentum.X() << " " << bMomentum.Y()<< " " << bMomentum.Z() << " " << bMomentum.E());
500 double bPt = bMomentum.Pt();
501
502 double bMass = bMomentum.M();
503 ATH_MSG_DEBUG("Candidate pt/mass under " << str << " track mass hypothesis is " << bPt << " / " << bMass);
505 if( !JpsiUpsilonCommon::cutRange(bMass, m_BMassLower, m_BMassUpper)) return false;
506 assert(masses.size()==4);
507 TLorentzVector tr1 = bHelper.refTrk(2,masses[2]);
508 TLorentzVector tr2 = bHelper.refTrk(3,masses[3]);
509 double bDiTrkPt = (tr1+tr2).Pt();
510 double bDiTrkMass = (tr1+tr2).M();
511 if( !JpsiUpsilonCommon::cutAcceptGreater(bDiTrkPt, m_finalDiTrackPt)) return false;
513
514 return true;
515 }
516
518 // Invariant mass calculation under the various hypotheses
519 // create the helper class
520
521 bool passesCuts = (m_kkMassHyp && passCuts(bHelper, m_mumukkMasses, "KK")) ||
522 (m_pipiMassHyp && passCuts(bHelper, m_mumupipiMasses, "pi pi")) ||
523 (m_kpiMassHyp && (passCuts(bHelper, m_mumukpiMasses, "K pi") ||
524 passCuts(bHelper, m_mumupikMasses, "pi K"))) ||
525 (m_kpMassHyp && (passCuts(bHelper, m_mumukpMasses, "K p") ||
526 passCuts(bHelper, m_mumupkMasses, "p K"))) ||
527 (!m_manualMassHypo.empty() && passCuts(bHelper, m_manualMassHypo, "manual"));
528 return passesCuts;
529 }
530
531
532} // End of namespace
533
534
535
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
: B-physics xAOD helpers.
static Double_t sc
A number of constexpr particle constants to avoid hardcoding them directly in various places.
size_t size() const
Number of registered mappings.
#define max(a, b)
Definition cfImp.cxx:41
static bool oppositeCharges(const xAOD::TrackParticle *, const xAOD::TrackParticle *)
ToolHandle< Trk::ITrackSelectorTool > m_trkSelector
std::vector< double > m_mumupkMasses
Trk::TrkVKalVrtFitter * m_VKVFitter
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_TrkParticleGSFCollection
std::vector< int > m_useGSFTrackIndices
virtual StatusCode initialize() override
std::vector< double > m_mumukpMasses
virtual StatusCode performSearch(const EventContext &ctx, xAOD::VertexContainer &) const override
JpsiPlus2Tracks(const std::string &t, const std::string &n, const IInterface *p)
std::vector< double > m_manualMassHypo
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_TrkParticleCollection
bool vertexCuts(xAOD::BPhysHelper &bHelper) const
bool passCuts(xAOD::BPhysHelper &bHelper, std::span< const double > masses, std::string_view str) const
std::vector< double > m_mumupipiMasses
ToolHandle< Trk::IVertexFitter > m_iVertexFitter
std::unique_ptr< xAOD::Vertex > fit(const EventContext &ctx, const std::vector< const xAOD::TrackParticle * > &, const xAOD::TrackParticleContainer *, const xAOD::TrackParticleContainer *GSL) const
SG::ReadHandleKey< xAOD::VertexContainer > m_jpsiCollectionKey
SG::ReadHandleKey< xAOD::MuonContainer > m_MuonsUsedInJpsi
std::vector< double > m_altMassMuonTracks
std::vector< double > m_mumukkMasses
std::vector< double > m_mumukpiMasses
std::vector< double > m_mumupikMasses
std::bitset< 4 > m_useGSFTrack
static bool cutRange(double value, double min, double max) noexcept
static double getInvariantMass(const xAOD::TrackParticle *trk1, double mass1, const xAOD::TrackParticle *trk2, double mass2)
static bool cutRangeOR(std::span< double const > values, double min, double max) noexcept
static bool isContainedIn(const xAOD::TrackParticle *, std::span< const xAOD::TrackParticle *const >) noexcept
static double getPt(std::span< const xAOD::TrackParticle *const > tracks)
static bool cutAcceptGreater(double value, double min) noexcept
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
Header file for AthHistogramAlgorithm.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
const_iterator cbegin() 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.
const_iterator cend() const noexcept
Return a const_iterator pointing past the end of the collection.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
bool setPrecedingVertices(const std::vector< const xAOD::Vertex * > &vertices, const xAOD::VertexContainer *vertexContainer)
Sets links to preceding vertices.
TVector3 refTrk(const size_t index)
Returns i-th refitted track 3-momentum.
bool setRefTrks(std::vector< float > px, std::vector< float > py, std::vector< float > pz)
Sets refitted track momenta.
TVector3 totalP()
: Returns total 3-momentum calculated from the refitted tracks
float qOverP() const
Returns the parameter.
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 namespace of all packages in PhysicsAnalysis/JetTagging.
constexpr double piMass
constexpr double kMass
constexpr double pMass
constexpr double muMass
constexpr double muonMassInMeV
the mass of the muon (in MeV)
constexpr double chargedKaonMassInMeV
the mass of the charged kaon (in MeV)
constexpr double protonMassInMeV
the mass of the proton (in MeV)
constexpr double chargedPionMassInMeV
the mass of the charged pion (in MeV)
STL namespace.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".