|
| 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 spectraKinkPiKa.cxx |
| 13 | +/// \brief Example of a simple task for the analysis of the muon from Kaon pion using kink topology |
| 14 | +/// \author sandeep dudi sandeep.dudi@cern.ch |
| 15 | + |
| 16 | +#include "PWGLF/DataModel/LFKinkDecayTables.h" |
| 17 | + |
| 18 | +#include "Common/DataModel/EventSelection.h" |
| 19 | +#include "Common/DataModel/PIDResponse.h" |
| 20 | + |
| 21 | +#include "Framework/AnalysisTask.h" |
| 22 | +#include "Framework/O2DatabasePDGPlugin.h" |
| 23 | +#include "Framework/runDataProcessing.h" |
| 24 | +#include "ReconstructionDataFormats/PID.h" |
| 25 | + |
| 26 | +#include "Math/GenVector/Boost.h" |
| 27 | +#include "Math/Vector3D.h" |
| 28 | +#include "Math/Vector4D.h" |
| 29 | +#include "TPDGCode.h" |
| 30 | +#include "TVector3.h" |
| 31 | +#include <TMath.h> |
| 32 | +#include <TString.h> |
| 33 | + |
| 34 | +#include <cstdlib> |
| 35 | +#include <vector> |
| 36 | + |
| 37 | +using namespace std; |
| 38 | +using namespace o2; |
| 39 | +using namespace o2::aod; |
| 40 | +using namespace o2::framework; |
| 41 | +using namespace o2::framework::expressions; |
| 42 | +using namespace o2::constants::physics; |
| 43 | + |
| 44 | +using TracksFull = soa::Join<aod::TracksIU, aod::TracksExtra, aod::TracksCovIU, aod::pidTPCPi, aod::pidTPCKa, aod::pidTPCMu>; |
| 45 | +using CollisionsFull = soa::Join<aod::Collisions, aod::EvSel>; |
| 46 | +using CollisionsFullMC = soa::Join<aod::Collisions, aod::McCollisionLabels, aod::EvSel>; |
| 47 | +struct spectraKinkPiKa { |
| 48 | + Service<o2::framework::O2DatabasePDG> pdg; |
| 49 | + // Histograms are defined with HistogramRegistry |
| 50 | + HistogramRegistry rEventSelection{"eventSelection", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; |
| 51 | + HistogramRegistry rpiKkink{"rpiKkink", {}, OutputObjHandlingPolicy::AnalysisObject, true, true}; |
| 52 | + |
| 53 | + // Configurable for event selection |
| 54 | + Configurable<float> cutzvertex{"cutzvertex", 10.0f, "Accepted z-vertex range (cm)"}; |
| 55 | + Configurable<float> cutNSigmaPi{"cutNSigmaPi", 4, "NSigmaTPCPion"}; |
| 56 | + Configurable<float> cutNSigmaKa{"cutNSigmaKa", 4, "NSigmaTPCKaon"}; |
| 57 | + Configurable<float> rapCut{"rapCut", 0.8, "rapCut"}; |
| 58 | + |
| 59 | + Configurable<int> pid{"pidMother", 321, ""}; |
| 60 | + Configurable<bool> d0pid{"dopid", 0, ""}; |
| 61 | + |
| 62 | + Preslice<aod::KinkCands> mPerCol = aod::track::collisionId; |
| 63 | + |
| 64 | + void init(InitContext const&) |
| 65 | + { |
| 66 | + // Axes |
| 67 | + const AxisSpec ptAxis{100, 0, 10, "#it{p}_{T} (GeV/#it{c})"}; |
| 68 | + const AxisSpec qtAxis{2000, 0, 2, "#it{q}_{T} (GeV/#it{c})"}; |
| 69 | + const AxisSpec kinkAxis{200, 0, 4, "#theta"}; |
| 70 | + const AxisSpec etaAxis{200, -5.0, 5.0, "#eta"}; |
| 71 | + const AxisSpec vertexZAxis{100, -15., 15., "vrtx_{Z} [cm]"}; |
| 72 | + |
| 73 | + // Event selection |
| 74 | + rEventSelection.add("hVertexZRec", "hVertexZRec", {HistType::kTH1F, {vertexZAxis}}); |
| 75 | + |
| 76 | + rpiKkink.add("h2_dau_pt_vs_eta_rec", "pt_vs_eta_dau", {HistType::kTH2F, {ptAxis, etaAxis}}); |
| 77 | + rpiKkink.add("h2_moth_pt_vs_eta_rec", "pt_vs_eta_moth", {HistType::kTH2F, {ptAxis, etaAxis}}); |
| 78 | + rpiKkink.add("h2_pt_moth_vs_dau_rec", "pt_moth_vs_dau", {HistType::kTH2F, {ptAxis, ptAxis}}); |
| 79 | + |
| 80 | + rpiKkink.add("h2_qt", "qt", {HistType::kTH1F, {qtAxis}}); |
| 81 | + rpiKkink.add("h2_qt_vs_pt", "qt_pt", {HistType::kTH2F, {qtAxis, ptAxis}}); |
| 82 | + |
| 83 | + rpiKkink.add("h2_kink_angle", "kink angle", {HistType::kTH1F, {kinkAxis}}); |
| 84 | + |
| 85 | + // pion |
| 86 | + rpiKkink.add("h2_dau_pt_vs_eta_rec_pion", "pt_vs_eta_dau", {HistType::kTH2F, {ptAxis, etaAxis}}); |
| 87 | + rpiKkink.add("h2_moth_pt_vs_eta_rec_pion", "pt_vs_eta_moth", {HistType::kTH2F, {ptAxis, etaAxis}}); |
| 88 | + rpiKkink.add("h2_pt_moth_vs_dau_rec_pion", "pt_moth_vs_dau", {HistType::kTH2F, {ptAxis, ptAxis}}); |
| 89 | + |
| 90 | + rpiKkink.add("h2_qt_pion", "qt", {HistType::kTH1F, {qtAxis}}); |
| 91 | + rpiKkink.add("h2_qt_vs_ptpion", "qt_pt", {HistType::kTH2F, {qtAxis, ptAxis}}); |
| 92 | + rpiKkink.add("h2_kink_angle_pion", "kink angle", {HistType::kTH1F, {kinkAxis}}); |
| 93 | + |
| 94 | + if (doprocessMC) { |
| 95 | + rpiKkink.add("h2_dau_pt_vs_eta_gen", "pt_vs_eta_dau", {HistType::kTH2F, {ptAxis, etaAxis}}); |
| 96 | + rpiKkink.add("h2_moth_pt_vs_eta_gen", "pt_vs_eta_moth", {HistType::kTH2F, {ptAxis, etaAxis}}); |
| 97 | + rpiKkink.add("h2_pt_moth_vs_dau_gen", "pt_moth_vs_dau", {HistType::kTH2F, {ptAxis, ptAxis}}); |
| 98 | + |
| 99 | + rpiKkink.add("h2_qt_gen", "qt", {HistType::kTH1F, {qtAxis}}); |
| 100 | + rpiKkink.add("h2_qt_rec", "qt", {HistType::kTH1F, {qtAxis}}); |
| 101 | + rpiKkink.add("h2_kink_angle_gen", "kink angle", {HistType::kTH1F, {kinkAxis}}); |
| 102 | + } |
| 103 | + } |
| 104 | + |
| 105 | + void processData(CollisionsFull::iterator const& collision, aod::KinkCands const& KinkCands, TracksFull const&) |
| 106 | + { |
| 107 | + ROOT::Math::PxPyPzMVector v0; |
| 108 | + ROOT::Math::PxPyPzMVector v1; |
| 109 | + |
| 110 | + if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8() || !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { |
| 111 | + return; |
| 112 | + } |
| 113 | + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { |
| 114 | + return; |
| 115 | + } |
| 116 | + |
| 117 | + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); |
| 118 | + for (const auto& kinkCand : KinkCands) { |
| 119 | + auto dauTrack = kinkCand.trackDaug_as<TracksFull>(); |
| 120 | + auto mothTrack = kinkCand.trackMoth_as<TracksFull>(); |
| 121 | + bool kaon = false; |
| 122 | + bool pion = false; |
| 123 | + if (std::abs(mothTrack.tpcNSigmaKa()) < cutNSigmaKa) { |
| 124 | + kaon = true; |
| 125 | + } |
| 126 | + if (std::abs(mothTrack.tpcNSigmaPi()) < cutNSigmaPi) { |
| 127 | + pion = true; |
| 128 | + } |
| 129 | + if (!kaon && !pion) |
| 130 | + continue; |
| 131 | + v0.SetCoordinates(mothTrack.px(), mothTrack.py(), mothTrack.pz(), o2::constants::physics::MassPionCharged); |
| 132 | + v1.SetCoordinates(dauTrack.px(), dauTrack.py(), dauTrack.pz(), o2::constants::physics::MassMuon); |
| 133 | + |
| 134 | + float pMoth = v0.P(); |
| 135 | + float pDaug = v1.P(); |
| 136 | + float spKink = mothTrack.px() * dauTrack.px() + mothTrack.py() * dauTrack.py() + mothTrack.pz() * dauTrack.pz(); |
| 137 | + float kinkangle = std::acos(spKink / (pMoth * pDaug)); |
| 138 | + if (kaon) { |
| 139 | + rpiKkink.fill(HIST("h2_moth_pt_vs_eta_rec"), v0.Pt(), v0.Eta()); |
| 140 | + rpiKkink.fill(HIST("h2_dau_pt_vs_eta_rec"), v1.Pt(), v1.Eta()); |
| 141 | + rpiKkink.fill(HIST("h2_pt_moth_vs_dau_rec"), v0.Pt(), v1.Pt()); |
| 142 | + rpiKkink.fill(HIST("h2_kink_angle"), kinkangle); |
| 143 | + } |
| 144 | + if (pion) { |
| 145 | + rpiKkink.fill(HIST("h2_moth_pt_vs_eta_rec_pion"), v0.Pt(), v0.Eta()); |
| 146 | + rpiKkink.fill(HIST("h2_dau_pt_vs_eta_rec_pion"), v1.Pt(), v1.Eta()); |
| 147 | + rpiKkink.fill(HIST("h2_pt_moth_vs_dau_rec_pion"), v0.Pt(), v1.Pt()); |
| 148 | + rpiKkink.fill(HIST("h2_kink_angle_pion"), kinkangle); |
| 149 | + } |
| 150 | + TVector3 pdlab(v1.Px(), v1.Py(), v1.Pz()); |
| 151 | + // Compute transverse component |
| 152 | + TVector3 motherDir(v0.Px(), v0.Py(), v0.Pz()); |
| 153 | + double ptd = pdlab.Perp(motherDir); // or p_d_lab.Mag() * sin(theta) |
| 154 | + |
| 155 | + if (kaon) { |
| 156 | + rpiKkink.fill(HIST("h2_qt"), ptd); |
| 157 | + rpiKkink.fill(HIST("h2_qt_vs_pt"), ptd, v1.Pt()); |
| 158 | + } |
| 159 | + if (pion) { |
| 160 | + rpiKkink.fill(HIST("h2_qt_pion"), ptd); |
| 161 | + rpiKkink.fill(HIST("h2_qt_vs_ptpion"), ptd, v1.Pt()); |
| 162 | + } |
| 163 | + } |
| 164 | + } |
| 165 | + PROCESS_SWITCH(spectraKinkPiKa, processData, "Data processing", true); |
| 166 | + |
| 167 | + void processMC(CollisionsFullMC const& collisions, aod::KinkCands const& KinkCands, aod::McTrackLabels const& trackLabelsMC, aod::McParticles const& particlesMC, TracksFull const&) |
| 168 | + { |
| 169 | + for (const auto& collision : collisions) { |
| 170 | + ROOT::Math::PxPyPzMVector v0; |
| 171 | + ROOT::Math::PxPyPzMVector v1; |
| 172 | + if (std::abs(collision.posZ()) > cutzvertex || !collision.sel8() || !collision.selection_bit(aod::evsel::kNoSameBunchPileup)) { |
| 173 | + continue; |
| 174 | + } |
| 175 | + if (!collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { |
| 176 | + continue; |
| 177 | + } |
| 178 | + rEventSelection.fill(HIST("hVertexZRec"), collision.posZ()); |
| 179 | + auto kinkCandPerColl = KinkCands.sliceBy(mPerCol, collision.globalIndex()); |
| 180 | + for (const auto& kinkCand : kinkCandPerColl) { |
| 181 | + auto dauTrack = kinkCand.trackDaug_as<TracksFull>(); |
| 182 | + auto mothTrack = kinkCand.trackMoth_as<TracksFull>(); |
| 183 | + if (dauTrack.sign() != mothTrack.sign()) { |
| 184 | + LOG(info) << "Skipping kink candidate with opposite sign daughter and mother: " << kinkCand.globalIndex(); |
| 185 | + continue; // Skip if the daughter has the opposite sign as the mother |
| 186 | + } |
| 187 | + bool kaon = false; |
| 188 | + bool pion = false; |
| 189 | + if (std::abs(mothTrack.tpcNSigmaKa()) < cutNSigmaKa) { |
| 190 | + kaon = true; |
| 191 | + } |
| 192 | + if (std::abs(mothTrack.tpcNSigmaPi()) < cutNSigmaPi) { |
| 193 | + pion = true; |
| 194 | + } |
| 195 | + if (!kaon && !pion) |
| 196 | + continue; |
| 197 | + |
| 198 | + v0.SetCoordinates(mothTrack.px(), mothTrack.py(), mothTrack.pz(), o2::constants::physics::MassPionCharged); |
| 199 | + v1.SetCoordinates(dauTrack.px(), dauTrack.py(), dauTrack.pz(), o2::constants::physics::MassMuon); |
| 200 | + |
| 201 | + float pMoth = v0.P(); |
| 202 | + float pDaug = v1.P(); |
| 203 | + float spKink = mothTrack.px() * dauTrack.px() + mothTrack.py() * dauTrack.py() + mothTrack.pz() * dauTrack.pz(); |
| 204 | + float kinkangle = std::acos(spKink / (pMoth * pDaug)); |
| 205 | + |
| 206 | + rpiKkink.fill(HIST("h2_moth_pt_vs_eta_rec"), v0.Pt(), v0.Eta()); |
| 207 | + rpiKkink.fill(HIST("h2_dau_pt_vs_eta_rec"), v1.Pt(), v1.Eta()); |
| 208 | + rpiKkink.fill(HIST("h2_pt_moth_vs_dau_rec"), v0.Pt(), v1.Pt()); |
| 209 | + rpiKkink.fill(HIST("h2_kink_angle"), kinkangle); |
| 210 | + |
| 211 | + TVector3 pdlab(v1.Px(), v1.Py(), v1.Pz()); |
| 212 | + // Compute transverse component |
| 213 | + TVector3 motherDir(v0.Px(), v0.Py(), v0.Pz()); |
| 214 | + double ptd = pdlab.Perp(motherDir); // or p_d_lab.Mag() * sin(theta) |
| 215 | + |
| 216 | + rpiKkink.fill(HIST("h2_qt"), ptd); |
| 217 | + |
| 218 | + // do MC association |
| 219 | + auto mcLabMoth = trackLabelsMC.rawIteratorAt(mothTrack.globalIndex()); |
| 220 | + auto mcLabDau = trackLabelsMC.rawIteratorAt(dauTrack.globalIndex()); |
| 221 | + if (mcLabMoth.has_mcParticle() && mcLabDau.has_mcParticle()) { |
| 222 | + auto mcTrackMoth = mcLabMoth.mcParticle_as<aod::McParticles>(); |
| 223 | + auto mcTrackDau = mcLabDau.mcParticle_as<aod::McParticles>(); |
| 224 | + if (!mcTrackDau.has_mothers()) { |
| 225 | + continue; |
| 226 | + } |
| 227 | + for (const auto& piMother : mcTrackDau.mothers_as<aod::McParticles>()) { |
| 228 | + if (piMother.globalIndex() != mcTrackMoth.globalIndex()) { |
| 229 | + continue; |
| 230 | + } |
| 231 | + if (std::abs(mcTrackMoth.pdgCode()) != pid || std::abs(mcTrackDau.pdgCode()) != kMuonPlus) { |
| 232 | + continue; |
| 233 | + } |
| 234 | + // rpiKkink.fill(HIST("h2MassPtMCRec"), kinkCand.ptMoth(), v1.Pt()); |
| 235 | + rpiKkink.fill(HIST("h2_qt_rec"), ptd); |
| 236 | + } |
| 237 | + } |
| 238 | + } |
| 239 | + } |
| 240 | + for (const auto& mcPart : particlesMC) { |
| 241 | + ROOT::Math::PxPyPzMVector v0; |
| 242 | + ROOT::Math::PxPyPzMVector v1; |
| 243 | + |
| 244 | + if (!d0pid && (std::abs(mcPart.pdgCode()) != pid || std::abs(mcPart.y()) > rapCut)) { |
| 245 | + continue; |
| 246 | + } |
| 247 | + if (d0pid && (std::abs(mcPart.pdgCode()) != kD0 || std::abs(mcPart.pdgCode()) != kDPlus || std::abs(mcPart.pdgCode()) != kDStar || std::abs(mcPart.y()) > rapCut)) { |
| 248 | + continue; |
| 249 | + } |
| 250 | + |
| 251 | + if (!mcPart.has_daughters()) { |
| 252 | + continue; // Skip if no daughters |
| 253 | + } |
| 254 | + bool hasKaonpionDaughter = false; |
| 255 | + for (const auto& daughter : mcPart.daughters_as<aod::McParticles>()) { |
| 256 | + if (std::abs(daughter.pdgCode()) == kMuonPlus) { // muon PDG code |
| 257 | + hasKaonpionDaughter = true; |
| 258 | + v1.SetCoordinates(daughter.px(), daughter.py(), daughter.pz(), o2::constants::physics::MassMuon); |
| 259 | + break; // Found a muon daughter, exit loop |
| 260 | + } |
| 261 | + } |
| 262 | + if (!hasKaonpionDaughter) { |
| 263 | + continue; // Skip if no muon daughter found |
| 264 | + } |
| 265 | + if (pid == kKPlus) { |
| 266 | + v0.SetCoordinates(mcPart.px(), mcPart.py(), mcPart.pz(), o2::constants::physics::MassKaonCharged); |
| 267 | + } |
| 268 | + |
| 269 | + if (pid == kPiPlus) { |
| 270 | + v0.SetCoordinates(mcPart.px(), mcPart.py(), mcPart.pz(), o2::constants::physics::MassPionCharged); |
| 271 | + } |
| 272 | + if (d0pid) { |
| 273 | + v0.SetCoordinates(mcPart.px(), mcPart.py(), mcPart.pz(), o2::constants::physics::MassD0); |
| 274 | + } |
| 275 | + |
| 276 | + float pMoth = v0.P(); |
| 277 | + float pDaug = v1.P(); |
| 278 | + float spKink = v0.Px() * v1.Px() + v0.Py() * v1.Py() + v0.Pz() * v1.Pz(); |
| 279 | + float kinkangle = std::acos(spKink / (pMoth * pDaug)); |
| 280 | + |
| 281 | + // std::cout<< kinkCand.ptMoth()<<" check "<<v0.Pt()<<std::endl; |
| 282 | + rpiKkink.fill(HIST("h2_moth_pt_vs_eta_gen"), v0.Pt(), v0.Eta()); |
| 283 | + rpiKkink.fill(HIST("h2_dau_pt_vs_eta_gen"), v1.Pt(), v1.Eta()); |
| 284 | + rpiKkink.fill(HIST("h2_pt_moth_vs_dau_gen"), v0.Pt(), v1.Pt()); |
| 285 | + rpiKkink.fill(HIST("h2_kink_angle_gen"), kinkangle); |
| 286 | + |
| 287 | + TVector3 pdlab(v1.Px(), v1.Py(), v1.Pz()); |
| 288 | + // Compute transverse component |
| 289 | + TVector3 motherDir(v0.Px(), v0.Py(), v0.Pz()); |
| 290 | + double ptd = pdlab.Perp(motherDir); // or p_d_lab.Mag() * sin(theta) |
| 291 | + rpiKkink.fill(HIST("h2_qt_gen"), ptd); |
| 292 | + } |
| 293 | + } |
| 294 | + PROCESS_SWITCH(spectraKinkPiKa, processMC, "MC processing", false); |
| 295 | +}; |
| 296 | + |
| 297 | +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) |
| 298 | +{ |
| 299 | + return WorkflowSpec{ |
| 300 | + adaptAnalysisTask<spectraKinkPiKa>(cfgc)}; |
| 301 | +} |
0 commit comments