|
| 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 | +/// \file pidStudies.cxx |
| 13 | +/// \brief task for studies of PID performance |
| 14 | +/// |
| 15 | +/// \author Fabrizio Chinu <fabrizio.chinu@cern.ch>, Università and INFN Torino |
| 16 | +/// \author Stefano Politanò <stefano.politano@cern.ch>, INFN Torino |
| 17 | +/// \author Marcello Di Costanzo <marcello.di.costanzo@cern.ch>, Politecnico and INFN Torino |
| 18 | +/// \author Luca Aglietta <luca.aglietta@unito.it>, Università and INFN Torino |
| 19 | + |
| 20 | +#include "TPDGCode.h" |
| 21 | + |
| 22 | +#include "Framework/AnalysisTask.h" |
| 23 | +#include "Framework/runDataProcessing.h" |
| 24 | + |
| 25 | +#include "Common/DataModel/PIDResponse.h" |
| 26 | +#include "Common/DataModel/Centrality.h" |
| 27 | +#include "Common/DataModel/Multiplicity.h" |
| 28 | +#include "Common/DataModel/EventSelection.h" |
| 29 | +#include "Common/DataModel/TrackSelectionTables.h" |
| 30 | +#include "PWGLF/DataModel/LFStrangenessTables.h" |
| 31 | +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" |
| 32 | + |
| 33 | +using namespace o2; |
| 34 | +using namespace o2::framework; |
| 35 | +using namespace o2::framework::expressions; |
| 36 | + |
| 37 | +namespace o2::aod |
| 38 | +{ |
| 39 | +namespace pid_studies |
| 40 | +{ |
| 41 | +enum Particle { NotMatched = 0, |
| 42 | + K0s, |
| 43 | + Lambda, |
| 44 | + Omega }; |
| 45 | +// V0s |
| 46 | +DECLARE_SOA_COLUMN(MassK0, massK0, float); //! Candidate mass |
| 47 | +DECLARE_SOA_COLUMN(MassLambda, massLambda, float); //! Candidate mass |
| 48 | +DECLARE_SOA_COLUMN(MassAntiLambda, massAntiLambda, float); //! Candidate mass |
| 49 | +DECLARE_SOA_COLUMN(Pt, pt, float); //! Transverse momentum of the candidate (GeV/c) |
| 50 | +DECLARE_SOA_COLUMN(PtPos, ptPos, float); //! Transverse momentum of positive track (GeV/c) |
| 51 | +DECLARE_SOA_COLUMN(PtNeg, ptNeg, float); //! Transverse momentum of negative track (GeV/c) |
| 52 | +DECLARE_SOA_COLUMN(Radius, radius, float); //! Radius |
| 53 | +DECLARE_SOA_COLUMN(Cpa, cpa, float); //! Cosine of pointing angle |
| 54 | +DECLARE_SOA_COLUMN(NSigmaTpcPosPi, nSigmaTpcPosPi, float); //! nSigmaTPC of positive track with pion hypothesis |
| 55 | +DECLARE_SOA_COLUMN(NSigmaTpcNegPi, nSigmaTpcNegPi, float); //! nSigmaTPC of negative track with pion hypothesis |
| 56 | +DECLARE_SOA_COLUMN(NSigmaTpcPosPr, nSigmaTpcPosPr, float); //! nSigmaTPC of positive track with proton hypothesis |
| 57 | +DECLARE_SOA_COLUMN(NSigmaTpcNegPr, nSigmaTpcNegPr, float); //! nSigmaTPC of negative track with proton hypothesis |
| 58 | +DECLARE_SOA_COLUMN(NSigmaTofPosPi, nSigmaTofPosPi, float); //! nSigmaTOF of positive track with pion hypothesis |
| 59 | +DECLARE_SOA_COLUMN(NSigmaTofNegPi, nSigmaTofNegPi, float); //! nSigmaTOF of negative track with pion hypothesis |
| 60 | +DECLARE_SOA_COLUMN(NSigmaTofPosPr, nSigmaTofPosPr, float); //! nSigmaTOF of positive track with proton hypothesis |
| 61 | +DECLARE_SOA_COLUMN(NSigmaTofNegPr, nSigmaTofNegPr, float); //! nSigmaTOF of negative track with proton hypothesis |
| 62 | +DECLARE_SOA_COLUMN(AlphaArm, alphaArm, float); //! Armenteros alpha |
| 63 | +DECLARE_SOA_COLUMN(QtArm, qtArm, float); //! Armenteros Qt |
| 64 | + |
| 65 | +// Cascades |
| 66 | +DECLARE_SOA_COLUMN(MassOmega, massOmega, float); //! Candidate mass |
| 67 | +DECLARE_SOA_COLUMN(MassXi, massXi, float); //! Candidate mass |
| 68 | +DECLARE_SOA_COLUMN(BachPt, bachPt, float); //! Transverse momentum of the bachelor (GeV/c) |
| 69 | +DECLARE_SOA_COLUMN(V0cosPA, v0cosPA, float); //! V0 CPA |
| 70 | +DECLARE_SOA_COLUMN(CascCosPA, casccosPA, float); //! Cascade CPA |
| 71 | +DECLARE_SOA_COLUMN(DCAV0daughters, dcaV0daughters, float); //! DCA of V0 daughters |
| 72 | +DECLARE_SOA_COLUMN(DCAv0topv, dcav0topv, float); //! V0 DCA to PV |
| 73 | +DECLARE_SOA_COLUMN(NSigmaTpcBachKa, nSigmaTpcBachKa, float); //! nSigmaTPC of bachelor with kaon hypothesis |
| 74 | +DECLARE_SOA_COLUMN(NSigmaTofBachKa, nSigmaTofBachKa, float); //! nSigmaTOF of bachelor with kaon hypothesis |
| 75 | + |
| 76 | +// Common columns |
| 77 | +DECLARE_SOA_COLUMN(OccupancyFt0c, occupancyFt0c, float); //! Occupancy from FT0C |
| 78 | +DECLARE_SOA_COLUMN(OccupancyIts, occupancyIts, float); //! Occupancy from ITS |
| 79 | +DECLARE_SOA_COLUMN(CentralityFT0C, centralityFT0C, float); //! Centrality from FT0C |
| 80 | +DECLARE_SOA_COLUMN(CentralityFT0M, centralityFT0M, float); //! Centrality from FT0M |
| 81 | +DECLARE_SOA_COLUMN(CandFlag, candFlag, int); //! Flag for MC matching |
| 82 | +} // namespace pid_studies |
| 83 | + |
| 84 | +DECLARE_SOA_TABLE(PidV0s, "AOD", "PIDV0S", //! Table with PID information |
| 85 | + pid_studies::MassK0, |
| 86 | + pid_studies::MassLambda, |
| 87 | + pid_studies::MassAntiLambda, |
| 88 | + pid_studies::Pt, |
| 89 | + pid_studies::PtPos, |
| 90 | + pid_studies::PtNeg, |
| 91 | + pid_studies::Radius, |
| 92 | + pid_studies::Cpa, |
| 93 | + pid_studies::NSigmaTpcPosPi, |
| 94 | + pid_studies::NSigmaTpcNegPi, |
| 95 | + pid_studies::NSigmaTpcPosPr, |
| 96 | + pid_studies::NSigmaTpcNegPr, |
| 97 | + pid_studies::NSigmaTofPosPi, |
| 98 | + pid_studies::NSigmaTofNegPi, |
| 99 | + pid_studies::NSigmaTofPosPr, |
| 100 | + pid_studies::NSigmaTofNegPr, |
| 101 | + pid_studies::AlphaArm, |
| 102 | + pid_studies::QtArm, |
| 103 | + pid_studies::OccupancyFt0c, |
| 104 | + pid_studies::OccupancyIts, |
| 105 | + pid_studies::CentralityFT0C, |
| 106 | + pid_studies::CentralityFT0M, |
| 107 | + pid_studies::CandFlag); |
| 108 | + |
| 109 | +DECLARE_SOA_TABLE(PidCascades, "AOD", "PIDCASCADES", //! Table with PID information |
| 110 | + pid_studies::MassOmega, |
| 111 | + pid_studies::Pt, |
| 112 | + pid_studies::BachPt, |
| 113 | + pid_studies::V0cosPA, |
| 114 | + pid_studies::MassXi, |
| 115 | + pid_studies::CascCosPA, |
| 116 | + pid_studies::DCAV0daughters, |
| 117 | + pid_studies::DCAv0topv, |
| 118 | + pid_studies::NSigmaTpcBachKa, |
| 119 | + pid_studies::NSigmaTofBachKa, |
| 120 | + pid_studies::OccupancyFt0c, |
| 121 | + pid_studies::OccupancyIts, |
| 122 | + pid_studies::CentralityFT0C, |
| 123 | + pid_studies::CentralityFT0M, |
| 124 | + pid_studies::CandFlag); |
| 125 | +} // namespace o2::aod |
| 126 | + |
| 127 | +struct HfPidStudies { |
| 128 | + Produces<o2::aod::PidV0s> pidV0; |
| 129 | + Produces<o2::aod::PidCascades> pidCascade; |
| 130 | + |
| 131 | + Configurable<float> massK0Min{"massK0Min", 0.4, "Minimum mass for K0"}; |
| 132 | + Configurable<float> massK0Max{"massK0Max", 0.6, "Maximum mass for K0"}; |
| 133 | + Configurable<float> massLambdaMin{"massLambdaMin", 1.0, "Minimum mass for lambda"}; |
| 134 | + Configurable<float> massLambdaMax{"massLambdaMax", 1.3, "Maximum mass for lambda"}; |
| 135 | + Configurable<float> massOmegaMin{"massOmegaMin", 1.5, "Minimum mass for omega"}; |
| 136 | + Configurable<float> massOmegaMax{"massOmegaMax", 1.8, "Maximum mass for omega"}; |
| 137 | + Configurable<float> downSampleBkgFactor{"downSampleBkgFactor", 1., "Fraction of candidates to keep"}; |
| 138 | + Configurable<float> ptMaxForDownSample{"ptMaxForDownSample", 10., "Maximum pt for the application of the downsampling factor"}; |
| 139 | + |
| 140 | + using PidTracks = soa::Join<aod::Tracks, aod::TracksExtra, |
| 141 | + aod::pidTPCFullPi, aod::pidTPCFullKa, aod::pidTPCFullPr, |
| 142 | + aod::pidTOFFullPi, aod::pidTOFFullKa, aod::pidTOFFullPr>; |
| 143 | + using CollSels = soa::Join<aod::Collisions, aod::EvSels, aod::CentFT0Cs, aod::CentFT0Ms>; |
| 144 | + using V0sMcRec = soa::Join<aod::V0Datas, aod::V0CoreMCLabels>; |
| 145 | + using CascsMcRec = soa::Join<aod::CascDatas, aod::CascCoreMCLabels>; |
| 146 | + |
| 147 | + template <bool isV0, typename Cand> |
| 148 | + void fillTree(Cand const& candidate, const int flag) |
| 149 | + { |
| 150 | + float pseudoRndm = candidate.pt() * 1000. - static_cast<int64_t>(candidate.pt() * 1000); |
| 151 | + if (candidate.pt() < ptMaxForDownSample && pseudoRndm > downSampleBkgFactor) { |
| 152 | + return; |
| 153 | + } |
| 154 | + |
| 155 | + const auto& coll = candidate.template collision_as<CollSels>(); |
| 156 | + if constexpr (isV0) { |
| 157 | + const auto& posTrack = candidate.template posTrack_as<PidTracks>(); |
| 158 | + const auto& negTrack = candidate.template negTrack_as<PidTracks>(); |
| 159 | + pidV0( |
| 160 | + candidate.mK0Short(), |
| 161 | + candidate.mLambda(), |
| 162 | + candidate.mAntiLambda(), |
| 163 | + candidate.pt(), |
| 164 | + posTrack.pt(), |
| 165 | + negTrack.pt(), |
| 166 | + candidate.v0radius(), |
| 167 | + candidate.v0cosPA(), |
| 168 | + posTrack.tofNSigmaPi(), |
| 169 | + negTrack.tofNSigmaPi(), |
| 170 | + posTrack.tofNSigmaPr(), |
| 171 | + negTrack.tofNSigmaPr(), |
| 172 | + posTrack.tpcNSigmaPi(), |
| 173 | + negTrack.tpcNSigmaPi(), |
| 174 | + posTrack.tpcNSigmaPr(), |
| 175 | + negTrack.tpcNSigmaPr(), |
| 176 | + candidate.alpha(), |
| 177 | + candidate.qtarm(), |
| 178 | + coll.ft0cOccupancyInTimeRange(), |
| 179 | + coll.trackOccupancyInTimeRange(), |
| 180 | + coll.centFT0C(), |
| 181 | + coll.centFT0M(), |
| 182 | + flag); |
| 183 | + } else { |
| 184 | + const auto& bachTrack = candidate.template bachelor_as<PidTracks>(); |
| 185 | + pidCascade( |
| 186 | + candidate.mOmega(), |
| 187 | + candidate.pt(), |
| 188 | + candidate.bachelorpt(), |
| 189 | + candidate.v0cosPA(coll.posX(), coll.posY(), coll.posZ()), |
| 190 | + candidate.mXi(), |
| 191 | + candidate.casccosPA(coll.posX(), coll.posY(), coll.posZ()), |
| 192 | + candidate.dcaV0daughters(), |
| 193 | + candidate.dcav0topv(coll.posX(), coll.posY(), coll.posZ()), |
| 194 | + bachTrack.tpcNSigmaKa(), |
| 195 | + bachTrack.tofNSigmaKa(), |
| 196 | + coll.ft0cOccupancyInTimeRange(), |
| 197 | + coll.trackOccupancyInTimeRange(), |
| 198 | + coll.centFT0C(), |
| 199 | + coll.centFT0M(), |
| 200 | + flag); |
| 201 | + } |
| 202 | + } |
| 203 | + |
| 204 | + template <typename T1> |
| 205 | + int isMatched(const T1& cand) |
| 206 | + { |
| 207 | + if constexpr (std::is_same<T1, V0sMcRec::iterator>::value) { |
| 208 | + if (!cand.has_v0MCCore()) { |
| 209 | + return aod::pid_studies::Particle::NotMatched; |
| 210 | + } |
| 211 | + auto v0MC = cand.template v0MCCore_as<aod::V0MCCores>(); |
| 212 | + if (v0MC.pdgCode() == kK0Short && v0MC.pdgCodeNegative() == -kPiPlus && v0MC.pdgCodePositive() == kPiPlus) { |
| 213 | + return aod::pid_studies::Particle::K0s; |
| 214 | + } |
| 215 | + if (v0MC.pdgCode() == kLambda0 && v0MC.pdgCodeNegative() == -kPiPlus && v0MC.pdgCodePositive() == kProton) { |
| 216 | + return aod::pid_studies::Particle::Lambda; |
| 217 | + } |
| 218 | + if (v0MC.pdgCode() == -kLambda0 && v0MC.pdgCodeNegative() == -kProton && v0MC.pdgCodePositive() == kPiPlus) { |
| 219 | + return -aod::pid_studies::Particle::Lambda; |
| 220 | + } |
| 221 | + } |
| 222 | + if constexpr (std::is_same<T1, CascsMcRec::iterator>::value) { |
| 223 | + if (!cand.has_cascMCCore()) { |
| 224 | + return aod::pid_studies::Particle::NotMatched; |
| 225 | + } |
| 226 | + auto cascMC = cand.template cascMCCore_as<aod::CascMCCores>(); |
| 227 | + if (cascMC.pdgCode() == kOmegaMinus && |
| 228 | + cascMC.pdgCodeBachelor() == -kKPlus && |
| 229 | + cascMC.pdgCodeV0() == kLambda0 && |
| 230 | + cascMC.pdgCodePositive() == kProton && |
| 231 | + cascMC.pdgCodeNegative() == -kPiPlus) { |
| 232 | + return aod::pid_studies::Particle::Omega; |
| 233 | + } |
| 234 | + if (cascMC.pdgCode() == -kOmegaMinus && |
| 235 | + cascMC.pdgCodeBachelor() == kKPlus && |
| 236 | + cascMC.pdgCodeV0() == -kLambda0 && |
| 237 | + cascMC.pdgCodePositive() == kPiPlus && |
| 238 | + cascMC.pdgCodeNegative() == -kProton) { |
| 239 | + return -aod::pid_studies::Particle::Omega; |
| 240 | + } |
| 241 | + } |
| 242 | + return aod::pid_studies::Particle::NotMatched; |
| 243 | + } |
| 244 | + |
| 245 | + void processMc(V0sMcRec const& V0s, |
| 246 | + aod::V0MCCores const&, |
| 247 | + CascsMcRec const& cascades, |
| 248 | + aod::CascMCCores const&, |
| 249 | + CollSels const&, |
| 250 | + PidTracks const&) |
| 251 | + { |
| 252 | + for (const auto& v0 : V0s) { |
| 253 | + if ((v0.mK0Short() > massK0Min && v0.mK0Short() < massK0Max) || |
| 254 | + (v0.mLambda() > massLambdaMin && v0.mLambda() < massLambdaMax) || |
| 255 | + (v0.mAntiLambda() > massLambdaMin && v0.mAntiLambda() < massLambdaMax)) { |
| 256 | + int matched = isMatched(v0); |
| 257 | + if (matched != aod::pid_studies::Particle::NotMatched) { |
| 258 | + fillTree<true>(v0, matched); |
| 259 | + } |
| 260 | + } |
| 261 | + } |
| 262 | + for (const auto& casc : cascades) { |
| 263 | + if (casc.mOmega() > massOmegaMin && casc.mOmega() < massOmegaMax && casc.mLambda() > massLambdaMin && casc.mLambda() < massLambdaMax) { |
| 264 | + int matched = isMatched(casc); |
| 265 | + if (matched != aod::pid_studies::Particle::NotMatched) { |
| 266 | + fillTree<false>(casc, matched); |
| 267 | + } |
| 268 | + } |
| 269 | + } |
| 270 | + } |
| 271 | + PROCESS_SWITCH(HfPidStudies, processMc, "Process MC", true); |
| 272 | + |
| 273 | + void processData(aod::V0Datas const& V0s, aod::CascDatas const& cascades, CollSels const&, PidTracks const&) |
| 274 | + { |
| 275 | + for (const auto& v0 : V0s) { |
| 276 | + if ((v0.mK0Short() > massK0Min && v0.mK0Short() < massK0Max) || |
| 277 | + (v0.mLambda() > massLambdaMin && v0.mLambda() < massLambdaMax) || |
| 278 | + (v0.mAntiLambda() > massLambdaMin && v0.mAntiLambda() < massLambdaMax)) { |
| 279 | + fillTree<true>(v0, aod::pid_studies::Particle::NotMatched); |
| 280 | + } |
| 281 | + } |
| 282 | + for (const auto& casc : cascades) { |
| 283 | + if (casc.mOmega() > massOmegaMin && casc.mOmega() < massOmegaMax && casc.mLambda() > massLambdaMin && casc.mLambda() < massLambdaMax) { |
| 284 | + fillTree<false>(casc, aod::pid_studies::Particle::NotMatched); |
| 285 | + } |
| 286 | + } |
| 287 | + } |
| 288 | + PROCESS_SWITCH(HfPidStudies, processData, "Process data", false); |
| 289 | +}; |
| 290 | + |
| 291 | +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) |
| 292 | +{ |
| 293 | + return WorkflowSpec{adaptAnalysisTask<HfPidStudies>(cfgc)}; |
| 294 | +} |
0 commit comments