Skip to content

Commit 7b5749e

Browse files
mfagginMattia Faggin
andauthored
DPG/PWGHF: monitor single-track efficiency from HF decays (#6260)
* Loop on McParticles and manual collision grouping. * Add possibility to check only HF particles. * Add possibility to apply cut on vertex-z for gen. collision. * Add the code also in processMCWithoutCollisions. * Fix clang format and MegaLinter. --------- Co-authored-by: Mattia Faggin <mfaggin@cern.ch>
1 parent 83f510b commit 7b5749e

1 file changed

Lines changed: 189 additions & 99 deletions

File tree

DPG/Tasks/AOTTrack/qaEfficiency.cxx

Lines changed: 189 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "Common/Core/TrackSelectionDefaults.h"
2929
#include "Common/DataModel/TrackSelectionTables.h"
3030
#include "PWGLF/DataModel/LFParticleIdentification.h"
31+
#include "Common/Core/RecoDecay.h"
3132

3233
// ROOT includes
3334
#include "TPDGCode.h"
@@ -430,13 +431,16 @@ struct QaEfficiency {
430431
// Selection on mothers
431432
Configurable<bool> checkForMothers{"checkForMothers", false, "Flag to use the array of mothers to check if the particle of interest come from any of those particles"};
432433
Configurable<std::vector<int>> mothersPDGs{"mothersPDGs", std::vector<int>{3312, -3312}, "PDGs of origin of the particle under study"};
434+
Configurable<bool> keepOnlyHfParticles{"keepOnlyHfParticles", false, "Flag to decide wheter to consider only HF particles"};
433435
// Track only selection, options to select only specific tracks
434436
Configurable<bool> trackSelection{"trackSelection", true, "Local track selection"};
435437
Configurable<int> globalTrackSelection{"globalTrackSelection", 0, "Global track selection: 0 -> No Cut, 1 -> kGlobalTrack, 2 -> kGlobalTrackWoPtEta, 3 -> kGlobalTrackWoDCA, 4 -> kQualityTracks, 5 -> kInAcceptanceTracks, 6 -> custom track cuts via Configurable"};
436438
// Event selection
437439
Configurable<int> nMinNumberOfContributors{"nMinNumberOfContributors", 2, "Minimum required number of contributors to the primary vertex"};
438-
Configurable<float> vertexZMin{"vertex-z-min", -10.f, "Minimum position of the generated vertez in Z (cm)"};
439-
Configurable<float> vertexZMax{"vertex-z-max", 10.f, "Maximum position of the generated vertez in Z (cm)"};
440+
Configurable<float> vertexZMin{"vertex-z-min", -10.f, "Minimum position of the primary vertez in Z (cm)"};
441+
Configurable<float> vertexZMax{"vertex-z-max", 10.f, "Maximum position of the primary vertez in Z (cm)"};
442+
Configurable<bool> applyPvZCutGenColl{"applyPvZCutGenColl", false, "Flag to enable the cut on the generated vertex z coordinate"};
443+
Configurable<bool> applyPvZCutInProcessMcWoColl{"applyPvZCutInProcessMcWoColl", false, "Flag to enable the cut on the vertex z coordinate (reco. & gen.) also in processMCWithoutCollisions"};
440444
// Histogram configuration
441445
ConfigurableAxis ptBins{"ptBins", {200, 0.f, 5.f}, "Pt binning"};
442446
Configurable<int> logPt{"log-pt", 0, "Flag to use a logarithmic pT axis"};
@@ -1750,141 +1754,213 @@ struct QaEfficiency {
17501754
}
17511755

17521756
// MC process
1757+
// Single-track efficiency calculated only for MC collisions with at least 1 reco. collision
17531758
SliceCache cache;
17541759
Preslice<o2::aod::Tracks> perCollision = o2::aod::track::collisionId;
17551760
Preslice<o2::aod::McParticles> perCollisionMc = o2::aod::mcparticle::mcCollisionId;
1756-
void processMC(o2::aod::McCollision const&,
1757-
o2::soa::SmallGroups<o2::soa::Join<o2::aod::Collisions, o2::aod::McCollisionLabels, o2::aod::EvSels>> const& collisions,
1761+
PresliceUnsorted<o2::soa::Join<o2::aod::Collisions, o2::aod::McCollisionLabels, o2::aod::EvSels>> collPerCollMc = o2::aod::mccollisionlabel::mcCollisionId;
1762+
void processMC(o2::aod::McCollisions const& mcCollisions,
1763+
// o2::soa::SmallGroups<o2::soa::Join<o2::aod::Collisions, o2::aod::McCollisionLabels, o2::aod::EvSels>> const& collisions,
1764+
o2::soa::Join<o2::aod::Collisions, o2::aod::McCollisionLabels, o2::aod::EvSels> const& collisions,
17581765
o2::soa::Join<TrackCandidates, o2::aod::McTrackLabels> const& tracks,
17591766
o2::aod::McParticles const& mcParticles)
17601767
{
1761-
histos.fill(HIST("MC/generatedCollisions"), 1);
17621768

1763-
if (collisions.size() < 1) { // Skipping MC events that have no reconstructed collisions
1764-
return;
1765-
}
1766-
histos.fill(HIST("MC/generatedCollisions"), 2);
1767-
if (skipEventsWithoutTPCTracks) {
1768-
int nTPCTracks = 0;
1769-
for (const auto& collision : collisions) {
1770-
const auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex());
1771-
for (const auto& track : groupedTracks) {
1772-
if (track.hasTPC()) {
1773-
nTPCTracks++;
1774-
break;
1769+
/// loop over generated collisions
1770+
for (const auto& mcCollision : mcCollisions) {
1771+
histos.fill(HIST("MC/generatedCollisions"), 1);
1772+
1773+
const auto groupedCollisions = collisions.sliceBy(collPerCollMc, mcCollision.globalIndex());
1774+
const auto groupedMcParticles = mcParticles.sliceBy(perCollisionMc, mcCollision.globalIndex());
1775+
1776+
// LOG(info) << "groupedCollisions.size() " << groupedCollisions.size();
1777+
1778+
if (groupedCollisions.size() < 1) { // Skipping MC events that have no reconstructed collisions
1779+
continue;
1780+
}
1781+
histos.fill(HIST("MC/generatedCollisions"), 2);
1782+
if (skipEventsWithoutTPCTracks) {
1783+
int nTPCTracks = 0;
1784+
for (const auto& collision : groupedCollisions) {
1785+
const auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex());
1786+
for (const auto& track : groupedTracks) {
1787+
if (track.hasTPC()) {
1788+
nTPCTracks++;
1789+
break;
1790+
}
17751791
}
17761792
}
1793+
if (nTPCTracks == 0) {
1794+
LOG(info) << "Skipping event with no TPC tracks";
1795+
continue;
1796+
}
17771797
}
1778-
if (nTPCTracks == 0) {
1779-
LOG(info) << "Skipping event with no TPC tracks";
1780-
return;
1781-
}
1782-
}
1783-
histos.fill(HIST("MC/generatedCollisions"), 3);
1798+
histos.fill(HIST("MC/generatedCollisions"), 3);
17841799

1785-
for (const auto& collision : collisions) {
1786-
histos.fill(HIST("MC/generatedCollisions"), 4);
1787-
if (!isCollisionSelected<false>(collision)) {
1788-
continue;
1789-
}
1790-
histos.fill(HIST("MC/generatedCollisions"), 5);
1800+
/// loop over reconstructed collisions
1801+
for (const auto& collision : groupedCollisions) {
1802+
histos.fill(HIST("MC/generatedCollisions"), 4);
1803+
if (!isCollisionSelected<false>(collision)) {
1804+
continue;
1805+
}
1806+
histos.fill(HIST("MC/generatedCollisions"), 5);
17911807

1792-
const auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex());
1808+
const auto groupedTracks = tracks.sliceBy(perCollision, collision.globalIndex());
17931809

1794-
// Track loop
1795-
for (const auto& track : groupedTracks) {
1796-
if (!isTrackSelected(track, HIST("MC/trackSelection"))) {
1810+
// Track loop
1811+
for (const auto& track : groupedTracks) {
1812+
if (!isTrackSelected(track, HIST("MC/trackSelection"))) {
1813+
continue;
1814+
}
1815+
1816+
// search for particles from HF decays
1817+
// no need to check if track.has_mcParticle() == true, this is done already in isTrackSelected
1818+
const auto& particle = track.mcParticle();
1819+
if (keepOnlyHfParticles && !RecoDecay::getCharmHadronOrigin(mcParticles, particle, /*searchUpToQuark*/ true)) {
1820+
continue;
1821+
}
1822+
1823+
// Filling variable histograms
1824+
histos.fill(HIST("MC/trackLength"), track.length());
1825+
static_for<0, 1>([&](auto pdgSign) {
1826+
fillMCTrackHistograms<pdgSign, o2::track::PID::Electron>(track, doEl);
1827+
fillMCTrackHistograms<pdgSign, o2::track::PID::Muon>(track, doMu);
1828+
fillMCTrackHistograms<pdgSign, o2::track::PID::Pion>(track, doPi);
1829+
fillMCTrackHistograms<pdgSign, o2::track::PID::Kaon>(track, doKa);
1830+
fillMCTrackHistograms<pdgSign, o2::track::PID::Proton>(track, doPr);
1831+
fillMCTrackHistograms<pdgSign, o2::track::PID::Deuteron>(track, doDe);
1832+
fillMCTrackHistograms<pdgSign, o2::track::PID::Triton>(track, doTr);
1833+
fillMCTrackHistograms<pdgSign, o2::track::PID::Helium3>(track, doHe);
1834+
fillMCTrackHistograms<pdgSign, o2::track::PID::Alpha>(track, doAl);
1835+
});
1836+
}
1837+
1838+
// Skipping collisions without the generated collisions
1839+
// Actually this should never happen, since we group per MC collision
1840+
if (!collision.has_mcCollision()) {
17971841
continue;
1842+
} else {
1843+
// skip generated collisions outside the allowed vtx-z range
1844+
// putting this condition here avoids the particle loop a few lines below
1845+
if (applyPvZCutGenColl) {
1846+
const float genPvZ = mcCollision.posZ();
1847+
if (genPvZ < vertexZMin || genPvZ > vertexZMax) {
1848+
continue;
1849+
}
1850+
}
17981851
}
1799-
// Filling variable histograms
1800-
histos.fill(HIST("MC/trackLength"), track.length());
1801-
static_for<0, 1>([&](auto pdgSign) {
1802-
fillMCTrackHistograms<pdgSign, o2::track::PID::Electron>(track, doEl);
1803-
fillMCTrackHistograms<pdgSign, o2::track::PID::Muon>(track, doMu);
1804-
fillMCTrackHistograms<pdgSign, o2::track::PID::Pion>(track, doPi);
1805-
fillMCTrackHistograms<pdgSign, o2::track::PID::Kaon>(track, doKa);
1806-
fillMCTrackHistograms<pdgSign, o2::track::PID::Proton>(track, doPr);
1807-
fillMCTrackHistograms<pdgSign, o2::track::PID::Deuteron>(track, doDe);
1808-
fillMCTrackHistograms<pdgSign, o2::track::PID::Triton>(track, doTr);
1809-
fillMCTrackHistograms<pdgSign, o2::track::PID::Helium3>(track, doHe);
1810-
fillMCTrackHistograms<pdgSign, o2::track::PID::Alpha>(track, doAl);
1811-
});
1812-
}
18131852

1814-
// Skipping collisions without the generated collisions
1815-
if (!collision.has_mcCollision()) {
1816-
continue;
1853+
/// only to fill denominator of ITS-TPC matched primary tracks only in MC events with at least 1 reco. vtx
1854+
for (const auto& particle : groupedMcParticles) { // Particle loop
1855+
1856+
/// require generated particle in acceptance
1857+
if (!isInAcceptance<true, false>(particle, nullptr)) {
1858+
continue;
1859+
}
1860+
1861+
// search for particles from HF decays
1862+
if (keepOnlyHfParticles && !RecoDecay::getCharmHadronOrigin(mcParticles, particle, /*searchUpToQuark*/ true)) {
1863+
continue;
1864+
}
1865+
1866+
static_for<0, 1>([&](auto pdgSign) {
1867+
fillMCParticleHistograms<pdgSign, o2::track::PID::Electron, true>(particle, doEl);
1868+
fillMCParticleHistograms<pdgSign, o2::track::PID::Muon, true>(particle, doMu);
1869+
fillMCParticleHistograms<pdgSign, o2::track::PID::Pion, true>(particle, doPi);
1870+
fillMCParticleHistograms<pdgSign, o2::track::PID::Kaon, true>(particle, doKa);
1871+
fillMCParticleHistograms<pdgSign, o2::track::PID::Proton, true>(particle, doPr);
1872+
fillMCParticleHistograms<pdgSign, o2::track::PID::Deuteron, true>(particle, doDe);
1873+
fillMCParticleHistograms<pdgSign, o2::track::PID::Triton, true>(particle, doTr);
1874+
fillMCParticleHistograms<pdgSign, o2::track::PID::Helium3, true>(particle, doHe);
1875+
fillMCParticleHistograms<pdgSign, o2::track::PID::Alpha, true>(particle, doAl);
1876+
});
1877+
}
1878+
} /// end loop over reconstructed collisions
1879+
1880+
// skip generated collisions outside the allowed vtx-z range
1881+
// putting this condition here avoids the particle loop a few lines below
1882+
if (applyPvZCutGenColl) {
1883+
const float genPvZ = mcCollision.posZ();
1884+
if (genPvZ < vertexZMin || genPvZ > vertexZMax) {
1885+
continue;
1886+
}
18171887
}
18181888

1819-
for (const auto& particle : mcParticles) { // Particle loop
1889+
// Loop on particles to fill the denominator
1890+
float dNdEta = 0; // Multiplicity
1891+
for (const auto& mcParticle : groupedMcParticles) {
1892+
if (TMath::Abs(mcParticle.eta()) <= 2.f && !mcParticle.has_daughters()) {
1893+
dNdEta += 1.f;
1894+
}
1895+
if (!isInAcceptance(mcParticle, HIST("MC/particleSelection"))) {
1896+
continue;
1897+
}
18201898

1821-
/// require generated particle in acceptance
1822-
if (!isInAcceptance<true, false>(particle, nullptr)) {
1899+
// search for particles from HF decays
1900+
if (keepOnlyHfParticles && !RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, /*searchUpToQuark*/ true)) {
18231901
continue;
18241902
}
18251903

18261904
static_for<0, 1>([&](auto pdgSign) {
1827-
fillMCParticleHistograms<pdgSign, o2::track::PID::Electron, true>(particle, doEl);
1828-
fillMCParticleHistograms<pdgSign, o2::track::PID::Muon, true>(particle, doMu);
1829-
fillMCParticleHistograms<pdgSign, o2::track::PID::Pion, true>(particle, doPi);
1830-
fillMCParticleHistograms<pdgSign, o2::track::PID::Kaon, true>(particle, doKa);
1831-
fillMCParticleHistograms<pdgSign, o2::track::PID::Proton, true>(particle, doPr);
1832-
fillMCParticleHistograms<pdgSign, o2::track::PID::Deuteron, true>(particle, doDe);
1833-
fillMCParticleHistograms<pdgSign, o2::track::PID::Triton, true>(particle, doTr);
1834-
fillMCParticleHistograms<pdgSign, o2::track::PID::Helium3, true>(particle, doHe);
1835-
fillMCParticleHistograms<pdgSign, o2::track::PID::Alpha, true>(particle, doAl);
1905+
fillMCParticleHistograms<pdgSign, o2::track::PID::Electron>(mcParticle, doEl);
1906+
fillMCParticleHistograms<pdgSign, o2::track::PID::Muon>(mcParticle, doMu);
1907+
fillMCParticleHistograms<pdgSign, o2::track::PID::Pion>(mcParticle, doPi);
1908+
fillMCParticleHistograms<pdgSign, o2::track::PID::Kaon>(mcParticle, doKa);
1909+
fillMCParticleHistograms<pdgSign, o2::track::PID::Proton>(mcParticle, doPr);
1910+
fillMCParticleHistograms<pdgSign, o2::track::PID::Deuteron>(mcParticle, doDe);
1911+
fillMCParticleHistograms<pdgSign, o2::track::PID::Triton>(mcParticle, doTr);
1912+
fillMCParticleHistograms<pdgSign, o2::track::PID::Helium3>(mcParticle, doHe);
1913+
fillMCParticleHistograms<pdgSign, o2::track::PID::Alpha>(mcParticle, doAl);
18361914
});
18371915
}
1838-
}
1839-
1840-
// Loop on particles to fill the denominator
1841-
float dNdEta = 0; // Multiplicity
1842-
for (const auto& mcParticle : mcParticles) {
1843-
if (TMath::Abs(mcParticle.eta()) <= 2.f && !mcParticle.has_daughters()) {
1844-
dNdEta += 1.f;
1845-
}
1846-
if (!isInAcceptance(mcParticle, HIST("MC/particleSelection"))) {
1847-
continue;
1848-
}
1916+
histos.fill(HIST("MC/eventMultiplicity"), dNdEta * 0.5f / 2.f);
18491917

1918+
// Fill TEfficiencies
18501919
static_for<0, 1>([&](auto pdgSign) {
1851-
fillMCParticleHistograms<pdgSign, o2::track::PID::Electron>(mcParticle, doEl);
1852-
fillMCParticleHistograms<pdgSign, o2::track::PID::Muon>(mcParticle, doMu);
1853-
fillMCParticleHistograms<pdgSign, o2::track::PID::Pion>(mcParticle, doPi);
1854-
fillMCParticleHistograms<pdgSign, o2::track::PID::Kaon>(mcParticle, doKa);
1855-
fillMCParticleHistograms<pdgSign, o2::track::PID::Proton>(mcParticle, doPr);
1856-
fillMCParticleHistograms<pdgSign, o2::track::PID::Deuteron>(mcParticle, doDe);
1857-
fillMCParticleHistograms<pdgSign, o2::track::PID::Triton>(mcParticle, doTr);
1858-
fillMCParticleHistograms<pdgSign, o2::track::PID::Helium3>(mcParticle, doHe);
1859-
fillMCParticleHistograms<pdgSign, o2::track::PID::Alpha>(mcParticle, doAl);
1920+
fillMCEfficiency<pdgSign, o2::track::PID::Electron>(doEl);
1921+
fillMCEfficiency<pdgSign, o2::track::PID::Muon>(doMu);
1922+
fillMCEfficiency<pdgSign, o2::track::PID::Pion>(doPi);
1923+
fillMCEfficiency<pdgSign, o2::track::PID::Kaon>(doKa);
1924+
fillMCEfficiency<pdgSign, o2::track::PID::Proton>(doPr);
1925+
fillMCEfficiency<pdgSign, o2::track::PID::Deuteron>(doDe);
1926+
fillMCEfficiency<pdgSign, o2::track::PID::Triton>(doTr);
1927+
fillMCEfficiency<pdgSign, o2::track::PID::Helium3>(doHe);
1928+
fillMCEfficiency<pdgSign, o2::track::PID::Alpha>(doAl);
18601929
});
1861-
}
1862-
histos.fill(HIST("MC/eventMultiplicity"), dNdEta * 0.5f / 2.f);
1863-
1864-
// Fill TEfficiencies
1865-
static_for<0, 1>([&](auto pdgSign) {
1866-
fillMCEfficiency<pdgSign, o2::track::PID::Electron>(doEl);
1867-
fillMCEfficiency<pdgSign, o2::track::PID::Muon>(doMu);
1868-
fillMCEfficiency<pdgSign, o2::track::PID::Pion>(doPi);
1869-
fillMCEfficiency<pdgSign, o2::track::PID::Kaon>(doKa);
1870-
fillMCEfficiency<pdgSign, o2::track::PID::Proton>(doPr);
1871-
fillMCEfficiency<pdgSign, o2::track::PID::Deuteron>(doDe);
1872-
fillMCEfficiency<pdgSign, o2::track::PID::Triton>(doTr);
1873-
fillMCEfficiency<pdgSign, o2::track::PID::Helium3>(doHe);
1874-
fillMCEfficiency<pdgSign, o2::track::PID::Alpha>(doAl);
1875-
});
1930+
} /// end loop over generated collisions
18761931
}
18771932
PROCESS_SWITCH(QaEfficiency, processMC, "process MC", false);
18781933

18791934
// MC process without the collision association
1880-
void processMCWithoutCollisions(o2::soa::Join<TrackCandidates, o2::aod::McTrackLabels> const& tracks,
1881-
o2::aod::McParticles const& mcParticles)
1935+
// Single-track efficiency calculated:
1936+
// - considering also MC collisions without any reco. collision
1937+
// - considering also tracks not associated to any collision
1938+
// - ignoring the track-to-collision association
1939+
void processMCWithoutCollisions(o2::soa::Join<TrackCandidates, o2::aod::McTrackLabels> const& tracks, o2::aod::Collisions const&,
1940+
o2::aod::McParticles const& mcParticles, o2::aod::McCollisions const&)
18821941
{
18831942
// Track loop
18841943
for (const auto& track : tracks) {
18851944
if (!isTrackSelected(track, HIST("MC/trackSelection"))) {
18861945
continue;
18871946
}
1947+
1948+
/// checking the PV z coordinate, if the track has been assigned to any collision
1949+
if (applyPvZCutInProcessMcWoColl && track.has_collision()) {
1950+
const auto collision = track.collision();
1951+
const float posZ = collision.posZ();
1952+
if (posZ < vertexZMin || posZ > vertexZMax) {
1953+
continue;
1954+
}
1955+
}
1956+
1957+
// search for particles from HF decays
1958+
// no need to check if track.has_mcParticle() == true, this is done already in isTrackSelected
1959+
const auto& particle = track.mcParticle();
1960+
if (keepOnlyHfParticles && !RecoDecay::getCharmHadronOrigin(mcParticles, particle, /*searchUpToQuark*/ true)) {
1961+
continue;
1962+
}
1963+
18881964
// Filling variable histograms
18891965
histos.fill(HIST("MC/trackLength"), track.length());
18901966
static_for<0, 1>([&](auto pdgSign) {
@@ -1905,6 +1981,20 @@ struct QaEfficiency {
19051981
continue;
19061982
}
19071983

1984+
/// checking the PV z coordinate for the generated collision
1985+
if (applyPvZCutInProcessMcWoColl && applyPvZCutGenColl) {
1986+
const auto mcCollision = mcParticle.mcCollision();
1987+
const float posZ = mcCollision.posZ();
1988+
if (posZ < vertexZMin || posZ > vertexZMax) {
1989+
continue;
1990+
}
1991+
}
1992+
1993+
// search for particles from HF decays
1994+
if (keepOnlyHfParticles && !RecoDecay::getCharmHadronOrigin(mcParticles, mcParticle, /*searchUpToQuark*/ true)) {
1995+
continue;
1996+
}
1997+
19081998
static_for<0, 1>([&](auto pdgSign) {
19091999
fillMCParticleHistograms<pdgSign, o2::track::PID::Electron>(mcParticle, doEl);
19102000
fillMCParticleHistograms<pdgSign, o2::track::PID::Muon>(mcParticle, doMu);

0 commit comments

Comments
 (0)