diff --git a/Common/Utils/include/CommonUtils/IRFrameSelector.h b/Common/Utils/include/CommonUtils/IRFrameSelector.h index a4365030b6a12..0b3f55f83dab5 100644 --- a/Common/Utils/include/CommonUtils/IRFrameSelector.h +++ b/Common/Utils/include/CommonUtils/IRFrameSelector.h @@ -39,7 +39,7 @@ class IRFrameSelector } void clear(); - size_t loadIRFrames(const std::string& fname); + size_t loadIRFrames(const std::string& fname, size_t margin = 0); void applyMargins(size_t bwd, size_t fwd, long shift, bool removeOverlaps = true); void print(bool lst = false) const; diff --git a/Common/Utils/src/IRFrameSelector.cxx b/Common/Utils/src/IRFrameSelector.cxx index abc0ee1ee6ce3..0afc68f7f3399 100644 --- a/Common/Utils/src/IRFrameSelector.cxx +++ b/Common/Utils/src/IRFrameSelector.cxx @@ -100,7 +100,7 @@ long IRFrameSelector::check(o2::dataformats::IRFrame fr, size_t bwd, size_t fwd) return ans; } -size_t IRFrameSelector::loadIRFrames(const std::string& fname) +size_t IRFrameSelector::loadIRFrames(const std::string& fname, size_t margin) { // read IRFrames to filter from the file std::unique_ptr tfl(TFile::Open(fname.c_str())); @@ -155,15 +155,14 @@ size_t IRFrameSelector::loadIRFrames(const std::string& fname) toBeSorted = true; } } - + if (!done) { + LOGP(fatal, "Did not find neither tree nor vector of IRFrames in {}", fname); + } if (toBeSorted) { LOGP(info, "Sorting {} IRFrames", mOwnList.size()); std::sort(mOwnList.begin(), mOwnList.end(), [](const auto& a, const auto& b) { return a.getMin() < b.getMin(); }); } - if (!true) { - LOGP(fatal, "Did not find neither tree nor vector of IRFrames in {}", fname); - } - setSelectedIRFrames(mOwnList); + setSelectedIRFrames(mOwnList, margin, margin); return mOwnList.size(); } diff --git a/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h b/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h index 51f2fca2c8303..28b7da7d56c4d 100644 --- a/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h +++ b/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h @@ -32,6 +32,7 @@ struct CTFReaderInp { std::string remoteRegex{}; std::string metricChannel{}; std::string fileIRFrames{}; + uint32_t selectIRFramesExtraBCMargin = 0; std::string fileRunTimeSpans{}; std::string dictOpt{}; std::vector ctfIDs{}; diff --git a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx index 9fba8a220be55..be0080769995f 100644 --- a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx @@ -177,10 +177,9 @@ void CTFReaderSpec::init(InitContext& ic) mFileFetcher->setFailThreshold(ic.options().get("fetch-failure-threshold")); mFileFetcher->start(); if (!mInput.fileIRFrames.empty()) { - mIRFrameSelector.loadIRFrames(mInput.fileIRFrames); - const auto& hbfu = o2::raw::HBFUtils::Instance(); - mTFLength = hbfu.nHBFPerTF; - LOGP(info, "IRFrames will be selected from {}, assumed TF length: {} HBF", mInput.fileIRFrames, mTFLength); + mIRFrameSelector.loadIRFrames(mInput.fileIRFrames, mInput.selectIRFramesExtraBCMargin); + mTFLength = o2::raw::HBFUtils::Instance().nHBFPerTF; + LOGP(info, "IRFrames will be selected from {} with {} margin, assumed TF length: {} HBF", mInput.fileIRFrames, mInput.selectIRFramesExtraBCMargin, mTFLength); mIFRamesOut = true; } if (!mInput.fileRunTimeSpans.empty()) { diff --git a/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx b/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx index 366fa76f74983..31ad95a3889c3 100644 --- a/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx +++ b/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx @@ -70,12 +70,15 @@ void customize(std::vector& workflowOptions) options.push_back(ConfigParamSpec{"ctf-data-subspec", VariantType::Int, 0, {"subspec to use for decoded CTF messages (use non-0 if CTF writer will be attached downstream)"}}); options.push_back(ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}); options.push_back(ConfigParamSpec{"ir-frames-files", VariantType::String, "", {"If non empty, inject selected IRFrames from this file"}}); + options.push_back(ConfigParamSpec{"ir-frames-extra-margin", VariantType::UInt32, uint32_t(0), {"Impose additional FWD/BWD BC margin on selected IRFrames"}}); options.push_back(ConfigParamSpec{"run-time-span-file", VariantType::String, "", {"If non empty, inject selected IRFrames from this text file (run, min/max orbit or unix time)"}}); options.push_back(ConfigParamSpec{"skip-skimmed-out-tf", VariantType::Bool, false, {"Do not process TFs with empty IR-Frame coverage"}}); options.push_back(ConfigParamSpec{"invert-irframe-selection", VariantType::Bool, false, {"Select only frames mentioned in ir-frames-file (skip-skimmed-out-tf applied to TF not selected!)"}}); // options.push_back(ConfigParamSpec{"its-digits", VariantType::Bool, false, {"convert ITS clusters to digits"}}); + options.push_back(ConfigParamSpec{"its-select-ir-frames", VariantType::Bool, false, {"select ITS rofs matching ITFrames"}}); options.push_back(ConfigParamSpec{"mft-digits", VariantType::Bool, false, {"convert MFT clusters to digits"}}); + options.push_back(ConfigParamSpec{"mft-select-ir-frames", VariantType::Bool, false, {"select ITS rofs matching ITFrames"}}); // options.push_back(ConfigParamSpec{"emcal-decoded-subspec", VariantType::Int, 0, {"subspec to use for decoded EMCAL data"}}); // @@ -134,6 +137,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) ctfInput.sup0xccdb = !configcontext.options().get("send-diststf-0xccdb"); ctfInput.minSHM = std::stoul(configcontext.options().get("timeframes-shm-limit")); ctfInput.fileIRFrames = configcontext.options().get("ir-frames-files"); + ctfInput.selectIRFramesExtraBCMargin = configcontext.options().get("ir-frames-extra-margin"); ctfInput.fileRunTimeSpans = configcontext.options().get("run-time-span-file"); ctfInput.skipSkimmedOutTF = configcontext.options().get("skip-skimmed-out-tf"); ctfInput.invertIRFramesSelection = configcontext.options().get("invert-irframe-selection"); @@ -145,7 +149,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) if (rateLimitingIPCID > -1 && !chanFmt.empty()) { ctfInput.metricChannel = fmt::format(fmt::runtime(chanFmt), o2::framework::ChannelSpecHelpers::defaultIPCFolder(), rateLimitingIPCID); } - if (!ctfInput.fileRunTimeSpans.empty()) { + if (!ctfInput.fileRunTimeSpans.empty() || !ctfInput.fileIRFrames.empty()) { ctfInput.skipSkimmedOutTF = true; } if (!ctfInput.fileIRFrames.empty() && !ctfInput.fileRunTimeSpans.empty()) { @@ -190,11 +194,11 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // add decoders for all allowed detectors. if (ctfInput.detMask[DetID::ITS]) { bool doStag = o2::itsmft::DPLAlpideParamInitializer::isITSStaggeringEnabled(configcontext); - addSpecs(o2::itsmft::getITSEntropyDecoderSpec(verbosity, doStag, configcontext.options().get("its-digits"), ctfInput.subspec, ctfInput.dictOpt)); + addSpecs(o2::itsmft::getITSEntropyDecoderSpec(verbosity, doStag, configcontext.options().get("its-digits"), configcontext.options().get("its-select-ir-frames"), ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::MFT]) { bool doStag = o2::itsmft::DPLAlpideParamInitializer::isMFTStaggeringEnabled(configcontext); - addSpecs(o2::itsmft::getMFTEntropyDecoderSpec(verbosity, doStag, configcontext.options().get("mft-digits"), ctfInput.subspec, ctfInput.dictOpt)); + addSpecs(o2::itsmft::getMFTEntropyDecoderSpec(verbosity, doStag, configcontext.options().get("mft-digits"), configcontext.options().get("mft-select-ir-frames"), ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::TPC]) { addSpecs(o2::tpc::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); diff --git a/Detectors/GlobalTracking/CMakeLists.txt b/Detectors/GlobalTracking/CMakeLists.txt index ecf77ea741e21..2cefcf1263eae 100644 --- a/Detectors/GlobalTracking/CMakeLists.txt +++ b/Detectors/GlobalTracking/CMakeLists.txt @@ -74,3 +74,5 @@ if (OpenMP_CXX_FOUND) target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) endif() + +add_subdirectory(macros) diff --git a/Detectors/GlobalTracking/macros/CMakeLists.txt b/Detectors/GlobalTracking/macros/CMakeLists.txt new file mode 100644 index 0000000000000..54c308246c3eb --- /dev/null +++ b/Detectors/GlobalTracking/macros/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright 2019-2026 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_test_root_macro(selectPVIRFrames.C + PUBLIC_LINK_LIBRARIES O2::GlobalTracking + LABELS glo) diff --git a/Detectors/GlobalTracking/macros/selectPVIRFrames.C b/Detectors/GlobalTracking/macros/selectPVIRFrames.C new file mode 100644 index 0000000000000..8a1125ddc9c53 --- /dev/null +++ b/Detectors/GlobalTracking/macros/selectPVIRFrames.C @@ -0,0 +1,48 @@ +// Copyright 2019-2026 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 selectPVIRFrames.C +/// \brief Macro to select IRFrames for specific vertices + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include > +#include + +#include +#include + +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "CommonDataFormat/IRFrame.h" +#endif + +void selectPVIRFrames(const char* fName = "o2_primary_vertex.root") +{ + auto fPVs = TFile::Open(fName); + TTree* tPVs = (TTree*)fPVs->Get("o2sim"); + std::vector pvArr, *pvArrPtr{&pvArr}; + tPVs->SetBranchAddress("PrimaryVertex", &pvArrPtr); + std::vector irFrames; + for (Long64_t iEntry{0}; tPVs->LoadTree(iEntry) >= 0; ++iEntry) { + tPVs->GetEntry(iEntry); + for (const auto& pv : pvArr) { + // make selection of pvs + if (pv.getNContributors() > 3000) { + irFrames.emplace_back(pv.getIRMin(), pv.getIRMax()); + } + } + } + // sort to make sure they are in the correct order + std::sort(irFrames.begin(), irFrames.end(), [](const auto& a, const auto& b) { return a.getMin() < b.getMin(); }); + printf("Selected %zu irFrames\n", irFrames.size()); + auto fIRFrames = TFile::Open("irFrames.root", "RECREATE"); + fIRFrames->WriteObjectAny(&irFrames, "std::vector", "irframes"); + fIRFrames->Close(); +} diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h index 6862e96c17afe..6ae7776d25501 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h @@ -33,7 +33,7 @@ template class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity, bool doStag, bool getDigits = false, const std::string& ctfdictOpt = "none"); + EntropyDecoderSpec(int verbosity, bool doStag, bool selectIRFrames, bool getDigits = false, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void init(o2::framework::InitContext& ic) final; void run(o2::framework::ProcessingContext& pc) final; @@ -51,6 +51,7 @@ class EntropyDecoderSpec : public o2::framework::Task const NoiseMap* mNoiseMap = nullptr; LookUp mPattIdConverter; bool mDoStaggering{false}; + bool mSelectIRFrames{false}; bool mGetDigits{false}; bool mMaskNoise{false}; bool mUseClusterDictionary{true}; @@ -60,8 +61,8 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getITSEntropyDecoderSpec(int verbosity, bool doStag, bool getDigits, unsigned int sspec, const std::string& ctfdictOpt); -framework::DataProcessorSpec getMFTEntropyDecoderSpec(int verbosity, bool doStag, bool getDigits, unsigned int sspec, const std::string& ctfdictOpt); +framework::DataProcessorSpec getITSEntropyDecoderSpec(int verbosity, bool doStag, bool getDigits, bool selectIRFrames, unsigned int sspec, const std::string& ctfdictOpt); +framework::DataProcessorSpec getMFTEntropyDecoderSpec(int verbosity, bool doStag, bool getDigits, bool selectIRFrames, unsigned int sspec, const std::string& ctfdictOpt); } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx index 7c8bfe7dfed67..d4b2332424a1b 100644 --- a/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx @@ -37,8 +37,8 @@ std::string EntropyDecoderSpec::getBinding(const std::string& name, int spec) } template -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, bool doStag, bool getDigits, const std::string& ctfdictOpt) - : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, doStag, ctfdictOpt), mDoStaggering(doStag), mGetDigits(getDigits) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, bool doStag, bool selectIRFrames, bool getDigits, const std::string& ctfdictOpt) + : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, doStag, ctfdictOpt), mDoStaggering(doStag), mSelectIRFrames(selectIRFrames), mGetDigits(getDigits) { mTimer.Stop(); mTimer.Reset(); @@ -96,6 +96,27 @@ void EntropyDecoderSpec::run(ProcessingContext& pc) } ndigcl += compcl.size(); } + if (mSelectIRFrames) { + int nSelected{0}; + /// mask ROF entries not matching with selected IRFrames + auto irFrames = pc.inputs().get>("selIRFrames"); + for (auto& rof : rofs) { + bool masked = true; + for (const auto& irFrame : irFrames) { + const auto irStart = rof.getBCData(), irEnd = irStart + DPLAlpideParam::Instance().getROFLengthInBC(iLayer); + o2::dataformats::IRFrame irROF(irStart, irEnd); + if (irFrame.isOutside(irROF) == o2::dataformats::IRFrame::Relation::Inside) { + ++nSelected; + masked = false; + break; + } + } + if (masked) { + rof.setNEntries(0); + } + } + LOGP(info, "Selected {} out of {} rofs", nSelected, rofs.size()); + } } pc.outputs().snapshot({nm + "ctfrep", 0}, iosize); mTimer.Stop(); @@ -149,7 +170,7 @@ void EntropyDecoderSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& mat } template -DataProcessorSpec getEntropyDecoderSpec(int verbosity, bool doStag, bool getDigits, unsigned int sspec, const std::string& ctfdictOpt) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, bool doStag, bool getDigits, bool selectIRFrames, unsigned int sspec, const std::string& ctfdictOpt) { constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; constexpr o2::detectors::DetID ID{N == o2::detectors::DetID::ITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT}; @@ -181,25 +202,28 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, bool doStag, bool getDigi inputs.emplace_back(std::string{"ctfdict_"} + ID.getName(), Origin, "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/CTFDictionaryTree", Origin.as()))); } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); + if (selectIRFrames) { + inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", Lifetime::Timeframe); + } return DataProcessorSpec{ Origin == o2::header::gDataOriginITS ? "its-entropy-decoder" : "mft-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask>(verbosity, doStag, getDigits, ctfdictOpt)}, + AlgorithmSpec{adaptFromTask>(verbosity, doStag, selectIRFrames, getDigits, ctfdictOpt)}, Options{{"mask-noise", VariantType::Bool, false, {"apply noise mask to digits or clusters (involves reclusterization)"}}, {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } -framework::DataProcessorSpec getITSEntropyDecoderSpec(int verbosity, bool doStag, bool getDigits, unsigned int sspec, const std::string& ctfdictOpt) +framework::DataProcessorSpec getITSEntropyDecoderSpec(int verbosity, bool doStag, bool getDigits, bool selectIRFrames, unsigned int sspec, const std::string& ctfdictOpt) { - return getEntropyDecoderSpec(verbosity, doStag, getDigits, sspec, ctfdictOpt); + return getEntropyDecoderSpec(verbosity, doStag, getDigits, selectIRFrames, sspec, ctfdictOpt); } -framework::DataProcessorSpec getMFTEntropyDecoderSpec(int verbosity, bool doStag, bool getDigits, unsigned int sspec, const std::string& ctfdictOpt) +framework::DataProcessorSpec getMFTEntropyDecoderSpec(int verbosity, bool doStag, bool getDigits, bool selectIRFrames, unsigned int sspec, const std::string& ctfdictOpt) { - return getEntropyDecoderSpec(verbosity, doStag, getDigits, sspec, ctfdictOpt); + return getEntropyDecoderSpec(verbosity, doStag, getDigits, selectIRFrames, sspec, ctfdictOpt); } } // namespace itsmft