|
| 1 | +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. |
| 2 | +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. |
| 3 | +// All rights not expressly granted are reserved. |
| 4 | +// |
| 5 | +// This software is distributed under the terms of the GNU General Public |
| 6 | +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". |
| 7 | +// |
| 8 | +// In applying this license CERN does not waive the privileges and immunities |
| 9 | +// granted to it by virtue of its status as an Intergovernmental Organization |
| 10 | +// or submit itself to any jurisdiction. |
| 11 | +/// |
| 12 | +/// \brief Task for analysis of rho' in UPCs using UD tables (from SG producer). |
| 13 | +/// \author Cesar Ramirez, cesar.ramirez@cern.ch |
| 14 | + |
| 15 | +#include <string> // Para std::string |
| 16 | +#include <vector> // Para std::vector |
| 17 | + |
| 18 | +#include "Framework/AnalysisTask.h" |
| 19 | +#include "Framework/AnalysisDataModel.h" |
| 20 | +#include "Framework/runDataProcessing.h" |
| 21 | + |
| 22 | +#include "Math/Vector4D.h" // similiar to TLorentzVector (which is now legacy apparently) |
| 23 | +#include "random" |
| 24 | + |
| 25 | +#include "Common/DataModel/PIDResponse.h" |
| 26 | + |
| 27 | +#include "PWGUD/DataModel/UDTables.h" |
| 28 | +#include "PWGUD/Core/UPCTauCentralBarrelHelperRL.h" |
| 29 | + |
| 30 | +using namespace o2; |
| 31 | +using namespace o2::framework; |
| 32 | +using namespace o2::framework::expressions; |
| 33 | + |
| 34 | +using FullUDSgCollision = soa::Join<aod::UDCollisions, aod::UDCollisionsSels, aod::UDZdcsReduced, aod::SGCollisions>::iterator; |
| 35 | +using FullUDTracks = soa::Join<aod::UDTracks, aod::UDTracksExtra, aod::UDTracksDCA, aod::UDTracksPID, aod::UDTracksFlags>; |
| 36 | + |
| 37 | +namespace o2::aod |
| 38 | +{ |
| 39 | +namespace fourpi |
| 40 | +{ |
| 41 | + |
| 42 | +// for event |
| 43 | +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); |
| 44 | + |
| 45 | +// for Rhos |
| 46 | +DECLARE_SOA_COLUMN(M, m, double); |
| 47 | +DECLARE_SOA_COLUMN(Pt, pt, double); |
| 48 | +DECLARE_SOA_COLUMN(Eta, eta, double); |
| 49 | +DECLARE_SOA_COLUMN(Phi, phi, double); |
| 50 | + |
| 51 | +// for vertex |
| 52 | +DECLARE_SOA_COLUMN(PosX, posX, double); |
| 53 | +DECLARE_SOA_COLUMN(PosY, posY, double); |
| 54 | +DECLARE_SOA_COLUMN(PosZ, posZ, double); |
| 55 | + |
| 56 | +// for other |
| 57 | +DECLARE_SOA_COLUMN(TotalCharge, totalCharge, int); |
| 58 | + |
| 59 | +// info Detec |
| 60 | +DECLARE_SOA_COLUMN(TotalFT0AmplitudeA, totalFT0AmplitudeA, float); |
| 61 | +DECLARE_SOA_COLUMN(TotalFT0AmplitudeC, totalFT0AmplitudeC, float); |
| 62 | +DECLARE_SOA_COLUMN(TotalFV0AmplitudeA, totalFV0AmplitudeA, float); |
| 63 | +DECLARE_SOA_COLUMN(TotalFDDAmplitudeA, totalFDDAmplitudeA, float); |
| 64 | +DECLARE_SOA_COLUMN(TotalFDDAmplitudeC, totalFDDAmplitudeC, float); |
| 65 | +DECLARE_SOA_COLUMN(TimeFT0A, timeFT0A, float); |
| 66 | +DECLARE_SOA_COLUMN(TimeFT0C, timeFT0C, float); |
| 67 | +DECLARE_SOA_COLUMN(TimeFV0A, timeFV0A, float); |
| 68 | +DECLARE_SOA_COLUMN(TimeFDDA, timeFDDA, float); |
| 69 | +DECLARE_SOA_COLUMN(TimeFDDC, timeFDDC, float); |
| 70 | + |
| 71 | +// for pion tracks |
| 72 | +// DECLARE_SOA_COLUMN(TrackSign, trackSign, std::vector<int>); |
| 73 | +// DECLARE_SOA_COLUMN(TrackM, trackM, std::vector<double>); |
| 74 | +// DECLARE_SOA_COLUMN(TrackPt, trackPt, std::vector<double>); |
| 75 | +// DECLARE_SOA_COLUMN(TrackEta, trackEta, std::vector<double>); |
| 76 | +// DECLARE_SOA_COLUMN(TrackPhi, trackPhi, std::vector<double>); |
| 77 | + |
| 78 | +} // namespace fourpi |
| 79 | +DECLARE_SOA_TABLE(SYSTEMTREE, "AOD", "SystemTree", fourpi::RunNumber, fourpi::M, fourpi::Pt, fourpi::Eta, fourpi::Phi, |
| 80 | + fourpi::PosX, fourpi::PosY, fourpi::PosZ, fourpi::TotalCharge, fourpi::TotalFT0AmplitudeA, fourpi::TotalFT0AmplitudeC, fourpi::TotalFV0AmplitudeA, |
| 81 | + fourpi::TotalFDDAmplitudeA, fourpi::TotalFDDAmplitudeC, fourpi::TimeFT0A, fourpi::TimeFT0C, fourpi::TimeFV0A, fourpi::TimeFDDA, fourpi::TimeFDDC); |
| 82 | +} // namespace o2::aod |
| 83 | + |
| 84 | +struct upcRhoPrimeAnalysis { |
| 85 | + Produces<aod::SYSTEMTREE> systemTree; |
| 86 | + |
| 87 | + double PcEtaCut = 0.9; // physics coordination recommendation |
| 88 | + |
| 89 | + Configurable<bool> specifyGapSide{"specifyGapSide", true, "specify gap side for SG/DG produced data"}; |
| 90 | + Configurable<int> gapSide{"gapSide", 2, "gap side for SG produced data"}; |
| 91 | + Configurable<bool> requireTof{"requireTof", false, "require TOF signal"}; |
| 92 | + |
| 93 | + Configurable<double> collisionsPosZMaxCut{"collisionsPosZMaxCut", 10.0, "max Z position cut on collisions"}; |
| 94 | + Configurable<double> ZNcommonEnergyCut{"ZNcommonEnergyCut", 0.0, "ZN common energy cut"}; |
| 95 | + Configurable<double> ZNtimeCut{"ZNtimeCut", 2.0, "ZN time cut"}; |
| 96 | + |
| 97 | + Configurable<double> tracksTpcNSigmaPiCut{"tracksTpcNSigmaPiCut", 3.0, "TPC nSigma pion cut"}; |
| 98 | + Configurable<double> tracksDcaMaxCut{"tracksDcaMaxCut", 1.0, "max DCA cut on tracks"}; |
| 99 | + |
| 100 | + Configurable<double> systemMassMinCut{"systemMassMinCut", 0.5, "min M cut for reco system"}; |
| 101 | + Configurable<double> systemMassMaxCut{"systemMassMaxCut", 1.2, "max M cut for reco system"}; |
| 102 | + Configurable<double> systemPtCut{"systemPtMaxCut", 0.1, "max pT cut for reco system"}; |
| 103 | + Configurable<double> systemYCut{"systemYCut", 0.9, "rapiditiy cut for reco system"}; |
| 104 | + |
| 105 | + ConfigurableAxis mAxis{"mAxis", {1000, 0.0, 10.0}, "m (GeV/#it{c}^{2})"}; |
| 106 | + ConfigurableAxis mCutAxis{"mCutAxis", {70, 0.5, 1.2}, "m (GeV/#it{c}^{2})"}; |
| 107 | + ConfigurableAxis ptAxis{"ptAxis", {1000, 0.0, 10.0}, "p_{T} (GeV/#it{c})"}; |
| 108 | + ConfigurableAxis ptCutAxis{"ptCutAxis", {300, 0.0, 0.3}, "p_{T} (GeV/#it{c})"}; |
| 109 | + ConfigurableAxis pt2Axis{"pt2Axis", {300, 0.0, 0.09}, "p_{T}^{2} (GeV^{2}/#it{c}^{2})"}; |
| 110 | + ConfigurableAxis etaAxis{"etaAxis", {180, -0.9, 0.9}, "#eta"}; |
| 111 | + ConfigurableAxis yAxis{"yAxis", {180, -0.9, 0.9}, "y"}; |
| 112 | + ConfigurableAxis phiAxis{"phiAxis", {180, 0.0, o2::constants::math::TwoPI}, "#phi"}; |
| 113 | + ConfigurableAxis phiAsymmAxis{"phiAsymmAxis", {182, -o2::constants::math::PI, o2::constants::math::PI}, "#phi"}; |
| 114 | + ConfigurableAxis momentumFromPhiAxis{"momentumFromPhiAxis", {400, -0.1, 0.1}, "p (GeV/#it{c})"}; |
| 115 | + ConfigurableAxis ptQuantileAxis{"ptQuantileAxis", {0, 0.0181689, 0.0263408, 0.0330488, 0.0390369, 0.045058, 0.0512604, 0.0582598, 0.066986, 0.0788085, 0.1}, "p_{T} (GeV/#it{c})"}; |
| 116 | + |
| 117 | + HistogramRegistry registry{"registry", {}, OutputObjHandlingPolicy::AnalysisObject}; |
| 118 | + |
| 119 | + void init(o2::framework::InitContext&) |
| 120 | + { |
| 121 | + // selection counter |
| 122 | + std::vector<std::string> selectionCounterLabels = {"all tracks", "PV contributor", "ITS + TPC hit", "TOF requirement", "DCA cut", "#eta cut", "2D TPC n#sigma_{#pi} cut"}; |
| 123 | + |
| 124 | + // 4PI SYSTEM |
| 125 | + // registry.add("4pi/hM", ";m (GeV/#it{c}^{2});counts", kTH1D, {mAxis}); |
| 126 | + // registry.add("4pi/hPt", ";p_{T} (GeV/#it{c});counts", kTH1D, {ptAxis}); |
| 127 | + // registry.add("4pi/hEta", ";Eta (1);counts", kTH1D, {etaAxis}); |
| 128 | + // registry.add("4pi/hPhi", ";Phi ();counts", kTH1D, {phiAxis}); |
| 129 | + } |
| 130 | + |
| 131 | + template <typename C> |
| 132 | + bool collisionPassesCuts(const C& collision) // collision cuts |
| 133 | + { |
| 134 | + if (std::abs(collision.posZ()) > collisionsPosZMaxCut) |
| 135 | + return false; |
| 136 | + if (specifyGapSide && collision.gapSide() != gapSide) |
| 137 | + return false; |
| 138 | + return true; |
| 139 | + } |
| 140 | + |
| 141 | + template <typename T> |
| 142 | + bool trackPassesCuts(const T& track) // track cuts (PID done separately) |
| 143 | + { |
| 144 | + if (!track.isPVContributor()) |
| 145 | + return false; |
| 146 | + if (!track.hasITS() || !track.hasTPC()) |
| 147 | + return false; |
| 148 | + if (requireTof && !track.hasTOF()) |
| 149 | + return false; |
| 150 | + if (std::abs(track.dcaZ()) > tracksDcaMaxCut || std::abs(track.dcaXY()) > (0.0182 + 0.0350 / std::pow(track.pt(), 1.01))) // Run 2 dynamic DCA cut |
| 151 | + return false; |
| 152 | + if (std::abs(eta(track.px(), track.py(), track.pz())) > PcEtaCut) |
| 153 | + return false; |
| 154 | + return true; |
| 155 | + } |
| 156 | + |
| 157 | + template <typename T> |
| 158 | + bool tracksPassPiPID(const T& cutTracks) // n-dimensional PID cut |
| 159 | + { |
| 160 | + double radius = 0.0; |
| 161 | + for (const auto& track : cutTracks) |
| 162 | + radius += std::pow(track.tpcNSigmaPi(), 2); |
| 163 | + return radius < std::pow(tracksTpcNSigmaPiCut, 2); |
| 164 | + } |
| 165 | + |
| 166 | + template <typename T> |
| 167 | + double tracksTotalCharge(const T& cutTracks) // total charge of selected tracks |
| 168 | + { |
| 169 | + double charge = 0.0; |
| 170 | + for (const auto& track : cutTracks) |
| 171 | + charge += track.sign(); |
| 172 | + return charge; |
| 173 | + } |
| 174 | + |
| 175 | + bool systemPassCuts(const ROOT::Math::PxPyPzMVector& system) // system cuts |
| 176 | + { |
| 177 | + if (system.M() < systemMassMinCut || system.M() > systemMassMaxCut) |
| 178 | + return false; |
| 179 | + if (system.Pt() > systemPtCut) |
| 180 | + return false; |
| 181 | + if (std::abs(system.Rapidity()) > systemYCut) |
| 182 | + return false; |
| 183 | + return true; |
| 184 | + } |
| 185 | + |
| 186 | + ROOT::Math::PxPyPzMVector reconstructSystem(const std::vector<ROOT::Math::PxPyPzMVector>& cutTracks4Vecs) // reconstruct system from 4-vectors |
| 187 | + { |
| 188 | + ROOT::Math::PxPyPzMVector system; |
| 189 | + for (const auto& track4Vec : cutTracks4Vecs) |
| 190 | + system += track4Vec; |
| 191 | + return system; |
| 192 | + } |
| 193 | + |
| 194 | + double deltaPhi(const ROOT::Math::PxPyPzMVector& p1, const ROOT::Math::PxPyPzMVector& p2) |
| 195 | + { |
| 196 | + double dPhi = p1.Phi() - p2.Phi(); |
| 197 | + if (dPhi > o2::constants::math::PI) |
| 198 | + dPhi -= o2::constants::math::TwoPI; |
| 199 | + else if (dPhi < -o2::constants::math::PI) |
| 200 | + dPhi += o2::constants::math::TwoPI; |
| 201 | + return dPhi; // calculate delta phi in (-pi, pi) |
| 202 | + } |
| 203 | + |
| 204 | + double getPhiRandom(const std::vector<ROOT::Math::PxPyPzMVector>& cutTracks4Vecs) // decay phi anisotropy |
| 205 | + { // two possible definitions of phi: randomize the tracks |
| 206 | + std::vector<int> indices = {0, 1}; |
| 207 | + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); // get time-based seed |
| 208 | + std::shuffle(indices.begin(), indices.end(), std::default_random_engine(seed)); // shuffle indices |
| 209 | + // calculate phi |
| 210 | + ROOT::Math::PxPyPzMVector pOne = cutTracks4Vecs[indices[0]]; |
| 211 | + ROOT::Math::PxPyPzMVector pTwo = cutTracks4Vecs[indices[1]]; |
| 212 | + ROOT::Math::PxPyPzMVector pPlus = pOne + pTwo; |
| 213 | + ROOT::Math::PxPyPzMVector pMinus = pOne - pTwo; |
| 214 | + return deltaPhi(pPlus, pMinus); |
| 215 | + } |
| 216 | + |
| 217 | + template <typename T> |
| 218 | + double getPhiCharge(const T& cutTracks, const std::vector<ROOT::Math::PxPyPzMVector>& cutTracks4Vecs) |
| 219 | + { // two possible definitions of phi: charge-based assignment |
| 220 | + ROOT::Math::PxPyPzMVector pOne, pTwo; |
| 221 | + if (cutTracks[0].sign() > 0) { |
| 222 | + pOne = cutTracks4Vecs[0]; |
| 223 | + pTwo = cutTracks4Vecs[1]; |
| 224 | + } else { |
| 225 | + pOne = cutTracks4Vecs[1]; |
| 226 | + pTwo = cutTracks4Vecs[0]; |
| 227 | + } |
| 228 | + ROOT::Math::PxPyPzMVector pPlus = pOne + pTwo; |
| 229 | + ROOT::Math::PxPyPzMVector pMinus = pOne - pTwo; |
| 230 | + return deltaPhi(pPlus, pMinus); |
| 231 | + } |
| 232 | + |
| 233 | + void processReco(FullUDSgCollision const& collision, FullUDTracks const& tracks) |
| 234 | + { |
| 235 | + |
| 236 | + if (!collisionPassesCuts(collision)) |
| 237 | + return; |
| 238 | + |
| 239 | + // vectors for storing selected tracks and their 4-vectors |
| 240 | + std::vector<decltype(tracks.begin())> cutTracks; |
| 241 | + std::vector<ROOT::Math::PxPyPzMVector> cutTracks4Vecs; |
| 242 | + |
| 243 | + // int trackCounter = 0; |
| 244 | + for (const auto& track : tracks) { |
| 245 | + |
| 246 | + if (!trackPassesCuts(track)) |
| 247 | + continue; |
| 248 | + // trackCounter++; |
| 249 | + cutTracks.push_back(track); |
| 250 | + cutTracks4Vecs.push_back(ROOT::Math::PxPyPzMVector(track.px(), track.py(), track.pz(), o2::constants::physics::MassPionCharged)); // apriori assume pion mass |
| 251 | + } |
| 252 | + |
| 253 | + if (!tracksPassPiPID(cutTracks)) |
| 254 | + return; |
| 255 | + // reonstruct system and calculate total charge, save commonly used values into variables |
| 256 | + ROOT::Math::PxPyPzMVector system = reconstructSystem(cutTracks4Vecs); |
| 257 | + int totalCharge = tracksTotalCharge(cutTracks); |
| 258 | + int nTracks = cutTracks.size(); |
| 259 | + double mass = system.M(); |
| 260 | + double pT = system.Pt(); |
| 261 | + // double pTsquare = pT * pT; |
| 262 | + double rapidity = system.Rapidity(); |
| 263 | + double systemPhi = system.Phi() + o2::constants::math::PI; |
| 264 | + |
| 265 | + if (nTracks == 4 && tracksTotalCharge(cutTracks) == 0) { // 4pi system |
| 266 | + |
| 267 | + systemTree(collision.runNumber(), mass, pT, rapidity, systemPhi, collision.posX(), collision.posY(), collision.posZ(), totalCharge, |
| 268 | + collision.totalFT0AmplitudeA(), collision.totalFT0AmplitudeC(), collision.timeFV0A(), collision.totalFDDAmplitudeA(), collision.totalFDDAmplitudeC(), |
| 269 | + collision.timeFT0A(), collision.timeFT0C(), collision.timeFV0A(), collision.timeFDDA(), collision.timeFDDC()); |
| 270 | + |
| 271 | + // registry.fill(HIST("4pi/hM"), mass); |
| 272 | + // registry.fill(HIST("4pi/hPt"), pT); |
| 273 | + // registry.fill(HIST("4pi/hEta"), rapiditiy); |
| 274 | + // registry.fill(HIST("4pi/hPhi"), system); |
| 275 | + } |
| 276 | + // std::cout<<"Hello World"<<std::endl; |
| 277 | + } |
| 278 | + PROCESS_SWITCH(upcRhoPrimeAnalysis, processReco, "analyse reco tracks", true); |
| 279 | +}; |
| 280 | + |
| 281 | +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) |
| 282 | +{ |
| 283 | + return WorkflowSpec{ |
| 284 | + o2::framework::adaptAnalysisTask<upcRhoPrimeAnalysis>(cfgc)}; |
| 285 | +} |
0 commit comments