From 0e1c8989677ce7e507599cdc11f5c7820255a7dd Mon Sep 17 00:00:00 2001 From: jryu Date: Tue, 2 Jun 2026 11:44:36 +0900 Subject: [PATCH] Add ITS stuck-pixel CCDB object output --- .../Detectors/ITSMFT/common/CMakeLists.txt | 1 + .../DataFormatsITSMFT/StuckPixelData.h | 77 +++++ .../ITSMFTWorkflow/DeadMapBuilderSpec.h | 13 +- .../workflow/src/DeadMapBuilderSpec.cxx | 293 +++++++++++++----- 4 files changed, 300 insertions(+), 84 deletions(-) create mode 100644 DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/StuckPixelData.h diff --git a/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt b/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt index a619f8ad0081d..b80509c52fcee 100644 --- a/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt +++ b/DataFormats/Detectors/ITSMFT/common/CMakeLists.txt @@ -35,6 +35,7 @@ o2_target_root_dictionary(DataFormatsITSMFT include/DataFormatsITSMFT/GBTCalibData.h include/DataFormatsITSMFT/NoiseMap.h include/DataFormatsITSMFT/TimeDeadMap.h + include/DataFormatsITSMFT/StuckPixelData.h include/DataFormatsITSMFT/Cluster.h include/DataFormatsITSMFT/CompCluster.h include/DataFormatsITSMFT/ClusterPattern.h diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/StuckPixelData.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/StuckPixelData.h new file mode 100644 index 0000000000000..6175304729c7f --- /dev/null +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/StuckPixelData.h @@ -0,0 +1,77 @@ +// 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 StuckPixelData.h +/// @brief CCDB-serializable container for stuck (repeating) pixel error records. +/// +/// Design rationale +/// ---------------- +/// TTree-based storage is intentionally avoided for CCDB objects because TTree +/// branches hold internal file-pointer state; serialising an in-memory TTree +/// via CcdbApi::createObjectImage() can silently drop the last unflushed basket. +/// A plain std::vector has no such issue: ROOT's TClass +/// machinery serialises it correctly via the generated dictionary, exactly as +/// it does for TimeDeadMap. + +#ifndef ITSMFT_STUCKPIXELDATA_H +#define ITSMFT_STUCKPIXELDATA_H + +#include +#include +#include // ClassDefNV + +namespace o2 +{ +namespace itsmft +{ + +/// One stuck-pixel (RepeatingPixel error) record. +struct StuckPixelEntry { + Long64_t orbit{0}; ///< first orbit of the TF in which the error was seen + uint16_t chipID{0}; ///< global chip ID (ITS only) + uint16_t row{0}; ///< pixel row + uint16_t col{0}; ///< pixel column + + StuckPixelEntry() = default; + StuckPixelEntry(Long64_t o, uint16_t c, uint16_t r, uint16_t col_) + : orbit(o), chipID(c), row(r), col(col_) {} + + ClassDefNV(StuckPixelEntry, 1); +}; + +/// CCDB payload object: a run-level collection of stuck-pixel records. +class StuckPixelData +{ + public: + StuckPixelData() = default; + ~StuckPixelData() = default; + + void addEntry(Long64_t orbit, uint16_t chipID, uint16_t row, uint16_t col) + { + mEntries.emplace_back(orbit, chipID, row, col); + } + + void clear() { mEntries.clear(); } + + const std::vector& getEntries() const { return mEntries; } + std::size_t size() const { return mEntries.size(); } + bool empty() const { return mEntries.empty(); } + + private: + std::vector mEntries; + + ClassDefNV(StuckPixelData, 1); +}; + +} // namespace itsmft +} // namespace o2 + +#endif // ITSMFT_STUCKPIXELDATA_H \ No newline at end of file diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DeadMapBuilderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DeadMapBuilderSpec.h index 2a15c332ecde1..dc6090a340f57 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DeadMapBuilderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DeadMapBuilderSpec.h @@ -132,8 +132,19 @@ class ITSMFTDeadMapBuilder : public Task // Flag to avoid that endOfStream and stop are both done bool isEnded = false; +<<<<<<< HEAD +======= + + std::string mStuckPixelFileName = ""; + + TTree* mErrorTree = nullptr; + Long64_t mErrOrbit = 0; + UShort_t mErrChipID = 0; + UShort_t mErrRow = 0; + UShort_t mErrCol = 0; +>>>>>>> 5df4d36ff6 (Add ITS stuck-pixel CCDB object output) }; - +6 // Create a processor spec o2::framework::DataProcessorSpec getITSMFTDeadMapBuilderSpec(std::string datasource, bool doMFT); diff --git a/Detectors/ITSMFT/common/workflow/src/DeadMapBuilderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/DeadMapBuilderSpec.cxx index 8f249136c54c0..5e5dbc5aacb92 100644 --- a/Detectors/ITSMFT/common/workflow/src/DeadMapBuilderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/DeadMapBuilderSpec.cxx @@ -17,6 +17,9 @@ #include "DataFormatsITSMFT/Digit.h" #include "DataFormatsITSMFT/CompCluster.h" #include "DataFormatsITSMFT/TimeDeadMap.h" +#include "DataFormatsITSMFT/StuckPixelData.h" // NEW +#include "ITSMFTReconstruction/DecodingStat.h" +#include namespace o2 { @@ -36,14 +39,12 @@ ITSMFTDeadMapBuilder::ITSMFTDeadMapBuilder(std::string datasource, bool doMFT) // Default deconstructor ITSMFTDeadMapBuilder::~ITSMFTDeadMapBuilder() { - // Clear dynamic memory return; } ////////////////////////////////////////////////////////////////////////////// void ITSMFTDeadMapBuilder::init(InitContext& ic) { - LOG(info) << "ITSMFTDeadMapBuilder init... " << mSelfName; mTFSampling = ic.options().get("tf-sampling"); @@ -87,11 +88,24 @@ void ITSMFTDeadMapBuilder::init(InitContext& ic) LOG(info) << "Sampling one TF every " << mTFSampling << " with " << mTFSamplingTolerance << " TF tolerance"; + // ------------------------------------------------------------------ + // Stuck-pixel setup + // Disabled for MFT (ITS-specific feature) or when option is not set. + // ------------------------------------------------------------------ + mStuckPixelFileName = ic.options().get("save-stuck-pixels"); + mDoStuckPixels = (!mRunMFT && !mStuckPixelFileName.empty()); + + if (mDoStuckPixels) { + LOG(info) << "Stuck pixel saving ENABLED. CCDB object name: " << mStuckPixelFileName; + mStuckPixelData.clear(); + } else { + LOG(info) << "Stuck pixel saving DISABLED."; + } + return; } /////////////////////////////////////////////////////////////////// -// TODO: can ChipMappingITS help here? std::vector ITSMFTDeadMapBuilder::getChipIDsOnSameCable(uint16_t chip) { if (mRunMFT || chip < N_CHIPS_ITSIB) { @@ -104,12 +118,9 @@ std::vector ITSMFTDeadMapBuilder::getChipIDsOnSameCable(uint16_t chip) } } +////////////////////////////////////////////////////////////////////////////// bool ITSMFTDeadMapBuilder::acceptTF(long orbit) { - - // Description of the algorithm: - // Return true if the TF index (calculated as orbit/TF_length) falls within any interval [k * tf_sampling, k * tf_sampling + tolerance) for some integer k, provided no other TFs have been found in the same interval. - if (mTFSamplingTolerance < 1) { return ((orbit / mTFLength) % mTFSampling == 0); } @@ -121,7 +132,6 @@ bool ITSMFTDeadMapBuilder::acceptTF(long orbit) long sampling_index = orbit / mTFLength / mTFSampling; if (mSampledTFs.find(sampling_index) == mSampledTFs.end()) { - mSampledTFs.insert(sampling_index); mSampledHistory.push_back(sampling_index); @@ -138,10 +148,9 @@ bool ITSMFTDeadMapBuilder::acceptTF(long orbit) } ////////////////////////////////////////////////////////////////////////////// - void ITSMFTDeadMapBuilder::finalizeOutput() { - + // ---- static dead map ---- if (!mSkipStaticMap) { std::vector staticmap{}; int staticmap_chipcounter = 0; @@ -161,17 +170,54 @@ void ITSMFTDeadMapBuilder::finalizeOutput() } } - LOG(info) << "Filling static part of the map with " << staticmap_chipcounter << " dead chips, saved into " << staticmap.size() << " words"; - + LOG(info) << "Filling static part of the map with " << staticmap_chipcounter + << " dead chips, saved into " << staticmap.size() << " words"; mMapObject.fillMap(staticmap); } + // ---- local ROOT output: TimeDeadMap ---- if (mDoLocalOutput) { std::string localoutfilename = mLocalOutputDir + "/" + mObjectName; TFile outfile(localoutfilename.c_str(), "RECREATE"); outfile.WriteObjectAny(&mMapObject, "o2::itsmft::TimeDeadMap", "ccdb_object"); outfile.Close(); } + + // ---- local ROOT output: StuckPixelData as TTree ---- + // For local analysis convenience the same data is written as a TTree. + // The CCDB payload itself is the StuckPixelData object, not this TTree. + if (mDoStuckPixels && mDoLocalOutput) { + std::string stuckOutFileName = mLocalOutputDir + "/" + mStuckPixelFileName; + TFile stuckOutFile(stuckOutFileName.c_str(), "RECREATE"); + + if (!stuckOutFile.IsZombie()) { + stuckOutFile.cd(); + + TTree localTree("ErrorTree", "Stuck Pixel Errors"); + localTree.SetDirectory(&stuckOutFile); + localTree.Branch("orbit", &mErrOrbit, "orbit/L"); + localTree.Branch("chipid", &mErrChipID, "chipid/s"); + localTree.Branch("row", &mErrRow, "row/s"); + localTree.Branch("col", &mErrCol, "col/s"); + + for (const auto& entry : mStuckPixelData.getEntries()) { + mErrOrbit = entry.orbit; + mErrChipID = entry.chipID; + mErrRow = entry.row; + mErrCol = entry.col; + localTree.Fill(); + } + + stuckOutFile.Write(); + stuckOutFile.Close(); + + LOG(info) << "StuckPixel TTree saved locally to " << stuckOutFileName + << " (" << mStuckPixelData.size() << " entries)"; + } else { + LOG(error) << "Failed to open " << stuckOutFileName << " for StuckPixel TTree."; + } + } + return; } @@ -179,17 +225,16 @@ void ITSMFTDeadMapBuilder::finalizeOutput() // Main running function void ITSMFTDeadMapBuilder::run(ProcessingContext& pc) { - // Skip everything in case of garbage (potentially at EoS) if (pc.services().get().firstTForbit == -1U) { - LOG(info) << "Skipping the processing of inputs for timeslice " << pc.services().get().timeslice << " (firstTForbit is " << pc.services().get().firstTForbit << ")"; + LOG(info) << "Skipping the processing of inputs for timeslice " + << pc.services().get().timeslice + << " (firstTForbit is " + << pc.services().get().firstTForbit << ")"; return; } - std::chrono::time_point start; - std::chrono::time_point end; - - start = std::chrono::high_resolution_clock::now(); + auto start = std::chrono::high_resolution_clock::now(); const auto& tinfo = pc.services().get(); @@ -203,6 +248,7 @@ void ITSMFTDeadMapBuilder::run(ProcessingContext& pc) if (isEnded) { return; } + mFirstOrbitTF = tinfo.firstTForbit; mTFCounter++; @@ -213,7 +259,25 @@ void ITSMFTDeadMapBuilder::run(ProcessingContext& pc) } mStepCounter++; - LOG(info) << "Processing step #" << mStepCounter << " out of " << mTFCounter << " good TF received. First orbit " << mFirstOrbitTF; + + // ---- collect stuck pixel (RepeatingPixel) errors ---- + // ErrorInfo input is declared only for ITS. Entries are stored only when + // save-stuck-pixels is set. + if (mDoStuckPixels) { + const auto repErrors = pc.inputs().get>("repErr"); + for (const auto& err : repErrors) { + if (err.errType == o2::itsmft::ChipStat::RepeatingPixel) { + mStuckPixelData.addEntry( + static_cast(mFirstOrbitTF), + static_cast(err.id), + static_cast(err.errInfo0), + static_cast(err.errInfo1)); + } + } + } + + LOG(info) << "Processing step #" << mStepCounter << " out of " << mTFCounter + << " good TF received. First orbit " << mFirstOrbitTF; mDeadMapTF.clear(); @@ -284,19 +348,21 @@ void ITSMFTDeadMapBuilder::run(ProcessingContext& pc) } } - LOG(info) << "TF contains " << CountDead << " dead chips, saved into " << mDeadMapTF.size() << " words."; + LOG(info) << "TF contains " << CountDead << " dead chips, saved into " + << mDeadMapTF.size() << " words."; // filling the map mMapObject.fillMap(mFirstOrbitTF, mDeadMapTF); - end = std::chrono::high_resolution_clock::now(); + auto end = std::chrono::high_resolution_clock::now(); int difference = std::chrono::duration_cast(end - start).count(); LOG(info) << "Elapsed time in TF processing: " << difference / 1000. << " ms"; if (pc.transitionState() == TransitionHandlingState::Requested && !isEnded) { std::string detname = mRunMFT ? "MFT" : "ITS"; - LOG(warning) << "Transition state requested for " << detname << " process, calling stop() and stopping the process of new data."; + LOG(warning) << "Transition state requested for " << detname + << " process, calling stop() and stopping the process of new data."; stop(); } @@ -304,76 +370,121 @@ void ITSMFTDeadMapBuilder::run(ProcessingContext& pc) } ////////////////////////////////////////////////////////////////////////////// -void ITSMFTDeadMapBuilder::PrepareOutputCcdb(EndOfStreamContext* ec, std::string ccdburl = "") +void ITSMFTDeadMapBuilder::PrepareOutputCcdb(EndOfStreamContext* ec, std::string ccdburl) { - - // if ccdburl is specified, the object is sent to ccdb from this workflow - long tend = o2::ccdb::getCurrentTimestamp(); - - std::map md = {{"map_version", MAP_VERSION}, {"runNumber", std::to_string(mRunNumber)}}; + std::map md = { + {"map_version", MAP_VERSION}, + {"runNumber", std::to_string(mRunNumber)} + }; std::string path = mRunMFT ? "MFT/Calib/" : "ITS/Calib/"; - std::string name_str = "TimeDeadMap"; - o2::ccdb::CcdbObjectInfo info((path + name_str), name_str, mObjectName, md, mTimeStart - 120 * 1000, tend + 60 * 1000); + // ---- TimeDeadMap ---- + { + std::string name_str = "TimeDeadMap"; - auto image = o2::ccdb::CcdbApi::createObjectImage(&mMapObject, &info); - info.setFileName(mObjectName); + o2::ccdb::CcdbObjectInfo info( + (path + name_str), + name_str, + mObjectName, + md, + mTimeStart - 120 * 1000, + tend + 60 * 1000); - info.setAdjustableEOV(); + auto image = o2::ccdb::CcdbApi::createObjectImage(&mMapObject, &info); + info.setFileName(mObjectName); + info.setAdjustableEOV(); - if (ec != nullptr) { - - LOG(important) << "Sending object " << info.getPath() << "/" << info.getFileName() - << " to ccdb-populator, of size " << image->size() << " bytes, valid for " - << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); - - if (mRunMFT) { - ec->outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TimeDeadMap", 1}, *image.get()); - ec->outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TimeDeadMap", 1}, info); + if (mMapObject.getEvolvingMapSize() > 0) { + if (ec != nullptr) { + LOG(important) << "Sending object " << info.getPath() << "/" << info.getFileName() + << " to ccdb-populator, of size " << image->size() + << " bytes, valid for " + << info.getStartValidityTimestamp() << " : " + << info.getEndValidityTimestamp(); + + if (mRunMFT) { + ec->outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TimeDeadMap", 1}, *image.get()); + ec->outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TimeDeadMap", 1}, info); + } else { + ec->outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TimeDeadMap", 0}, *image.get()); + ec->outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TimeDeadMap", 0}, info); + } + } else if (!ccdburl.empty()) { + LOG(important) << mSelfName << " sending object " << ccdburl << "/browse/" + << info.getPath() << "/" << info.getFileName() + << " of size " << image->size() << " bytes, valid for " + << info.getStartValidityTimestamp() << " : " + << info.getEndValidityTimestamp(); + + o2::ccdb::CcdbApi mApi; + mApi.init(ccdburl); + mApi.storeAsBinaryFile( + &image->at(0), image->size(), info.getFileName(), info.getObjectType(), + info.getPath(), info.getMetaData(), + info.getStartValidityTimestamp(), info.getEndValidityTimestamp()); + o2::ccdb::adjustOverriddenEOV(mApi, info); + } else { + LOG(warning) << "PrepareOutputCcdb called with empty arguments for TimeDeadMap. Doing nothing."; + } } else { - ec->outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TimeDeadMap", 0}, *image.get()); - ec->outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "TimeDeadMap", 0}, info); + LOG(warning) << "Time-dependent dead map is empty and will not be forwarded as output"; } } - else if (!ccdburl.empty()) { // send from this workflow - - LOG(important) << mSelfName << " sending object " << ccdburl << "/browse/" << info.getPath() << "/" << info.getFileName() - << " of size " << image->size() << " bytes, valid for " - << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); - - o2::ccdb::CcdbApi mApi; - mApi.init(ccdburl); - mApi.storeAsBinaryFile( - &image->at(0), image->size(), info.getFileName(), info.getObjectType(), - info.getPath(), info.getMetaData(), - info.getStartValidityTimestamp(), info.getEndValidityTimestamp()); - o2::ccdb::adjustOverriddenEOV(mApi, info); - } - - else { - - LOG(warning) << "PrepareOutputCcdb called with empty arguments. Doing nothing."; + // ---- StuckPixelData ---- + // ITS-only CCDB payload. Empty objects are intentionally allowed when + // the feature is enabled, since this object is meant to record the result + // of the checked data sample rather than a mandatory calibration for all runs. + if (mDoStuckPixels) { + std::string name_sp = "StuckPixels"; + + o2::ccdb::CcdbObjectInfo info_sp( + (path + name_sp), + name_sp, + mStuckPixelFileName, + md, + mTimeStart - 120 * 1000, + tend + 60 * 1000); + + auto image_sp = o2::ccdb::CcdbApi::createObjectImage(&mStuckPixelData, &info_sp); + info_sp.setFileName(mStuckPixelFileName); + info_sp.setAdjustableEOV(); + + LOG(info) << "StuckPixelData contains " << mStuckPixelData.size() + << " entries (" << image_sp->size() + << " bytes), publishing to " << path + name_sp; + + if (ec != nullptr) { + ec->outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "StuckPixels", 0}, *image_sp.get()); + ec->outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "StuckPixels", 0}, info_sp); + } else if (!ccdburl.empty()) { + LOG(important) << mSelfName << " sending StuckPixelData to " + << ccdburl << "/browse/" << info_sp.getPath(); + + o2::ccdb::CcdbApi mApi_sp; + mApi_sp.init(ccdburl); + mApi_sp.storeAsBinaryFile( + &image_sp->at(0), image_sp->size(), info_sp.getFileName(), info_sp.getObjectType(), + info_sp.getPath(), info_sp.getMetaData(), + info_sp.getStartValidityTimestamp(), info_sp.getEndValidityTimestamp()); + o2::ccdb::adjustOverriddenEOV(mApi_sp, info_sp); + } else { + LOG(warning) << "PrepareOutputCcdb called with empty arguments for StuckPixels. Doing nothing."; + } } return; } ////////////////////////////////////////////////////////////////////////////// -// O2 functionality allowing to do post-processing when the upstream device -// tells that there will be no more input data void ITSMFTDeadMapBuilder::endOfStream(EndOfStreamContext& ec) { if (!isEnded) { LOG(info) << "endOfStream report: " << mSelfName; finalizeOutput(); - if (mMapObject.getEvolvingMapSize() > 0) { - PrepareOutputCcdb(&ec); - } else { - LOG(warning) << "Time-dependent dead map is empty and will not be forwarded as output"; - } + PrepareOutputCcdb(&ec); LOG(info) << "Stop process of new data because of endOfStream"; isEnded = true; } @@ -381,7 +492,6 @@ void ITSMFTDeadMapBuilder::endOfStream(EndOfStreamContext& ec) } ////////////////////////////////////////////////////////////////////////////// -// DDS stop method: create local output if endOfStream not processed void ITSMFTDeadMapBuilder::stop() { if (!isEnded) { @@ -389,7 +499,8 @@ void ITSMFTDeadMapBuilder::stop() finalizeOutput(); if (!mCCDBUrl.empty()) { std::string detname = mRunMFT ? "MFT" : "ITS"; - LOG(warning) << "endOfStream not processed. Sending output to ccdb from the " << detname << " deadmap builder workflow."; + LOG(warning) << "endOfStream not processed. Sending output to ccdb from the " + << detname << " deadmap builder workflow."; PrepareOutputCcdb(nullptr, mCCDBUrl); } else { LOG(alarm) << "endOfStream not processed. Nothing forwarded as output."; @@ -421,13 +532,25 @@ DataProcessorSpec getITSMFTDeadMapBuilderSpec(std::string datasource, bool doMFT } else if (datasource == "chipsstatus") { inputs.emplace_back("elements", detOrig, "CHIPSSTATUS", 0, Lifetime::Timeframe); } else { - return DataProcessorSpec{0x0}; // TODO: ADD PROTECTION + return DataProcessorSpec{0x0}; + } + + // ITS-only input for stuck-pixel collection. + // MFT is left unchanged and does not declare the StuckPixels-related input. + if (!doMFT) { + inputs.emplace_back("repErr", detOrig, "ErrorInfo", 0, Lifetime::Timeframe); } std::vector outputs; outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "TimeDeadMap"}, Lifetime::Sporadic); outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "TimeDeadMap"}, Lifetime::Sporadic); + // ITS-only output for the new StuckPixels CCDB object. + if (!doMFT) { + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "StuckPixels"}, Lifetime::Sporadic); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "StuckPixels"}, Lifetime::Sporadic); + } + std::string detector = doMFT ? "mft" : "its"; std::string objectname_default = detector + "_time_deadmap.root"; @@ -436,17 +559,21 @@ DataProcessorSpec getITSMFTDeadMapBuilderSpec(std::string datasource, bool doMFT inputs, outputs, AlgorithmSpec{adaptFromTask(datasource, doMFT)}, - Options{{"tf-sampling", VariantType::Int, 350, {"Process every Nth TF. Selection according to first TF orbit."}}, - {"tf-sampling-tolerance", VariantType::Int, 20, {"Tolerance on the tf-sampling value (sliding window size)."}}, - {"tf-sampling-history-size", VariantType::Int, 1000, {"Do not check if new TF is contained in a window that is older than N steps."}}, - {"tf-length", VariantType::Int, 32, {"Orbits per TF."}}, - {"skip-static-map", VariantType::Bool, false, {"Do not fill static part of the map."}}, - {"no-group-its-lanes", VariantType::Bool, false, {"Do not group ITS OB chips into lanes."}}, - {"ccdb-url", VariantType::String, "", {"CCDB url. Ignored if endOfStream is processed."}}, - {"outfile", VariantType::String, objectname_default, {"ROOT object file name."}}, - {"local-output", VariantType::Bool, false, {"Save ROOT tree file locally."}}, - {"output-dir", VariantType::String, "./", {"ROOT tree local output directory."}}}}; + Options{ + {"tf-sampling", VariantType::Int, 350, {"Process every Nth TF. Selection according to first TF orbit."}}, + {"tf-sampling-tolerance", VariantType::Int, 20, {"Tolerance on the tf-sampling value (sliding window size)."}}, + {"tf-sampling-history-size", VariantType::Int, 1000, {"Do not check if new TF is contained in a window that is older than N steps."}}, + {"tf-length", VariantType::Int, 32, {"Orbits per TF."}}, + {"skip-static-map", VariantType::Bool, false, {"Do not fill static part of the map."}}, + {"no-group-its-lanes", VariantType::Bool, false, {"Do not group ITS OB chips into lanes."}}, + {"ccdb-url", VariantType::String, std::string(""), {"CCDB url. Ignored if endOfStream is processed."}}, + {"outfile", VariantType::String, objectname_default, {"ROOT object file name."}}, + {"local-output", VariantType::Bool, false, {"Save ROOT file locally."}}, + {"output-dir", VariantType::String, std::string("./"), {"Local output directory."}}, + {"save-stuck-pixels", VariantType::String, std::string(""), + {"Enable ITS stuck-pixel collection and set the CCDB/local ROOT filename. Empty = disabled."}}, + }}; } } // namespace itsmft -} // namespace o2 +} // namespace o2 \ No newline at end of file