diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index bc9883747a0e9aad120c691a3071046e81d13912..a2a052fa4026f62246d4be605c6a50c2217bf65a 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -154,6 +154,8 @@ set(SRCS qa/QaData.cxx qa/RecoGeneralQa.cxx qa/QaManager.cxx + qa/hitfind/BmonHitfindQa.cxx + qa/hitfind/BmonHitfindQaParameters.cxx qa/unpack/StsDigiQa.cxx ca/TrackingSetup.cxx ca/TrackingChain.cxx @@ -191,6 +193,7 @@ target_include_directories(Algo ${CMAKE_CURRENT_SOURCE_DIR}/detectors ${CMAKE_CURRENT_SOURCE_DIR}/qa ${CMAKE_CURRENT_SOURCE_DIR}/qa/unpack + ${CMAKE_CURRENT_SOURCE_DIR}/qa/hitfind ${CMAKE_CURRENT_SOURCE_DIR}/kf ${CMAKE_CURRENT_SOURCE_DIR}/kf/core ${CMAKE_CURRENT_SOURCE_DIR}/kf/core/utils diff --git a/algo/ca/qa/CaQa.h b/algo/ca/qa/CaQa.h index 655d6fa50b16a9dac1133223ebafb56abeef08e7..1c42b60562f19c5adf5274c045971fe9bda330bf 100644 --- a/algo/ca/qa/CaQa.h +++ b/algo/ca/qa/CaQa.h @@ -54,7 +54,7 @@ namespace cbm::algo::ca static constexpr HitSetArray_t<EHitSet> kHitSets = {EHitSet::Input, EHitSet::Used}; public: - /// \brief Default destructor + /// \brief Constructor /// \param pManager Pointer to the QA manager /// \param name Name of the QA (directory) Qa(const std::unique_ptr<qa::Manager>& pManager, std::string_view name) : qa::TaskHeader(pManager, name) {} diff --git a/algo/detectors/bmon/Calibrate.cxx b/algo/detectors/bmon/Calibrate.cxx index 1a2a6af79d13a522eaf08ffcf6072ccefdc70852..d5519854902605e3c84e77f584324d3811c88d04 100644 --- a/algo/detectors/bmon/Calibrate.cxx +++ b/algo/detectors/bmon/Calibrate.cxx @@ -77,8 +77,8 @@ Calibrate::resultType Calibrate::operator()(gsl::span<const CbmBmonDigi> digiIn) // --- Output data resultType result = {}; - auto& calDigiOut = result.first; - auto& monitor = result.second; + auto& calDigiOut = std::get<0>(result); + auto& monitor = std::get<1>(result); calDigiOut.reserve(digiIn.size()); // Reset the channel dead time diff --git a/algo/detectors/bmon/Calibrate.h b/algo/detectors/bmon/Calibrate.h index 0e602e6b4cc1b626c768b006c001c541aef5b8db..644fd203200dbceeac0402248b5cf3a2943be3c3 100644 --- a/algo/detectors/bmon/Calibrate.h +++ b/algo/detectors/bmon/Calibrate.h @@ -30,7 +30,7 @@ namespace cbm::algo::bmon /// \brief Algorithm to calibrate BMon digis class Calibrate { public: - using resultType = std::pair<std::vector<CbmBmonDigi>, CalibrateMonitorData>; + using resultType = std::tuple<std::vector<CbmBmonDigi>, CalibrateMonitorData>; /// \brief Constructor /// \param params Calibration parameters diff --git a/algo/detectors/bmon/Clusterizer.cxx b/algo/detectors/bmon/Clusterizer.cxx index 2d48416e35b526462ee7b8ef9bcb2d15086015cf..d3a8e3d4abf18a8a9e1e727606fd08a187afdf88 100644 --- a/algo/detectors/bmon/Clusterizer.cxx +++ b/algo/detectors/bmon/Clusterizer.cxx @@ -67,6 +67,7 @@ Clusterizer::Output_t Clusterizer::operator()(const Clusterizer::Input_t& digis) hits.emplace_back(fParams.fAddress, itLast->first); digiIndices.emplace_back(itLast->second); } + return res; } diff --git a/algo/detectors/bmon/Hitfind.cxx b/algo/detectors/bmon/Hitfind.cxx index b1e6794c8e0291231e2fb2e87d51d6ce92f0bb38..d39a46f6c4bf9faf4bfbe2425557ef85ba02664a 100644 --- a/algo/detectors/bmon/Hitfind.cxx +++ b/algo/detectors/bmon/Hitfind.cxx @@ -86,6 +86,7 @@ Hitfind::Output_t Hitfind::operator()(gsl::span<CbmBmonDigi> digisIn, uint32_t i // Distribute digis over diamonds, apply cuts on this level (maybe the Calibrator is a more proper place for it) size_t nDiamonds = algoPerThread.size(); auto vDigiStorage = std::vector<Clusterizer::Input_t>(nDiamonds, Clusterizer::Input_t(0)); + for (int32_t iDigi = 0; iDigi < static_cast<int32_t>(digisIn.size()); ++iDigi) { const auto& digi = digisIn[iDigi]; size_t iDiamond = GetDiamondIndex(digi.GetAddress()); diff --git a/algo/detectors/bmon/HitfindSetup.h b/algo/detectors/bmon/HitfindSetup.h index c98cc163ff616f0f0e0b8a55158ea224ebf9cbb6..c958cbc17ca2ffcdc2f5027a42f3e6f8f09b1e22 100644 --- a/algo/detectors/bmon/HitfindSetup.h +++ b/algo/detectors/bmon/HitfindSetup.h @@ -7,6 +7,7 @@ /// \since 06.02.2025 /// \author Sergei Zharko <s.zharko@gsi.de> +#pragma once #include "Definitions.h" #include "yaml/Property.h" diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index 5b2698cb3f2f0c2928165baaa30abfcf298040fe..8460ea28bf34fa71071601370839602433199058 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -24,6 +24,7 @@ #include "evbuild/Config.h" #include "much/Unpack.h" #include "qa/QaManager.h" +#include "qa/hitfind/BmonHitfindQa.h" #include "rich/Unpack.h" #include "sts/ChannelMaskSet.h" #include "sts/HitfinderChain.h" @@ -217,6 +218,12 @@ void Reco::Init(const Options& opts) auto hitfindSetup = yaml::ReadFromFile<bmon::HitfindSetup>(opts.ParamsDir() / parFiles.bmon.hitfinder); fBmonHitFinder = std::make_unique<bmon::Hitfind>(hitfindSetup); + + if (fQaManager != nullptr && Opts().Has(QaStep::RecoBmon)) { + fBmonHitFinderQa = std::make_unique<bmon::HitfindQa>(fQaManager, "BmonHitfindEvent"); + fBmonHitFinderQa->InitParameters(calibSetup, hitfindSetup); + fBmonHitFinderQa->Init(); + } } // TOF Hitfinder @@ -236,7 +243,7 @@ void Reco::Init(const Options& opts) // Tracking if (Opts().Has(Step::Tracking)) { - if (Opts().Has(QaStep::Tracking)) { + if (fQaManager != nullptr && Opts().Has(QaStep::Tracking)) { fTracking = std::make_unique<TrackingChain>(fQaManager, "CaTimeslice"); } else { @@ -389,24 +396,18 @@ RecoResults Reco::Run(const fles::Timeslice& ts) // ***** DEBUG: BEGIN if constexpr (0) { int nEvents = events.size(); - size_t nBmonHitsOneChannel{0}; - size_t nBmonHitsTwoChannels{0}; for (int iE = 0; iE < nEvents; ++iE) { const auto& event = events[iE]; // Calibrate TOF digis: auto [bmonDigis, bmonCalMonitor] = (*fBmonCalibrator)(event.fBmon); - auto [bmonHits, hitmonitor, digiindices] = (*fBmonHitFinder)(bmonDigis); - for (const auto& hit : bmonHits.Data()) { - if (hit.GetNofChannels() == 1) { - ++nBmonHitsOneChannel; - } - else { - ++nBmonHitsTwoChannels; - } + auto [bmonHits, hitmonitor, digiIndices] = (*fBmonHitFinder)(bmonDigis); + if (fBmonHitFinderQa != nullptr) { + fBmonHitFinderQa->RegisterDigis(&bmonDigis); + fBmonHitFinderQa->RegisterHits(&bmonHits); + fBmonHitFinderQa->RegisterDigiIndices(&digiIndices); + fBmonHitFinderQa->Exec(); } } - L_(info) << "!!!! BMON hits with two channels: " << nBmonHitsTwoChannels << " / " - << (nBmonHitsTwoChannels + nBmonHitsOneChannel); } // ***** DEBUG: END diff --git a/algo/global/Reco.h b/algo/global/Reco.h index 19027c8368b9fe496282f40eca52eaff22f339d6..6182decdad9d289e7a654aabbb6b5db8650efe29 100644 --- a/algo/global/Reco.h +++ b/algo/global/Reco.h @@ -29,6 +29,7 @@ namespace cbm::algo class Unpack; class Calibrate; class Hitfind; + class HitfindQa; } namespace much @@ -150,6 +151,7 @@ namespace cbm::algo std::unique_ptr<bmon::Unpack> fBmonUnpack; std::unique_ptr<bmon::Calibrate> fBmonCalibrator; std::unique_ptr<bmon::Hitfind> fBmonHitFinder; + std::unique_ptr<bmon::HitfindQa> fBmonHitFinderQa; // MUCH std::unique_ptr<much::Unpack> fMuchUnpack; diff --git a/algo/qa/PadConfig.h b/algo/qa/PadConfig.h index 4d6ac5376c121a618601111ff3aa1d6d07deba09..104b2144263b06834952557d14d3b30d21e6197a 100644 --- a/algo/qa/PadConfig.h +++ b/algo/qa/PadConfig.h @@ -43,6 +43,15 @@ namespace cbm::algo::qa { } + /// \brief Constructor from a single histogram + /// \tparam Hist Histogram class + /// \param hist Histogram object + /// \param opt Draw options for the histogram + template<class Hist> + PadConfig(const Hist* hist, std::string_view opt) + { + RegisterHistogram(hist, opt); + } /// \brief Copy constructor PadConfig(const PadConfig&) = default; @@ -104,11 +113,11 @@ namespace cbm::algo::qa std::string ToString() const; private: - bool fbGridX = false; ///< Grid flag for x-axis - bool fbGridY = false; ///< Grid flag for y-axis - bool fbLogX = false; ///< Log flag for x-axis - bool fbLogY = false; ///< Log flag for y-axis - bool fbLogZ = false; ///< Log flag for z-axis + bool fbGridX{false}; ///< Grid flag for x-axis + bool fbGridY{false}; ///< Grid flag for y-axis + bool fbLogX{false}; ///< Log flag for x-axis + bool fbLogY{false}; ///< Log flag for y-axis + bool fbLogZ{false}; ///< Log flag for z-axis std::vector<std::pair<std::string, std::string>> fvObjectList; ///< List of objects on the pad }; diff --git a/algo/qa/QaTaskHeader.h b/algo/qa/QaTaskHeader.h index ca41383152a066fd98b79293f874428cd53fb350..ceb03e5ad457c9b6ceecb1145c7a5f4c15f262b9 100644 --- a/algo/qa/QaTaskHeader.h +++ b/algo/qa/QaTaskHeader.h @@ -24,7 +24,8 @@ namespace cbm::algo::qa /// \param pManager a QA-manager /// \param name A name of the task (histograms directory) TaskHeader(const std::unique_ptr<Manager>& pManager, std::string_view name) - : fpData(pManager != nullptr ? pManager->GetData() : nullptr) + : fsName(name) + , fpData(pManager != nullptr ? pManager->GetData() : nullptr) { if (fpData != nullptr) { fpData->RegisterNewTask(name); @@ -52,6 +53,9 @@ namespace cbm::algo::qa /// the fpData instance is not defined, and no actions on the task should be performed bool IsActive() const { return static_cast<bool>(fpData != nullptr); } + /// \brief Gets name of the task + const std::string& GetTaskName() { return fsName; } + protected: /// \brief Adds a canvas configuration /// \param canvas A CanvasConfig object @@ -68,6 +72,7 @@ namespace cbm::algo::qa } private: + std::string fsName{}; ///< Name of the task std::shared_ptr<Data> fpData{nullptr}; ///< An instance of the QA data (shared between different tasks) }; } // namespace cbm::algo::qa diff --git a/algo/qa/hitfind/BmonHitfindQa.cxx b/algo/qa/hitfind/BmonHitfindQa.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0bf088900f35ef7f55b6ce59f311bda818dee011 --- /dev/null +++ b/algo/qa/hitfind/BmonHitfindQa.cxx @@ -0,0 +1,112 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file BmonHitfindQa.cxx +/// \brief A BMON hitfinder QA (implementation) +/// \since 09.02.2025 +/// \author Sergei Zharko <s.zharko@gsi.de> + +#include "qa/hitfind/BmonHitfindQa.h" + +#include "CbmBmonDigi.h" +#include "CbmTofAddress.h" +#include "bmon/Hit.h" +#include "qa/Histogram.h" + +#include <fmt/format.h> + +using cbm::algo::bmon::HitfindQa; + +// --------------------------------------------------------------------------------------------------------------------- +// +void HitfindQa::Init() +try { + using fmt::format; + if (!IsActive()) { + return; + } + + size_t nDiamonds = fParameters.diamonds.size(); + if (nDiamonds < 1) { + throw std::runtime_error("parameters were not initialized. Please, provide the configuration using the function " + "HitfindQa::InitParameters(calSetup, hitSetup)"); + } + + fvphDigiOccupVsChan.resize(nDiamonds, nullptr); + fvphDigiChargeVsChan.resize(nDiamonds, nullptr); + fvphHitNofChan.resize(nDiamonds, nullptr); + fvphHitTimeDiff.resize(nDiamonds, nullptr); + + for (size_t iD = 0; iD < nDiamonds; ++iD) { + const auto& diamondPar = fParameters.diamonds[iD]; + int nCh = diamondPar.nChannels; + auto sDN = format("_diamond_{:#08x}", diamondPar.address); // diamond suffix + + // Histograms initialisation + /* clang-format off */ + fvphDigiOccupVsChan[iD] = MakeObj<qa::H1D>( + format("bmon_digi_occup_channel{}", sDN), + format("BMON-{} digi occupancy vs. channel;channel;counts", iD), + nCh, -0.5, nCh - 0.5); + fvphDigiChargeVsChan[iD] = MakeObj<qa::H2D>( + format("bmon_digi_charge_channel{}", sDN), + format("BMON-{} digi charge vs. channel;channel;charge;counts", iD), + nCh, -0.5, nCh - 0.5, kChrgB, kChrgL, kChrgU); + fvphHitNofChan[iD] = MakeObj<qa::H1D>( + format("bmon_hit_nChannels{}", sDN), + format("BMON-{} hit number of channels;N_{{chan}};counts", iD), + 2, 0.5, 2.5); + fvphHitTimeDiff[iD] = MakeObj<qa::H1D>( + format("bmon_hit_time_diff{}", sDN), + format("BMON-{} digi time difference in a hit formed from two digis;#Delta t_{{digi}} [ns];counts", iD), + kDtimeB, kDtimeL, kDtimeU); + /* clang-format on */ + + // Canvas initialization + auto cName = format("{}/bmon{}", GetTaskName(), sDN); + auto cTitl = format("BMON-{}", iD); + auto canv = qa::CanvasConfig(cName, cTitl, 2, 2); + canv.AddPadConfig(qa::PadConfig(fvphDigiOccupVsChan[iD], "hist")); // (0,0) + canv.AddPadConfig(qa::PadConfig(fvphDigiChargeVsChan[iD], "colz")); // (1,0) + canv.AddPadConfig(qa::PadConfig(fvphHitNofChan[iD], "hist")); // (0,1) + canv.AddPadConfig(qa::PadConfig(fvphHitTimeDiff[iD], "hist")); // (1,1) + AddCanvasConfig(canv); + } +} +catch (const std::exception& err) { + L_(fatal) << "bmon::HitfindQa: initialization failed. Reason: " << err.what(); + throw std::runtime_error("bmon::HitfindQa initialization failure"); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void HitfindQa::Exec() +{ + if (!IsActive()) { + return; + } + + // Fill digi distributions + for (const auto& digi : *fpDigis) { + size_t iDiamond = fParameters.GetDiamondIndex(digi.GetAddress()); + int32_t chan = digi.GetChannel(); + fvphDigiOccupVsChan[iDiamond]->Fill(chan); + fvphDigiChargeVsChan[iDiamond]->Fill(chan, digi.GetCharge()); + } + + // Fill hit distributions + const auto& hits = fpHits->Data(); + for (size_t iH = 0; iH < hits.size(); ++iH) { + const auto& hit = hits[iH]; + size_t iDiamond = fParameters.GetDiamondIndex(hit.GetAddress()); + int nChannels = hit.GetNofChannels(); + fvphHitNofChan[iDiamond]->Fill(nChannels); + if (nChannels == 2) { + int32_t iDigi = (*fpDigiIndices)[iH]; + const auto& digiF = (*fpDigis)[iDigi]; + const auto& digiS = (*fpDigis)[iDigi + 1]; + fvphHitTimeDiff[iDiamond]->Fill(digiS.GetTime() - digiF.GetTime()); + } + } +} diff --git a/algo/qa/hitfind/BmonHitfindQa.h b/algo/qa/hitfind/BmonHitfindQa.h new file mode 100644 index 0000000000000000000000000000000000000000..020f62fa821a2c8ec298c8aa758684aee023cc21 --- /dev/null +++ b/algo/qa/hitfind/BmonHitfindQa.h @@ -0,0 +1,112 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file BmonHitfindQa.h +/// \brief A BMON hitfinder QA +/// \since 07.02.2025 +/// \author Sergei Zharko <s.zharko@gsi.de> + +#pragma once + +#include "PODVector.h" +#include "PartitionedVector.h" +#include "qa/QaTaskHeader.h" +#include "qa/hitfind/BmonHitfindQaParameters.h" + +class CbmBmonDigi; + +namespace cbm::algo +{ + namespace qa + { + class H1D; + class H2D; + } // namespace qa + + namespace bmon + { + class Hit; + } +} // namespace cbm::algo + +namespace cbm::algo::bmon +{ + /// \class HitfindQa + /// \brief A QA module for the BMON hit-finder + /// \param pManager Pointer to the QA manager + /// \param name Name of the QA (directory) + class HitfindQa : public qa::TaskHeader { + public: + /// \brief Constructor + /// \param pManager Pointer to the QA manager + /// \param name Name of the QA (directory) + HitfindQa(const std::unique_ptr<qa::Manager>& pManager, std::string_view name) : qa::TaskHeader(pManager, name) {} + + /// \brief Constructor from the configuration object + /// \param config QA configuration object + HitfindQa() = default; + + /// \brief Copy constructor + HitfindQa(const HitfindQa&) = delete; + + /// \brief Move constructor + HitfindQa(HitfindQa&&) = delete; + + /// \brief Destructor + ~HitfindQa() = default; + + /// \brief Copy assignment operator + HitfindQa& operator=(const HitfindQa&) = delete; + + /// \brief Move assignment operator + HitfindQa& operator=(HitfindQa&&) = delete; + + /// \brief Executes the task, fills the histograms + void Exec(); + + /// \brief Initialized the task + void Init(); + + /// \brief Initialisation of the parameters + void InitParameters(const CalibrateSetup& calSetup, const HitfindSetup& hitSetup) + { + fParameters = std::move(HitfindQaParameters(calSetup, hitSetup)); + } + + /// \brief Registers a sample of digis + /// \param pDigis A pointer to a vector of digis + void RegisterDigis(const std::vector<CbmBmonDigi>* pDigis) { fpDigis = pDigis; } + + /// \brief Registers a sample of hits + /// \param pHits A pointer to a vector of hits + void RegisterHits(const PartitionedVector<bmon::Hit>* pHits) { fpHits = pHits; } + + /// \brief Registers a sample of digi indices, used by hits + /// \param pDigiIndices A pointer to a vector of digi indices + void RegisterDigiIndices(const PODVector<int32_t>* pDigiIndices) { fpDigiIndices = pDigiIndices; } + + private: + //* Constants + static constexpr int kChrgB = 150; ///< charge scale: number of bins + static constexpr double kChrgL = 0.; ///< charge scale: lower bound + static constexpr double kChrgU = 150.; ///< charge scale: upper bound + static constexpr int kDtimeB = 40; ///< digi time difference: number of bins + static constexpr double kDtimeL = 0.; ///< digi time difference: lower bound [ns] + static constexpr double kDtimeU = 2.0; ///< digi time difference: upper bound [ns] + + //* Parameters + HitfindQaParameters fParameters; ///< Parameters of the hit finder QA + + //* Data samples + const std::vector<CbmBmonDigi>* fpDigis{nullptr}; ///< Pointer to BMON digi sample + const PartitionedVector<bmon::Hit>* fpHits{nullptr}; ///< Pointer to BMON hit sample + const PODVector<int32_t>* fpDigiIndices{nullptr}; ///< Pointer to BMON digi indices, used by hits + + //* Histograms + std::vector<qa::H1D*> fvphDigiOccupVsChan; ///< Digi occupancy vs. channel [diamond] + std::vector<qa::H2D*> fvphDigiChargeVsChan; ///< Digi charge vs channel [diamond] + std::vector<qa::H1D*> fvphHitNofChan; ///< Hit number of channels [diamond] + std::vector<qa::H1D*> fvphHitTimeDiff; ///< Time difference of two digis in a hit [diamond] + }; +} // namespace cbm::algo::bmon diff --git a/algo/qa/hitfind/BmonHitfindQaParameters.cxx b/algo/qa/hitfind/BmonHitfindQaParameters.cxx new file mode 100644 index 0000000000000000000000000000000000000000..aa7f4aadce0f8e7cad631de165f789177a02c4c9 --- /dev/null +++ b/algo/qa/hitfind/BmonHitfindQaParameters.cxx @@ -0,0 +1,58 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file BmonHitfindQaParameters.cxx +/// \brief A BMON hitfinder QA parameter configuration (implementation) +/// \since 10.02.2025 +/// \author Sergei Zharko <s.zharko@gsi.de> + +#include "qa/hitfind/BmonHitfindQaParameters.h" + +#include "AlgoFairloggerCompat.h" +#include "CbmTofAddress.h" + +using cbm::algo::bmon::CalibrateSetup; +using cbm::algo::bmon::HitfindQaParameters; +using cbm::algo::bmon::HitfindSetup; + +// --------------------------------------------------------------------------------------------------------------------- +// +HitfindQaParameters::HitfindQaParameters(const CalibrateSetup& calSetup, const HitfindSetup& hitSetup) +{ + + this->selectionMask = calSetup.selectionMask; + if (this->selectionMask != hitSetup.selectionMask) { + throw std::runtime_error("Mismatch of the selection bitmask in the BMON CalibrateSetup and HitfindSetup configs"); + } + + auto nDiamonds = calSetup.diamonds.size(); + if (nDiamonds != hitSetup.diamonds.size()) { + throw std::runtime_error("Mismatch of number of diamonds in the BMON CalibrateSetup and HitfindSetup configs"); + } + + if (nDiamonds > 1) { + while (!((this->selectionMask >> fSelectionBitsOffset) % 2)) { + ++fSelectionBitsOffset; + } + } + + this->diamonds.resize(nDiamonds); + for (const auto& calDiamond : calSetup.diamonds) { + uint32_t address = calDiamond.refAddress & ~CbmTofAddress::GetChannelIdBitmask(); + auto& thisDiamond = this->diamonds[GetDiamondIndex(address)]; + thisDiamond.address = address; + thisDiamond.nChannels = calDiamond.chanPar.size(); + } + + for (const auto& hitDiamond : hitSetup.diamonds) { + int32_t address = hitDiamond.refAddress & ~CbmTofAddress::GetChannelIdBitmask(); + auto& thisDiamond = this->diamonds[GetDiamondIndex(address)]; + if (thisDiamond.address != address) { + throw std::runtime_error("Mismatch between diamond addresses in BMON CalibrateSetup and HitfindSetup configs"); + } + thisDiamond.deadStrips = hitDiamond.deadStrips; + thisDiamond.timeRes = hitDiamond.timeRes; + thisDiamond.maxTimeDist = hitDiamond.maxTimeDist; + } +} diff --git a/algo/qa/hitfind/BmonHitfindQaParameters.h b/algo/qa/hitfind/BmonHitfindQaParameters.h new file mode 100644 index 0000000000000000000000000000000000000000..25f524ba87945024350ed277757e8856f1eb6de6 --- /dev/null +++ b/algo/qa/hitfind/BmonHitfindQaParameters.h @@ -0,0 +1,50 @@ +/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file BmonHitfindQaParameters.h +/// \brief A BMON hitfinder QA parameter configuration +/// \since 10.02.2025 +/// \author Sergei Zharko <s.zharko@gsi.de> + +#pragma once + +#include "bmon/CalibrateSetup.h" +#include "bmon/HitfindSetup.h" + +#include <vector> + +namespace cbm::algo::bmon +{ + /// \struct HitfindQaParameters + /// \brief A structure to handle BMON QA parameters + struct HitfindQaParameters { + /// \struct Diamond + /// \brief A diamond representation + struct Diamond { + double timeRes{0.}; ///< Time resolution [ns] + double maxTimeDist{0.}; ///< Max time distance between digis in a hit [ns] + int32_t address{0}; ///< Address of a diamond + int32_t nChannels{0}; ///< Number of channels in a diamond + uint32_t deadStrips{0}; ///< A bit mask of dead strips + }; + + uint32_t selectionMask{0}; ///< A bitmask to distinguish different diamonds + std::vector<Diamond> diamonds{}; + + /// \brief Default constructor + HitfindQaParameters() = default; + + /// \brief Constructor + /// \param calSetup Calibration parameters + /// \param hitSetup Hitfinder parameters + HitfindQaParameters(const CalibrateSetup& calSetup, const HitfindSetup& hitSetup); + + /// \brief Returns an index of the diamond by the address + /// \param address A hardware address of the digi + size_t GetDiamondIndex(uint32_t address) const { return ((selectionMask & address) >> fSelectionBitsOffset); } + + private: + uint32_t fSelectionBitsOffset{0}; ///< Number of bits to the right from the first bit in the selection mask + }; +} // namespace cbm::algo::bmon