ATLAS Offline Software
Loading...
Searching...
No Matches
JpsiFinder_ee.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5// ****************************************************************************
6// ----------------------------------------------------------------------------
7// JpsiFinder_ee
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
21#include "AthLinks/ElementLink.h"
22#include "xAODTracking/Vertex.h"
28namespace Analysis {
29
31
32 // Initialize the ReadHandles
35
36 // Initialize ReadDecorHandles
37 ATH_CHECK(m_gsfCaloLinkKey.initialize());
38
39 // retrieving vertex Fitter
40 ATH_CHECK(m_iVertexFitter.retrieve());
41
42 // Get the track selector tool from ToolSvc
43 ATH_CHECK(m_trkSelector.retrieve());
44
45
46 // Get the vertex point estimator tool from ToolSvc
47 ATH_CHECK(m_vertexEstimator.retrieve());
48 m_gendata = std::make_shared<GenData>();
49
50
51 if (m_diElectrons) {
52 const double elMass = m_gendata->particleMass(MC::ELECTRON).value_or(ParticleConstants::electronMassInMeV);
53 m_trk1M = elMass;
54 m_trk2M = elMass;
55 }
56
57 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");
58
59
60// // Check that the user's settings are sensible
61 bool illogicalOptions(false);
62 if ( (m_elel && m_eltrk) || (m_elel && m_trktrk) || (m_eltrk && m_trktrk) ) {
63 ATH_MSG_WARNING("You are requesting incompatible combinations of muons and tracks in the pairs. JpsiEECandidates will be EMPTY!");
64 illogicalOptions=true;
65 };
67 ATH_MSG_WARNING("You are requesting Tag and Probe analysis but have not requested mu+trk mode. This is impossible. JpsiEECandidates will be EMPTY!");
68 illogicalOptions=true;
69 };
71 ATH_MSG_WARNING("You are requesting incompatible combinations of charges in the pairs. JpsiEECandidates will be EMPTY!");
72 illogicalOptions=true;
73 };
75 ATH_MSG_WARNING("You are requesting same-sign or all-sign combinations in a tag and probe analysis. This doesn't make sense. JpsiEECandidates will be EMPTY!");
76 illogicalOptions=true;
77 }
78 if (illogicalOptions) return StatusCode::FAILURE;
79
80
81
82 ATH_MSG_DEBUG("Initialize successful");
83
84 return StatusCode::SUCCESS;
85
86 }
87
88
89 JpsiFinder_ee::JpsiFinder_ee(const std::string& t, const std::string& n, const IInterface* p) : AthAlgTool(t,n,p),
90 m_elel(true),
91 m_eltrk(false),
92 m_trktrk(false),
93 m_allElectrons(false),
95 m_diElectrons(true),
96 m_trk1M(ParticleConstants::electronMassInMeV),
97 m_trk2M(ParticleConstants::electronMassInMeV),
98 m_thresholdPt(0.0),
99 m_higherPt(0.0),
100 m_trkThresholdPt(0.0),
101 m_invMassUpper(100000.0),
102 m_invMassLower(0.0),
103 m_collAngleTheta(0.0),
104 m_collAnglePhi(0.0),
105 m_Chi2Cut(50.),
106 m_oppChOnly(true),
107 m_sameChOnly(false),
108 m_allChCombs(false),
109 m_electronCollectionKey("Electrons"),
110 m_TrkParticleCollection("InDetTrackParticles"),
111 m_iVertexFitter("Trk::TrkVKalVrtFitter"),
112 m_trkSelector("InDet::TrackSelectorTool"),
113 m_vertexEstimator("InDet::VertexPointEstimator"),
114 m_egammaCuts(true),
115 m_elSelection("d0_or_nod0"),
116 m_doTagAndProbe(false)
117
118 {
119 declareInterface<JpsiFinder_ee>(this);
120 declareProperty("elAndEl",m_elel);
121 declareProperty("elAndTrack",m_eltrk);
122 declareProperty("TrackAndTrack",m_trktrk);
123 declareProperty("allElectrons",m_allElectrons);
124 declareProperty("useElectronTrackMeasurement",m_useTrackMeasurement);
125 declareProperty("assumeDiElectrons",m_diElectrons);
126// declareProperty("electronLHValue",m_electronLHValue);
127 declareProperty("track1Mass",m_trk1M);
128 declareProperty("track2Mass",m_trk2M);
129 declareProperty("elThresholdPt",m_thresholdPt);
130 declareProperty("higherPt",m_higherPt);
131 declareProperty("trackThresholdPt",m_trkThresholdPt);
132 declareProperty("invMassUpper",m_invMassUpper);
133 declareProperty("invMassLower",m_invMassLower);
134 declareProperty("collAngleTheta",m_collAngleTheta);
135 declareProperty("collAnglePhi",m_collAnglePhi);
136 declareProperty("Chi2Cut",m_Chi2Cut);
137 declareProperty("oppChargesOnly",m_oppChOnly);
138 declareProperty("sameChargesOnly",m_sameChOnly);
139 declareProperty("allChargeCombinations",m_allChCombs);
140 declareProperty("electronCollectionKey",m_electronCollectionKey);
141 declareProperty("TrackParticleCollection",m_TrkParticleCollection);
142 declareProperty("TrkVertexFitterTool",m_iVertexFitter);
143 declareProperty("TrackSelectorTool",m_trkSelector);
144 declareProperty("VertexPointEstimator",m_vertexEstimator);
145 declareProperty("useEgammaCuts",m_egammaCuts);
146 declareProperty("doTagAndProbe",m_doTagAndProbe);
147 declareProperty("ElectronSelection",m_elSelection);
148 }
149
151
152 //-------------------------------------------------------------------------------------
153 // Find the candidates
154 //-------------------------------------------------------------------------------------
155
156
157 StatusCode JpsiFinder_ee::performSearch(const EventContext& ctx, xAOD::VertexContainer& vxContainer) const
158 {
159 ATH_MSG_DEBUG( "JpsiFinder_ee::performSearch" );
160
161
162 // Get the electrons from StoreGate
163 const xAOD::ElectronContainer* importedElectronCollection=nullptr;
165 if(!ehandle.isValid()){
166 ATH_MSG_WARNING("No electron collection with key " << m_electronCollectionKey.key() << " found in StoreGate. JpsiEECandidates will be EMPTY!");
167 return StatusCode::SUCCESS;;
168 }else{
169 importedElectronCollection = ehandle.cptr();
170 ATH_MSG_DEBUG("Found electron collections with key "<<m_electronCollectionKey.key());
171 }
172 ATH_MSG_DEBUG("Electron container size "<<importedElectronCollection->size());
173
174 // Get ID tracks
176 const xAOD::TrackParticleContainer* importedTrackCollection(0);
177 if(!thandle.isValid()){
178 ATH_MSG_WARNING("No TrackParticle collection with name " << m_TrkParticleCollection << " found in StoreGate!");
179 return StatusCode::SUCCESS;;
180 } else {
181 importedTrackCollection = thandle.cptr();
182 }
183
184 // Typedef for vectors of tracks and muons
185 typedef std::vector<const xAOD::TrackParticle*> TrackBag;
186 typedef std::vector<const xAOD::Electron*> ElectronBag;
187
188 // Select the inner detector tracks
189 const xAOD::Vertex* vx = 0;
190 TrackBag theIDTracksAfterSelection;
191 if (m_trktrk || m_eltrk) {
193 for (trkCItr=importedTrackCollection->begin(); trkCItr!=importedTrackCollection->end(); ++trkCItr) {
194 const xAOD::TrackParticle* TP = (*trkCItr);
195 if ( fabs(TP->pt())<m_trkThresholdPt ) continue;
196 if ( !m_trkSelector->decision(*TP, vx) ) continue;
197 theIDTracksAfterSelection.push_back(TP);
198 }
199 if (theIDTracksAfterSelection.size() == 0) return StatusCode::SUCCESS;;
200 ATH_MSG_DEBUG("Number of tracks after ID track selection: " << theIDTracksAfterSelection.size());
201 }
202
203 // Select the muons
204 ElectronBag theElectronsAfterSelection;
206 if (m_elel || m_eltrk) {
207 for (elItr=importedElectronCollection->begin(); elItr!=importedElectronCollection->end(); ++elItr) {
208 if ( *elItr == NULL ) continue;
209 if (!(*elItr)->trackParticleLink().isValid()) continue; // No electrons without ID tracks
210 const xAOD::TrackParticle* elTrk(0);
211 if (m_TrkParticleCollection.key() == "GSFCaloContainer") {
213 refittedTrackParticleLink(m_gsfCaloLinkKey, ctx);
214 const ElementLink<xAOD::TrackParticleContainer>& refittedTrackLink = refittedTrackParticleLink(*(*elItr));
215 if (!refittedTrackLink.isValid()) continue;
216 elTrk = *refittedTrackLink;
217 } else {
218 if (!(*elItr)->trackParticleLink().isValid()) continue;
219 elTrk = (*elItr)->trackParticleLink().cachedElement();
220 }
221
222 if ( elTrk==NULL) continue;
223 if ( !m_trkSelector->decision(*elTrk, vx) ) continue; // all ID tracks must pass basic tracking cuts
224 if ( fabs(elTrk->pt())<m_thresholdPt ) continue; // higher pt cut if needed
225
226 if ( m_egammaCuts && !passesEgammaCuts(*elItr)) continue; // egamma cuts
227 theElectronsAfterSelection.push_back(*elItr);
228 }
229 if (theElectronsAfterSelection.size() == 0) return StatusCode::SUCCESS;;
230 ATH_MSG_DEBUG("Number of electrons after selection: " << theElectronsAfterSelection.size());
231 }
232
233 // Sort into pairs - end result will be a vector of JpsiEECandidate structs
234 std::vector<JpsiEECandidate> jpsiCandidates;
235 if (m_elel) jpsiCandidates = getPairs(theElectronsAfterSelection);
236 if (m_trktrk) jpsiCandidates = getPairs(theIDTracksAfterSelection);
237 if (m_eltrk) jpsiCandidates = getPairs2Colls(theIDTracksAfterSelection,theElectronsAfterSelection,m_doTagAndProbe);
238
239 ATH_MSG_DEBUG("Number of pairs with ee from a B decay: " << jpsiCandidates.size() );
240
241 // Pair-wise selections
242 std::vector<JpsiEECandidate>::iterator jpsiItr;
243
244 // (1) Enforce one combined muon [deleted, no electron equivalent]
245
246 // (2) Establish track content for candidates
247 // and set the appropriate track collections for the combined muon tracks where appropriate (for saving to persistency later)
248
249 // el+trk or trk+trk - always ID track collection
250 if (m_eltrk || m_trktrk) {
251 for (jpsiItr=jpsiCandidates.begin(); jpsiItr!=jpsiCandidates.end(); ++jpsiItr) {
252 (*jpsiItr).collection1 = importedTrackCollection;
253 (*jpsiItr).collection2 = importedTrackCollection;
254 }
255 }
256
257 if (m_elel) {
258 for (jpsiItr=jpsiCandidates.begin(); jpsiItr!=jpsiCandidates.end(); ++jpsiItr) {
259 if ( m_useTrackMeasurement ) {
260 if (m_TrkParticleCollection.key() == "GSFCaloContainer") {
262 refittedTrackParticleLink(m_gsfCaloLinkKey, ctx);
263 const ElementLink<xAOD::TrackParticleContainer>& refittedTrackLink1 = refittedTrackParticleLink(*((*jpsiItr).el1));
264 const ElementLink<xAOD::TrackParticleContainer>& refittedTrackLink2 = refittedTrackParticleLink(*((*jpsiItr).el2));
265 (*jpsiItr).trackParticle1 = *refittedTrackLink1;
266 (*jpsiItr).trackParticle2 = *refittedTrackLink2;
267 } else {
268 (*jpsiItr).trackParticle1 = (*jpsiItr).el1->trackParticleLink().cachedElement();
269 (*jpsiItr).trackParticle2 = (*jpsiItr).el2->trackParticleLink().cachedElement();
270 }
271 (*jpsiItr).collection1 = importedTrackCollection;
272 (*jpsiItr).collection2 = importedTrackCollection;
273 } else {
274 ATH_MSG_WARNING("Not setup for non-track electron measurements yet....");
275 }
276 } // iteration over candidates
277 }
278
279
280 // (3) Enforce higher track pt if requested
281 if (m_higherPt>0.0) {
282 int index(0);
283 std::vector<int> listToDelete;
284 std::vector<int>::reverse_iterator ii;
285 for(jpsiItr=jpsiCandidates.begin(); jpsiItr!=jpsiCandidates.end();++jpsiItr,++index) {
286 if( (fabs((*jpsiItr).trackParticle1->pt()) < m_higherPt) && (fabs((*jpsiItr).trackParticle2->pt()) < m_higherPt) ) listToDelete.push_back(index);
287 }
288 for (ii=listToDelete.rbegin(); ii!=listToDelete.rend(); ++ii) {
289 jpsiCandidates.erase(jpsiCandidates.begin() + (*ii) );
290 }
291 ATH_MSG_DEBUG("Number of candidates after higherPt cut: " << jpsiCandidates.size() );
292 }
293
294 // (4) Select all opp/same charged track pairs
295 std::vector<JpsiEECandidate> sortedJpsiEECandidates;
296 if (m_oppChOnly) sortedJpsiEECandidates = selectCharges(jpsiCandidates,"OPPOSITE");
297 if (m_sameChOnly) sortedJpsiEECandidates = selectCharges(jpsiCandidates,"SAME");
298 if (m_allChCombs) sortedJpsiEECandidates = selectCharges(jpsiCandidates,"ALL");
299 ATH_MSG_DEBUG("Number of candidates after charge selection: " << sortedJpsiEECandidates.size() );
300
301 // (5) Select for decay angle, if requested
302 if (m_collAnglePhi>0.0 && m_collAngleTheta>0.0) {
303 int index(0);
304 std::vector<int> listToDelete;
305 std::vector<int>::reverse_iterator ii;
306 for(jpsiItr=sortedJpsiEECandidates.begin(); jpsiItr!=sortedJpsiEECandidates.end();++jpsiItr,++index) {
307 double deltatheta = fabs( (*jpsiItr).trackParticle1->theta() - (*jpsiItr).trackParticle2->theta() );
308 // -3.14 < phi < +3.14 ==> correction
309 double deltaphi = std::abs(xAOD::P4Helpers::deltaPhi((*jpsiItr).trackParticle1->phi0() , (*jpsiItr).trackParticle2->phi0()));
310 // perform the angle cuts
311 if ((deltatheta > m_collAngleTheta) || (deltaphi > m_collAnglePhi)) listToDelete.push_back(index);
312 }
313 for (ii=listToDelete.rbegin(); ii!=listToDelete.rend(); ++ii) {
314 sortedJpsiEECandidates.erase(sortedJpsiEECandidates.begin() + (*ii) );
315 }
316 ATH_MSG_DEBUG("Number of collimated candidates: " << sortedJpsiEECandidates.size() );
317 }
318
319 // (6) Select for invariant mass, if requested
320 std::vector<double> trkMasses;
321 trkMasses.push_back(m_trk1M);
322 trkMasses.push_back(m_trk2M);
323 if ( (m_invMassLower > 0.0) || (m_invMassUpper > 0.0) ) {
324 int index(0);
325 std::vector<int> listToDelete;
326 std::vector<int>::reverse_iterator ii;
327 for(jpsiItr=sortedJpsiEECandidates.begin(); jpsiItr!=sortedJpsiEECandidates.end(); ++jpsiItr,++index) {
328 double invMass = getInvariantMass(*jpsiItr,trkMasses);
329 // std::cout << "inv. mass: " << invMass << std::endl;
330 if ( invMass < m_invMassLower || invMass > m_invMassUpper ) {
331 listToDelete.push_back(index);
332 }
333 }
334 for (ii=listToDelete.rbegin(); ii!=listToDelete.rend(); ++ii) {
335 sortedJpsiEECandidates.erase(sortedJpsiEECandidates.begin() + (*ii) );
336 }
337 ATH_MSG_DEBUG("Number of candidates passing invariant mass selection: " << sortedJpsiEECandidates.size() );
338 }
339
340 if (sortedJpsiEECandidates.size() == 0) return StatusCode::SUCCESS;;
341
342 // Fit each pair of tracks to a vertex
343 int itritn = 0;
344 for(jpsiItr=sortedJpsiEECandidates.begin(); jpsiItr!=sortedJpsiEECandidates.end(); ++jpsiItr) {
345 ATH_MSG_DEBUG("jpsiItr: " << itritn); itritn++;
346 std::vector<const xAOD::TrackParticle*> theTracks; theTracks.clear();
347 theTracks.push_back((*jpsiItr).trackParticle1);
348 theTracks.push_back((*jpsiItr).trackParticle2);
349 ATH_MSG_DEBUG("theTracks size (should be two!) " << theTracks.size() << " being vertexed with tracks " << importedTrackCollection);
350 std::unique_ptr<xAOD::Vertex> myVxCandidate{fit(ctx, theTracks,importedTrackCollection)}; // This line actually does the fitting and object making
351 if (myVxCandidate != 0) {
352 // Chi2 cut if requested
353 double chi2 = myVxCandidate->chiSquared();
354 ATH_MSG_DEBUG("chi2 is: " << chi2);
355 if (m_Chi2Cut == 0.0 || chi2 <= m_Chi2Cut) {
356 // decorate the candidate with refitted tracks and muons via the BPhysHelper
357 xAOD::BPhysHelper jpsiHelper(myVxCandidate.get());
358 jpsiHelper.setRefTrks();
359 if (m_elel || m_eltrk) {
360 std::vector<const xAOD::Electron*> theStoredElectrons;
361 theStoredElectrons.push_back((*jpsiItr).el1);
362 if (m_elel) theStoredElectrons.push_back((*jpsiItr).el2);
363 jpsiHelper.setElectrons(theStoredElectrons,importedElectronCollection);
364 }
365 // Retain the vertex
366 vxContainer.push_back(std::move(myVxCandidate));
367 }
368 } else { // fit failed
369 ATH_MSG_DEBUG("Fitter failed!");
370 // Don't try to delete the object, since we arrived here,
371 // because this pointer is null...
372 //delete myVxCandidate;
373 }
374 }
375 ATH_MSG_DEBUG("vxContainer size " << vxContainer.size());
376
377 return StatusCode::SUCCESS;;
378 }
379
380 // *********************************************************************************
381
382 // ---------------------------------------------------------------------------------
383 // fit - does the fit
384 // ---------------------------------------------------------------------------------
385
386 std::unique_ptr<xAOD::Vertex> JpsiFinder_ee::fit(const EventContext& ctx, const std::vector<const xAOD::TrackParticle*> &inputTracks,const xAOD::TrackParticleContainer* importedTrackCollection) const {
387 ATH_MSG_DEBUG("inside JpsiFinder_ee::fit");
388
389 const Trk::Perigee& aPerigee1 = inputTracks[0]->perigeeParameters();
390 const Trk::Perigee& aPerigee2 = inputTracks[1]->perigeeParameters();
391 int sflag = 0;
392 int errorcode = 0;
393 Amg::Vector3D startingPoint = m_vertexEstimator->getCirclesIntersectionPoint(&aPerigee1,&aPerigee2,sflag,errorcode);
394 if (errorcode != 0) {startingPoint(0) = 0.0; startingPoint(1) = 0.0; startingPoint(2) = 0.0;}
395
396 auto myVxCandidate = m_iVertexFitter->fit(ctx, inputTracks, startingPoint);
397 ATH_MSG_DEBUG("Initial fit was a success! " << myVxCandidate);
398 // Added by ASC
399 if(myVxCandidate != 0){
400 std::vector<ElementLink<DataVector<xAOD::TrackParticle> > > newLinkVector;
401 for(unsigned int i=0; i< myVxCandidate->trackParticleLinks().size(); i++){
402 ElementLink<DataVector<xAOD::TrackParticle> > mylink=myVxCandidate->trackParticleLinks()[i]; //makes a copy (non-const)
403 mylink.setStorableObject(*importedTrackCollection, true);
404 newLinkVector.push_back( mylink );
405 ATH_MSG_DEBUG("Set a link!");
406 }
407 myVxCandidate->clearTracks();
408 myVxCandidate->setTrackParticleLinks( newLinkVector );
409 ATH_MSG_DEBUG("Set all links");
410 }
411
412 return myVxCandidate;
413
414 } // End of fit method
415
416
417 // *********************************************************************************
418
419 // ---------------------------------------------------------------------------------
420 // getPairs: forms up 2-plets of tracks
421 // ---------------------------------------------------------------------------------
422
423 std::vector<JpsiEECandidate> JpsiFinder_ee::getPairs(const std::vector<const xAOD::TrackParticle*> &TracksIn) const {
424
425 std::vector<JpsiEECandidate> myPairs;
427 std::vector<const xAOD::TrackParticle*>::const_iterator outerItr;
428 std::vector<const xAOD::TrackParticle*>::const_iterator innerItr;
429
430 if(TracksIn.size()>=2){
431 for(outerItr=TracksIn.begin();outerItr<TracksIn.end();++outerItr){
432 for(innerItr=(outerItr+1);innerItr!=TracksIn.end();++innerItr){
433 pair.trackParticle1 = *innerItr;
434 pair.trackParticle2 = *outerItr;
435 pair.pairType = TRK2;
436 myPairs.push_back(pair);
437 }
438 }
439 }
440
441 return(myPairs);
442 }
443
444 // *********************************************************************************
445
446 // ---------------------------------------------------------------------------------
447 // getPairs: forms up 2-plets of electrons
448 // ---------------------------------------------------------------------------------
449
450 std::vector<JpsiEECandidate> JpsiFinder_ee::getPairs(const std::vector<const xAOD::Electron*> &electronsIn) const {
451
452 std::vector<JpsiEECandidate> myPairs;
454 std::vector<const xAOD::Electron*>::const_iterator outerItr;
455 std::vector<const xAOD::Electron*>::const_iterator innerItr;
456
457 if(electronsIn.size()>=2){
458 for(outerItr=electronsIn.begin();outerItr<electronsIn.end();++outerItr){
459 for(innerItr=(outerItr+1);innerItr!=electronsIn.end();++innerItr){
460 pair.el1 = *innerItr;
461 pair.el2 = *outerItr;
462 pair.pairType = ELEL;
463 myPairs.push_back(pair);
464 }
465 }
466 }
467
468 return(myPairs);
469 }
470
471 // *********************************************************************************
472
473 // ---------------------------------------------------------------------------------
474 // getPairs2Colls: forms up 2-plets of tracks from two independent collections
475 // ---------------------------------------------------------------------------------
476
477 std::vector<JpsiEECandidate> JpsiFinder_ee::getPairs2Colls(const std::vector<const xAOD::TrackParticle*> &tracks, const std::vector<const xAOD::Electron*> &electrons, bool tagAndProbe) const {
478
479 std::vector<JpsiEECandidate> myPairs;
480 if (m_TrkParticleCollection.key() == "GSFCaloContainer") {
481 ATH_MSG_FATAL("GSFCaloContainer mode not implemented in getPairs2Colls.");
482 return myPairs;
483 }
485
486 // Unless user is running in tag and probe mode, remove tracks which are also identified as muons
487 std::vector<const xAOD::TrackParticle*> tracksToKeep;
488 if (!tagAndProbe) {
489 if(tracks.size()>=1 && electrons.size()>=1){
490 for (const xAOD::TrackParticle* trk : tracks) {
491 bool trackIsElectron(false);
492 for (const xAOD::Electron* ele : electrons) {
493 if ( ele->trackParticleLink().cachedElement() == trk ) {
494 trackIsElectron=true;
495 break;
496 }
497 }
498 if (!trackIsElectron) tracksToKeep.push_back(trk);
499 }
500 }
501 } else {tracksToKeep = tracks;}
502
503 if(tracksToKeep.size()>=1 && electrons.size()>=1){
504 for (const xAOD::TrackParticle* trk : tracks) {
505 for (const xAOD::Electron* ele : electrons) {
506 pair.el1 = ele;
507 // Muon track 1st
508 pair.trackParticle1 = ele->trackParticleLink().cachedElement();
509 pair.trackParticle2 = trk;
510 pair.pairType = ELTRK;
511 myPairs.push_back(pair);
512 }
513 }
514 }
515
516 return(myPairs);
517 }
518
519
520
521 // *********************************************************************************
522
523 // ---------------------------------------------------------------------------------
524 // getInvariantMass: returns invariant mass
525 // ---------------------------------------------------------------------------------
526
527 double JpsiFinder_ee::getInvariantMass(const JpsiEECandidate &jpsiIn, const std::vector<double> &massHypotheses) const {
528
529 // construct 4-vectors from track perigee parameters using given mass hypotheses.
530 // NOTE: in new data model (xAOD) the defining parameters are expressed as perigee parameters w.r.t. the beamspot
531 // NOTE2: TrackParticle::p4() method already returns TLorentzVector, however, we want to enforce our own mass hypothesis
532 auto mu1 = jpsiIn.trackParticle1->genvecP4();
533 auto mu2 = jpsiIn.trackParticle2->genvecP4();
534 mu1.SetM(massHypotheses[0]);
535 mu2.SetM(massHypotheses[1]);
536
537 return (mu1+mu2).M();
538
539 }
540
541 // ---------------------------------------------------------------------------------
542 // selectCharges: selects track pairs with opposite charge / store + before -
543 // Boolean argument is to decide whether to accept oppositely or identically charged
544 // particles (true for oppositely charged)
545 // ---------------------------------------------------------------------------------
546
547 std::vector<JpsiEECandidate> JpsiFinder_ee::selectCharges(const std::vector<JpsiEECandidate> &jpsisIn, const std::string &selection) const {
548
549 bool opposite(false),same(false),all(false);
550 if (selection=="OPPOSITE") opposite=true;
551 if (selection=="SAME") same=true;
552 if (selection=="ALL") all=true;
553
554 JpsiEECandidate tmpJpsi;
555 std::vector<JpsiEECandidate> jpsis;
556 double qOverP1=0.;
557 double qOverP2=0.;
558 for(auto jpsiItr=jpsisIn.cbegin();jpsiItr!=jpsisIn.cend();jpsiItr++){
559 bool oppCh(false),sameCh(false);
560 tmpJpsi = *jpsiItr;
561 qOverP1=(*jpsiItr).trackParticle1->qOverP();
562 qOverP2=(*jpsiItr).trackParticle2->qOverP();
563 if(qOverP1*qOverP2<0.0) oppCh=true; // product charge < 0
564 if(qOverP1*qOverP2>0.0) sameCh=true; // product charge > 0
565 // +ve should be first so swap
566 // Don't do it for tag and probe analyses (because tag muon must not change position)
567 if (oppCh && qOverP1<0.0 && !m_doTagAndProbe) {
568 tmpJpsi.trackParticle1 = (*jpsiItr).trackParticle2;
569 tmpJpsi.trackParticle2 = (*jpsiItr).trackParticle1;
570 tmpJpsi.el1 = (*jpsiItr).el2;
571 tmpJpsi.el2 = (*jpsiItr).el1;
572 tmpJpsi.collection1 = (*jpsiItr).collection2;
573 tmpJpsi.collection2 = (*jpsiItr).collection1;
574 }
575 if (oppCh && (opposite || all) ) jpsis.push_back(tmpJpsi);
576 if (sameCh && (same || all) ) jpsis.push_back(tmpJpsi);
577
578 } // end of for loop
579
580 return(jpsis);
581 }
582
583 // ---------------------------------------------------------------------------------
584 // Apply the current cuts of the MCP group recommendation.
585 // ---------------------------------------------------------------------------------
586
588
589 static const SG::AuxElement::ConstAccessor<char> isLHVeryLoosenod0("DFCommonElectronsLHVeryLoosenod0");
590 static const SG::AuxElement::ConstAccessor<char> isLHVeryLoose("DFCommonElectronsLHVeryLoose");
591
592 bool passesSelection = false;
593 bool passesLHVLoose = isLHVeryLoose(*electron);
594 bool passesLHVLoosenod0 = isLHVeryLoosenod0(*electron);
595
596 if(m_elSelection == "d0") passesSelection = passesLHVLoose;
597 else if(m_elSelection == "nod0") passesSelection = passesLHVLoosenod0;
598 else if(m_elSelection == "d0_or_nod0") passesSelection = passesLHVLoose || passesLHVLoosenod0;
599 else ATH_MSG_ERROR("Invalid electron selection " << m_elSelection);
600
601 ATH_MSG_DEBUG("Electron with pT, eta: " << electron->pt() << " " << electron->eta() << " passes " << m_elSelection << " " << passesSelection);
602 return passesSelection;
603
604 }
605
606
607 // ---------------------------------------------------------------------------------
608 // Checks whether a TPB is in the collection
609 // ---------------------------------------------------------------------------------
610
611 bool JpsiFinder_ee::isContainedIn(const xAOD::TrackParticle* theTrack, const xAOD::TrackParticleContainer* theCollection) const {
612 return std::find(theCollection->begin(), theCollection->end(), theTrack) != theCollection->end();
613 }
614
615}
#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.
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.
bool isContainedIn(const xAOD::TrackParticle *, const xAOD::TrackParticleContainer *) const
bool passesEgammaCuts(const xAOD::Electron *) const
std::vector< JpsiEECandidate > getPairs(const std::vector< const xAOD::TrackParticle * > &) const
std::unique_ptr< xAOD::Vertex > fit(const EventContext &ctx, const std::vector< const xAOD::TrackParticle * > &, const xAOD::TrackParticleContainer *importedTrackCollection) const
SG::ReadHandleKey< xAOD::ElectronContainer > m_electronCollectionKey
ToolHandle< Trk::ITrackSelectorTool > m_trkSelector
std::vector< JpsiEECandidate > selectCharges(const std::vector< JpsiEECandidate > &, const std::string &) const
SG::ReadDecorHandleKey< xAOD::ElectronContainer > m_gsfCaloLinkKey
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_TrkParticleCollection
virtual StatusCode initialize() override
JpsiFinder_ee(const std::string &t, const std::string &n, const IInterface *p)
virtual StatusCode performSearch(const EventContext &ctx, xAOD::VertexContainer &vxContainer) const override
ToolHandle< InDet::VertexPointEstimator > m_vertexEstimator
double getInvariantMass(const JpsiEECandidate &, const std::vector< double > &) const
ToolHandle< Trk::IVertexFitter > m_iVertexFitter
std::shared_ptr< GenData > m_gendata
std::vector< JpsiEECandidate > getPairs2Colls(const std::vector< const xAOD::TrackParticle * > &, const std::vector< const xAOD::Electron * > &, bool) const
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)
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.
Handle class for reading a decoration on an object.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
STL class.
bool setElectrons(const std::vector< const xAOD::Electron * > &electrons, const xAOD::ElectronContainer *electronContainer)
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)
const std::string selection
Eigen::Matrix< double, 3, 1 > Vector3D
The namespace of all packages in PhysicsAnalysis/JetTagging.
static const int ELECTRON
constexpr double electronMassInMeV
the mass of the electron (in MeV)
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
Definition index.py:1
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
ElectronContainer_v1 ElectronContainer
Definition of the current "electron container version".
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".
Electron_v1 Electron
Definition of the current "egamma version".
const xAOD::TrackParticleContainer * collection2
const xAOD::TrackParticleContainer * collection1
const xAOD::TrackParticle * trackParticle2
const xAOD::Electron * el2
const xAOD::Electron * el1
const xAOD::TrackParticle * trackParticle1