Skip to content

Commit 99b0f1e

Browse files
authored
Cascade analysis mc task - first commit (#1105)
1 parent daf6f0c commit 99b0f1e

3 files changed

Lines changed: 316 additions & 3 deletions

File tree

PWGLF/Tasks/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ o2physics_add_dpl_workflow(cascadeanalysis
7474
PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::DetectorsVertexing
7575
COMPONENT_NAME Analysis)
7676

77+
o2physics_add_dpl_workflow(cascadeanalysismc
78+
SOURCES cascadeanalysisMC.cxx
79+
PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::DetectorsVertexing
80+
COMPONENT_NAME Analysis)
81+
7782
o2physics_add_dpl_workflow(v0cascades-qa
7883
SOURCES v0cascadesqa.cxx
7984
PUBLIC_LINK_LIBRARIES O2::Framework O2::DetectorsBase O2Physics::AnalysisCore O2::DetectorsVertexing

PWGLF/Tasks/cascadeanalysis.cxx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
// during reconstruction and collision association is better
2424
// done at that stage.
2525
//
26-
// This task also includes a switchable process function
27-
// to cover MC generated cascades.
28-
//
2926
// Comments, questions, complaints, suggestions?
3027
// Please write to:
3128
// david.dobrigkeit.chinellato@cern.ch

PWGLF/Tasks/cascadeanalysisMC.cxx

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
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+
// Example cascade analysis task
13+
// =============================
14+
//
15+
// This code loops over a CascData table and produces some
16+
// standard analysis output. It requires either
17+
// the cascade finder or the cascade builder tasks
18+
// to have been executed in the workflow (before).
19+
//
20+
// Note, however, that only the cascade builder does
21+
// time-frame-aware cascade building at this time. This
22+
// is deliberate, as time-frame information is available
23+
// during reconstruction and collision association is better
24+
// done at that stage.
25+
//
26+
// this task makes use of labels provided by the cascade
27+
// builder to process cascades quickly.
28+
//
29+
// Comments, questions, complaints, suggestions?
30+
// Please write to:
31+
// david.dobrigkeit.chinellato@cern.ch
32+
//
33+
34+
#include "Framework/runDataProcessing.h"
35+
#include "Framework/AnalysisTask.h"
36+
#include "Framework/AnalysisDataModel.h"
37+
#include "Framework/ASoAHelpers.h"
38+
#include "ReconstructionDataFormats/Track.h"
39+
#include "Common/Core/RecoDecay.h"
40+
#include "Common/Core/trackUtilities.h"
41+
#include "Common/DataModel/StrangenessTables.h"
42+
#include "Common/Core/TrackSelection.h"
43+
#include "Common/DataModel/TrackSelectionTables.h"
44+
#include "Common/DataModel/EventSelection.h"
45+
#include "Common/DataModel/Centrality.h"
46+
47+
#include <TFile.h>
48+
#include <TH2F.h>
49+
#include <TProfile.h>
50+
#include <TLorentzVector.h>
51+
#include <Math/Vector4D.h>
52+
#include <TPDGCode.h>
53+
#include <TDatabasePDG.h>
54+
#include <cmath>
55+
#include <array>
56+
#include <cstdlib>
57+
#include "Framework/ASoAHelpers.h"
58+
59+
using namespace o2;
60+
using namespace o2::framework;
61+
using namespace o2::framework::expressions;
62+
using std::array;
63+
64+
//use parameters + cov mat non-propagated, aux info + (extension propagated)
65+
using FullTracksExt = soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksCov, aod::TracksDCA>;
66+
using FullTracksExtIU = soa::Join<aod::TracksIU, aod::TracksExtra, aod::TracksCovIU, aod::TracksDCA>;
67+
using LabeledCascades = soa::Join<aod::CascDataExt, aod::McCascLabels>;
68+
69+
struct cascadeQaMC {
70+
// Basic checks
71+
HistogramRegistry registry{
72+
"registry",
73+
{
74+
{"hMassXiMinus", "hMassXiMinus", {HistType::kTH1F, {{3000, 0.0f, 3.0f, "Inv. Mass (GeV/c^{2})"}}}},
75+
{"hMassXiPlus", "hMassXiPlus", {HistType::kTH1F, {{3000, 0.0f, 3.0f, "Inv. Mass (GeV/c^{2}²)"}}}},
76+
{"hMassOmegaMinus", "hMassOmegaMinus", {HistType::kTH1F, {{3000, 0.0f, 3.0f, "Inv. Mass (GeV/c^{2})"}}}},
77+
{"hMassOmegaPlus", "hMassOmegaPlus", {HistType::kTH1F, {{3000, 0.0f, 3.0f, "Inv. Mass (GeV/c^{2})"}}}},
78+
79+
{"hV0Radius", "hV0Radius", {HistType::kTH1F, {{1000, 0.0f, 100.0f, "cm"}}}},
80+
{"hCascRadius", "hCascRadius", {HistType::kTH1F, {{1000, 0.0f, 100.0f, "cm"}}}},
81+
{"hV0CosPA", "hV0CosPA", {HistType::kTH1F, {{1000, 0.95f, 1.0f}}}},
82+
{"hCascCosPA", "hCascCosPA", {HistType::kTH1F, {{1000, 0.95f, 1.0f}}}},
83+
{"hDCAPosToPV", "hDCAPosToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}},
84+
{"hDCANegToPV", "hDCANegToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}},
85+
{"hDCABachToPV", "hDCABachToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}},
86+
{"hDCAV0ToPV", "hDCAV0ToPV", {HistType::kTH1F, {{1000, -10.0f, 10.0f, "cm"}}}},
87+
{"hDCAV0Dau", "hDCAV0Dau", {HistType::kTH1F, {{1000, 0.0f, 10.0f, "cm^{2}"}}}},
88+
{"hDCACascDau", "hDCACascDau", {HistType::kTH1F, {{1000, 0.0f, 10.0f, "cm^{2}"}}}},
89+
{"hLambdaMass", "hLambdaMass", {HistType::kTH1F, {{1000, 0.0f, 10.0f, "Inv. Mass (GeV/c^{2})"}}}},
90+
},
91+
};
92+
93+
Configurable<bool> assocMC{"assocMC", true, "fill histograms only for MC associated candidates"};
94+
95+
void process(aod::Collision const& collision, LabeledCascades const& Cascades, aod::McParticles const&)
96+
{
97+
for (auto& casc : Cascades) {
98+
Int_t lPDG = 0;
99+
if (assocMC) {
100+
if (!casc.has_mcParticle())
101+
continue;
102+
auto cascmc = casc.mcParticle();
103+
if (TMath::Abs(cascmc.pdgCode()) == 3312 || TMath::Abs(cascmc.pdgCode()) == 3334)
104+
lPDG = cascmc.pdgCode();
105+
}
106+
107+
if (casc.sign() < 0) { // FIXME: could be done better...
108+
if (!assocMC || lPDG == 3312)
109+
registry.fill(HIST("hMassXiMinus"), casc.mXi());
110+
if (!assocMC || lPDG == 3334)
111+
registry.fill(HIST("hMassOmegaMinus"), casc.mOmega());
112+
} else {
113+
if (!assocMC || lPDG == -3312)
114+
registry.fill(HIST("hMassXiPlus"), casc.mXi());
115+
if (!assocMC || lPDG == -3334)
116+
registry.fill(HIST("hMassOmegaPlus"), casc.mOmega());
117+
}
118+
// The basic eleven!
119+
registry.fill(HIST("hV0Radius"), casc.v0radius());
120+
registry.fill(HIST("hCascRadius"), casc.cascradius());
121+
registry.fill(HIST("hV0CosPA"), casc.v0cosPA(collision.posX(), collision.posY(), collision.posZ()));
122+
registry.fill(HIST("hCascCosPA"), casc.casccosPA(collision.posX(), collision.posY(), collision.posZ()));
123+
registry.fill(HIST("hDCAPosToPV"), casc.dcapostopv());
124+
registry.fill(HIST("hDCANegToPV"), casc.dcanegtopv());
125+
registry.fill(HIST("hDCABachToPV"), casc.dcabachtopv());
126+
registry.fill(HIST("hDCAV0ToPV"), casc.dcav0topv(collision.posX(), collision.posY(), collision.posZ()));
127+
registry.fill(HIST("hDCAV0Dau"), casc.dcaV0daughters());
128+
registry.fill(HIST("hDCACascDau"), casc.dcacascdaughters());
129+
registry.fill(HIST("hLambdaMass"), casc.mLambda());
130+
}
131+
}
132+
};
133+
134+
struct cascadeAnalysisMC {
135+
HistogramRegistry registry{
136+
"registry",
137+
{},
138+
};
139+
140+
void init(InitContext const&)
141+
{
142+
AxisSpec ptAxis = {200, 0.0f, 10.0f, "it{p}_{T} (GeV/c)"};
143+
AxisSpec massAxisXi = {200, 1.222f, 1.422f, "Inv. Mass (GeV/c^{2})"};
144+
AxisSpec massAxisOmega = {200, 1.572f, 1.772f, "Inv. Mass (GeV/c^{2})"};
145+
146+
registry.add("hCandidateCounter", "hCandidateCounter", {HistType::kTH1F, {{10, 0.0f, 10.0f}}});
147+
registry.add("h2dMassXiMinus", "h2dMassXiMinus", {HistType::kTH2F, {ptAxis, massAxisXi}});
148+
registry.add("h2dMassXiPlus", "h2dMassXiPlus", {HistType::kTH2F, {ptAxis, massAxisXi}});
149+
registry.add("h2dMassOmegaMinus", "h2dMassOmegaMinus", {HistType::kTH2F, {ptAxis, massAxisOmega}});
150+
registry.add("h2dMassOmegaPlus", "h2dMassOmegaPlus", {HistType::kTH2F, {ptAxis, massAxisOmega}});
151+
}
152+
153+
// Selection criteria
154+
Configurable<double> v0cospa{"v0cospa", 0.95, "V0 CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0)
155+
Configurable<double> casccospa{"casccospa", 0.95, "Casc CosPA"}; // double -> N.B. dcos(x)/dx = 0 at x=0)
156+
Configurable<float> dcav0dau{"dcav0dau", 2.0, "DCA V0 Daughters"};
157+
Configurable<float> dcacascdau{"dcacascdau", 1.0, "DCA Casc Daughters"};
158+
Configurable<float> dcanegtopv{"dcanegtopv", .05, "DCA Neg To PV"};
159+
Configurable<float> dcapostopv{"dcapostopv", .05, "DCA Pos To PV"};
160+
Configurable<float> dcabachtopv{"dcabachtopv", .05, "DCA Bach To PV"};
161+
Configurable<float> dcav0topv{"dcav0topv", .05, "DCA V0 To PV"};
162+
Configurable<float> v0radius{"v0radius", 0.9, "v0radius"};
163+
Configurable<float> cascradius{"cascradius", 0.5, "cascradius"};
164+
Configurable<float> v0masswindow{"v0masswindow", 0.008, "v0masswindow"};
165+
Configurable<bool> eventSelection{"eventSelection", true, "event selection"};
166+
167+
Configurable<int> tpcClusters{"tpcClusters", 70, "minimum number of TPC clusters requirement"};
168+
Configurable<int> itsClusters{"itsClusters", 4, "minimum number of ITS clusters requirement for ITSSA tracks"};
169+
Configurable<bool> allowITSSAbachelor{"allowITSSAbachelor", true, "allow for bachelor <- cascade track to be via ITS tracking only"};
170+
Configurable<bool> allowITSSAproton{"allowITSSAproton", true, "allow for proton <- lambda track to be via ITS tracking only"};
171+
Configurable<bool> allowITSSApion{"allowITSSApion", false, "allow for pion <- lambda track to be via ITS tracking only "};
172+
Configurable<bool> assocMC{"assocMC", true, "fill histograms only for MC associated candidates"};
173+
174+
Filter preFilter =
175+
nabs(aod::cascdata::dcapostopv) > dcapostopv&& nabs(aod::cascdata::dcanegtopv) > dcanegtopv&& nabs(aod::cascdata::dcabachtopv) > dcabachtopv&& aod::cascdata::dcaV0daughters < dcav0dau&& aod::cascdata::dcacascdaughters < dcacascdau;
176+
177+
Partition<LabeledCascades> associatedCascades = (aod::mccasclabel::mcParticleId > -1);
178+
179+
template <class TCascTracksTo>
180+
void fillCascadeOutput(soa::Filtered<LabeledCascades> const& cascades, float const& pvx, float const& pvy, float const& pvz)
181+
//function to process cascades and generate corresponding invariant mass distributions
182+
{
183+
for (auto& casc : cascades) {
184+
registry.fill(HIST("hCandidateCounter"), 0.5); //all candidates
185+
//check mc association if requested
186+
Int_t lPDG = 0;
187+
if (assocMC) {
188+
if (!casc.has_mcParticle())
189+
continue;
190+
auto cascmc = casc.mcParticle();
191+
if (TMath::Abs(cascmc.pdgCode()) == 3312 || TMath::Abs(cascmc.pdgCode()) == 3334)
192+
lPDG = cascmc.pdgCode();
193+
}
194+
195+
auto v0 = casc.v0_as<o2::aod::V0sLinked>();
196+
if (!(v0.has_v0Data())) {
197+
continue; //skip those cascades for which V0 doesn't exist
198+
}
199+
registry.fill(HIST("hCandidateCounter"), 1.5); //v0data exists
200+
auto v0data = v0.v0Data(); // de-reference index to correct v0data in case it exists
201+
auto bachTrackCast = casc.bachelor_as<TCascTracksTo>();
202+
auto posTrackCast = v0data.posTrack_as<TCascTracksTo>();
203+
auto negTrackCast = v0data.negTrack_as<TCascTracksTo>();
204+
205+
//track-level selections
206+
Bool_t lEnoughTPCNClsBac = kTRUE;
207+
Bool_t lEnoughTPCNClsPos = kTRUE;
208+
Bool_t lEnoughTPCNClsNeg = kTRUE;
209+
Bool_t lEnoughITSNClsBac = kTRUE;
210+
Bool_t lEnoughITSNClsPos = kTRUE;
211+
Bool_t lEnoughITSNClsNeg = kTRUE;
212+
213+
if (bachTrackCast.tpcNClsFound() < tpcClusters)
214+
lEnoughTPCNClsBac = kFALSE;
215+
if (posTrackCast.tpcNClsFound() < tpcClusters)
216+
lEnoughTPCNClsPos = kFALSE;
217+
if (negTrackCast.tpcNClsFound() < tpcClusters)
218+
lEnoughTPCNClsNeg = kFALSE;
219+
if (bachTrackCast.itsNCls() < itsClusters)
220+
lEnoughITSNClsBac = kFALSE;
221+
if (posTrackCast.itsNCls() < itsClusters)
222+
lEnoughITSNClsPos = kFALSE;
223+
if (negTrackCast.itsNCls() < itsClusters)
224+
lEnoughITSNClsNeg = kFALSE;
225+
226+
//Logic: either you have enough TPC clusters, OR you enabled ITSSA and have enough ITS clusters as requested
227+
//N.B.: This will require dedicated studies!
228+
229+
Bool_t lGoodCandidate = kFALSE;
230+
if (casc.sign() < 0) {
231+
if (
232+
(lEnoughTPCNClsBac || (allowITSSAbachelor && lEnoughITSNClsBac)) && //bachelor conditional
233+
(lEnoughTPCNClsPos || (allowITSSAproton && lEnoughITSNClsPos)) && //bachelor conditional
234+
(lEnoughTPCNClsNeg || (allowITSSApion && lEnoughITSNClsNeg)) //bachelor conditional
235+
) {
236+
lGoodCandidate = kTRUE;
237+
}
238+
}
239+
if (casc.sign() > 0) {
240+
if (
241+
(lEnoughTPCNClsBac || (allowITSSAbachelor && lEnoughITSNClsBac)) && //bachelor conditional
242+
(lEnoughTPCNClsPos || (allowITSSApion && lEnoughITSNClsPos)) && //bachelor conditional
243+
(lEnoughTPCNClsNeg || (allowITSSAproton && lEnoughITSNClsNeg)) //bachelor conditional
244+
) {
245+
lGoodCandidate = kTRUE;
246+
}
247+
}
248+
if (!lGoodCandidate)
249+
continue;
250+
registry.fill(HIST("hCandidateCounter"), 2.5); //okay track quality
251+
252+
if (casc.v0radius() > v0radius &&
253+
casc.cascradius() > cascradius &&
254+
casc.v0cosPA(pvx, pvy, pvz) > v0cospa &&
255+
casc.casccosPA(pvx, pvy, pvz) > casccospa &&
256+
casc.dcav0topv(pvx, pvy, pvz) > dcav0topv &&
257+
TMath::Abs(casc.mLambda() - 1.115683) < v0masswindow) {
258+
registry.fill(HIST("hCandidateCounter"), 3.5); //pass cascade selections
259+
if (casc.sign() < 0) {
260+
if (TMath::Abs(casc.yXi()) < 0.5 && ((!assocMC) || (lPDG == 3312))) {
261+
registry.fill(HIST("h2dMassXiMinus"), casc.template pt(), casc.template mXi());
262+
}
263+
if (TMath::Abs(casc.yOmega()) < 0.5 && ((!assocMC) || (lPDG == 3334))) {
264+
registry.fill(HIST("h2dMassOmegaMinus"), casc.template pt(), casc.template mOmega());
265+
}
266+
} else {
267+
if (TMath::Abs(casc.yXi()) < 0.5 && ((!assocMC) || (lPDG == -3312))) {
268+
registry.fill(HIST("h2dMassXiPlus"), casc.template pt(), casc.template mXi());
269+
}
270+
if (TMath::Abs(casc.yOmega()) < 0.5 && ((!assocMC) || (lPDG == -3334))) {
271+
registry.fill(HIST("h2dMassOmegaPlus"), casc.template pt(), casc.template mOmega());
272+
}
273+
}
274+
}
275+
}
276+
}
277+
278+
void processRun3(soa::Join<aod::Collisions, aod::EvSels>::iterator const& collision, soa::Filtered<LabeledCascades> const& Cascades, aod::V0sLinked const&, aod::V0Datas const&, FullTracksExtIU const&, aod::McParticles const&)
279+
//process function subscribing to Run 3-like analysis objects
280+
{
281+
//Run 3 event selection criteria
282+
if (eventSelection && !collision.sel8()) {
283+
return;
284+
}
285+
//fill cascade information with tracksIU typecast (Run 3)
286+
fillCascadeOutput<FullTracksExtIU>(Cascades, collision.posX(), collision.posY(), collision.posZ());
287+
}
288+
PROCESS_SWITCH(cascadeAnalysisMC, processRun3, "Process Run 3 data", true);
289+
290+
void processRun2(soa::Join<aod::Collisions, aod::EvSels, aod::CentRun2V0Ms>::iterator const& collision, soa::Filtered<LabeledCascades> const& Cascades, aod::V0sLinked const&, aod::V0Datas const&, FullTracksExt const&, aod::McParticles const&)
291+
//process function subscribing to Run 3-like analysis objects
292+
{
293+
//Run 2 event selection criteria
294+
if (eventSelection && !collision.alias()[kINT7]) {
295+
return;
296+
}
297+
if (eventSelection && !collision.sel7()) {
298+
return;
299+
}
300+
//fill cascade information with tracks typecast (Run 2)
301+
fillCascadeOutput<FullTracksExt>(Cascades, collision.posX(), collision.posY(), collision.posZ());
302+
}
303+
PROCESS_SWITCH(cascadeAnalysisMC, processRun2, "Process Run 2 data", false);
304+
};
305+
306+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
307+
{
308+
return WorkflowSpec{
309+
adaptAnalysisTask<cascadeAnalysisMC>(cfgc),
310+
adaptAnalysisTask<cascadeQaMC>(cfgc)};
311+
}

0 commit comments

Comments
 (0)