|
57 | 57 | #include <array> |
58 | 58 | #include <cmath> |
59 | 59 | #include <cstdlib> |
| 60 | +#include <deque> |
| 61 | +#include <iostream> |
| 62 | +#include <iterator> |
| 63 | +#include <set> // <<< CHANGED: for dedup sets |
60 | 64 | #include <string> |
| 65 | +#include <type_traits> |
| 66 | +#include <unordered_map> // <<< CHANGED: for seenMap |
| 67 | +#include <utility> |
61 | 68 | #include <vector> |
62 | 69 |
|
63 | 70 | using namespace o2; |
@@ -88,6 +95,11 @@ struct lambdapolsp { |
88 | 95 | Configurable<int> sys{"sys", 1, "flag to select systematic source"}; |
89 | 96 | Configurable<bool> dosystematic{"dosystematic", false, "flag to perform systematic study"}; |
90 | 97 | Configurable<bool> needetaaxis{"needetaaxis", false, "flag to use last axis"}; |
| 98 | + struct : ConfigurableGroup { |
| 99 | + Configurable<bool> doRandomPsi{"doRandomPsi", true, "randomize psi"}; |
| 100 | + Configurable<bool> doRandomPsiAC{"doRandomPsiAC", true, "randomize psiAC"}; |
| 101 | + Configurable<bool> doRandomPhi{"doRandomPhi", true, "randomize phi"}; |
| 102 | + } randGrp; |
91 | 103 | // events |
92 | 104 | Configurable<float> cfgCutVertex{"cfgCutVertex", 10.0f, "Accepted z-vertex range"}; |
93 | 105 | Configurable<float> cfgCutCentralityMax{"cfgCutCentralityMax", 50.0f, "Accepted maximum Centrality"}; |
@@ -483,6 +495,7 @@ struct lambdapolsp { |
483 | 495 | } |
484 | 496 |
|
485 | 497 | // check TPC tracking properties |
| 498 | + |
486 | 499 | if (posTrackExtra.tpcNClsCrossedRows() < cfgTPCcluster || negTrackExtra.tpcNClsCrossedRows() < cfgTPCcluster) { |
487 | 500 | return false; |
488 | 501 | } |
@@ -584,10 +597,14 @@ struct lambdapolsp { |
584 | 597 | double psiZDCC, double psiZDCA, double psiZDC, double centrality, |
585 | 598 | double candmass, double candpt, float desbinvalue, double acvalue) |
586 | 599 | { |
| 600 | + TRandom3 randPhi(0); |
587 | 601 |
|
588 | 602 | ROOT::Math::Boost boost{particle.BoostToCM()}; |
589 | 603 | auto fourVecDauCM = boost(daughter); |
590 | 604 | auto phiangle = TMath::ATan2(fourVecDauCM.Py(), fourVecDauCM.Px()); |
| 605 | + if (randGrp.doRandomPhi) { |
| 606 | + phiangle = randPhi.Uniform(0, 2 * TMath::Pi()); |
| 607 | + } |
591 | 608 | auto phiminuspsiC = GetPhiInRange(phiangle - psiZDCC); |
592 | 609 | auto phiminuspsiA = GetPhiInRange(phiangle - psiZDCA); |
593 | 610 | auto phiminuspsi = GetPhiInRange(phiangle - psiZDC); |
@@ -1338,6 +1355,7 @@ struct lambdapolsp { |
1338 | 1355 |
|
1339 | 1356 | void processDerivedDataMixed(soa::Join<aod::StraCollisions, aod::StraCents, aod::StraEvSels, aod::StraStamps, aod::StraZDCSP> const& collisions, v0Candidates const& V0s, dauTracks const&) |
1340 | 1357 | { |
| 1358 | + TRandom3 randGen(0); |
1341 | 1359 |
|
1342 | 1360 | for (auto& [collision1, collision2] : selfCombinations(colBinning, meGrp.nMix, -1, collisions, collisions)) { |
1343 | 1361 |
|
@@ -1413,6 +1431,17 @@ struct lambdapolsp { |
1413 | 1431 |
|
1414 | 1432 | histos.fill(HIST("hCentrality"), centrality); |
1415 | 1433 |
|
| 1434 | + if (randGrp.doRandomPsi) { |
| 1435 | + psiZDC = randGen.Uniform(0, 2 * TMath::Pi()); |
| 1436 | + } |
| 1437 | + if (randGrp.doRandomPsiAC) { |
| 1438 | + psiZDCA = randGen.Uniform(0, 2 * TMath::Pi()); |
| 1439 | + psiZDCC = randGen.Uniform(0, 2 * TMath::Pi()); |
| 1440 | + } |
| 1441 | + |
| 1442 | + histos.fill(HIST("hpRes"), centrality, (TMath::Cos(GetPhiInRange(psiZDCA - psiZDCC)))); |
| 1443 | + histos.fill(HIST("hpResSin"), centrality, (TMath::Sin(GetPhiInRange(psiZDCA - psiZDCC)))); |
| 1444 | + |
1416 | 1445 | for (const auto& v0 : groupV0) { |
1417 | 1446 |
|
1418 | 1447 | bool LambdaTag = isCompatible(v0, 0); |
@@ -1457,6 +1486,149 @@ struct lambdapolsp { |
1457 | 1486 | } |
1458 | 1487 | } |
1459 | 1488 | PROCESS_SWITCH(lambdapolsp, processDerivedDataMixed, "Process mixed event using derived data", false); |
| 1489 | + |
| 1490 | + void processDerivedDataMixedFIFO(soa::Join<aod::StraCollisions, aod::StraCents, aod::StraEvSels, aod::StraStamps, aod::StraZDCSP> const& collisions, v0Candidates const& V0s, dauTracks const&) |
| 1491 | + { |
| 1492 | + |
| 1493 | + auto nBins = colBinning.getAllBinsCount(); |
| 1494 | + std::vector<std::deque<int>> eventPools(nBins); // Pool per bin holding just event indices |
| 1495 | + |
| 1496 | + for (auto& collision1 : collisions) { |
| 1497 | + |
| 1498 | + if (!collision1.sel8()) { |
| 1499 | + continue; |
| 1500 | + } |
| 1501 | + if (!collision1.triggereventsp()) { // provided by StraZDCSP |
| 1502 | + continue; |
| 1503 | + } |
| 1504 | + if (rctCut.requireRCTFlagChecker && !rctChecker(collision1)) { |
| 1505 | + continue; |
| 1506 | + } |
| 1507 | + |
| 1508 | + if (additionalEvSel && (!collision1.selection_bit(aod::evsel::kNoSameBunchPileup) || !collision1.selection_bit(aod::evsel::kIsGoodZvtxFT0vsPV))) { |
| 1509 | + continue; |
| 1510 | + } |
| 1511 | + if (additionalEvSel2 && (collision1.trackOccupancyInTimeRange() > cfgMaxOccupancy || collision1.trackOccupancyInTimeRange() < cfgMinOccupancy)) { |
| 1512 | + continue; |
| 1513 | + } |
| 1514 | + if (additionalEvSel3 && (!collision1.selection_bit(aod::evsel::kNoTimeFrameBorder) || !collision1.selection_bit(aod::evsel::kNoITSROFrameBorder))) { |
| 1515 | + continue; |
| 1516 | + } |
| 1517 | + if (additionalEvSel4 && !collision1.selection_bit(o2::aod::evsel::kIsGoodITSLayersAll)) { |
| 1518 | + continue; |
| 1519 | + } |
| 1520 | + |
| 1521 | + int bin = colBinning.getBin(std::make_tuple(collision1.posZ(), collision1.centFT0C())); |
| 1522 | + auto groupV0_evt1 = V0s.sliceBy(tracksPerCollisionV0Mixed, collision1.index()); |
| 1523 | + float centrality = collision1.centFT0C(); |
| 1524 | + auto qxZDCA = collision1.qxZDCA(); |
| 1525 | + auto qxZDCC = collision1.qxZDCC(); |
| 1526 | + auto qyZDCA = collision1.qyZDCA(); |
| 1527 | + auto qyZDCC = collision1.qyZDCC(); |
| 1528 | + auto psiZDCC = collision1.psiZDCC(); |
| 1529 | + auto psiZDCA = collision1.psiZDCA(); |
| 1530 | + double modqxZDCA; |
| 1531 | + double modqyZDCA; |
| 1532 | + double modqxZDCC; |
| 1533 | + double modqyZDCC; |
| 1534 | + |
| 1535 | + if (bin < 0) |
| 1536 | + continue; |
| 1537 | + modqxZDCA = TMath::Sqrt((qxZDCA * qxZDCA) + (qyZDCA * qyZDCA)) * TMath::Cos(psiZDCA); |
| 1538 | + modqyZDCA = TMath::Sqrt((qxZDCA * qxZDCA) + (qyZDCA * qyZDCA)) * TMath::Sin(psiZDCA); |
| 1539 | + modqxZDCC = TMath::Sqrt((qxZDCC * qxZDCC) + (qyZDCC * qyZDCC)) * TMath::Cos(psiZDCC); |
| 1540 | + modqyZDCC = TMath::Sqrt((qxZDCC * qxZDCC) + (qyZDCC * qyZDCC)) * TMath::Sin(psiZDCC); |
| 1541 | + |
| 1542 | + auto psiZDC = TMath::ATan2((modqyZDCC - modqyZDCA), (modqxZDCC - modqxZDCA)); // full event plane from collision |
| 1543 | + |
| 1544 | + histos.fill(HIST("hCentrality"), centrality); |
| 1545 | + histos.fill(HIST("hpRes"), centrality, (TMath::Cos(GetPhiInRange(psiZDCA - psiZDCC)))); |
| 1546 | + |
| 1547 | + // For deduplication of (v0_evt1, v0_evt2) pairs per mixed event |
| 1548 | + std::unordered_map<int, std::set<std::pair<int, int>>> seenMap; |
| 1549 | + |
| 1550 | + // Loop over Λ candidates in collision1 (keep psi from here) |
| 1551 | + |
| 1552 | + for (auto& v0_evt1 : groupV0_evt1) { |
| 1553 | + if (!SelectionV0(collision1, v0_evt1)) |
| 1554 | + continue; |
| 1555 | + bool LambdaTag1 = isCompatible(v0_evt1, 0); |
| 1556 | + bool aLambdaTag1 = isCompatible(v0_evt1, 1); |
| 1557 | + ROOT::Math::PxPyPzMVector proton1, pion1, antiproton1, antipion1, LambdaTag1dummy, AntiLambdaTag1dummy; |
| 1558 | + if (LambdaTag1) { |
| 1559 | + proton1 = {v0_evt1.pxpos(), v0_evt1.pypos(), v0_evt1.pzpos(), massPr}; |
| 1560 | + antipion1 = {v0_evt1.pxneg(), v0_evt1.pyneg(), v0_evt1.pzneg(), massPi}; |
| 1561 | + LambdaTag1dummy = proton1 + antipion1; |
| 1562 | + } |
| 1563 | + if (aLambdaTag1) { |
| 1564 | + antiproton1 = {v0_evt1.pxneg(), v0_evt1.pyneg(), v0_evt1.pzneg(), massPr}; |
| 1565 | + pion1 = {v0_evt1.pxpos(), v0_evt1.pypos(), v0_evt1.pzpos(), massPi}; |
| 1566 | + AntiLambdaTag1dummy = antiproton1 + pion1; |
| 1567 | + } |
| 1568 | + if (shouldReject(LambdaTag1, aLambdaTag1, LambdaTag1dummy, AntiLambdaTag1dummy)) { |
| 1569 | + continue; |
| 1570 | + } |
| 1571 | + if (TMath::Abs(v0_evt1.eta()) > 0.8) |
| 1572 | + continue; |
| 1573 | + |
| 1574 | + // Loop over all FIFO pool events (mixed events) for this centrality bin |
| 1575 | + int nMixedEvents = 0; |
| 1576 | + for (auto it = eventPools[bin].rbegin(); it != eventPools[bin].rend() && nMixedEvents < meGrp.nMix; ++it, ++nMixedEvents) { |
| 1577 | + int collision2idx = *it; |
| 1578 | + if (collision1.index() == collision2idx) |
| 1579 | + continue; |
| 1580 | + auto groupV0_evt2 = V0s.sliceBy(tracksPerCollisionV0Mixed, collision2idx); |
| 1581 | + |
| 1582 | + // Now loop over Λ candidates in collision2 to randomize proton phi* (randomize decay angle) |
| 1583 | + for (auto& v0_evt2 : groupV0_evt2) { |
| 1584 | + if (!SelectionV0(collision1, v0_evt2)) |
| 1585 | + continue; |
| 1586 | + bool LambdaTag2 = isCompatible(v0_evt2, 0); |
| 1587 | + bool aLambdaTag2 = isCompatible(v0_evt2, 1); |
| 1588 | + if (!LambdaTag2 && !aLambdaTag2) |
| 1589 | + continue; |
| 1590 | + |
| 1591 | + // Deduplicate (v0_evt1, v0_evt2) pairs per collision2idx |
| 1592 | + auto key = std::make_pair(v0_evt1.index(), v0_evt2.index()); |
| 1593 | + if (!seenMap[collision2idx].insert(key).second) |
| 1594 | + continue; |
| 1595 | + |
| 1596 | + ROOT::Math::PxPyPzMVector proton_mix, antiproton_mix, pion_mix, antipion_mix, LambdaTag2dummy, AntiLambdaTag2dummy; |
| 1597 | + if (LambdaTag2) { |
| 1598 | + proton_mix = {v0_evt2.pxpos(), v0_evt2.pypos(), v0_evt2.pzpos(), massPr}; |
| 1599 | + antipion_mix = {v0_evt2.pxneg(), v0_evt2.pyneg(), v0_evt2.pzneg(), massPi}; |
| 1600 | + LambdaTag2dummy = proton_mix + antipion_mix; |
| 1601 | + } |
| 1602 | + if (aLambdaTag2) { |
| 1603 | + antiproton_mix = {v0_evt2.pxneg(), v0_evt2.pyneg(), v0_evt2.pzneg(), massPr}; |
| 1604 | + pion_mix = {v0_evt2.pxpos(), v0_evt2.pypos(), v0_evt2.pzpos(), massPi}; |
| 1605 | + AntiLambdaTag2dummy = antiproton_mix + pion_mix; |
| 1606 | + } |
| 1607 | + if (shouldReject(LambdaTag2, aLambdaTag2, LambdaTag2dummy, AntiLambdaTag2dummy)) { |
| 1608 | + continue; |
| 1609 | + } |
| 1610 | + if (TMath::Abs(v0_evt2.eta()) > 0.8) |
| 1611 | + continue; |
| 1612 | + if (LambdaTag1) { |
| 1613 | + double acvalue = 1.0; |
| 1614 | + fillHistograms(1, 0, LambdaTag1dummy, proton_mix, psiZDCC, psiZDCA, psiZDC, centrality, v0_evt1.mLambda(), v0_evt1.pt(), v0_evt1.eta(), acvalue); |
| 1615 | + } |
| 1616 | + if (aLambdaTag1) { |
| 1617 | + double acvalue = 1.0; |
| 1618 | + fillHistograms(0, 1, AntiLambdaTag1dummy, antiproton_mix, psiZDCC, psiZDCA, psiZDC, centrality, v0_evt1.mAntiLambda(), v0_evt1.pt(), v0_evt1.eta(), acvalue); |
| 1619 | + } |
| 1620 | + } |
| 1621 | + } |
| 1622 | + } |
| 1623 | + // After processing all mixes, add current event V0s to pool for future mixing |
| 1624 | + eventPools[bin].push_back(collision1.index()); |
| 1625 | + // Keep only N last events in FIFO queue |
| 1626 | + if (static_cast<int>(eventPools[bin].size()) > meGrp.nMix) { |
| 1627 | + eventPools[bin].pop_front(); |
| 1628 | + } |
| 1629 | + } |
| 1630 | + } |
| 1631 | + PROCESS_SWITCH(lambdapolsp, processDerivedDataMixedFIFO, "Process mixed event using derived data with FIFO method", false); |
1460 | 1632 | }; |
1461 | 1633 | WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) |
1462 | 1634 | { |
|
0 commit comments