@@ -50,6 +50,9 @@ using namespace o2::framework::expressions;
5050using std::array;
5151using namespace o2 ::aod::rctsel;
5252
53+ using dauTracks = soa::Join<aod::DauTrackExtras, aod::DauTrackTPCPIDs>;
54+ using v0Candidates = soa::Join<aod::V0CollRefs, aod::V0Cores, aod::V0Extras>;
55+
5356struct LfTaskLambdaSpinCorr {
5457
5558 Service<o2::ccdb::BasicCCDBManager> ccdb;
@@ -375,6 +378,32 @@ struct LfTaskLambdaSpinCorr {
375378 return {lambdaTag, aLambdaTag, true }; // Valid candidate
376379 }
377380
381+ std::tuple<int , int , bool > getLambdaTagsDD (const auto & v0, const auto & collision)
382+ {
383+ auto postrack = v0.template posTrackExtra_as <dauTracks>();
384+ auto negtrack = v0.template negTrackExtra_as <dauTracks>();
385+
386+ int lambdaTag = 0 ;
387+ int aLambdaTag = 0 ;
388+
389+ if (isSelectedV0Daughter (v0, postrack, 0 ) && isSelectedV0Daughter (v0, negtrack, 1 )) {
390+ lambdaTag = 1 ;
391+ }
392+ if (isSelectedV0Daughter (v0, negtrack, 0 ) && isSelectedV0Daughter (v0, postrack, 1 )) {
393+ aLambdaTag = 1 ;
394+ }
395+
396+ if (!lambdaTag && !aLambdaTag) {
397+ return {0 , 0 , false }; // No valid tags
398+ }
399+
400+ if (!selectionV0 (collision, v0)) {
401+ return {0 , 0 , false }; // Fails selection
402+ }
403+
404+ return {lambdaTag, aLambdaTag, true }; // Valid candidate
405+ }
406+
378407 std::tuple<int , int , bool > getLambdaTagsMC (const auto & v0, const auto & collision)
379408 {
380409 auto postrack = v0.template posTrack_as <TrackMCRecTable>();
@@ -766,6 +795,340 @@ struct LfTaskLambdaSpinCorr {
766795 }
767796 PROCESS_SWITCH (LfTaskLambdaSpinCorr, processME, " Process data ME" , true );
768797
798+ void processDerivedData (soa::Join<aod::StraCollisions, aod::StraCents, aod::StraEvSels, aod::StraStamps>::iterator const & collision, v0Candidates const & V0s, dauTracks const &)
799+ {
800+ histos.fill (HIST (" hEvtSelInfo" ), 0.5 );
801+ if (rctCut.requireRCTFlagChecker && !rctChecker (collision)) {
802+ return ;
803+ }
804+ histos.fill (HIST (" hEvtSelInfo" ), 1.5 );
805+ if (!collision.sel8 ()) {
806+ return ;
807+ }
808+ histos.fill (HIST (" hEvtSelInfo" ), 2.5 );
809+ auto centrality = collision.centFT0C ();
810+ int occupancy = collision.trackOccupancyInTimeRange ();
811+ if (additionalEvSel && (!collision.selection_bit (aod::evsel::kNoSameBunchPileup ) || !collision.selection_bit (aod::evsel::kIsGoodZvtxFT0vsPV ))) {
812+ return ;
813+ }
814+ histos.fill (HIST (" hEvtSelInfo" ), 3.5 );
815+ if (additionalEvSel3 && (!collision.selection_bit (aod::evsel::kNoTimeFrameBorder ) || !collision.selection_bit (aod::evsel::kNoITSROFrameBorder ))) {
816+ return ;
817+ }
818+ histos.fill (HIST (" hEvtSelInfo" ), 4.5 );
819+ if (additionalEvSel4 && !collision.selection_bit (o2::aod::evsel::kNoCollInTimeRangeStandard )) {
820+ return ;
821+ }
822+ histos.fill (HIST (" hEvtSelInfo" ), 5.5 );
823+ if (additionalEvSel5 && !collision.selection_bit (o2::aod::evsel::kIsGoodITSLayersAll )) {
824+ return ;
825+ }
826+ histos.fill (HIST (" hEvtSelInfo" ), 6.5 );
827+ if (occupancy > cfgCutOccupancy) {
828+ return ;
829+ }
830+ histos.fill (HIST (" hEvtSelInfo" ), 7.5 );
831+ histos.fill (HIST (" hCentrality" ), centrality);
832+
833+ for (const auto & v0 : V0s) {
834+ auto [lambdaTag, aLambdaTag, isValid] = getLambdaTagsDD (v0, collision);
835+ if (!isValid) {
836+ continue ;
837+ }
838+
839+ if (lambdaTag && aLambdaTag) {
840+ continue ;
841+ }
842+
843+ if (lambdaTag) {
844+ proton = ROOT::Math::PxPyPzMVector (v0.pxpos (), v0.pypos (), v0.pzpos (), o2::constants::physics::MassProton);
845+ antiPion = ROOT::Math::PxPyPzMVector (v0.pxneg (), v0.pyneg (), v0.pzneg (), o2::constants::physics::MassPionCharged);
846+ lambda = proton + antiPion;
847+ }
848+ if (aLambdaTag) {
849+ antiProton = ROOT::Math::PxPyPzMVector (v0.pxneg (), v0.pyneg (), v0.pzneg (), o2::constants::physics::MassProton);
850+ pion = ROOT::Math::PxPyPzMVector (v0.pxpos (), v0.pypos (), v0.pzpos (), o2::constants::physics::MassPionCharged);
851+ antiLambda = antiProton + pion;
852+ }
853+
854+ if (lambdaTag && (lambda.M () < lbinIM || lambda.M () > hbinIM)) {
855+ continue ;
856+ }
857+ if (aLambdaTag && (antiLambda.M () < lbinIM || antiLambda.M () > hbinIM)) {
858+ continue ;
859+ }
860+
861+ // auto postrack1 = v0.template posTrackExtra_as<dauTracks>();
862+ // auto negtrack1 = v0.template negTrackExtra_as<dauTracks>();
863+
864+ // 2nd loop for combination of lambda lambda
865+ for (const auto & v02 : V0s) {
866+ if (v02.index () <= v0.index ()) {
867+ continue ;
868+ }
869+ auto [lambdaTag2, aLambdaTag2, isValid2] = getLambdaTagsDD (v02, collision);
870+ if (!isValid2) {
871+ continue ;
872+ }
873+ if (lambdaTag2 && aLambdaTag2) {
874+ continue ;
875+ }
876+ if (lambdaTag2) {
877+ proton2 = ROOT::Math::PxPyPzMVector (v02.pxpos (), v02.pypos (), v02.pzpos (), o2::constants::physics::MassProton);
878+ antiPion2 = ROOT::Math::PxPyPzMVector (v02.pxneg (), v02.pyneg (), v02.pzneg (), o2::constants::physics::MassPionCharged);
879+ lambda2 = proton2 + antiPion2;
880+ }
881+ if (aLambdaTag2) {
882+ antiProton2 = ROOT::Math::PxPyPzMVector (v02.pxneg (), v02.pyneg (), v02.pzneg (), o2::constants::physics::MassProton);
883+ pion2 = ROOT::Math::PxPyPzMVector (v02.pxpos (), v02.pypos (), v02.pzpos (), o2::constants::physics::MassPionCharged);
884+ antiLambda2 = antiProton2 + pion2;
885+ }
886+
887+ if (lambdaTag2 && (lambda2.M () < lbinIM || lambda2.M () > hbinIM)) {
888+ continue ;
889+ }
890+ if (aLambdaTag2 && (antiLambda2.M () < lbinIM || antiLambda2.M () > hbinIM)) {
891+ continue ;
892+ }
893+
894+ // auto postrack2 = v02.template posTrackExtra_as<dauTracks>();
895+ // auto negtrack2 = v02.template negTrackExtra_as<dauTracks>();
896+ if (v0.posTrackExtraId () == v02.posTrackExtraId () || v0.negTrackExtraId () == v02.negTrackExtraId ()) {
897+ continue ;
898+ }
899+
900+ if (lambdaTag && lambdaTag2) {
901+ fillHistograms (1 , 0 , 1 , 0 , lambda, lambda2, proton, proton2, centrality, 0 );
902+ }
903+ if (aLambdaTag && aLambdaTag2) {
904+ fillHistograms (0 , 1 , 0 , 1 , antiLambda, antiLambda2, antiProton, antiProton2, centrality, 0 );
905+ }
906+ if (lambdaTag && aLambdaTag2) {
907+ fillHistograms (1 , 0 , 0 , 1 , lambda, antiLambda2, proton, antiProton2, centrality, 0 );
908+ }
909+ if (aLambdaTag && lambdaTag2) {
910+ fillHistograms (0 , 1 , 1 , 0 , antiLambda, lambda2, antiProton, proton2, centrality, 0 );
911+ }
912+ }
913+ }
914+ }
915+ PROCESS_SWITCH (LfTaskLambdaSpinCorr, processDerivedData, " Process derived data" , true );
916+
917+ Preslice<v0Candidates> tracksPerCollisionV0Mixed = o2::aod::v0data::straCollisionId; // for derived data only
918+ void processDerivedDataMixed (soa::Join<aod::StraCollisions, aod::StraCents, aod::StraEvSels, aod::StraStamps> const & collisions, v0Candidates const & V0s, dauTracks const &)
919+
920+ {
921+
922+ for (auto & [collision1, collision2] : selfCombinations (colBinning, nMix, -1 , collisions, collisions)) {
923+ // LOGF(info, "Mixed event collisions: (%d, %d)", collision1.index(), collision2.index());
924+ if (rctCut.requireRCTFlagChecker && !rctChecker (collision1)) {
925+ continue ;
926+ }
927+ if (rctCut.requireRCTFlagChecker && !rctChecker (collision2)) {
928+ continue ;
929+ }
930+ int occupancy1 = collision1.trackOccupancyInTimeRange ();
931+ int occupancy2 = collision2.trackOccupancyInTimeRange ();
932+
933+ if (collision1.index () == collision2.index ()) {
934+ continue ;
935+ }
936+ if (!collision1.sel8 () || !collision2.sel8 ()) {
937+ continue ;
938+ }
939+ if (additionalEvSel && (!collision1.selection_bit (aod::evsel::kNoSameBunchPileup ) || !collision1.selection_bit (aod::evsel::kIsGoodZvtxFT0vsPV ))) {
940+ continue ;
941+ }
942+ if (occupancy1 > cfgCutOccupancy) {
943+ continue ;
944+ }
945+ if (additionalEvSel && (!collision2.selection_bit (aod::evsel::kNoSameBunchPileup ) || !collision2.selection_bit (aod::evsel::kIsGoodZvtxFT0vsPV ))) {
946+ continue ;
947+ }
948+ if (occupancy2 > cfgCutOccupancy) {
949+ continue ;
950+ }
951+ if (additionalEvSel3 && (!collision1.selection_bit (aod::evsel::kNoTimeFrameBorder ) || !collision1.selection_bit (aod::evsel::kNoITSROFrameBorder ))) {
952+ continue ;
953+ }
954+ if (additionalEvSel4 && !collision1.selection_bit (o2::aod::evsel::kNoCollInTimeRangeStandard )) {
955+ continue ;
956+ }
957+ if (mixingEvSel && additionalEvSel5 && !collision1.selection_bit (o2::aod::evsel::kIsGoodITSLayersAll )) {
958+ continue ;
959+ }
960+
961+ if (additionalEvSel3 && (!collision2.selection_bit (aod::evsel::kNoTimeFrameBorder ) || !collision2.selection_bit (aod::evsel::kNoITSROFrameBorder ))) {
962+ continue ;
963+ }
964+ if (additionalEvSel4 && !collision2.selection_bit (o2::aod::evsel::kNoCollInTimeRangeStandard )) {
965+ continue ;
966+ }
967+ if (mixingEvSel && additionalEvSel5 && !collision2.selection_bit (o2::aod::evsel::kIsGoodITSLayersAll )) {
968+ continue ;
969+ }
970+ auto centrality = collision1.centFT0C ();
971+ auto groupV01 = V0s.sliceBy (tracksPerCollisionV0Mixed, collision1.globalIndex ());
972+ auto groupV02 = V0s.sliceBy (tracksPerCollisionV0Mixed, collision1.globalIndex ());
973+ auto groupV03 = V0s.sliceBy (tracksPerCollisionV0Mixed, collision2.globalIndex ());
974+
975+ size_t rows = groupV03.size () + 20 ;
976+ size_t cols = groupV01.size () + 20 ;
977+ std::vector<std::vector<bool >> pairStatus (rows, std::vector<bool >(cols, false ));
978+ histos.fill (HIST (" hv0Mult" ), groupV01.size ());
979+ for (auto & [t1, t2] : soa::combinations (o2::soa::CombinationsFullIndexPolicy (groupV01, groupV02))) {
980+ bool pairfound = false ;
981+ if (t2.index () <= t1.index ()) {
982+ continue ;
983+ }
984+ if (t1.straCollisionId () != t2.straCollisionId ()) {
985+ continue ;
986+ }
987+
988+ auto [lambdaTag1, aLambdaTag1, isValid1] = getLambdaTagsDD (t1, collision1);
989+ auto [lambdaTag2, aLambdaTag2, isValid2] = getLambdaTagsDD (t2, collision1);
990+ if (!isValid1) {
991+ continue ;
992+ }
993+ if (!isValid2) {
994+ continue ;
995+ }
996+ if (lambdaTag1 && aLambdaTag1) {
997+ continue ;
998+ }
999+ if (lambdaTag2 && aLambdaTag2) {
1000+ continue ;
1001+ }
1002+ // auto postrack1 = t1.template posTrackExtra_as<dauTracks>();
1003+ // auto negtrack1 = t1.template negTrackExtra_as<dauTracks>();
1004+ // auto postrack2 = t2.template posTrackExtra_as<dauTracks>();
1005+ // auto negtrack2 = t2.template negTrackExtra_as<dauTracks>();
1006+ if (t1.posTrackExtraId () == t2.posTrackExtraId () || t1.negTrackExtraId () == t2.negTrackExtraId ()) {
1007+ continue ;
1008+ }
1009+ // auto samePairSumPt = t1.pt() + t2.pt();
1010+ // auto samePairR = TMath::Sqrt(TMath::Power(t1.phi() - t2.phi(), 2.0) + TMath::Power(t1.eta() - t2.eta(), 2.0));
1011+
1012+ double deltaPhiSame = RecoDecay::constrainAngle (t1.phi () - t2.phi (), 0.0 );
1013+ auto samePairR = TMath::Sqrt (TMath::Power (deltaPhiSame, 2.0 ) + TMath::Power (t1.eta () - t2.eta (), 2.0 ));
1014+
1015+ if (lambdaTag1) {
1016+ proton0 = ROOT::Math::PxPyPzMVector (t1.pxpos (), t1.pypos (), t1.pzpos (), o2::constants::physics::MassProton);
1017+ antiPion0 = ROOT::Math::PxPyPzMVector (t1.pxneg (), t1.pyneg (), t1.pzneg (), o2::constants::physics::MassPionCharged);
1018+ lambda0 = proton0 + antiPion0;
1019+ }
1020+ if (aLambdaTag1) {
1021+ antiProton0 = ROOT::Math::PxPyPzMVector (t1.pxneg (), t1.pyneg (), t1.pzneg (), o2::constants::physics::MassProton);
1022+ pion0 = ROOT::Math::PxPyPzMVector (t1.pxpos (), t1.pypos (), t1.pzpos (), o2::constants::physics::MassPionCharged);
1023+ antiLambda0 = antiProton0 + pion0;
1024+ }
1025+ if (lambdaTag1 && (lambda0.M () < lbinIM || lambda0.M () > hbinIM)) {
1026+ continue ;
1027+ }
1028+ if (aLambdaTag1 && (antiLambda0.M () < lbinIM || antiLambda0.M () > hbinIM)) {
1029+ continue ;
1030+ }
1031+ if (lambdaTag2) {
1032+ proton = ROOT::Math::PxPyPzMVector (t2.pxpos (), t2.pypos (), t2.pzpos (), o2::constants::physics::MassProton);
1033+ antiPion = ROOT::Math::PxPyPzMVector (t2.pxneg (), t2.pyneg (), t2.pzneg (), o2::constants::physics::MassPionCharged);
1034+ lambda = proton + antiPion;
1035+ }
1036+ if (aLambdaTag2) {
1037+ antiProton = ROOT::Math::PxPyPzMVector (t2.pxneg (), t2.pyneg (), t2.pzneg (), o2::constants::physics::MassProton);
1038+ pion = ROOT::Math::PxPyPzMVector (t2.pxpos (), t2.pypos (), t2.pzpos (), o2::constants::physics::MassPionCharged);
1039+ antiLambda = antiProton + pion;
1040+ }
1041+ if (lambdaTag2 && (lambda.M () < lbinIM || lambda.M () > hbinIM)) {
1042+ continue ;
1043+ }
1044+ if (aLambdaTag2 && (antiLambda.M () < lbinIM || antiLambda.M () > hbinIM)) {
1045+ continue ;
1046+ }
1047+
1048+ for (const auto & t3 : groupV03) {
1049+ if (pairStatus[t3.index ()][t2.index ()]) {
1050+ continue ;
1051+ }
1052+ if (t1.straCollisionId () == t3.straCollisionId ()) {
1053+ continue ;
1054+ }
1055+ auto [lambdaTag3, aLambdaTag3, isValid3] = getLambdaTagsDD (t3, collision2);
1056+ if (!isValid3) {
1057+ continue ;
1058+ }
1059+ if (lambdaTag3 && aLambdaTag3) {
1060+ continue ;
1061+ }
1062+ if (lambdaTag1 != lambdaTag3 || aLambdaTag1 != aLambdaTag3) {
1063+ continue ;
1064+ }
1065+
1066+ if (lambdaTag3) {
1067+ proton2 = ROOT::Math::PxPyPzMVector (t3.pxpos (), t3.pypos (), t3.pzpos (), o2::constants::physics::MassProton);
1068+ antiPion2 = ROOT::Math::PxPyPzMVector (t3.pxneg (), t3.pyneg (), t3.pzneg (), o2::constants::physics::MassPionCharged);
1069+ lambda2 = proton2 + antiPion2;
1070+ }
1071+ if (aLambdaTag3) {
1072+ antiProton2 = ROOT::Math::PxPyPzMVector (t3.pxneg (), t3.pyneg (), t3.pzneg (), o2::constants::physics::MassProton);
1073+ pion2 = ROOT::Math::PxPyPzMVector (t3.pxpos (), t3.pypos (), t3.pzpos (), o2::constants::physics::MassPionCharged);
1074+ antiLambda2 = antiProton2 + pion2;
1075+ }
1076+ if (lambdaTag3 && (lambda2.M () < lbinIM || lambda2.M () > hbinIM)) {
1077+ continue ;
1078+ }
1079+
1080+ if (aLambdaTag3 && (antiLambda2.M () < lbinIM || antiLambda2.M () > hbinIM)) {
1081+ continue ;
1082+ }
1083+
1084+ double deltaPhiMix = RecoDecay::constrainAngle (t3.phi () - t2.phi (), 0.0 );
1085+ auto mixPairR = TMath::Sqrt (TMath::Power (deltaPhiMix, 2.0 ) + TMath::Power (t3.eta () - t2.eta (), 2.0 ));
1086+
1087+ auto etaDiff = t1.eta () - t3.eta ();
1088+ auto phiDiff = RecoDecay::constrainAngle (t1.phi () - t3.phi (), 0.0 );
1089+
1090+ histos.fill (HIST (" hPtDiff" ), t1.pt () - t3.pt ());
1091+ histos.fill (HIST (" hPhiDiff" ), phiDiff);
1092+ histos.fill (HIST (" hRDiff" ), etaDiff);
1093+
1094+ if (mixingCombination == 0 && std::abs (t1.pt () - t3.pt ()) > ptMix) {
1095+ continue ;
1096+ }
1097+ if (mixingCombination == 0 && t1.eta () * t3.eta () > 0 && std::abs (etaDiff) > etaMix) {
1098+ continue ;
1099+ }
1100+ if (mixingCombination == 0 && phiDiff > phiMix) {
1101+ continue ;
1102+ }
1103+ if (mixingCombination == 1 && std::abs (t1.pt () - t3.pt ()) > ptMix) {
1104+ continue ;
1105+ }
1106+ if (mixingCombination == 1 && std::abs (mixPairR - samePairR) > etaMix) {
1107+ continue ;
1108+ }
1109+ if (lambdaTag2 && lambdaTag3) {
1110+ fillHistograms (1 , 0 , 1 , 0 , lambda, lambda2, proton, proton2, centrality, 2 );
1111+ } else if (aLambdaTag2 && aLambdaTag3) {
1112+ fillHistograms (0 , 1 , 0 , 1 , antiLambda, antiLambda2, antiProton, antiProton2, centrality, 2 );
1113+ } else if (lambdaTag2 && aLambdaTag3) {
1114+ fillHistograms (1 , 0 , 0 , 1 , lambda, antiLambda2, proton, antiProton2, centrality, 2 );
1115+ } else if (aLambdaTag2 && lambdaTag3) {
1116+ fillHistograms (0 , 1 , 1 , 0 , antiLambda, lambda2, antiProton, proton2, centrality, 2 );
1117+ } else {
1118+ continue ;
1119+ }
1120+ pairfound = true ;
1121+ pairStatus[t3.index ()][t2.index ()] = true ;
1122+ if (pairfound) {
1123+ break ;
1124+ }
1125+ }
1126+ }
1127+ }
1128+ }
1129+
1130+ PROCESS_SWITCH (LfTaskLambdaSpinCorr, processDerivedDataMixed, " Process mixed derived data" , true );
1131+
7691132 using CollisionMCRecTableCentFT0C = soa::Join<aod::Collisions, aod::CentFT0Cs, aod::EvSels>;
7701133 using TrackMCRecTable = soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA, aod::TrackSelection, aod::pidTPCFullPi, aod::pidTPCFullPr>;
7711134 using V0TrackCandidatesMC = soa::Join<aod::V0Datas, aod::McV0Labels>;
0 commit comments