diff --git a/PWGCF/DataModel/CorrelationsDerived.h b/PWGCF/DataModel/CorrelationsDerived.h index 5f88fc15c6f..2542a2e416a 100644 --- a/PWGCF/DataModel/CorrelationsDerived.h +++ b/PWGCF/DataModel/CorrelationsDerived.h @@ -8,8 +8,8 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef O2_ANALYSIS_CFDERIVED_H -#define O2_ANALYSIS_CFDERIVED_H +#ifndef PWGCF_DATAMODEL_CORRELATIONSDERIVED_H_ +#define PWGCF_DATAMODEL_CORRELATIONSDERIVED_H_ #include "Framework/ASoA.h" #include "Framework/AnalysisDataModel.h" @@ -79,6 +79,42 @@ using CFTrack = CFTracks::iterator; using CFTrackLabel = CFTrackLabels::iterator; using CFTracksWithLabel = soa::Join; using CFTrackWithLabel = CFTracksWithLabel::iterator; + +//------transient CF-filter to CF-2prong-filter +DECLARE_SOA_TABLE(CFCollRefs, "AOD", "CFCOLLREF", o2::soa::Index<>, track::CollisionId); //! Transient cf collision index table + +using CFCollRef = CFCollRefs::iterator; + +namespace cftrackref +{ +DECLARE_SOA_INDEX_COLUMN(Track, track); +} // namespace cftrackref +DECLARE_SOA_TABLE(CFTrackRefs, "AOD", "CFTRACKREF", o2::soa::Index<>, track::CollisionId, cftrackref::TrackId); //! Transient cf track index table + +using CFTrackRef = CFTrackRefs::iterator; +//------ + +namespace cf2prongtrack +{ +DECLARE_SOA_INDEX_COLUMN_FULL(CFTrackProng0, cfTrackProng0, int, CFTracks, "_0"); //! Index to prong 1 CFTrack +DECLARE_SOA_INDEX_COLUMN_FULL(CFTrackProng1, cfTrackProng1, int, CFTracks, "_1"); //! Index to prong 2 CFTrack +DECLARE_SOA_COLUMN(Pt, pt, float); //! pT (GeV/c) +DECLARE_SOA_COLUMN(Eta, eta, float); //! Pseudorapidity +DECLARE_SOA_COLUMN(Phi, phi, float); //! Phi angle +DECLARE_SOA_COLUMN(Decay, decay, uint8_t); //! Particle decay +enum ParticleDecay { + D0ToPiK, + JPsiToEE, + JPsiToMuMu +}; +} // namespace cf2prongtrack +DECLARE_SOA_TABLE(CF2ProngTracks, "AOD", "CF2PRONGTRACK", //! Reduced track table + o2::soa::Index<>, + cftrack::CFCollisionId, + cf2prongtrack::CFTrackProng0Id, + cf2prongtrack::CFTrackProng1Id, + cf2prongtrack::Pt, cf2prongtrack::Eta, cf2prongtrack::Phi, cf2prongtrack::Decay); +using CF2ProngTrack = CF2ProngTracks::iterator; } // namespace o2::aod -#endif // O2_ANALYSIS_CFDERIVED_H +#endif // PWGCF_DATAMODEL_CORRELATIONSDERIVED_H_ diff --git a/PWGCF/TableProducer/CMakeLists.txt b/PWGCF/TableProducer/CMakeLists.txt index 4a90ccdea3d..1bfef915ff3 100644 --- a/PWGCF/TableProducer/CMakeLists.txt +++ b/PWGCF/TableProducer/CMakeLists.txt @@ -14,7 +14,12 @@ o2physics_add_dpl_workflow(filter-correlations PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) +o2physics_add_dpl_workflow(filter-correlations-2prong + SOURCES filter2Prong.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) + o2physics_add_dpl_workflow(dptdpt-filter SOURCES dptdptfilter.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore - COMPONENT_NAME Analysis) \ No newline at end of file + COMPONENT_NAME Analysis) diff --git a/PWGCF/TableProducer/filter2Prong.cxx b/PWGCF/TableProducer/filter2Prong.cxx new file mode 100644 index 00000000000..00584f804f5 --- /dev/null +++ b/PWGCF/TableProducer/filter2Prong.cxx @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" + +#include "MathUtils/detail/TypeTruncation.h" + +#include "PWGCF/DataModel/CorrelationsDerived.h" + +#include "PWGHF/Core/HfHelper.h" +#include "PWGHF/DataModel/CandidateReconstructionTables.h" +#include "PWGHF/DataModel/CandidateSelectionTables.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using namespace o2::math_utils::detail; + +#define FLOAT_PRECISION 0xFFFFFFF0 +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct Filter2Prong { + O2_DEFINE_CONFIGURABLE(cfgVerbosity, int, 0, "Verbosity level (0 = major, 1 = per collision)") + + Produces output2ProngTracks; + + using HFCandidates = soa::Join; + void processData(aod::Collisions::iterator const& collision, aod::BCsWithTimestamps const&, aod::CFCollRefs const& cfcollisions, aod::CFTrackRefs const& cftracks, HFCandidates const& candidates) + { + if (cfcollisions.size() <= 0 || cftracks.size() <= 0) + return; // rejected collision + if (cfgVerbosity > 0 && candidates.size() > 0) + LOGF(info, "Candidates for collision: %lu, cfcollisions: %lu, CFTracks: %lu", candidates.size(), cfcollisions.size(), cftracks.size()); + for (auto& c : candidates) { + int prongCFId[2] = {-1, -1}; + for (auto& cftrack : cftracks) { + if (c.prong0Id() == cftrack.trackId()) { + prongCFId[0] = cftrack.globalIndex(); + break; + } + } + for (auto& cftrack : cftracks) { + if (c.prong1Id() == cftrack.trackId()) { + prongCFId[1] = cftrack.globalIndex(); + break; + } + } + // look-up the collision id + auto collisionId = cfcollisions.begin().globalIndex(); + if ((c.hfflag() & (1 << aod::hf_cand_2prong::DecayType::D0ToPiK)) == 0) + continue; + output2ProngTracks(collisionId, + prongCFId[0], prongCFId[1], c.pt(), c.eta(), c.phi(), aod::cf2prongtrack::D0ToPiK); + } + } + PROCESS_SWITCH(Filter2Prong, processData, "Process data D0 candidates", true); +}; // struct + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc, TaskName{"filter-2prong"})}; +} diff --git a/PWGCF/TableProducer/filterCorrelations.cxx b/PWGCF/TableProducer/filterCorrelations.cxx index 24c398289e4..686145f3738 100644 --- a/PWGCF/TableProducer/filterCorrelations.cxx +++ b/PWGCF/TableProducer/filterCorrelations.cxx @@ -55,6 +55,7 @@ struct FilterCF { O2_DEFINE_CONFIGURABLE(cfgVerbosity, int, 1, "Verbosity level (0 = major, 1 = per collision)") O2_DEFINE_CONFIGURABLE(cfgTrigger, int, 7, "Trigger choice: (0 = none, 7 = sel7, 8 = sel8)") O2_DEFINE_CONFIGURABLE(cfgCollisionFlags, uint16_t, aod::collision::CollisionFlagsRun2::Run2VertexerTracks, "Request collision flags if non-zero (0 = off, 1 = Run2VertexerTracks)") + O2_DEFINE_CONFIGURABLE(cfgTransientTables, bool, false, "Output transient tables for collision and track IDs") // Filters and input definitions Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgCutVertex; @@ -78,6 +79,9 @@ struct FilterCF { Produces outputMcCollisions; Produces outputMcParticles; + Produces outputCollRefs; + Produces outputTrackRefs; + template bool keepCollision(TCollision& collision) { @@ -104,6 +108,9 @@ struct FilterCF { auto bc = collision.bc_as(); outputCollisions(bc.runNumber(), collision.posZ(), collision.multiplicity(), bc.timestamp()); + if (cfgTransientTables) + outputCollRefs(collision.globalIndex()); + for (auto& track : tracks) { uint8_t trackType = 0; if (track.isGlobalTrack()) { @@ -113,6 +120,8 @@ struct FilterCF { } outputTracks(outputCollisions.lastIndex(), track.pt(), track.eta(), track.phi(), track.sign(), trackType); + if (cfgTransientTables) + outputTrackRefs(collision.globalIndex(), track.globalIndex()); yields->Fill(collision.multiplicity(), track.pt(), track.eta()); etaphi->Fill(collision.multiplicity(), track.eta(), track.phi()); diff --git a/PWGCF/Tasks/correlations.cxx b/PWGCF/Tasks/correlations.cxx index 6986c0bf4fc..0cbbfba5f39 100644 --- a/PWGCF/Tasks/correlations.cxx +++ b/PWGCF/Tasks/correlations.cxx @@ -8,11 +8,18 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include + +#include +#include +#include +#include + #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include "Framework/AnalysisDataModel.h" #include "Framework/ASoAHelpers.h" -#include +#include "CCDB/BasicCCDBManager.h" #include "Framework/StepTHn.h" #include "Framework/HistogramRegistry.h" #include "Framework/RunningWorkflowInfo.h" @@ -27,11 +34,6 @@ #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsParameters/GRPMagField.h" -#include -#include -#include -#include - using namespace o2; using namespace o2::framework; using namespace o2::framework::expressions; @@ -78,6 +80,8 @@ struct CorrelationTask { O2_DEFINE_CONFIGURABLE(cfgVerbosity, int, 1, "Verbosity level (0 = major, 1 = per collision)") + O2_DEFINE_CONFIGURABLE(cfgDecayParticleMask, int, 0, "Selection bitmask for the decay particles: 0 = no selection") + ConfigurableAxis axisVertex{"axisVertex", {7, -7, 7}, "vertex axis for histograms"}; ConfigurableAxis axisDeltaPhi{"axisDeltaPhi", {72, -PIHalf, PIHalf * 3}, "delta phi axis for histograms"}; ConfigurableAxis axisDeltaEta{"axisDeltaEta", {40, -2, 2}, "delta eta axis for histograms"}; @@ -102,6 +106,9 @@ struct CorrelationTask { Filter cfMCCollisionFilter = nabs(aod::mccollision::posZ) < cfgCutVertex; Filter cfMCParticleFilter = (nabs(aod::cfmcparticle::eta) < cfgCutEta) && (aod::cfmcparticle::pt > cfgCutPt) && (aod::cfmcparticle::sign != 0); + // HF filters + Filter track2pFilter = (aod::cf2prongtrack::eta < cfgCutEta) && (aod::cf2prongtrack::pt > cfgCutPt); + // Output definitions OutputObj same{"sameEvent"}; OutputObj mixed{"mixedEvent"}; @@ -128,6 +135,10 @@ struct CorrelationTask { { registry.add("yields", "multiplicity/centrality vs pT vs eta", {HistType::kTH3F, {{100, 0, 100, "/multiplicity/centrality"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"}}}); registry.add("etaphi", "multiplicity/centrality vs eta vs phi", {HistType::kTH3F, {{100, 0, 100, "multiplicity/centrality"}, {100, -2, 2, "#eta"}, {200, 0, 2 * M_PI, "#varphi"}}}); + if (doprocessSame2ProngDerived) { + registry.add("yieldsTrack2", "multiplicity/centrality vs pT vs eta (track2)", {HistType::kTH3F, {{100, 0, 100, "/multiplicity/centrality"}, {40, 0, 20, "p_{T}"}, {100, -2, 2, "#eta"}}}); + registry.add("etaphiTrack2", "multiplicity/centrality vs eta vs phi (track2)", {HistType::kTH3F, {{100, 0, 100, "multiplicity/centrality"}, {100, -2, 2, "#eta"}, {200, 0, 2 * M_PI, "#varphi"}}}); + } const int maxMixBin = AxisSpec(axisMultiplicity).getNbins() * AxisSpec(axisVertex).getNbins(); registry.add("eventcount_same", "bin", {HistType::kTH1F, {{maxMixBin + 2, -2.5, -0.5 + maxMixBin, "bin"}}}); @@ -171,7 +182,7 @@ struct CorrelationTask { ccdb->setCaching(true); ccdb->setLocalObjectValidityChecking(); - long now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); ccdb->setCreatedNotAfter(now); // TODO must become global parameter from the train creation time } @@ -193,7 +204,7 @@ struct CorrelationTask { } template - void fillQA(TCollision collision, float multiplicity, TTracks tracks) + void fillQA(const TCollision& collision, float multiplicity, const TTracks& tracks) { for (auto& track1 : tracks) { registry.fill(HIST("yields"), multiplicity, track1.pt(), track1.eta()); @@ -201,6 +212,20 @@ struct CorrelationTask { } } + template + void fillQA(const TCollision& collision, float multiplicity, const TTracks1& tracks1, const TTracks2& tracks2) + { + fillQA(collision, multiplicity, tracks1); + for (auto& track2 : tracks2) { + if constexpr (std::is_same::value) { + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << (uint32_t)track2.decay())) == 0u) + continue; + } + registry.fill(HIST("yieldsTrack2"), multiplicity, track2.pt(), track2.eta()); + registry.fill(HIST("etaphiTrack2"), multiplicity, track2.eta(), track2.phi()); + } + } + template bool fillCollisionAOD(TTarget target, TCollision collision, float multiplicity) { @@ -229,8 +254,11 @@ struct CorrelationTask { return true; } - template - void fillCorrelations(TTarget target, TTracks& tracks1, TTracks& tracks2, float multiplicity, float posZ, int magField, float eventWeight) + template + using hasSign = decltype(std::declval().sign()); + + template + void fillCorrelations(TTarget target, TTracks1& tracks1, TTracks2& tracks2, float multiplicity, float posZ, int magField, float eventWeight) { // Cache efficiency for particles (too many FindBin lookups) float* efficiencyAssociated = nullptr; @@ -267,9 +295,17 @@ struct CorrelationTask { target->getTriggerHist()->Fill(step, track1.pt(), multiplicity, posZ, triggerWeight); for (auto& track2 : tracks2) { - if (track1.globalIndex() == track2.globalIndex()) { - // LOGF(info, "Track identical: %f | %f | %f || %f | %f | %f", track1.eta(), track1.phi(), track1.pt(), track2.eta(), track2.phi(), track2.pt()); - continue; + if constexpr (std::is_same::value) { + if (track1.globalIndex() == track2.globalIndex()) { + // LOGF(info, "Track identical: %f | %f | %f || %f | %f | %f", track1.eta(), track1.phi(), track1.pt(), track2.eta(), track2.phi(), track2.pt()); + continue; + } + } + if constexpr (std::is_same::value) { + if (track1.globalIndex() == track2.cfTrackProng0Id() || track1.globalIndex() == track2.cfTrackProng1Id()) // do not correlate daughter tracks of the same event + continue; + if (cfgDecayParticleMask != 0 && (cfgDecayParticleMask & (1u << (uint32_t)track2.decay())) == 0u) + continue; } if constexpr (step <= CorrelationContainer::kCFStepTracked) { @@ -282,23 +318,27 @@ struct CorrelationTask { continue; } - if (cfgAssociatedCharge != 0 && cfgAssociatedCharge * track2.sign() < 0) { - continue; - } - if (cfgPairCharge != 0 && cfgPairCharge * track1.sign() * track2.sign() < 0) { - continue; - } - - if constexpr (step >= CorrelationContainer::kCFStepReconstructed) { - if (cfg.mPairCuts && mPairCuts.conversionCuts(track1, track2)) { + if constexpr (std::experimental::is_detected::value) { + if (cfgAssociatedCharge != 0 && cfgAssociatedCharge * track2.sign() < 0) { continue; } - - if (cfgTwoTrackCut > 0 && mPairCuts.twoTrackCut(track1, track2, magField)) { + if (cfgPairCharge != 0 && cfgPairCharge * track1.sign() * track2.sign() < 0) { continue; } } + if constexpr (std::is_same::value) { + if constexpr (step >= CorrelationContainer::kCFStepReconstructed) { + if (cfg.mPairCuts && mPairCuts.conversionCuts(track1, track2)) { + continue; + } + + if (cfgTwoTrackCut > 0 && mPairCuts.twoTrackCut(track1, track2, magField)) { + continue; + } + } + } + float associatedWeight = triggerWeight; if constexpr (step == CorrelationContainer::kCFStepCorrected) { if (cfg.mEfficiencyAssociated) { @@ -405,6 +445,29 @@ struct CorrelationTask { } PROCESS_SWITCH(CorrelationTask, processSameDerived, "Process same event on derived data", false); + void processSame2ProngDerived(derivedCollisions::iterator const& collision, soa::Filtered const& tracks, soa::Filtered const& p2tracks) + { + if (cfgVerbosity > 0) { + LOGF(info, "processSame2ProngDerived: Tracks for collision: %d | 2-prong candidates: %d | Vertex: %.1f | Multiplicity/Centrality: %.1f", tracks.size(), p2tracks.size(), collision.posZ(), collision.multiplicity()); + } + loadEfficiency(collision.timestamp()); + + const auto multiplicity = collision.multiplicity(); + + int bin = configurableBinningDerived.getBin({collision.posZ(), collision.multiplicity()}); + registry.fill(HIST("eventcount_same"), bin); + fillQA(collision, multiplicity, tracks, p2tracks); + + same->fillEvent(multiplicity, CorrelationContainer::kCFStepReconstructed); + fillCorrelations(same, tracks, p2tracks, multiplicity, collision.posZ(), 0, 1.0f); + + if (cfg.mEfficiencyAssociated || cfg.mEfficiencyTrigger) { + same->fillEvent(multiplicity, CorrelationContainer::kCFStepCorrected); + fillCorrelations(same, tracks, p2tracks, multiplicity, collision.posZ(), 0, 1.0f); + } + } + PROCESS_SWITCH(CorrelationTask, processSame2ProngDerived, "Process same event on derived data", false); + using BinningTypeAOD = ColumnBinningPolicy; void processMixedAOD(aodCollisions& collisions, aodTracks const& tracks, aod::BCsWithTimestamps const&) {