From f19ba10aef3a3664ed387839200fecc673fe7986 Mon Sep 17 00:00:00 2001 From: jesgum Date: Wed, 5 Aug 2026 17:25:57 +0200 Subject: [PATCH] Add ZDC and FIT time tables and kIsBBZPA && kIsBBZPC selections to centrality study --- Common/DataModel/Multiplicity.h | 20 ++++ .../TableProducer/multiplicityExtraTable.cxx | 105 +++++++++++++----- Common/Tasks/centralityStudy.cxx | 90 +++++++++------ 3 files changed, 157 insertions(+), 58 deletions(-) diff --git a/Common/DataModel/Multiplicity.h b/Common/DataModel/Multiplicity.h index c2bdd2c6a75..713c4f2f67b 100644 --- a/Common/DataModel/Multiplicity.h +++ b/Common/DataModel/Multiplicity.h @@ -104,6 +104,16 @@ DECLARE_SOA_COLUMN(FT0TriggerMask, ft0TriggerMask, uint8_t); //! DECLARE_SOA_COLUMN(MultFV0AOuter, multFV0AOuter, float); //! FV0 without innermost ring DECLARE_SOA_COLUMN(MultFT0AOuter, multFT0AOuter, float); //! FT0A without innermost ring +// Timing information +DECLARE_SOA_COLUMN(TimeZNA, timeZNA, float); //! +DECLARE_SOA_COLUMN(TimeZNC, timeZNC, float); //! +DECLARE_SOA_COLUMN(TimeZPA, timeZPA, float); //! +DECLARE_SOA_COLUMN(TimeZPC, timeZPC, float); //! +DECLARE_SOA_COLUMN(TimeT0A, timeT0A, float); //! +DECLARE_SOA_COLUMN(TimeT0C, timeT0C, float); //! +DECLARE_SOA_COLUMN(TimeFDA, timeFDA, float); //! +DECLARE_SOA_COLUMN(TimeFDC, timeFDC, float); //! + } // namespace mult DECLARE_SOA_TABLE(FV0Mults, "AOD", "FV0MULT", //! Multiplicity with the FV0 detector mult::MultFV0A, mult::MultFV0C, @@ -318,6 +328,16 @@ DECLARE_SOA_TABLE_VERSIONED(MultBcSel_001, "AOD", "MULTBCSEL", 1, //! BC selecti mult::MultTVX, mult::MultFV0OrA); +DECLARE_SOA_TABLE(TimeBCs, "AOD", "TIMEBC", //! + mult::TimeT0A, + mult::TimeT0C, + mult::TimeFDA, + mult::TimeFDC, + mult::TimeZNA, + mult::TimeZNC, + mult::TimeZPA, + mult::TimeZPC) + using MultBCs = MultBCs_001; using MultBcSel = MultBcSel_001; using MultBC = MultBCs::iterator; diff --git a/Common/TableProducer/multiplicityExtraTable.cxx b/Common/TableProducer/multiplicityExtraTable.cxx index 488ec9a1917..3211b23a346 100644 --- a/Common/TableProducer/multiplicityExtraTable.cxx +++ b/Common/TableProducer/multiplicityExtraTable.cxx @@ -8,6 +8,13 @@ // 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. + +/// +/// \file multiplicityExtraTable.cxx +/// \brief This tasks produces BC based multiplicity tables +/// \author David Dobrigkeit Chinellato and Jesper Karlsson Gumprecht +/// + #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" @@ -43,6 +50,7 @@ struct MultiplicityExtraTable { Produces multBC; Produces multBcSel; Produces multNeigh; + Produces timeBC; Produces mult2bc; Produces bc2mult; @@ -59,8 +67,10 @@ struct MultiplicityExtraTable { float tru(float value) { - if (bcTableFloatPrecision < 1e-4) + static constexpr float PrecisionThreshold = 1e-4; + if (bcTableFloatPrecision < PrecisionThreshold) { return value; // make sure nothing bad happens in case zero (best precision) + } return bcTableFloatPrecision * std::round(value / bcTableFloatPrecision) + 0.5f * bcTableFloatPrecision; }; @@ -68,8 +78,8 @@ struct MultiplicityExtraTable { unsigned int randomSeed = 0; o2::ccdb::CcdbApi ccdbApi; - Service ccdb; - BCPattern CollidingBunch; + Service ccdb{}; + BCPattern collidingBunch; int newRunNumber = -999; int oldRunNumber = -999; @@ -116,7 +126,7 @@ struct MultiplicityExtraTable { float multFT0C = 0.f; if (bc.has_ft0()) { auto ft0 = bc.ft0(); - for (auto amplitude : ft0.amplitudeC()) { + for (const auto amplitude : ft0.amplitudeC()) { multFT0C += amplitude; } } else { @@ -148,7 +158,7 @@ struct MultiplicityExtraTable { continue; // don't keep if low mult or downsampled out } - bool Tvx = false; + bool tvx = false; bool isFV0OrA = false; float multFT0C = 0.f; float multFT0A = 0.f; @@ -166,6 +176,16 @@ struct MultiplicityExtraTable { float multZPA = -1.f; float multZPC = -1.f; + // FT0 and ZDC time + float timeFT0A = -1e+3; + float timeFT0C = -1e+3; + float timeFDDA = -1e+3; + float timeFDDC = -1e+3; + float timeZNA = -1e+3; + float timeZNC = -1e+3; + float timeZPA = -1e+3; + float timeZPC = -1e+3; + float posZFT0 = -1e+3; bool posZFT0valid = false; @@ -185,32 +205,37 @@ struct MultiplicityExtraTable { LOG(info) << " newRunNumber " << newRunNumber << " time stamp " << ts; oldRunNumber = newRunNumber; auto grplhcif = ccdb->getForTimeStamp("GLO/Config/GRPLHCIF", ts); - CollidingBunch = grplhcif->getBunchFilling().getBCPattern(); + collidingBunch = grplhcif->getBunchFilling().getBCPattern(); } // new run number - bool collidingBC = CollidingBunch.test(localBC); + bool collidingBC = collidingBunch.test(localBC); if (bc.has_ft0()) { const auto& ft0 = bc.ft0(); std::bitset<8> triggers = ft0.triggerMask(); - Tvx = triggers[o2::fit::Triggers::bitVertex]; + tvx = triggers[o2::fit::Triggers::bitVertex]; multFT0TriggerBits = static_cast(triggers.to_ulong()); // calculate T0 charge for (size_t ii = 0; ii < ft0.amplitudeA().size(); ++ii) { multFT0A += ft0.amplitudeA()[ii]; - if (ft0.channelA()[ii] > 31) { + static constexpr int MaxChannelIdInnerRingFT0A = 31; + if (ft0.channelA()[ii] > MaxChannelIdInnerRingFT0A) { multFT0AOuter += ft0.amplitudeA()[ii]; } } - for (auto amplitude : ft0.amplitudeC()) { + for (const auto amplitude : ft0.amplitudeC()) { multFT0C += amplitude; } posZFT0 = ft0.posZ(); posZFT0valid = ft0.isValidTime(); + timeFT0A = ft0.timeC(); + timeFT0C = ft0.timeA(); } else { multFT0A = -999.0f; multFT0C = -999.0f; + timeFT0A = -999.0f; + timeFT0C = -999.0f; } if (bc.has_fv0a()) { auto fv0 = bc.fv0a(); @@ -221,7 +246,8 @@ struct MultiplicityExtraTable { auto amplitude = fv0.amplitude()[ii]; auto channel = fv0.channel()[ii]; multFV0A += amplitude; - if (channel > 7) { + static constexpr int MaxChannelIdInnerRingFV0 = 7; + if (channel > MaxChannelIdInnerRingFV0) { multFV0AOuter += amplitude; } } @@ -235,15 +261,20 @@ struct MultiplicityExtraTable { std::bitset<8> fFDDTriggers = fdd.triggerMask(); multFDDTriggerBits = static_cast(fFDDTriggers.to_ulong()); - for (auto amplitude : fdd.chargeA()) { + for (const auto amplitude : fdd.chargeA()) { multFDDA += amplitude; } - for (auto amplitude : fdd.chargeC()) { + for (const auto amplitude : fdd.chargeC()) { multFDDC += amplitude; } + + timeFDDA = fdd.timeA(); + timeFDDC = fdd.timeC(); } else { multFDDA = -999.0f; multFDDC = -999.0f; + timeFDDA = -999.0f; + timeFDDC = -999.0f; } if (bc.has_zdc()) { @@ -253,6 +284,8 @@ struct MultiplicityExtraTable { multZEM2 = bc.zdc().amplitudeZEM2(); multZPA = bc.zdc().amplitudeZPA(); multZPC = bc.zdc().amplitudeZPC(); + timeZPA = bc.zdc().timeZPA(); + timeZPC = bc.zdc().timeZPC(); } else { multZNA = -999.f; multZNC = -999.f; @@ -260,6 +293,10 @@ struct MultiplicityExtraTable { multZEM2 = -999.f; multZPA = -999.f; multZPC = -999.f; + timeZNA = -999.f; + timeZNC = -999.f; + timeZPA = -999.f; + timeZPC = -999.f; } bc2mult(bc2multArray[bc.globalIndex()]); @@ -290,8 +327,18 @@ struct MultiplicityExtraTable { multFDDTriggerBits, multBCTriggerMask, collidingBC, - Tvx, + tvx, isFV0OrA); + + timeBC( + timeFT0A, + timeFT0C, + timeFDDA, + timeFDDC, + timeZNA, + timeZNC, + timeZPA, + timeZPC); } } @@ -307,16 +354,24 @@ struct MultiplicityExtraTable { float deltaPrevious = 1e+6, deltaPrePrevious = 1e+6; float deltaNext = 1e+6, deltaNeNext = 1e+6; for (const auto& collision : collisions) { - int ii = collision.globalIndex(); - - if (ii - 1 >= 0) - deltaPrevious = timeArray[ii] - timeArray[ii - 1]; - if (ii - 2 >= 0) - deltaPrePrevious = timeArray[ii] - timeArray[ii - 2]; - if (ii + 1 < collisions.size()) - deltaNext = timeArray[ii + 1] - timeArray[ii]; - if (ii + 2 < collisions.size()) - deltaNeNext = timeArray[ii + 2] - timeArray[ii]; + const int thisCollision = collision.globalIndex(); + const int prevCollision = thisCollision - 1; + const int prevPrevCollision = thisCollision - 2; + const int nextCollision = thisCollision + 1; + const int nextNextCollision = thisCollision + 2; + + if (prevCollision >= 0) { + deltaPrevious = timeArray[thisCollision] - timeArray[prevCollision]; + } + if (prevPrevCollision >= 0) { + deltaPrePrevious = timeArray[thisCollision] - timeArray[prevPrevCollision]; + } + if (nextCollision < collisions.size()) { + deltaNext = timeArray[nextCollision] - timeArray[thisCollision]; + } + if (nextNextCollision < collisions.size()) { + deltaNeNext = timeArray[nextNextCollision] - timeArray[thisCollision]; + } multNeigh(deltaPrePrevious, deltaPrevious, deltaNext, deltaNeNext); } @@ -342,5 +397,5 @@ struct MultiplicityExtraTable { WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { - return WorkflowSpec{adaptAnalysisTask(cfgc, TaskName{"multiplicity-extra-table"})}; + return WorkflowSpec{adaptAnalysisTask(cfgc)}; } diff --git a/Common/Tasks/centralityStudy.cxx b/Common/Tasks/centralityStudy.cxx index 349696b76cf..f473fea90b2 100644 --- a/Common/Tasks/centralityStudy.cxx +++ b/Common/Tasks/centralityStudy.cxx @@ -134,7 +134,7 @@ struct CentralityStudy { Configurable rejectIsFlangeEvent{"rejectIsFlangeEvent", false, "At least one channel with -350 TDC < time < -450 TDC"}; Configurable rejectITSinROFpileupStandard{"rejectITSinROFpileupStandard", false, "reject collisions in case of in-ROF ITS pileup (standard)"}; Configurable rejectITSinROFpileupStrict{"rejectITSinROFpileupStrict", false, "reject collisions in case of in-ROF ITS pileup (strict)"}; - Configurable rejectUpc{"rejectUpc", false, "Reject upc events based on forward signals. Configurable group: upcRejection"}; + Configurable rejectUpc{"rejectUpc", false, "Reject upc events based on forward signals. Configurable group: cfgFwd"}; Configurable rejectCollInTimeRangeNarrow{"rejectCollInTimeRangeNarrow", false, "reject if extra colls in time range (narrow)"}; Configurable maxVtxZ{"maxVtxZ", 10.0f, "max vertex z distance from ip"}; Configurable applyBcSel{"applyBcSel", false, "For each collision; de-reference the bc and apply the bc selections"}; @@ -147,27 +147,31 @@ struct CentralityStudy { struct : ConfigurableGroup { std::string prefix = "bcsel"; Configurable rejectZNAC{"rejectZNAC", false, "reject if !(kIsBBZNA && kIsBBZNC)"}; + Configurable rejectZPAC{"rejectZPAC", false, "reject if !(kIsBBZPA && kIsBBZPC)"}; Configurable selectCollidingBCs{"selectCollidingBCs", true, "BC analysis: select colliding BCs"}; Configurable selectTVX{"selectTVX", true, "BC analysis: select TVX"}; Configurable selectFV0OrA{"selectFV0OrA", true, "BC analysis: select FV0OrA"}; - Configurable rejectUpc{"rejectUpc", false, "Reject upc events based on forward signals. Configurable group: upcRejection"}; + Configurable rejectUpc{"rejectUpc", false, "Reject upc events based on forward signals. Configurable group: cfgFwd"}; Configurable vertexZwithT0{"vertexZwithT0", 1000.0f, "require a certain vertex-Z in BC analysis"}; Configurable rejectIsFlangeEvent{"rejectIsFlangeEvent", false, "At least one channel with -350 TDC < time < -450 TDC"}; Configurable minFT0CforVertexZ{"minFT0CforVertexZ", -1.0f, "minimum FT0C for vertex-Z profile calculation"}; } bcsel; // _______________________________________ - // upc rejection criteria - // reject low zna/c + // Limits for selections using forward detectors struct : ConfigurableGroup { - std::string prefix = "upcRejection"; + std::string prefix = "cfgFwd"; Configurable minZNACsignal{"minZNACsignal", -999999.0f, "min zna/c signal"}; - Configurable maxFT0CforZNACselection{"maxFT0CforZNACselection", -99999.0f, "max ft0c signal for minZNACsignal to work"}; Configurable minFV0Asignal{"minFV0Asignal", -999999.0f, "min fv0a signal"}; - Configurable maxFT0CforFV0Aselection{"maxFT0CforFV0Aselection", -99999.0f, "max ft0c signal for minFV0Asignal to work"}; Configurable minFDDAsignal{"minFDDAsignal", -999999.0f, "min fdda signal"}; + Configurable maxFT0CforZNACselection{"maxFT0CforZNACselection", -99999.0f, "max ft0c signal for minZNACsignal to work"}; + Configurable maxFT0CforFV0Aselection{"maxFT0CforFV0Aselection", -99999.0f, "max ft0c signal for minFV0Asignal to work"}; Configurable maxFT0CforFDDAselection{"maxFT0CforFDDAselection", -99999.0f, "max ft0c signal for minFDDAsignal to work"}; - } upcRejection; + Configurable fZPABBlower{"fZPABBlower", -2.f, "lower time limit ZPA (ns)"}; + Configurable fZPCBBlower{"fZPCBBlower", -2.f, "lower time limit ZPC (ns)"}; + Configurable fZPABBupper{"fZPABBupper", 2.f, "upper time limit ZPA (ns)"}; + Configurable fZPCBBupper{"fZPCBBupper", 2.f, "upper time limit ZPC (ns)"}; + } cfgFwd; // _______________________________________ // Scaling @@ -353,7 +357,7 @@ struct CentralityStudy { } } - if (doprocessBCs) { + if (doprocessBCs || doprocessBCsWithTime) { histos.add("hBCSelection", "hBCSelection", kTH1D, {{20, -0.5, 19.5f}}); histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(1, "All BCs"); histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(2, "Colliding BCs"); @@ -361,8 +365,9 @@ struct CentralityStudy { histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(4, "FV0OrA"); histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(5, "FT0PosZ"); histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(6, "upc rej"); - histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(7, "zdc rej"); - histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(8, "isFlangeEvent"); + histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(7, "znac time"); + histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(8, "zpac time"); + histos.get(HIST("hBCSelection"))->GetXaxis()->SetBinLabel(9, "isFlangeEvent"); histos.add("hFT0C_BCs", "hFT0C_BCs", kTH1D, {axisMultUltraFineFT0C}); histos.add("hFT0A_BCs", "hFT0A_BCs", kTH1D, {axisMultUltraFineFT0A}); @@ -370,7 +375,6 @@ struct CentralityStudy { histos.add("hFT0M_BCs", "hFT0M_BCs", kTH1D, {axisMultUltraFineFT0M}); histos.add("hFT0MOuterA_BCs", "hFT0MOuterA_BCs", kTH1D, {axisMultUltraFineFT0M}); histos.add("hFV0A_BCs", "hFV0A_BCs", kTH1D, {axisMultUltraFineFV0A}); - histos.add("hInteractionRate_BCs", "hInteractionRate_BCs", kTH1D, {axisInteractionRate}); histos.add("hFV0AT0C_BCs", "hFV0AT0C_BCs", kTH1D, {axisMultUltraFineFV0AT0C}); histos.add("hScaledFT0M_BCs", "hScaledFT0M_BCs", kTH1D, {axisMultUltraFineScaledFT0M}); @@ -813,17 +817,17 @@ struct CentralityStudy { } if (evsel.rejectUpc) { - if (collision.multFT0C() < upcRejection.maxFT0CforZNACselection && - collision.multZNA() < upcRejection.minZNACsignal && - collision.multZNC() < upcRejection.minZNACsignal) { + if (collision.multFT0C() < cfgFwd.maxFT0CforZNACselection && + collision.multZNA() < cfgFwd.minZNACsignal && + collision.multZNC() < cfgFwd.minZNACsignal) { return; } - if (collision.multFT0C() < upcRejection.maxFT0CforFV0Aselection && - collision.multFV0A() < upcRejection.minFV0Asignal) { + if (collision.multFT0C() < cfgFwd.maxFT0CforFV0Aselection && + collision.multFV0A() < cfgFwd.minFV0Asignal) { return; } - if (collision.multFT0C() < upcRejection.maxFT0CforFDDAselection && - collision.multFDDA() < upcRejection.minFDDAsignal) { + if (collision.multFT0C() < cfgFwd.maxFT0CforFDDAselection && + collision.multFDDA() < cfgFwd.minFDDAsignal) { return; } } @@ -1124,17 +1128,17 @@ struct CentralityStudy { } if (bcsel.rejectUpc) { - if (bc.multFT0C() < upcRejection.maxFT0CforZNACselection && - bc.multZNA() < upcRejection.minZNACsignal && - bc.multZNC() < upcRejection.minZNACsignal) { + if (bc.multFT0C() < cfgFwd.maxFT0CforZNACselection && + bc.multZNA() < cfgFwd.minZNACsignal && + bc.multZNC() < cfgFwd.minZNACsignal) { return false; } - if (bc.multFT0C() < upcRejection.maxFT0CforFV0Aselection && - bc.multFV0A() < upcRejection.minFV0Asignal) { + if (bc.multFT0C() < cfgFwd.maxFT0CforFV0Aselection && + bc.multFV0A() < cfgFwd.minFV0Asignal) { return false; } - if (bc.multFT0C() < upcRejection.maxFT0CforFDDAselection && - bc.multFDDA() < upcRejection.minFDDAsignal) { + if (bc.multFT0C() < cfgFwd.maxFT0CforFDDAselection && + bc.multFDDA() < cfgFwd.minFDDAsignal) { return false; } } @@ -1151,6 +1155,18 @@ struct CentralityStudy { histos.fill(HIST("hBCSelection"), 6); // znac time } + if constexpr (requires { bc.timeZPA(); }) { + const bool kIsBBZPA = bc.timeZPA() > cfgFwd.fZPABBlower && bc.timeZPA() < cfgFwd.fZPABBupper; + const bool kIsBBZPC = bc.timeZPC() > cfgFwd.fZPCBBlower && bc.timeZPC() < cfgFwd.fZPCBBupper; + if (bcsel.rejectZPAC && !(kIsBBZPA && kIsBBZPC)) { + return false; + } + } + + if (fillHistograms) { + histos.fill(HIST("hBCSelection"), 7); // zpac time + } + if (bcsel.rejectIsFlangeEvent) { constexpr int IsFlangeEventId = 7; std::bitset<8> ft0TriggerMask = bc.multT0triggerBits(); @@ -1160,13 +1176,14 @@ struct CentralityStudy { } if (fillHistograms) { - histos.fill(HIST("hBCSelection"), 7); // isFlangeEvent + histos.fill(HIST("hBCSelection"), 8); // isFlangeEvent } return true; } - void processBCs(soa::Join const& multbcs, soa::Join const&) + template + void genericProcessBCs(const TBunchCrossing& multbcs) { // process BCs, calculate FT0C distribution for (const auto& multbc : multbcs) { @@ -1183,10 +1200,6 @@ struct CentralityStudy { histos.fill(HIST("hFV0A_BCs"), multbc.multFV0A() * scale.factorFV0A); histos.fill(HIST("hFV0AT0C_BCs"), (multbc.multFV0A() + multbc.multFT0C()) * scale.factorFV0AT0C); - const uint64_t bcTimestamp = multbc.timestamp(); - const float interactionRate = mRateFetcher.fetch(ccdb.service, bcTimestamp, mRunNumber, ccdbSettings.irSource.value, ccdbSettings.irCrashOnNull) / 1000.; // kHz - histos.fill(HIST("hInteractionRate_BCs"), interactionRate); - if (studies.do2DPlots) { histos.fill(HIST("hFT0AVsFT0C_BCs"), multbc.multFT0C() * scale.factorFT0C, multbc.multFT0A() * scale.factorFT0A); histos.fill(HIST("hFV0AVsFT0C_BCs"), multbc.multFT0C() * scale.factorFT0C, multbc.multFV0A() * scale.factorFV0A); @@ -1204,7 +1217,7 @@ struct CentralityStudy { } if (multbc.has_ft0Mult()) { - auto multco = multbc.ft0Mult_as>(); + auto multco = multbc.template ft0Mult_as>(); if (multbc.multFT0PosZValid()) { histos.fill(HIST("hVertexZ_BCvsCO"), multco.multPVz(), multbc.multFT0PosZ()); } @@ -1224,11 +1237,22 @@ struct CentralityStudy { } } + void processBCs(soa::Join const& multbcs, soa::Join const&) + { + genericProcessBCs(multbcs); + } + + void processBCsWithTime(soa::Join const& multbcs, soa::Join const&) + { + genericProcessBCs(multbcs); + } + PROCESS_SWITCH(CentralityStudy, processCollisions, "per-collision analysis", false); PROCESS_SWITCH(CentralityStudy, processCollisionsWithResolutionStudy, "per-collision analysis, with reso study", false); PROCESS_SWITCH(CentralityStudy, processCollisionsWithCentrality, "per-collision analysis", true); PROCESS_SWITCH(CentralityStudy, processCollisionsWithCentralityWithNeighbours, "per-collision analysis", false); PROCESS_SWITCH(CentralityStudy, processBCs, "per-BC analysis", true); + PROCESS_SWITCH(CentralityStudy, processBCsWithTime, "per-BC analysis with extra detector information", false); }; WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)