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