Skip to content

Commit 7f9ac54

Browse files
Sushanta TripathySushanta Tripathy
authored andcommitted
Add lambdastar-deuteron and f0-phi proxy tasks
1 parent ab4d79a commit 7f9ac54

3 files changed

Lines changed: 2413 additions & 0 deletions

File tree

‎PWGLF/Tasks/Resonances/CMakeLists.txt‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,13 @@ o2physics_add_dpl_workflow(xi1530kaoncorrelation
338338
SOURCES xi1530kaoncorrelation.cxx
339339
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
340340
COMPONENT_NAME Analysis)
341+
342+
o2physics_add_dpl_workflow(f0phiproxy
343+
SOURCES f0phiproxy.cxx
344+
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
345+
COMPONENT_NAME Analysis)
346+
347+
o2physics_add_dpl_workflow(lambdastarproxy
348+
SOURCES lambdastarproxy.cxx
349+
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
350+
COMPONENT_NAME Analysis)
Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
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
3+
// holders. 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 f0phiproxy.cxx
13+
/// \author Sushanta Tripathy
14+
/// \brief Dipion f0 candidates with a half-momentum kaon proxy and bachelor
15+
/// kaon.
16+
17+
#include "Common/DataModel/EventSelection.h"
18+
#include "Common/DataModel/Multiplicity.h"
19+
#include "Common/DataModel/PIDResponseTOF.h"
20+
#include "Common/DataModel/PIDResponseTPC.h"
21+
#include "Common/DataModel/TrackSelectionTables.h"
22+
23+
#include <CommonConstants/PhysicsConstants.h>
24+
#include <Framework/AnalysisTask.h>
25+
#include <Framework/HistogramRegistry.h>
26+
#include <Framework/runDataProcessing.h>
27+
28+
#include <Math/Vector4D.h>
29+
30+
#include <cmath>
31+
#include <cstdint>
32+
#include <deque>
33+
#include <map>
34+
#include <stdexcept>
35+
#include <utility>
36+
#include <vector>
37+
38+
using namespace o2;
39+
using namespace o2::framework;
40+
41+
struct F0phiproxy {
42+
using Collisions = soa::Join<aod::Collisions, aod::EvSels, aod::Mults>;
43+
using Tracks =
44+
soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA,
45+
aod::TrackSelection, aod::pidTPCFullPi, aod::pidTOFFullPi,
46+
aod::pidTPCFullKa, aod::pidTOFFullKa>;
47+
using FourVector = ROOT::Math::PxPyPzMVector;
48+
Preslice<Tracks> perCollision = aod::track::collisionId;
49+
HistogramRegistry histos{
50+
"histos",
51+
{},
52+
OutputObjHandlingPolicy::AnalysisObject};
53+
Configurable<float> vertexMax{"vertexMax", 10.f,
54+
"Maximum absolute vertex z (cm)"};
55+
Configurable<bool> requireSel8{"requireSel8", true, "Require sel8"};
56+
Configurable<bool> requireINELgt0{"requireINELgt0", true,
57+
"Require at least one PV track in |eta|<1"};
58+
Configurable<float> trackPtMin{"trackPtMin", 0.15f,
59+
"Minimum track pT (GeV/c)"};
60+
Configurable<float> trackEtaMax{"trackEtaMax", 0.8f, "Maximum track |eta|"};
61+
Configurable<bool> requireGlobalTrack{"requireGlobalTrack", true,
62+
"Require global track selection"};
63+
Configurable<bool> requirePVContributor{"requirePVContributor", true,
64+
"Require PV contributor"};
65+
Configurable<float> pionTPC{"pionTPC", 3.f, "Pion TPC nSigma cut"};
66+
Configurable<float> pionTOF{"pionTOF", 3.f, "Pion TOF veto when matched"};
67+
Configurable<float> kaonTPC{"kaonTPC", 3.f, "Kaon TPC nSigma cut"};
68+
Configurable<float> kaonTOF{"kaonTOF", 3.f, "Kaon TOF veto when matched"};
69+
Configurable<bool> requireTOF{"requireTOF", false, "Require TOF for both species instead of veto-only"};
70+
Configurable<float> dipionYMax{"dipionYMax", 0.5f, "Maximum dipion |y|"};
71+
Configurable<float> proxyYMax{"proxyYMax", 0.5f,
72+
"Maximum proxy+bachelor |y|"};
73+
Configurable<float> dipionMassMin{"dipionMassMin", 0.6f,
74+
"Lower dipion mass for proxy construction"};
75+
Configurable<float> dipionMassMax{"dipionMassMax", 1.4f,
76+
"Upper dipion mass for proxy construction"};
77+
Configurable<int> mixDepth{"mixDepth", 5, "Previous events per mixing bin; zero disables mixing"};
78+
Configurable<float> mixZWidth{"mixZWidth", 2.f, "Vertex bin width (cm)"};
79+
Configurable<float> mixMultWidth{"mixMultWidth", 20.f,
80+
"PV multiplicity bin width"};
81+
82+
struct TrackCandidate {
83+
int64_t id;
84+
int sign;
85+
double px, py, pz;
86+
bool hasTOF;
87+
FourVector vector(double mass) const
88+
{
89+
return FourVector(px, py, pz, mass);
90+
}
91+
};
92+
struct Event {
93+
std::vector<TrackCandidate> pions, kaons;
94+
};
95+
96+
void init(InitContext const&)
97+
{
98+
if (mixDepth < 0 || mixZWidth <= 0.f || mixMultWidth <= 0.f ||
99+
vertexMax <= 0.f || pionTPC <= 0.f || pionTOF <= 0.f ||
100+
kaonTPC <= 0.f || kaonTOF <= 0.f || dipionMassMin >= dipionMassMax) {
101+
throw std::runtime_error("Invalid F0PhiProxy configuration");
102+
}
103+
AxisSpec massPi{300, 0.2, 1.7, "m_{#pi#pi} (GeV/c^{2})"};
104+
AxisSpec massProxy{600, 0.9, 1.5, "m_{K,proxy K} (GeV/c^{2})"};
105+
AxisSpec pt{100, 0., 10., "p_{T} (GeV/c)"};
106+
AxisSpec mult{100, 0., 200., "N_{PV}(|#eta|<1)"};
107+
AxisSpec charge{3, -0.5, 2.5, "dipion: 0=unlike, 1=++, 2=--"};
108+
AxisSpec bachelorCharge{2, -1.5, 1.5, "bachelor charge"};
109+
AxisSpec tof{2, -0.5, 1.5, "bachelor has TOF"};
110+
histos.add("hEventSelection", "Received; selected", HistType::kTH1D,
111+
{{2, 0.5, 2.5}});
112+
histos.add("hMixPartners", "Mixing partners;N", HistType::kTH1D,
113+
{{101, -0.5, 100.5}});
114+
histos.add("hPionTPC", "Quality-selected tracks;pT;nSigmaTPC pion",
115+
HistType::kTH2F, {pt, {100, -10., 10.}});
116+
histos.add("hPionTOF", "TOF-matched quality tracks;pT;nSigmaTOF pion",
117+
HistType::kTH2F, {pt, {100, -10., 10.}});
118+
histos.add("hKaonTPC", "Quality-selected tracks;pT;nSigmaTPC kaon",
119+
HistType::kTH2F, {pt, {100, -10., 10.}});
120+
histos.add("hKaonTOF", "TOF-matched quality tracks;pT;nSigmaTOF kaon",
121+
HistType::kTH2F, {pt, {100, -10., 10.}});
122+
histos.add("hDipionSE", "Dipion SE", HistType::kTHnSparseF,
123+
{massPi, pt, mult, charge});
124+
histos.add("hDipionME", "Dipion ME (raw)", HistType::kTHnSparseF,
125+
{massPi, pt, mult, charge});
126+
// Keep measured dipion mass: no f0 identification by a mass window alone.
127+
histos.add("hProxySE", "Dipion plus bachelor proxy SE",
128+
HistType::kTHnSparseF,
129+
{massProxy, pt, massPi, mult, charge, bachelorCharge, tof});
130+
histos.add("hProxyME", "Intact same-event dipion plus mixed bachelor (raw)",
131+
HistType::kTHnSparseF,
132+
{massProxy, pt, massPi, mult, charge, bachelorCharge, tof});
133+
AxisSpec massKK{600, 0.9, 1.5, "m_{KK} (GeV/c^{2})"};
134+
histos.add("hPhiKK", "Unlike-sign kaon control SE", HistType::kTHnSparseF,
135+
{massKK, pt, mult});
136+
histos.add("hPhiKKLikePP", "K+K+ control SE", HistType::kTHnSparseF,
137+
{massKK, pt, mult});
138+
histos.add("hPhiKKLikeMM", "K-K- control SE", HistType::kTHnSparseF,
139+
{massKK, pt, mult});
140+
histos.add("hPhiKKMixed", "Unlike-sign kaon control ME (raw)", HistType::kTHnSparseF,
141+
{massKK, pt, mult});
142+
histos.add("hPhiKKMixedLikePP", "K+K+ control ME (raw)", HistType::kTHnSparseF,
143+
{massKK, pt, mult});
144+
histos.add("hPhiKKMixedLikeMM", "K-K- control ME (raw)", HistType::kTHnSparseF,
145+
{massKK, pt, mult});
146+
}
147+
148+
bool passPID(float tpc, float tof, bool matched, float tpcCut,
149+
float tofCut) const
150+
{
151+
return std::isfinite(tpc) && std::abs(tpc) < tpcCut &&
152+
(!requireTOF.value || matched) &&
153+
(!matched || (std::isfinite(tof) && std::abs(tof) < tofCut));
154+
}
155+
156+
static int chargeCategory(int a, int b)
157+
{
158+
return a != b ? 0 : (a > 0 ? 1 : 2);
159+
}
160+
161+
void fillProxy(FourVector const& dipion, TrackCandidate const& first,
162+
TrackCandidate const& second,
163+
std::vector<TrackCandidate> const& kaons, float mult,
164+
bool mixed)
165+
{
166+
const FourVector constituent(dipion.Px() * 0.5, dipion.Py() * 0.5,
167+
dipion.Pz() * 0.5,
168+
constants::physics::MassKaonCharged);
169+
const int category = chargeCategory(first.sign, second.sign);
170+
for (auto const& kaon : kaons) {
171+
if (!mixed && (kaon.id == first.id || kaon.id == second.id)) {
172+
continue;
173+
}
174+
const auto pair =
175+
constituent + kaon.vector(constants::physics::MassKaonCharged);
176+
if (std::abs(pair.Rapidity()) >= proxyYMax) {
177+
continue;
178+
}
179+
// The neutral dipion has no measured constituent-kaon charge: fill once
180+
// per bachelor.
181+
if (mixed) {
182+
histos.fill(HIST("hProxyME"), pair.M(), pair.Pt(), dipion.M(), mult,
183+
category, kaon.sign, kaon.hasTOF);
184+
} else {
185+
histos.fill(HIST("hProxySE"), pair.M(), pair.Pt(), dipion.M(), mult,
186+
category, kaon.sign, kaon.hasTOF);
187+
}
188+
}
189+
}
190+
191+
void fillPhiPair(TrackCandidate const& first, TrackCandidate const& second, float mult, bool mixed)
192+
{
193+
const auto pair = first.vector(constants::physics::MassKaonCharged) +
194+
second.vector(constants::physics::MassKaonCharged);
195+
if (std::abs(pair.Rapidity()) >= proxyYMax.value) {
196+
return;
197+
}
198+
if (mixed) {
199+
if (first.sign != second.sign) {
200+
histos.fill(HIST("hPhiKKMixed"), pair.M(), pair.Pt(), mult);
201+
} else if (first.sign > 0) {
202+
histos.fill(HIST("hPhiKKMixedLikePP"), pair.M(), pair.Pt(), mult);
203+
} else {
204+
histos.fill(HIST("hPhiKKMixedLikeMM"), pair.M(), pair.Pt(), mult);
205+
}
206+
} else {
207+
if (first.sign != second.sign) {
208+
histos.fill(HIST("hPhiKK"), pair.M(), pair.Pt(), mult);
209+
} else if (first.sign > 0) {
210+
histos.fill(HIST("hPhiKKLikePP"), pair.M(), pair.Pt(), mult);
211+
} else {
212+
histos.fill(HIST("hPhiKKLikeMM"), pair.M(), pair.Pt(), mult);
213+
}
214+
}
215+
}
216+
217+
void fillPhiControls(Event const& event, std::deque<Event> const& pool, float mult)
218+
{
219+
for (size_t i = 0; i < event.kaons.size(); ++i) {
220+
// Each same-event unordered pair is counted once.
221+
for (size_t j = i + 1; j < event.kaons.size(); ++j) {
222+
fillPhiPair(event.kaons[i], event.kaons[j], mult, false);
223+
}
224+
// Includes K+current K-previous and K-current K+previous once each.
225+
// Pool insertion occurs after this call; no event is mixed with itself.
226+
for (auto const& previous : pool) {
227+
for (auto const& second : previous.kaons) {
228+
fillPhiPair(event.kaons[i], second, mult, true);
229+
}
230+
}
231+
}
232+
}
233+
234+
void process(Collisions const& collisions, Tracks const& tracks,
235+
aod::BCsWithTimestamps const&)
236+
{
237+
// Local pools cannot retain track IDs across dataframes. Run is part of the
238+
// key.
239+
std::map<std::pair<int, std::pair<int, int>>, std::deque<Event>> pools;
240+
for (auto const& collision : collisions) {
241+
histos.fill(HIST("hEventSelection"), 1.);
242+
if (std::abs(collision.posZ()) >= vertexMax ||
243+
(requireSel8 && !collision.sel8()) ||
244+
(requireINELgt0 && collision.multNTracksPVeta1() < 1)) {
245+
continue;
246+
}
247+
histos.fill(HIST("hEventSelection"), 2.);
248+
const float mult = collision.multNTracksPVeta1();
249+
const int run = collision.bc_as<aod::BCsWithTimestamps>().runNumber();
250+
auto& pool =
251+
pools[{run,
252+
{static_cast<int>(std::floor(collision.posZ() / mixZWidth)),
253+
static_cast<int>(std::floor(mult / mixMultWidth))}}];
254+
Event event;
255+
auto selected = tracks.sliceBy(perCollision, collision.globalIndex());
256+
for (auto const& track : selected) {
257+
if (track.sign() == 0 || track.pt() < trackPtMin ||
258+
std::abs(track.eta()) >= trackEtaMax ||
259+
(requireGlobalTrack && !track.isGlobalTrack()) ||
260+
(requirePVContributor && !track.isPVContributor())) {
261+
continue;
262+
}
263+
const bool tof = track.hasTOF();
264+
histos.fill(HIST("hPionTPC"), track.pt(), track.tpcNSigmaPi());
265+
histos.fill(HIST("hKaonTPC"), track.pt(), track.tpcNSigmaKa());
266+
if (tof) {
267+
histos.fill(HIST("hPionTOF"), track.pt(), track.tofNSigmaPi());
268+
histos.fill(HIST("hKaonTOF"), track.pt(), track.tofNSigmaKa());
269+
}
270+
TrackCandidate candidate{track.globalIndex(), track.sign(), track.px(),
271+
track.py(), track.pz(), tof};
272+
if (passPID(track.tpcNSigmaPi(), track.tofNSigmaPi(), tof, pionTPC,
273+
pionTOF)) {
274+
event.pions.push_back(candidate);
275+
}
276+
if (passPID(track.tpcNSigmaKa(), track.tofNSigmaKa(), tof, kaonTPC,
277+
kaonTOF)) {
278+
event.kaons.push_back(candidate);
279+
}
280+
}
281+
histos.fill(HIST("hMixPartners"), pool.size());
282+
for (size_t i = 0; i < event.pions.size(); ++i) {
283+
auto const& first = event.pions[i];
284+
for (size_t j = i + 1; j < event.pions.size(); ++j) {
285+
auto const& second = event.pions[j];
286+
const auto pair = first.vector(constants::physics::MassPionCharged) +
287+
second.vector(constants::physics::MassPionCharged);
288+
if (std::abs(pair.Rapidity()) >= dipionYMax) {
289+
continue;
290+
}
291+
histos.fill(HIST("hDipionSE"), pair.M(), pair.Pt(), mult,
292+
chargeCategory(first.sign, second.sign));
293+
if (pair.M() < dipionMassMin || pair.M() >= dipionMassMax) {
294+
continue;
295+
}
296+
fillProxy(pair, first, second, event.kaons, mult, false);
297+
for (auto const& previous : pool) {
298+
fillProxy(pair, first, second, previous.kaons, mult, true);
299+
}
300+
}
301+
for (auto const& previous : pool) {
302+
for (auto const& second : previous.pions) {
303+
const auto pair =
304+
first.vector(constants::physics::MassPionCharged) +
305+
second.vector(constants::physics::MassPionCharged);
306+
if (std::abs(pair.Rapidity()) < dipionYMax) {
307+
histos.fill(HIST("hDipionME"), pair.M(), pair.Pt(), mult,
308+
chargeCategory(first.sign, second.sign));
309+
}
310+
}
311+
}
312+
}
313+
fillPhiControls(event, pool, mult);
314+
if (mixDepth > 0) {
315+
pool.push_back(std::move(event));
316+
if (pool.size() > static_cast<size_t>(mixDepth.value)) {
317+
pool.pop_front();
318+
}
319+
}
320+
}
321+
}
322+
};
323+
324+
WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
325+
{
326+
return WorkflowSpec{
327+
adaptAnalysisTask<F0phiproxy>(cfgc)};
328+
}

0 commit comments

Comments
 (0)