@@ -36,6 +36,10 @@ using namespace o2::framework;
3636using namespace o2 ::framework::expressions;
3737using namespace o2 ::math_utils::detail;
3838
39+ enum LambdaPid { kLambda = 0 ,
40+ kAntiLambda
41+ };
42+
3943// #define FLOAT_PRECISION 0xFFFFFFF0
4044#define O2_DEFINE_CONFIGURABLE (NAME, TYPE, DEFAULT, HELP ) Configurable<TYPE> NAME{#NAME, DEFAULT, HELP};
4145
@@ -50,10 +54,9 @@ struct Filter2Prong {
5054 O2_DEFINE_CONFIGURABLE (cfgImCutPt, float , 0 .2f , " Minimal pT for candidates" )
5155 O2_DEFINE_CONFIGURABLE (cfgImMinInvMass, float , 0 .95f , " Minimum invariant mass for generic 2 prong" )
5256 O2_DEFINE_CONFIGURABLE (cfgImMaxInvMass, float , 1 .07f , " Maximum invariant mass for generic 2 prong" )
53- O2_DEFINE_CONFIGURABLE (cfgImSigmaFormula, std::string, " (z < 0.5 && x < 3.0) || (z >= 0.5 && x < 2.5 && y < 3.0)" , " pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)" )
57+ O2_DEFINE_CONFIGURABLE (cfgImSigmaFormula, std::string, " (z < 0.5 && abs(x) < 3.0) || (z >= 0.5 && abs(x) < 2.5 && abs(y) < 3.0)" , " pT dependent daughter track sigma pass condition (x = TPC sigma, y = TOF sigma, z = pT)" )
5458
5559 struct : ConfigurableGroup{
56- O2_DEFINE_CONFIGURABLE (DoV0, bool , true , " Store V0s information" )
5760 O2_DEFINE_CONFIGURABLE (tpcNClsCrossedRowsTrackMin, float , 70 , " Minimum number of crossed rows in TPC" )
5861 O2_DEFINE_CONFIGURABLE (etaTrackMax, float , 0.8 , " Maximum pseudorapidity" )
5962 O2_DEFINE_CONFIGURABLE (ptTrackMin, float , 0.1 , " Minimum transverse momentum" )
@@ -79,7 +82,6 @@ struct Filter2Prong {
7982 } grpV0;
8083
8184 struct : ConfigurableGroup{
82- O2_DEFINE_CONFIGURABLE (DoPhi, bool , false , " Store Phi information" )
8385 O2_DEFINE_CONFIGURABLE (ImMinInvMassPhiMeson, float , 0 .98f , " Minimum invariant mass Phi meson (GeV)" )
8486 O2_DEFINE_CONFIGURABLE (ImMaxInvMassPhiMeson, float , 1 .07f , " Maximum invariant mass Phi meson (GeV)" )
8587 O2_DEFINE_CONFIGURABLE (ITSPIDSelection, bool , true , " PID ITS" )
@@ -293,8 +295,8 @@ struct Filter2Prong {
293295 return true ;
294296 }
295297
296- template <typename Collision, typename V0Cand>
297- bool isSelectedV0AsLambda (Collision const & collision, const V0Cand& v0, int pid /* 0: lambda, 1: antilambda */ )
298+ template <LambdaPid pid, typename Collision, typename V0Cand>
299+ bool isSelectedV0AsLambda (Collision const & collision, const V0Cand& v0)
298300 {
299301 const auto & posTrack = v0.template posTrack_as <PIDTrack>();
300302 const auto & negTrack = v0.template negTrack_as <PIDTrack>();
@@ -314,18 +316,19 @@ struct Filter2Prong {
314316 if (v0.dcaV0daughters () > grpV0.dcaV0DaughtersMaxLambda ) {
315317 return false ;
316318 }
317- if (pid == 0 && (TMath::Abs (v0.dcapostopv ()) < grpV0.minV0DCAPr || TMath::Abs (v0.dcanegtopv ()) < grpV0.minV0DCAPiLambda )) {
318- return false ;
319- }
320- if (pid == 1 && (TMath::Abs (v0.dcapostopv ()) < grpV0.minV0DCAPiLambda || TMath::Abs (v0.dcanegtopv ()) < grpV0.minV0DCAPr )) {
319+ if (pid == LambdaPid::kLambda && (TMath::Abs (v0.dcapostopv ()) < grpV0.minV0DCAPr || TMath::Abs (v0.dcanegtopv ()) < grpV0.minV0DCAPiLambda )) {
321320 return false ;
322321 }
323- if (pid == 0 && ((std::abs (posTrack.tpcNSigmaPr ()) > grpV0.daughPIDCuts ) || (std::abs (negTrack.tpcNSigmaPi ()) > grpV0.daughPIDCuts ))) {
324- return false ;
325- }
326- if (pid == 1 && ((std::abs (posTrack.tpcNSigmaPi ()) > grpV0.daughPIDCuts ) || (std::abs (negTrack.tpcNSigmaPr ()) > grpV0.daughPIDCuts ))) {
322+ if (pid == LambdaPid::kAntiLambda && (TMath::Abs (v0.dcapostopv ()) < grpV0.minV0DCAPiLambda || TMath::Abs (v0.dcanegtopv ()) < grpV0.minV0DCAPr )) {
327323 return false ;
328324 }
325+ if (pid == LambdaPid::kLambda && ((std::abs (posTrack.tpcNSigmaPr ()) > grpV0.daughPIDCuts ) || (std::abs (negTrack.tpcNSigmaPi ()) > grpV0.daughPIDCuts )))
326+ {
327+ return false ;
328+ }
329+ if (pid == LambdaPid::kAntiLambda && ((std::abs (posTrack.tpcNSigmaPi ()) > grpV0.daughPIDCuts ) || (std::abs (negTrack.tpcNSigmaPr ()) > grpV0.daughPIDCuts ))) {
330+ return false ;
331+ }
329332 if (std::abs (CtauLambda) > grpV0.maxLambdaLifeTime ) {
330333 return false ;
331334 }
@@ -369,7 +372,7 @@ struct Filter2Prong {
369372 } else if (candidate.hasTOF () && TMath::Sqrt (candidate.tpcNSigmaKa () * candidate.tpcNSigmaKa () + candidate.tofNSigmaKa () * candidate.tofNSigmaKa ()) < grpPhi.nsigmaCutTOF && candidate.beta () > grpPhi.cutTOFBeta ) {
370373 return true ;
371374 }
372- } else if (!cfgMomDepPID) {
375+ } else {
373376 if (!candidate.hasTOF () && TMath::Abs (candidate.tpcNSigmaKa ()) < grpPhi.nsigmaCutTPC ) {
374377 return true ;
375378 } else if (candidate.hasTOF () && TMath::Sqrt (candidate.tpcNSigmaKa () * candidate.tpcNSigmaKa () + candidate.tofNSigmaKa () * candidate.tofNSigmaKa ()) < grpPhi.nsigmaCutTOF && candidate.beta () > grpPhi.cutTOFBeta ) {
@@ -413,105 +416,111 @@ struct Filter2Prong {
413416 PROCESS_SWITCH (Filter2Prong, processDataInvMass, " Process data generic 2-prong candidates with invariant mass method" , false );
414417
415418 // Phi and V0s invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now.
416- void processDataPhiV0 (aod::Collisions::iterator const & collision, aod::BCsWithTimestamps const &, aod::CFCollRefs const & cfcollisions, aod::CFTrackRefs const & cftracks, Filter2Prong::PIDTrack const & tracks, aod::V0Datas const & V0s)
419+ void processDataV0 (aod::Collisions::iterator const & collision, aod::BCsWithTimestamps const &, aod::CFCollRefs const & cfcollisions, aod::CFTrackRefs const & cftracks, Filter2Prong::PIDTrack const & tracks, aod::V0Datas const & V0s)
420+ {
421+ if (cfcollisions.size () <= 0 || cftracks.size () <= 0 )
422+ return ; // rejected collision
423+
424+ o2::aod::ITSResponse itsResponse;
425+
426+ for (const auto & v0 : V0s) { // Loop over V0 candidates
427+ if (!isV0TrackSelected (v0)) { // Quality selection for V0 prongs
428+ continue ;
429+ }
430+
431+ const auto & posTrack = v0.template posTrack_as <PIDTrack>();
432+ const auto & negTrack = v0.template negTrack_as <PIDTrack>();
433+ double massV0 = 0.0 ;
434+
435+ // K0s
436+ if (isSelectedV0AsK0s (collision, v0)) { // candidate is K0s
437+ output2ProngTracks (cfcollisions.begin ().globalIndex (),
438+ posTrack.globalIndex (), negTrack.globalIndex (),
439+ v0.pt (), v0.eta (), v0.phi (), v0.mK0Short (), aod::cf2prongtrack::K0stoPiPi);
440+ }
441+
442+ // Lambda and Anti-Lambda
443+ bool LambdaTag = isSelectedV0AsLambda<LambdaPid::kLambda >(collision, v0);
444+ bool aLambdaTag = isSelectedV0AsLambda<LambdaPid::kAntiLambda >(collision, v0);
445+
446+ // Note: candidate compatible with Lambda and Anti-Lambda hypothesis are counted twice (once for each hypothesis)
447+ if (LambdaTag) { // candidate is Lambda
448+ massV0 = v0.mLambda ();
449+ output2ProngTracks (cfcollisions.begin ().globalIndex (), posTrack.globalIndex (), negTrack.globalIndex (),
450+ v0.pt (), v0.eta (), v0.phi (), massV0, aod::cf2prongtrack::LambdatoPPi);
451+ }
452+ if (aLambdaTag) { // candidate is Anti-lambda
453+ massV0 = v0.mAntiLambda ();
454+ output2ProngTracks (cfcollisions.begin ().globalIndex (), posTrack.globalIndex (), negTrack.globalIndex (),
455+ v0.pt (), v0.eta (), v0.phi (), massV0, aod::cf2prongtrack::AntiLambdatoPiP);
456+ } // end of Lambda and Anti-Lambda processing
457+ } // end of loop over V0 candidates
458+ }
459+ PROCESS_SWITCH (Filter2Prong, processDataV0, " Process data V0 candidates with invariant mass method" , false );
460+
461+ // Phi and V0s invariant mass method candidate finder. Only works for non-identical daughters of opposite charge for now.
462+ void processDataPhi (aod::Collisions::iterator const & collision, aod::BCsWithTimestamps const &, aod::CFCollRefs const & cfcollisions, aod::CFTrackRefs const & cftracks, Filter2Prong::PIDTrack const & tracks)
417463 {
418464 if (cfcollisions.size () <= 0 || cftracks.size () <= 0 )
419465 return ; // rejected collision
420466
421467 o2::aod::ITSResponse itsResponse;
422468
423- if (grpPhi.DoPhi ) { // Process Phi mesons
424- for (const auto & cftrack1 : cftracks) { // Loop over first track
425- const auto & p1 = tracks.iteratorAt (cftrack1.trackId () - tracks.begin ().globalIndex ());
426- if (p1.sign () != 1 ) {
469+ for (const auto & cftrack1 : cftracks) { // Loop over first track
470+ const auto & p1 = tracks.iteratorAt (cftrack1.trackId () - tracks.begin ().globalIndex ());
471+ if (p1.sign () != 1 ) {
472+ continue ;
473+ }
474+ if (!selectionTrack (p1)) {
475+ continue ;
476+ }
477+ if (grpPhi.ITSPIDSelection && p1.p () < grpPhi.ITSPIDPthreshold .value && !(itsResponse.nSigmaITS <o2::track::PID::Kaon>(p1) > grpPhi.lowITSPIDNsigma .value && itsResponse.nSigmaITS <o2::track::PID::Kaon>(p1) < grpPhi.highITSPIDNsigma .value )) { // Check ITS PID condition
478+ continue ;
479+ }
480+ if (!selectionPID (p1)) {
481+ continue ;
482+ }
483+ if (grpPhi.removefaketrack && isFakeTrack (p1)) { // Check if the track is a fake kaon
484+ continue ;
485+ }
486+
487+ for (const auto & cftrack2 : cftracks) { // Loop over second track
488+ if (cftrack2.globalIndex () == cftrack1.globalIndex ()) // Skip if it's the same track as the first one
427489 continue ;
428- }
429- if (!selectionTrack (p1)) {
490+
491+ const auto & p2 = tracks.iteratorAt (cftrack2.trackId () - tracks.begin ().globalIndex ());
492+ if (p2.sign () != -1 ) {
430493 continue ;
431494 }
432- if (grpPhi. ITSPIDSelection && p1. p () < grpPhi. ITSPIDPthreshold . value && !(itsResponse. nSigmaITS <o2::track::PID::Kaon>(p1) > grpPhi. lowITSPIDNsigma . value && itsResponse. nSigmaITS <o2::track::PID::Kaon>(p1) < grpPhi. highITSPIDNsigma . value )) { // Check ITS PID condition
495+ if (! selectionTrack (p2)) {
433496 continue ;
434497 }
435- if (!selectionPID (p1 )) {
498+ if (!selectionPID (p2 )) {
436499 continue ;
437500 }
438- if (grpPhi.removefaketrack && isFakeTrack (p1)) { // Check if the track is a fake kaon
501+ if (grpPhi.ITSPIDSelection && p2. p () < grpPhi. ITSPIDPthreshold . value && !(itsResponse. nSigmaITS <o2::track::PID::Kaon>(p2) > grpPhi. lowITSPIDNsigma . value && itsResponse. nSigmaITS <o2:: track::PID::Kaon>(p2) < grpPhi. highITSPIDNsigma . value )) { // Check ITS PID condition
439502 continue ;
440503 }
441-
442- for (const auto & cftrack2 : cftracks) { // Loop over second track
443- if (cftrack2.globalIndex () == cftrack1.globalIndex ()) // Skip if it's the same track as the first one
444- continue ;
445-
446- const auto & p2 = tracks.iteratorAt (cftrack2.trackId () - tracks.begin ().globalIndex ());
447- if (p2.sign () != -1 ) {
448- continue ;
449- }
450- if (!selectionTrack (p2)) {
451- continue ;
452- }
453- if (!selectionPID (p2)) {
454- continue ;
455- }
456- if (grpPhi.ITSPIDSelection && p2.p () < grpPhi.ITSPIDPthreshold .value && !(itsResponse.nSigmaITS <o2::track::PID::Kaon>(p2) > grpPhi.lowITSPIDNsigma .value && itsResponse.nSigmaITS <o2::track::PID::Kaon>(p2) < grpPhi.highITSPIDNsigma .value )) { // Check ITS PID condition
457- continue ;
458- }
459- if (grpPhi.removefaketrack && isFakeTrack (p2)) { // Check if the track is a fake kaon
460- continue ;
461- }
462- if (!selectionPair (p1, p2)) {
463- continue ;
464- }
465-
466- ROOT::Math::PtEtaPhiMVector vec1 (p1.pt (), p1.eta (), p1.phi (), cfgImPart1Mass);
467- ROOT::Math::PtEtaPhiMVector vec2 (p2.pt (), p2.eta (), p2.phi (), cfgImPart2Mass);
468- ROOT::Math::PtEtaPhiMVector s = vec1 + vec2;
469- if (s.M () < grpPhi.ImMinInvMassPhiMeson || s.M () > grpPhi.ImMaxInvMassPhiMeson ) {
470- continue ;
471- }
472- float phi = RecoDecay::constrainAngle (s.Phi (), 0 .0f );
473- output2ProngTracks (cfcollisions.begin ().globalIndex (),
474- cftrack1.globalIndex (), cftrack2.globalIndex (), s.pt (), s.eta (), phi, s.M (), aod::cf2prongtrack::PhiToKK);
475- } // end of loop over second track
476- } // end of loop over first track
477- } // end of processing Phi mesons
478-
479- if (grpV0.DoV0 ) { // Process V0 candidates (K0s, Lambdas, Anti-Lambdas)
480- for (const auto & v0 : V0s) { // Loop over V0 candidates
481- if (!isV0TrackSelected (v0)) { // Quality selection for V0 prongs
504+ if (grpPhi.removefaketrack && isFakeTrack (p2)) { // Check if the track is a fake kaon
482505 continue ;
483506 }
484-
485- const auto & posTrack = v0.template posTrack_as <PIDTrack>();
486- const auto & negTrack = v0.template negTrack_as <PIDTrack>();
487- double massV0 = 0.0 ;
488-
489- // K0s
490- if (isSelectedV0AsK0s (collision, v0)) { // candidate is K0s
491- output2ProngTracks (cfcollisions.begin ().globalIndex (),
492- posTrack.globalIndex (), negTrack.globalIndex (),
493- v0.pt (), v0.eta (), v0.phi (), v0.mK0Short (), aod::cf2prongtrack::K0stoPiPi);
507+ if (!selectionPair (p1, p2)) {
508+ continue ;
494509 }
495510
496- // Lambda and Anti-Lambda
497- bool LambdaTag = isSelectedV0AsLambda (collision, v0, 0 );
498- bool aLambdaTag = isSelectedV0AsLambda (collision, v0, 1 );
499-
500- // Note: candidate compatible with Lambda and Anti-Lambda hypothesis are counted twice (once for each hypothesis)
501- if (LambdaTag) { // candidate is Lambda
502- massV0 = v0.mLambda ();
503- output2ProngTracks (cfcollisions.begin ().globalIndex (), posTrack.globalIndex (), negTrack.globalIndex (),
504- v0.pt (), v0.eta (), v0.phi (), massV0, aod::cf2prongtrack::LambdatoPPi);
511+ ROOT::Math::PtEtaPhiMVector vec1 (p1.pt (), p1.eta (), p1.phi (), cfgImPart1Mass);
512+ ROOT::Math::PtEtaPhiMVector vec2 (p2.pt (), p2.eta (), p2.phi (), cfgImPart2Mass);
513+ ROOT::Math::PtEtaPhiMVector s = vec1 + vec2;
514+ if (s.M () < grpPhi.ImMinInvMassPhiMeson || s.M () > grpPhi.ImMaxInvMassPhiMeson ) {
515+ continue ;
505516 }
506- if (aLambdaTag) { // candidate is Anti-lambda
507- massV0 = v0.mAntiLambda ();
508- output2ProngTracks (cfcollisions.begin ().globalIndex (), posTrack.globalIndex (), negTrack.globalIndex (),
509- v0.pt (), v0.eta (), v0.phi (), massV0, aod::cf2prongtrack::AntiLambdatoPiP);
510- } // end of Lambda and Anti-Lambda processing
511- } // end of loop over V0 candidates
512- } // end of processing V0 candidates
517+ float phi = RecoDecay::constrainAngle (s.Phi (), 0 .0f );
518+ output2ProngTracks (cfcollisions.begin ().globalIndex (),
519+ cftrack1.globalIndex (), cftrack2.globalIndex (), s.pt (), s.eta (), phi, s.M (), aod::cf2prongtrack::PhiToKK);
520+ } // end of loop over second track
521+ } // end of loop over first track
513522 }
514- PROCESS_SWITCH (Filter2Prong, processDataPhiV0 , " Process data PhiV0 candidates with invariant mass method" , false );
523+ PROCESS_SWITCH (Filter2Prong, processDataPhi , " Process data Phi candidates with invariant mass method" , false );
515524
516525}; // struct
517526
0 commit comments