From 5c32551e550ba54c7765d3922b0c717bca663935 Mon Sep 17 00:00:00 2001 From: gianniliveraro Date: Tue, 8 Jul 2025 17:02:12 -0300 Subject: [PATCH 1/8] New process functions for grouping QA --- .../Strangeness/sigma0builder.cxx | 245 ++++++++++++++++++ 1 file changed, 245 insertions(+) diff --git a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx index acdae0bca7c..5e5cd1470d3 100644 --- a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx +++ b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -73,6 +74,7 @@ struct sigma0builder { // For manual sliceBy PresliceUnsorted perCollisionMCDerived = o2::aod::v0data::straCollisionId; PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; + Preslice perCollisionSTDSorted = o2::aod::v0data::straCollisionId; PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; // pack track quality but separte also afterburner @@ -90,6 +92,7 @@ struct sigma0builder { Configurable fillBkgQAhistos{"fillBkgQAhistos", false, "if true, fill MC QA histograms for Bkg study"}; Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; Configurable doAssocStudy{"doAssocStudy", false, "Do v0 to collision association study."}; + Configurable fverbose{"fverbose", false, "QA printout."}; // Event level Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; @@ -1317,6 +1320,8 @@ struct sigma0builder { void processRealData(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) { + uint64_t CollIDBuffer = 0; + auto start = std::chrono::high_resolution_clock::now(); for (const auto& coll : collisions) { if (!IsEventAccepted(coll, true)) @@ -1324,6 +1329,11 @@ struct sigma0builder { // Do analysis with collision-grouped V0s, retain full collision information const uint64_t collIdx = coll.globalIndex(); + if (collIdx < CollIDBuffer) + LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, collIdx); + + CollIDBuffer = collIdx; + auto V0s = fullV0s.sliceBy(perCollisionSTDDerived, collIdx); float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); @@ -1383,8 +1393,240 @@ struct sigma0builder { if (nSigmaCandidates % 10000 == 0) LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; } + } + } + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + + if (fverbose) LOGF(info, "[Process function call, PreSliceUnsorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + } + + void processRealDataSorted(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + uint64_t CollIDBuffer = 0; + auto start = std::chrono::high_resolution_clock::now(); + for (const auto& coll : collisions) { + + if (!IsEventAccepted(coll, true)) + continue; + + // Do analysis with collision-grouped V0s, retain full collision information + const uint64_t collIdx = coll.globalIndex(); + if (collIdx < CollIDBuffer) + LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, collIdx); + + CollIDBuffer = collIdx; + + auto V0s = fullV0s.sliceBy(perCollisionSTDSorted, collIdx); + float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); + + //_______________________________________________ + // Retrieving IR info + float interactionRate = -1; + if (fGetIR) { + interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource, fIRCrashOnNull) * 1.e-3; + if (interactionRate < 0) + histos.get(HIST("GeneralQA/hRunNumberNegativeIR"))->Fill(Form("%d", coll.runNumber()), 1); + + histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); + histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), centrality, interactionRate); + } + + std::vector bestGammasArray; + std::vector bestLambdasArray; + + //_______________________________________________ + // V0s loop + for (auto& v0 : V0s) { + if (processPhotonCandidate(v0, coll)) // selecting photons + bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates + + if (processLambdaCandidate(v0, coll)) // selecting lambdas + bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates + } + + //_______________________________________________ + // Pi0 optional loop + if (doPi0QA) { + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); + for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { + auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); + runPi0QA(gamma1, gamma2, coll); + } + } } + + //_______________________________________________ + // Sigma0 nested loop + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); + + for (size_t j = 0; j < bestLambdasArray.size(); ++j) { + auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); + + // Building sigma0 candidate + if (!buildSigma0(lambda, gamma, coll)) + continue; + + // Filling tables with accepted candidates + fillTables(lambda, gamma, coll); + + nSigmaCandidates++; + if (nSigmaCandidates % 10000 == 0) + LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; + } + } } + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + + if (fverbose) LOGF(info, "[Process function call, PreSliceSorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + } + + void processRealDataIterator(soa::Join::iterator const& coll, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + auto start = std::chrono::high_resolution_clock::now(); + + if (!IsEventAccepted(coll, true)) + continue; + + float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); + + //_______________________________________________ + // Retrieving IR info + float interactionRate = -1; + if (fGetIR) { + interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource, fIRCrashOnNull) * 1.e-3; + if (interactionRate < 0) + histos.get(HIST("GeneralQA/hRunNumberNegativeIR"))->Fill(Form("%d", coll.runNumber()), 1); + + histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); + histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), centrality, interactionRate); + } + + std::vector bestGammasArray; + std::vector bestLambdasArray; + + //_______________________________________________ + // V0s loop + for (auto& v0 : fullV0s) { + if (processPhotonCandidate(v0, coll)) // selecting photons + bestGammasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best gamma candidates + + if (processLambdaCandidate(v0, coll)) // selecting lambdas + bestLambdasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best lambda candidates + } + + //_______________________________________________ + // Pi0 optional loop + if (doPi0QA) { + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); + for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { + auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); + runPi0QA(gamma1, gamma2, coll); + } + } + } + + //_______________________________________________ + // Sigma0 nested loop + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); + + for (size_t j = 0; j < bestLambdasArray.size(); ++j) { + auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); + + // Building sigma0 candidate + if (!buildSigma0(lambda, gamma, coll)) + continue; + + // Filling tables with accepted candidates + fillTables(lambda, gamma, coll); + + nSigmaCandidates++; + if (nSigmaCandidates % 10000 == 0) + LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; + } + } + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + + if (fverbose) LOGF(info, "[Process function call, Iterator] N. V0s per collision: %i, Processing time (s): %lf", fullV0s.size(), elapsed.count()); + } + + void processRealDataDavid(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + auto start = std::chrono::high_resolution_clock::now(); + + // brute force grouped index construction + std::vector> v0grouped(collisions.size()); + + for (const auto& v0 : fullV0s) { + v0grouped[v0.straCollisionId()].push_back(v0.globalIndex()); + } + + for (const auto& coll : collisions) { + + if (!IsEventAccepted(coll, true)) + continue; + + float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); + + std::vector bestGammasArray; + std::vector bestLambdasArray; + + //_______________________________________________ + // V0s loop + for (size_t i; i < v0grouped[coll.globalIndex()].size(); i++) { + auto v0 = fullV0s.rawIteratorAt(v0grouped[coll.globalIndex()][i]); + if (processPhotonCandidate(v0, coll)) // selecting photons + bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates + + if (processLambdaCandidate(v0, coll)) // selecting lambdas + bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates + } + + //_______________________________________________ + // Pi0 optional loop + if (doPi0QA) { + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); + for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { + auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); + runPi0QA(gamma1, gamma2, coll); + } + } + } + + //_______________________________________________ + // Sigma0 nested loop + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); + + for (size_t j = 0; j < bestLambdasArray.size(); ++j) { + auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); + + // Building sigma0 candidate + if (!buildSigma0(lambda, gamma, coll)) + continue; + + // Filling tables with accepted candidates + fillTables(lambda, gamma, coll); + + nSigmaCandidates++; + if (nSigmaCandidates % 10000 == 0) + LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; + } + } + } + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + + if (fverbose) LOGF(info, "[David's process function call] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + } // Simulated processing in Run 3 (subscribes to MC information too) @@ -1395,6 +1637,9 @@ struct sigma0builder { PROCESS_SWITCH(sigma0builder, processMonteCarlo, "process as if MC data", false); PROCESS_SWITCH(sigma0builder, processRealData, "process as if real data", true); + PROCESS_SWITCH(sigma0builder, processRealDataSorted, "process as if real data. QA only.", true); + PROCESS_SWITCH(sigma0builder, processRealDataIterator, "process as if real data. QA only.", true); + PROCESS_SWITCH(sigma0builder, processRealDataDavid, "process as if real data. QA only.", true); PROCESS_SWITCH(sigma0builder, processGeneratedRun3, "process generated MC collisions", false); }; From 2f766a559687a9d27fd4a4871f0734d1a54cc4d0 Mon Sep 17 00:00:00 2001 From: gianniliveraro Date: Wed, 9 Jul 2025 07:37:36 -0300 Subject: [PATCH 2/8] Undo last commit --- .../Strangeness/sigma0builder.cxx | 245 ------------------ 1 file changed, 245 deletions(-) diff --git a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx index 5e5cd1470d3..acdae0bca7c 100644 --- a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx +++ b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx @@ -24,7 +24,6 @@ #include #include #include -#include #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" @@ -74,7 +73,6 @@ struct sigma0builder { // For manual sliceBy PresliceUnsorted perCollisionMCDerived = o2::aod::v0data::straCollisionId; PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; - Preslice perCollisionSTDSorted = o2::aod::v0data::straCollisionId; PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; // pack track quality but separte also afterburner @@ -92,7 +90,6 @@ struct sigma0builder { Configurable fillBkgQAhistos{"fillBkgQAhistos", false, "if true, fill MC QA histograms for Bkg study"}; Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; Configurable doAssocStudy{"doAssocStudy", false, "Do v0 to collision association study."}; - Configurable fverbose{"fverbose", false, "QA printout."}; // Event level Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; @@ -1320,8 +1317,6 @@ struct sigma0builder { void processRealData(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) { - uint64_t CollIDBuffer = 0; - auto start = std::chrono::high_resolution_clock::now(); for (const auto& coll : collisions) { if (!IsEventAccepted(coll, true)) @@ -1329,11 +1324,6 @@ struct sigma0builder { // Do analysis with collision-grouped V0s, retain full collision information const uint64_t collIdx = coll.globalIndex(); - if (collIdx < CollIDBuffer) - LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, collIdx); - - CollIDBuffer = collIdx; - auto V0s = fullV0s.sliceBy(perCollisionSTDDerived, collIdx); float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); @@ -1393,240 +1383,8 @@ struct sigma0builder { if (nSigmaCandidates % 10000 == 0) LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; } - } - } - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - - if (fverbose) LOGF(info, "[Process function call, PreSliceUnsorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); - } - - void processRealDataSorted(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) - { - uint64_t CollIDBuffer = 0; - auto start = std::chrono::high_resolution_clock::now(); - for (const auto& coll : collisions) { - - if (!IsEventAccepted(coll, true)) - continue; - - // Do analysis with collision-grouped V0s, retain full collision information - const uint64_t collIdx = coll.globalIndex(); - if (collIdx < CollIDBuffer) - LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, collIdx); - - CollIDBuffer = collIdx; - - auto V0s = fullV0s.sliceBy(perCollisionSTDSorted, collIdx); - float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); - - //_______________________________________________ - // Retrieving IR info - float interactionRate = -1; - if (fGetIR) { - interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource, fIRCrashOnNull) * 1.e-3; - if (interactionRate < 0) - histos.get(HIST("GeneralQA/hRunNumberNegativeIR"))->Fill(Form("%d", coll.runNumber()), 1); - - histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); - histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), centrality, interactionRate); - } - - std::vector bestGammasArray; - std::vector bestLambdasArray; - - //_______________________________________________ - // V0s loop - for (auto& v0 : V0s) { - if (processPhotonCandidate(v0, coll)) // selecting photons - bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates - - if (processLambdaCandidate(v0, coll)) // selecting lambdas - bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates - } - - //_______________________________________________ - // Pi0 optional loop - if (doPi0QA) { - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); - for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { - auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); - runPi0QA(gamma1, gamma2, coll); - } - } } - - //_______________________________________________ - // Sigma0 nested loop - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); - - for (size_t j = 0; j < bestLambdasArray.size(); ++j) { - auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); - - // Building sigma0 candidate - if (!buildSigma0(lambda, gamma, coll)) - continue; - - // Filling tables with accepted candidates - fillTables(lambda, gamma, coll); - - nSigmaCandidates++; - if (nSigmaCandidates % 10000 == 0) - LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; - } - } } - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - - if (fverbose) LOGF(info, "[Process function call, PreSliceSorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); - } - - void processRealDataIterator(soa::Join::iterator const& coll, V0StandardDerivedDatas const& fullV0s, dauTracks const&) - { - auto start = std::chrono::high_resolution_clock::now(); - - if (!IsEventAccepted(coll, true)) - continue; - - float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); - - //_______________________________________________ - // Retrieving IR info - float interactionRate = -1; - if (fGetIR) { - interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource, fIRCrashOnNull) * 1.e-3; - if (interactionRate < 0) - histos.get(HIST("GeneralQA/hRunNumberNegativeIR"))->Fill(Form("%d", coll.runNumber()), 1); - - histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); - histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), centrality, interactionRate); - } - - std::vector bestGammasArray; - std::vector bestLambdasArray; - - //_______________________________________________ - // V0s loop - for (auto& v0 : fullV0s) { - if (processPhotonCandidate(v0, coll)) // selecting photons - bestGammasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best gamma candidates - - if (processLambdaCandidate(v0, coll)) // selecting lambdas - bestLambdasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best lambda candidates - } - - //_______________________________________________ - // Pi0 optional loop - if (doPi0QA) { - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); - for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { - auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); - runPi0QA(gamma1, gamma2, coll); - } - } - } - - //_______________________________________________ - // Sigma0 nested loop - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); - - for (size_t j = 0; j < bestLambdasArray.size(); ++j) { - auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); - - // Building sigma0 candidate - if (!buildSigma0(lambda, gamma, coll)) - continue; - - // Filling tables with accepted candidates - fillTables(lambda, gamma, coll); - - nSigmaCandidates++; - if (nSigmaCandidates % 10000 == 0) - LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; - } - } - - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - - if (fverbose) LOGF(info, "[Process function call, Iterator] N. V0s per collision: %i, Processing time (s): %lf", fullV0s.size(), elapsed.count()); - } - - void processRealDataDavid(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) - { - auto start = std::chrono::high_resolution_clock::now(); - - // brute force grouped index construction - std::vector> v0grouped(collisions.size()); - - for (const auto& v0 : fullV0s) { - v0grouped[v0.straCollisionId()].push_back(v0.globalIndex()); - } - - for (const auto& coll : collisions) { - - if (!IsEventAccepted(coll, true)) - continue; - - float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); - - std::vector bestGammasArray; - std::vector bestLambdasArray; - - //_______________________________________________ - // V0s loop - for (size_t i; i < v0grouped[coll.globalIndex()].size(); i++) { - auto v0 = fullV0s.rawIteratorAt(v0grouped[coll.globalIndex()][i]); - if (processPhotonCandidate(v0, coll)) // selecting photons - bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates - - if (processLambdaCandidate(v0, coll)) // selecting lambdas - bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates - } - - //_______________________________________________ - // Pi0 optional loop - if (doPi0QA) { - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); - for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { - auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); - runPi0QA(gamma1, gamma2, coll); - } - } - } - - //_______________________________________________ - // Sigma0 nested loop - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); - - for (size_t j = 0; j < bestLambdasArray.size(); ++j) { - auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); - - // Building sigma0 candidate - if (!buildSigma0(lambda, gamma, coll)) - continue; - - // Filling tables with accepted candidates - fillTables(lambda, gamma, coll); - - nSigmaCandidates++; - if (nSigmaCandidates % 10000 == 0) - LOG(info) << "Sigma0 Candidates built: " << nSigmaCandidates; - } - } - } - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - - if (fverbose) LOGF(info, "[David's process function call] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); - } // Simulated processing in Run 3 (subscribes to MC information too) @@ -1637,9 +1395,6 @@ struct sigma0builder { PROCESS_SWITCH(sigma0builder, processMonteCarlo, "process as if MC data", false); PROCESS_SWITCH(sigma0builder, processRealData, "process as if real data", true); - PROCESS_SWITCH(sigma0builder, processRealDataSorted, "process as if real data. QA only.", true); - PROCESS_SWITCH(sigma0builder, processRealDataIterator, "process as if real data. QA only.", true); - PROCESS_SWITCH(sigma0builder, processRealDataDavid, "process as if real data. QA only.", true); PROCESS_SWITCH(sigma0builder, processGeneratedRun3, "process generated MC collisions", false); }; From 6a9d283cdec9e8dc05520d66f825f03da14da421 Mon Sep 17 00:00:00 2001 From: gianniliveraro Date: Wed, 9 Jul 2025 10:37:30 -0300 Subject: [PATCH 3/8] New task for v0 grouping QC --- PWGLF/TableProducer/QC/CMakeLists.txt | 5 + PWGLF/TableProducer/QC/sigma0QC.cxx | 1767 +++++++++++++++++++++++++ 2 files changed, 1772 insertions(+) create mode 100644 PWGLF/TableProducer/QC/sigma0QC.cxx diff --git a/PWGLF/TableProducer/QC/CMakeLists.txt b/PWGLF/TableProducer/QC/CMakeLists.txt index db3fdb4876b..933f7710366 100644 --- a/PWGLF/TableProducer/QC/CMakeLists.txt +++ b/PWGLF/TableProducer/QC/CMakeLists.txt @@ -18,3 +18,8 @@ o2physics_add_dpl_workflow(flow-qc SOURCES flowQC.cxx PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(sigma0qc + SOURCES sigma0QC.cxx + PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2Physics::MLCore O2Physics::AnalysisCCDB + COMPONENT_NAME Analysis) diff --git a/PWGLF/TableProducer/QC/sigma0QC.cxx b/PWGLF/TableProducer/QC/sigma0QC.cxx new file mode 100644 index 00000000000..65d2f869755 --- /dev/null +++ b/PWGLF/TableProducer/QC/sigma0QC.cxx @@ -0,0 +1,1767 @@ +// 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. +// +// This is a task that employs the standard derived V0 tables and attempts to combine +// two V0s into a Sigma0 -> Lambda + gamma candidate. +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// Sigma0 QC task +// *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* +// +// Comments, questions, complaints, suggestions? +// Please write to: +// gianni.shigeru.setoue.liveraro@cern.ch +// + +#include +#include +#include +#include + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/ASoA.h" +#include "ReconstructionDataFormats/Track.h" +#include "Common/Core/RecoDecay.h" +#include "Common/Core/trackUtilities.h" +#include "Common/Core/TrackSelection.h" +#include "Common/DataModel/TrackSelectionTables.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/PIDResponse.h" +#include "Common/CCDB/ctpRateFetcher.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFSigmaTables.h" +#include "CCDB/BasicCCDBManager.h" +#include +#include +#include +#include +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; +using std::array; +using dauTracks = soa::Join; +using V0StandardDerivedDatas = soa::Join; + +struct sigma0QC { + Service ccdb; + ctpRateFetcher rateFetcher; + + SliceCache cache; + + // For manual sliceBy + PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; + + // Histogram registry + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; + Configurable fverbose{"fverbose", false, "QA printout."}; + + // Event level + Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + Configurable fGetIR{"fGetIR", false, "Flag to retrieve the IR info."}; + Configurable fIRCrashOnNull{"fIRCrashOnNull", false, "Flag to avoid CTP RateFetcher crash."}; + Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + + struct : ConfigurableGroup { + Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", true, "require events with at least one ITS-TPC track"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", false, "reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; + Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds"}; + Configurable requireNoCollInTimeRangeVzDep{"requireNoCollInTimeRangeVzDep", false, "reject collisions corrupted by the cannibalism, with other collisions with pvZ of drifting TPC tracks from past/future collisions within 2.5 cm the current pvZ"}; + Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold"}; + Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF"}; + Configurable requireINEL0{"requireINEL0", false, "require INEL>0 event selection"}; + Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; + Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; + Configurable useEvtSelInDenomEff{"useEvtSelInDenomEff", false, "Consider event selections in the recoed <-> gen collision association for the denominator (or numerator) of the acc. x eff. (or signal loss)?"}; + Configurable applyZVtxSelOnMCPV{"applyZVtxSelOnMCPV", false, "Apply Z-vtx cut on the PV of the generated collision?"}; + Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + + // fast check on interaction rate + Configurable minIR{"minIR", -1, "minimum IR collisions"}; + Configurable maxIR{"maxIR", -1, "maximum IR collisions"}; + + } eventSelections; + + // For ML Selection + Configurable useMLScores{"useMLScores", false, "use ML scores to select candidates"}; + Configurable Gamma_MLThreshold{"Gamma_MLThreshold", 0.1, "Decision Threshold value to select gammas"}; + Configurable Lambda_MLThreshold{"Lambda_MLThreshold", 0.1, "Decision Threshold value to select lambdas"}; + Configurable AntiLambda_MLThreshold{"AntiLambda_MLThreshold", 0.1, "Decision Threshold value to select antilambdas"}; + + // For standard approach: + //// Lambda criteria: + Configurable V0Rapidity{"V0Rapidity", 0.8, "v0 rapidity"}; + + Configurable LambdaDauPseudoRap{"LambdaDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; + Configurable LambdaMinDCANegToPv{"LambdaMinDCANegToPv", 0.0, "min DCA Neg To PV (cm)"}; + Configurable LambdaMinDCAPosToPv{"LambdaMinDCAPosToPv", 0.0, "min DCA Pos To PV (cm)"}; + Configurable LambdaMaxDCAV0Dau{"LambdaMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable LambdaMinv0radius{"LambdaMinv0radius", 0.0, "Min V0 radius (cm)"}; + Configurable LambdaMaxv0radius{"LambdaMaxv0radius", 60, "Max V0 radius (cm)"}; + Configurable LambdaWindow{"LambdaWindow", 0.05, "Mass window around expected (in GeV/c2)"}; + + //// Photon criteria: + Configurable PhotonMaxDauPseudoRap{"PhotonMaxDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; + Configurable PhotonMinDCAToPv{"PhotonMinDCAToPv", 0.0, "Min DCA daughter To PV (cm)"}; + Configurable PhotonMaxDCAV0Dau{"PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable PhotonMinRadius{"PhotonMinRadius", 0.0, "Min photon conversion radius (cm)"}; + Configurable PhotonMaxRadius{"PhotonMaxRadius", 240, "Max photon conversion radius (cm)"}; + Configurable PhotonMaxMass{"PhotonMaxMass", 0.3, "Max photon mass (GeV/c^{2})"}; + + //// Sigma0 criteria: + Configurable Sigma0Window{"Sigma0Window", 0.1, "Mass window around expected (in GeV/c2)"}; + Configurable SigmaMaxRap{"SigmaMaxRap", 0.8, "Max sigma0 rapidity"}; + + //// Extras: + Configurable Pi0PhotonMinDCADauToPv{"Pi0PhotonMinDCADauToPv", 0.0, "Min DCA daughter To PV (cm)"}; + Configurable Pi0PhotonMaxDCAV0Dau{"Pi0PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable Pi0PhotonMinTPCCrossedRows{"Pi0PhotonMinTPCCrossedRows", 0, "Min daughter TPC Crossed Rows"}; + Configurable Pi0PhotonMaxTPCNSigmas{"Pi0PhotonMaxTPCNSigmas", 7, "Max TPC NSigmas for daughters"}; + Configurable Pi0PhotonMaxEta{"Pi0PhotonMaxEta", 0.8, "Max photon rapidity"}; + Configurable Pi0PhotonMinRadius{"Pi0PhotonMinRadius", 3.0, "Min photon conversion radius (cm)"}; + Configurable Pi0PhotonMaxRadius{"Pi0PhotonMaxRadius", 115, "Max photon conversion radius (cm)"}; + Configurable Pi0PhotonMaxQt{"Pi0PhotonMaxQt", 0.05, "Max photon qt value (AP plot) (GeV/c)"}; + Configurable Pi0PhotonMaxAlpha{"Pi0PhotonMaxAlpha", 0.95, "Max photon alpha absolute value (AP plot)"}; + Configurable Pi0PhotonMinV0cospa{"Pi0PhotonMinV0cospa", 0.80, "Min V0 CosPA"}; + Configurable Pi0PhotonMaxMass{"Pi0PhotonMaxMass", 0.10, "Max photon mass (GeV/c^{2})"}; + + // Axis + // base properties + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Centrality"}; + + // Invariant Mass + ConfigurableAxis axisSigmaMass{"axisSigmaMass", {500, 1.10f, 1.30f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.05f, 1.151f}, "M_{#Lambda} (GeV/c^{2})"}; + ConfigurableAxis axisPhotonMass{"axisPhotonMass", {200, -0.1f, 0.5f}, "M_{#Gamma}"}; + ConfigurableAxis axisPi0Mass{"axisPi0Mass", {200, 0.08f, 0.18f}, "M_{#Pi^{0}}"}; + ConfigurableAxis axisK0SMass{"axisK0SMass", {200, 0.4f, 0.6f}, "M_{K^{0}}"}; + + // AP plot axes + ConfigurableAxis axisAPAlpha{"axisAPAlpha", {220, -1.1f, 1.1f}, "V0 AP alpha"}; + ConfigurableAxis axisAPQt{"axisAPQt", {220, 0.0f, 0.5f}, "V0 AP alpha"}; + + // Track quality axes + ConfigurableAxis axisTPCrows{"axisTPCrows", {160, 0.0f, 160.0f}, "N TPC rows"}; + + // topological variable QA axes + ConfigurableAxis axisDCAtoPV{"axisDCAtoPV", {500, 0.0f, 50.0f}, "DCA (cm)"}; + ConfigurableAxis axisXY{"axisXY", {120, -120.0f, 120.0f}, "XY axis"}; + ConfigurableAxis axisDCAdau{"axisDCAdau", {50, 0.0f, 5.0f}, "DCA (cm)"}; + ConfigurableAxis axisRadius{"axisRadius", {240, 0.0f, 120.0f}, "V0 radius (cm)"}; + ConfigurableAxis axisPA{"axisPA", {100, 0.0f, 1}, "Pointing angle"}; + ConfigurableAxis axisRapidity{"axisRapidity", {100, -2.0f, 2.0f}, "Rapidity"}; + ConfigurableAxis axisCandSel{"axisCandSel", {7, 0.5f, +7.5f}, "Candidate Selection"}; + ConfigurableAxis axisNch{"axisNch", {300, 0.0f, 3000.0f}, "N_{ch}"}; + ConfigurableAxis axisIRBinning{"axisIRBinning", {150, 0, 1500}, "Binning for the interaction rate (kHz)"}; + + void init(InitContext const&) + { + // setting CCDB service + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + + // Event Counters + histos.add("hEventSelection", "hEventSelection", kTH1D, {{21, -0.5f, +20.5f}}); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "posZ cut"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeStrict"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); + if (doPPAnalysis) { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "INEL>0"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); + } else { + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "Below min occup."); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "Above max occup."); + } + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "Below min IR"); + histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "Above max IR"); + + histos.add("hEventCentrality", "hEventCentrality", kTH1D, {axisCentrality}); + + histos.add("PhotonSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Photon Mass Cut"); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Photon Eta/Y Cut"); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(4, "Photon DCAToPV Cut"); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(5, "Photon DCADau Cut"); + histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(6, "Photon Radius Cut"); + + histos.add("PhotonSel/hPhotonMass", "hPhotonMass", kTH1F, {axisPhotonMass}); + histos.add("PhotonSel/hPhotonNegEta", "hPhotonNegEta", kTH1F, {axisRapidity}); + histos.add("PhotonSel/hPhotonPosEta", "hPhotonPosEta", kTH1F, {axisRapidity}); + histos.add("PhotonSel/hPhotonY", "hPhotonY", kTH1F, {axisRapidity}); + histos.add("PhotonSel/hPhotonDCANegToPV", "hPhotonDCANegToPV", kTH1F, {axisDCAtoPV}); + histos.add("PhotonSel/hPhotonDCAPosToPV", "hPhotonDCAPosToPV", kTH1F, {axisDCAtoPV}); + histos.add("PhotonSel/hPhotonDCADau", "hPhotonDCADau", kTH1F, {axisDCAdau}); + histos.add("PhotonSel/hPhotonRadius", "hPhotonRadius", kTH1F, {axisRadius}); + histos.add("PhotonSel/h3dPhotonMass", "h3dPhotonMass", kTH3D, {axisCentrality, axisPt, axisPhotonMass}); + + histos.add("LambdaSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Lambda Mass Cut"); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Lambda Eta/Y Cut"); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(4, "Lambda DCAToPV Cut"); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(5, "Lambda Radius Cut"); + histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(6, "Lambda DCADau Cut"); + + histos.add("LambdaSel/hLambdaMass", "hLambdaMass", kTH1F, {axisLambdaMass}); + histos.add("LambdaSel/hAntiLambdaMass", "hAntiLambdaMass", kTH1F, {axisLambdaMass}); + histos.add("LambdaSel/hLambdaNegEta", "hLambdaNegEta", kTH1F, {axisRapidity}); + histos.add("LambdaSel/hLambdaPosEta", "hLambdaPosEta", kTH1F, {axisRapidity}); + histos.add("LambdaSel/hLambdaY", "hLambdaY", kTH1F, {axisRapidity}); + histos.add("LambdaSel/hLambdaDCANegToPV", "hLambdaDCANegToPV", kTH1F, {axisDCAtoPV}); + histos.add("LambdaSel/hLambdaDCAPosToPV", "hLambdaDCAPosToPV", kTH1F, {axisDCAtoPV}); + histos.add("LambdaSel/hLambdaDCADau", "hLambdaDCADau", kTH1F, {axisDCAdau}); + histos.add("LambdaSel/hLambdaRadius", "hLambdaRadius", kTH1F, {axisRadius}); + histos.add("LambdaSel/h3dLambdaMass", "h3dLambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); + histos.add("LambdaSel/h3dALambdaMass", "h3dALambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); + + histos.add("SigmaSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Sigma Mass Window"); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Sigma Y Window"); + + // For selection: + histos.add("SigmaSel/h3dMassSigma0BeforeSel", "h3dMassSigma0BeforeSel", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); + histos.add("SigmaSel/hSigmaMass", "hSigmaMass", kTH1F, {axisSigmaMass}); + histos.add("SigmaSel/hSigmaMassWindow", "hSigmaMassWindow", kTH1F, {{200, -0.09f, 0.11f}}); + histos.add("SigmaSel/hSigmaY", "hSigmaY", kTH1F, {axisRapidity}); + histos.add("SigmaSel/hSigmaMassSelected", "hSigmaMassSelected", kTH1F, {axisSigmaMass}); + histos.add("SigmaSel/h3dMassSigma0AfterSel", "h3dMassSigma0AfterSel", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); + + if (fGetIR) { + histos.add("GeneralQA/hRunNumberNegativeIR", "", kTH1D, {{1, 0., 1.}}); + histos.add("GeneralQA/hInteractionRate", "hInteractionRate", kTH1F, {axisIRBinning}); + histos.add("GeneralQA/hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2F, {axisCentrality, axisIRBinning}); + } + + // For Pi0 QA + if (doPi0QA) { + histos.add("Pi0QA/h3dMassPi0BeforeSel_MCAssoc", "h3dMassPi0BeforeSel_MCAssoc", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); + histos.add("Pi0QA/h3dMassPi0AfterSel_MCAssoc", "h3dMassPi0AfterSel_MCAssoc", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); + histos.add("Pi0QA/h3dMassPi0BeforeSel_Candidates", "h3dMassPi0BeforeSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); + histos.add("Pi0QA/h3dMassPi0AfterSel_Candidates", "h3dMassPi0AfterSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); + } + } + + template + bool IsEventAccepted(TCollision collision, bool fillHists) + // check whether the collision passes our collision selections + { + if (fillHists) + histos.fill(HIST("hEventSelection"), 0. /* all collisions */); + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 2 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */); + if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 4 /* Not at TF border */); + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 5 /* vertex-Z selected */); + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 6 /* Contains at least one ITS-TPC track */); + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 7 /* PV position consistency check */); + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 8 /* PV with at least one contributor matched with TOF */); + if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 9 /* PV with at least one contributor matched with TRD */); + if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 10 /* Not at same bunch pile-up */); + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 11 /* No other collision within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds*/); + if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 12 /* No other collision within +/- 10 microseconds */); + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 13 /* No other collision within +/- 2 microseconds */); + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 14 /* No other collision within the same ITS ROF with mult. above a certain threshold */); + if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 15 /* No other collision within the same ITS ROF */); + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); + } else { // we are in Pb-Pb + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 16 /* Below min occupancy */); + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 17 /* Above max occupancy */); + } + // Fetch interaction rate only if required (in order to limit ccdb calls) + double interactionRate = (eventSelections.minIR >= 0 || eventSelections.maxIR >= 0) ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource, fIRCrashOnNull) * 1.e-3 : -1; + if (eventSelections.minIR >= 0 && interactionRate < eventSelections.minIR) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 18 /* Below min IR */); + + if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { + return false; + } + if (fillHists) + histos.fill(HIST("hEventSelection"), 19 /* Above max IR */); + + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("hEventCentrality"), centrality); + return true; + } + + template + void runPi0QA(TV0Object const& gamma1, TV0Object const& gamma2, TCollision collision) + { + // Check if both V0s are made of the same tracks + if (gamma1.posTrackExtraId() == gamma2.posTrackExtraId() || + gamma1.negTrackExtraId() == gamma2.negTrackExtraId()) { + return; + } + + // Calculate pi0 properties + std::array pVecGamma1{gamma1.px(), gamma1.py(), gamma1.pz()}; + std::array pVecGamma2{gamma2.px(), gamma2.py(), gamma2.pz()}; + std::array arrpi0{pVecGamma1, pVecGamma2}; + float pi0Mass = RecoDecay::m(arrpi0, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassPhoton}); + float pi0Pt = RecoDecay::pt(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py()}); + float pi0Y = RecoDecay::y(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py(), gamma1.pz() + gamma2.pz()}, o2::constants::physics::MassPi0); + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + // MC-specific variables + bool fIsPi0 = false, fIsMC = false; + + // Check if MC data and populate fIsMC, fIsPi0 + if constexpr (requires { gamma1.motherMCPartId(); gamma2.motherMCPartId(); }) { + if (gamma1.has_v0MCCore() && gamma2.has_v0MCCore()) { + fIsMC = true; + auto gamma1MC = gamma1.template v0MCCore_as>(); + auto gamma2MC = gamma2.template v0MCCore_as>(); + + if (gamma1MC.pdgCode() == 22 && gamma2MC.pdgCode() == 22 && + gamma1MC.pdgCodeMother() == 111 && gamma2MC.pdgCodeMother() == 111 && + gamma1.motherMCPartId() == gamma2.motherMCPartId()) { + fIsPi0 = true; + histos.fill(HIST("Pi0QA/h3dMassPi0BeforeSel_MCAssoc"), centrality, pi0Pt, pi0Mass); + } + } + } + + histos.fill(HIST("Pi0QA/h3dMassPi0BeforeSel_Candidates"), centrality, pi0Pt, pi0Mass); + + // Photon-specific selections + auto posTrackGamma1 = gamma1.template posTrackExtra_as(); + auto negTrackGamma1 = gamma1.template negTrackExtra_as(); + auto posTrackGamma2 = gamma2.template posTrackExtra_as(); + auto negTrackGamma2 = gamma2.template negTrackExtra_as(); + + // Gamma1 Selection + bool passedTPCGamma1 = (TMath::Abs(posTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || + (TMath::Abs(negTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); + + if (TMath::Abs(gamma1.mGamma()) > Pi0PhotonMaxMass || + gamma1.qtarm() >= Pi0PhotonMaxQt || + TMath::Abs(gamma1.alpha()) >= Pi0PhotonMaxAlpha || + TMath::Abs(gamma1.dcapostopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma1.dcanegtopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma1.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || + TMath::Abs(gamma1.negativeeta()) >= Pi0PhotonMaxEta || + TMath::Abs(gamma1.positiveeta()) >= Pi0PhotonMaxEta || + gamma1.v0cosPA() <= Pi0PhotonMinV0cospa || + gamma1.v0radius() <= Pi0PhotonMinRadius || + gamma1.v0radius() >= Pi0PhotonMaxRadius || + posTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + negTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + !passedTPCGamma1) { + return; + } + + // Gamma2 Selection + bool passedTPCGamma2 = (TMath::Abs(posTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || + (TMath::Abs(negTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); + + if (TMath::Abs(gamma2.mGamma()) > Pi0PhotonMaxMass || + gamma2.qtarm() >= Pi0PhotonMaxQt || + TMath::Abs(gamma2.alpha()) >= Pi0PhotonMaxAlpha || + TMath::Abs(gamma2.dcapostopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma2.dcanegtopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma2.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || + TMath::Abs(gamma2.negativeeta()) >= Pi0PhotonMaxEta || + TMath::Abs(gamma2.positiveeta()) >= Pi0PhotonMaxEta || + gamma2.v0cosPA() <= Pi0PhotonMinV0cospa || + gamma2.v0radius() <= Pi0PhotonMinRadius || + gamma2.v0radius() >= Pi0PhotonMaxRadius || + posTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + negTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + !passedTPCGamma2) { + return; + } + + // Pi0-specific selections: + if (TMath::Abs(pi0Y) > 0.5) { + return; + } + + // Fill histograms + histos.fill(HIST("Pi0QA/h3dMassPi0AfterSel_Candidates"), centrality, pi0Pt, pi0Mass); + if (fIsMC && fIsPi0) + histos.fill(HIST("Pi0QA/h3dMassPi0AfterSel_MCAssoc"), centrality, pi0Pt, pi0Mass); + } + + // Process photon candidate + template + bool processPhotonCandidate(TV0Object const& gamma, TCollision collision) + { + if (gamma.v0Type() == 0) + return false; + + if (useMLScores) { + // Gamma selection: + if (gamma.gammaBDTScore() <= Gamma_MLThreshold) + return false; + + } else { + // Standard selection + // Gamma basic selection criteria: + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 1.); + histos.fill(HIST("PhotonSel/hPhotonMass"), gamma.mGamma()); + if ((gamma.mGamma() < 0) || (gamma.mGamma() > PhotonMaxMass)) + return false; + float PhotonY = RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma); + histos.fill(HIST("PhotonSel/hPhotonNegEta"), gamma.negativeeta()); + histos.fill(HIST("PhotonSel/hPhotonPosEta"), gamma.positiveeta()); + histos.fill(HIST("PhotonSel/hPhotonY"), PhotonY); + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 2.); + if ((TMath::Abs(PhotonY) > V0Rapidity) || (TMath::Abs(gamma.negativeeta()) > PhotonMaxDauPseudoRap) || (TMath::Abs(gamma.positiveeta()) > PhotonMaxDauPseudoRap)) + return false; + histos.fill(HIST("PhotonSel/hPhotonDCANegToPV"), TMath::Abs(gamma.dcanegtopv())); + histos.fill(HIST("PhotonSel/hPhotonDCAPosToPV"), TMath::Abs(gamma.dcapostopv())); + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 3.); + if ((TMath::Abs(gamma.dcapostopv()) < PhotonMinDCAToPv) || (TMath::Abs(gamma.dcanegtopv()) < PhotonMinDCAToPv)) + return false; + histos.fill(HIST("PhotonSel/hPhotonDCADau"), TMath::Abs(gamma.dcaV0daughters())); + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 4.); + if (TMath::Abs(gamma.dcaV0daughters()) > PhotonMaxDCAV0Dau) + return false; + histos.fill(HIST("PhotonSel/hPhotonRadius"), gamma.v0radius()); + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 5.); + if ((gamma.v0radius() < PhotonMinRadius) || (gamma.v0radius() > PhotonMaxRadius)) + return false; + histos.fill(HIST("PhotonSel/hSelectionStatistics"), 6.); + } + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("PhotonSel/h3dPhotonMass"), centrality, gamma.pt(), gamma.mGamma()); + return true; + } + + // Process photon candidate + template + bool processLambdaCandidate(TV0Object const& lambda, TCollision collision) + { + if (lambda.v0Type() != 1) + return false; + + if (useMLScores) { + if ((lambda.lambdaBDTScore() <= Lambda_MLThreshold) && (lambda.antiLambdaBDTScore() <= AntiLambda_MLThreshold)) + return false; + + } else { + // Lambda basic selection criteria: + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 1.); + histos.fill(HIST("LambdaSel/hLambdaMass"), lambda.mLambda()); + histos.fill(HIST("LambdaSel/hAntiLambdaMass"), lambda.mAntiLambda()); + if ((TMath::Abs(lambda.mLambda() - o2::constants::physics::MassLambda0) > LambdaWindow) && (TMath::Abs(lambda.mAntiLambda() - o2::constants::physics::MassLambda0) > LambdaWindow)) + return false; + histos.fill(HIST("LambdaSel/hLambdaNegEta"), lambda.negativeeta()); + histos.fill(HIST("LambdaSel/hLambdaPosEta"), lambda.positiveeta()); + histos.fill(HIST("LambdaSel/hLambdaY"), lambda.yLambda()); + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 2.); + if ((TMath::Abs(lambda.yLambda()) > V0Rapidity) || (TMath::Abs(lambda.negativeeta()) > LambdaDauPseudoRap) || (TMath::Abs(lambda.positiveeta()) > LambdaDauPseudoRap)) + return false; + histos.fill(HIST("LambdaSel/hLambdaDCANegToPV"), lambda.dcanegtopv()); + histos.fill(HIST("LambdaSel/hLambdaDCAPosToPV"), lambda.dcapostopv()); + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 3.); + if ((TMath::Abs(lambda.dcapostopv()) < LambdaMinDCAPosToPv) || (TMath::Abs(lambda.dcanegtopv()) < LambdaMinDCANegToPv)) + return false; + histos.fill(HIST("LambdaSel/hLambdaRadius"), lambda.v0radius()); + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 4.); + if ((lambda.v0radius() < LambdaMinv0radius) || (lambda.v0radius() > LambdaMaxv0radius)) + return false; + histos.fill(HIST("LambdaSel/hLambdaDCADau"), lambda.dcaV0daughters()); + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 5.); + if (TMath::Abs(lambda.dcaV0daughters()) > LambdaMaxDCAV0Dau) + return false; + histos.fill(HIST("LambdaSel/hSelectionStatistics"), 6.); + } + + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("LambdaSel/h3dLambdaMass"), centrality, lambda.pt(), lambda.mLambda()); + histos.fill(HIST("LambdaSel/h3dALambdaMass"), centrality, lambda.pt(), lambda.mAntiLambda()); + + return true; + } + /////////// + // Process sigma candidate and store properties in object + template + bool buildSigma0(TV0Object const& lambda, TV0Object const& gamma, TCollision collision) + { + // Checking if both V0s are made of the very same tracks + if (gamma.posTrackExtraId() == lambda.posTrackExtraId() || + gamma.negTrackExtraId() == lambda.negTrackExtraId()) { + return false; + } + + // Sigma0 candidate properties + std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; + std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; + auto arrMom = std::array{pVecPhotons, pVecLambda}; + float sigmaMass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); + float sigmaY = RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0); + float SigmapT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + // Before any selection + histos.fill(HIST("SigmaSel/h3dMassSigma0BeforeSel"), centrality, SigmapT, sigmaMass); + + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 1.); + histos.fill(HIST("SigmaSel/hSigmaMass"), sigmaMass); + histos.fill(HIST("SigmaSel/hSigmaMassWindow"), sigmaMass - 1.192642); + + if (TMath::Abs(sigmaMass - 1.192642) > Sigma0Window) + return false; + + histos.fill(HIST("SigmaSel/hSigmaY"), sigmaY); + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 2.); + + if (TMath::Abs(sigmaY) > SigmaMaxRap) + return false; + + histos.fill(HIST("SigmaSel/hSigmaMassSelected"), sigmaMass); + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 3.); + histos.fill(HIST("SigmaSel/h3dMassSigma0AfterSel"), centrality, SigmapT, sigmaMass); + + return true; + } + + // ______________________________________________________ + // Real data processing - no MC subscription + template + void runAnalysis(TCollision const& collisions, TV0s const& fullV0s, bool fDavidTest) + { + + // brute force grouped index construction + std::vector> v0grouped(collisions.size()); + + if (fDavidTest){ + for (const auto& v0 : fullV0s) { + v0grouped[v0.straCollisionId()].push_back(v0.globalIndex()); + } + } + + uint64_t CollIDBuffer = 0; + for (const auto& coll : collisions) { + if (!IsEventAccepted(coll, true)) + continue; + + float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); + const uint64_t collIdx = coll.globalIndex(); + if (collIdx < CollIDBuffer) + LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, collIdx); + + CollIDBuffer = collIdx; + + //_______________________________________________ + // V0s loop + std::vector bestGammasArray; + std::vector bestLambdasArray; + if (fDavidTest){ + for (size_t i; i < v0grouped[coll.globalIndex()].size(); i++) { + auto v0 = fullV0s.rawIteratorAt(v0grouped[coll.globalIndex()][i]); + + if (processPhotonCandidate(v0, coll)) // selecting photons + bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates + + if (processLambdaCandidate(v0, coll)) // selecting lambdas + bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates + } + } + else{ + auto V0s = fullV0s.sliceBy(perCollisionSTDDerived, collIdx); + for (auto& v0 : V0s) { + if (processPhotonCandidate(v0, coll)) // selecting photons + bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates + + if (processLambdaCandidate(v0, coll)) // selecting lambdas + bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates + } + } + + //_______________________________________________ + // Retrieving IR info + float interactionRate = -1; + if (fGetIR) { + interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource, fIRCrashOnNull) * 1.e-3; + if (interactionRate < 0) + histos.get(HIST("GeneralQA/hRunNumberNegativeIR"))->Fill(Form("%d", coll.runNumber()), 1); + + histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); + histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), centrality, interactionRate); + } + + //_______________________________________________ + // Pi0 optional loop + if (doPi0QA) { + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); + for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { + auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); + runPi0QA(gamma1, gamma2, coll); + } + } + } + + //_______________________________________________ + // Sigma0 nested loop + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); + + for (size_t j = 0; j < bestLambdasArray.size(); ++j) { + auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); + + // Building sigma0 candidate + if (!buildSigma0(lambda, gamma, coll)) + continue; + } + } + } + } + + void processRealData(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + auto start = std::chrono::high_resolution_clock::now(); + + runAnalysis(collisions, fullV0s, false); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + + if (fverbose) LOGF(info, "[Process function call, PreSliceUnsorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + + } + + void processRealDataDavid(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + auto start = std::chrono::high_resolution_clock::now(); + + runAnalysis(collisions, fullV0s, true); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + + if (fverbose) LOGF(info, "[David's process function call] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + + } + + PROCESS_SWITCH(sigma0QC, processRealData, "process using sliceby unsorted", true); + PROCESS_SWITCH(sigma0QC, processRealDataDavid, "process using David's grouping approach", true); +}; + +struct sigma0QCSorted { + Service ccdb; + ctpRateFetcher rateFetcher; + + SliceCache cache; + + // For manual sliceBy + Preslice perCollisionSTDDerived = o2::aod::v0data::straCollisionId; + + // Histogram registry + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable fillQAhistos{"fillQAhistos", false, "if true, fill QA histograms"}; + Configurable fillBkgQAhistos{"fillBkgQAhistos", false, "if true, fill MC QA histograms for Bkg study"}; + Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; + Configurable doAssocStudy{"doAssocStudy", false, "Do v0 to collision association study."}; + Configurable fverbose{"fverbose", false, "QA printout."}; + + // Event level + Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + Configurable fGetIR{"fGetIR", false, "Flag to retrieve the IR info."}; + Configurable fIRCrashOnNull{"fIRCrashOnNull", false, "Flag to avoid CTP RateFetcher crash."}; + Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + + struct : ConfigurableGroup { + Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", true, "require events with at least one ITS-TPC track"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", false, "reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; + Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds"}; + Configurable requireNoCollInTimeRangeVzDep{"requireNoCollInTimeRangeVzDep", false, "reject collisions corrupted by the cannibalism, with other collisions with pvZ of drifting TPC tracks from past/future collisions within 2.5 cm the current pvZ"}; + Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold"}; + Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF"}; + Configurable requireINEL0{"requireINEL0", false, "require INEL>0 event selection"}; + Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; + Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; + Configurable useEvtSelInDenomEff{"useEvtSelInDenomEff", false, "Consider event selections in the recoed <-> gen collision association for the denominator (or numerator) of the acc. x eff. (or signal loss)?"}; + Configurable applyZVtxSelOnMCPV{"applyZVtxSelOnMCPV", false, "Apply Z-vtx cut on the PV of the generated collision?"}; + Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + + // fast check on interaction rate + Configurable minIR{"minIR", -1, "minimum IR collisions"}; + Configurable maxIR{"maxIR", -1, "maximum IR collisions"}; + + } eventSelections; + + // For ML Selection + Configurable useMLScores{"useMLScores", false, "use ML scores to select candidates"}; + Configurable Gamma_MLThreshold{"Gamma_MLThreshold", 0.1, "Decision Threshold value to select gammas"}; + Configurable Lambda_MLThreshold{"Lambda_MLThreshold", 0.1, "Decision Threshold value to select lambdas"}; + Configurable AntiLambda_MLThreshold{"AntiLambda_MLThreshold", 0.1, "Decision Threshold value to select antilambdas"}; + + // For standard approach: + //// Lambda criteria: + Configurable V0Rapidity{"V0Rapidity", 0.8, "v0 rapidity"}; + + Configurable LambdaDauPseudoRap{"LambdaDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; + Configurable LambdaMinDCANegToPv{"LambdaMinDCANegToPv", 0.0, "min DCA Neg To PV (cm)"}; + Configurable LambdaMinDCAPosToPv{"LambdaMinDCAPosToPv", 0.0, "min DCA Pos To PV (cm)"}; + Configurable LambdaMaxDCAV0Dau{"LambdaMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable LambdaMinv0radius{"LambdaMinv0radius", 0.0, "Min V0 radius (cm)"}; + Configurable LambdaMaxv0radius{"LambdaMaxv0radius", 60, "Max V0 radius (cm)"}; + Configurable LambdaWindow{"LambdaWindow", 0.05, "Mass window around expected (in GeV/c2)"}; + + //// Photon criteria: + Configurable PhotonMaxDauPseudoRap{"PhotonMaxDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; + Configurable PhotonMinDCAToPv{"PhotonMinDCAToPv", 0.0, "Min DCA daughter To PV (cm)"}; + Configurable PhotonMaxDCAV0Dau{"PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable PhotonMinRadius{"PhotonMinRadius", 0.0, "Min photon conversion radius (cm)"}; + Configurable PhotonMaxRadius{"PhotonMaxRadius", 240, "Max photon conversion radius (cm)"}; + Configurable PhotonMaxMass{"PhotonMaxMass", 0.3, "Max photon mass (GeV/c^{2})"}; + + //// Sigma0 criteria: + Configurable Sigma0Window{"Sigma0Window", 0.1, "Mass window around expected (in GeV/c2)"}; + Configurable SigmaMaxRap{"SigmaMaxRap", 0.8, "Max sigma0 rapidity"}; + + //// Extras: + Configurable Pi0PhotonMinDCADauToPv{"Pi0PhotonMinDCADauToPv", 0.0, "Min DCA daughter To PV (cm)"}; + Configurable Pi0PhotonMaxDCAV0Dau{"Pi0PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable Pi0PhotonMinTPCCrossedRows{"Pi0PhotonMinTPCCrossedRows", 0, "Min daughter TPC Crossed Rows"}; + Configurable Pi0PhotonMaxTPCNSigmas{"Pi0PhotonMaxTPCNSigmas", 7, "Max TPC NSigmas for daughters"}; + Configurable Pi0PhotonMaxEta{"Pi0PhotonMaxEta", 0.8, "Max photon rapidity"}; + Configurable Pi0PhotonMinRadius{"Pi0PhotonMinRadius", 3.0, "Min photon conversion radius (cm)"}; + Configurable Pi0PhotonMaxRadius{"Pi0PhotonMaxRadius", 115, "Max photon conversion radius (cm)"}; + Configurable Pi0PhotonMaxQt{"Pi0PhotonMaxQt", 0.05, "Max photon qt value (AP plot) (GeV/c)"}; + Configurable Pi0PhotonMaxAlpha{"Pi0PhotonMaxAlpha", 0.95, "Max photon alpha absolute value (AP plot)"}; + Configurable Pi0PhotonMinV0cospa{"Pi0PhotonMinV0cospa", 0.80, "Min V0 CosPA"}; + Configurable Pi0PhotonMaxMass{"Pi0PhotonMaxMass", 0.10, "Max photon mass (GeV/c^{2})"}; + + // Axis + // base properties + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Centrality"}; + + // Invariant Mass + ConfigurableAxis axisSigmaMass{"axisSigmaMass", {500, 1.10f, 1.30f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.05f, 1.151f}, "M_{#Lambda} (GeV/c^{2})"}; + ConfigurableAxis axisPhotonMass{"axisPhotonMass", {200, -0.1f, 0.5f}, "M_{#Gamma}"}; + ConfigurableAxis axisPi0Mass{"axisPi0Mass", {200, 0.08f, 0.18f}, "M_{#Pi^{0}}"}; + + // topological variable QA axes + ConfigurableAxis axisRapidity{"axisRapidity", {100, -2.0f, 2.0f}, "Rapidity"}; + ConfigurableAxis axisCandSel{"axisCandSel", {7, 0.5f, +7.5f}, "Candidate Selection"}; + ConfigurableAxis axisIRBinning{"axisIRBinning", {150, 0, 1500}, "Binning for the interaction rate (kHz)"}; + + void init(InitContext const&) + { + // setting CCDB service + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + + histos.add("hEventCentrality", "hEventCentrality", kTH1D, {axisCentrality}); + + histos.add("PhotonSel/h3dPhotonMass", "h3dPhotonMass", kTH3D, {axisCentrality, axisPt, axisPhotonMass}); + histos.add("LambdaSel/h3dLambdaMass", "h3dLambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); + histos.add("LambdaSel/h3dALambdaMass", "h3dALambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); + + histos.add("SigmaSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Sigma Mass Window"); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Sigma Y Window"); + + // For selection: + histos.add("SigmaSel/h3dMassSigma0BeforeSel", "h3dMassSigma0BeforeSel", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); + histos.add("SigmaSel/hSigmaMass", "hSigmaMass", kTH1F, {axisSigmaMass}); + histos.add("SigmaSel/hSigmaMassWindow", "hSigmaMassWindow", kTH1F, {{200, -0.09f, 0.11f}}); + histos.add("SigmaSel/hSigmaY", "hSigmaY", kTH1F, {axisRapidity}); + histos.add("SigmaSel/hSigmaMassSelected", "hSigmaMassSelected", kTH1F, {axisSigmaMass}); + histos.add("SigmaSel/h3dMassSigma0AfterSel", "h3dMassSigma0AfterSel", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); + + if (fGetIR) { + histos.add("GeneralQA/hRunNumberNegativeIR", "", kTH1D, {{1, 0., 1.}}); + histos.add("GeneralQA/hInteractionRate", "hInteractionRate", kTH1F, {axisIRBinning}); + histos.add("GeneralQA/hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2F, {axisCentrality, axisIRBinning}); + } + + // For Pi0 QA + if (doPi0QA) { + histos.add("Pi0QA/h3dMassPi0BeforeSel_Candidates", "h3dMassPi0BeforeSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); + histos.add("Pi0QA/h3dMassPi0AfterSel_Candidates", "h3dMassPi0AfterSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); + } + } + + template + bool IsEventAccepted(TCollision collision) + // check whether the collision passes our collision selections + { + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + } else { // we are in Pb-Pb + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + return false; + } + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } + } + // Fetch interaction rate only if required (in order to limit ccdb calls) + double interactionRate = (eventSelections.minIR >= 0 || eventSelections.maxIR >= 0) ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource, fIRCrashOnNull) * 1.e-3 : -1; + if (eventSelections.minIR >= 0 && interactionRate < eventSelections.minIR) { + return false; + } + if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { + return false; + } + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("hEventCentrality"), centrality); + return true; + } + + template + void runPi0QA(TV0Object const& gamma1, TV0Object const& gamma2, TCollision collision) + { + // Check if both V0s are made of the same tracks + if (gamma1.posTrackExtraId() == gamma2.posTrackExtraId() || + gamma1.negTrackExtraId() == gamma2.negTrackExtraId()) { + return; + } + + // Calculate pi0 properties + std::array pVecGamma1{gamma1.px(), gamma1.py(), gamma1.pz()}; + std::array pVecGamma2{gamma2.px(), gamma2.py(), gamma2.pz()}; + std::array arrpi0{pVecGamma1, pVecGamma2}; + float pi0Mass = RecoDecay::m(arrpi0, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassPhoton}); + float pi0Pt = RecoDecay::pt(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py()}); + float pi0Y = RecoDecay::y(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py(), gamma1.pz() + gamma2.pz()}, o2::constants::physics::MassPi0); + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + histos.fill(HIST("Pi0QA/h3dMassPi0BeforeSel_Candidates"), centrality, pi0Pt, pi0Mass); + + // Photon-specific selections + auto posTrackGamma1 = gamma1.template posTrackExtra_as(); + auto negTrackGamma1 = gamma1.template negTrackExtra_as(); + auto posTrackGamma2 = gamma2.template posTrackExtra_as(); + auto negTrackGamma2 = gamma2.template negTrackExtra_as(); + + // Gamma1 Selection + bool passedTPCGamma1 = (TMath::Abs(posTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || + (TMath::Abs(negTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); + + if (TMath::Abs(gamma1.mGamma()) > Pi0PhotonMaxMass || + gamma1.qtarm() >= Pi0PhotonMaxQt || + TMath::Abs(gamma1.alpha()) >= Pi0PhotonMaxAlpha || + TMath::Abs(gamma1.dcapostopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma1.dcanegtopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma1.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || + TMath::Abs(gamma1.negativeeta()) >= Pi0PhotonMaxEta || + TMath::Abs(gamma1.positiveeta()) >= Pi0PhotonMaxEta || + gamma1.v0cosPA() <= Pi0PhotonMinV0cospa || + gamma1.v0radius() <= Pi0PhotonMinRadius || + gamma1.v0radius() >= Pi0PhotonMaxRadius || + posTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + negTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + !passedTPCGamma1) { + return; + } + + // Gamma2 Selection + bool passedTPCGamma2 = (TMath::Abs(posTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || + (TMath::Abs(negTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); + + if (TMath::Abs(gamma2.mGamma()) > Pi0PhotonMaxMass || + gamma2.qtarm() >= Pi0PhotonMaxQt || + TMath::Abs(gamma2.alpha()) >= Pi0PhotonMaxAlpha || + TMath::Abs(gamma2.dcapostopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma2.dcanegtopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma2.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || + TMath::Abs(gamma2.negativeeta()) >= Pi0PhotonMaxEta || + TMath::Abs(gamma2.positiveeta()) >= Pi0PhotonMaxEta || + gamma2.v0cosPA() <= Pi0PhotonMinV0cospa || + gamma2.v0radius() <= Pi0PhotonMinRadius || + gamma2.v0radius() >= Pi0PhotonMaxRadius || + posTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + negTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + !passedTPCGamma2) { + return; + } + + // Pi0-specific selections: + if (TMath::Abs(pi0Y) > 0.5) { + return; + } + + // Fill histograms + histos.fill(HIST("Pi0QA/h3dMassPi0AfterSel_Candidates"), centrality, pi0Pt, pi0Mass); + } + + // Process photon candidate + template + bool processPhotonCandidate(TV0Object const& gamma, TCollision collision) + { + if (gamma.v0Type() == 0) + return false; + + if (useMLScores) { + // Gamma selection: + if (gamma.gammaBDTScore() <= Gamma_MLThreshold) + return false; + + } else { + // Standard selection + // Gamma basic selection criteria: + if ((gamma.mGamma() < 0) || (gamma.mGamma() > PhotonMaxMass)) + return false; + float PhotonY = RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma); + if ((TMath::Abs(PhotonY) > V0Rapidity) || (TMath::Abs(gamma.negativeeta()) > PhotonMaxDauPseudoRap) || (TMath::Abs(gamma.positiveeta()) > PhotonMaxDauPseudoRap)) + return false; + if ((TMath::Abs(gamma.dcapostopv()) < PhotonMinDCAToPv) || (TMath::Abs(gamma.dcanegtopv()) < PhotonMinDCAToPv)) + return false; + if (TMath::Abs(gamma.dcaV0daughters()) > PhotonMaxDCAV0Dau) + return false; + if ((gamma.v0radius() < PhotonMinRadius) || (gamma.v0radius() > PhotonMaxRadius)) + return false; + } + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("PhotonSel/h3dPhotonMass"), centrality, gamma.pt(), gamma.mGamma()); + return true; + } + + // Process photon candidate + template + bool processLambdaCandidate(TV0Object const& lambda, TCollision collision) + { + if (lambda.v0Type() != 1) + return false; + + if (useMLScores) { + if ((lambda.lambdaBDTScore() <= Lambda_MLThreshold) && (lambda.antiLambdaBDTScore() <= AntiLambda_MLThreshold)) + return false; + + } else { + // Lambda basic selection criteria: + if ((TMath::Abs(lambda.mLambda() - o2::constants::physics::MassLambda0) > LambdaWindow) && (TMath::Abs(lambda.mAntiLambda() - o2::constants::physics::MassLambda0) > LambdaWindow)) + return false; + if ((TMath::Abs(lambda.yLambda()) > V0Rapidity) || (TMath::Abs(lambda.negativeeta()) > LambdaDauPseudoRap) || (TMath::Abs(lambda.positiveeta()) > LambdaDauPseudoRap)) + return false; + if ((TMath::Abs(lambda.dcapostopv()) < LambdaMinDCAPosToPv) || (TMath::Abs(lambda.dcanegtopv()) < LambdaMinDCANegToPv)) + return false; + if ((lambda.v0radius() < LambdaMinv0radius) || (lambda.v0radius() > LambdaMaxv0radius)) + return false; + if (TMath::Abs(lambda.dcaV0daughters()) > LambdaMaxDCAV0Dau) + return false; + } + + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("LambdaSel/h3dLambdaMass"), centrality, lambda.pt(), lambda.mLambda()); + histos.fill(HIST("LambdaSel/h3dALambdaMass"), centrality, lambda.pt(), lambda.mAntiLambda()); + + return true; + } + /////////// + // Process sigma candidate and store properties in object + template + bool buildSigma0(TV0Object const& lambda, TV0Object const& gamma, TCollision collision) + { + // Checking if both V0s are made of the very same tracks + if (gamma.posTrackExtraId() == lambda.posTrackExtraId() || + gamma.negTrackExtraId() == lambda.negTrackExtraId()) { + return false; + } + + // Sigma0 candidate properties + std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; + std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; + auto arrMom = std::array{pVecPhotons, pVecLambda}; + float sigmaMass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); + float sigmaY = RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0); + float SigmapT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + // Before any selection + histos.fill(HIST("SigmaSel/h3dMassSigma0BeforeSel"), centrality, SigmapT, sigmaMass); + + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 1.); + histos.fill(HIST("SigmaSel/hSigmaMass"), sigmaMass); + histos.fill(HIST("SigmaSel/hSigmaMassWindow"), sigmaMass - 1.192642); + + if (TMath::Abs(sigmaMass - 1.192642) > Sigma0Window) + return false; + + histos.fill(HIST("SigmaSel/hSigmaY"), sigmaY); + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 2.); + + if (TMath::Abs(sigmaY) > SigmaMaxRap) + return false; + + histos.fill(HIST("SigmaSel/hSigmaMassSelected"), sigmaMass); + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 3.); + histos.fill(HIST("SigmaSel/h3dMassSigma0AfterSel"), centrality, SigmapT, sigmaMass); + + return true; + } + + // ______________________________________________________ + // Real data processing - no MC subscription + template + void runAnalysis(TCollision const& collisions, TV0s const& fullV0s) + { + uint64_t CollIDBuffer = 0; + for (const auto& coll : collisions) { + if (!IsEventAccepted(coll)) + continue; + + float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); + const uint64_t collIdx = coll.globalIndex(); + if (collIdx < CollIDBuffer) + LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, collIdx); + + CollIDBuffer = collIdx; + + //_______________________________________________ + // V0s loop + std::vector bestGammasArray; + std::vector bestLambdasArray; + + auto V0s = fullV0s.sliceBy(perCollisionSTDDerived, collIdx); + for (auto& v0 : V0s) { + if (processPhotonCandidate(v0, coll)) // selecting photons + bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates + + if (processLambdaCandidate(v0, coll)) // selecting lambdas + bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates + } + + //_______________________________________________ + // Retrieving IR info + float interactionRate = -1; + if (fGetIR) { + interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource, fIRCrashOnNull) * 1.e-3; + if (interactionRate < 0) + histos.get(HIST("GeneralQA/hRunNumberNegativeIR"))->Fill(Form("%d", coll.runNumber()), 1); + + histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); + histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), centrality, interactionRate); + } + + //_______________________________________________ + // Pi0 optional loop + if (doPi0QA) { + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); + for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { + auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); + runPi0QA(gamma1, gamma2, coll); + } + } + } + + //_______________________________________________ + // Sigma0 nested loop + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); + + for (size_t j = 0; j < bestLambdasArray.size(); ++j) { + auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); + + // Building sigma0 candidate + if (!buildSigma0(lambda, gamma, coll)) + continue; + } + } + } + } + + void processRealData(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + auto start = std::chrono::high_resolution_clock::now(); + + runAnalysis(collisions, fullV0s); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + + if (fverbose) LOGF(info, "[Process function call, PreSlice] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + } + PROCESS_SWITCH(sigma0QCSorted, processRealData, "process using sliceby sorted", true); +}; + +struct sigma0QCIterator { + Service ccdb; + ctpRateFetcher rateFetcher; + + // Histogram registry + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; + Configurable fverbose{"fverbose", false, "QA printout."}; + + // Event level + Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + Configurable fGetIR{"fGetIR", false, "Flag to retrieve the IR info."}; + Configurable fIRCrashOnNull{"fIRCrashOnNull", false, "Flag to avoid CTP RateFetcher crash."}; + Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + + struct : ConfigurableGroup { + Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; + Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; + Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; + Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", true, "require events with at least one ITS-TPC track"}; + Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; + Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; + Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; + Configurable rejectSameBunchPileup{"rejectSameBunchPileup", false, "reject collisions in case of pileup with another collision in the same foundBC"}; + Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds"}; + Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; + Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds"}; + Configurable requireNoCollInTimeRangeVzDep{"requireNoCollInTimeRangeVzDep", false, "reject collisions corrupted by the cannibalism, with other collisions with pvZ of drifting TPC tracks from past/future collisions within 2.5 cm the current pvZ"}; + Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold"}; + Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF"}; + Configurable requireINEL0{"requireINEL0", false, "require INEL>0 event selection"}; + Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; + Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; + Configurable useEvtSelInDenomEff{"useEvtSelInDenomEff", false, "Consider event selections in the recoed <-> gen collision association for the denominator (or numerator) of the acc. x eff. (or signal loss)?"}; + Configurable applyZVtxSelOnMCPV{"applyZVtxSelOnMCPV", false, "Apply Z-vtx cut on the PV of the generated collision?"}; + Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; + // fast check on occupancy + Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + + // fast check on interaction rate + Configurable minIR{"minIR", -1, "minimum IR collisions"}; + Configurable maxIR{"maxIR", -1, "maximum IR collisions"}; + + } eventSelections; + + // For ML Selection + Configurable useMLScores{"useMLScores", false, "use ML scores to select candidates"}; + Configurable Gamma_MLThreshold{"Gamma_MLThreshold", 0.1, "Decision Threshold value to select gammas"}; + Configurable Lambda_MLThreshold{"Lambda_MLThreshold", 0.1, "Decision Threshold value to select lambdas"}; + Configurable AntiLambda_MLThreshold{"AntiLambda_MLThreshold", 0.1, "Decision Threshold value to select antilambdas"}; + + // For standard approach: + //// Lambda criteria: + Configurable V0Rapidity{"V0Rapidity", 0.8, "v0 rapidity"}; + + Configurable LambdaDauPseudoRap{"LambdaDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; + Configurable LambdaMinDCANegToPv{"LambdaMinDCANegToPv", 0.0, "min DCA Neg To PV (cm)"}; + Configurable LambdaMinDCAPosToPv{"LambdaMinDCAPosToPv", 0.0, "min DCA Pos To PV (cm)"}; + Configurable LambdaMaxDCAV0Dau{"LambdaMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable LambdaMinv0radius{"LambdaMinv0radius", 0.0, "Min V0 radius (cm)"}; + Configurable LambdaMaxv0radius{"LambdaMaxv0radius", 60, "Max V0 radius (cm)"}; + Configurable LambdaWindow{"LambdaWindow", 0.05, "Mass window around expected (in GeV/c2)"}; + + //// Photon criteria: + Configurable PhotonMaxDauPseudoRap{"PhotonMaxDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; + Configurable PhotonMinDCAToPv{"PhotonMinDCAToPv", 0.0, "Min DCA daughter To PV (cm)"}; + Configurable PhotonMaxDCAV0Dau{"PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable PhotonMinRadius{"PhotonMinRadius", 0.0, "Min photon conversion radius (cm)"}; + Configurable PhotonMaxRadius{"PhotonMaxRadius", 240, "Max photon conversion radius (cm)"}; + Configurable PhotonMaxMass{"PhotonMaxMass", 0.3, "Max photon mass (GeV/c^{2})"}; + + //// Sigma0 criteria: + Configurable Sigma0Window{"Sigma0Window", 0.1, "Mass window around expected (in GeV/c2)"}; + Configurable SigmaMaxRap{"SigmaMaxRap", 0.8, "Max sigma0 rapidity"}; + + //// Extras: + Configurable Pi0PhotonMinDCADauToPv{"Pi0PhotonMinDCADauToPv", 0.0, "Min DCA daughter To PV (cm)"}; + Configurable Pi0PhotonMaxDCAV0Dau{"Pi0PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + Configurable Pi0PhotonMinTPCCrossedRows{"Pi0PhotonMinTPCCrossedRows", 0, "Min daughter TPC Crossed Rows"}; + Configurable Pi0PhotonMaxTPCNSigmas{"Pi0PhotonMaxTPCNSigmas", 7, "Max TPC NSigmas for daughters"}; + Configurable Pi0PhotonMaxEta{"Pi0PhotonMaxEta", 0.8, "Max photon rapidity"}; + Configurable Pi0PhotonMinRadius{"Pi0PhotonMinRadius", 3.0, "Min photon conversion radius (cm)"}; + Configurable Pi0PhotonMaxRadius{"Pi0PhotonMaxRadius", 115, "Max photon conversion radius (cm)"}; + Configurable Pi0PhotonMaxQt{"Pi0PhotonMaxQt", 0.05, "Max photon qt value (AP plot) (GeV/c)"}; + Configurable Pi0PhotonMaxAlpha{"Pi0PhotonMaxAlpha", 0.95, "Max photon alpha absolute value (AP plot)"}; + Configurable Pi0PhotonMinV0cospa{"Pi0PhotonMinV0cospa", 0.80, "Min V0 CosPA"}; + Configurable Pi0PhotonMaxMass{"Pi0PhotonMaxMass", 0.10, "Max photon mass (GeV/c^{2})"}; + + // Axis + // base properties + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Centrality"}; + + // Invariant Mass + ConfigurableAxis axisSigmaMass{"axisSigmaMass", {500, 1.10f, 1.30f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; + ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.05f, 1.151f}, "M_{#Lambda} (GeV/c^{2})"}; + ConfigurableAxis axisPhotonMass{"axisPhotonMass", {200, -0.1f, 0.5f}, "M_{#Gamma}"}; + ConfigurableAxis axisPi0Mass{"axisPi0Mass", {200, 0.08f, 0.18f}, "M_{#Pi^{0}}"}; + + // topological variable QA axes + ConfigurableAxis axisRapidity{"axisRapidity", {100, -2.0f, 2.0f}, "Rapidity"}; + ConfigurableAxis axisCandSel{"axisCandSel", {7, 0.5f, +7.5f}, "Candidate Selection"}; + ConfigurableAxis axisIRBinning{"axisIRBinning", {150, 0, 1500}, "Binning for the interaction rate (kHz)"}; + + std::chrono::high_resolution_clock::time_point start{}; + std::chrono::high_resolution_clock::time_point end{}; + + void init(InitContext const&) + { + // setting CCDB service + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setFatalWhenNull(false); + + histos.add("hEventCentrality", "hEventCentrality", kTH1D, {axisCentrality}); + histos.add("PhotonSel/h3dPhotonMass", "h3dPhotonMass", kTH3D, {axisCentrality, axisPt, axisPhotonMass}); + histos.add("LambdaSel/h3dLambdaMass", "h3dLambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); + histos.add("LambdaSel/h3dALambdaMass", "h3dALambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); + + histos.add("SigmaSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Sigma Mass Window"); + histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Sigma Y Window"); + + // For selection: + histos.add("SigmaSel/h3dMassSigma0BeforeSel", "h3dMassSigma0BeforeSel", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); + histos.add("SigmaSel/hSigmaMass", "hSigmaMass", kTH1F, {axisSigmaMass}); + histos.add("SigmaSel/hSigmaMassWindow", "hSigmaMassWindow", kTH1F, {{200, -0.09f, 0.11f}}); + histos.add("SigmaSel/hSigmaY", "hSigmaY", kTH1F, {axisRapidity}); + histos.add("SigmaSel/hSigmaMassSelected", "hSigmaMassSelected", kTH1F, {axisSigmaMass}); + histos.add("SigmaSel/h3dMassSigma0AfterSel", "h3dMassSigma0AfterSel", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); + + if (fGetIR) { + histos.add("GeneralQA/hRunNumberNegativeIR", "", kTH1D, {{1, 0., 1.}}); + histos.add("GeneralQA/hInteractionRate", "hInteractionRate", kTH1F, {axisIRBinning}); + histos.add("GeneralQA/hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2F, {axisCentrality, axisIRBinning}); + } + + // For Pi0 QA + if (doPi0QA) { + histos.add("Pi0QA/h3dMassPi0BeforeSel_Candidates", "h3dMassPi0BeforeSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); + histos.add("Pi0QA/h3dMassPi0AfterSel_Candidates", "h3dMassPi0AfterSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); + } + } + + template + bool IsEventAccepted(TCollision collision) + // check whether the collision passes our collision selections + { + if (eventSelections.requireSel8 && !collision.sel8()) { + return false; + } + if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { + return false; + } + if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if (doPPAnalysis) { // we are in pp + if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + } else { // we are in Pb-Pb + float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { + return false; + } + if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { + return false; + } + } + // Fetch interaction rate only if required (in order to limit ccdb calls) + double interactionRate = (eventSelections.minIR >= 0 || eventSelections.maxIR >= 0) ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource, fIRCrashOnNull) * 1.e-3 : -1; + if (eventSelections.minIR >= 0 && interactionRate < eventSelections.minIR) { + return false; + } + if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { + return false; + } + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("hEventCentrality"), centrality); + return true; + } + + template + void runPi0QA(TV0Object const& gamma1, TV0Object const& gamma2, TCollision collision) + { + // Check if both V0s are made of the same tracks + if (gamma1.posTrackExtraId() == gamma2.posTrackExtraId() || + gamma1.negTrackExtraId() == gamma2.negTrackExtraId()) { + return; + } + + // Calculate pi0 properties + std::array pVecGamma1{gamma1.px(), gamma1.py(), gamma1.pz()}; + std::array pVecGamma2{gamma2.px(), gamma2.py(), gamma2.pz()}; + std::array arrpi0{pVecGamma1, pVecGamma2}; + float pi0Mass = RecoDecay::m(arrpi0, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassPhoton}); + float pi0Pt = RecoDecay::pt(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py()}); + float pi0Y = RecoDecay::y(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py(), gamma1.pz() + gamma2.pz()}, o2::constants::physics::MassPi0); + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + histos.fill(HIST("Pi0QA/h3dMassPi0BeforeSel_Candidates"), centrality, pi0Pt, pi0Mass); + + // Photon-specific selections + auto posTrackGamma1 = gamma1.template posTrackExtra_as(); + auto negTrackGamma1 = gamma1.template negTrackExtra_as(); + auto posTrackGamma2 = gamma2.template posTrackExtra_as(); + auto negTrackGamma2 = gamma2.template negTrackExtra_as(); + + // Gamma1 Selection + bool passedTPCGamma1 = (TMath::Abs(posTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || + (TMath::Abs(negTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); + + if (TMath::Abs(gamma1.mGamma()) > Pi0PhotonMaxMass || + gamma1.qtarm() >= Pi0PhotonMaxQt || + TMath::Abs(gamma1.alpha()) >= Pi0PhotonMaxAlpha || + TMath::Abs(gamma1.dcapostopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma1.dcanegtopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma1.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || + TMath::Abs(gamma1.negativeeta()) >= Pi0PhotonMaxEta || + TMath::Abs(gamma1.positiveeta()) >= Pi0PhotonMaxEta || + gamma1.v0cosPA() <= Pi0PhotonMinV0cospa || + gamma1.v0radius() <= Pi0PhotonMinRadius || + gamma1.v0radius() >= Pi0PhotonMaxRadius || + posTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + negTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + !passedTPCGamma1) { + return; + } + + // Gamma2 Selection + bool passedTPCGamma2 = (TMath::Abs(posTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || + (TMath::Abs(negTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); + + if (TMath::Abs(gamma2.mGamma()) > Pi0PhotonMaxMass || + gamma2.qtarm() >= Pi0PhotonMaxQt || + TMath::Abs(gamma2.alpha()) >= Pi0PhotonMaxAlpha || + TMath::Abs(gamma2.dcapostopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma2.dcanegtopv()) < Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma2.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || + TMath::Abs(gamma2.negativeeta()) >= Pi0PhotonMaxEta || + TMath::Abs(gamma2.positiveeta()) >= Pi0PhotonMaxEta || + gamma2.v0cosPA() <= Pi0PhotonMinV0cospa || + gamma2.v0radius() <= Pi0PhotonMinRadius || + gamma2.v0radius() >= Pi0PhotonMaxRadius || + posTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + negTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || + !passedTPCGamma2) { + return; + } + + // Pi0-specific selections: + if (TMath::Abs(pi0Y) > 0.5) { + return; + } + + // Fill histograms + histos.fill(HIST("Pi0QA/h3dMassPi0AfterSel_Candidates"), centrality, pi0Pt, pi0Mass); + } + + // Process photon candidate + template + bool processPhotonCandidate(TV0Object const& gamma, TCollision collision) + { + if (gamma.v0Type() == 0) + return false; + + if (useMLScores) { + // Gamma selection: + if (gamma.gammaBDTScore() <= Gamma_MLThreshold) + return false; + + } else { + // Standard selection + // Gamma basic selection criteria: + if ((gamma.mGamma() < 0) || (gamma.mGamma() > PhotonMaxMass)) + return false; + float PhotonY = RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma); + if ((TMath::Abs(PhotonY) > V0Rapidity) || (TMath::Abs(gamma.negativeeta()) > PhotonMaxDauPseudoRap) || (TMath::Abs(gamma.positiveeta()) > PhotonMaxDauPseudoRap)) + return false; + if ((TMath::Abs(gamma.dcapostopv()) < PhotonMinDCAToPv) || (TMath::Abs(gamma.dcanegtopv()) < PhotonMinDCAToPv)) + return false; + if (TMath::Abs(gamma.dcaV0daughters()) > PhotonMaxDCAV0Dau) + return false; + if ((gamma.v0radius() < PhotonMinRadius) || (gamma.v0radius() > PhotonMaxRadius)) + return false; + } + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("PhotonSel/h3dPhotonMass"), centrality, gamma.pt(), gamma.mGamma()); + return true; + } + + // Process photon candidate + template + bool processLambdaCandidate(TV0Object const& lambda, TCollision collision) + { + if (lambda.v0Type() != 1) + return false; + + if (useMLScores) { + if ((lambda.lambdaBDTScore() <= Lambda_MLThreshold) && (lambda.antiLambdaBDTScore() <= AntiLambda_MLThreshold)) + return false; + + } else { + // Lambda basic selection criteria: + if ((TMath::Abs(lambda.mLambda() - o2::constants::physics::MassLambda0) > LambdaWindow) && (TMath::Abs(lambda.mAntiLambda() - o2::constants::physics::MassLambda0) > LambdaWindow)) + return false; + if ((TMath::Abs(lambda.yLambda()) > V0Rapidity) || (TMath::Abs(lambda.negativeeta()) > LambdaDauPseudoRap) || (TMath::Abs(lambda.positiveeta()) > LambdaDauPseudoRap)) + return false; + if ((TMath::Abs(lambda.dcapostopv()) < LambdaMinDCAPosToPv) || (TMath::Abs(lambda.dcanegtopv()) < LambdaMinDCANegToPv)) + return false; + if ((lambda.v0radius() < LambdaMinv0radius) || (lambda.v0radius() > LambdaMaxv0radius)) + return false; + if (TMath::Abs(lambda.dcaV0daughters()) > LambdaMaxDCAV0Dau) + return false; + } + + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.fill(HIST("LambdaSel/h3dLambdaMass"), centrality, lambda.pt(), lambda.mLambda()); + histos.fill(HIST("LambdaSel/h3dALambdaMass"), centrality, lambda.pt(), lambda.mAntiLambda()); + + return true; + } + /////////// + // Process sigma candidate and store properties in object + template + bool buildSigma0(TV0Object const& lambda, TV0Object const& gamma, TCollision collision) + { + // Checking if both V0s are made of the very same tracks + if (gamma.posTrackExtraId() == lambda.posTrackExtraId() || + gamma.negTrackExtraId() == lambda.negTrackExtraId()) { + return false; + } + + // Sigma0 candidate properties + std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; + std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; + auto arrMom = std::array{pVecPhotons, pVecLambda}; + float sigmaMass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); + float sigmaY = RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0); + float SigmapT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); + float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + // Before any selection + histos.fill(HIST("SigmaSel/h3dMassSigma0BeforeSel"), centrality, SigmapT, sigmaMass); + + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 1.); + histos.fill(HIST("SigmaSel/hSigmaMass"), sigmaMass); + histos.fill(HIST("SigmaSel/hSigmaMassWindow"), sigmaMass - 1.192642); + + if (TMath::Abs(sigmaMass - 1.192642) > Sigma0Window) + return false; + + histos.fill(HIST("SigmaSel/hSigmaY"), sigmaY); + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 2.); + + if (TMath::Abs(sigmaY) > SigmaMaxRap) + return false; + + histos.fill(HIST("SigmaSel/hSigmaMassSelected"), sigmaMass); + histos.fill(HIST("SigmaSel/hSelectionStatistics"), 3.); + histos.fill(HIST("SigmaSel/h3dMassSigma0AfterSel"), centrality, SigmapT, sigmaMass); + + return true; + } + + // ______________________________________________________ + // Real data processing - no MC subscription + template + void runAnalysis(TCollision const& coll, TV0s const& fullV0s) + { + if (!IsEventAccepted(coll)) + return; + + float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); + + //_______________________________________________ + // V0s loop + std::vector bestGammasArray; + std::vector bestLambdasArray; + + for (auto& v0 : fullV0s) { + if (processPhotonCandidate(v0, coll)) // selecting photons + bestGammasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best gamma candidates + + if (processLambdaCandidate(v0, coll)) // selecting lambdas + bestLambdasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best lambda candidates + } + + //_______________________________________________ + // Retrieving IR info + float interactionRate = -1; + if (fGetIR) { + interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource, fIRCrashOnNull) * 1.e-3; + if (interactionRate < 0) + histos.get(HIST("GeneralQA/hRunNumberNegativeIR"))->Fill(Form("%d", coll.runNumber()), 1); + + histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); + histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), centrality, interactionRate); + } + + //_______________________________________________ + // Pi0 optional loop + if (doPi0QA) { + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); + for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { + auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); + runPi0QA(gamma1, gamma2, coll); + } + } + } + + //_______________________________________________ + // Sigma0 nested loop + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); + + for (size_t j = 0; j < bestLambdasArray.size(); ++j) { + auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); + + // Building sigma0 candidate + if (!buildSigma0(lambda, gamma, coll)) + continue; + } + } + } + + void processStartTime() + { + start = std::chrono::high_resolution_clock::now(); + } + void processRealData(soa::Join::iterator const& coll, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + processStartTime(); + runAnalysis(coll, fullV0s); + } + void processEndTime(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s) + { + end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + + if (fverbose) LOGF(info, "[Process function call, Iterator] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + } + PROCESS_SWITCH(sigma0QCIterator, processRealData, "process using iterators", true); + PROCESS_SWITCH(sigma0QCIterator, processEndTime, "process using iterators. End time.", true); +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +} From 5d140bcb5c91a592cab70b7eb54144d19873f69f Mon Sep 17 00:00:00 2001 From: gianniliveraro Date: Fri, 11 Jul 2025 05:15:10 -0300 Subject: [PATCH 4/8] More modularity for grouping QC --- PWGLF/TableProducer/QC/sigma0QC.cxx | 1710 +-------------------------- PWGLF/Utils/sigma0BuilderHelper.h | 539 +++++++++ 2 files changed, 596 insertions(+), 1653 deletions(-) create mode 100644 PWGLF/Utils/sigma0BuilderHelper.h diff --git a/PWGLF/TableProducer/QC/sigma0QC.cxx b/PWGLF/TableProducer/QC/sigma0QC.cxx index 65d2f869755..de752c0534e 100644 --- a/PWGLF/TableProducer/QC/sigma0QC.cxx +++ b/PWGLF/TableProducer/QC/sigma0QC.cxx @@ -50,6 +50,7 @@ #include #include #include +#include using namespace o2; using namespace o2::framework; @@ -57,1711 +58,114 @@ using namespace o2::framework::expressions; using std::array; using dauTracks = soa::Join; using V0StandardDerivedDatas = soa::Join; +using StraColls = soa::Join; -struct sigma0QC { + +struct sigma0Sorted { Service ccdb; ctpRateFetcher rateFetcher; - SliceCache cache; + // Load configurables and the sigma0 module, please + o2::pwglf::sigma0::evselConfigurables evselOpts; + o2::pwglf::sigma0::lambdaselConfigurables lambdaselOpts; + o2::pwglf::sigma0::photonselConfigurables photonselOpts; + o2::pwglf::sigma0::sigma0selConfigurables sigma0selOpts; + o2::pwglf::sigma0::pi0selConfigurables pi0selOpts; + o2::pwglf::sigma0::axisConfigurables axisOpts; + + o2::pwglf::sigma0::Sigma0BuilderModule sigma0Module; // For manual sliceBy - PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; + SliceCache cache; + Preslice perCollisionSTDDerived = o2::aod::v0data::straCollisionId; // Histogram registry HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; - Configurable fverbose{"fverbose", false, "QA printout."}; - - // Event level - Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; - Configurable fGetIR{"fGetIR", false, "Flag to retrieve the IR info."}; - Configurable fIRCrashOnNull{"fIRCrashOnNull", false, "Flag to avoid CTP RateFetcher crash."}; - Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; - - struct : ConfigurableGroup { - Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; - Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; - Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; - Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; - Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", true, "require events with at least one ITS-TPC track"}; - Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; - Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; - Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; - Configurable rejectSameBunchPileup{"rejectSameBunchPileup", false, "reject collisions in case of pileup with another collision in the same foundBC"}; - Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds"}; - Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; - Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds"}; - Configurable requireNoCollInTimeRangeVzDep{"requireNoCollInTimeRangeVzDep", false, "reject collisions corrupted by the cannibalism, with other collisions with pvZ of drifting TPC tracks from past/future collisions within 2.5 cm the current pvZ"}; - Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold"}; - Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF"}; - Configurable requireINEL0{"requireINEL0", false, "require INEL>0 event selection"}; - Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; - Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; - Configurable useEvtSelInDenomEff{"useEvtSelInDenomEff", false, "Consider event selections in the recoed <-> gen collision association for the denominator (or numerator) of the acc. x eff. (or signal loss)?"}; - Configurable applyZVtxSelOnMCPV{"applyZVtxSelOnMCPV", false, "Apply Z-vtx cut on the PV of the generated collision?"}; - Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; - // fast check on occupancy - Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; - Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; - - // fast check on interaction rate - Configurable minIR{"minIR", -1, "minimum IR collisions"}; - Configurable maxIR{"maxIR", -1, "maximum IR collisions"}; - - } eventSelections; - - // For ML Selection - Configurable useMLScores{"useMLScores", false, "use ML scores to select candidates"}; - Configurable Gamma_MLThreshold{"Gamma_MLThreshold", 0.1, "Decision Threshold value to select gammas"}; - Configurable Lambda_MLThreshold{"Lambda_MLThreshold", 0.1, "Decision Threshold value to select lambdas"}; - Configurable AntiLambda_MLThreshold{"AntiLambda_MLThreshold", 0.1, "Decision Threshold value to select antilambdas"}; - - // For standard approach: - //// Lambda criteria: - Configurable V0Rapidity{"V0Rapidity", 0.8, "v0 rapidity"}; - - Configurable LambdaDauPseudoRap{"LambdaDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; - Configurable LambdaMinDCANegToPv{"LambdaMinDCANegToPv", 0.0, "min DCA Neg To PV (cm)"}; - Configurable LambdaMinDCAPosToPv{"LambdaMinDCAPosToPv", 0.0, "min DCA Pos To PV (cm)"}; - Configurable LambdaMaxDCAV0Dau{"LambdaMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; - Configurable LambdaMinv0radius{"LambdaMinv0radius", 0.0, "Min V0 radius (cm)"}; - Configurable LambdaMaxv0radius{"LambdaMaxv0radius", 60, "Max V0 radius (cm)"}; - Configurable LambdaWindow{"LambdaWindow", 0.05, "Mass window around expected (in GeV/c2)"}; - - //// Photon criteria: - Configurable PhotonMaxDauPseudoRap{"PhotonMaxDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; - Configurable PhotonMinDCAToPv{"PhotonMinDCAToPv", 0.0, "Min DCA daughter To PV (cm)"}; - Configurable PhotonMaxDCAV0Dau{"PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; - Configurable PhotonMinRadius{"PhotonMinRadius", 0.0, "Min photon conversion radius (cm)"}; - Configurable PhotonMaxRadius{"PhotonMaxRadius", 240, "Max photon conversion radius (cm)"}; - Configurable PhotonMaxMass{"PhotonMaxMass", 0.3, "Max photon mass (GeV/c^{2})"}; - - //// Sigma0 criteria: - Configurable Sigma0Window{"Sigma0Window", 0.1, "Mass window around expected (in GeV/c2)"}; - Configurable SigmaMaxRap{"SigmaMaxRap", 0.8, "Max sigma0 rapidity"}; - - //// Extras: - Configurable Pi0PhotonMinDCADauToPv{"Pi0PhotonMinDCADauToPv", 0.0, "Min DCA daughter To PV (cm)"}; - Configurable Pi0PhotonMaxDCAV0Dau{"Pi0PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; - Configurable Pi0PhotonMinTPCCrossedRows{"Pi0PhotonMinTPCCrossedRows", 0, "Min daughter TPC Crossed Rows"}; - Configurable Pi0PhotonMaxTPCNSigmas{"Pi0PhotonMaxTPCNSigmas", 7, "Max TPC NSigmas for daughters"}; - Configurable Pi0PhotonMaxEta{"Pi0PhotonMaxEta", 0.8, "Max photon rapidity"}; - Configurable Pi0PhotonMinRadius{"Pi0PhotonMinRadius", 3.0, "Min photon conversion radius (cm)"}; - Configurable Pi0PhotonMaxRadius{"Pi0PhotonMaxRadius", 115, "Max photon conversion radius (cm)"}; - Configurable Pi0PhotonMaxQt{"Pi0PhotonMaxQt", 0.05, "Max photon qt value (AP plot) (GeV/c)"}; - Configurable Pi0PhotonMaxAlpha{"Pi0PhotonMaxAlpha", 0.95, "Max photon alpha absolute value (AP plot)"}; - Configurable Pi0PhotonMinV0cospa{"Pi0PhotonMinV0cospa", 0.80, "Min V0 CosPA"}; - Configurable Pi0PhotonMaxMass{"Pi0PhotonMaxMass", 0.10, "Max photon mass (GeV/c^{2})"}; - - // Axis - // base properties - ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; - ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Centrality"}; - - // Invariant Mass - ConfigurableAxis axisSigmaMass{"axisSigmaMass", {500, 1.10f, 1.30f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; - ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.05f, 1.151f}, "M_{#Lambda} (GeV/c^{2})"}; - ConfigurableAxis axisPhotonMass{"axisPhotonMass", {200, -0.1f, 0.5f}, "M_{#Gamma}"}; - ConfigurableAxis axisPi0Mass{"axisPi0Mass", {200, 0.08f, 0.18f}, "M_{#Pi^{0}}"}; - ConfigurableAxis axisK0SMass{"axisK0SMass", {200, 0.4f, 0.6f}, "M_{K^{0}}"}; - - // AP plot axes - ConfigurableAxis axisAPAlpha{"axisAPAlpha", {220, -1.1f, 1.1f}, "V0 AP alpha"}; - ConfigurableAxis axisAPQt{"axisAPQt", {220, 0.0f, 0.5f}, "V0 AP alpha"}; - - // Track quality axes - ConfigurableAxis axisTPCrows{"axisTPCrows", {160, 0.0f, 160.0f}, "N TPC rows"}; - - // topological variable QA axes - ConfigurableAxis axisDCAtoPV{"axisDCAtoPV", {500, 0.0f, 50.0f}, "DCA (cm)"}; - ConfigurableAxis axisXY{"axisXY", {120, -120.0f, 120.0f}, "XY axis"}; - ConfigurableAxis axisDCAdau{"axisDCAdau", {50, 0.0f, 5.0f}, "DCA (cm)"}; - ConfigurableAxis axisRadius{"axisRadius", {240, 0.0f, 120.0f}, "V0 radius (cm)"}; - ConfigurableAxis axisPA{"axisPA", {100, 0.0f, 1}, "Pointing angle"}; - ConfigurableAxis axisRapidity{"axisRapidity", {100, -2.0f, 2.0f}, "Rapidity"}; - ConfigurableAxis axisCandSel{"axisCandSel", {7, 0.5f, +7.5f}, "Candidate Selection"}; - ConfigurableAxis axisNch{"axisNch", {300, 0.0f, 3000.0f}, "N_{ch}"}; - ConfigurableAxis axisIRBinning{"axisIRBinning", {150, 0, 1500}, "Binning for the interaction rate (kHz)"}; + Configurable fverbose{"fverbose", true, "QA printout."}; void init(InitContext const&) { // setting CCDB service ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); - // Event Counters - histos.add("hEventSelection", "hEventSelection", kTH1D, {{21, -0.5f, +20.5f}}); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(1, "All collisions"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(2, "sel8 cut"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(3, "kIsTriggerTVX"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(4, "kNoITSROFrameBorder"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(5, "kNoTimeFrameBorder"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(6, "posZ cut"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(7, "kIsVertexITSTPC"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(8, "kIsGoodZvtxFT0vsPV"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(9, "kIsVertexTOFmatched"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(10, "kIsVertexTRDmatched"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(11, "kNoSameBunchPileup"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(12, "kNoCollInTimeRangeStd"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(13, "kNoCollInTimeRangeStrict"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(14, "kNoCollInTimeRangeNarrow"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(15, "kNoCollInRofStd"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(16, "kNoCollInRofStrict"); - if (doPPAnalysis) { - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "INEL>0"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "INEL>1"); - } else { - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(17, "Below min occup."); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(18, "Above max occup."); - } - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(19, "Below min IR"); - histos.get(HIST("hEventSelection"))->GetXaxis()->SetBinLabel(20, "Above max IR"); - - histos.add("hEventCentrality", "hEventCentrality", kTH1D, {axisCentrality}); - - histos.add("PhotonSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); - histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); - histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Photon Mass Cut"); - histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Photon Eta/Y Cut"); - histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(4, "Photon DCAToPV Cut"); - histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(5, "Photon DCADau Cut"); - histos.get(HIST("PhotonSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(6, "Photon Radius Cut"); - - histos.add("PhotonSel/hPhotonMass", "hPhotonMass", kTH1F, {axisPhotonMass}); - histos.add("PhotonSel/hPhotonNegEta", "hPhotonNegEta", kTH1F, {axisRapidity}); - histos.add("PhotonSel/hPhotonPosEta", "hPhotonPosEta", kTH1F, {axisRapidity}); - histos.add("PhotonSel/hPhotonY", "hPhotonY", kTH1F, {axisRapidity}); - histos.add("PhotonSel/hPhotonDCANegToPV", "hPhotonDCANegToPV", kTH1F, {axisDCAtoPV}); - histos.add("PhotonSel/hPhotonDCAPosToPV", "hPhotonDCAPosToPV", kTH1F, {axisDCAtoPV}); - histos.add("PhotonSel/hPhotonDCADau", "hPhotonDCADau", kTH1F, {axisDCAdau}); - histos.add("PhotonSel/hPhotonRadius", "hPhotonRadius", kTH1F, {axisRadius}); - histos.add("PhotonSel/h3dPhotonMass", "h3dPhotonMass", kTH3D, {axisCentrality, axisPt, axisPhotonMass}); - - histos.add("LambdaSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); - histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); - histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Lambda Mass Cut"); - histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Lambda Eta/Y Cut"); - histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(4, "Lambda DCAToPV Cut"); - histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(5, "Lambda Radius Cut"); - histos.get(HIST("LambdaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(6, "Lambda DCADau Cut"); - - histos.add("LambdaSel/hLambdaMass", "hLambdaMass", kTH1F, {axisLambdaMass}); - histos.add("LambdaSel/hAntiLambdaMass", "hAntiLambdaMass", kTH1F, {axisLambdaMass}); - histos.add("LambdaSel/hLambdaNegEta", "hLambdaNegEta", kTH1F, {axisRapidity}); - histos.add("LambdaSel/hLambdaPosEta", "hLambdaPosEta", kTH1F, {axisRapidity}); - histos.add("LambdaSel/hLambdaY", "hLambdaY", kTH1F, {axisRapidity}); - histos.add("LambdaSel/hLambdaDCANegToPV", "hLambdaDCANegToPV", kTH1F, {axisDCAtoPV}); - histos.add("LambdaSel/hLambdaDCAPosToPV", "hLambdaDCAPosToPV", kTH1F, {axisDCAtoPV}); - histos.add("LambdaSel/hLambdaDCADau", "hLambdaDCADau", kTH1F, {axisDCAdau}); - histos.add("LambdaSel/hLambdaRadius", "hLambdaRadius", kTH1F, {axisRadius}); - histos.add("LambdaSel/h3dLambdaMass", "h3dLambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); - histos.add("LambdaSel/h3dALambdaMass", "h3dALambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); - - histos.add("SigmaSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); - histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); - histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Sigma Mass Window"); - histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Sigma Y Window"); - - // For selection: - histos.add("SigmaSel/h3dMassSigma0BeforeSel", "h3dMassSigma0BeforeSel", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); - histos.add("SigmaSel/hSigmaMass", "hSigmaMass", kTH1F, {axisSigmaMass}); - histos.add("SigmaSel/hSigmaMassWindow", "hSigmaMassWindow", kTH1F, {{200, -0.09f, 0.11f}}); - histos.add("SigmaSel/hSigmaY", "hSigmaY", kTH1F, {axisRapidity}); - histos.add("SigmaSel/hSigmaMassSelected", "hSigmaMassSelected", kTH1F, {axisSigmaMass}); - histos.add("SigmaSel/h3dMassSigma0AfterSel", "h3dMassSigma0AfterSel", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); - - if (fGetIR) { - histos.add("GeneralQA/hRunNumberNegativeIR", "", kTH1D, {{1, 0., 1.}}); - histos.add("GeneralQA/hInteractionRate", "hInteractionRate", kTH1F, {axisIRBinning}); - histos.add("GeneralQA/hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2F, {axisCentrality, axisIRBinning}); - } - - // For Pi0 QA - if (doPi0QA) { - histos.add("Pi0QA/h3dMassPi0BeforeSel_MCAssoc", "h3dMassPi0BeforeSel_MCAssoc", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); - histos.add("Pi0QA/h3dMassPi0AfterSel_MCAssoc", "h3dMassPi0AfterSel_MCAssoc", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); - histos.add("Pi0QA/h3dMassPi0BeforeSel_Candidates", "h3dMassPi0BeforeSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); - histos.add("Pi0QA/h3dMassPi0AfterSel_Candidates", "h3dMassPi0AfterSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); - } + // Initialize task + sigma0Module.init(histos, evselOpts, lambdaselOpts, photonselOpts, sigma0selOpts, pi0selOpts, axisOpts); } - template - bool IsEventAccepted(TCollision collision, bool fillHists) - // check whether the collision passes our collision selections - { - if (fillHists) - histos.fill(HIST("hEventSelection"), 0. /* all collisions */); - if (eventSelections.requireSel8 && !collision.sel8()) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 1 /* sel8 collisions */); - if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 2 /* FT0 vertex (acceptable FT0C-FT0A time difference) collisions */); - if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 3 /* Not at ITS ROF border */); - if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 4 /* Not at TF border */); - if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 5 /* vertex-Z selected */); - if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 6 /* Contains at least one ITS-TPC track */); - if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 7 /* PV position consistency check */); - if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 8 /* PV with at least one contributor matched with TOF */); - if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 9 /* PV with at least one contributor matched with TRD */); - if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 10 /* Not at same bunch pile-up */); - if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 11 /* No other collision within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds*/); - if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 12 /* No other collision within +/- 10 microseconds */); - if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 13 /* No other collision within +/- 2 microseconds */); - if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 14 /* No other collision within the same ITS ROF with mult. above a certain threshold */); - if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 15 /* No other collision within the same ITS ROF */); - if (doPPAnalysis) { // we are in pp - if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 16 /* INEL > 0 */); - if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 17 /* INEL > 1 */); - } else { // we are in Pb-Pb - float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); - if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 16 /* Below min occupancy */); - if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 17 /* Above max occupancy */); - } - // Fetch interaction rate only if required (in order to limit ccdb calls) - double interactionRate = (eventSelections.minIR >= 0 || eventSelections.maxIR >= 0) ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource, fIRCrashOnNull) * 1.e-3 : -1; - if (eventSelections.minIR >= 0 && interactionRate < eventSelections.minIR) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 18 /* Below min IR */); - - if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { - return false; - } - if (fillHists) - histos.fill(HIST("hEventSelection"), 19 /* Above max IR */); - - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - histos.fill(HIST("hEventCentrality"), centrality); - return true; - } - - template - void runPi0QA(TV0Object const& gamma1, TV0Object const& gamma2, TCollision collision) - { - // Check if both V0s are made of the same tracks - if (gamma1.posTrackExtraId() == gamma2.posTrackExtraId() || - gamma1.negTrackExtraId() == gamma2.negTrackExtraId()) { - return; - } - - // Calculate pi0 properties - std::array pVecGamma1{gamma1.px(), gamma1.py(), gamma1.pz()}; - std::array pVecGamma2{gamma2.px(), gamma2.py(), gamma2.pz()}; - std::array arrpi0{pVecGamma1, pVecGamma2}; - float pi0Mass = RecoDecay::m(arrpi0, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassPhoton}); - float pi0Pt = RecoDecay::pt(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py()}); - float pi0Y = RecoDecay::y(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py(), gamma1.pz() + gamma2.pz()}, o2::constants::physics::MassPi0); - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - - // MC-specific variables - bool fIsPi0 = false, fIsMC = false; + // Dummy process function + void process(StraColls const&){} - // Check if MC data and populate fIsMC, fIsPi0 - if constexpr (requires { gamma1.motherMCPartId(); gamma2.motherMCPartId(); }) { - if (gamma1.has_v0MCCore() && gamma2.has_v0MCCore()) { - fIsMC = true; - auto gamma1MC = gamma1.template v0MCCore_as>(); - auto gamma2MC = gamma2.template v0MCCore_as>(); + void processRealData(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&){ + auto start = std::chrono::high_resolution_clock::now(); - if (gamma1MC.pdgCode() == 22 && gamma2MC.pdgCode() == 22 && - gamma1MC.pdgCodeMother() == 111 && gamma2MC.pdgCodeMother() == 111 && - gamma1.motherMCPartId() == gamma2.motherMCPartId()) { - fIsPi0 = true; - histos.fill(HIST("Pi0QA/h3dMassPi0BeforeSel_MCAssoc"), centrality, pi0Pt, pi0Mass); - } - } - } + sigma0Module.process(collisions, fullV0s, histos, cache, ccdb, rateFetcher); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; - histos.fill(HIST("Pi0QA/h3dMassPi0BeforeSel_Candidates"), centrality, pi0Pt, pi0Mass); - - // Photon-specific selections - auto posTrackGamma1 = gamma1.template posTrackExtra_as(); - auto negTrackGamma1 = gamma1.template negTrackExtra_as(); - auto posTrackGamma2 = gamma2.template posTrackExtra_as(); - auto negTrackGamma2 = gamma2.template negTrackExtra_as(); - - // Gamma1 Selection - bool passedTPCGamma1 = (TMath::Abs(posTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || - (TMath::Abs(negTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); - - if (TMath::Abs(gamma1.mGamma()) > Pi0PhotonMaxMass || - gamma1.qtarm() >= Pi0PhotonMaxQt || - TMath::Abs(gamma1.alpha()) >= Pi0PhotonMaxAlpha || - TMath::Abs(gamma1.dcapostopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma1.dcanegtopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma1.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || - TMath::Abs(gamma1.negativeeta()) >= Pi0PhotonMaxEta || - TMath::Abs(gamma1.positiveeta()) >= Pi0PhotonMaxEta || - gamma1.v0cosPA() <= Pi0PhotonMinV0cospa || - gamma1.v0radius() <= Pi0PhotonMinRadius || - gamma1.v0radius() >= Pi0PhotonMaxRadius || - posTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - negTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - !passedTPCGamma1) { - return; - } - - // Gamma2 Selection - bool passedTPCGamma2 = (TMath::Abs(posTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || - (TMath::Abs(negTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); - - if (TMath::Abs(gamma2.mGamma()) > Pi0PhotonMaxMass || - gamma2.qtarm() >= Pi0PhotonMaxQt || - TMath::Abs(gamma2.alpha()) >= Pi0PhotonMaxAlpha || - TMath::Abs(gamma2.dcapostopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma2.dcanegtopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma2.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || - TMath::Abs(gamma2.negativeeta()) >= Pi0PhotonMaxEta || - TMath::Abs(gamma2.positiveeta()) >= Pi0PhotonMaxEta || - gamma2.v0cosPA() <= Pi0PhotonMinV0cospa || - gamma2.v0radius() <= Pi0PhotonMinRadius || - gamma2.v0radius() >= Pi0PhotonMaxRadius || - posTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - negTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - !passedTPCGamma2) { - return; - } - - // Pi0-specific selections: - if (TMath::Abs(pi0Y) > 0.5) { - return; - } - - // Fill histograms - histos.fill(HIST("Pi0QA/h3dMassPi0AfterSel_Candidates"), centrality, pi0Pt, pi0Mass); - if (fIsMC && fIsPi0) - histos.fill(HIST("Pi0QA/h3dMassPi0AfterSel_MCAssoc"), centrality, pi0Pt, pi0Mass); + if (fverbose) LOGF(info, "[Process function call, Sorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); } - - // Process photon candidate - template - bool processPhotonCandidate(TV0Object const& gamma, TCollision collision) - { - if (gamma.v0Type() == 0) - return false; - - if (useMLScores) { - // Gamma selection: - if (gamma.gammaBDTScore() <= Gamma_MLThreshold) - return false; - - } else { - // Standard selection - // Gamma basic selection criteria: - histos.fill(HIST("PhotonSel/hSelectionStatistics"), 1.); - histos.fill(HIST("PhotonSel/hPhotonMass"), gamma.mGamma()); - if ((gamma.mGamma() < 0) || (gamma.mGamma() > PhotonMaxMass)) - return false; - float PhotonY = RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma); - histos.fill(HIST("PhotonSel/hPhotonNegEta"), gamma.negativeeta()); - histos.fill(HIST("PhotonSel/hPhotonPosEta"), gamma.positiveeta()); - histos.fill(HIST("PhotonSel/hPhotonY"), PhotonY); - histos.fill(HIST("PhotonSel/hSelectionStatistics"), 2.); - if ((TMath::Abs(PhotonY) > V0Rapidity) || (TMath::Abs(gamma.negativeeta()) > PhotonMaxDauPseudoRap) || (TMath::Abs(gamma.positiveeta()) > PhotonMaxDauPseudoRap)) - return false; - histos.fill(HIST("PhotonSel/hPhotonDCANegToPV"), TMath::Abs(gamma.dcanegtopv())); - histos.fill(HIST("PhotonSel/hPhotonDCAPosToPV"), TMath::Abs(gamma.dcapostopv())); - histos.fill(HIST("PhotonSel/hSelectionStatistics"), 3.); - if ((TMath::Abs(gamma.dcapostopv()) < PhotonMinDCAToPv) || (TMath::Abs(gamma.dcanegtopv()) < PhotonMinDCAToPv)) - return false; - histos.fill(HIST("PhotonSel/hPhotonDCADau"), TMath::Abs(gamma.dcaV0daughters())); - histos.fill(HIST("PhotonSel/hSelectionStatistics"), 4.); - if (TMath::Abs(gamma.dcaV0daughters()) > PhotonMaxDCAV0Dau) - return false; - histos.fill(HIST("PhotonSel/hPhotonRadius"), gamma.v0radius()); - histos.fill(HIST("PhotonSel/hSelectionStatistics"), 5.); - if ((gamma.v0radius() < PhotonMinRadius) || (gamma.v0radius() > PhotonMaxRadius)) - return false; - histos.fill(HIST("PhotonSel/hSelectionStatistics"), 6.); - } - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - histos.fill(HIST("PhotonSel/h3dPhotonMass"), centrality, gamma.pt(), gamma.mGamma()); - return true; - } - - // Process photon candidate - template - bool processLambdaCandidate(TV0Object const& lambda, TCollision collision) - { - if (lambda.v0Type() != 1) - return false; - - if (useMLScores) { - if ((lambda.lambdaBDTScore() <= Lambda_MLThreshold) && (lambda.antiLambdaBDTScore() <= AntiLambda_MLThreshold)) - return false; - - } else { - // Lambda basic selection criteria: - histos.fill(HIST("LambdaSel/hSelectionStatistics"), 1.); - histos.fill(HIST("LambdaSel/hLambdaMass"), lambda.mLambda()); - histos.fill(HIST("LambdaSel/hAntiLambdaMass"), lambda.mAntiLambda()); - if ((TMath::Abs(lambda.mLambda() - o2::constants::physics::MassLambda0) > LambdaWindow) && (TMath::Abs(lambda.mAntiLambda() - o2::constants::physics::MassLambda0) > LambdaWindow)) - return false; - histos.fill(HIST("LambdaSel/hLambdaNegEta"), lambda.negativeeta()); - histos.fill(HIST("LambdaSel/hLambdaPosEta"), lambda.positiveeta()); - histos.fill(HIST("LambdaSel/hLambdaY"), lambda.yLambda()); - histos.fill(HIST("LambdaSel/hSelectionStatistics"), 2.); - if ((TMath::Abs(lambda.yLambda()) > V0Rapidity) || (TMath::Abs(lambda.negativeeta()) > LambdaDauPseudoRap) || (TMath::Abs(lambda.positiveeta()) > LambdaDauPseudoRap)) - return false; - histos.fill(HIST("LambdaSel/hLambdaDCANegToPV"), lambda.dcanegtopv()); - histos.fill(HIST("LambdaSel/hLambdaDCAPosToPV"), lambda.dcapostopv()); - histos.fill(HIST("LambdaSel/hSelectionStatistics"), 3.); - if ((TMath::Abs(lambda.dcapostopv()) < LambdaMinDCAPosToPv) || (TMath::Abs(lambda.dcanegtopv()) < LambdaMinDCANegToPv)) - return false; - histos.fill(HIST("LambdaSel/hLambdaRadius"), lambda.v0radius()); - histos.fill(HIST("LambdaSel/hSelectionStatistics"), 4.); - if ((lambda.v0radius() < LambdaMinv0radius) || (lambda.v0radius() > LambdaMaxv0radius)) - return false; - histos.fill(HIST("LambdaSel/hLambdaDCADau"), lambda.dcaV0daughters()); - histos.fill(HIST("LambdaSel/hSelectionStatistics"), 5.); - if (TMath::Abs(lambda.dcaV0daughters()) > LambdaMaxDCAV0Dau) - return false; - histos.fill(HIST("LambdaSel/hSelectionStatistics"), 6.); - } - - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - histos.fill(HIST("LambdaSel/h3dLambdaMass"), centrality, lambda.pt(), lambda.mLambda()); - histos.fill(HIST("LambdaSel/h3dALambdaMass"), centrality, lambda.pt(), lambda.mAntiLambda()); - - return true; - } - /////////// - // Process sigma candidate and store properties in object - template - bool buildSigma0(TV0Object const& lambda, TV0Object const& gamma, TCollision collision) - { - // Checking if both V0s are made of the very same tracks - if (gamma.posTrackExtraId() == lambda.posTrackExtraId() || - gamma.negTrackExtraId() == lambda.negTrackExtraId()) { - return false; - } - - // Sigma0 candidate properties - std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; - std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; - auto arrMom = std::array{pVecPhotons, pVecLambda}; - float sigmaMass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); - float sigmaY = RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0); - float SigmapT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - - // Before any selection - histos.fill(HIST("SigmaSel/h3dMassSigma0BeforeSel"), centrality, SigmapT, sigmaMass); - - histos.fill(HIST("SigmaSel/hSelectionStatistics"), 1.); - histos.fill(HIST("SigmaSel/hSigmaMass"), sigmaMass); - histos.fill(HIST("SigmaSel/hSigmaMassWindow"), sigmaMass - 1.192642); - - if (TMath::Abs(sigmaMass - 1.192642) > Sigma0Window) - return false; - - histos.fill(HIST("SigmaSel/hSigmaY"), sigmaY); - histos.fill(HIST("SigmaSel/hSelectionStatistics"), 2.); - - if (TMath::Abs(sigmaY) > SigmaMaxRap) - return false; - - histos.fill(HIST("SigmaSel/hSigmaMassSelected"), sigmaMass); - histos.fill(HIST("SigmaSel/hSelectionStatistics"), 3.); - histos.fill(HIST("SigmaSel/h3dMassSigma0AfterSel"), centrality, SigmapT, sigmaMass); - - return true; - } - - // ______________________________________________________ - // Real data processing - no MC subscription - template - void runAnalysis(TCollision const& collisions, TV0s const& fullV0s, bool fDavidTest) - { - - // brute force grouped index construction - std::vector> v0grouped(collisions.size()); - - if (fDavidTest){ - for (const auto& v0 : fullV0s) { - v0grouped[v0.straCollisionId()].push_back(v0.globalIndex()); - } - } - - uint64_t CollIDBuffer = 0; - for (const auto& coll : collisions) { - if (!IsEventAccepted(coll, true)) - continue; - - float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); - const uint64_t collIdx = coll.globalIndex(); - if (collIdx < CollIDBuffer) - LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, collIdx); - - CollIDBuffer = collIdx; - - //_______________________________________________ - // V0s loop - std::vector bestGammasArray; - std::vector bestLambdasArray; - if (fDavidTest){ - for (size_t i; i < v0grouped[coll.globalIndex()].size(); i++) { - auto v0 = fullV0s.rawIteratorAt(v0grouped[coll.globalIndex()][i]); - - if (processPhotonCandidate(v0, coll)) // selecting photons - bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates - - if (processLambdaCandidate(v0, coll)) // selecting lambdas - bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates - } - } - else{ - auto V0s = fullV0s.sliceBy(perCollisionSTDDerived, collIdx); - for (auto& v0 : V0s) { - if (processPhotonCandidate(v0, coll)) // selecting photons - bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates - - if (processLambdaCandidate(v0, coll)) // selecting lambdas - bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates - } - } - - //_______________________________________________ - // Retrieving IR info - float interactionRate = -1; - if (fGetIR) { - interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource, fIRCrashOnNull) * 1.e-3; - if (interactionRate < 0) - histos.get(HIST("GeneralQA/hRunNumberNegativeIR"))->Fill(Form("%d", coll.runNumber()), 1); - - histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); - histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), centrality, interactionRate); - } - - //_______________________________________________ - // Pi0 optional loop - if (doPi0QA) { - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); - for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { - auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); - runPi0QA(gamma1, gamma2, coll); - } - } - } - - //_______________________________________________ - // Sigma0 nested loop - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); - - for (size_t j = 0; j < bestLambdasArray.size(); ++j) { - auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); - - // Building sigma0 candidate - if (!buildSigma0(lambda, gamma, coll)) - continue; - } - } - } - } - - void processRealData(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) - { - auto start = std::chrono::high_resolution_clock::now(); - - runAnalysis(collisions, fullV0s, false); - - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - - if (fverbose) LOGF(info, "[Process function call, PreSliceUnsorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); - } - - void processRealDataDavid(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) - { - auto start = std::chrono::high_resolution_clock::now(); - - runAnalysis(collisions, fullV0s, true); - - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - - if (fverbose) LOGF(info, "[David's process function call] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); - - } - - PROCESS_SWITCH(sigma0QC, processRealData, "process using sliceby unsorted", true); - PROCESS_SWITCH(sigma0QC, processRealDataDavid, "process using David's grouping approach", true); + PROCESS_SWITCH(sigma0Sorted, processRealData, "process run 3 real data", true); }; -struct sigma0QCSorted { +struct sigma0Unsorted { Service ccdb; ctpRateFetcher rateFetcher; - SliceCache cache; - - // For manual sliceBy - Preslice perCollisionSTDDerived = o2::aod::v0data::straCollisionId; - - // Histogram registry - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - Configurable fillQAhistos{"fillQAhistos", false, "if true, fill QA histograms"}; - Configurable fillBkgQAhistos{"fillBkgQAhistos", false, "if true, fill MC QA histograms for Bkg study"}; - Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; - Configurable doAssocStudy{"doAssocStudy", false, "Do v0 to collision association study."}; - Configurable fverbose{"fverbose", false, "QA printout."}; - - // Event level - Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; - Configurable fGetIR{"fGetIR", false, "Flag to retrieve the IR info."}; - Configurable fIRCrashOnNull{"fIRCrashOnNull", false, "Flag to avoid CTP RateFetcher crash."}; - Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; - - struct : ConfigurableGroup { - Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; - Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; - Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; - Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; - Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", true, "require events with at least one ITS-TPC track"}; - Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; - Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; - Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; - Configurable rejectSameBunchPileup{"rejectSameBunchPileup", false, "reject collisions in case of pileup with another collision in the same foundBC"}; - Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds"}; - Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; - Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds"}; - Configurable requireNoCollInTimeRangeVzDep{"requireNoCollInTimeRangeVzDep", false, "reject collisions corrupted by the cannibalism, with other collisions with pvZ of drifting TPC tracks from past/future collisions within 2.5 cm the current pvZ"}; - Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold"}; - Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF"}; - Configurable requireINEL0{"requireINEL0", false, "require INEL>0 event selection"}; - Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; - Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; - Configurable useEvtSelInDenomEff{"useEvtSelInDenomEff", false, "Consider event selections in the recoed <-> gen collision association for the denominator (or numerator) of the acc. x eff. (or signal loss)?"}; - Configurable applyZVtxSelOnMCPV{"applyZVtxSelOnMCPV", false, "Apply Z-vtx cut on the PV of the generated collision?"}; - Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; - // fast check on occupancy - Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; - Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; - - // fast check on interaction rate - Configurable minIR{"minIR", -1, "minimum IR collisions"}; - Configurable maxIR{"maxIR", -1, "maximum IR collisions"}; - - } eventSelections; - - // For ML Selection - Configurable useMLScores{"useMLScores", false, "use ML scores to select candidates"}; - Configurable Gamma_MLThreshold{"Gamma_MLThreshold", 0.1, "Decision Threshold value to select gammas"}; - Configurable Lambda_MLThreshold{"Lambda_MLThreshold", 0.1, "Decision Threshold value to select lambdas"}; - Configurable AntiLambda_MLThreshold{"AntiLambda_MLThreshold", 0.1, "Decision Threshold value to select antilambdas"}; - - // For standard approach: - //// Lambda criteria: - Configurable V0Rapidity{"V0Rapidity", 0.8, "v0 rapidity"}; - - Configurable LambdaDauPseudoRap{"LambdaDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; - Configurable LambdaMinDCANegToPv{"LambdaMinDCANegToPv", 0.0, "min DCA Neg To PV (cm)"}; - Configurable LambdaMinDCAPosToPv{"LambdaMinDCAPosToPv", 0.0, "min DCA Pos To PV (cm)"}; - Configurable LambdaMaxDCAV0Dau{"LambdaMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; - Configurable LambdaMinv0radius{"LambdaMinv0radius", 0.0, "Min V0 radius (cm)"}; - Configurable LambdaMaxv0radius{"LambdaMaxv0radius", 60, "Max V0 radius (cm)"}; - Configurable LambdaWindow{"LambdaWindow", 0.05, "Mass window around expected (in GeV/c2)"}; - - //// Photon criteria: - Configurable PhotonMaxDauPseudoRap{"PhotonMaxDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; - Configurable PhotonMinDCAToPv{"PhotonMinDCAToPv", 0.0, "Min DCA daughter To PV (cm)"}; - Configurable PhotonMaxDCAV0Dau{"PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; - Configurable PhotonMinRadius{"PhotonMinRadius", 0.0, "Min photon conversion radius (cm)"}; - Configurable PhotonMaxRadius{"PhotonMaxRadius", 240, "Max photon conversion radius (cm)"}; - Configurable PhotonMaxMass{"PhotonMaxMass", 0.3, "Max photon mass (GeV/c^{2})"}; - - //// Sigma0 criteria: - Configurable Sigma0Window{"Sigma0Window", 0.1, "Mass window around expected (in GeV/c2)"}; - Configurable SigmaMaxRap{"SigmaMaxRap", 0.8, "Max sigma0 rapidity"}; - - //// Extras: - Configurable Pi0PhotonMinDCADauToPv{"Pi0PhotonMinDCADauToPv", 0.0, "Min DCA daughter To PV (cm)"}; - Configurable Pi0PhotonMaxDCAV0Dau{"Pi0PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; - Configurable Pi0PhotonMinTPCCrossedRows{"Pi0PhotonMinTPCCrossedRows", 0, "Min daughter TPC Crossed Rows"}; - Configurable Pi0PhotonMaxTPCNSigmas{"Pi0PhotonMaxTPCNSigmas", 7, "Max TPC NSigmas for daughters"}; - Configurable Pi0PhotonMaxEta{"Pi0PhotonMaxEta", 0.8, "Max photon rapidity"}; - Configurable Pi0PhotonMinRadius{"Pi0PhotonMinRadius", 3.0, "Min photon conversion radius (cm)"}; - Configurable Pi0PhotonMaxRadius{"Pi0PhotonMaxRadius", 115, "Max photon conversion radius (cm)"}; - Configurable Pi0PhotonMaxQt{"Pi0PhotonMaxQt", 0.05, "Max photon qt value (AP plot) (GeV/c)"}; - Configurable Pi0PhotonMaxAlpha{"Pi0PhotonMaxAlpha", 0.95, "Max photon alpha absolute value (AP plot)"}; - Configurable Pi0PhotonMinV0cospa{"Pi0PhotonMinV0cospa", 0.80, "Min V0 CosPA"}; - Configurable Pi0PhotonMaxMass{"Pi0PhotonMaxMass", 0.10, "Max photon mass (GeV/c^{2})"}; - - // Axis - // base properties - ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; - ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Centrality"}; - - // Invariant Mass - ConfigurableAxis axisSigmaMass{"axisSigmaMass", {500, 1.10f, 1.30f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; - ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.05f, 1.151f}, "M_{#Lambda} (GeV/c^{2})"}; - ConfigurableAxis axisPhotonMass{"axisPhotonMass", {200, -0.1f, 0.5f}, "M_{#Gamma}"}; - ConfigurableAxis axisPi0Mass{"axisPi0Mass", {200, 0.08f, 0.18f}, "M_{#Pi^{0}}"}; - - // topological variable QA axes - ConfigurableAxis axisRapidity{"axisRapidity", {100, -2.0f, 2.0f}, "Rapidity"}; - ConfigurableAxis axisCandSel{"axisCandSel", {7, 0.5f, +7.5f}, "Candidate Selection"}; - ConfigurableAxis axisIRBinning{"axisIRBinning", {150, 0, 1500}, "Binning for the interaction rate (kHz)"}; - - void init(InitContext const&) - { - // setting CCDB service - ccdb->setURL("http://alice-ccdb.cern.ch"); - ccdb->setCaching(true); - ccdb->setFatalWhenNull(false); - - histos.add("hEventCentrality", "hEventCentrality", kTH1D, {axisCentrality}); - - histos.add("PhotonSel/h3dPhotonMass", "h3dPhotonMass", kTH3D, {axisCentrality, axisPt, axisPhotonMass}); - histos.add("LambdaSel/h3dLambdaMass", "h3dLambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); - histos.add("LambdaSel/h3dALambdaMass", "h3dALambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); - - histos.add("SigmaSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); - histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); - histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Sigma Mass Window"); - histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Sigma Y Window"); + // Load configurables and the sigma0 module, please + o2::pwglf::sigma0::evselConfigurables evselOpts; + o2::pwglf::sigma0::lambdaselConfigurables lambdaselOpts; + o2::pwglf::sigma0::photonselConfigurables photonselOpts; + o2::pwglf::sigma0::sigma0selConfigurables sigma0selOpts; + o2::pwglf::sigma0::pi0selConfigurables pi0selOpts; + o2::pwglf::sigma0::axisConfigurables axisOpts; - // For selection: - histos.add("SigmaSel/h3dMassSigma0BeforeSel", "h3dMassSigma0BeforeSel", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); - histos.add("SigmaSel/hSigmaMass", "hSigmaMass", kTH1F, {axisSigmaMass}); - histos.add("SigmaSel/hSigmaMassWindow", "hSigmaMassWindow", kTH1F, {{200, -0.09f, 0.11f}}); - histos.add("SigmaSel/hSigmaY", "hSigmaY", kTH1F, {axisRapidity}); - histos.add("SigmaSel/hSigmaMassSelected", "hSigmaMassSelected", kTH1F, {axisSigmaMass}); - histos.add("SigmaSel/h3dMassSigma0AfterSel", "h3dMassSigma0AfterSel", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); + o2::pwglf::sigma0::Sigma0BuilderModule sigma0Module; - if (fGetIR) { - histos.add("GeneralQA/hRunNumberNegativeIR", "", kTH1D, {{1, 0., 1.}}); - histos.add("GeneralQA/hInteractionRate", "hInteractionRate", kTH1F, {axisIRBinning}); - histos.add("GeneralQA/hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2F, {axisCentrality, axisIRBinning}); - } - - // For Pi0 QA - if (doPi0QA) { - histos.add("Pi0QA/h3dMassPi0BeforeSel_Candidates", "h3dMassPi0BeforeSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); - histos.add("Pi0QA/h3dMassPi0AfterSel_Candidates", "h3dMassPi0AfterSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); - } - } - - template - bool IsEventAccepted(TCollision collision) - // check whether the collision passes our collision selections - { - if (eventSelections.requireSel8 && !collision.sel8()) { - return false; - } - if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { - return false; - } - if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - return false; - } - if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - return false; - } - if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { - return false; - } - if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { - return false; - } - if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - return false; - } - if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { - return false; - } - if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { - return false; - } - if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - return false; - } - if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { - return false; - } - if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { - return false; - } - if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { - return false; - } - if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { - return false; - } - if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { - return false; - } - if (doPPAnalysis) { // we are in pp - if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { - return false; - } - if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { - return false; - } - } else { // we are in Pb-Pb - float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); - if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { - return false; - } - if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { - return false; - } - } - // Fetch interaction rate only if required (in order to limit ccdb calls) - double interactionRate = (eventSelections.minIR >= 0 || eventSelections.maxIR >= 0) ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource, fIRCrashOnNull) * 1.e-3 : -1; - if (eventSelections.minIR >= 0 && interactionRate < eventSelections.minIR) { - return false; - } - if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { - return false; - } - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - histos.fill(HIST("hEventCentrality"), centrality); - return true; - } - - template - void runPi0QA(TV0Object const& gamma1, TV0Object const& gamma2, TCollision collision) - { - // Check if both V0s are made of the same tracks - if (gamma1.posTrackExtraId() == gamma2.posTrackExtraId() || - gamma1.negTrackExtraId() == gamma2.negTrackExtraId()) { - return; - } - - // Calculate pi0 properties - std::array pVecGamma1{gamma1.px(), gamma1.py(), gamma1.pz()}; - std::array pVecGamma2{gamma2.px(), gamma2.py(), gamma2.pz()}; - std::array arrpi0{pVecGamma1, pVecGamma2}; - float pi0Mass = RecoDecay::m(arrpi0, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassPhoton}); - float pi0Pt = RecoDecay::pt(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py()}); - float pi0Y = RecoDecay::y(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py(), gamma1.pz() + gamma2.pz()}, o2::constants::physics::MassPi0); - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - - histos.fill(HIST("Pi0QA/h3dMassPi0BeforeSel_Candidates"), centrality, pi0Pt, pi0Mass); - - // Photon-specific selections - auto posTrackGamma1 = gamma1.template posTrackExtra_as(); - auto negTrackGamma1 = gamma1.template negTrackExtra_as(); - auto posTrackGamma2 = gamma2.template posTrackExtra_as(); - auto negTrackGamma2 = gamma2.template negTrackExtra_as(); - - // Gamma1 Selection - bool passedTPCGamma1 = (TMath::Abs(posTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || - (TMath::Abs(negTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); - - if (TMath::Abs(gamma1.mGamma()) > Pi0PhotonMaxMass || - gamma1.qtarm() >= Pi0PhotonMaxQt || - TMath::Abs(gamma1.alpha()) >= Pi0PhotonMaxAlpha || - TMath::Abs(gamma1.dcapostopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma1.dcanegtopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma1.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || - TMath::Abs(gamma1.negativeeta()) >= Pi0PhotonMaxEta || - TMath::Abs(gamma1.positiveeta()) >= Pi0PhotonMaxEta || - gamma1.v0cosPA() <= Pi0PhotonMinV0cospa || - gamma1.v0radius() <= Pi0PhotonMinRadius || - gamma1.v0radius() >= Pi0PhotonMaxRadius || - posTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - negTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - !passedTPCGamma1) { - return; - } - - // Gamma2 Selection - bool passedTPCGamma2 = (TMath::Abs(posTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || - (TMath::Abs(negTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); - - if (TMath::Abs(gamma2.mGamma()) > Pi0PhotonMaxMass || - gamma2.qtarm() >= Pi0PhotonMaxQt || - TMath::Abs(gamma2.alpha()) >= Pi0PhotonMaxAlpha || - TMath::Abs(gamma2.dcapostopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma2.dcanegtopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma2.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || - TMath::Abs(gamma2.negativeeta()) >= Pi0PhotonMaxEta || - TMath::Abs(gamma2.positiveeta()) >= Pi0PhotonMaxEta || - gamma2.v0cosPA() <= Pi0PhotonMinV0cospa || - gamma2.v0radius() <= Pi0PhotonMinRadius || - gamma2.v0radius() >= Pi0PhotonMaxRadius || - posTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - negTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - !passedTPCGamma2) { - return; - } - - // Pi0-specific selections: - if (TMath::Abs(pi0Y) > 0.5) { - return; - } - - // Fill histograms - histos.fill(HIST("Pi0QA/h3dMassPi0AfterSel_Candidates"), centrality, pi0Pt, pi0Mass); - } - - // Process photon candidate - template - bool processPhotonCandidate(TV0Object const& gamma, TCollision collision) - { - if (gamma.v0Type() == 0) - return false; - - if (useMLScores) { - // Gamma selection: - if (gamma.gammaBDTScore() <= Gamma_MLThreshold) - return false; - - } else { - // Standard selection - // Gamma basic selection criteria: - if ((gamma.mGamma() < 0) || (gamma.mGamma() > PhotonMaxMass)) - return false; - float PhotonY = RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma); - if ((TMath::Abs(PhotonY) > V0Rapidity) || (TMath::Abs(gamma.negativeeta()) > PhotonMaxDauPseudoRap) || (TMath::Abs(gamma.positiveeta()) > PhotonMaxDauPseudoRap)) - return false; - if ((TMath::Abs(gamma.dcapostopv()) < PhotonMinDCAToPv) || (TMath::Abs(gamma.dcanegtopv()) < PhotonMinDCAToPv)) - return false; - if (TMath::Abs(gamma.dcaV0daughters()) > PhotonMaxDCAV0Dau) - return false; - if ((gamma.v0radius() < PhotonMinRadius) || (gamma.v0radius() > PhotonMaxRadius)) - return false; - } - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - histos.fill(HIST("PhotonSel/h3dPhotonMass"), centrality, gamma.pt(), gamma.mGamma()); - return true; - } - - // Process photon candidate - template - bool processLambdaCandidate(TV0Object const& lambda, TCollision collision) - { - if (lambda.v0Type() != 1) - return false; - - if (useMLScores) { - if ((lambda.lambdaBDTScore() <= Lambda_MLThreshold) && (lambda.antiLambdaBDTScore() <= AntiLambda_MLThreshold)) - return false; - - } else { - // Lambda basic selection criteria: - if ((TMath::Abs(lambda.mLambda() - o2::constants::physics::MassLambda0) > LambdaWindow) && (TMath::Abs(lambda.mAntiLambda() - o2::constants::physics::MassLambda0) > LambdaWindow)) - return false; - if ((TMath::Abs(lambda.yLambda()) > V0Rapidity) || (TMath::Abs(lambda.negativeeta()) > LambdaDauPseudoRap) || (TMath::Abs(lambda.positiveeta()) > LambdaDauPseudoRap)) - return false; - if ((TMath::Abs(lambda.dcapostopv()) < LambdaMinDCAPosToPv) || (TMath::Abs(lambda.dcanegtopv()) < LambdaMinDCANegToPv)) - return false; - if ((lambda.v0radius() < LambdaMinv0radius) || (lambda.v0radius() > LambdaMaxv0radius)) - return false; - if (TMath::Abs(lambda.dcaV0daughters()) > LambdaMaxDCAV0Dau) - return false; - } - - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - histos.fill(HIST("LambdaSel/h3dLambdaMass"), centrality, lambda.pt(), lambda.mLambda()); - histos.fill(HIST("LambdaSel/h3dALambdaMass"), centrality, lambda.pt(), lambda.mAntiLambda()); - - return true; - } - /////////// - // Process sigma candidate and store properties in object - template - bool buildSigma0(TV0Object const& lambda, TV0Object const& gamma, TCollision collision) - { - // Checking if both V0s are made of the very same tracks - if (gamma.posTrackExtraId() == lambda.posTrackExtraId() || - gamma.negTrackExtraId() == lambda.negTrackExtraId()) { - return false; - } - - // Sigma0 candidate properties - std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; - std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; - auto arrMom = std::array{pVecPhotons, pVecLambda}; - float sigmaMass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); - float sigmaY = RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0); - float SigmapT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - - // Before any selection - histos.fill(HIST("SigmaSel/h3dMassSigma0BeforeSel"), centrality, SigmapT, sigmaMass); - - histos.fill(HIST("SigmaSel/hSelectionStatistics"), 1.); - histos.fill(HIST("SigmaSel/hSigmaMass"), sigmaMass); - histos.fill(HIST("SigmaSel/hSigmaMassWindow"), sigmaMass - 1.192642); - - if (TMath::Abs(sigmaMass - 1.192642) > Sigma0Window) - return false; - - histos.fill(HIST("SigmaSel/hSigmaY"), sigmaY); - histos.fill(HIST("SigmaSel/hSelectionStatistics"), 2.); - - if (TMath::Abs(sigmaY) > SigmaMaxRap) - return false; - - histos.fill(HIST("SigmaSel/hSigmaMassSelected"), sigmaMass); - histos.fill(HIST("SigmaSel/hSelectionStatistics"), 3.); - histos.fill(HIST("SigmaSel/h3dMassSigma0AfterSel"), centrality, SigmapT, sigmaMass); - - return true; - } - - // ______________________________________________________ - // Real data processing - no MC subscription - template - void runAnalysis(TCollision const& collisions, TV0s const& fullV0s) - { - uint64_t CollIDBuffer = 0; - for (const auto& coll : collisions) { - if (!IsEventAccepted(coll)) - continue; - - float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); - const uint64_t collIdx = coll.globalIndex(); - if (collIdx < CollIDBuffer) - LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, collIdx); - - CollIDBuffer = collIdx; - - //_______________________________________________ - // V0s loop - std::vector bestGammasArray; - std::vector bestLambdasArray; - - auto V0s = fullV0s.sliceBy(perCollisionSTDDerived, collIdx); - for (auto& v0 : V0s) { - if (processPhotonCandidate(v0, coll)) // selecting photons - bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates - - if (processLambdaCandidate(v0, coll)) // selecting lambdas - bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates - } - - //_______________________________________________ - // Retrieving IR info - float interactionRate = -1; - if (fGetIR) { - interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource, fIRCrashOnNull) * 1.e-3; - if (interactionRate < 0) - histos.get(HIST("GeneralQA/hRunNumberNegativeIR"))->Fill(Form("%d", coll.runNumber()), 1); - - histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); - histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), centrality, interactionRate); - } - - //_______________________________________________ - // Pi0 optional loop - if (doPi0QA) { - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); - for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { - auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); - runPi0QA(gamma1, gamma2, coll); - } - } - } - - //_______________________________________________ - // Sigma0 nested loop - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); - - for (size_t j = 0; j < bestLambdasArray.size(); ++j) { - auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); - - // Building sigma0 candidate - if (!buildSigma0(lambda, gamma, coll)) - continue; - } - } - } - } - - void processRealData(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) - { - auto start = std::chrono::high_resolution_clock::now(); - - runAnalysis(collisions, fullV0s); - - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - - if (fverbose) LOGF(info, "[Process function call, PreSlice] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); - } - PROCESS_SWITCH(sigma0QCSorted, processRealData, "process using sliceby sorted", true); -}; - -struct sigma0QCIterator { - Service ccdb; - ctpRateFetcher rateFetcher; + // For manual sliceBy + SliceCache cache; + PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; // Histogram registry HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - - Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; - Configurable fverbose{"fverbose", false, "QA printout."}; - - // Event level - Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; - Configurable fGetIR{"fGetIR", false, "Flag to retrieve the IR info."}; - Configurable fIRCrashOnNull{"fIRCrashOnNull", false, "Flag to avoid CTP RateFetcher crash."}; - Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; - - struct : ConfigurableGroup { - Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; - Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; - Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; - Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; - Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", true, "require events with at least one ITS-TPC track"}; - Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; - Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; - Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; - Configurable rejectSameBunchPileup{"rejectSameBunchPileup", false, "reject collisions in case of pileup with another collision in the same foundBC"}; - Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds"}; - Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; - Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds"}; - Configurable requireNoCollInTimeRangeVzDep{"requireNoCollInTimeRangeVzDep", false, "reject collisions corrupted by the cannibalism, with other collisions with pvZ of drifting TPC tracks from past/future collisions within 2.5 cm the current pvZ"}; - Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold"}; - Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF"}; - Configurable requireINEL0{"requireINEL0", false, "require INEL>0 event selection"}; - Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; - Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; - Configurable useEvtSelInDenomEff{"useEvtSelInDenomEff", false, "Consider event selections in the recoed <-> gen collision association for the denominator (or numerator) of the acc. x eff. (or signal loss)?"}; - Configurable applyZVtxSelOnMCPV{"applyZVtxSelOnMCPV", false, "Apply Z-vtx cut on the PV of the generated collision?"}; - Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; - // fast check on occupancy - Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; - Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; - - // fast check on interaction rate - Configurable minIR{"minIR", -1, "minimum IR collisions"}; - Configurable maxIR{"maxIR", -1, "maximum IR collisions"}; - - } eventSelections; - - // For ML Selection - Configurable useMLScores{"useMLScores", false, "use ML scores to select candidates"}; - Configurable Gamma_MLThreshold{"Gamma_MLThreshold", 0.1, "Decision Threshold value to select gammas"}; - Configurable Lambda_MLThreshold{"Lambda_MLThreshold", 0.1, "Decision Threshold value to select lambdas"}; - Configurable AntiLambda_MLThreshold{"AntiLambda_MLThreshold", 0.1, "Decision Threshold value to select antilambdas"}; - - // For standard approach: - //// Lambda criteria: - Configurable V0Rapidity{"V0Rapidity", 0.8, "v0 rapidity"}; - - Configurable LambdaDauPseudoRap{"LambdaDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; - Configurable LambdaMinDCANegToPv{"LambdaMinDCANegToPv", 0.0, "min DCA Neg To PV (cm)"}; - Configurable LambdaMinDCAPosToPv{"LambdaMinDCAPosToPv", 0.0, "min DCA Pos To PV (cm)"}; - Configurable LambdaMaxDCAV0Dau{"LambdaMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; - Configurable LambdaMinv0radius{"LambdaMinv0radius", 0.0, "Min V0 radius (cm)"}; - Configurable LambdaMaxv0radius{"LambdaMaxv0radius", 60, "Max V0 radius (cm)"}; - Configurable LambdaWindow{"LambdaWindow", 0.05, "Mass window around expected (in GeV/c2)"}; - - //// Photon criteria: - Configurable PhotonMaxDauPseudoRap{"PhotonMaxDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; - Configurable PhotonMinDCAToPv{"PhotonMinDCAToPv", 0.0, "Min DCA daughter To PV (cm)"}; - Configurable PhotonMaxDCAV0Dau{"PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; - Configurable PhotonMinRadius{"PhotonMinRadius", 0.0, "Min photon conversion radius (cm)"}; - Configurable PhotonMaxRadius{"PhotonMaxRadius", 240, "Max photon conversion radius (cm)"}; - Configurable PhotonMaxMass{"PhotonMaxMass", 0.3, "Max photon mass (GeV/c^{2})"}; - - //// Sigma0 criteria: - Configurable Sigma0Window{"Sigma0Window", 0.1, "Mass window around expected (in GeV/c2)"}; - Configurable SigmaMaxRap{"SigmaMaxRap", 0.8, "Max sigma0 rapidity"}; - - //// Extras: - Configurable Pi0PhotonMinDCADauToPv{"Pi0PhotonMinDCADauToPv", 0.0, "Min DCA daughter To PV (cm)"}; - Configurable Pi0PhotonMaxDCAV0Dau{"Pi0PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; - Configurable Pi0PhotonMinTPCCrossedRows{"Pi0PhotonMinTPCCrossedRows", 0, "Min daughter TPC Crossed Rows"}; - Configurable Pi0PhotonMaxTPCNSigmas{"Pi0PhotonMaxTPCNSigmas", 7, "Max TPC NSigmas for daughters"}; - Configurable Pi0PhotonMaxEta{"Pi0PhotonMaxEta", 0.8, "Max photon rapidity"}; - Configurable Pi0PhotonMinRadius{"Pi0PhotonMinRadius", 3.0, "Min photon conversion radius (cm)"}; - Configurable Pi0PhotonMaxRadius{"Pi0PhotonMaxRadius", 115, "Max photon conversion radius (cm)"}; - Configurable Pi0PhotonMaxQt{"Pi0PhotonMaxQt", 0.05, "Max photon qt value (AP plot) (GeV/c)"}; - Configurable Pi0PhotonMaxAlpha{"Pi0PhotonMaxAlpha", 0.95, "Max photon alpha absolute value (AP plot)"}; - Configurable Pi0PhotonMinV0cospa{"Pi0PhotonMinV0cospa", 0.80, "Min V0 CosPA"}; - Configurable Pi0PhotonMaxMass{"Pi0PhotonMaxMass", 0.10, "Max photon mass (GeV/c^{2})"}; - - // Axis - // base properties - ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; - ConfigurableAxis axisCentrality{"axisCentrality", {VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Centrality"}; - - // Invariant Mass - ConfigurableAxis axisSigmaMass{"axisSigmaMass", {500, 1.10f, 1.30f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; - ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.05f, 1.151f}, "M_{#Lambda} (GeV/c^{2})"}; - ConfigurableAxis axisPhotonMass{"axisPhotonMass", {200, -0.1f, 0.5f}, "M_{#Gamma}"}; - ConfigurableAxis axisPi0Mass{"axisPi0Mass", {200, 0.08f, 0.18f}, "M_{#Pi^{0}}"}; - - // topological variable QA axes - ConfigurableAxis axisRapidity{"axisRapidity", {100, -2.0f, 2.0f}, "Rapidity"}; - ConfigurableAxis axisCandSel{"axisCandSel", {7, 0.5f, +7.5f}, "Candidate Selection"}; - ConfigurableAxis axisIRBinning{"axisIRBinning", {150, 0, 1500}, "Binning for the interaction rate (kHz)"}; - - std::chrono::high_resolution_clock::time_point start{}; - std::chrono::high_resolution_clock::time_point end{}; + Configurable fverbose{"fverbose", true, "QA printout."}; void init(InitContext const&) { // setting CCDB service ccdb->setURL("http://alice-ccdb.cern.ch"); ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); ccdb->setFatalWhenNull(false); - histos.add("hEventCentrality", "hEventCentrality", kTH1D, {axisCentrality}); - histos.add("PhotonSel/h3dPhotonMass", "h3dPhotonMass", kTH3D, {axisCentrality, axisPt, axisPhotonMass}); - histos.add("LambdaSel/h3dLambdaMass", "h3dLambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); - histos.add("LambdaSel/h3dALambdaMass", "h3dALambdaMass", kTH3D, {axisCentrality, axisPt, axisLambdaMass}); - - histos.add("SigmaSel/hSelectionStatistics", "hSelectionStatistics", kTH1D, {axisCandSel}); - histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(1, "No Sel"); - histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(2, "Sigma Mass Window"); - histos.get(HIST("SigmaSel/hSelectionStatistics"))->GetXaxis()->SetBinLabel(3, "Sigma Y Window"); - - // For selection: - histos.add("SigmaSel/h3dMassSigma0BeforeSel", "h3dMassSigma0BeforeSel", kTH3F, {axisCentrality, axisPt, axisSigmaMass}); - histos.add("SigmaSel/hSigmaMass", "hSigmaMass", kTH1F, {axisSigmaMass}); - histos.add("SigmaSel/hSigmaMassWindow", "hSigmaMassWindow", kTH1F, {{200, -0.09f, 0.11f}}); - histos.add("SigmaSel/hSigmaY", "hSigmaY", kTH1F, {axisRapidity}); - histos.add("SigmaSel/hSigmaMassSelected", "hSigmaMassSelected", kTH1F, {axisSigmaMass}); - histos.add("SigmaSel/h3dMassSigma0AfterSel", "h3dMassSigma0AfterSel", kTH3D, {axisCentrality, axisPt, axisSigmaMass}); - - if (fGetIR) { - histos.add("GeneralQA/hRunNumberNegativeIR", "", kTH1D, {{1, 0., 1.}}); - histos.add("GeneralQA/hInteractionRate", "hInteractionRate", kTH1F, {axisIRBinning}); - histos.add("GeneralQA/hCentralityVsInteractionRate", "hCentralityVsInteractionRate", kTH2F, {axisCentrality, axisIRBinning}); - } - - // For Pi0 QA - if (doPi0QA) { - histos.add("Pi0QA/h3dMassPi0BeforeSel_Candidates", "h3dMassPi0BeforeSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); - histos.add("Pi0QA/h3dMassPi0AfterSel_Candidates", "h3dMassPi0AfterSel_Candidates", kTH3D, {axisCentrality, axisPt, axisPi0Mass}); - } + // Initialize task + sigma0Module.init(histos, evselOpts, lambdaselOpts, photonselOpts, sigma0selOpts, pi0selOpts, axisOpts); } - template - bool IsEventAccepted(TCollision collision) - // check whether the collision passes our collision selections - { - if (eventSelections.requireSel8 && !collision.sel8()) { - return false; - } - if (eventSelections.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { - return false; - } - if (eventSelections.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - return false; - } - if (eventSelections.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { - return false; - } - if (std::abs(collision.posZ()) > eventSelections.maxZVtxPosition) { - return false; - } - if (eventSelections.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { - return false; - } - if (eventSelections.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { - return false; - } - if (eventSelections.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { - return false; - } - if (eventSelections.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { - return false; - } - if (eventSelections.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { - return false; - } - if (eventSelections.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { - return false; - } - if (eventSelections.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { - return false; - } - if (eventSelections.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { - return false; - } - if (eventSelections.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { - return false; - } - if (eventSelections.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { - return false; - } - if (doPPAnalysis) { // we are in pp - if (eventSelections.requireINEL0 && collision.multNTracksPVeta1() < 1) { - return false; - } - if (eventSelections.requireINEL1 && collision.multNTracksPVeta1() < 2) { - return false; - } - } else { // we are in Pb-Pb - float collisionOccupancy = eventSelections.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); - if (eventSelections.minOccupancy >= 0 && collisionOccupancy < eventSelections.minOccupancy) { - return false; - } - if (eventSelections.maxOccupancy >= 0 && collisionOccupancy > eventSelections.maxOccupancy) { - return false; - } - } - // Fetch interaction rate only if required (in order to limit ccdb calls) - double interactionRate = (eventSelections.minIR >= 0 || eventSelections.maxIR >= 0) ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), irSource, fIRCrashOnNull) * 1.e-3 : -1; - if (eventSelections.minIR >= 0 && interactionRate < eventSelections.minIR) { - return false; - } - if (eventSelections.maxIR >= 0 && interactionRate > eventSelections.maxIR) { - return false; - } - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - histos.fill(HIST("hEventCentrality"), centrality); - return true; - } - - template - void runPi0QA(TV0Object const& gamma1, TV0Object const& gamma2, TCollision collision) - { - // Check if both V0s are made of the same tracks - if (gamma1.posTrackExtraId() == gamma2.posTrackExtraId() || - gamma1.negTrackExtraId() == gamma2.negTrackExtraId()) { - return; - } - - // Calculate pi0 properties - std::array pVecGamma1{gamma1.px(), gamma1.py(), gamma1.pz()}; - std::array pVecGamma2{gamma2.px(), gamma2.py(), gamma2.pz()}; - std::array arrpi0{pVecGamma1, pVecGamma2}; - float pi0Mass = RecoDecay::m(arrpi0, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassPhoton}); - float pi0Pt = RecoDecay::pt(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py()}); - float pi0Y = RecoDecay::y(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py(), gamma1.pz() + gamma2.pz()}, o2::constants::physics::MassPi0); - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - - histos.fill(HIST("Pi0QA/h3dMassPi0BeforeSel_Candidates"), centrality, pi0Pt, pi0Mass); - - // Photon-specific selections - auto posTrackGamma1 = gamma1.template posTrackExtra_as(); - auto negTrackGamma1 = gamma1.template negTrackExtra_as(); - auto posTrackGamma2 = gamma2.template posTrackExtra_as(); - auto negTrackGamma2 = gamma2.template negTrackExtra_as(); - - // Gamma1 Selection - bool passedTPCGamma1 = (TMath::Abs(posTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || - (TMath::Abs(negTrackGamma1.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); - - if (TMath::Abs(gamma1.mGamma()) > Pi0PhotonMaxMass || - gamma1.qtarm() >= Pi0PhotonMaxQt || - TMath::Abs(gamma1.alpha()) >= Pi0PhotonMaxAlpha || - TMath::Abs(gamma1.dcapostopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma1.dcanegtopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma1.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || - TMath::Abs(gamma1.negativeeta()) >= Pi0PhotonMaxEta || - TMath::Abs(gamma1.positiveeta()) >= Pi0PhotonMaxEta || - gamma1.v0cosPA() <= Pi0PhotonMinV0cospa || - gamma1.v0radius() <= Pi0PhotonMinRadius || - gamma1.v0radius() >= Pi0PhotonMaxRadius || - posTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - negTrackGamma1.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - !passedTPCGamma1) { - return; - } + // Dummy process function + void process(StraColls const&){} - // Gamma2 Selection - bool passedTPCGamma2 = (TMath::Abs(posTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas) || - (TMath::Abs(negTrackGamma2.tpcNSigmaEl()) < Pi0PhotonMaxTPCNSigmas); + void processRealData(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&){ + auto start = std::chrono::high_resolution_clock::now(); - if (TMath::Abs(gamma2.mGamma()) > Pi0PhotonMaxMass || - gamma2.qtarm() >= Pi0PhotonMaxQt || - TMath::Abs(gamma2.alpha()) >= Pi0PhotonMaxAlpha || - TMath::Abs(gamma2.dcapostopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma2.dcanegtopv()) < Pi0PhotonMinDCADauToPv || - TMath::Abs(gamma2.dcaV0daughters()) > Pi0PhotonMaxDCAV0Dau || - TMath::Abs(gamma2.negativeeta()) >= Pi0PhotonMaxEta || - TMath::Abs(gamma2.positiveeta()) >= Pi0PhotonMaxEta || - gamma2.v0cosPA() <= Pi0PhotonMinV0cospa || - gamma2.v0radius() <= Pi0PhotonMinRadius || - gamma2.v0radius() >= Pi0PhotonMaxRadius || - posTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - negTrackGamma2.tpcCrossedRows() < Pi0PhotonMinTPCCrossedRows || - !passedTPCGamma2) { - return; - } + sigma0Module.process(collisions, fullV0s, histos, cache, ccdb, rateFetcher); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; - // Pi0-specific selections: - if (TMath::Abs(pi0Y) > 0.5) { - return; - } - - // Fill histograms - histos.fill(HIST("Pi0QA/h3dMassPi0AfterSel_Candidates"), centrality, pi0Pt, pi0Mass); + if (fverbose) LOGF(info, "[Process function call, Sorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); } - - // Process photon candidate - template - bool processPhotonCandidate(TV0Object const& gamma, TCollision collision) - { - if (gamma.v0Type() == 0) - return false; - - if (useMLScores) { - // Gamma selection: - if (gamma.gammaBDTScore() <= Gamma_MLThreshold) - return false; - - } else { - // Standard selection - // Gamma basic selection criteria: - if ((gamma.mGamma() < 0) || (gamma.mGamma() > PhotonMaxMass)) - return false; - float PhotonY = RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma); - if ((TMath::Abs(PhotonY) > V0Rapidity) || (TMath::Abs(gamma.negativeeta()) > PhotonMaxDauPseudoRap) || (TMath::Abs(gamma.positiveeta()) > PhotonMaxDauPseudoRap)) - return false; - if ((TMath::Abs(gamma.dcapostopv()) < PhotonMinDCAToPv) || (TMath::Abs(gamma.dcanegtopv()) < PhotonMinDCAToPv)) - return false; - if (TMath::Abs(gamma.dcaV0daughters()) > PhotonMaxDCAV0Dau) - return false; - if ((gamma.v0radius() < PhotonMinRadius) || (gamma.v0radius() > PhotonMaxRadius)) - return false; - } - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - histos.fill(HIST("PhotonSel/h3dPhotonMass"), centrality, gamma.pt(), gamma.mGamma()); - return true; - } - - // Process photon candidate - template - bool processLambdaCandidate(TV0Object const& lambda, TCollision collision) - { - if (lambda.v0Type() != 1) - return false; - - if (useMLScores) { - if ((lambda.lambdaBDTScore() <= Lambda_MLThreshold) && (lambda.antiLambdaBDTScore() <= AntiLambda_MLThreshold)) - return false; - - } else { - // Lambda basic selection criteria: - if ((TMath::Abs(lambda.mLambda() - o2::constants::physics::MassLambda0) > LambdaWindow) && (TMath::Abs(lambda.mAntiLambda() - o2::constants::physics::MassLambda0) > LambdaWindow)) - return false; - if ((TMath::Abs(lambda.yLambda()) > V0Rapidity) || (TMath::Abs(lambda.negativeeta()) > LambdaDauPseudoRap) || (TMath::Abs(lambda.positiveeta()) > LambdaDauPseudoRap)) - return false; - if ((TMath::Abs(lambda.dcapostopv()) < LambdaMinDCAPosToPv) || (TMath::Abs(lambda.dcanegtopv()) < LambdaMinDCANegToPv)) - return false; - if ((lambda.v0radius() < LambdaMinv0radius) || (lambda.v0radius() > LambdaMaxv0radius)) - return false; - if (TMath::Abs(lambda.dcaV0daughters()) > LambdaMaxDCAV0Dau) - return false; - } - - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - histos.fill(HIST("LambdaSel/h3dLambdaMass"), centrality, lambda.pt(), lambda.mLambda()); - histos.fill(HIST("LambdaSel/h3dALambdaMass"), centrality, lambda.pt(), lambda.mAntiLambda()); - - return true; - } - /////////// - // Process sigma candidate and store properties in object - template - bool buildSigma0(TV0Object const& lambda, TV0Object const& gamma, TCollision collision) - { - // Checking if both V0s are made of the very same tracks - if (gamma.posTrackExtraId() == lambda.posTrackExtraId() || - gamma.negTrackExtraId() == lambda.negTrackExtraId()) { - return false; - } - - // Sigma0 candidate properties - std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; - std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; - auto arrMom = std::array{pVecPhotons, pVecLambda}; - float sigmaMass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); - float sigmaY = RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0); - float SigmapT = RecoDecay::pt(array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); - float centrality = doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); - - // Before any selection - histos.fill(HIST("SigmaSel/h3dMassSigma0BeforeSel"), centrality, SigmapT, sigmaMass); - - histos.fill(HIST("SigmaSel/hSelectionStatistics"), 1.); - histos.fill(HIST("SigmaSel/hSigmaMass"), sigmaMass); - histos.fill(HIST("SigmaSel/hSigmaMassWindow"), sigmaMass - 1.192642); - - if (TMath::Abs(sigmaMass - 1.192642) > Sigma0Window) - return false; - - histos.fill(HIST("SigmaSel/hSigmaY"), sigmaY); - histos.fill(HIST("SigmaSel/hSelectionStatistics"), 2.); - - if (TMath::Abs(sigmaY) > SigmaMaxRap) - return false; - - histos.fill(HIST("SigmaSel/hSigmaMassSelected"), sigmaMass); - histos.fill(HIST("SigmaSel/hSelectionStatistics"), 3.); - histos.fill(HIST("SigmaSel/h3dMassSigma0AfterSel"), centrality, SigmapT, sigmaMass); - - return true; - } - - // ______________________________________________________ - // Real data processing - no MC subscription - template - void runAnalysis(TCollision const& coll, TV0s const& fullV0s) - { - if (!IsEventAccepted(coll)) - return; - - float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); - - //_______________________________________________ - // V0s loop - std::vector bestGammasArray; - std::vector bestLambdasArray; - - for (auto& v0 : fullV0s) { - if (processPhotonCandidate(v0, coll)) // selecting photons - bestGammasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best gamma candidates - - if (processLambdaCandidate(v0, coll)) // selecting lambdas - bestLambdasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best lambda candidates - } - //_______________________________________________ - // Retrieving IR info - float interactionRate = -1; - if (fGetIR) { - interactionRate = rateFetcher.fetch(ccdb.service, coll.timestamp(), coll.runNumber(), irSource, fIRCrashOnNull) * 1.e-3; - if (interactionRate < 0) - histos.get(HIST("GeneralQA/hRunNumberNegativeIR"))->Fill(Form("%d", coll.runNumber()), 1); - - histos.fill(HIST("GeneralQA/hInteractionRate"), interactionRate); - histos.fill(HIST("GeneralQA/hCentralityVsInteractionRate"), centrality, interactionRate); - } - - //_______________________________________________ - // Pi0 optional loop - if (doPi0QA) { - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); - for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { - auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); - runPi0QA(gamma1, gamma2, coll); - } - } - } - - //_______________________________________________ - // Sigma0 nested loop - for (size_t i = 0; i < bestGammasArray.size(); ++i) { - auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); - - for (size_t j = 0; j < bestLambdasArray.size(); ++j) { - auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); - - // Building sigma0 candidate - if (!buildSigma0(lambda, gamma, coll)) - continue; - } - } - } - - void processStartTime() - { - start = std::chrono::high_resolution_clock::now(); - } - void processRealData(soa::Join::iterator const& coll, V0StandardDerivedDatas const& fullV0s, dauTracks const&) - { - processStartTime(); - runAnalysis(coll, fullV0s); - } - void processEndTime(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s) - { - end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - - if (fverbose) LOGF(info, "[Process function call, Iterator] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); - } - PROCESS_SWITCH(sigma0QCIterator, processRealData, "process using iterators", true); - PROCESS_SWITCH(sigma0QCIterator, processEndTime, "process using iterators. End time.", true); + PROCESS_SWITCH(sigma0Unsorted, processRealData, "process run 3 real data", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Utils/sigma0BuilderHelper.h b/PWGLF/Utils/sigma0BuilderHelper.h new file mode 100644 index 00000000000..528f861b9d4 --- /dev/null +++ b/PWGLF/Utils/sigma0BuilderHelper.h @@ -0,0 +1,539 @@ +// 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. + +#ifndef PWGLF_UTILS_SIGMA0BUILDERHELPER_H_ +#define PWGLF_UTILS_SIGMA0BUILDERHELPER_H_ + +#include +#include +#include +#include "Framework/AnalysisDataModel.h" +#include "ReconstructionDataFormats/Track.h" +#include "CommonConstants/PhysicsConstants.h" +#include "Common/Core/trackUtilities.h" + +namespace o2 +{ +namespace pwglf +{ +namespace sigma0 +{ + +// event selection configurables +struct evselConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "evselOpts"; + + o2::framework::Configurable doPPAnalysis{"doPPAnalysis", true, "if in pp, set to true"}; + o2::framework::Configurable requireSel8{"requireSel8", true, "require sel8 event selection"}; + o2::framework::Configurable requireTriggerTVX{"requireTriggerTVX", true, "require FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level"}; + o2::framework::Configurable rejectITSROFBorder{"rejectITSROFBorder", true, "reject events at ITS ROF border"}; + o2::framework::Configurable rejectTFBorder{"rejectTFBorder", true, "reject events at TF border"}; + o2::framework::Configurable requireIsVertexITSTPC{"requireIsVertexITSTPC", true, "require events with at least one ITS-TPC track"}; + o2::framework::Configurable requireIsGoodZvtxFT0VsPV{"requireIsGoodZvtxFT0VsPV", true, "require events with PV position along z consistent (within 1 cm) between PV reconstructed using tracks and PV using FT0 A-C time difference"}; + o2::framework::Configurable requireIsVertexTOFmatched{"requireIsVertexTOFmatched", false, "require events with at least one of vertex contributors matched to TOF"}; + o2::framework::Configurable requireIsVertexTRDmatched{"requireIsVertexTRDmatched", false, "require events with at least one of vertex contributors matched to TRD"}; + o2::framework::Configurable rejectSameBunchPileup{"rejectSameBunchPileup", false, "reject collisions in case of pileup with another collision in the same foundBC"}; + o2::framework::Configurable requireNoCollInTimeRangeStd{"requireNoCollInTimeRangeStd", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds or mult above a certain threshold in -4 - -2 microseconds"}; + o2::framework::Configurable requireNoCollInTimeRangeStrict{"requireNoCollInTimeRangeStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 10 microseconds"}; + o2::framework::Configurable requireNoCollInTimeRangeNarrow{"requireNoCollInTimeRangeNarrow", false, "reject collisions corrupted by the cannibalism, with other collisions within +/- 2 microseconds"}; + o2::framework::Configurable requireNoCollInTimeRangeVzDep{"requireNoCollInTimeRangeVzDep", false, "reject collisions corrupted by the cannibalism, with other collisions with pvZ of drifting TPC tracks from past/future collisions within 2.5 cm the current pvZ"}; + o2::framework::Configurable requireNoCollInROFStd{"requireNoCollInROFStd", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF with mult. above a certain threshold"}; + o2::framework::Configurable requireNoCollInROFStrict{"requireNoCollInROFStrict", false, "reject collisions corrupted by the cannibalism, with other collisions within the same ITS ROF"}; + o2::framework::Configurable requireINEL0{"requireINEL0", false, "require INEL>0 event selection"}; + o2::framework::Configurable requireINEL1{"requireINEL1", false, "require INEL>1 event selection"}; + o2::framework::Configurable maxZVtxPosition{"maxZVtxPosition", 10., "max Z vtx position"}; + o2::framework::Configurable useEvtSelInDenomEff{"useEvtSelInDenomEff", false, "Consider event selections in the recoed <-> gen collision association for the denominator (or numerator) of the acc. x eff. (or signal loss)?"}; + o2::framework::Configurable applyZVtxSelOnMCPV{"applyZVtxSelOnMCPV", false, "Apply Z-vtx cut on the PV of the generated collision?"}; + o2::framework::Configurable useFT0CbasedOccupancy{"useFT0CbasedOccupancy", false, "Use sum of FT0-C amplitudes for estimating occupancy? (if not, use track-based definition)"}; + // fast check on occupancy + o2::framework::Configurable minOccupancy{"minOccupancy", -1, "minimum occupancy from neighbouring collisions"}; + o2::framework::Configurable maxOccupancy{"maxOccupancy", -1, "maximum occupancy from neighbouring collisions"}; + + // fast check on interaction rate + o2::framework::Configurable fGetIR{"fGetIR", false, "Flag to retrieve the IR info."}; + o2::framework::Configurable fIRCrashOnNull{"fIRCrashOnNull", false, "Flag to avoid CTP RateFetcher crash."}; + o2::framework::Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; + o2::framework::Configurable minIR{"minIR", -1, "minimum IR collisions"}; + o2::framework::Configurable maxIR{"maxIR", -1, "maximum IR collisions"}; + +}; + +// Lambda criteria: +struct lambdaselConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "lambdaselOpts"; + + o2::framework::Configurable useMLScores{"useMLScores", false, "use ML scores to select candidates"}; + o2::framework::Configurable Lambda_MLThreshold{"Lambda_MLThreshold", 0.1, "Decision Threshold value to select lambdas"}; + o2::framework::Configurable AntiLambda_MLThreshold{"AntiLambda_MLThreshold", 0.1, "Decision Threshold value to select antilambdas"}; + o2::framework::Configurable LambdaRapidity{"LambdaRapidity", 0.8, "v0 rapidity"}; + o2::framework::Configurable LambdaDauPseudoRap{"LambdaDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; + o2::framework::Configurable LambdaMinDCANegToPv{"LambdaMinDCANegToPv", 0.0, "min DCA Neg To PV (cm)"}; + o2::framework::Configurable LambdaMinDCAPosToPv{"LambdaMinDCAPosToPv", 0.0, "min DCA Pos To PV (cm)"}; + o2::framework::Configurable LambdaMaxDCAV0Dau{"LambdaMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + o2::framework::Configurable LambdaMinv0radius{"LambdaMinv0radius", 0.0, "Min V0 radius (cm)"}; + o2::framework::Configurable LambdaMaxv0radius{"LambdaMaxv0radius", 60, "Max V0 radius (cm)"}; + o2::framework::Configurable LambdaWindow{"LambdaWindow", 0.05, "Mass window around expected (in GeV/c2)"}; +}; + +struct photonselConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "photonselOpts"; + + o2::framework::Configurable useMLScores{"useMLScores", false, "use ML scores to select candidates"}; + o2::framework::Configurable Gamma_MLThreshold{"Gamma_MLThreshold", 0.1, "Decision Threshold value to select gammas"}; + o2::framework::Configurable PhotonRapidity{"PhotonRapidity", 0.8, "v0 rapidity"}; + o2::framework::Configurable PhotonMaxDauPseudoRap{"PhotonMaxDauPseudoRap", 1.5, "Max pseudorapidity of daughter tracks"}; + o2::framework::Configurable PhotonMinDCAToPv{"PhotonMinDCAToPv", 0.0, "Min DCA daughter To PV (cm)"}; + o2::framework::Configurable PhotonMaxDCAV0Dau{"PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + o2::framework::Configurable PhotonMinRadius{"PhotonMinRadius", 0.0, "Min photon conversion radius (cm)"}; + o2::framework::Configurable PhotonMaxRadius{"PhotonMaxRadius", 240, "Max photon conversion radius (cm)"}; + o2::framework::Configurable PhotonMaxMass{"PhotonMaxMass", 0.3, "Max photon mass (GeV/c^{2})"}; +}; + +struct sigma0selConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "sigma0selOpts"; + + o2::framework::Configurable Sigma0Window{"Sigma0Window", 0.1, "Mass window around expected (in GeV/c2)"}; + o2::framework::Configurable SigmaMaxRap{"SigmaMaxRap", 0.8, "Max sigma0 rapidity"}; + +}; + +struct pi0selConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "pi0selOpts"; + + o2::framework::Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; + o2::framework::Configurable Pi0PhotonMinDCADauToPv{"Pi0PhotonMinDCADauToPv", 0.0, "Min DCA daughter To PV (cm)"}; + o2::framework::Configurable Pi0PhotonMaxDCAV0Dau{"Pi0PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; + o2::framework::Configurable Pi0PhotonMinTPCCrossedRows{"Pi0PhotonMinTPCCrossedRows", 0, "Min daughter TPC Crossed Rows"}; + o2::framework::Configurable Pi0PhotonMaxTPCNSigmas{"Pi0PhotonMaxTPCNSigmas", 7, "Max TPC NSigmas for daughters"}; + o2::framework::Configurable Pi0PhotonMaxEta{"Pi0PhotonMaxEta", 0.8, "Max photon rapidity"}; + o2::framework::Configurable Pi0PhotonMinRadius{"Pi0PhotonMinRadius", 3.0, "Min photon conversion radius (cm)"}; + o2::framework::Configurable Pi0PhotonMaxRadius{"Pi0PhotonMaxRadius", 115, "Max photon conversion radius (cm)"}; + o2::framework::Configurable Pi0PhotonMaxQt{"Pi0PhotonMaxQt", 0.05, "Max photon qt value (AP plot) (GeV/c)"}; + o2::framework::Configurable Pi0PhotonMaxAlpha{"Pi0PhotonMaxAlpha", 0.95, "Max photon alpha absolute value (AP plot)"}; + o2::framework::Configurable Pi0PhotonMinV0cospa{"Pi0PhotonMinV0cospa", 0.80, "Min V0 CosPA"}; + o2::framework::Configurable Pi0PhotonMaxMass{"Pi0PhotonMaxMass", 0.10, "Max photon mass (GeV/c^{2})"}; +}; + +struct axisConfigurables : o2::framework::ConfigurableGroup { + std::string prefix = "axisOpts"; + + // base properties + o2::framework::ConfigurableAxis axisPt{"axisPt", {o2::framework::VARIABLE_WIDTH, 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f, 1.8f, 1.9f, 2.0f, 2.2f, 2.4f, 2.6f, 2.8f, 3.0f, 3.2f, 3.4f, 3.6f, 3.8f, 4.0f, 4.4f, 4.8f, 5.2f, 5.6f, 6.0f, 6.5f, 7.0f, 7.5f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 17.0f, 19.0f, 21.0f, 23.0f, 25.0f, 30.0f, 35.0f, 40.0f, 50.0f}, "pt axis for analysis"}; + o2::framework::ConfigurableAxis axisCentrality{"axisCentrality", {o2::framework::VARIABLE_WIDTH, 0.0f, 5.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f, 70.0f, 80.0f, 90.0f, 100.0f, 110.0f}, "Centrality"}; + + // Invariant Mass + o2::framework::ConfigurableAxis axisSigmaMass{"axisSigmaMass", {500, 1.10f, 1.30f}, "M_{#Sigma^{0}} (GeV/c^{2})"}; + o2::framework::ConfigurableAxis axisLambdaMass{"axisLambdaMass", {200, 1.05f, 1.151f}, "M_{#Lambda} (GeV/c^{2})"}; + o2::framework::ConfigurableAxis axisPhotonMass{"axisPhotonMass", {200, -0.1f, 0.5f}, "M_{#Gamma}"}; + o2::framework::ConfigurableAxis axisPi0Mass{"axisPi0Mass", {200, 0.08f, 0.18f}, "M_{#Pi^{0}}"}; + + // AP plot axes + o2::framework::ConfigurableAxis axisAPAlpha{"axisAPAlpha", {220, -1.1f, 1.1f}, "V0 AP alpha"}; + o2::framework::ConfigurableAxis axisAPQt{"axisAPQt", {220, 0.0f, 0.5f}, "V0 AP alpha"}; + + // Track quality axes + o2::framework::ConfigurableAxis axisTPCrows{"axisTPCrows", {160, 0.0f, 160.0f}, "N TPC rows"}; + + // topological variable QA axes + o2::framework::ConfigurableAxis axisDCAtoPV{"axisDCAtoPV", {500, 0.0f, 50.0f}, "DCA (cm)"}; + o2::framework::ConfigurableAxis axisXY{"axisXY", {120, -120.0f, 120.0f}, "XY axis"}; + o2::framework::ConfigurableAxis axisDCAdau{"axisDCAdau", {50, 0.0f, 5.0f}, "DCA (cm)"}; + o2::framework::ConfigurableAxis axisRadius{"axisRadius", {240, 0.0f, 120.0f}, "V0 radius (cm)"}; + o2::framework::ConfigurableAxis axisPA{"axisPA", {100, 0.0f, 1}, "Pointing angle"}; + o2::framework::ConfigurableAxis axisRapidity{"axisRapidity", {100, -2.0f, 2.0f}, "Rapidity"}; + o2::framework::ConfigurableAxis axisCandSel{"axisCandSel", {7, 0.5f, +7.5f}, "Candidate Selection"}; + o2::framework::ConfigurableAxis axisNch{"axisNch", {300, 0.0f, 3000.0f}, "N_{ch}"}; + o2::framework::ConfigurableAxis axisIRBinning{"axisIRBinning", {150, 0, 1500}, "Binning for the interaction rate (kHz)"}; +}; + + +class Sigma0BuilderModule +{ + public: + Sigma0BuilderModule() + { + // constructor + } + + template + bool IsEventAccepted(TCollision collision, THistoRegistry& histos, TCCDB ccdb, TRateFetcher rateFetcher) + // check whether the collision passes our collision selections + { + if (evselOpts.requireSel8 && !collision.sel8()) { + return false; + } + if (evselOpts.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { + return false; + } + if (evselOpts.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + return false; + } + if (evselOpts.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { + return false; + } + if (std::abs(collision.posZ()) > evselOpts.maxZVtxPosition) { + return false; + } + if (evselOpts.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { + return false; + } + if (evselOpts.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { + return false; + } + if (evselOpts.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { + return false; + } + if (evselOpts.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { + return false; + } + if (evselOpts.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { + return false; + } + if (evselOpts.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { + return false; + } + if (evselOpts.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { + return false; + } + if (evselOpts.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { + return false; + } + if (evselOpts.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { + return false; + } + if (evselOpts.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { + return false; + } + if (evselOpts.doPPAnalysis) { // we are in pp + if (evselOpts.requireINEL0 && collision.multNTracksPVeta1() < 1) { + return false; + } + if (evselOpts.requireINEL1 && collision.multNTracksPVeta1() < 2) { + return false; + } + } else { // we are in Pb-Pb + float collisionOccupancy = evselOpts.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); + if (evselOpts.minOccupancy >= 0 && collisionOccupancy < evselOpts.minOccupancy) { + return false; + } + if (evselOpts.maxOccupancy >= 0 && collisionOccupancy > evselOpts.maxOccupancy) { + return false; + } + } + // Fetch interaction rate only if required (in order to limit ccdb calls) + double interactionRate = (evselOpts.minIR >= 0 || evselOpts.maxIR >= 0) ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), evselOpts.irSource, evselOpts.fIRCrashOnNull) * 1.e-3 : -1; + if (evselOpts.minIR >= 0 && interactionRate < evselOpts.minIR) { + return false; + } + if (evselOpts.maxIR >= 0 && interactionRate > evselOpts.maxIR) { + return false; + } + float centrality = evselOpts.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + histos.template get(HIST("hEventCentrality"))->Fill(centrality); + histos.template get(HIST("hInteractionRate"))->Fill(interactionRate); + histos.template get(HIST("hCentralityVsInteractionRate"))->Fill(centrality, interactionRate); + + return true; + } + + template + void runPi0QA(TV0Object const& gamma1, TV0Object const& gamma2, TCollision collision, THistoRegistry& histos) + { + // Check if both V0s are made of the same tracks + if (gamma1.posTrackExtraId() == gamma2.posTrackExtraId() || + gamma1.negTrackExtraId() == gamma2.negTrackExtraId()) { + return; + } + + // Calculate pi0 properties + std::array pVecGamma1{gamma1.px(), gamma1.py(), gamma1.pz()}; + std::array pVecGamma2{gamma2.px(), gamma2.py(), gamma2.pz()}; + std::array arrpi0{pVecGamma1, pVecGamma2}; + float pi0Mass = RecoDecay::m(arrpi0, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassPhoton}); + float pi0Pt = RecoDecay::pt(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py()}); + float pi0Y = RecoDecay::y(std::array{gamma1.px() + gamma2.px(), gamma1.py() + gamma2.py(), gamma1.pz() + gamma2.pz()}, o2::constants::physics::MassPi0); + float centrality = evselOpts.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + histos.template get(HIST("Pi0QA/h3dMassPi0BeforeSel_Candidates"))->Fill(centrality, pi0Pt, pi0Mass); + + // Photon-specific selections + auto posTrackGamma1 = gamma1.template posTrackExtra_as>(); + auto negTrackGamma1 = gamma1.template negTrackExtra_as>(); + auto posTrackGamma2 = gamma2.template posTrackExtra_as>(); + auto negTrackGamma2 = gamma2.template negTrackExtra_as>(); + + // Gamma1 Selection + bool passedTPCGamma1 = (TMath::Abs(posTrackGamma1.tpcNSigmaEl()) < pi0selOpts.Pi0PhotonMaxTPCNSigmas) || + (TMath::Abs(negTrackGamma1.tpcNSigmaEl()) < pi0selOpts.Pi0PhotonMaxTPCNSigmas); + + if (TMath::Abs(gamma1.mGamma()) > pi0selOpts.Pi0PhotonMaxMass || + gamma1.qtarm() >= pi0selOpts.Pi0PhotonMaxQt || + TMath::Abs(gamma1.alpha()) >= pi0selOpts.Pi0PhotonMaxAlpha || + TMath::Abs(gamma1.dcapostopv()) < pi0selOpts.Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma1.dcanegtopv()) < pi0selOpts.Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma1.dcaV0daughters()) > pi0selOpts.Pi0PhotonMaxDCAV0Dau || + TMath::Abs(gamma1.negativeeta()) >= pi0selOpts.Pi0PhotonMaxEta || + TMath::Abs(gamma1.positiveeta()) >= pi0selOpts.Pi0PhotonMaxEta || + gamma1.v0cosPA() <= pi0selOpts.Pi0PhotonMinV0cospa || + gamma1.v0radius() <= pi0selOpts.Pi0PhotonMinRadius || + gamma1.v0radius() >= pi0selOpts.Pi0PhotonMaxRadius || + posTrackGamma1.tpcCrossedRows() < pi0selOpts.Pi0PhotonMinTPCCrossedRows || + negTrackGamma1.tpcCrossedRows() < pi0selOpts.Pi0PhotonMinTPCCrossedRows || + !passedTPCGamma1) { + return; + } + + // Gamma2 Selection + bool passedTPCGamma2 = (TMath::Abs(posTrackGamma2.tpcNSigmaEl()) < pi0selOpts.Pi0PhotonMaxTPCNSigmas) || + (TMath::Abs(negTrackGamma2.tpcNSigmaEl()) < pi0selOpts.Pi0PhotonMaxTPCNSigmas); + + if (TMath::Abs(gamma2.mGamma()) > pi0selOpts.Pi0PhotonMaxMass || + gamma2.qtarm() >= pi0selOpts.Pi0PhotonMaxQt || + TMath::Abs(gamma2.alpha()) >= pi0selOpts.Pi0PhotonMaxAlpha || + TMath::Abs(gamma2.dcapostopv()) < pi0selOpts.Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma2.dcanegtopv()) < pi0selOpts.Pi0PhotonMinDCADauToPv || + TMath::Abs(gamma2.dcaV0daughters()) > pi0selOpts.Pi0PhotonMaxDCAV0Dau || + TMath::Abs(gamma2.negativeeta()) >= pi0selOpts.Pi0PhotonMaxEta || + TMath::Abs(gamma2.positiveeta()) >= pi0selOpts.Pi0PhotonMaxEta || + gamma2.v0cosPA() <= pi0selOpts.Pi0PhotonMinV0cospa || + gamma2.v0radius() <= pi0selOpts.Pi0PhotonMinRadius || + gamma2.v0radius() >= pi0selOpts.Pi0PhotonMaxRadius || + posTrackGamma2.tpcCrossedRows() < pi0selOpts.Pi0PhotonMinTPCCrossedRows || + negTrackGamma2.tpcCrossedRows() < pi0selOpts.Pi0PhotonMinTPCCrossedRows || + !passedTPCGamma2) { + return; + } + + // Pi0-specific selections: + if (TMath::Abs(pi0Y) > 0.5) { + return; + } + + // Fill histograms + histos.template get(HIST("Pi0QA/h3dMassPi0AfterSel_Candidates"))->Fill(centrality, pi0Pt, pi0Mass); + } + + // Process photon candidate + template + bool processPhotonCandidate(TV0Object const& gamma, TCollision collision, THistoRegistry& histos) + { + if (gamma.v0Type() == 0) + return false; + + if (photonselOpts.useMLScores) { + // Gamma selection: + if (gamma.gammaBDTScore() <= photonselOpts.Gamma_MLThreshold) + return false; + + } else { + // Standard selection + // Gamma basic selection criteria: + if ((gamma.mGamma() < 0) || (gamma.mGamma() > photonselOpts.PhotonMaxMass)) + return false; + float PhotonY = RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma); + if ((TMath::Abs(PhotonY) > photonselOpts.PhotonRapidity) || (TMath::Abs(gamma.negativeeta()) > photonselOpts.PhotonMaxDauPseudoRap) || (TMath::Abs(gamma.positiveeta()) > photonselOpts.PhotonMaxDauPseudoRap)) + return false; + if ((TMath::Abs(gamma.dcapostopv()) < photonselOpts.PhotonMinDCAToPv) || (TMath::Abs(gamma.dcanegtopv()) < photonselOpts.PhotonMinDCAToPv)) + return false; + if (TMath::Abs(gamma.dcaV0daughters()) > photonselOpts.PhotonMaxDCAV0Dau) + return false; + if ((gamma.v0radius() < photonselOpts.PhotonMinRadius) || (gamma.v0radius() > photonselOpts.PhotonMaxRadius)) + return false; + } + float centrality = evselOpts.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.template get(HIST("PhotonSel/h3dPhotonMass"))->Fill(centrality, gamma.pt(), gamma.mGamma()); + + return true; + } + + // Process photon candidate + template + bool processLambdaCandidate(TV0Object const& lambda, TCollision collision, THistoRegistry& histos) + { + if (lambda.v0Type() != 1) + return false; + + if (lambdaselOpts.useMLScores) { + if ((lambda.lambdaBDTScore() <= lambdaselOpts.Lambda_MLThreshold) && (lambda.antiLambdaBDTScore() <= lambdaselOpts.AntiLambda_MLThreshold)) + return false; + + } else { + // Lambda basic selection criteria: + if ((TMath::Abs(lambda.mLambda() - o2::constants::physics::MassLambda0) > lambdaselOpts.LambdaWindow) && (TMath::Abs(lambda.mAntiLambda() - o2::constants::physics::MassLambda0) > lambdaselOpts.LambdaWindow)) + return false; + if ((TMath::Abs(lambda.yLambda()) > lambdaselOpts.LambdaRapidity) || (TMath::Abs(lambda.negativeeta()) > lambdaselOpts.LambdaDauPseudoRap) || (TMath::Abs(lambda.positiveeta()) > lambdaselOpts.LambdaDauPseudoRap)) + return false; + if ((TMath::Abs(lambda.dcapostopv()) < lambdaselOpts.LambdaMinDCAPosToPv) || (TMath::Abs(lambda.dcanegtopv()) < lambdaselOpts.LambdaMinDCANegToPv)) + return false; + if ((lambda.v0radius() < lambdaselOpts.LambdaMinv0radius) || (lambda.v0radius() > lambdaselOpts.LambdaMaxv0radius)) + return false; + if (TMath::Abs(lambda.dcaV0daughters()) > lambdaselOpts.LambdaMaxDCAV0Dau) + return false; + } + + float centrality = evselOpts.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + histos.template get(HIST("LambdaSel/h3dLambdaMass"))->Fill(centrality, lambda.pt(), lambda.mLambda()); + histos.template get(HIST("LambdaSel/h3dALambdaMass"))->Fill(centrality, lambda.pt(), lambda.mAntiLambda()); + + return true; + } + /////////// + // Process sigma candidate and store properties in object + template + bool buildSigma0(TV0Object const& lambda, TV0Object const& gamma, TCollision collision, THistoRegistry& histos) + { + // Checking if both V0s are made of the very same tracks + if (gamma.posTrackExtraId() == lambda.posTrackExtraId() || + gamma.negTrackExtraId() == lambda.negTrackExtraId()) { + return false; + } + + // Sigma0 candidate properties + std::array pVecPhotons{gamma.px(), gamma.py(), gamma.pz()}; + std::array pVecLambda{lambda.px(), lambda.py(), lambda.pz()}; + auto arrMom = std::array{pVecPhotons, pVecLambda}; + float sigmaMass = RecoDecay::m(arrMom, std::array{o2::constants::physics::MassPhoton, o2::constants::physics::MassLambda0}); + float sigmaY = RecoDecay::y(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py(), gamma.pz() + lambda.pz()}, o2::constants::physics::MassSigma0); + float SigmapT = RecoDecay::pt(std::array{gamma.px() + lambda.px(), gamma.py() + lambda.py()}); + float centrality = evselOpts.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); + + // Before any selection + histos.template get(HIST("SigmaSel/h3dMassSigma0BeforeSel"))->Fill(centrality, SigmapT, sigmaMass); + histos.template get(HIST("SigmaSel/hSigmaMass"))->Fill(sigmaMass); + histos.template get(HIST("SigmaSel/hSigmaMassWindow"))->Fill(sigmaMass - 1.192642); + + if (TMath::Abs(sigmaMass - 1.192642) > sigma0selOpts.Sigma0Window) + return false; + + histos.template get(HIST("SigmaSel/hSigmaY"))->Fill(sigmaY); + + if (TMath::Abs(sigmaY) > sigma0selOpts.SigmaMaxRap) + return false; + + histos.template get(HIST("SigmaSel/hSigmaMassSelected"))->Fill(sigmaMass); + histos.template get(HIST("SigmaSel/h3dMassSigma0AfterSel"))->Fill(centrality, SigmapT, sigmaMass); + + return true; + } + + // declaration of structs here + // (N.B.: will be invisible to the outside, create your own copies) + o2::pwglf::sigma0::evselConfigurables evselOpts; + o2::pwglf::sigma0::lambdaselConfigurables lambdaselOpts; + o2::pwglf::sigma0::photonselConfigurables photonselOpts; + o2::pwglf::sigma0::sigma0selConfigurables sigma0selOpts; + o2::pwglf::sigma0::pi0selConfigurables pi0selOpts; + o2::pwglf::sigma0::axisConfigurables axisOpts; + + template + void init(THistoRegistry& histos, + TEvSelOpt const& external_evselopts, + TLambdaSelOpt const& external_lambdaselopts, + TPhotonSelOpt const& external_photonselopts, + TSigma0SelOpt const& external_sigma0selopts, + TPi0Opt const& external_pi0selopts, + TAxisOpt const& external_axisopts) + { + // read in configurations from the task where it's used + evselOpts = external_evselopts; + lambdaselOpts = external_lambdaselopts; + photonselOpts = external_photonselopts; + sigma0selOpts = external_sigma0selopts; + pi0selOpts = external_pi0selopts; + axisOpts = external_axisopts; + + histos.add("hEventCentrality", "hEventCentrality", framework::kTH1D, {axisOpts.axisCentrality}); + histos.add("hInteractionRate", "hInteractionRate", framework::kTH1F, {axisOpts.axisIRBinning}); + histos.add("hCentralityVsInteractionRate", "hCentralityVsInteractionRate", o2::framework::kTH2F, {axisOpts.axisCentrality, axisOpts.axisIRBinning}); + + // For selection: + histos.add("PhotonSel/h3dPhotonMass", "h3dPhotonMass", framework::kTH3D, {axisOpts.axisCentrality, axisOpts.axisPt, axisOpts.axisPhotonMass}); + histos.add("LambdaSel/h3dLambdaMass", "h3dLambdaMass", framework::kTH3D, {axisOpts.axisCentrality, axisOpts.axisPt, axisOpts.axisLambdaMass}); + histos.add("LambdaSel/h3dALambdaMass", "h3dALambdaMass", framework::kTH3D, {axisOpts.axisCentrality, axisOpts.axisPt, axisOpts.axisLambdaMass}); + + histos.add("SigmaSel/h3dMassSigma0BeforeSel", "h3dMassSigma0BeforeSel", framework::kTH3F, {axisOpts.axisCentrality, axisOpts.axisPt, axisOpts.axisSigmaMass}); + histos.add("SigmaSel/hSigmaMass", "hSigmaMass", framework::kTH1F, {axisOpts.axisSigmaMass}); + histos.add("SigmaSel/hSigmaMassWindow", "hSigmaMassWindow", framework::kTH1F, {{200, -0.09f, 0.11f}}); + histos.add("SigmaSel/hSigmaY", "hSigmaY", framework::kTH1F, {axisOpts.axisRapidity}); + histos.add("SigmaSel/hSigmaMassSelected", "hSigmaMassSelected", framework::kTH1F, {axisOpts.axisSigmaMass}); + histos.add("SigmaSel/h3dMassSigma0AfterSel", "h3dMassSigma0AfterSel", framework::kTH3D, {axisOpts.axisCentrality, axisOpts.axisPt, axisOpts.axisSigmaMass}); + + // For Pi0 QA + histos.add("Pi0QA/h3dMassPi0BeforeSel_Candidates", "h3dMassPi0BeforeSel_Candidates", framework::kTH3D, {axisOpts.axisCentrality, axisOpts.axisPt, axisOpts.axisPi0Mass}); + histos.add("Pi0QA/h3dMassPi0AfterSel_Candidates", "h3dMassPi0AfterSel_Candidates", framework::kTH3D, {axisOpts.axisCentrality, axisOpts.axisPt, axisOpts.axisPi0Mass}); + } + + // ______________________________________________________ + // Real data processing - no MC subscription + template + void process(TCollision const& collisions, TV0s const& fullV0s, THistoRegistry& histos, TSlicecache& cache, TCCDB const& ccdb, TRateFetcher& rateFetcher) + { + uint64_t CollIDBuffer = 0; + for (const auto& coll : collisions) { + if (!IsEventAccepted(coll, histos, ccdb, rateFetcher)) + continue; + + const uint64_t collIdx = coll.globalIndex(); + if (collIdx < CollIDBuffer) + LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, collIdx); + + CollIDBuffer = collIdx; + + //_______________________________________________ + // V0s loop + std::vector bestGammasArray; + std::vector bestLambdasArray; + + auto V0s = fullV0s.sliceByCached(o2::aod::v0data::straCollisionId, collIdx, cache); + for (auto& v0 : V0s) { + if (processPhotonCandidate(v0, coll, histos)) // selecting photons + bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates + + if (processLambdaCandidate(v0, coll, histos)) // selecting lambdas + bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates + } + + + //_______________________________________________ + // Pi0 optional loop + if (pi0selOpts.doPi0QA) { + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); + for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { + auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); + runPi0QA(gamma1, gamma2, coll, histos); + } + } + } + + //_______________________________________________ + // Sigma0 nested loop + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); + + for (size_t j = 0; j < bestLambdasArray.size(); ++j) { + auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); + + // Building sigma0 candidate + if (!buildSigma0(lambda, gamma, coll, histos)) + continue; + } + } + } + } // end process +}; // end Sigma0BuilderModule + +} // namespace sigma0 +} // namespace pwglf +} // namespace o2 + +#endif // PWGLF_UTILS_SIGMA0BUILDERHELPER_H_ From cb092033737678e9bc0bd21d5e87c3d5b88166e7 Mon Sep 17 00:00:00 2001 From: gianniliveraro Date: Fri, 11 Jul 2025 12:02:10 -0300 Subject: [PATCH 5/8] Fixes + new structs for v0 grouping --- PWGLF/TableProducer/QC/sigma0QC.cxx | 132 +++++++++++++++++++++++++-- PWGLF/Utils/sigma0BuilderHelper.h | 133 ++++++++++++++++++++++++++-- 2 files changed, 248 insertions(+), 17 deletions(-) diff --git a/PWGLF/TableProducer/QC/sigma0QC.cxx b/PWGLF/TableProducer/QC/sigma0QC.cxx index de752c0534e..c0e1ebd505b 100644 --- a/PWGLF/TableProducer/QC/sigma0QC.cxx +++ b/PWGLF/TableProducer/QC/sigma0QC.cxx @@ -66,12 +66,13 @@ struct sigma0Sorted { ctpRateFetcher rateFetcher; // Load configurables and the sigma0 module, please + Configurable fverbose{"fverbose", true, "QA printout."}; o2::pwglf::sigma0::evselConfigurables evselOpts; o2::pwglf::sigma0::lambdaselConfigurables lambdaselOpts; o2::pwglf::sigma0::photonselConfigurables photonselOpts; o2::pwglf::sigma0::sigma0selConfigurables sigma0selOpts; o2::pwglf::sigma0::pi0selConfigurables pi0selOpts; - o2::pwglf::sigma0::axisConfigurables axisOpts; + o2::pwglf::sigma0::axisConfigurables axisOpts; o2::pwglf::sigma0::Sigma0BuilderModule sigma0Module; @@ -81,7 +82,6 @@ struct sigma0Sorted { // Histogram registry HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - Configurable fverbose{"fverbose", true, "QA printout."}; void init(InitContext const&) { @@ -101,7 +101,7 @@ struct sigma0Sorted { void processRealData(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&){ auto start = std::chrono::high_resolution_clock::now(); - sigma0Module.process(collisions, fullV0s, histos, cache, ccdb, rateFetcher); + sigma0Module.processSlicing(collisions, fullV0s, perCollisionSTDDerived, histos, ccdb, rateFetcher); auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration elapsed = end - start; @@ -117,12 +117,13 @@ struct sigma0Unsorted { ctpRateFetcher rateFetcher; // Load configurables and the sigma0 module, please + Configurable fverbose{"fverbose", true, "QA printout."}; o2::pwglf::sigma0::evselConfigurables evselOpts; o2::pwglf::sigma0::lambdaselConfigurables lambdaselOpts; o2::pwglf::sigma0::photonselConfigurables photonselOpts; o2::pwglf::sigma0::sigma0selConfigurables sigma0selOpts; o2::pwglf::sigma0::pi0selConfigurables pi0selOpts; - o2::pwglf::sigma0::axisConfigurables axisOpts; + o2::pwglf::sigma0::axisConfigurables axisOpts; o2::pwglf::sigma0::Sigma0BuilderModule sigma0Module; @@ -131,8 +132,7 @@ struct sigma0Unsorted { PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; // Histogram registry - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; - Configurable fverbose{"fverbose", true, "QA printout."}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext const&) { @@ -152,20 +152,134 @@ struct sigma0Unsorted { void processRealData(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&){ auto start = std::chrono::high_resolution_clock::now(); - sigma0Module.process(collisions, fullV0s, histos, cache, ccdb, rateFetcher); + sigma0Module.processSlicing(collisions, fullV0s, perCollisionSTDDerived, histos, ccdb, rateFetcher); auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration elapsed = end - start; - if (fverbose) LOGF(info, "[Process function call, Sorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + if (fverbose) LOGF(info, "[Process function call, Unsorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); } PROCESS_SWITCH(sigma0Unsorted, processRealData, "process run 3 real data", true); }; +struct sigma0Iterator { + Service ccdb; + ctpRateFetcher rateFetcher; + + // Load configurables and the sigma0 module, please + Configurable fverbose{"fverbose", true, "QA printout."}; + o2::pwglf::sigma0::evselConfigurables evselOpts; + o2::pwglf::sigma0::lambdaselConfigurables lambdaselOpts; + o2::pwglf::sigma0::photonselConfigurables photonselOpts; + o2::pwglf::sigma0::sigma0selConfigurables sigma0selOpts; + o2::pwglf::sigma0::pi0selConfigurables pi0selOpts; + o2::pwglf::sigma0::axisConfigurables axisOpts; + + o2::pwglf::sigma0::Sigma0BuilderModule sigma0Module; + + // Histogram registry + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + uint64_t CollIDBuffer = 0; + std::chrono::high_resolution_clock::time_point start{}; + std::chrono::high_resolution_clock::time_point end{}; + void init(InitContext const&) + { + // setting CCDB service + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + // Initialize task + sigma0Module.init(histos, evselOpts, lambdaselOpts, photonselOpts, sigma0selOpts, pi0selOpts, axisOpts); + } + + // Dummy process function + void process(V0StandardDerivedDatas const&){} + + void processCheckIndexOrdered(V0StandardDerivedDatas const& fullV0s){ + CollIDBuffer=0; + for (const auto& v0 : fullV0s) { + const uint64_t v0collidx = v0.straCollisionId(); + if (v0collidx < CollIDBuffer) + LOGF(fatal, "V0 -> stracollision: index unsorted! Previous index: %i, current index: %i", CollIDBuffer, v0collidx); + CollIDBuffer = v0collidx; + } + } + void processTI(StraColls const&){ + start = std::chrono::high_resolution_clock::now(); + } + + void processRealData(StraColls::iterator const& collision, V0StandardDerivedDatas const& fullV0s, dauTracks const&){ + sigma0Module.processIterator(collision, fullV0s, histos, ccdb, rateFetcher); + } + + void processTF(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s){ + end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + + if (fverbose) LOGF(info, "[Process function call, Iterator] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + } + + PROCESS_SWITCH(sigma0Iterator, processCheckIndexOrdered, "check ordering", true); + PROCESS_SWITCH(sigma0Iterator, processTI, "Initial setup", true); + PROCESS_SWITCH(sigma0Iterator, processRealData, "process data", true); + PROCESS_SWITCH(sigma0Iterator, processTF, "Printouts", true); +}; + +struct sigma0CustomGrouping { + Service ccdb; + ctpRateFetcher rateFetcher; + + // Load configurables and the sigma0 module, please + Configurable fverbose{"fverbose", true, "QA printout."}; + o2::pwglf::sigma0::evselConfigurables evselOpts; + o2::pwglf::sigma0::lambdaselConfigurables lambdaselOpts; + o2::pwglf::sigma0::photonselConfigurables photonselOpts; + o2::pwglf::sigma0::sigma0selConfigurables sigma0selOpts; + o2::pwglf::sigma0::pi0selConfigurables pi0selOpts; + o2::pwglf::sigma0::axisConfigurables axisOpts; + + o2::pwglf::sigma0::Sigma0BuilderModule sigma0Module; + + // Histogram registry + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + + void init(InitContext const&) + { + // setting CCDB service + ccdb->setURL("http://alice-ccdb.cern.ch"); + ccdb->setCaching(true); + ccdb->setLocalObjectValidityChecking(); + ccdb->setFatalWhenNull(false); + + // Initialize task + sigma0Module.init(histos, evselOpts, lambdaselOpts, photonselOpts, sigma0selOpts, pi0selOpts, axisOpts); + } + + // Dummy process function + void process(StraColls const&){} + + void processRealData(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&){ + auto start = std::chrono::high_resolution_clock::now(); + + sigma0Module.processCustomGrouping(collisions, fullV0s, histos, ccdb, rateFetcher); + + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + + if (fverbose) LOGF(info, "[Process function call, Custom] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + } + + PROCESS_SWITCH(sigma0CustomGrouping, processRealData, "process run 3 real data", true); +}; + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/Utils/sigma0BuilderHelper.h b/PWGLF/Utils/sigma0BuilderHelper.h index 528f861b9d4..7559ad9e483 100644 --- a/PWGLF/Utils/sigma0BuilderHelper.h +++ b/PWGLF/Utils/sigma0BuilderHelper.h @@ -474,8 +474,8 @@ class Sigma0BuilderModule // ______________________________________________________ // Real data processing - no MC subscription - template - void process(TCollision const& collisions, TV0s const& fullV0s, THistoRegistry& histos, TSlicecache& cache, TCCDB const& ccdb, TRateFetcher& rateFetcher) + template + void processSlicing(TCollision const& collisions, TV0s const& fullV0s, TSlicer& slicer, THistoRegistry& histos, TCCDB const& ccdb, TRateFetcher& rateFetcher) { uint64_t CollIDBuffer = 0; for (const auto& coll : collisions) { @@ -483,18 +483,85 @@ class Sigma0BuilderModule continue; const uint64_t collIdx = coll.globalIndex(); - if (collIdx < CollIDBuffer) - LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, collIdx); - - CollIDBuffer = collIdx; //_______________________________________________ // V0s loop std::vector bestGammasArray; std::vector bestLambdasArray; - auto V0s = fullV0s.sliceByCached(o2::aod::v0data::straCollisionId, collIdx, cache); + auto V0s = fullV0s.sliceBy(slicer, collIdx); for (auto& v0 : V0s) { + const uint64_t v0collidx = v0.straCollisionId(); + if (v0collidx < CollIDBuffer) + LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, v0collidx); + + if (processPhotonCandidate(v0, coll, histos)) // selecting photons + bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates + + if (processLambdaCandidate(v0, coll, histos)) // selecting lambdas + bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates + + CollIDBuffer = v0collidx; + } + + + //_______________________________________________ + // Pi0 optional loop + if (pi0selOpts.doPi0QA) { + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); + for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { + auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); + runPi0QA(gamma1, gamma2, coll, histos); + } + } + } + + //_______________________________________________ + // Sigma0 nested loop + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); + + for (size_t j = 0; j < bestLambdasArray.size(); ++j) { + auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); + + // Building sigma0 candidate + if (!buildSigma0(lambda, gamma, coll, histos)) + continue; + } + } + } + } // end processSlicing + + // ______________________________________________________ + // Real data processing - no MC subscription + template + void processCustomGrouping(TCollision const& collisions, TV0s const& fullV0s, THistoRegistry& histos, TCCDB const& ccdb, TRateFetcher& rateFetcher) + { + uint64_t CollIDBuffer = 0; + // brute force grouped index construction + std::vector> v0grouped(collisions.size()); + + for (const auto& v0 : fullV0s) { + v0grouped[v0.straCollisionId()].push_back(v0.globalIndex()); + + const uint64_t v0collidx = v0.straCollisionId(); + if (v0collidx < CollIDBuffer) + LOGF(fatal, "V0 -> stracollision: index unsorted! Previous index: %i, current index: %i", CollIDBuffer, v0collidx); + CollIDBuffer = v0collidx; + } + + for (const auto& coll : collisions) { + if (!IsEventAccepted(coll, histos, ccdb, rateFetcher)) + continue; + + //_______________________________________________ + // V0s loop + std::vector bestGammasArray; + std::vector bestLambdasArray; + + for (size_t i = 0; i < v0grouped[coll.globalIndex()].size(); i++) { + auto v0 = fullV0s.rawIteratorAt(v0grouped[coll.globalIndex()][i]); if (processPhotonCandidate(v0, coll, histos)) // selecting photons bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates @@ -529,7 +596,57 @@ class Sigma0BuilderModule } } } - } // end process + } // end processCustomGrouping + + // ______________________________________________________ + // Real data processing - no MC subscription + template + void processIterator(TCollision const& coll, TV0s const& fullV0s, THistoRegistry& histos, TCCDB const& ccdb, TRateFetcher& rateFetcher) + { + if (!IsEventAccepted(coll, histos, ccdb, rateFetcher)) + return; + + //_______________________________________________ + // V0s loop + std::vector bestGammasArray; + std::vector bestLambdasArray; + + for (auto& v0 : fullV0s) { + if (processPhotonCandidate(v0, coll, histos)) // selecting photons + bestGammasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best gamma candidates + + if (processLambdaCandidate(v0, coll, histos)) // selecting lambdas + bestLambdasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best lambda candidates + } + + //_______________________________________________ + // Pi0 optional loop + if (pi0selOpts.doPi0QA) { + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma1 = fullV0s.rawIteratorAt(bestGammasArray[i]); + for (size_t j = i + 1; j < bestGammasArray.size(); ++j) { + auto gamma2 = fullV0s.rawIteratorAt(bestGammasArray[j]); + runPi0QA(gamma1, gamma2, coll, histos); + } + } + } + + //_______________________________________________ + // Sigma0 nested loop + for (size_t i = 0; i < bestGammasArray.size(); ++i) { + auto gamma = fullV0s.rawIteratorAt(bestGammasArray[i]); + + for (size_t j = 0; j < bestLambdasArray.size(); ++j) { + auto lambda = fullV0s.rawIteratorAt(bestLambdasArray[j]); + + // Building sigma0 candidate + if (!buildSigma0(lambda, gamma, coll, histos)) + continue; + } + } + + } // end processIterator + }; // end Sigma0BuilderModule } // namespace sigma0 From 289744c571aa0fbc95306607a5af6c7507523169 Mon Sep 17 00:00:00 2001 From: gianniliveraro Date: Fri, 11 Jul 2025 13:49:30 -0300 Subject: [PATCH 6/8] Use of brute force grouping in sigma0builder --- .../Strangeness/sigma0builder.cxx | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx index acdae0bca7c..eb12d1a6887 100644 --- a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx +++ b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx @@ -63,7 +63,7 @@ struct sigma0builder { Service ccdb; ctpRateFetcher rateFetcher; - SliceCache cache; + //SliceCache cache; Produces sigma0cores; // save sigma0 candidates for analysis Produces sigmaPhotonExtras; // save sigma0 candidates for analysis @@ -71,8 +71,8 @@ struct sigma0builder { Produces sigma0mccores; // For manual sliceBy - PresliceUnsorted perCollisionMCDerived = o2::aod::v0data::straCollisionId; - PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; + //PresliceUnsorted perCollisionMCDerived = o2::aod::v0data::straCollisionId; + //PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; // pack track quality but separte also afterburner @@ -1138,16 +1138,20 @@ struct sigma0builder { void processMonteCarlo(soa::Join const& collisions, V0DerivedMCDatas const& fullV0s, dauTracks const&, aod::MotherMCParts const&, soa::Join const&, soa::Join const&) { + // brute force grouped index construction + std::vector> v0grouped(collisions.size()); + + for (const auto& v0 : fullV0s) { + v0grouped[v0.straCollisionId()].push_back(v0.globalIndex()); + } + for (const auto& coll : collisions) { if (!IsEventAccepted(coll, true)) continue; - // Do analysis with collision-grouped V0s, retain full collision information - const uint64_t collIdx = coll.globalIndex(); - auto V0s = fullV0s.sliceBy(perCollisionMCDerived, collIdx); float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); - + bool fhasMCColl = false; if (coll.has_straMCCollision()) fhasMCColl = true; @@ -1169,7 +1173,9 @@ struct sigma0builder { //_______________________________________________ // V0s loop - for (auto& v0 : V0s) { + for (size_t i = 0; i < v0grouped[coll.globalIndex()].size(); i++) { + auto v0 = fullV0s.rawIteratorAt(v0grouped[coll.globalIndex()][i]); + if (!v0.has_v0MCCore()) continue; @@ -1317,14 +1323,18 @@ struct sigma0builder { void processRealData(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) { + // brute force grouped index construction + std::vector> v0grouped(collisions.size()); + + for (const auto& v0 : fullV0s) { + v0grouped[v0.straCollisionId()].push_back(v0.globalIndex()); + } + for (const auto& coll : collisions) { if (!IsEventAccepted(coll, true)) continue; - // Do analysis with collision-grouped V0s, retain full collision information - const uint64_t collIdx = coll.globalIndex(); - auto V0s = fullV0s.sliceBy(perCollisionSTDDerived, collIdx); float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); //_______________________________________________ @@ -1344,7 +1354,8 @@ struct sigma0builder { //_______________________________________________ // V0s loop - for (auto& v0 : V0s) { + for (size_t i = 0; i < v0grouped[coll.globalIndex()].size(); i++) { + auto v0 = fullV0s.rawIteratorAt(v0grouped[coll.globalIndex()][i]); if (processPhotonCandidate(v0, coll)) // selecting photons bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates From 884fbfe950001fcbfc9e01b5f2cd2a0f3b3d16fa Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Fri, 11 Jul 2025 17:10:01 +0000 Subject: [PATCH 7/8] Please consider the following formatting changes --- PWGLF/TableProducer/QC/sigma0QC.cxx | 183 ++++++++++-------- .../Strangeness/sigma0builder.cxx | 20 +- PWGLF/Utils/sigma0BuilderHelper.h | 155 ++++++++------- 3 files changed, 184 insertions(+), 174 deletions(-) diff --git a/PWGLF/TableProducer/QC/sigma0QC.cxx b/PWGLF/TableProducer/QC/sigma0QC.cxx index c0e1ebd505b..5ba02e074f2 100644 --- a/PWGLF/TableProducer/QC/sigma0QC.cxx +++ b/PWGLF/TableProducer/QC/sigma0QC.cxx @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. // // This is a task that employs the standard derived V0 tables and attempts to combine -// two V0s into a Sigma0 -> Lambda + gamma candidate. +// two V0s into a Sigma0 -> Lambda + gamma candidate. // *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* // Sigma0 QC task // *+-+*+-+*+-+*+-+*+-+*+-+*+-+*+-+* @@ -20,37 +20,40 @@ // gianni.shigeru.setoue.liveraro@cern.ch // -#include -#include -#include -#include +#include "PWGLF/DataModel/LFSigmaTables.h" +#include "PWGLF/DataModel/LFStrangenessMLTables.h" +#include "PWGLF/DataModel/LFStrangenessPIDTables.h" +#include "PWGLF/DataModel/LFStrangenessTables.h" +#include -#include "Framework/runDataProcessing.h" -#include "Framework/AnalysisTask.h" -#include "Framework/AnalysisDataModel.h" -#include "Framework/ASoAHelpers.h" -#include "Framework/ASoA.h" -#include "ReconstructionDataFormats/Track.h" +#include "Common/CCDB/ctpRateFetcher.h" #include "Common/Core/RecoDecay.h" -#include "Common/Core/trackUtilities.h" #include "Common/Core/TrackSelection.h" -#include "Common/DataModel/TrackSelectionTables.h" -#include "Common/DataModel/EventSelection.h" +#include "Common/Core/trackUtilities.h" #include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" #include "Common/DataModel/PIDResponse.h" -#include "Common/CCDB/ctpRateFetcher.h" -#include "PWGLF/DataModel/LFStrangenessTables.h" -#include "PWGLF/DataModel/LFStrangenessPIDTables.h" -#include "PWGLF/DataModel/LFStrangenessMLTables.h" -#include "PWGLF/DataModel/LFSigmaTables.h" +#include "Common/DataModel/TrackSelectionTables.h" + #include "CCDB/BasicCCDBManager.h" +#include "Framework/ASoA.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/runDataProcessing.h" +#include "ReconstructionDataFormats/Track.h" + +#include +#include #include #include -#include #include #include -#include -#include +#include + +#include +#include +#include using namespace o2; using namespace o2::framework; @@ -60,7 +63,6 @@ using dauTracks = soa::Join; using V0StandardDerivedDatas = soa::Join; using StraColls = soa::Join; - struct sigma0Sorted { Service ccdb; ctpRateFetcher rateFetcher; @@ -72,13 +74,13 @@ struct sigma0Sorted { o2::pwglf::sigma0::photonselConfigurables photonselOpts; o2::pwglf::sigma0::sigma0selConfigurables sigma0selOpts; o2::pwglf::sigma0::pi0selConfigurables pi0selOpts; - o2::pwglf::sigma0::axisConfigurables axisOpts; + o2::pwglf::sigma0::axisConfigurables axisOpts; o2::pwglf::sigma0::Sigma0BuilderModule sigma0Module; - // For manual sliceBy + // For manual sliceBy SliceCache cache; - Preslice perCollisionSTDDerived = o2::aod::v0data::straCollisionId; + Preslice perCollisionSTDDerived = o2::aod::v0data::straCollisionId; // Histogram registry HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; @@ -95,21 +97,23 @@ struct sigma0Sorted { sigma0Module.init(histos, evselOpts, lambdaselOpts, photonselOpts, sigma0selOpts, pi0selOpts, axisOpts); } - // Dummy process function - void process(StraColls const&){} + // Dummy process function + void process(StraColls const&) {} - void processRealData(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&){ - auto start = std::chrono::high_resolution_clock::now(); + void processRealData(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + auto start = std::chrono::high_resolution_clock::now(); + + sigma0Module.processSlicing(collisions, fullV0s, perCollisionSTDDerived, histos, ccdb, rateFetcher); - sigma0Module.processSlicing(collisions, fullV0s, perCollisionSTDDerived, histos, ccdb, rateFetcher); - - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; - if (fverbose) LOGF(info, "[Process function call, Sorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + if (fverbose) + LOGF(info, "[Process function call, Sorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); } - - PROCESS_SWITCH(sigma0Sorted, processRealData, "process run 3 real data", true); + + PROCESS_SWITCH(sigma0Sorted, processRealData, "process run 3 real data", true); }; struct sigma0Unsorted { @@ -123,16 +127,16 @@ struct sigma0Unsorted { o2::pwglf::sigma0::photonselConfigurables photonselOpts; o2::pwglf::sigma0::sigma0selConfigurables sigma0selOpts; o2::pwglf::sigma0::pi0selConfigurables pi0selOpts; - o2::pwglf::sigma0::axisConfigurables axisOpts; + o2::pwglf::sigma0::axisConfigurables axisOpts; o2::pwglf::sigma0::Sigma0BuilderModule sigma0Module; - // For manual sliceBy + // For manual sliceBy SliceCache cache; - PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; + PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; // Histogram registry - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext const&) { @@ -146,21 +150,23 @@ struct sigma0Unsorted { sigma0Module.init(histos, evselOpts, lambdaselOpts, photonselOpts, sigma0selOpts, pi0selOpts, axisOpts); } - // Dummy process function - void process(StraColls const&){} + // Dummy process function + void process(StraColls const&) {} + + void processRealData(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + auto start = std::chrono::high_resolution_clock::now(); - void processRealData(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&){ - auto start = std::chrono::high_resolution_clock::now(); + sigma0Module.processSlicing(collisions, fullV0s, perCollisionSTDDerived, histos, ccdb, rateFetcher); - sigma0Module.processSlicing(collisions, fullV0s, perCollisionSTDDerived, histos, ccdb, rateFetcher); - - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; - if (fverbose) LOGF(info, "[Process function call, Unsorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + if (fverbose) + LOGF(info, "[Process function call, Unsorted] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); } - - PROCESS_SWITCH(sigma0Unsorted, processRealData, "process run 3 real data", true); + + PROCESS_SWITCH(sigma0Unsorted, processRealData, "process run 3 real data", true); }; struct sigma0Iterator { @@ -174,12 +180,12 @@ struct sigma0Iterator { o2::pwglf::sigma0::photonselConfigurables photonselOpts; o2::pwglf::sigma0::sigma0selConfigurables sigma0selOpts; o2::pwglf::sigma0::pi0selConfigurables pi0selOpts; - o2::pwglf::sigma0::axisConfigurables axisOpts; + o2::pwglf::sigma0::axisConfigurables axisOpts; o2::pwglf::sigma0::Sigma0BuilderModule sigma0Module; // Histogram registry - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; uint64_t CollIDBuffer = 0; std::chrono::high_resolution_clock::time_point start{}; std::chrono::high_resolution_clock::time_point end{}; @@ -195,37 +201,42 @@ struct sigma0Iterator { sigma0Module.init(histos, evselOpts, lambdaselOpts, photonselOpts, sigma0selOpts, pi0selOpts, axisOpts); } - // Dummy process function - void process(V0StandardDerivedDatas const&){} + // Dummy process function + void process(V0StandardDerivedDatas const&) {} - void processCheckIndexOrdered(V0StandardDerivedDatas const& fullV0s){ - CollIDBuffer=0; + void processCheckIndexOrdered(V0StandardDerivedDatas const& fullV0s) + { + CollIDBuffer = 0; for (const auto& v0 : fullV0s) { - const uint64_t v0collidx = v0.straCollisionId(); - if (v0collidx < CollIDBuffer) - LOGF(fatal, "V0 -> stracollision: index unsorted! Previous index: %i, current index: %i", CollIDBuffer, v0collidx); + const uint64_t v0collidx = v0.straCollisionId(); + if (v0collidx < CollIDBuffer) + LOGF(fatal, "V0 -> stracollision: index unsorted! Previous index: %i, current index: %i", CollIDBuffer, v0collidx); CollIDBuffer = v0collidx; } } - void processTI(StraColls const&){ + void processTI(StraColls const&) + { start = std::chrono::high_resolution_clock::now(); } - void processRealData(StraColls::iterator const& collision, V0StandardDerivedDatas const& fullV0s, dauTracks const&){ - sigma0Module.processIterator(collision, fullV0s, histos, ccdb, rateFetcher); + void processRealData(StraColls::iterator const& collision, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + sigma0Module.processIterator(collision, fullV0s, histos, ccdb, rateFetcher); } - void processTF(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s){ + void processTF(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s) + { end = std::chrono::high_resolution_clock::now(); std::chrono::duration elapsed = end - start; - if (fverbose) LOGF(info, "[Process function call, Iterator] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + if (fverbose) + LOGF(info, "[Process function call, Iterator] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); } - + PROCESS_SWITCH(sigma0Iterator, processCheckIndexOrdered, "check ordering", true); PROCESS_SWITCH(sigma0Iterator, processTI, "Initial setup", true); PROCESS_SWITCH(sigma0Iterator, processRealData, "process data", true); - PROCESS_SWITCH(sigma0Iterator, processTF, "Printouts", true); + PROCESS_SWITCH(sigma0Iterator, processTF, "Printouts", true); }; struct sigma0CustomGrouping { @@ -239,12 +250,12 @@ struct sigma0CustomGrouping { o2::pwglf::sigma0::photonselConfigurables photonselOpts; o2::pwglf::sigma0::sigma0selConfigurables sigma0selOpts; o2::pwglf::sigma0::pi0selConfigurables pi0selOpts; - o2::pwglf::sigma0::axisConfigurables axisOpts; + o2::pwglf::sigma0::axisConfigurables axisOpts; o2::pwglf::sigma0::Sigma0BuilderModule sigma0Module; // Histogram registry - HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; + HistogramRegistry histos{"Histos", {}, OutputObjHandlingPolicy::AnalysisObject}; void init(InitContext const&) { @@ -258,28 +269,30 @@ struct sigma0CustomGrouping { sigma0Module.init(histos, evselOpts, lambdaselOpts, photonselOpts, sigma0selOpts, pi0selOpts, axisOpts); } - // Dummy process function - void process(StraColls const&){} + // Dummy process function + void process(StraColls const&) {} - void processRealData(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&){ - auto start = std::chrono::high_resolution_clock::now(); + void processRealData(StraColls const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) + { + auto start = std::chrono::high_resolution_clock::now(); + + sigma0Module.processCustomGrouping(collisions, fullV0s, histos, ccdb, rateFetcher); - sigma0Module.processCustomGrouping(collisions, fullV0s, histos, ccdb, rateFetcher); - - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; - if (fverbose) LOGF(info, "[Process function call, Custom] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); + if (fverbose) + LOGF(info, "[Process function call, Custom] N. Collisions: %i, N. V0s: %i, Processing time (s): %lf", collisions.size(), fullV0s.size(), elapsed.count()); } - - PROCESS_SWITCH(sigma0CustomGrouping, processRealData, "process run 3 real data", true); + + PROCESS_SWITCH(sigma0CustomGrouping, processRealData, "process run 3 real data", true); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { return WorkflowSpec{ - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc), - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; } diff --git a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx index eb12d1a6887..09e89ec81af 100644 --- a/PWGLF/TableProducer/Strangeness/sigma0builder.cxx +++ b/PWGLF/TableProducer/Strangeness/sigma0builder.cxx @@ -63,7 +63,7 @@ struct sigma0builder { Service ccdb; ctpRateFetcher rateFetcher; - //SliceCache cache; + // SliceCache cache; Produces sigma0cores; // save sigma0 candidates for analysis Produces sigmaPhotonExtras; // save sigma0 candidates for analysis @@ -71,8 +71,8 @@ struct sigma0builder { Produces sigma0mccores; // For manual sliceBy - //PresliceUnsorted perCollisionMCDerived = o2::aod::v0data::straCollisionId; - //PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; + // PresliceUnsorted perCollisionMCDerived = o2::aod::v0data::straCollisionId; + // PresliceUnsorted perCollisionSTDDerived = o2::aod::v0data::straCollisionId; PresliceUnsorted> perMcCollision = aod::v0data::straMCCollisionId; // pack track quality but separte also afterburner @@ -1138,9 +1138,9 @@ struct sigma0builder { void processMonteCarlo(soa::Join const& collisions, V0DerivedMCDatas const& fullV0s, dauTracks const&, aod::MotherMCParts const&, soa::Join const&, soa::Join const&) { - // brute force grouped index construction - std::vector> v0grouped(collisions.size()); - + // brute force grouped index construction + std::vector> v0grouped(collisions.size()); + for (const auto& v0 : fullV0s) { v0grouped[v0.straCollisionId()].push_back(v0.globalIndex()); } @@ -1151,7 +1151,7 @@ struct sigma0builder { continue; float centrality = doPPAnalysis ? coll.centFT0M() : coll.centFT0C(); - + bool fhasMCColl = false; if (coll.has_straMCCollision()) fhasMCColl = true; @@ -1323,9 +1323,9 @@ struct sigma0builder { void processRealData(soa::Join const& collisions, V0StandardDerivedDatas const& fullV0s, dauTracks const&) { - // brute force grouped index construction - std::vector> v0grouped(collisions.size()); - + // brute force grouped index construction + std::vector> v0grouped(collisions.size()); + for (const auto& v0 : fullV0s) { v0grouped[v0.straCollisionId()].push_back(v0.globalIndex()); } diff --git a/PWGLF/Utils/sigma0BuilderHelper.h b/PWGLF/Utils/sigma0BuilderHelper.h index 7559ad9e483..e6b97abb7b0 100644 --- a/PWGLF/Utils/sigma0BuilderHelper.h +++ b/PWGLF/Utils/sigma0BuilderHelper.h @@ -12,13 +12,15 @@ #ifndef PWGLF_UTILS_SIGMA0BUILDERHELPER_H_ #define PWGLF_UTILS_SIGMA0BUILDERHELPER_H_ -#include -#include -#include +#include "Common/Core/trackUtilities.h" + +#include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisDataModel.h" #include "ReconstructionDataFormats/Track.h" -#include "CommonConstants/PhysicsConstants.h" -#include "Common/Core/trackUtilities.h" + +#include +#include +#include namespace o2 { @@ -63,7 +65,6 @@ struct evselConfigurables : o2::framework::ConfigurableGroup { o2::framework::Configurable irSource{"irSource", "T0VTX", "Estimator of the interaction rate (Recommended: pp --> T0VTX, Pb-Pb --> ZNC hadronic)"}; o2::framework::Configurable minIR{"minIR", -1, "minimum IR collisions"}; o2::framework::Configurable maxIR{"maxIR", -1, "maximum IR collisions"}; - }; // Lambda criteria: @@ -102,13 +103,12 @@ struct sigma0selConfigurables : o2::framework::ConfigurableGroup { o2::framework::Configurable Sigma0Window{"Sigma0Window", 0.1, "Mass window around expected (in GeV/c2)"}; o2::framework::Configurable SigmaMaxRap{"SigmaMaxRap", 0.8, "Max sigma0 rapidity"}; - }; struct pi0selConfigurables : o2::framework::ConfigurableGroup { std::string prefix = "pi0selOpts"; - o2::framework::Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; + o2::framework::Configurable doPi0QA{"doPi0QA", true, "Flag to fill QA histos for pi0 rejection study."}; o2::framework::Configurable Pi0PhotonMinDCADauToPv{"Pi0PhotonMinDCADauToPv", 0.0, "Min DCA daughter To PV (cm)"}; o2::framework::Configurable Pi0PhotonMaxDCAV0Dau{"Pi0PhotonMaxDCAV0Dau", 3.5, "Max DCA V0 Daughters (cm)"}; o2::framework::Configurable Pi0PhotonMinTPCCrossedRows{"Pi0PhotonMinTPCCrossedRows", 0, "Min daughter TPC Crossed Rows"}; @@ -154,7 +154,6 @@ struct axisConfigurables : o2::framework::ConfigurableGroup { o2::framework::ConfigurableAxis axisIRBinning{"axisIRBinning", {150, 0, 1500}, "Binning for the interaction rate (kHz)"}; }; - class Sigma0BuilderModule { public: @@ -169,73 +168,73 @@ class Sigma0BuilderModule { if (evselOpts.requireSel8 && !collision.sel8()) { return false; - } + } if (evselOpts.requireTriggerTVX && !collision.selection_bit(aod::evsel::kIsTriggerTVX)) { return false; - } + } if (evselOpts.rejectITSROFBorder && !collision.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { return false; - } + } if (evselOpts.rejectTFBorder && !collision.selection_bit(o2::aod::evsel::kNoTimeFrameBorder)) { return false; - } + } if (std::abs(collision.posZ()) > evselOpts.maxZVtxPosition) { return false; - } + } if (evselOpts.requireIsVertexITSTPC && !collision.selection_bit(o2::aod::evsel::kIsVertexITSTPC)) { return false; - } + } if (evselOpts.requireIsGoodZvtxFT0VsPV && !collision.selection_bit(o2::aod::evsel::kIsGoodZvtxFT0vsPV)) { return false; - } + } if (evselOpts.requireIsVertexTOFmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTOFmatched)) { return false; - } + } if (evselOpts.requireIsVertexTRDmatched && !collision.selection_bit(o2::aod::evsel::kIsVertexTRDmatched)) { return false; - } + } if (evselOpts.rejectSameBunchPileup && !collision.selection_bit(o2::aod::evsel::kNoSameBunchPileup)) { return false; - } + } if (evselOpts.requireNoCollInTimeRangeStd && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStandard)) { return false; - } + } if (evselOpts.requireNoCollInTimeRangeStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeStrict)) { return false; - } + } if (evselOpts.requireNoCollInTimeRangeNarrow && !collision.selection_bit(o2::aod::evsel::kNoCollInTimeRangeNarrow)) { return false; - } + } if (evselOpts.requireNoCollInROFStd && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStandard)) { return false; - } + } if (evselOpts.requireNoCollInROFStrict && !collision.selection_bit(o2::aod::evsel::kNoCollInRofStrict)) { return false; - } + } if (evselOpts.doPPAnalysis) { // we are in pp if (evselOpts.requireINEL0 && collision.multNTracksPVeta1() < 1) { return false; - } + } if (evselOpts.requireINEL1 && collision.multNTracksPVeta1() < 2) { return false; - } + } } else { // we are in Pb-Pb float collisionOccupancy = evselOpts.useFT0CbasedOccupancy ? collision.ft0cOccupancyInTimeRange() : collision.trackOccupancyInTimeRange(); if (evselOpts.minOccupancy >= 0 && collisionOccupancy < evselOpts.minOccupancy) { return false; - } + } if (evselOpts.maxOccupancy >= 0 && collisionOccupancy > evselOpts.maxOccupancy) { return false; - } + } } // Fetch interaction rate only if required (in order to limit ccdb calls) double interactionRate = (evselOpts.minIR >= 0 || evselOpts.maxIR >= 0) ? rateFetcher.fetch(ccdb.service, collision.timestamp(), collision.runNumber(), evselOpts.irSource, evselOpts.fIRCrashOnNull) * 1.e-3 : -1; if (evselOpts.minIR >= 0 && interactionRate < evselOpts.minIR) { return false; - } + } if (evselOpts.maxIR >= 0 && interactionRate > evselOpts.maxIR) { return false; - } + } float centrality = evselOpts.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); histos.template get(HIST("hEventCentrality"))->Fill(centrality); @@ -273,7 +272,7 @@ class Sigma0BuilderModule // Gamma1 Selection bool passedTPCGamma1 = (TMath::Abs(posTrackGamma1.tpcNSigmaEl()) < pi0selOpts.Pi0PhotonMaxTPCNSigmas) || - (TMath::Abs(negTrackGamma1.tpcNSigmaEl()) < pi0selOpts.Pi0PhotonMaxTPCNSigmas); + (TMath::Abs(negTrackGamma1.tpcNSigmaEl()) < pi0selOpts.Pi0PhotonMaxTPCNSigmas); if (TMath::Abs(gamma1.mGamma()) > pi0selOpts.Pi0PhotonMaxMass || gamma1.qtarm() >= pi0selOpts.Pi0PhotonMaxQt || @@ -294,7 +293,7 @@ class Sigma0BuilderModule // Gamma2 Selection bool passedTPCGamma2 = (TMath::Abs(posTrackGamma2.tpcNSigmaEl()) < pi0selOpts.Pi0PhotonMaxTPCNSigmas) || - (TMath::Abs(negTrackGamma2.tpcNSigmaEl()) < pi0selOpts.Pi0PhotonMaxTPCNSigmas); + (TMath::Abs(negTrackGamma2.tpcNSigmaEl()) < pi0selOpts.Pi0PhotonMaxTPCNSigmas); if (TMath::Abs(gamma2.mGamma()) > pi0selOpts.Pi0PhotonMaxMass || gamma2.qtarm() >= pi0selOpts.Pi0PhotonMaxQt || @@ -318,7 +317,7 @@ class Sigma0BuilderModule return; } - // Fill histograms + // Fill histograms histos.template get(HIST("Pi0QA/h3dMassPi0AfterSel_Candidates"))->Fill(centrality, pi0Pt, pi0Mass); } @@ -336,18 +335,18 @@ class Sigma0BuilderModule } else { // Standard selection - // Gamma basic selection criteria: + // Gamma basic selection criteria: if ((gamma.mGamma() < 0) || (gamma.mGamma() > photonselOpts.PhotonMaxMass)) return false; - float PhotonY = RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma); + float PhotonY = RecoDecay::y(std::array{gamma.px(), gamma.py(), gamma.pz()}, o2::constants::physics::MassGamma); if ((TMath::Abs(PhotonY) > photonselOpts.PhotonRapidity) || (TMath::Abs(gamma.negativeeta()) > photonselOpts.PhotonMaxDauPseudoRap) || (TMath::Abs(gamma.positiveeta()) > photonselOpts.PhotonMaxDauPseudoRap)) - return false; + return false; if ((TMath::Abs(gamma.dcapostopv()) < photonselOpts.PhotonMinDCAToPv) || (TMath::Abs(gamma.dcanegtopv()) < photonselOpts.PhotonMinDCAToPv)) - return false; + return false; if (TMath::Abs(gamma.dcaV0daughters()) > photonselOpts.PhotonMaxDCAV0Dau) - return false; + return false; if ((gamma.v0radius() < photonselOpts.PhotonMinRadius) || (gamma.v0radius() > photonselOpts.PhotonMaxRadius)) - return false; + return false; } float centrality = evselOpts.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); histos.template get(HIST("PhotonSel/h3dPhotonMass"))->Fill(centrality, gamma.pt(), gamma.mGamma()); @@ -367,17 +366,17 @@ class Sigma0BuilderModule return false; } else { - // Lambda basic selection criteria: + // Lambda basic selection criteria: if ((TMath::Abs(lambda.mLambda() - o2::constants::physics::MassLambda0) > lambdaselOpts.LambdaWindow) && (TMath::Abs(lambda.mAntiLambda() - o2::constants::physics::MassLambda0) > lambdaselOpts.LambdaWindow)) - return false; + return false; if ((TMath::Abs(lambda.yLambda()) > lambdaselOpts.LambdaRapidity) || (TMath::Abs(lambda.negativeeta()) > lambdaselOpts.LambdaDauPseudoRap) || (TMath::Abs(lambda.positiveeta()) > lambdaselOpts.LambdaDauPseudoRap)) - return false; + return false; if ((TMath::Abs(lambda.dcapostopv()) < lambdaselOpts.LambdaMinDCAPosToPv) || (TMath::Abs(lambda.dcanegtopv()) < lambdaselOpts.LambdaMinDCANegToPv)) - return false; + return false; if ((lambda.v0radius() < lambdaselOpts.LambdaMinv0radius) || (lambda.v0radius() > lambdaselOpts.LambdaMaxv0radius)) - return false; + return false; if (TMath::Abs(lambda.dcaV0daughters()) > lambdaselOpts.LambdaMaxDCAV0Dau) - return false; + return false; } float centrality = evselOpts.doPPAnalysis ? collision.centFT0M() : collision.centFT0C(); @@ -413,7 +412,7 @@ class Sigma0BuilderModule if (TMath::Abs(sigmaMass - 1.192642) > sigma0selOpts.Sigma0Window) return false; - + histos.template get(HIST("SigmaSel/hSigmaY"))->Fill(sigmaY); if (TMath::Abs(sigmaY) > sigma0selOpts.SigmaMaxRap) @@ -435,7 +434,7 @@ class Sigma0BuilderModule o2::pwglf::sigma0::axisConfigurables axisOpts; template - void init(THistoRegistry& histos, + void init(THistoRegistry& histos, TEvSelOpt const& external_evselopts, TLambdaSelOpt const& external_lambdaselopts, TPhotonSelOpt const& external_photonselopts, @@ -451,7 +450,7 @@ class Sigma0BuilderModule pi0selOpts = external_pi0selopts; axisOpts = external_axisopts; - histos.add("hEventCentrality", "hEventCentrality", framework::kTH1D, {axisOpts.axisCentrality}); + histos.add("hEventCentrality", "hEventCentrality", framework::kTH1D, {axisOpts.axisCentrality}); histos.add("hInteractionRate", "hInteractionRate", framework::kTH1F, {axisOpts.axisIRBinning}); histos.add("hCentralityVsInteractionRate", "hCentralityVsInteractionRate", o2::framework::kTH2F, {axisOpts.axisCentrality, axisOpts.axisIRBinning}); @@ -466,7 +465,7 @@ class Sigma0BuilderModule histos.add("SigmaSel/hSigmaY", "hSigmaY", framework::kTH1F, {axisOpts.axisRapidity}); histos.add("SigmaSel/hSigmaMassSelected", "hSigmaMassSelected", framework::kTH1F, {axisOpts.axisSigmaMass}); histos.add("SigmaSel/h3dMassSigma0AfterSel", "h3dMassSigma0AfterSel", framework::kTH3D, {axisOpts.axisCentrality, axisOpts.axisPt, axisOpts.axisSigmaMass}); - + // For Pi0 QA histos.add("Pi0QA/h3dMassPi0BeforeSel_Candidates", "h3dMassPi0BeforeSel_Candidates", framework::kTH3D, {axisOpts.axisCentrality, axisOpts.axisPt, axisOpts.axisPi0Mass}); histos.add("Pi0QA/h3dMassPi0AfterSel_Candidates", "h3dMassPi0AfterSel_Candidates", framework::kTH3D, {axisOpts.axisCentrality, axisOpts.axisPt, axisOpts.axisPi0Mass}); @@ -482,29 +481,28 @@ class Sigma0BuilderModule if (!IsEventAccepted(coll, histos, ccdb, rateFetcher)) continue; - const uint64_t collIdx = coll.globalIndex(); + const uint64_t collIdx = coll.globalIndex(); //_______________________________________________ // V0s loop std::vector bestGammasArray; std::vector bestLambdasArray; - auto V0s = fullV0s.sliceBy(slicer, collIdx); + auto V0s = fullV0s.sliceBy(slicer, collIdx); for (auto& v0 : V0s) { - const uint64_t v0collidx = v0.straCollisionId(); - if (v0collidx < CollIDBuffer) - LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, v0collidx); - - if (processPhotonCandidate(v0, coll, histos)) // selecting photons + const uint64_t v0collidx = v0.straCollisionId(); + if (v0collidx < CollIDBuffer) + LOGF(fatal, "Collision table unsorted! Previous index: %i, current index: %i", CollIDBuffer, v0collidx); + + if (processPhotonCandidate(v0, coll, histos)) // selecting photons bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates - if (processLambdaCandidate(v0, coll, histos)) // selecting lambdas + if (processLambdaCandidate(v0, coll, histos)) // selecting lambdas bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates CollIDBuffer = v0collidx; } - - + //_______________________________________________ // Pi0 optional loop if (pi0selOpts.doPi0QA) { @@ -527,27 +525,27 @@ class Sigma0BuilderModule // Building sigma0 candidate if (!buildSigma0(lambda, gamma, coll, histos)) - continue; + continue; } } } - } // end processSlicing + } // end processSlicing - // ______________________________________________________ + // ______________________________________________________ // Real data processing - no MC subscription template void processCustomGrouping(TCollision const& collisions, TV0s const& fullV0s, THistoRegistry& histos, TCCDB const& ccdb, TRateFetcher& rateFetcher) { uint64_t CollIDBuffer = 0; - // brute force grouped index construction - std::vector> v0grouped(collisions.size()); + // brute force grouped index construction + std::vector> v0grouped(collisions.size()); for (const auto& v0 : fullV0s) { v0grouped[v0.straCollisionId()].push_back(v0.globalIndex()); - const uint64_t v0collidx = v0.straCollisionId(); - if (v0collidx < CollIDBuffer) - LOGF(fatal, "V0 -> stracollision: index unsorted! Previous index: %i, current index: %i", CollIDBuffer, v0collidx); + const uint64_t v0collidx = v0.straCollisionId(); + if (v0collidx < CollIDBuffer) + LOGF(fatal, "V0 -> stracollision: index unsorted! Previous index: %i, current index: %i", CollIDBuffer, v0collidx); CollIDBuffer = v0collidx; } @@ -562,14 +560,13 @@ class Sigma0BuilderModule for (size_t i = 0; i < v0grouped[coll.globalIndex()].size(); i++) { auto v0 = fullV0s.rawIteratorAt(v0grouped[coll.globalIndex()][i]); - if (processPhotonCandidate(v0, coll, histos)) // selecting photons + if (processPhotonCandidate(v0, coll, histos)) // selecting photons bestGammasArray.push_back(v0.globalIndex()); // Save indices of best gamma candidates - if (processLambdaCandidate(v0, coll, histos)) // selecting lambdas + if (processLambdaCandidate(v0, coll, histos)) // selecting lambdas bestLambdasArray.push_back(v0.globalIndex()); // Save indices of best lambda candidates } - - + //_______________________________________________ // Pi0 optional loop if (pi0selOpts.doPi0QA) { @@ -592,11 +589,11 @@ class Sigma0BuilderModule // Building sigma0 candidate if (!buildSigma0(lambda, gamma, coll, histos)) - continue; + continue; } } } - } // end processCustomGrouping + } // end processCustomGrouping // ______________________________________________________ // Real data processing - no MC subscription @@ -612,13 +609,13 @@ class Sigma0BuilderModule std::vector bestLambdasArray; for (auto& v0 : fullV0s) { - if (processPhotonCandidate(v0, coll, histos)) // selecting photons + if (processPhotonCandidate(v0, coll, histos)) // selecting photons bestGammasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best gamma candidates - if (processLambdaCandidate(v0, coll, histos)) // selecting lambdas + if (processLambdaCandidate(v0, coll, histos)) // selecting lambdas bestLambdasArray.push_back(v0.globalIndex() - fullV0s.offset()); // Save indices of best lambda candidates } - + //_______________________________________________ // Pi0 optional loop if (pi0selOpts.doPi0QA) { @@ -641,11 +638,11 @@ class Sigma0BuilderModule // Building sigma0 candidate if (!buildSigma0(lambda, gamma, coll, histos)) - continue; + continue; } } - - } // end processIterator + + } // end processIterator }; // end Sigma0BuilderModule From 4807e00e936f88e964ad3593f31f246f55efba43 Mon Sep 17 00:00:00 2001 From: ddobrigk Date: Fri, 11 Jul 2025 20:11:04 +0200 Subject: [PATCH 8/8] Update sigma0BuilderHelper.h --- PWGLF/Utils/sigma0BuilderHelper.h | 1 + 1 file changed, 1 insertion(+) diff --git a/PWGLF/Utils/sigma0BuilderHelper.h b/PWGLF/Utils/sigma0BuilderHelper.h index e6b97abb7b0..ad1fadd8e93 100644 --- a/PWGLF/Utils/sigma0BuilderHelper.h +++ b/PWGLF/Utils/sigma0BuilderHelper.h @@ -16,6 +16,7 @@ #include "CommonConstants/PhysicsConstants.h" #include "Framework/AnalysisDataModel.h" +#include "Framework/HistogramRegistry.h" #include "ReconstructionDataFormats/Track.h" #include