From c9c8f8f63b274f561dc066a5751916289c25585f Mon Sep 17 00:00:00 2001 From: Ella Taylor Date: Thu, 18 Jun 2026 15:53:15 +0200 Subject: [PATCH 1/4] Change headers for lumi --- Detectors/CTP/CMakeLists.txt | 2 + Detectors/CTP/workflowLumi/CMakeLists.txt | 28 ++ .../include/CTPWorkflowLumi/RawDecoderSpec.h | 100 +++++++ .../CTP/workflowLumi/src/RawDecoderSpec.cxx | 275 ++++++++++++++++++ .../workflowLumi/src/ctp-raw-decoder-lumi.cxx | 56 ++++ 5 files changed, 461 insertions(+) create mode 100644 Detectors/CTP/workflowLumi/CMakeLists.txt create mode 100644 Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h create mode 100644 Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx create mode 100644 Detectors/CTP/workflowLumi/src/ctp-raw-decoder-lumi.cxx diff --git a/Detectors/CTP/CMakeLists.txt b/Detectors/CTP/CMakeLists.txt index e4fffe22e8814..d67b8797b527c 100644 --- a/Detectors/CTP/CMakeLists.txt +++ b/Detectors/CTP/CMakeLists.txt @@ -14,4 +14,6 @@ add_subdirectory(reconstruction) add_subdirectory(workflow) add_subdirectory(workflowIO) add_subdirectory(workflowScalers) +add_subdirectory(workflowLumi) add_subdirectory(macro) + diff --git a/Detectors/CTP/workflowLumi/CMakeLists.txt b/Detectors/CTP/workflowLumi/CMakeLists.txt new file mode 100644 index 0000000000000..52e57cc3e9bfd --- /dev/null +++ b/Detectors/CTP/workflowLumi/CMakeLists.txt @@ -0,0 +1,28 @@ +# 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. + +o2_add_library(CTPWorkflowLumi + SOURCES src/RawDecoderSpec.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::DataFormatsCTP + O2::DPLUtils + O2::DetectorsRaw + O2::Algorithm + O2::CTPReconstruction + O2::CTPWorkflowIO) +o2_add_executable(lumi-workflow + COMPONENT_NAME ctp + SOURCES src/ctp-raw-decoder-lumi.cxx + PUBLIC_LINK_LIBRARIES O2::Algorithm + O2::CTPWorkflowLumi) + + + diff --git a/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h b/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h new file mode 100644 index 0000000000000..3198e5c33e219 --- /dev/null +++ b/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h @@ -0,0 +1,100 @@ +// 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 O2_CTP_RAWDECODER_H +#define O2_CTP_RAWDECODER_H + +#include +#include +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" +#include "DataFormatsCTP/Digits.h" +#include "DataFormatsCTP/LumiInfo.h" +#include "CTPReconstruction/RawDataDecoder.h" + +namespace o2 +{ +namespace ctp +{ +namespace reco_workflow +{ + +/// \class RawDecoderSpec +/// \brief Coverter task for Raw data to CTP digits +/// \author Roman Lietava from CPV example +/// +class RawDecoderSpec : public framework::Task +{ + public: + /// \brief Constructor + /// \param propagateMC If true the MCTruthContainer is propagated to the output + RawDecoderSpec(bool digits, bool lumi) : mDoDigits(digits), mDoLumi(lumi) {} + /// \brief Destructor + ~RawDecoderSpec() override = default; + /// \brief Initializing the RawDecoderSpec + /// \param ctx Init context + void init(framework::InitContext& ctx) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + /// \brief Run conversion of raw data to cells + /// \param ctx Processing context + /// + /// The following branches are linked: + /// Input RawData: {"ROUT", "RAWDATA", 0, Lifetime::Timeframe} + /// Output HW errors: {"CTP", "RAWHWERRORS", 0, Lifetime::Timeframe} -later + void run(framework::ProcessingContext& ctx) final; + void updateTimeDependentParams(framework::ProcessingContext& pc); + + protected: + private: + // for digits + bool mDoDigits = true; + o2::pmr::vector mOutputDigits; + int mMaxInputSize = 0; + bool mMaxInputSizeFatal = 0; + // for lumi + bool mDoLumi = true; + // + LumiInfo mOutputLumiInfo; + bool mVerbose = false; + uint64_t mCountsT = 0; + uint64_t mCountsV = 0; + uint32_t mNTFToIntegrate = 1; + uint32_t mNHBIntegratedT = 0; + uint32_t mNHBIntegratedV = 0; + bool mDecodeinputs = 0; + std::deque mHistoryT; + std::deque mHistoryV; + RawDataDecoder mDecoder; + // Errors + int mLostDueToShiftInps = 0; + int mErrorIR = 0; + int mErrorTCR = 0; + int mIRRejected = 0; + int mTCRRejected = 0; + std::array mClsEA{}; + std::array mClsEB{}; // from inputs + std::array mClsA{}; + std::array mClsB{}; // from inputs + bool mCheckConsistency = false; +}; + +/// \brief Creating DataProcessorSpec for the CTP +/// +o2::framework::DataProcessorSpec getRawDecoderSpec(bool askSTFDist, bool digits, bool lumi); + +} // namespace reco_workflow + +} // namespace ctp + +} // namespace o2 + +#endif diff --git a/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx b/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx new file mode 100644 index 0000000000000..ecd6efac0a615 --- /dev/null +++ b/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx @@ -0,0 +1,275 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include "Framework/InputRecordWalker.h" +#include "Framework/DataRefUtils.h" +#include "Framework/ConfigParamRegistry.h" +#include "DetectorsRaw/RDHUtils.h" +#include "CTPWorkflowLumi/RawDecoderSpec.h" +#include "CommonUtils/VerbosityConfig.h" +#include "Framework/InputRecord.h" +#include "DataFormatsCTP/TriggerOffsetsParam.h" +#include "Framework/CCDBParamSpec.h" +#include "DataFormatsCTP/Configuration.h" + +using namespace o2::ctp::reco_workflow; + +void RawDecoderSpec::init(framework::InitContext& ctx) +{ + mCheckConsistency = ctx.options().get("check-consistency"); + mDecoder.setCheckConsistency(mCheckConsistency); + mDecodeinputs = ctx.options().get("ctpinputs-decoding"); + mDecoder.setDecodeInps(mDecodeinputs); + mNTFToIntegrate = ctx.options().get("ntf-to-average"); + mVerbose = ctx.options().get("use-verbose-mode"); + int maxerrors = ctx.options().get("print-errors-num"); + mDecoder.setVerbose(mVerbose); + mDecoder.setDoLumi(mDoLumi); + mDecoder.setDoDigits(mDoDigits); + mDecoder.setMAXErrors(maxerrors); + std::string lumiinp1 = ctx.options().get("lumi-inp1"); + std::string lumiinp2 = ctx.options().get("lumi-inp2"); + int inp1 = mDecoder.setLumiInp(1, lumiinp1); + int inp2 = mDecoder.setLumiInp(2, lumiinp2); + mOutputLumiInfo.inp1 = inp1; + mOutputLumiInfo.inp2 = inp2; + mMaxInputSize = ctx.options().get("max-input-size"); + mMaxInputSizeFatal = ctx.options().get("max-input-size-fatal"); + LOG(info) << "CTP reco init done. Inputs decoding here:" << mDecodeinputs << " DoLumi:" << mDoLumi << " DoDigits:" << mDoDigits << " NTF:" << mNTFToIntegrate << " Lumi inputs:" << lumiinp1 << ":" << inp1 << " " << lumiinp2 << ":" << inp2 << " Max errors:" << maxerrors << " Max input size:" << mMaxInputSize << " MaxInputSizeFatal:" << mMaxInputSizeFatal << " CheckConsistency:" << mCheckConsistency; + // mOutputLumiInfo.printInputs(); +} +void RawDecoderSpec::endOfStream(framework::EndOfStreamContext& ec) +{ + auto clsEA = mDecoder.getClassErrorsA(); + auto clsEB = mDecoder.getClassErrorsB(); + auto cntCA = mDecoder.getClassCountersA(); + auto cntCB = mDecoder.getClassCountersB(); + int totClasses = 0; + for (int i = 0; i < o2::ctp::CTP_NCLASSES; i++) { + mClsEA[i] += clsEA[i]; + mClsEB[i] += clsEB[i]; + mClsA[i] += cntCA[i]; + mClsB[i] += cntCB[i]; + totClasses += cntCA[i]; + } + auto& TFOrbits = mDecoder.getTFOrbits(); + std::sort(TFOrbits.begin(), TFOrbits.end()); + size_t l = TFOrbits.size(); + uint32_t o0 = 0; + if (l) { + o0 = TFOrbits[0]; + } + int nmiss = 0; + int nprt = 0; + std::cout << "Missing orbits:"; + for (int i = 1; i < l; i++) { + if ((TFOrbits[i] - o0) > 0x20) { + if (nprt < 20) { + std::cout << " " << o0 << "-" << TFOrbits[i]; + } + nmiss += (TFOrbits[i] - o0) / 0x20; + nprt++; + } + o0 = TFOrbits[i]; + } + std::cout << std::endl; + LOG(info) << "Number of non continous TF:" << nmiss << std::endl; + LOG(info) << "Lost in shiftInputs:" << mLostDueToShiftInps; + LOG(info) << "Lost in addDigit Inputs:" << mIRRejected << " Classes:" << mTCRRejected; + if (mErrorIR || mErrorTCR) { + LOG(error) << "# of IR errors:" << mErrorIR << " TCR errors:" << mErrorTCR << std::endl; + } + if (mCheckConsistency) { + LOG(info) << "Lost due to the shift Consistency Checker:" << mDecoder.getLostDueToShiftCls(); + LOG(info) << "Total classes:" << totClasses; + auto ctpcfg = mDecoder.getCTPConfig(); + for (int i = 0; i < o2::ctp::CTP_NCLASSES; i++) { + std::string name = ctpcfg.getClassNameFromIndex(i); + if (mClsEA[i]) { + LOG(error) << " Class without inputs:"; + } + LOG(important) << "CLASS:" << name << ":" << i << " Cls=>Inp:" << mClsA[i] << " Inp=>Cls:" << mClsB[i] << " ErrorsCls=>Inps:" << mClsEA[i] << " MissingInps=>Cls:" << mClsEB[i]; + } + } +} +void RawDecoderSpec::run(framework::ProcessingContext& ctx) +{ + updateTimeDependentParams(ctx); + mOutputDigits.clear(); + std::map digits; + using InputSpec = o2::framework::InputSpec; + using ConcreteDataTypeMatcher = o2::framework::ConcreteDataTypeMatcher; + using Lifetime = o2::framework::Lifetime; + // setUpDummyLink + auto& inputs = ctx.inputs(); + auto dummyOutput = [&ctx, this]() { + if (this->mDoDigits) { + ctx.outputs().snapshot(o2::framework::Output{"CTP", "DIGITS", 0}, this->mOutputDigits); + } + if (this->mDoLumi) { + ctx.outputs().snapshot(o2::framework::Output{"CTP", "LUMI", 0}, this->mOutputLumiInfo); + } + }; + // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" + // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow + { + static size_t contDeadBeef = 0; // number of times 0xDEADBEEF was seen continuously + std::vector dummy{InputSpec{"dummy", o2::framework::ConcreteDataMatcher{"CTP", "RAWDATA", 0xDEADBEEF}}}; + for (const auto& ref : o2::framework::InputRecordWalker(inputs, dummy)) { + const auto dh = o2::framework::DataRefUtils::getHeader(ref); + auto payloadSize = o2::framework::DataRefUtils::getPayloadSize(ref); + if (payloadSize == 0) { + auto maxWarn = o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef; + if (++contDeadBeef <= maxWarn) { + LOGP(alarm, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF{}", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, payloadSize, + contDeadBeef == maxWarn ? fmt::format(". {} such inputs in row received, stopping reporting", contDeadBeef) : ""); + } + dummyOutput(); + return; + } + } + contDeadBeef = 0; // if good data, reset the counter + } + // + std::vector lumiPointsHBF1; + std::vector filter{InputSpec{"filter", ConcreteDataTypeMatcher{"CTP", "RAWDATA"}, Lifetime::Timeframe}}; + bool fatal_flag = 0; + if (mMaxInputSize > 0) { + size_t payloadSize = 0; + for (const auto& ref : o2::framework::InputRecordWalker(inputs, filter)) { + const auto dh = o2::framework::DataRefUtils::getHeader(ref); + payloadSize += o2::framework::DataRefUtils::getPayloadSize(ref); + } + if (payloadSize > (size_t)mMaxInputSize) { + if (mMaxInputSizeFatal) { + fatal_flag = 1; + LOG(error) << "Input data size bigger than threshold: " << mMaxInputSize << " < " << payloadSize << " decoding TF and exiting."; + // LOG(fatal) << "Input data size:" << payloadSize; - fatal issued in decoder + } else { + LOG(error) << "Input data size:" << payloadSize << " sending dummy output"; + dummyOutput(); + return; + } + } + } + int ret = 0; + if (fatal_flag) { + ret = mDecoder.decodeRawFatal(inputs, filter); + } else { + ret = mDecoder.decodeRaw(inputs, filter, mOutputDigits, lumiPointsHBF1); + } + if (ret == 1) { + dummyOutput(); + return; + } + if (mDoDigits) { + LOG(info) << "[CTPRawToDigitConverter - run] Writing " << mOutputDigits.size() << " digits. IR rejected:" << mDecoder.getIRRejected() << " TCR rejected:" << mDecoder.getTCRRejected(); + ctx.outputs().snapshot(o2::framework::Output{"CTP", "DIGITS", 0}, mOutputDigits); + mLostDueToShiftInps += mDecoder.getLostDueToShiftInp(); + mErrorIR += mDecoder.getErrorIR(); + mErrorTCR += mDecoder.getErrorTCR(); + mIRRejected += mDecoder.getIRRejected(); + mTCRRejected += mDecoder.getTCRRejected(); + } + if (mDoLumi) { + uint32_t tfCountsT = 0; + uint32_t tfCountsV = 0; + for (auto const& lp : lumiPointsHBF1) { + tfCountsT += lp.counts; + tfCountsV += lp.countsFV0; + } + // LOG(info) << "Lumi rate:" << tfCounts/(128.*88e-6); + // FT0 + mHistoryT.push_back(tfCountsT); + mCountsT += tfCountsT; + if (mHistoryT.size() <= mNTFToIntegrate) { + mNHBIntegratedT += lumiPointsHBF1.size(); + } else { + mCountsT -= mHistoryT.front(); + mHistoryT.pop_front(); + } + // FV0 + mHistoryV.push_back(tfCountsV); + mCountsV += tfCountsV; + if (mHistoryV.size() <= mNTFToIntegrate) { + mNHBIntegratedV += lumiPointsHBF1.size(); + } else { + mCountsV -= mHistoryV.front(); + mHistoryV.pop_front(); + } + // + if (mNHBIntegratedT || mNHBIntegratedV) { + mOutputLumiInfo.orbit = lumiPointsHBF1[0].orbit; + } + mOutputLumiInfo.counts = mCountsT; + + mOutputLumiInfo.countsFV0 = mCountsV; + mOutputLumiInfo.nHBFCounted = mNHBIntegratedT; + mOutputLumiInfo.nHBFCountedFV0 = mNHBIntegratedV; + if (mVerbose) { + mOutputLumiInfo.printInputs(); + LOGP(info, "Orbit {}: {}/{} counts inp1/inp2 in {}/{} HBFs -> lumi_inp1 = {:.3e}+-{:.3e} lumi_inp2 = {:.3e}+-{:.3e}", mOutputLumiInfo.orbit, mCountsT, mCountsV, mNHBIntegratedT, mNHBIntegratedV, mOutputLumiInfo.getLumi(), mOutputLumiInfo.getLumiError(), mOutputLumiInfo.getLumiFV0(), mOutputLumiInfo.getLumiFV0Error()); + } + ctx.outputs().snapshot(o2::framework::Output{"CTP", "LUMI", 0}, mOutputLumiInfo); + } +} +o2::framework::DataProcessorSpec o2::ctp::reco_workflow::getRawDecoderSpec(bool askDISTSTF, bool digits, bool lumi) +{ + if (!digits && !lumi) { + throw std::runtime_error("all outputs were disabled"); + } + std::vector inputs; + inputs.emplace_back("TF", o2::framework::ConcreteDataTypeMatcher{"CTP", "RAWDATA"}, o2::framework::Lifetime::Timeframe); + if (askDISTSTF) { + inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe); + } + + std::vector outputs; + inputs.emplace_back("ctpconfig", "CTP", "CTPCONFIG", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("CTP/Config/Config", 1)); + inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("CTP/Config/TriggerOffsets")); + if (digits) { + outputs.emplace_back("CTP", "DIGITS", 0, o2::framework::Lifetime::Timeframe); + } + if (lumi) { + outputs.emplace_back("CTP", "LUMI", 0, o2::framework::Lifetime::Timeframe); + } + return o2::framework::DataProcessorSpec{ + "ctp-raw-decoder", + inputs, + outputs, + o2::framework::AlgorithmSpec{o2::framework::adaptFromTask(digits, lumi)}, + o2::framework::Options{ + {"ntf-to-average", o2::framework::VariantType::Int, 90, {"Time interval for averaging luminosity in units of TF"}}, + {"print-errors-num", o2::framework::VariantType::Int, 3, {"Max number of errors to print"}}, + {"lumi-inp1", o2::framework::VariantType::String, "TVX", {"The first input used for online lumi. Name in capital."}}, + {"lumi-inp2", o2::framework::VariantType::String, "VBA", {"The second input used for online lumi. Name in capital."}}, + {"use-verbose-mode", o2::framework::VariantType::Bool, false, {"Verbose logging"}}, + {"max-input-size", o2::framework::VariantType::Int, 0, {"Do not process input if bigger than max size, 0 - do not check"}}, + {"max-input-size-fatal", o2::framework::VariantType::Bool, false, {"If true issue fatal error otherwise error only"}}, + {"check-consistency", o2::framework::VariantType::Bool, false, {"If true checks digits consistency using ctp config"}}, + {"ctpinputs-decoding", o2::framework::VariantType::Bool, false, {"Inputs alignment: true - raw decoder - has to be compatible with CTF decoder: allowed options: 10,01,00"}}}}; +} +void RawDecoderSpec::updateTimeDependentParams(framework::ProcessingContext& pc) +{ + if (pc.services().get().globalRunNumberChanged) { + pc.inputs().get("trigoffset"); + const auto& trigOffsParam = o2::ctp::TriggerOffsetsParam::Instance(); + LOG(info) << "updateing TroggerOffsetsParam: inputs L0_L1:" << trigOffsParam.L0_L1 << " classes L0_L1:" << trigOffsParam.L0_L1_classes; + const auto ctpcfg = pc.inputs().get("ctpconfig"); + if (ctpcfg != nullptr) { + mDecoder.setCTPConfig(*ctpcfg); + LOG(info) << "ctpconfig for run done:" << mDecoder.getCTPConfig().getRunNumber(); + } + } +} diff --git a/Detectors/CTP/workflowLumi/src/ctp-raw-decoder-lumi.cxx b/Detectors/CTP/workflowLumi/src/ctp-raw-decoder-lumi.cxx new file mode 100644 index 0000000000000..47ec132578661 --- /dev/null +++ b/Detectors/CTP/workflowLumi/src/ctp-raw-decoder-lumi.cxx @@ -0,0 +1,56 @@ +// 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. + +/// @file ctp-reco-workflow.cxx +/// @author RL from CPV example +/// @brief Basic DPL workflow for CTP reconstruction starting from digits +#include "Framework/WorkflowSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/CallbacksPolicy.h" + +#include +#include +#include + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + std::vector options{ + {"ignore-dist-stf", o2::framework::VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, + {"no-lumi", o2::framework::VariantType::Bool, false, {"do not produce luminosity output"}}, + {"no-digits", o2::framework::VariantType::Bool, false, {"do not produce digits output"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writer"}}, + {"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" // the main driver +#include "CTPWorkflowLumi/RawDecoderSpec.h" +#include "CTPWorkflowIO/DigitWriterSpec.h" + +/// The workflow executable for the stand alone CTP reconstruction workflow +/// - digit and lumi reader +/// This function hooks up the the workflow specifications into the DPL driver. +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) +{ + o2::framework::WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); + + specs.emplace_back(o2::ctp::reco_workflow::getRawDecoderSpec(!cfgc.options().get("ignore-dist-stf"), + !cfgc.options().get("no-digits"), + !cfgc.options().get("no-lumi"))); + if (!cfgc.options().get("disable-root-output")) { + specs.emplace_back(o2::ctp::getDigitWriterSpec(!cfgc.options().get("no-lumi"))); + } + return specs; +} From e51c8e7b2d4012fdf68b37a0df08b492d11e2c05 Mon Sep 17 00:00:00 2001 From: Ella Taylor Date: Mon, 13 Jul 2026 14:33:39 +0200 Subject: [PATCH 2/4] Reads TF files and prints rate per BC --- Detectors/CTP/workflow/CMakeLists.txt | 3 +- .../include/CTPWorkflowLumi/RawDecoderSpec.h | 15 ++- .../CTP/workflowLumi/src/RawDecoderSpec.cxx | 103 +++++++++++++++++- 3 files changed, 118 insertions(+), 3 deletions(-) diff --git a/Detectors/CTP/workflow/CMakeLists.txt b/Detectors/CTP/workflow/CMakeLists.txt index 32d87b1cf2167..44ce5d2a20ae5 100644 --- a/Detectors/CTP/workflow/CMakeLists.txt +++ b/Detectors/CTP/workflow/CMakeLists.txt @@ -19,7 +19,8 @@ o2_add_library(CTPWorkflow O2::DetectorsRaw O2::Algorithm O2::CTPReconstruction - O2::CTPWorkflowIO) + O2::CTPWorkflowIO + O2::DataFormatsParameters) o2_add_executable(reco-workflow COMPONENT_NAME ctp SOURCES src/ctp-raw-decoder.cxx diff --git a/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h b/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h index 3198e5c33e219..2924f753e1d0d 100644 --- a/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h +++ b/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h @@ -52,7 +52,13 @@ class RawDecoderSpec : public framework::Task /// Output HW errors: {"CTP", "RAWHWERRORS", 0, Lifetime::Timeframe} -later void run(framework::ProcessingContext& ctx) final; void updateTimeDependentParams(framework::ProcessingContext& pc); - + /// \brief Compute per BC luminosity from the interaction counts from CTP digits + /// \param ctpdigits Vector of CTP digits to be processed + /// \return Array of luminosity values for each BC + std::pair, std::array> computeLumiPerBC(const o2::pmr::vector& ctpdigits); + /// \brief Integrate luminosity per BC over multiple time frames + /// \param perTF Array of luminosity values for each BC from a single time frame + void integrateLumi(const std::array& perTFInp1, const std::array& perTFInp2); protected: private: // for digits @@ -85,6 +91,13 @@ class RawDecoderSpec : public framework::Task std::array mClsA{}; std::array mClsB{}; // from inputs bool mCheckConsistency = false; + std::array mCountsPerBC1{}; + std::array mCountsPerBC2{}; + double totalTime = 0.0; + const double orbitsPerTF = 32; + const double tfTime = orbitsPerTF * o2::constants::lhc::LHCOrbitMUS * 1e-6; // total time in seconds for one timeframe + std::bitset<3564> mLHCBCs; + const double timeInterval = o2::constants::lhc::LHCOrbitMUS * 1e-6; // one HBF }; /// \brief Creating DataProcessorSpec for the CTP diff --git a/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx b/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx index ecd6efac0a615..5c34f3d19fed1 100644 --- a/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx +++ b/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx @@ -21,6 +21,8 @@ #include "DataFormatsCTP/TriggerOffsetsParam.h" #include "Framework/CCDBParamSpec.h" #include "DataFormatsCTP/Configuration.h" +#include "CommonConstants/LHCConstants.h" +#include using namespace o2::ctp::reco_workflow; @@ -181,6 +183,9 @@ void RawDecoderSpec::run(framework::ProcessingContext& ctx) mErrorTCR += mDecoder.getErrorTCR(); mIRRejected += mDecoder.getIRRejected(); mTCRRejected += mDecoder.getTCRRejected(); + // Luminosity per bunch crossing + const auto [countsPerBC1, countsPerBC2] = computeLumiPerBC(mOutputDigits); + integrateLumi(countsPerBC1, countsPerBC2); } if (mDoLumi) { uint32_t tfCountsT = 0; @@ -224,6 +229,89 @@ void RawDecoderSpec::run(framework::ProcessingContext& ctx) ctx.outputs().snapshot(o2::framework::Output{"CTP", "LUMI", 0}, mOutputLumiInfo); } } +// Function to compute luminosity per BC from the interaction counts from CTP digits +std::pair, std::array> RawDecoderSpec::computeLumiPerBC(const o2::pmr::vector& ctpdigits) +{ + int inp1 = mOutputLumiInfo.inp1; + int inp2 = mOutputLumiInfo.inp2; + + uint64_t inputMask1 = 1ull << (inp1 - 1); // TVX + uint64_t inputMask2 = 1ull << (inp2 - 1); // VBA + + double integratedRate = 0.0; + std::cout << "Lumi called" << std::endl; + + std::array countsPerBC1{}; + std::array countsPerBC2{}; + + for (const auto& digit : ctpdigits) { + uint64_t mask = digit.CTPInputMask.to_ullong(); + uint16_t bc = digit.intRecord.bc; + + if (bc < o2::constants::lhc::LHCMaxBunches) { + if (mask & inputMask1) { + countsPerBC1[bc] += 1.0; + integratedRate += 1.0; + // std::cout << "Orbit: " << std::dec << digit.intRecord.orbit << " Orbit: 0x" << std::hex << digit.intRecord.orbit << std::endl; + } + + if (mask & inputMask2) { + countsPerBC2[bc] += 1.0; + } + } + } + totalTime += tfTime; // Accumulate total time for all processed time frames + for (size_t bc = 0; bc < countsPerBC1.size(); ++bc) { + if (countsPerBC1[bc] > 0) { + // LOG(info) << " BC " << bc << ": " << lumiPerBC[bc]/totalTime; + } + } + // std::cout << "Integrated luminosity over all BCs: " << integratedRate/totalTime << std::endl; + return {countsPerBC1, countsPerBC2}; +} +// Accumulate luminosity per BC over multiple time frames +void RawDecoderSpec::integrateLumi(const std::array& perTFInp1, + const std::array& perTFInp2) +{ + + for (size_t bc = 0; bc < mCountsPerBC1.size(); ++bc) { + mCountsPerBC1[bc] += perTFInp1[bc]; + } + + for (size_t bc = 0; bc < mCountsPerBC2.size(); ++bc) { + mCountsPerBC2[bc] += perTFInp2[bc]; + } + + // Count number of filled BCs + size_t filledBCs = mLHCBCs.count(); + + for (size_t bc = 0; bc < mCountsPerBC1.size(); ++bc) { + if (mLHCBCs.test(bc)) { // Only print filled BCs + LOG(info) << " Filled BC " << bc + << ": Input1 Lumi: " << mCountsPerBC1[bc] / (totalTime * filledBCs) + << ", Input2 Lumi: " << mCountsPerBC2[bc] / (totalTime * filledBCs) + << "; Accumulated Counts Input1: " << mCountsPerBC1[bc] + << ", Input2: " << mCountsPerBC2[bc]; + } else if (mCountsPerBC1[bc] > 0) { // Only print non-zero luminosity + LOG(info) << " BC " << bc + << ": Input1 Lumi: " << mCountsPerBC1[bc] / (totalTime * filledBCs) + << ", Input2 Lumi: " << mCountsPerBC2[bc] / (totalTime * filledBCs) + << "; Accumulated Counts Input1: " << mCountsPerBC1[bc] + << ", Input2: " << mCountsPerBC2[bc]; + } + } + // Calculate and print the total integrated luminosity + int totalCountsInp1 = 0; + int totalCountsInp2 = 0; + for (const auto& count : mCountsPerBC1) { + totalCountsInp1 += count; + } + LOG(info) << "Total Integrated Luminosity Input 1: " << totalCountsInp1 / totalTime; + for (const auto& count : mCountsPerBC2) { + totalCountsInp2 += count; + } + LOG(info) << "Total Integrated Luminosity Input 2: " << totalCountsInp2 / totalTime; +} o2::framework::DataProcessorSpec o2::ctp::reco_workflow::getRawDecoderSpec(bool askDISTSTF, bool digits, bool lumi) { if (!digits && !lumi) { @@ -237,6 +325,7 @@ o2::framework::DataProcessorSpec o2::ctp::reco_workflow::getRawDecoderSpec(bool std::vector outputs; inputs.emplace_back("ctpconfig", "CTP", "CTPCONFIG", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("CTP/Config/Config", 1)); + inputs.emplace_back("grplhcif", "GLO", "GRPLHCIF", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("GLO/Config/GRPLHCIF")); inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("CTP/Config/TriggerOffsets")); if (digits) { outputs.emplace_back("CTP", "DIGITS", 0, o2::framework::Lifetime::Timeframe); @@ -245,7 +334,7 @@ o2::framework::DataProcessorSpec o2::ctp::reco_workflow::getRawDecoderSpec(bool outputs.emplace_back("CTP", "LUMI", 0, o2::framework::Lifetime::Timeframe); } return o2::framework::DataProcessorSpec{ - "ctp-raw-decoder", + "ctp-raw-decoder-lumi", inputs, outputs, o2::framework::AlgorithmSpec{o2::framework::adaptFromTask(digits, lumi)}, @@ -271,5 +360,17 @@ void RawDecoderSpec::updateTimeDependentParams(framework::ProcessingContext& pc) mDecoder.setCTPConfig(*ctpcfg); LOG(info) << "ctpconfig for run done:" << mDecoder.getCTPConfig().getRunNumber(); } + const auto grplhcif = pc.inputs().get("grplhcif"); + if (grplhcif != nullptr) { + LOG(info) << "GRPLHCIF injection scheme: " << grplhcif->getInjectionScheme(); + + // Get filled bunches + auto bfilling = grplhcif->getBunchFilling(); + std::vector bcs = bfilling.getFilledBCs(); + mLHCBCs.reset(); + for (auto const& bc : bcs) { + mLHCBCs.set(bc, 1); + } + } } } From c63fb6e7d094a5f092b914ee92e86505768b4d56 Mon Sep 17 00:00:00 2001 From: Ella Taylor Date: Fri, 21 Aug 2026 16:43:25 +0200 Subject: [PATCH 3/4] final lumi per BC --- .../include/CTPWorkflowLumi/RawDecoderSpec.h | 53 ++- .../CTP/workflowLumi/src/RawDecoderSpec.cxx | 333 ++++++++++++++---- 2 files changed, 311 insertions(+), 75 deletions(-) diff --git a/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h b/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h index 2924f753e1d0d..009bf01b27348 100644 --- a/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h +++ b/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h @@ -20,6 +20,7 @@ #include "DataFormatsCTP/Digits.h" #include "DataFormatsCTP/LumiInfo.h" #include "CTPReconstruction/RawDataDecoder.h" +#include "DataFormatsParameters/AggregatedRunInfo.h" namespace o2 { @@ -55,10 +56,16 @@ class RawDecoderSpec : public framework::Task /// \brief Compute per BC luminosity from the interaction counts from CTP digits /// \param ctpdigits Vector of CTP digits to be processed /// \return Array of luminosity values for each BC - std::pair, std::array> computeLumiPerBC(const o2::pmr::vector& ctpdigits); + // std::pair, std::array> + void computeLumiPerBC(const o2::pmr::vector& ctpdigits, uint32_t firstOrbit, uint32_t orbitsPerTF); /// \brief Integrate luminosity per BC over multiple time frames - /// \param perTF Array of luminosity values for each BC from a single time frame - void integrateLumi(const std::array& perTFInp1, const std::array& perTFInp2); + /// \param perInterval Array of luminosity values for each BC for a given time interval + void integrateLumi(const std::array& tfCounts1, const std::array& tfCounts2, int64_t unixTime, uint32_t nOrbitsThisTF); + void writeMassiLinePerBC(int bc, int64_t unixTime, double lumi, double lumiErr, double correctedRate, double correctedLumi, double mu); + void writeMassiLineLumi(int64_t unixTime, double lumi, double lumiErr); + int64_t unixTimeForOrbitStart(uint32_t orbit) const; + int yearFromUnixTime(int64_t unixTime) const; + void fetchRunInfo(int runNumber); protected: private: // for digits @@ -74,8 +81,14 @@ class RawDecoderSpec : public framework::Task uint64_t mCountsT = 0; uint64_t mCountsV = 0; uint32_t mNTFToIntegrate = 1; + uint32_t mNHBIntegrated = 0; uint32_t mNHBIntegratedT = 0; uint32_t mNHBIntegratedV = 0; + uint32_t mNHBToIntegrate = 1; + uint32_t mFirstOrbit = 0; + uint32_t mOrbitsInCurrentWindow = 0; + uint32_t mTFsInCurrentWindow = 0; + double mWindowStartTime = 0.0; bool mDecodeinputs = 0; std::deque mHistoryT; std::deque mHistoryV; @@ -94,10 +107,38 @@ class RawDecoderSpec : public framework::Task std::array mCountsPerBC1{}; std::array mCountsPerBC2{}; double totalTime = 0.0; - const double orbitsPerTF = 32; - const double tfTime = orbitsPerTF * o2::constants::lhc::LHCOrbitMUS * 1e-6; // total time in seconds for one timeframe + uint32_t mOrbitsPerTF = 0; + const double tfTime = mOrbitsPerTF * o2::constants::lhc::LHCOrbitMUS * 1e-6; // total time in seconds for one timeframe std::bitset<3564> mLHCBCs; - const double timeInterval = o2::constants::lhc::LHCOrbitMUS * 1e-6; // one HBF + static constexpr double orbitTime = o2::constants::lhc::LHCOrbitMUS * 1e-6; // one HBF + std::array mTotalCountsPerBC1{}; + std::array mTotalCountsPerBC2{}; + double mTotalElapsedTime = 0.0; + // Massi file output + std::string mFillNumber = "unknown"; + std::string mMassiOutDir; + int mMassiYear = 0; + double mOrbitResetTimeSec = 0.0; + bool mStableBeams = false; + std::map mMassiFiles; // one open file per RF bucket + o2::parameters::AggregatedRunInfo mRunInfo; + double mCrossSection = 1.0; + double mTFsInMin = 0.0; + uint32_t mPrevTFLastOrbit = 0; + bool mHavePrevTF = false; + int mRunStartTime = 0; + int mRunEndTime = 0; + struct PendingTF { + std::array countsPerBC1{}; + std::array countsPerBC2{}; + int64_t unixTimeStart; + uint32_t nOrbitsThisTF; + }; + std::map mPendingTFs; + uint32_t mReorderDepth = 5; + void flushReadyTFs(); + void flushAllPendingTFs(); + std::pair pileupCorrection(double rate) const; }; /// \brief Creating DataProcessorSpec for the CTP diff --git a/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx b/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx index 5c34f3d19fed1..2238c158facd7 100644 --- a/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx +++ b/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx @@ -33,6 +33,7 @@ void RawDecoderSpec::init(framework::InitContext& ctx) mDecodeinputs = ctx.options().get("ctpinputs-decoding"); mDecoder.setDecodeInps(mDecodeinputs); mNTFToIntegrate = ctx.options().get("ntf-to-average"); + LOG(info) << "Window size: " << mNTFToIntegrate << " TFs"; mVerbose = ctx.options().get("use-verbose-mode"); int maxerrors = ctx.options().get("print-errors-num"); mDecoder.setVerbose(mVerbose); @@ -48,6 +49,11 @@ void RawDecoderSpec::init(framework::InitContext& ctx) mMaxInputSize = ctx.options().get("max-input-size"); mMaxInputSizeFatal = ctx.options().get("max-input-size-fatal"); LOG(info) << "CTP reco init done. Inputs decoding here:" << mDecodeinputs << " DoLumi:" << mDoLumi << " DoDigits:" << mDoDigits << " NTF:" << mNTFToIntegrate << " Lumi inputs:" << lumiinp1 << ":" << inp1 << " " << lumiinp2 << ":" << inp2 << " Max errors:" << maxerrors << " Max input size:" << mMaxInputSize << " MaxInputSizeFatal:" << mMaxInputSizeFatal << " CheckConsistency:" << mCheckConsistency; + mMassiOutDir = ctx.options().get("massi-out-dir"); + LOG(info) << "Massi output dir:" << mMassiOutDir; + mCrossSection = ctx.options().get("cross-section"); + LOG(info) << "Cross section (ub): " << mCrossSection; + mReorderDepth = ctx.options().get("tf-reorder-depth"); // mOutputLumiInfo.printInputs(); } void RawDecoderSpec::endOfStream(framework::EndOfStreamContext& ec) @@ -103,6 +109,52 @@ void RawDecoderSpec::endOfStream(framework::EndOfStreamContext& ec) LOG(important) << "CLASS:" << name << ":" << i << " Cls=>Inp:" << mClsA[i] << " Inp=>Cls:" << mClsB[i] << " ErrorsCls=>Inps:" << mClsEA[i] << " MissingInps=>Cls:" << mClsEB[i]; } } + flushAllPendingTFs(); + if (mTFsInCurrentWindow > 0) { + double timeInterval = orbitTime * mOrbitsInCurrentWindow; + double totalLumi1 = 0.0; + double totalLumi2 = 0.0; + double totalLumiErr1 = 0.0; + double totalLumiErr2 = 0.0; + size_t filledBCs = mLHCBCs.count(); + for (size_t bc = 0; bc < mCountsPerBC1.size(); ++bc) { + if (mCountsPerBC1[bc] > 0) { + double rate1 = mCountsPerBC1[bc] / timeInterval; + double lumi1 = rate1 / mCrossSection; + double lumiErr1 = std::sqrt(mCountsPerBC1[bc]) / (timeInterval * mCrossSection); + auto [mu, correctedRate1] = pileupCorrection(rate1); + double correctedLumi1 = correctedRate1 / mCrossSection; + writeMassiLinePerBC(bc, mWindowStartTime, lumi1, lumiErr1, correctedLumi1, correctedRate1, mu); + } + if (mLHCBCs.test(bc)) { + totalLumi1 += mCountsPerBC1[bc] / (timeInterval * mCrossSection); + totalLumi2 += mCountsPerBC2[bc] / (timeInterval * mCrossSection); + totalLumiErr1 += std::sqrt(mCountsPerBC1[bc]) / (timeInterval * mCrossSection); + totalLumiErr2 += std::sqrt(mCountsPerBC2[bc]) / (timeInterval * mCrossSection); + writeMassiLineLumi(mWindowStartTime, totalLumi1, totalLumiErr1); + } + } + LOG(info) << "Flushed trailing partial window of " << mTFsInCurrentWindow << " TFs at end of stream"; + } + // Calculate and print total luminosity for given fill + double totalFillCountsInp1 = 0.0; + double totalFillCountsInp2 = 0.0; + for (const auto& count : mTotalCountsPerBC1) { + totalFillCountsInp1 += count; + } + for (const auto& count : mTotalCountsPerBC2) { + totalFillCountsInp2 += count; + } + // Estimate the total integrated luminosity for the fill in ub^-1 and the rate in Hz + double avgRate1 = totalFillCountsInp1 / mTotalElapsedTime; + double fillDurationSec = (mRunInfo.eor - mRunInfo.sor) / 1000.0; + double totalIntLumiInp1 = totalFillCountsInp1 / mCrossSection; + double estimatedTotalIntLumiInp1 = (avgRate1 / mCrossSection) * fillDurationSec; + LOG(info) << "Total Integrated Luminosity Input 1: " << totalIntLumiInp1 << " ub^-1" << " Rate (vis): " << avgRate1 << " Hz, Estimated Total Integrated Lumi: " << estimatedTotalIntLumiInp1 << " ub^-1"; + // Close files at end of stream + for (auto& [bucket, ofs] : mMassiFiles) { + ofs.close(); + } } void RawDecoderSpec::run(framework::ProcessingContext& ctx) { @@ -147,24 +199,47 @@ void RawDecoderSpec::run(framework::ProcessingContext& ctx) std::vector lumiPointsHBF1; std::vector filter{InputSpec{"filter", ConcreteDataTypeMatcher{"CTP", "RAWDATA"}, Lifetime::Timeframe}}; bool fatal_flag = 0; - if (mMaxInputSize > 0) { - size_t payloadSize = 0; - for (const auto& ref : o2::framework::InputRecordWalker(inputs, filter)) { - const auto dh = o2::framework::DataRefUtils::getHeader(ref); + size_t payloadSize = 0; + bool gotFirstOrbit = false; + + for (const auto& ref : o2::framework::InputRecordWalker(inputs, filter)) { + const auto dh = o2::framework::DataRefUtils::getHeader(ref); + if (!gotFirstOrbit) { + mFirstOrbit = dh->firstTForbit; + gotFirstOrbit = true; + if (mHavePrevTF) { + uint32_t expectedOrbit = mPrevTFLastOrbit; + if (mFirstOrbit != expectedOrbit) { + int64_t diff = static_cast(mFirstOrbit) - static_cast(mPrevTFLastOrbit); + if (diff < 0) { + LOG(warning) << "TF arrived out of order: previous TF ended at orbit " << mPrevTFLastOrbit << ", this TF starts at " << mFirstOrbit << " (orbit went backwards by " << diff << ")"; + } + else if (diff > 0) { + LOG(warning) << "Gap detected: previous TF ended at orbit " << expectedOrbit << ", this TF starts at " << mFirstOrbit << " (missing " << (mFirstOrbit - expectedOrbit) << " orbits)"; + } + } + } + } + mPrevTFLastOrbit = mFirstOrbit + mRunInfo.orbitsPerTF; + mHavePrevTF = true; + if (mMaxInputSize > 0) { payloadSize += o2::framework::DataRefUtils::getPayloadSize(ref); } - if (payloadSize > (size_t)mMaxInputSize) { - if (mMaxInputSizeFatal) { - fatal_flag = 1; - LOG(error) << "Input data size bigger than threshold: " << mMaxInputSize << " < " << payloadSize << " decoding TF and exiting."; - // LOG(fatal) << "Input data size:" << payloadSize; - fatal issued in decoder - } else { - LOG(error) << "Input data size:" << payloadSize << " sending dummy output"; - dummyOutput(); - return; - } + } + LOG(info) << "mFirstOrbit for this TF: " << mFirstOrbit << " gotFirstOrbit: " << gotFirstOrbit; + // if (payloadSize > (size_t)mMaxInputSize) { + if (mMaxInputSize > 0 && payloadSize > (size_t)mMaxInputSize) { + if (mMaxInputSizeFatal) { + fatal_flag = 1; + LOG(error) << "Input data size bigger than threshold: " << mMaxInputSize << " < " << payloadSize << " decoding TF and exiting."; + // LOG(fatal) << "Input data size:" << payloadSize; - fatal issued in decoder + } else { + LOG(error) << "Input data size:" << payloadSize << " sending dummy output"; + dummyOutput(); + return; } } + int ret = 0; if (fatal_flag) { ret = mDecoder.decodeRawFatal(inputs, filter); @@ -184,8 +259,7 @@ void RawDecoderSpec::run(framework::ProcessingContext& ctx) mIRRejected += mDecoder.getIRRejected(); mTCRRejected += mDecoder.getTCRRejected(); // Luminosity per bunch crossing - const auto [countsPerBC1, countsPerBC2] = computeLumiPerBC(mOutputDigits); - integrateLumi(countsPerBC1, countsPerBC2); + computeLumiPerBC(mOutputDigits, mFirstOrbit, static_cast(mRunInfo.orbitsPerTF)); } if (mDoLumi) { uint32_t tfCountsT = 0; @@ -230,7 +304,8 @@ void RawDecoderSpec::run(framework::ProcessingContext& ctx) } } // Function to compute luminosity per BC from the interaction counts from CTP digits -std::pair, std::array> RawDecoderSpec::computeLumiPerBC(const o2::pmr::vector& ctpdigits) +// std::pair, std::array> +void RawDecoderSpec::computeLumiPerBC(const o2::pmr::vector& ctpdigits, uint32_t firstOrbit, uint32_t orbitsPerTF) { int inp1 = mOutputLumiInfo.inp1; int inp2 = mOutputLumiInfo.inp2; @@ -238,79 +313,189 @@ std::pair, std::array countsPerBC1{}; - std::array countsPerBC2{}; + std::array tfCountsPerBC1{}; + std::array tfCountsPerBC2{}; for (const auto& digit : ctpdigits) { + uint32_t orbit = digit.intRecord.orbit; + if (orbit < firstOrbit || orbit >= firstOrbit + orbitsPerTF) { + LOG(warning) << "Digit orbit " << orbit << " outside expected TF range [" << firstOrbit << ", " << (firstOrbit + orbitsPerTF) << ") - skipping"; + continue; + } uint64_t mask = digit.CTPInputMask.to_ullong(); uint16_t bc = digit.intRecord.bc; - if (bc < o2::constants::lhc::LHCMaxBunches) { - if (mask & inputMask1) { - countsPerBC1[bc] += 1.0; - integratedRate += 1.0; - // std::cout << "Orbit: " << std::dec << digit.intRecord.orbit << " Orbit: 0x" << std::hex << digit.intRecord.orbit << std::endl; - } - - if (mask & inputMask2) { - countsPerBC2[bc] += 1.0; - } + if (mask & inputMask1) tfCountsPerBC1[bc] += 1.0; + if (mask & inputMask2) tfCountsPerBC2[bc] += 1.0; } } - totalTime += tfTime; // Accumulate total time for all processed time frames - for (size_t bc = 0; bc < countsPerBC1.size(); ++bc) { - if (countsPerBC1[bc] > 0) { - // LOG(info) << " BC " << bc << ": " << lumiPerBC[bc]/totalTime; + int64_t unixTimeStart = unixTimeForOrbitStart(firstOrbit); + if (mPendingTFs.count(firstOrbit)) { + LOG(warning) << "Duplicate firstOrbit " << firstOrbit << " received - overwriting pending entry"; + } + mPendingTFs[firstOrbit] = PendingTF{tfCountsPerBC1, tfCountsPerBC2, unixTimeStart, orbitsPerTF}; + if (!mPendingTFs.empty()) { + uint32_t smallestPending = mPendingTFs.begin()->first; + if (firstOrbit < smallestPending) { + LOG(warning) << "Late TF: firstOrbit=" << firstOrbit << " arrived after smallest pending=" << smallestPending; } } - // std::cout << "Integrated luminosity over all BCs: " << integratedRate/totalTime << std::endl; - return {countsPerBC1, countsPerBC2}; + flushReadyTFs(); + //integrateLumi(tfCountsPerBC1, tfCountsPerBC2, unixTimeStart, orbitsPerTF); } // Accumulate luminosity per BC over multiple time frames -void RawDecoderSpec::integrateLumi(const std::array& perTFInp1, - const std::array& perTFInp2) +void RawDecoderSpec::integrateLumi(const std::array& tfCounts1, const std::array& tfCounts2, int64_t unixTimeStart, uint32_t nOrbitsThisTF) { + if (mTFsInCurrentWindow == 0) { + mWindowStartTime = unixTimeStart; + } for (size_t bc = 0; bc < mCountsPerBC1.size(); ++bc) { - mCountsPerBC1[bc] += perTFInp1[bc]; + mCountsPerBC1[bc] += tfCounts1[bc]; + mTotalCountsPerBC1[bc] += tfCounts1[bc]; } - for (size_t bc = 0; bc < mCountsPerBC2.size(); ++bc) { - mCountsPerBC2[bc] += perTFInp2[bc]; + mCountsPerBC2[bc] += tfCounts2[bc]; + mTotalCountsPerBC2[bc] += tfCounts2[bc]; + } + mTotalElapsedTime += nOrbitsThisTF * orbitTime; + mOrbitsInCurrentWindow += nOrbitsThisTF; + ++mTFsInCurrentWindow; + + if (mTFsInCurrentWindow < mNTFToIntegrate) { + return; // Window not yet filled } - // Count number of filled BCs - size_t filledBCs = mLHCBCs.count(); + if (mTFsInCurrentWindow >= mNTFToIntegrate) { + double timeInterval = orbitTime * mOrbitsInCurrentWindow; // Total time in seconds for the current window + // Count number of filled BCs + size_t filledBCs = mLHCBCs.count(); + // Total lumi over filled BCs for this window + double totalLumi1 = 0.0; + double totalLumi2 = 0.0; + double totalLumiErr1 = 0.0; + double totalLumiErr2 = 0.0; + for (size_t bc = 0; bc < mCountsPerBC1.size(); ++bc) { // Luminosity per BC + if (mCountsPerBC1[bc] > 0 || mCountsPerBC2[bc] > 0) { + double rate1 = mCountsPerBC1[bc] / timeInterval; + double rate2 = mCountsPerBC2[bc] / timeInterval; + double lumi1 = rate1 / mCrossSection; + double lumi2 = rate2 / mCrossSection; + double lumiErr1 = std::sqrt(mCountsPerBC1[bc]) / (timeInterval * mCrossSection); + double lumiErr2 = std::sqrt(mCountsPerBC2[bc]) / (timeInterval * mCrossSection); + auto [mu, correctedRate1] = pileupCorrection(rate1); + double correctedLumi1 = correctedRate1 / mCrossSection; + if (mCountsPerBC1[bc] > 0) { + // LOG(info) << "BC: " << bc + 1 << " Rate: " << rate1 << " Corrected Rate: " << correctedRate1 << " mu: " << mu; + writeMassiLinePerBC(bc, mWindowStartTime, lumi1, lumiErr1, correctedRate1, correctedLumi1, mu); + } + } - for (size_t bc = 0; bc < mCountsPerBC1.size(); ++bc) { - if (mLHCBCs.test(bc)) { // Only print filled BCs - LOG(info) << " Filled BC " << bc - << ": Input1 Lumi: " << mCountsPerBC1[bc] / (totalTime * filledBCs) - << ", Input2 Lumi: " << mCountsPerBC2[bc] / (totalTime * filledBCs) - << "; Accumulated Counts Input1: " << mCountsPerBC1[bc] - << ", Input2: " << mCountsPerBC2[bc]; - } else if (mCountsPerBC1[bc] > 0) { // Only print non-zero luminosity - LOG(info) << " BC " << bc - << ": Input1 Lumi: " << mCountsPerBC1[bc] / (totalTime * filledBCs) - << ", Input2 Lumi: " << mCountsPerBC2[bc] / (totalTime * filledBCs) - << "; Accumulated Counts Input1: " << mCountsPerBC1[bc] - << ", Input2: " << mCountsPerBC2[bc]; + // Total luminosity over filled BCs for this window + if (mLHCBCs.test(bc)) { + totalLumi1 += mCountsPerBC1[bc] / (timeInterval * mCrossSection); + totalLumi2 += mCountsPerBC2[bc] / (timeInterval * mCrossSection); + totalLumiErr1 += std::sqrt(mCountsPerBC1[bc]) / (timeInterval * mCrossSection); + totalLumiErr2 += std::sqrt(mCountsPerBC2[bc]) / (timeInterval * mCrossSection); + } + } + writeMassiLineLumi(mWindowStartTime, totalLumi1, totalLumiErr1); + // Reset counters for the next window + mCountsPerBC1.fill(0.0); + mCountsPerBC2.fill(0.0); + mTFsInCurrentWindow = 0; + mOrbitsInCurrentWindow = 0; + } +} +void RawDecoderSpec::writeMassiLinePerBC(int bc, int64_t unixTimeStart, double lumi, double lumiErr, double correctedRate, double correctedLumi, double mu) +{ + int rfBucket = (bc * 10) + 1; + auto it = mMassiFiles.find(rfBucket); + if (it == mMassiFiles.end()) { + std::string dirPath = mMassiOutDir + "/" + std::to_string(mMassiYear) + "/lumi/" + mFillNumber; + + std::error_code ec; + std::filesystem::create_directories(dirPath, ec); + if (ec) { + LOG(error) << "Failed to create Massi output directory " << dirPath << ": " << ec.message(); + return; } + std::string filename = dirPath + "/" + mFillNumber + "_lumi_" + std::to_string(rfBucket) + "_ALICE.txt"; + auto result = mMassiFiles.emplace(rfBucket, std::ofstream(filename, std::ios::app)); + it = result.first; } - // Calculate and print the total integrated luminosity - int totalCountsInp1 = 0; - int totalCountsInp2 = 0; - for (const auto& count : mCountsPerBC1) { - totalCountsInp1 += count; + std::ofstream& ofs = it->second; + ofs << std::fixed << std::setprecision(0) << unixTimeStart << " " << mStableBeams << " "; + ofs << (std::abs(lumi) < 1e-3 ? std::scientific : std::fixed) << std::setprecision(7) << lumi << " "; + ofs << (std::abs(lumiErr) < 1e-3 ? std::scientific : std::fixed) << std::setprecision(7) << lumiErr << " "; + ofs << (std::abs(correctedLumi) < 1e-3 ? std::scientific : std::fixed) << std::setprecision(7) << correctedLumi << " "; + ofs << std::fixed << std::setprecision(7) << correctedRate << " " << mu << " " << std::endl; + ofs.flush(); +} +void RawDecoderSpec::writeMassiLineLumi(int64_t unixTimeStart, double lumi, double lumiErr) +{ + std::string dirPath = mMassiOutDir + "/" + std::to_string(mMassiYear) + "/lumi/" + mFillNumber; + std::error_code ec; + std::filesystem::create_directories(dirPath, ec); + if (ec) { + LOG(error) << "Failed to create Massi output directory " << dirPath << ": " << ec.message(); + return; } - LOG(info) << "Total Integrated Luminosity Input 1: " << totalCountsInp1 / totalTime; - for (const auto& count : mCountsPerBC2) { - totalCountsInp2 += count; + std::string filename = dirPath + "/" + mFillNumber + "_lumi_ALICE.txt"; + std::ofstream ofs(filename, std::ios::app); + ofs << std::fixed << std::setprecision(0) << unixTimeStart << " " << mStableBeams << " "; + ofs << (std::abs(lumi) < 1e-3 ? std::scientific : std::fixed) << std::setprecision(7) << lumi << " "; + ofs << (std::abs(lumiErr) < 1e-3 ? std::scientific : std::fixed) << std::setprecision(7) << lumiErr << " " << std::endl; + ofs.flush(); +} +int64_t RawDecoderSpec::unixTimeForOrbitStart(uint32_t orbit) const +{ + int64_t orbitResetTimeMUS = mRunInfo.orbitReset; + return (orbitResetTimeMUS + static_cast(orbit) * o2::constants::lhc::LHCOrbitMUS) * 1e-3; // Return in milliseconds +} +int RawDecoderSpec::yearFromUnixTime(int64_t unixTimeStart) const +{ + std::time_t time = static_cast(unixTimeStart); + std::tm* tm = std::gmtime(&time); + return tm->tm_year + 1900; +} +void RawDecoderSpec::fetchRunInfo(int runNumber) +{ + auto& ccdbMgr = o2::ccdb::BasicCCDBManager::instance(); + mRunInfo = o2::parameters::AggregatedRunInfo::buildAggregatedRunInfo_DATA(ccdbMgr, runNumber); + mOrbitsPerTF = mRunInfo.orbitsPerTF; + mMassiYear = yearFromUnixTime(mRunInfo.sor / 1000.0); + mOrbitResetTimeSec = mRunInfo.orbitReset * 1e-6; + mRunStartTime = mRunInfo.sor / 1000; + mRunEndTime = mRunInfo.eor / 1000; + LOG(info) << "Run start time: " << mRunStartTime << " Run end time: " << mRunEndTime; +} +void RawDecoderSpec::flushReadyTFs() +{ + while (mPendingTFs.size() > mReorderDepth) { + auto it = mPendingTFs.begin(); + integrateLumi(it->second.countsPerBC1, it->second.countsPerBC2, it->second.unixTimeStart, it->second.nOrbitsThisTF); + mPendingTFs.erase(it); + } +} +void RawDecoderSpec::flushAllPendingTFs() +{ + while (!mPendingTFs.empty()) { + auto it = mPendingTFs.begin(); + integrateLumi(it->second.countsPerBC1, it->second.countsPerBC2, it->second.unixTimeStart, it->second.nOrbitsThisTF); + mPendingTFs.erase(it); + } +} +std::pair RawDecoderSpec::pileupCorrection(double rate) const +{ + double p = rate / o2::constants::lhc::LHCRevFreq; + if (p >= 1.0) { + LOG(warning) << "Pile-up correction: p = " << p << " >= 1"; + return {0, 0}; } - LOG(info) << "Total Integrated Luminosity Input 2: " << totalCountsInp2 / totalTime; + double mu = -std::log(1-p); + double correctedRate = mu * o2::constants::lhc::LHCRevFreq; + return {mu, correctedRate}; } o2::framework::DataProcessorSpec o2::ctp::reco_workflow::getRawDecoderSpec(bool askDISTSTF, bool digits, bool lumi) { @@ -339,7 +524,7 @@ o2::framework::DataProcessorSpec o2::ctp::reco_workflow::getRawDecoderSpec(bool outputs, o2::framework::AlgorithmSpec{o2::framework::adaptFromTask(digits, lumi)}, o2::framework::Options{ - {"ntf-to-average", o2::framework::VariantType::Int, 90, {"Time interval for averaging luminosity in units of TF"}}, + {"ntf-to-average", o2::framework::VariantType::Int, 100, {"Time interval for averaging luminosity in units of TF"}}, {"print-errors-num", o2::framework::VariantType::Int, 3, {"Max number of errors to print"}}, {"lumi-inp1", o2::framework::VariantType::String, "TVX", {"The first input used for online lumi. Name in capital."}}, {"lumi-inp2", o2::framework::VariantType::String, "VBA", {"The second input used for online lumi. Name in capital."}}, @@ -347,7 +532,10 @@ o2::framework::DataProcessorSpec o2::ctp::reco_workflow::getRawDecoderSpec(bool {"max-input-size", o2::framework::VariantType::Int, 0, {"Do not process input if bigger than max size, 0 - do not check"}}, {"max-input-size-fatal", o2::framework::VariantType::Bool, false, {"If true issue fatal error otherwise error only"}}, {"check-consistency", o2::framework::VariantType::Bool, false, {"If true checks digits consistency using ctp config"}}, - {"ctpinputs-decoding", o2::framework::VariantType::Bool, false, {"Inputs alignment: true - raw decoder - has to be compatible with CTF decoder: allowed options: 10,01,00"}}}}; + {"ctpinputs-decoding", o2::framework::VariantType::Bool, false, {"Inputs alignment: true - raw decoder - has to be compatible with CTF decoder: allowed options: 10,01,00"}}, + {"cross-section", o2::framework::VariantType::Double, 59500.0, {"Cross-section in ub, default for pp collisions"}}, + {"tf-reorder-depth", o2::framework::VariantType::Int, 300, {"Number of TFs to buffer to correct out of-order TF delivery"}}, + {"massi-out-dir", o2::framework::VariantType::String, ".", {"Output directory for Massi files"}}}}; } void RawDecoderSpec::updateTimeDependentParams(framework::ProcessingContext& pc) { @@ -363,14 +551,21 @@ void RawDecoderSpec::updateTimeDependentParams(framework::ProcessingContext& pc) const auto grplhcif = pc.inputs().get("grplhcif"); if (grplhcif != nullptr) { LOG(info) << "GRPLHCIF injection scheme: " << grplhcif->getInjectionScheme(); + LOG(info) << "Bunch filling with time: " << grplhcif->getBunchFillingTime(); + LOG(info) << "Fill number time: " << grplhcif->getFillNumberTime(); + LOG(info) << "Injection scheme time: " << grplhcif->getInjectionSchemeTime(); // Get filled bunches auto bfilling = grplhcif->getBunchFilling(); std::vector bcs = bfilling.getFilledBCs(); + LOG(info) << "Filled BCs: " << bcs.size(); mLHCBCs.reset(); for (auto const& bc : bcs) { mLHCBCs.set(bc, 1); } + mFillNumber = std::to_string(grplhcif->getFillNumber()); } + int runNumber = pc.services().get().runNumber; + fetchRunInfo(runNumber); } } From ea1b2decafa6b3c6fa480666645753206b5c7a78 Mon Sep 17 00:00:00 2001 From: Ella Taylor Date: Fri, 21 Aug 2026 17:03:24 +0200 Subject: [PATCH 4/4] fixed clang --- .../include/CTPWorkflowLumi/RawDecoderSpec.h | 3 +- .../CTP/workflowLumi/src/RawDecoderSpec.cxx | 59 ++++++++++--------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h b/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h index 009bf01b27348..facf30be1bba6 100644 --- a/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h +++ b/Detectors/CTP/workflowLumi/include/CTPWorkflowLumi/RawDecoderSpec.h @@ -56,7 +56,7 @@ class RawDecoderSpec : public framework::Task /// \brief Compute per BC luminosity from the interaction counts from CTP digits /// \param ctpdigits Vector of CTP digits to be processed /// \return Array of luminosity values for each BC - // std::pair, std::array> + // std::pair, std::array> void computeLumiPerBC(const o2::pmr::vector& ctpdigits, uint32_t firstOrbit, uint32_t orbitsPerTF); /// \brief Integrate luminosity per BC over multiple time frames /// \param perInterval Array of luminosity values for each BC for a given time interval @@ -66,6 +66,7 @@ class RawDecoderSpec : public framework::Task int64_t unixTimeForOrbitStart(uint32_t orbit) const; int yearFromUnixTime(int64_t unixTime) const; void fetchRunInfo(int runNumber); + protected: private: // for digits diff --git a/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx b/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx index 2238c158facd7..c26cf6699aada 100644 --- a/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx +++ b/Detectors/CTP/workflowLumi/src/RawDecoderSpec.cxx @@ -125,7 +125,7 @@ void RawDecoderSpec::endOfStream(framework::EndOfStreamContext& ec) auto [mu, correctedRate1] = pileupCorrection(rate1); double correctedLumi1 = correctedRate1 / mCrossSection; writeMassiLinePerBC(bc, mWindowStartTime, lumi1, lumiErr1, correctedLumi1, correctedRate1, mu); - } + } if (mLHCBCs.test(bc)) { totalLumi1 += mCountsPerBC1[bc] / (timeInterval * mCrossSection); totalLumi2 += mCountsPerBC2[bc] / (timeInterval * mCrossSection); @@ -136,21 +136,21 @@ void RawDecoderSpec::endOfStream(framework::EndOfStreamContext& ec) } LOG(info) << "Flushed trailing partial window of " << mTFsInCurrentWindow << " TFs at end of stream"; } - // Calculate and print total luminosity for given fill - double totalFillCountsInp1 = 0.0; - double totalFillCountsInp2 = 0.0; - for (const auto& count : mTotalCountsPerBC1) { - totalFillCountsInp1 += count; - } - for (const auto& count : mTotalCountsPerBC2) { - totalFillCountsInp2 += count; - } - // Estimate the total integrated luminosity for the fill in ub^-1 and the rate in Hz - double avgRate1 = totalFillCountsInp1 / mTotalElapsedTime; - double fillDurationSec = (mRunInfo.eor - mRunInfo.sor) / 1000.0; - double totalIntLumiInp1 = totalFillCountsInp1 / mCrossSection; - double estimatedTotalIntLumiInp1 = (avgRate1 / mCrossSection) * fillDurationSec; - LOG(info) << "Total Integrated Luminosity Input 1: " << totalIntLumiInp1 << " ub^-1" << " Rate (vis): " << avgRate1 << " Hz, Estimated Total Integrated Lumi: " << estimatedTotalIntLumiInp1 << " ub^-1"; + // Calculate and print total luminosity for given fill + double totalFillCountsInp1 = 0.0; + double totalFillCountsInp2 = 0.0; + for (const auto& count : mTotalCountsPerBC1) { + totalFillCountsInp1 += count; + } + for (const auto& count : mTotalCountsPerBC2) { + totalFillCountsInp2 += count; + } + // Estimate the total integrated luminosity for the fill in ub^-1 and the rate in Hz + double avgRate1 = totalFillCountsInp1 / mTotalElapsedTime; + double fillDurationSec = (mRunInfo.eor - mRunInfo.sor) / 1000.0; + double totalIntLumiInp1 = totalFillCountsInp1 / mCrossSection; + double estimatedTotalIntLumiInp1 = (avgRate1 / mCrossSection) * fillDurationSec; + LOG(info) << "Total Integrated Luminosity Input 1: " << totalIntLumiInp1 << " ub^-1" << " Rate (vis): " << avgRate1 << " Hz, Estimated Total Integrated Lumi: " << estimatedTotalIntLumiInp1 << " ub^-1"; // Close files at end of stream for (auto& [bucket, ofs] : mMassiFiles) { ofs.close(); @@ -213,9 +213,8 @@ void RawDecoderSpec::run(framework::ProcessingContext& ctx) int64_t diff = static_cast(mFirstOrbit) - static_cast(mPrevTFLastOrbit); if (diff < 0) { LOG(warning) << "TF arrived out of order: previous TF ended at orbit " << mPrevTFLastOrbit << ", this TF starts at " << mFirstOrbit << " (orbit went backwards by " << diff << ")"; - } - else if (diff > 0) { - LOG(warning) << "Gap detected: previous TF ended at orbit " << expectedOrbit << ", this TF starts at " << mFirstOrbit << " (missing " << (mFirstOrbit - expectedOrbit) << " orbits)"; + } else if (diff > 0) { + LOG(warning) << "Gap detected: previous TF ended at orbit " << expectedOrbit << ", this TF starts at " << mFirstOrbit << " (missing " << (mFirstOrbit - expectedOrbit) << " orbits)"; } } } @@ -325,8 +324,10 @@ void RawDecoderSpec::computeLumiPerBC(const o2::pmr::vector& ctpdigits uint64_t mask = digit.CTPInputMask.to_ullong(); uint16_t bc = digit.intRecord.bc; if (bc < o2::constants::lhc::LHCMaxBunches) { - if (mask & inputMask1) tfCountsPerBC1[bc] += 1.0; - if (mask & inputMask2) tfCountsPerBC2[bc] += 1.0; + if (mask & inputMask1) + tfCountsPerBC1[bc] += 1.0; + if (mask & inputMask2) + tfCountsPerBC2[bc] += 1.0; } } int64_t unixTimeStart = unixTimeForOrbitStart(firstOrbit); @@ -341,7 +342,7 @@ void RawDecoderSpec::computeLumiPerBC(const o2::pmr::vector& ctpdigits } } flushReadyTFs(); - //integrateLumi(tfCountsPerBC1, tfCountsPerBC2, unixTimeStart, orbitsPerTF); + // integrateLumi(tfCountsPerBC1, tfCountsPerBC2, unixTimeStart, orbitsPerTF); } // Accumulate luminosity per BC over multiple time frames void RawDecoderSpec::integrateLumi(const std::array& tfCounts1, const std::array& tfCounts2, int64_t unixTimeStart, uint32_t nOrbitsThisTF) @@ -386,12 +387,12 @@ void RawDecoderSpec::integrateLumi(const std::array 0) { - // LOG(info) << "BC: " << bc + 1 << " Rate: " << rate1 << " Corrected Rate: " << correctedRate1 << " mu: " << mu; + // LOG(info) << "BC: " << bc + 1 << " Rate: " << rate1 << " Corrected Rate: " << correctedRate1 << " mu: " << mu; writeMassiLinePerBC(bc, mWindowStartTime, lumi1, lumiErr1, correctedRate1, correctedLumi1, mu); } } - // Total luminosity over filled BCs for this window + // Total luminosity over filled BCs for this window if (mLHCBCs.test(bc)) { totalLumi1 += mCountsPerBC1[bc] / (timeInterval * mCrossSection); totalLumi2 += mCountsPerBC2[bc] / (timeInterval * mCrossSection); @@ -429,7 +430,7 @@ void RawDecoderSpec::writeMassiLinePerBC(int bc, int64_t unixTimeStart, double l ofs << (std::abs(lumi) < 1e-3 ? std::scientific : std::fixed) << std::setprecision(7) << lumi << " "; ofs << (std::abs(lumiErr) < 1e-3 ? std::scientific : std::fixed) << std::setprecision(7) << lumiErr << " "; ofs << (std::abs(correctedLumi) < 1e-3 ? std::scientific : std::fixed) << std::setprecision(7) << correctedLumi << " "; - ofs << std::fixed << std::setprecision(7) << correctedRate << " " << mu << " " << std::endl; + ofs << std::fixed << std::setprecision(7) << correctedRate << " " << mu << " " << std::endl; ofs.flush(); } void RawDecoderSpec::writeMassiLineLumi(int64_t unixTimeStart, double lumi, double lumiErr) @@ -466,9 +467,9 @@ void RawDecoderSpec::fetchRunInfo(int runNumber) mOrbitsPerTF = mRunInfo.orbitsPerTF; mMassiYear = yearFromUnixTime(mRunInfo.sor / 1000.0); mOrbitResetTimeSec = mRunInfo.orbitReset * 1e-6; - mRunStartTime = mRunInfo.sor / 1000; + mRunStartTime = mRunInfo.sor / 1000; mRunEndTime = mRunInfo.eor / 1000; - LOG(info) << "Run start time: " << mRunStartTime << " Run end time: " << mRunEndTime; + LOG(info) << "Run start time: " << mRunStartTime << " Run end time: " << mRunEndTime; } void RawDecoderSpec::flushReadyTFs() { @@ -493,7 +494,7 @@ std::pair RawDecoderSpec::pileupCorrection(double rate) const LOG(warning) << "Pile-up correction: p = " << p << " >= 1"; return {0, 0}; } - double mu = -std::log(1-p); + double mu = -std::log(1 - p); double correctedRate = mu * o2::constants::lhc::LHCRevFreq; return {mu, correctedRate}; } @@ -566,6 +567,6 @@ void RawDecoderSpec::updateTimeDependentParams(framework::ProcessingContext& pc) mFillNumber = std::to_string(grplhcif->getFillNumber()); } int runNumber = pc.services().get().runNumber; - fetchRunInfo(runNumber); + fetchRunInfo(runNumber); } }