From 531a0611b2cd3d39ac4e8fbf4ba9cdb2e9fc37da Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Thu, 29 Feb 2024 05:57:02 +0100 Subject: [PATCH] cbm::algo::qa::Histogram is applied to the online QA and histogram server This commit introduces modifications to: - online digi-event builder QA (replacement of Histo1D with qa::H1D) - online tracking QA - histogram server (added 2D histograms) - histogram server tester (message initialization is replaced with qa::Data) --- algo/CMakeLists.txt | 6 +- algo/base/HistogramSender.h | 2 +- algo/ca/TrackingChain.cxx | 3 +- algo/ca/TrackingChain.h | 3 +- algo/ca/qa/CaQaBuilder.cxx | 66 ++++++++---- algo/ca/qa/CaQaBuilder.h | 59 +++++----- algo/ca/qa/CaQaConfig.cxx | 86 --------------- algo/ca/qa/CaQaConfig.h | 61 ----------- algo/ca/qa/CaQaData.cxx | 38 ------- algo/ca/qa/CaQaData.h | 63 ----------- algo/ca/qa/CaQaDefinitions.h | 59 ---------- algo/evbuild/EventbuildChain.cxx | 11 +- algo/qa/CanvasConfig.cxx | 4 +- algo/qa/CanvasConfig.h | 2 +- algo/qa/DigiEventQa.cxx | 15 +-- algo/qa/DigiEventQa.h | 13 ++- algo/qa/Histogram.h | 20 +++- algo/qa/HistogramContainer.cxx | 24 +++++ algo/qa/HistogramContainer.h | 38 +++++++ algo/qa/PadConfig.cxx | 2 +- algo/qa/PadConfig.h | 8 +- algo/qa/QaData.cxx | 40 ++++--- algo/qa/QaData.h | 38 ++++--- reco/tasks/CbmTaskDigiEventQa.cxx | 16 ++- reco/tasks/CbmTaskDigiEventQa.h | 6 +- services/histserv/app/Application.cxx | 65 ++++++++---- services/histserv/tester/Application.cxx | 130 ++++++++++------------- services/histserv/tester/Application.h | 27 ++--- 28 files changed, 354 insertions(+), 551 deletions(-) delete mode 100644 algo/ca/qa/CaQaConfig.cxx delete mode 100644 algo/ca/qa/CaQaConfig.h delete mode 100644 algo/ca/qa/CaQaData.cxx delete mode 100644 algo/ca/qa/CaQaData.h delete mode 100644 algo/ca/qa/CaQaDefinitions.h create mode 100644 algo/qa/HistogramContainer.cxx create mode 100644 algo/qa/HistogramContainer.h diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index 26ef7d4404..72869ece11 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -123,13 +123,12 @@ set(SRCS global/RecoResultsOutputArchive.cxx qa/DigiEventQa.cxx qa/Histo1D.cxx + qa/HistogramContainer.cxx qa/CanvasConfig.cxx qa/PadConfig.cxx qa/QaData.cxx ca/TrackingChain.cxx ca/qa/CaQaBuilder.cxx - ca/qa/CaQaConfig.cxx - ca/qa/CaQaData.cxx ) set(BUILD_INFO_CXX ${CMAKE_CURRENT_BINARY_DIR}/base/BuildInfo.cxx) @@ -248,9 +247,6 @@ install( # NOTE: SZh 20.11.2023: # The ca/qa directory depends on the online qa classes, so for now it has to be a part of the Algo library. ca/qa/CaQaBuilder.h - ca/qa/CaQaConfig.h - ca/qa/CaQaData.h - ca/qa/CaQaDefinitions.h DESTINATION include/ ) diff --git a/algo/base/HistogramSender.h b/algo/base/HistogramSender.h index b44a1bfae4..ec9847312c 100644 --- a/algo/base/HistogramSender.h +++ b/algo/base/HistogramSender.h @@ -29,7 +29,7 @@ namespace cbm::algo } /** @brief Serialize object and send it to the histogram server - ** @param obj: object to be serialized in the message, e.g. config pairs of strings or Histo1D + ** @param obj: object to be serialized in the message, e.g. config pairs of strings or QaData ** @param flags: or'ed values from zmq::send_flags, typ. zmq::send_flags::sndmore to indicate multi-parts message **/ template<typename Object> diff --git a/algo/ca/TrackingChain.cxx b/algo/ca/TrackingChain.cxx index f84d9f8fe0..b54a1dfc0a 100644 --- a/algo/ca/TrackingChain.cxx +++ b/algo/ca/TrackingChain.cxx @@ -30,13 +30,14 @@ using cbm::algo::ca::Framework; using cbm::algo::ca::HitTypes_t; using cbm::algo::ca::InitManager; using cbm::algo::ca::Parameters; +using cbm::algo::ca::QaBuilder; using cbm::algo::ca::Track; using cbm::algo::ca::constants::clrs::CL; // clear text using cbm::algo::ca::constants::clrs::GNb; // grin bald text // --------------------------------------------------------------------------------------------------------------------- // -TrackingChain::TrackingChain(std::shared_ptr<HistogramSender> histoSender) : fQaBuilder(ca::qa::Builder(histoSender)) {} +TrackingChain::TrackingChain(std::shared_ptr<HistogramSender> histoSender) : fQaBuilder(QaBuilder(histoSender)) {} // --------------------------------------------------------------------------------------------------------------------- // diff --git a/algo/ca/TrackingChain.h b/algo/ca/TrackingChain.h index 694ed96be2..43cd2b4ec9 100644 --- a/algo/ca/TrackingChain.h +++ b/algo/ca/TrackingChain.h @@ -12,7 +12,6 @@ #include "CaDataManager.h" #include "CaFramework.h" #include "CaQaBuilder.h" -#include "CaQaConfig.h" #include "CaTrack.h" #include "CaTrackingMonitor.h" #include "CaVector.h" @@ -101,7 +100,7 @@ namespace cbm::algo ca::TrackingMonitorData fCaMonitorData{}; ///< CA monitor data object ca::Framework fCaFramework{}; ///< CA framework instance ca::DataManager fCaDataManager{}; ///< CA data manager - ca::qa::Builder fQaBuilder; ///< CA QA builder + ca::QaBuilder fQaBuilder; ///< CA QA builder // ************************ // ** Auxilary variables diff --git a/algo/ca/qa/CaQaBuilder.cxx b/algo/ca/qa/CaQaBuilder.cxx index 5a690e7fc7..87e224ef18 100644 --- a/algo/ca/qa/CaQaBuilder.cxx +++ b/algo/ca/qa/CaQaBuilder.cxx @@ -2,7 +2,7 @@ SPDX-License-Identifier: GPL-3.0-only Authors: Sergei Zharko [committer] */ -/// \file CaQaBuilder.cxx +/// \file CaQaQaBuilder.cxx /// \date 20.11.2023 /// \brief A QA module for CA tracking (implementation) /// \author S.Zharko <s.zharko@gsi.de> @@ -16,17 +16,18 @@ #include <fmt/format.h> -using cbm::algo::CanvasConfig; -using cbm::algo::Histo1D; -using cbm::algo::PadConfig; -using cbm::algo::QaData; +using cbm::algo::ca::QaBuilder; using cbm::algo::ca::constants::math::Pi; -using cbm::algo::ca::qa::Builder; +using cbm::algo::qa::CanvasConfig; +using cbm::algo::qa::Data; +using cbm::algo::qa::H1D; +using cbm::algo::qa::H2D; +using cbm::algo::qa::PadConfig; // --------------------------------------------------------------------------------------------------------------------- // -void Builder::Init() +void QaBuilder::Init() { using fmt::format; @@ -42,29 +43,35 @@ void Builder::Init() { auto sName = format("track_{}_theta", vsPointName[i]); auto sTitl = format("#theta at {} hit; #theta", vsPointName[i]); - fvphTrkTheta[i] = fQaData.MakeObj<Histo1D>(62, 0., 90., sName, sTitl); + fvphTrkTheta[i] = fQaData.MakeObj<H1D>(sName, sTitl, 62, 0., 90.); } { auto sName = format("track_{}_phi", vsPointName[i]); auto sTitl = format("#phi at {} hit; #phi", vsPointName[i]); - fvphTrkPhi[i] = fQaData.MakeObj<Histo1D>(62, -180., 180., sName, sTitl); + fvphTrkPhi[i] = fQaData.MakeObj<H1D>(sName, sTitl, 62, -180., 180.); + } + { + auto sName = format("track_{}_thata_phi", vsPointName[i]); + auto sTitl = format("#theta vs #phi at {} hit; #phi; #theta", vsPointName[i]); + fvphTrkPhiTheta[i] = fQaData.MakeObj<H2D>(sName, sTitl, 62, -180., 180., 62, 0., 90.); } { auto sName = format("track_{}_chi2_ndf", vsPointName[i]); auto sTitl = format("#chi^{{2}}/NDF at {} hit; #chi^{{2}}/NDF", vsPointName[i]); - fvphTrkChi2Ndf[i] = fQaData.MakeObj<Histo1D>(100, 0., 20., sName, sTitl); + fvphTrkChi2Ndf[i] = fQaData.MakeObj<H1D>(sName, sTitl, 100, 0., 20.); } { auto sName = format("track_{}_hit_station", vsPointName[i]); auto sTitl = format("Station of {} hit;ID_{{sta}}", vsPointName[i]); - fvphHitSta[i] = fQaData.MakeObj<Histo1D>(100, -.5, 10.5, sName, sTitl); + fvphHitSta[i] = fQaData.MakeObj<H1D>(sName, sTitl, 100, -.5, 10.5); } } - fphTrkNofHits = fQaData.MakeObj<Histo1D>(11, -0.5, 10.5, "n_hits", "Number of hits;N_{hit}"); + fphTrkNofHits = fQaData.MakeObj<H1D>("n_hits", "Number of hits;N_{hit}", 11, -0.5, 10.5); // ---- Init canvases { // Track parameters at first/last track hit + for (int i = 0; i < knTrkParPoints; ++i) { auto sCanvName = fmt::format("ca_trk_{}_hit", vsPointName[i]); auto sCanvTitl = fmt::format("Track parameters at {} hit", vsPointName[i]); @@ -86,6 +93,20 @@ void Builder::Init() fQaData.AddCanvasConfig(canv); } + { + auto sCanvName = "ca_trk_theta_phi"; + auto sCanvTitl = "Track #theta vs #phi"; + auto canv = CanvasConfig(sCanvName, sCanvTitl); + for (int i = 0; i < knTrkParPoints; ++i) { + PadConfig pad; + pad.SetLog(false, false, true); + pad.SetGrid(true, true); + pad.RegisterHistogram(fvphTrkPhiTheta[i], "colz"); + canv.AddPadConfig(pad); + } + fQaData.AddCanvasConfig(canv); + } + // Number of hits in track { auto canv = CanvasConfig("ca_nhits_in_trk", "Number of hit in track"); @@ -103,26 +124,26 @@ void Builder::Init() // --------------------------------------------------------------------------------------------------------------------- // -void Builder::Build() +void QaBuilder::Build() { if (!fpSender.get()) { return; } if (!fpParameters) { - LOG(error) << "cbm::algo::ca::qa::Builder::Build(): parameters object is undefined"; + LOG(error) << "cbm::algo::ca::QaBuilder::Build(): parameters object is undefined"; return; } if (!fpInputData) { - LOG(error) << "cbm::algo::ca::qa::Builder::Build(): input data object is undefined"; + LOG(error) << "cbm::algo::ca::QaBuilder::Build(): input data object is undefined"; return; } if (!fpvTracks) { - LOG(error) << "cbm::algo::ca::qa::Builder::Build(): tracks vector is undefined"; + LOG(error) << "cbm::algo::ca::QaBuilder::Build(): tracks vector is undefined"; return; } if (!fpvRecoHits) { - LOG(error) << "cbm::algo::ca::qa::Builder::Build(): reco hit indices vector is undefined"; + LOG(error) << "cbm::algo::ca::QaBuilder::Build(): reco hit indices vector is undefined"; return; } @@ -141,13 +162,14 @@ void Builder::Build() int iHit = (ip == 0 ? iFstHit : iLstHit); const auto& trkPar = (ip == 0 ? track.fParFirst : track.fParLast); const auto& hit = fpInputData->GetHit(iHit); - fvphTrkTheta[ip]->Add(trkPar.GetTheta() * 180. / Pi); - fvphTrkPhi[ip]->Add(trkPar.GetPhi() * 180. / Pi); - fvphTrkChi2Ndf[ip]->Add(trkPar.GetChiSq() / trkPar.GetNdf()); - fvphHitSta[ip]->Add(hit.Station()); + fvphTrkTheta[ip]->Fill(trkPar.GetTheta() * 180. / Pi); + fvphTrkPhi[ip]->Fill(trkPar.GetPhi() * 180. / Pi); + fvphTrkPhiTheta[ip]->Fill(trkPar.GetPhi() * 180. / Pi, trkPar.GetTheta() * 180. / Pi); + fvphTrkChi2Ndf[ip]->Fill(trkPar.GetChiSq() / trkPar.GetNdf()); + fvphHitSta[ip]->Fill(hit.Station()); } // Other distributions - fphTrkNofHits->Add(nHits); + fphTrkNofHits->Fill(nHits); trkFirstHit += nHits; } } diff --git a/algo/ca/qa/CaQaBuilder.h b/algo/ca/qa/CaQaBuilder.h index ff3293acdb..5fa1f2321e 100644 --- a/algo/ca/qa/CaQaBuilder.h +++ b/algo/ca/qa/CaQaBuilder.h @@ -2,7 +2,7 @@ SPDX-License-Identifier: GPL-3.0-only Authors: Sergei Zharko [committer] */ -/// \file CaQaBuilder.h +/// \file CaQaQaBuilder.h /// \date 20.11.2023 /// \brief A QA module for CA tracking (header) /// \author S.Zharko <s.zharko@gsi.de> @@ -12,52 +12,54 @@ #include "CaHit.h" // for HitIndex_t #include "CaTimesliceHeader.h" #include "CaVector.h" -#include "QaData.h" +#include "QaData.h" // QA data namespace cbm::algo { - class Histo1D; - namespace ca + namespace qa { - template<typename DataT> - class Parameters; - class InputData; - class Track; - } // namespace ca -} // namespace cbm::algo::ca - -namespace cbm::algo::ca::qa + class H1D; + class H2D; + } // namespace qa +} // namespace cbm::algo + +namespace cbm::algo::ca { - /// \class cbm::algo::ca::qa::Builder - /// \brief Builder class for the CA tracking QA (header) + template<typename DataT> + class Parameters; + class InputData; + class Track; + + /// \class cbm::algo::ca::qa::QaBuilder + /// \brief QaBuilder class for the CA tracking QA (header) /// - class Builder { + class QaBuilder { public: using TrackV_t = ca::Vector<ca::Track>; using HitIndexV_t = ca::Vector<std::vector<std::pair<uint32_t, uint32_t>>>; /// \brief Default destructor /// \param pSender Pointer to the histogram sender - Builder(std::shared_ptr<HistogramSender> pSender) : fpSender(pSender){}; + QaBuilder(std::shared_ptr<HistogramSender> pSender) : fpSender(pSender){}; /// \brief Constructor from the configuration object /// \param config QA configuration object - Builder() = default; + QaBuilder() = default; /// \brief Copy constructor - Builder(const Builder&) = delete; + QaBuilder(const QaBuilder&) = delete; /// \brief Move constructor - Builder(Builder&&) = delete; + QaBuilder(QaBuilder&&) = delete; /// \brief Destructor - ~Builder() = default; + ~QaBuilder() = default; /// \brief Copy assignment operator - Builder& operator=(const Builder&) = delete; + QaBuilder& operator=(const QaBuilder&) = delete; /// \brief Move assignment operator - Builder& operator=(Builder&&) = delete; + QaBuilder& operator=(QaBuilder&&) = delete; /// \brief QA execution function void Build(); @@ -85,7 +87,7 @@ namespace cbm::algo::ca::qa void RegisterParameters(const Parameters<fvec>* pParameters) { fpParameters = pParameters; } private: - QaData fQaData{"CaQa"}; ///< QA data + qa::Data fQaData{"CaQa"}; ///< QA data std::shared_ptr<HistogramSender> fpSender = nullptr; ///< Histogram sender const Parameters<fvec>* fpParameters = nullptr; ///< Pointer to tracking parameters @@ -96,10 +98,11 @@ namespace cbm::algo::ca::qa // ----- List of the histograms ------------------------------------------------------------------------------------ static constexpr int knTrkParPoints = 2; ///< Number of track points to build par distributions - std::array<Histo1D*, knTrkParPoints> fvphTrkTheta = {{0}}; ///< hist: theta at first/last hit - std::array<Histo1D*, knTrkParPoints> fvphTrkPhi = {{0}}; ///< hist: phi at first/last hit - std::array<Histo1D*, knTrkParPoints> fvphTrkChi2Ndf = {{0}}; ///< hist: chi2/NDF at first/last hit - std::array<Histo1D*, knTrkParPoints> fvphHitSta = {{0}}; ///< hist: station of first/last hit - Histo1D* fphTrkNofHits = nullptr; ///< hist: number of hits in track + std::array<qa::H1D*, knTrkParPoints> fvphTrkTheta = {{0}}; ///< hist: theta at first/last hit + std::array<qa::H1D*, knTrkParPoints> fvphTrkPhi = {{0}}; ///< hist: phi at first/last hit + std::array<qa::H1D*, knTrkParPoints> fvphTrkChi2Ndf = {{0}}; ///< hist: chi2/NDF at first/last hit + std::array<qa::H1D*, knTrkParPoints> fvphHitSta = {{0}}; ///< hist: station of first/last hit + std::array<qa::H2D*, knTrkParPoints> fvphTrkPhiTheta = {{0}}; ///< hist: theta vs. phi at first/last hit + qa::H1D* fphTrkNofHits = nullptr; ///< hist: number of hits in track }; } // namespace cbm::algo::ca::qa diff --git a/algo/ca/qa/CaQaConfig.cxx b/algo/ca/qa/CaQaConfig.cxx deleted file mode 100644 index e9c696b7da..0000000000 --- a/algo/ca/qa/CaQaConfig.cxx +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt - SPDX-License-Identifier: GPL-3.0-only - Authors: Sergei Zharko [committer] */ - -/// \file CaQaConfig.cxx -/// \date 20.11.2023 -/// \brief A configuration class for the QA module of the CA tracking (implementation) -/// \author Sergei Zharko <s.zharko@gsi.de> - -#include "CaQaConfig.h" - -using cbm::algo::ca::qa::Config; - -// --------------------------------------------------------------------------------------------------------------------- -// -Config::Config() -{ - // Parameters initialization - // TODO: SZh 20.11.2023: Read from YAML - /* clang-format off */ - fvH1Pars[H1Key::FstTrkTheta] = { "track_first_theta", "#theta at first hit;#theta" , 62, 0., +90. }; - fvH1Pars[H1Key::FstTrkPhi] = { "track_first_phi" , "#phi at first hit;#phi" , 62, -180., +180. }; - fvH1Pars[H1Key::FstChi2Ndf] = { "track_first_chi2_ndf", "#chi^{2}/NDF at first hit;#chi^{2}/NDF", 100, 0., +20. }; - fvH1Pars[H1Key::FstHitSta] = { "first_hit_station", "Station of first hit;ID_{sta}" , 11, -0.5, 10.5 }; - fvH1Pars[H1Key::LstHitSta] = { "last_hit_station", "Station of last hit;ID_{sta}" , 11, -0.5, 10.5 }; - fvH1Pars[H1Key::TrkNofHits] = { "n_hits", "Number of hits;N_{hit}" , 11, -0.5, 10.5 }; - /* clang-format on */ - - // QA Canvas -} - -// --------------------------------------------------------------------------------------------------------------------- -// -std::vector<std::pair<std::string, std::string>> Config::GetHistogramConfigs() const -{ - std::vector<std::pair<std::string, std::string>> res; - auto nHistos = fvH1Pars.size(); - res.reserve(nHistos); - for (const auto& par : fvH1Pars) { - res.emplace_back(par.fName, fsQaName); - } - return res; -} - -// --------------------------------------------------------------------------------------------------------------------- -// -std::vector<std::pair<std::string, std::string>> Config::GetCanvasConfigs() const -{ - std::vector<std::pair<std::string, std::string>> res; - res.reserve(1); - { - std::string sConfig = "caQaSummary;CA QA Summary;3;2;"; - //sConfig += GetPadConfig({fvH1Pars[H1Key::FstTrkTx].fName}, 0, 1); - //sConfig += GetPadConfig({fvH1Pars[H1Key::FstTrkTy].fName}, 0, 1); - sConfig += GetPadConfig({fvH1Pars[H1Key::FstTrkTheta].fName}, 0, 1); - sConfig += GetPadConfig({fvH1Pars[H1Key::FstTrkPhi].fName}, 0, 1); - sConfig += GetPadConfig({fvH1Pars[H1Key::FstChi2Ndf].fName}, 0, 1); - sConfig += GetPadConfig({fvH1Pars[H1Key::FstHitSta].fName}, 0, 1); - sConfig += GetPadConfig({fvH1Pars[H1Key::LstHitSta].fName}, 0, 1); - sConfig += GetPadConfig({fvH1Pars[H1Key::TrkNofHits].fName}, 0, 1); - res.emplace_back("caQaSummary", sConfig); - } - return res; -} - -// --------------------------------------------------------------------------------------------------------------------- -// -std::string Config::GetPadConfig(const std::vector<std::string>& vHistNames, bool bLogX, bool bLogY) -{ - constexpr bool bGridX = true; - constexpr bool bGridY = true; - constexpr bool bLogZ = false; - - std::stringstream config; - config << bGridX << ',' << bGridY << ',' << bLogX << ',' << bLogY << ',' << bLogZ; - if (vHistNames.empty()) { - config << ','; - } - else { - for (auto& name : vHistNames) { - config << ",(" << name << ",hist)"; - } - } - config << ';'; - return config.str(); -} diff --git a/algo/ca/qa/CaQaConfig.h b/algo/ca/qa/CaQaConfig.h deleted file mode 100644 index 67f93eeae1..0000000000 --- a/algo/ca/qa/CaQaConfig.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt - SPDX-License-Identifier: GPL-3.0-only - Authors: Sergei Zharko [committer] */ - -/// \file CaQaConfig.h -/// \date 20.11.2023 -/// \brief A configuration class for the QA module of the CA tracking (header) -/// \author Sergei Zharko <s.zharko@gsi.de> - -#pragma once - -#include "CaQaDefinitions.h" - -#include <string> -#include <vector> - -namespace cbm::algo::ca::qa -{ - /// \brief Configuration structure for QA of the tracking - /// \struct cbm::algo::ca::qa::Config - class Config { - public: - /// \brief Default constructor - Config(); - - /// \brief Copy constructor - Config(const Config&) = default; - - /// \brief Move constructor - Config(Config&&) = default; - - /// \brief Destructor - ~Config() = default; - - /// \brief Access to 1D-histogram parameters - const H1KeyArray_t<H1Pars>& GetH1Pars() const { return fvH1Pars; } - - /// \brief Gets histograms configuration vector - /// \return A histogram configuration vector - /// - /// The returned configuration vector is a std::vector of std::pair of two strings. The first string is the - /// histogram name and the second string is the QA name (common for all the histograms within the QA module). - std::vector<std::pair<std::string, std::string>> GetHistogramConfigs() const; - - /// \brief Gets canvas configuration vector - /// \return A canvas configuration vector - /// - /// The returned configuration vector is a std::vector of std::pair of two strings. The first string is the - /// histogram name and the second string is the QA name (common for all the histograms within the QA module). - std::vector<std::pair<std::string, std::string>> GetCanvasConfigs() const; - - private: - /// \brief Gets pad configuration string - static std::string GetPadConfig(const std::vector<std::string>& vHistNames, bool bLogX, bool bLogY); - - std::string fsQaName = "CaQa"; ///< Name of the QA module - - H1KeyArray_t<H1Pars> fvH1Pars; ///< Parameters of 1D-histograms - std::string fsCanvasConfig = ""; ///< QA canvas configuration - }; -} // namespace cbm::algo::ca::qa diff --git a/algo/ca/qa/CaQaData.cxx b/algo/ca/qa/CaQaData.cxx deleted file mode 100644 index da495021f2..0000000000 --- a/algo/ca/qa/CaQaData.cxx +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt - SPDX-License-Identifier: GPL-3.0-only - Authors: Sergei Zharko [committer] */ - -/// \file CaQaData.h -/// \date 20.11.2023 -/// \brief A data structure for the QA module of the CA tracking (header) -/// \author S.Zharko <s.zharko@gsi.de> - -#include "CaQaData.h" - -#include <sstream> - -using cbm::algo::ca::qa::Config; -using cbm::algo::ca::qa::Data; - -// --------------------------------------------------------------------------------------------------------------------- -// -Data::Data(const Config& config) -{ - // 1D-histograms initialization - fvH1.reserve(static_cast<size_t>(H1Key::kEND)); - for (auto& par : config.GetH1Pars()) { - fvH1.emplace_back(par.fNumBins, par.fMinValue, par.fMaxValue, par.fName, par.fTitle); - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// -std::string Data::ToString() const -{ - std::stringstream msg; - msg << "CA QA histogram status:"; - for (const auto& hist : fvH1) { - msg << '\n' << hist.ToString(); - } - return msg.str(); -} diff --git a/algo/ca/qa/CaQaData.h b/algo/ca/qa/CaQaData.h deleted file mode 100644 index 345651740f..0000000000 --- a/algo/ca/qa/CaQaData.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt - SPDX-License-Identifier: GPL-3.0-only - Authors: Sergei Zharko [committer] */ - -/// \file CaQaData.h -/// \date 20.11.2023 -/// \brief A data structure for the QA module of the CA tracking (header) -/// \author S.Zharko <s.zharko@gsi.de> - -#pragma once - -#include "CaQaConfig.h" -#include "CaQaDefinitions.h" -#include "Histo1D.h" - -#include <string> -#include <vector> - -namespace cbm::algo::ca::qa -{ - /// \class cbm::algo::ca::qa::Data - /// \brief QA data structure for CA tracking - class Data { - public: - /// \brief Default constructor - Data() = delete; - - /// \brief Constructor from parameters - /// \param config QA configuration object - Data(const Config& config); - - /// \brief Copy constructor - Data(const Data&) = default; - - /// \brief Move constructor - Data(Data&&) = default; - - /// \brief Copy assignment operator - Data& operator=(const Data&) = default; - - /// \brief Move assignment operator - Data& operator=(Data&&) = default; - - /// \brief Destructor - ~Data() = default; - - /// \brief Accesses 1D-histogram - const Histo1D& H1(H1Key key) const { return fvH1[static_cast<size_t>(key)]; } - - /// \brief Accesses 1D-histogram (mutable) - Histo1D& H1(H1Key key) { return fvH1[static_cast<size_t>(key)]; } - - /// \brief Accesses the full histogram vector - const std::vector<Histo1D>& VectorOfH1() const { return fvH1; } - - /// \brief String representation of the data status - std::string ToString() const; - - private: - std::vector<Histo1D> fvH1 = {}; ///< Vector of 1D-histograms, indexed by H1Key - }; - -} // namespace cbm::algo::ca::qa diff --git a/algo/ca/qa/CaQaDefinitions.h b/algo/ca/qa/CaQaDefinitions.h deleted file mode 100644 index 2637d1e790..0000000000 --- a/algo/ca/qa/CaQaDefinitions.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt - SPDX-License-Identifier: GPL-3.0-only - Authors: Sergei Zharko [committer] */ - -/// \file CaQaDefinitions.h -/// \date 20.11.2023 -/// \brief Definitions (enums and structures) for the cbm::algo::ca::qa namespace -/// \author S.Zharko <s.zharko@gsi.de> - -#pragma once - -#include "CaEnumArray.h" - -#include <iomanip> -#include <sstream> - -namespace cbm::algo::ca::qa -{ - /// \struct H1Pars - /// \brief Parameters of the 1D-histograms - /// - struct H1Pars { - std::string fName; ///< Histogram name - std::string fTitle; ///< Histogram title - uint32_t fNumBins; ///< Number of bins in histogram - double fMinValue; ///< Minimal value - double fMaxValue; ///< Maximal value - - /// \brief String representation of the object - std::string ToString() const - { - using std::setw; - std::stringstream msg; - msg << "nbins " << setw(8) << fNumBins << ", min " << setw(15) << fMinValue << ", max " << setw(15) << fMaxValue; - return msg.str(); - }; - }; - - /// \enum H1Key - /// \brief Keys for the 1D-histograms - /// - enum class H1Key - { - //TrackFstTx, ///< First hit: Slope of the track along x-axis - //TrackFstTy, ///< First hit: Slope of the track along y-axis - FstTrkTheta, ///< First hit: Polar angle of the track - FstTrkPhi, ///< First hit: Azimuthal angle of the track - FstChi2Ndf, ///< First hit: chi2 / NDF - FstHitSta, ///< Station index of first hit - LstHitSta, ///< Station index of last hit - TrkNofHits, ///< Number of hits in track - kEND ///< END - }; - - /// \brief Alias to array, indexed by H1Key - template<typename T> - using H1KeyArray_t = EnumArray<H1Key, T>; - -} // namespace cbm::algo::ca::qa diff --git a/algo/evbuild/EventbuildChain.cxx b/algo/evbuild/EventbuildChain.cxx index 2843a98436..79ab194194 100644 --- a/algo/evbuild/EventbuildChain.cxx +++ b/algo/evbuild/EventbuildChain.cxx @@ -6,7 +6,7 @@ #include "CbmDigiTimeslice.h" #include "DigiData.h" -#include "Histo1D.h" +#include "HistogramContainer.h" #include "evbuild/Config.h" #include <sstream> @@ -51,7 +51,7 @@ EventbuildChain::EventbuildChain(const Config& config, std::shared_ptr<Histogram } /// => (empty) Histograms serialization and emission to close multi-part message - fSender->PrepareAndSendMsg(std::vector<Histo1D>{}, zmq::send_flags::none); + fSender->PrepareAndSendMsg(qa::HistogramContainer{}, zmq::send_flags::none); } } // ---------------------------------------------------------------------------- @@ -75,11 +75,14 @@ EventbuildChain::ResultType EventbuildChain::Run(const DigiData& timeslice) /// => Histograms serialization and emission if (fSender) { + L_(info) << "Running DigiEventQa"; // --- Run event QA DigiEventQaData qaData = fQa(events); + L_(info) << "Running DigiEventQa: done"; - fSender->PrepareAndSendMsg(qaData.fVectHistos, zmq::send_flags::none); - L_(info) << "Published histograms, nb: " << qaData.fVectHistos.size(); + fSender->PrepareAndSendMsg(qaData.fHistContainer, zmq::send_flags::none); + int nHistograms = std::distance(qaData.fHistContainer.fvH1.begin(), qaData.fHistContainer.fvH1.end()); + L_(info) << "Published histograms, nb: " << nHistograms; } // --- Some log diff --git a/algo/qa/CanvasConfig.cxx b/algo/qa/CanvasConfig.cxx index bfbb99c2f2..e0c3e3cb59 100644 --- a/algo/qa/CanvasConfig.cxx +++ b/algo/qa/CanvasConfig.cxx @@ -12,8 +12,8 @@ #include <log.hpp> #include <sstream> -using cbm::algo::CanvasConfig; -using cbm::algo::PadConfig; +using cbm::algo::qa::CanvasConfig; +using cbm::algo::qa::PadConfig; // --------------------------------------------------------------------------------------------------------------------- // diff --git a/algo/qa/CanvasConfig.h b/algo/qa/CanvasConfig.h index 0efe885c1c..20088d8b9b 100644 --- a/algo/qa/CanvasConfig.h +++ b/algo/qa/CanvasConfig.h @@ -16,7 +16,7 @@ #include <utility> #include <vector> -namespace cbm::algo +namespace cbm::algo::qa { /// \class CanvasConfig /// \brief A canvas configuration for the histogram server diff --git a/algo/qa/DigiEventQa.cxx b/algo/qa/DigiEventQa.cxx index b47b4993fa..3fb21feca3 100644 --- a/algo/qa/DigiEventQa.cxx +++ b/algo/qa/DigiEventQa.cxx @@ -4,10 +4,15 @@ #include "DigiEventQa.h" +#include "Histogram.h" + +#include <functional> #include <iomanip> +#include <iostream> #include <sstream> #include <string> +using cbm::algo::qa::H1D; using std::string; using std::vector; @@ -17,16 +22,14 @@ namespace cbm::algo::evbuild // --- Execution -------------------------------------------------------- DigiEventQaData DigiEventQa::operator()(const vector<DigiEvent>& events) const { - // --- Instantiate return object DigiEventQaData result; - result.fVectHistos.reserve(fConfig.fData.size()); for (const auto& entry : fConfig.fData) { ECbmModuleId subsystem = entry.first; auto& detConfig = fConfig.fData.at(subsystem); - result.fVectHistos.emplace_back(detConfig.fNumBins, detConfig.fMinValue, detConfig.fMaxValue, - DigiEventQaConfig::GetDigiTimeHistoName(subsystem)); - result.fDigiTimeHistos.emplace(subsystem, result.fVectHistos.back()); + result.fDigiTimeHistos[subsystem] = + &(result.fHistContainer.fvH1.emplace_front(DigiEventQaConfig::GetDigiTimeHistoName(subsystem), "", + detConfig.fNumBins, detConfig.fMinValue, detConfig.fMaxValue)); } // --- Event loop. Fill histograms. @@ -43,7 +46,7 @@ namespace cbm::algo::evbuild // --- QA: digi time within event ---------------------------------------- - void DigiEventQa::QaDigiTimeInEvent(const DigiEvent& event, ECbmModuleId system, Histo1D& histo) const + void DigiEventQa::QaDigiTimeInEvent(const DigiEvent& event, ECbmModuleId system, H1D* histo) const { switch (system) { diff --git a/algo/qa/DigiEventQa.h b/algo/qa/DigiEventQa.h index 7df6945795..91961d4649 100644 --- a/algo/qa/DigiEventQa.h +++ b/algo/qa/DigiEventQa.h @@ -7,7 +7,7 @@ #include "CbmDefs.h" #include "DigiData.h" -#include "Histo1D.h" +#include "HistogramContainer.h" #include "evbuild/EventBuilderConfig.h" #include <gsl/span> @@ -24,9 +24,8 @@ namespace cbm::algo::evbuild ** @since 16 June 2023 **/ struct DigiEventQaData { - - std::vector<Histo1D> fVectHistos = {}; - std::map<ECbmModuleId, Histo1D&> fDigiTimeHistos = {}; + qa::HistogramContainer fHistContainer; + std::map<ECbmModuleId, qa::H1D*> fDigiTimeHistos = {}; size_t fNumEvents = 0; }; @@ -142,10 +141,10 @@ namespace cbm::algo::evbuild ** The templated class is required to implement the method double GetTime(). **/ template<class Digi> - void FillDeltaT(gsl::span<const Digi> digis, double eventTime, Histo1D& histo) const + void FillDeltaT(gsl::span<const Digi> digis, double eventTime, qa::H1D* histo) const { for (const Digi& digi : digis) - histo.Add(digi.GetTime() - eventTime); + histo->Fill(digi.GetTime() - eventTime); } /** @brief Fill histogram with digi time within event @@ -153,7 +152,7 @@ namespace cbm::algo::evbuild ** @param eventTime Time of event ** @param histo Histogram to be filled **/ - void QaDigiTimeInEvent(const DigiEvent& event, ECbmModuleId system, Histo1D& histo) const; + void QaDigiTimeInEvent(const DigiEvent& event, ECbmModuleId system, qa::H1D* histo) const; private: // members diff --git a/algo/qa/Histogram.h b/algo/qa/Histogram.h index 273b6578c0..adb2f5b80a 100644 --- a/algo/qa/Histogram.h +++ b/algo/qa/Histogram.h @@ -202,10 +202,16 @@ namespace cbm::algo::qa H1D() = default; /// \brief Copy constructor - explicit H1D(const H1D&) = default; + H1D(const H1D&) = default; /// \brief Move constructor - explicit H1D(H1D&&) = default; + H1D(H1D&&) = default; + + /// \brief Copy assignment operator + H1D& operator=(const H1D&) = default; + + /// \brief Move assignment operator + H1D& operator=(H1D&&) = default; /// \brief Fills histogram /// \param value Value @@ -262,10 +268,16 @@ namespace cbm::algo::qa H2D() = default; /// \brief Copy constructor - explicit H2D(const H2D&) = default; + H2D(const H2D&) = default; /// \brief Move constructor - explicit H2D(H2D&&) = default; + H2D(H2D&&) = default; + + /// \brief Copy assignment operator + H2D& operator=(const H2D&) = default; + + /// \brief Move assignment operator + H2D& operator=(H2D&&) = default; /// \brief Fills histogram /// \param valueX Value along x-axis diff --git a/algo/qa/HistogramContainer.cxx b/algo/qa/HistogramContainer.cxx new file mode 100644 index 0000000000..a0fe588738 --- /dev/null +++ b/algo/qa/HistogramContainer.cxx @@ -0,0 +1,24 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file HistogramContainer.cxx +/// \date 29.02.2024 +/// \brief A histogram container for the histogram server (header) +/// \author Sergei Zharko <s.zharko@gsi.de> + +#include "HistogramContainer.h" + +using cbm::algo::qa::HistogramContainer; + +// --------------------------------------------------------------------------------------------------------------------- +// +void HistogramContainer::Reset() +{ + for (auto& h : fvH1) { + h.Reset(); + } + for (auto& h : fvH2) { + h.Reset(); + } +} diff --git a/algo/qa/HistogramContainer.h b/algo/qa/HistogramContainer.h new file mode 100644 index 0000000000..11dc4316cd --- /dev/null +++ b/algo/qa/HistogramContainer.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file HistogramContainer.h +/// \date 29.02.2024 +/// \brief A histogram container for the histogram server (header) +/// \author Sergei Zharko <s.zharko@gsi.de> + +#pragma once + +#include "Histogram.h" // for H1D, H2D + +#include <boost/serialization/forward_list.hpp> + +#include <forward_list> + +namespace cbm::algo::qa +{ + /// \struct HistogramContainer + /// \brief Structure to keep the histograms for sending them on the histogram server + struct HistogramContainer { + std::forward_list<qa::H1D> fvH1 = {}; ///< List of 1D-histograms + std::forward_list<qa::H2D> fvH2 = {}; ///< List of 2D-histograms + + /// \brief Resets the histograms + void Reset(); + + private: + friend class boost::serialization::access; + template<class Archive> + void serialize(Archive& ar, const unsigned int /*version*/) + { + ar& fvH1; + ar& fvH2; + } + }; +} // namespace cbm::algo::qa diff --git a/algo/qa/PadConfig.cxx b/algo/qa/PadConfig.cxx index 4b9d1a0394..93cdc8741b 100644 --- a/algo/qa/PadConfig.cxx +++ b/algo/qa/PadConfig.cxx @@ -12,7 +12,7 @@ #include <log.hpp> #include <sstream> -using cbm::algo::PadConfig; +using cbm::algo::qa::PadConfig; // --------------------------------------------------------------------------------------------------------------------- // diff --git a/algo/qa/PadConfig.h b/algo/qa/PadConfig.h index d95c1cdc1d..9c2e7bcf1a 100644 --- a/algo/qa/PadConfig.h +++ b/algo/qa/PadConfig.h @@ -9,14 +9,14 @@ #pragma once -#include "Histo1D.h" +#include "Histogram.h" #include <string> #include <string_view> #include <utility> #include <vector> -namespace cbm::algo +namespace cbm::algo::qa { /// \class PadConfig /// \brief A pad configuration for the histogram server @@ -65,7 +65,9 @@ namespace cbm::algo /// \brief Registers a histogram in the pad /// \param hist Histogram object /// \param opt Draw options for the histogram - void RegisterHistogram(const Histo1D* hist, std::string_view opt) { RegisterObject(hist->Name(), opt); } + // TODO: implement a single function + void RegisterHistogram(const H1D* hist, std::string_view opt) { RegisterObject(hist->GetName(), opt); } + void RegisterHistogram(const H2D* hist, std::string_view opt) { RegisterObject(hist->GetName(), opt); } /// \brief Returns message config std::string ToString() const; diff --git a/algo/qa/QaData.cxx b/algo/qa/QaData.cxx index 955c1ba27c..90151fe66a 100644 --- a/algo/qa/QaData.cxx +++ b/algo/qa/QaData.cxx @@ -2,25 +2,32 @@ SPDX-License-Identifier: GPL-3.0-only Authors: Sergei Zharko [committer] */ -/// \file QaData.cxx +/// \file Data.cxx /// \date 12.02.2024 /// \brief A unified data-structure to handle QA objects for the online reconstruction (implementation) /// \author Sergei Zharko <s.zharko@gsi.de> #include "QaData.h" -using cbm::algo::QaData; +using cbm::algo::qa::Data; // --------------------------------------------------------------------------------------------------------------------- // -void QaData::Init(std::shared_ptr<HistogramSender> histSender) +void Data::Init(std::shared_ptr<HistogramSender> histSender) { if (histSender.get()) { // Forming a histogram config message std::vector<std::pair<std::string, std::string>> vHistCfgs; - vHistCfgs.reserve(std::distance(fvH1.begin(), fvH1.end())); - for (const auto& hist : fvH1) { - vHistCfgs.emplace_back(hist.Name(), fsName); + size_t nHistograms = 0; + // NOTE: Important to keep the order of filling the histograms: 1D -> 2D -> .. + nHistograms += std::distance(fHistograms.fvH1.begin(), fHistograms.fvH1.end()); + nHistograms += std::distance(fHistograms.fvH2.begin(), fHistograms.fvH2.end()); + vHistCfgs.reserve(nHistograms); + for (const auto& hist : fHistograms.fvH1) { + vHistCfgs.emplace_back(hist.GetName(), fsName); + } + for (const auto& hist : fHistograms.fvH2) { + vHistCfgs.emplace_back(hist.GetName(), fsName); } // Forming a canvas config message @@ -39,26 +46,17 @@ void QaData::Init(std::shared_ptr<HistogramSender> histSender) histSender->PrepareAndSendMsg(cfg, zmq::send_flags::sndmore); } // Histograms serialization and emission to close multi-part message - histSender->PrepareAndSendMsg(std::vector<Histo1D>{}, zmq::send_flags::none); - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// -void QaData::Reset() -{ - // TODO: clear the vectors of other object types here as well - for (auto& hist : fvH1) { - hist.Clear(); + histSender->PrepareAndSendMsg(qa::HistogramContainer{}, zmq::send_flags::none); } } // --------------------------------------------------------------------------------------------------------------------- // -void QaData::Send(std::shared_ptr<HistogramSender> histoSender) +void Data::Send(std::shared_ptr<HistogramSender> histoSender) { - std::vector<Histo1D> vHisto1D{std::begin(fvH1), std::end(fvH1)}; - histoSender->PrepareAndSendMsg(vHisto1D, zmq::send_flags::none); - L_(info) << fsName << ": Published " << vHisto1D.size() << " 1D-histograms"; + histoSender->PrepareAndSendMsg(fHistograms, zmq::send_flags::none); + auto nH1 = std::distance(fHistograms.fvH1.begin(), fHistograms.fvH1.end()); + auto nH2 = std::distance(fHistograms.fvH2.begin(), fHistograms.fvH2.end()); + L_(info) << fsName << ": Published " << nH1 << " 1D- and " << nH2 << " 2D-histograms"; this->Reset(); } diff --git a/algo/qa/QaData.h b/algo/qa/QaData.h index 263614458c..e4fcc5c170 100644 --- a/algo/qa/QaData.h +++ b/algo/qa/QaData.h @@ -2,7 +2,7 @@ SPDX-License-Identifier: GPL-3.0-only Authors: Sergei Zharko [committer] */ -/// \file QaData.cxx +/// \file Data.cxx /// \date 12.02.2024 /// \brief A unified data-structure to handle QA objects for the online reconstruction /// \author Sergei Zharko <s.zharko@gsi.de> @@ -10,40 +10,41 @@ #pragma once #include "CanvasConfig.h" -#include "Histo1D.h" +#include "HistogramContainer.h" #include "HistogramSender.h" -#include <forward_list> +#include <boost/serialization/forward_list.hpp> + #include <log.hpp> #include <memory> #include <string_view> #include <type_traits> #include <vector> -namespace cbm::algo +namespace cbm::algo::qa { - /// \class QaData + /// \class Data /// \brief Class to handle QA-objects in the online reconstruction - class QaData { + class Data { public: /// \brief Constructor /// \param name Name of the QA module (appears as the directory name in the output) - QaData(std::string_view name) : fsName(name) {} + Data(std::string_view name) : fsName(name) {} /// \brief Copy constructor - QaData(const QaData&) = default; + Data(const Data&) = default; /// \brief Move constructor - QaData(QaData&&) = default; + Data(Data&&) = default; /// \brief Copy assignment operator - QaData& operator=(const QaData&) = default; + Data& operator=(const Data&) = default; /// \brief Move assignment operator - QaData& operator=(QaData&&) = default; + Data& operator=(Data&&) = default; /// \brief Destructor - ~QaData() = default; + ~Data() = default; /// \brief Adds a canvas to the canvas config list /// \param canvas A CanvasConfig object @@ -61,7 +62,7 @@ namespace cbm::algo void Init(std::shared_ptr<HistogramSender> histoSender); /// \brief Resets the histograms - void Reset(); + void Reset() { fHistograms.Reset(); } /// \brief Sends QA data to the HistogramSender /// \param histoSender A pointer to the histogram sender @@ -70,17 +71,20 @@ namespace cbm::algo private: std::string fsName; ///< Name of the QA module (used as a directory name) - std::forward_list<Histo1D> fvH1 = {}; ///< List of 1D-histograms + qa::HistogramContainer fHistograms; ///< Histograms container std::vector<std::string> fvsCanvCfgs = {}; ///< Vector of canvas configs }; // ------------------------------------------------------------------------------------------------------------------- // template<class Obj, typename... Args> - Obj* QaData::MakeObj(Args... args) + Obj* Data::MakeObj(Args... args) { - if constexpr (std::is_same_v<Obj, cbm::algo::Histo1D>) { - return &(fvH1.emplace_front(args...)); + if constexpr (std::is_same_v<Obj, cbm::algo::qa::H1D>) { + return &(fHistograms.fvH1.emplace_front(args...)); + } + else if constexpr (std::is_same_v<Obj, cbm::algo::qa::H2D>) { + return &(fHistograms.fvH2.emplace_front(args...)); } return nullptr; } diff --git a/reco/tasks/CbmTaskDigiEventQa.cxx b/reco/tasks/CbmTaskDigiEventQa.cxx index 1ea9b16047..f8a71bb955 100644 --- a/reco/tasks/CbmTaskDigiEventQa.cxx +++ b/reco/tasks/CbmTaskDigiEventQa.cxx @@ -80,7 +80,7 @@ void CbmTaskDigiEventQa::Exec(Option_t*) // which is then added to the member histogram (another data copy). Should implement a method for direct addition TH1D + Histo1D. for (const auto& entry : result.fDigiTimeHistos) { ECbmModuleId subsystem = entry.first; - fDigiTimeHistos[subsystem]->Add(ToTH1D(entry.second)); + fDigiTimeHistos[subsystem]->Add(ToTH1D(*entry.second)); } // --- Timeslice log @@ -159,19 +159,17 @@ InitStatus CbmTaskDigiEventQa::Init() // ----- Convert CBM histogram to ROOT histogram -------------------------- -TH1D* CbmTaskDigiEventQa::ToTH1D(const cbm::algo::Histo1D& source) +TH1D* CbmTaskDigiEventQa::ToTH1D(const cbm::algo::qa::H1D& source) { bool add = TH1::AddDirectoryStatus(); TH1::AddDirectory(false); // Needed to prevent ROOT from adding histogram to its internal registry - TH1D* result = - new TH1D(source.Name().c_str(), source.Name().c_str(), source.NumBins(), source.MinValue(), source.MaxValue()); + TH1D* result = new TH1D(source.GetName().c_str(), source.GetName().c_str(), source.GetNbinsX(), source.GetMinX(), + source.GetMaxX()); TH1::AddDirectory(add); // Needed to prevent ROOT from adding histogram to its internal registry - for (uint32_t bin = 0; bin < source.NumBins(); bin++) { - result->SetBinContent(1 + bin, source.Content(bin)); + for (uint32_t bin = 0; bin <= source.GetNbinsX() + 1; bin++) { + result->SetBinContent(bin, source.GetBinContent(bin)); } - result->SetBinContent(0, source.Underflow()); - result->SetBinContent(source.NumBins(), source.Overflow()); - result->SetEntries(source.NumEntries()); + result->SetEntries(source.GetEntries()); return result; } // ---------------------------------------------------------------------------- diff --git a/reco/tasks/CbmTaskDigiEventQa.h b/reco/tasks/CbmTaskDigiEventQa.h index ebd6566753..f338a29379 100644 --- a/reco/tasks/CbmTaskDigiEventQa.h +++ b/reco/tasks/CbmTaskDigiEventQa.h @@ -68,14 +68,14 @@ private: // methods virtual InitStatus Init(); - /** @brief Create a ROOT TH1D from a Histo1D object + /** @brief Create a ROOT TH1D from a H1D object ** @param Source histogram ** @param ROOT histogram */ - TH1D* ToTH1D(const cbm::algo::Histo1D& source); + TH1D* ToTH1D(const cbm::algo::qa::H1D& source); -private: // members + private: // members const std::vector<CbmDigiEvent>* fEvents = nullptr; //! Input data (events) size_t fNumTs = 0; ///< Number of processed timeslices size_t fNumEvents = 0; ///< Number of analysed events diff --git a/services/histserv/app/Application.cxx b/services/histserv/app/Application.cxx index 8a565c5811..0964416f9f 100644 --- a/services/histserv/app/Application.cxx +++ b/services/histserv/app/Application.cxx @@ -5,9 +5,7 @@ #include "Application.h" #include "CbmFlesCanvasTools.h" - -#include <Logger.h> - +#include "HistogramContainer.h" #include "TCanvas.h" #include "TEnv.h" #include "TFile.h" @@ -20,6 +18,8 @@ #include "TRootSniffer.h" #include "TSystem.h" +#include <Logger.h> + #include <boost/archive/binary_iarchive.hpp> #include <boost/iostreams/device/array.hpp> #include <boost/iostreams/stream.hpp> @@ -29,8 +29,6 @@ #include <mutex> #include <zmq_addon.hpp> -#include "Histo1D.h" - std::mutex mtx; namespace b_io = boost::iostreams; @@ -163,25 +161,56 @@ namespace cbm::services::histserv b_io::stream<b_io::basic_array_source<char>> s(device); b_ar::binary_iarchive iarch(s); - std::vector<cbm::algo::Histo1D> vHist; + cbm::algo::qa::HistogramContainer vHist; iarch >> vHist; - for (auto& source : vHist) { - /// copied from CbmTaskDigiEventQa::ToTH1D - /// FIXME: Should be placed in a tools/interface/whatever library with all similar functions!! - /// FIXME: Reverse OP need to be implemented + CI unit tests for back and forth in each direction (ROOT <-> Algo) - /// FIXME: Lead to "Warning in <TROOT::Append>: Replacing existing TH1: xxxxxx (Potential memory leak)." + /// copied from CbmTaskDigiEventQa::ToTH1D + /// FIXME: Should be placed in a tools/interface/whatever library with all similar functions!! + /// TODO: SZh 29.02.2024: Use core/qa/CbmQaOnlineInterface (for now a fast solution) + /// FIXME: Reverse OP need to be implemented + CI unit tests for back and forth in each direction (ROOT <-> Algo) + /// FIXME: Lead to "Warning in <TROOT::Append>: Replacing existing TH1: xxxxxx (Potential memory leak)." + + // Collect 1D-histograms + for (auto& source : vHist.fvH1) { + bool add = TH1::AddDirectoryStatus(); + TH1::AddDirectory(false); // Needed to prevent ROOT from adding histogram to its internal registry + const char* hName = source.GetName().c_str(); + const char* hTitl = source.GetTitle().c_str(); + uint32_t nBinsX = source.GetNbinsX(); + double xMin = source.GetMinX(); + double xMax = source.GetMaxX(); + TH1* result = new TH1D(hName, hTitl, nBinsX, xMin, xMax); + TH1::AddDirectory(add); // Needed to prevent ROOT from adding histogram to its internal registry + for (uint32_t bin = 0; bin <= nBinsX + 1; bin++) { + result->SetBinContent(bin, source.GetBinContent(bin)); + } + result->SetEntries(source.GetEntries()); + if (!ReadHistogram<TH1>(result)) { // + return false; + } + delete result; + } + + // Collect 2D-histograms + for (auto& source : vHist.fvH2) { bool add = TH1::AddDirectoryStatus(); TH1::AddDirectory(false); // Needed to prevent ROOT from adding histogram to its internal registry - TH1D* result = new TH1D(source.Name().c_str(), source.Title().c_str(), // Titles in ROOT convention with ";" sep - source.NumBins(), source.MinValue(), source.MaxValue()); + const char* hName = source.GetName().c_str(); + const char* hTitl = source.GetTitle().c_str(); + uint32_t nBinsX = source.GetNbinsX(); + double xMin = source.GetMinX(); + double xMax = source.GetMaxX(); + uint32_t nBinsY = source.GetNbinsY(); + double yMin = source.GetMinY(); + double yMax = source.GetMaxY(); + TH1* result = new TH2D(hName, hTitl, nBinsX, xMin, xMax, nBinsY, yMin, yMax); TH1::AddDirectory(add); // Needed to prevent ROOT from adding histogram to its internal registry - for (uint32_t bin = 0; bin < source.NumBins(); bin++) { - result->SetBinContent(1 + bin, source.Content(bin)); + for (uint32_t binX = 0; binX <= nBinsX + 1; binX++) { + for (uint32_t binY = 0; binY <= nBinsY + 1; binY++) { + result->SetBinContent(binX, binY, source.GetBinContent(binX, binY)); + } } - result->SetBinContent(0, source.Underflow()); - result->SetBinContent(source.NumBins(), source.Overflow()); - result->SetEntries(source.NumEntries()); + result->SetEntries(source.GetEntries()); if (!ReadHistogram<TH1>(result)) { // return false; } diff --git a/services/histserv/tester/Application.cxx b/services/histserv/tester/Application.cxx index 9c2b9fbdbc..f6a675dc72 100644 --- a/services/histserv/tester/Application.cxx +++ b/services/histserv/tester/Application.cxx @@ -4,7 +4,12 @@ #include "Application.h" +#include "CanvasConfig.h" #include "CbmFlesCanvasTools.h" +#include "Histogram.h" +#include "PadConfig.h" +#include "QaData.h" +#include "ui_callbacks.h" #include <Logger.h> @@ -17,9 +22,6 @@ #include <thread> -#include "Histo1D.h" -#include "ui_callbacks.h" - std::mutex mtx; namespace b_io = boost::iostreams; @@ -37,12 +39,13 @@ namespace cbm::services::histserv_tester LOG(info) << "Options for Application."; LOG(info) << " Output ZMQ channel: " << fOpt.ComChan(); LOG(info) << " Run time duration: " << fOpt.Runtime() << " s"; + fpSender = std::make_shared<cbm::algo::HistogramSender>(fOpt.ComChan()); /// FIXME: SOMETHING_To_Replace_FairMQ!!!!!!!!!!!!! /// FIXME: Initialize communication channels of SOMETHING_To_Replace_FairMQ /// FIXME: Link channel to method in order to process received messages - // fZmqSocket.set(zmq::sockopt::rcvhwm, int(hwm)); // FIXME: need for HWM? - fZmqSocket.connect(fOpt.ComChan().c_str()); // This side "connects" to socket => Other side should have "bind"!!!! + // fZmqSocket.set(zmq::sockopt::rcvhwm, int(hwm)); // FIXME: need for HWM? (NOTE: SZh 29.02.2024: if needed, move it + // do it in the HistogramSender) } // ------------------------------------------------------------------------------------------------------------------- @@ -50,6 +53,11 @@ namespace cbm::services::histserv_tester // ----- Main Loop ----------------------------------------------------------------------------------------------- void Application::Exec() { + using cbm::algo::qa::CanvasConfig; + using cbm::algo::qa::Data; + using cbm::algo::qa::H1D; + using cbm::algo::qa::PadConfig; + const std::chrono::milliseconds interval {250}; const std::chrono::seconds runtime(fOpt.Runtime()); const std::chrono::seconds pubint(fOpt.PubInterval()); @@ -57,72 +65,66 @@ namespace cbm::services::histserv_tester sctp stopTime = startTime + runtime; sctp lastPubTime = startTime; - std::vector<cbm::algo::Histo1D> vHist; - vHist.emplace_back((fOpt.Runtime() + 2), -1.0, fOpt.Runtime() + 1.0, "testHist", - "Tester source; Runtime [s]; Entries to histo [iterations]"); - vHist.emplace_back(1001, -0.025, 50.025, "transHist", - "Tester histos transmission time; Trans. time [ms]; Messages []"); + // Init QA data helper + Data qaData("Test"); + auto* pHistTest = qaData.MakeObj<H1D>("testHist", "Tester source; Runtime [s]; Entries to histo [iterations]", + fOpt.Runtime() + 2, -1.0, fOpt.Runtime() + 1.0); + auto* pHistTrans = qaData.MakeObj<H1D>( + "transHist", "Tester histos transmission time; Trans. time [ms]; Messages []", 1001, -0.025, 50.025); /// Initial emission, including generation and serialization of configs /// => Try to evaluate "time cost" of the histo transmission, including serialization sctp transStartTime = scsc::now(); - /// => Header for multi-part message with Configuration + data - /// => Format: std::pair< Nb histogram configs, Nb canvas configs > - std::pair<uint32_t, uint32_t> pHeader(vHist.size(), 1); - PrepareAndSendMsg(pHeader, zmq::send_flags::sndmore); - - /// => Histograms configuration = destination folder in http browser, mandatory but can be empty (= root folder) - /// => 1 ZMQ message per histogram (= 1 part) - /// => If no (new) histograms declared (e.g. new canvas declaration), has to be en empty message + `0` in the header - std::pair<std::string, std::string> pFirstHist(vHist[0].Name(), "TestFolder"); - std::pair<std::string, std::string> pSecondHist(vHist[1].Name(), "TestFolder/TestSubFolder"); - PrepareAndSendMsg(pFirstHist, zmq::send_flags::sndmore); - PrepareAndSendMsg(pSecondHist, zmq::send_flags::sndmore); - - /// => Canvas configuration = in old code extracted from canvas object, here need to be made by hand - /// => 1 ZMQ message per canvas (= 1 part) - /// => If no (new) canvas declared (e.g. only histos declaration), has to be en empty message + `0` in the header - /// => Format is "CanvasName;Canvas Title;NbPadX(U);NbPadY(U);ConfigPad1(s);....;ConfigPadXY(s)" - /// => Format of Pad config is - /// "GrixX(b),GridY(b),LogX(b),LogY(b),LogZ(b),(HistoName1,DrawOptions1),...,(HistoNameZ,DrawOptionsZ)" - /// => See core/base/utils/fles/CbmFlesCanvasTools for the full code, especially GenerateCanvasConfigString - /// (CanvasConfig class not used here as library loading would need binding to ROOT library) - std::pair<std::string, std::string> pCanvConfig("TestCanvas", "TestCanvas;Canvas configs testing;2;2;"); - pCanvConfig.second += "0,0,0,0,0,(" + vHist[0].Name() + ",hist);"; // Pad 0 - pCanvConfig.second += "1,1,0,0,0,(" + vHist[0].Name() + ",hist);"; // Pad 1 - pCanvConfig.second += "1,1,1,0,0,(" + vHist[1].Name() + ",hist);"; // Pad 2 - pCanvConfig.second += "1,1,1,1,0,(" + vHist[1].Name() + ",hist),(" + vHist[0].Name() + ",hist same);"; // Pad 3 - PrepareAndSendMsg(pCanvConfig, zmq::send_flags::sndmore); - - /// => (empty) Histograms serialization and emission - PrepareAndSendMsg(vHist, zmq::send_flags::none); + { + auto canv = CanvasConfig("TestCanvas", "TestCanvas"); + auto pad1 = PadConfig(); + pad1.SetGrid(false, false); + pad1.SetLog(false, false, false); + pad1.RegisterHistogram(pHistTest, "hist"); + canv.AddPadConfig(pad1); + auto pad2 = PadConfig(); + pad2.SetGrid(true, true); + pad2.SetLog(false, false, false); + pad2.RegisterHistogram(pHistTest, "hist"); + canv.AddPadConfig(pad2); + auto pad3 = PadConfig(); + pad3.SetGrid(true, true); + pad3.SetLog(true, false, false); + pad3.RegisterHistogram(pHistTrans, "hist"); + canv.AddPadConfig(pad3); + auto pad4 = PadConfig(); + pad4.SetGrid(true, true); + pad4.SetLog(true, false, false); + pad4.RegisterHistogram(pHistTrans, "hist"); + pad4.RegisterHistogram(pHistTest, "hist same"); + canv.AddPadConfig(pad4); + qaData.AddCanvasConfig(canv); + } + qaData.Init(fpSender); // Init the QA data + lastPubTime = scsc::now(); /// No general references as member/variable bec. simple example, use directly hardcoded vector "array access" - vHist[1].Add(std::chrono::duration_cast<std::chrono::microseconds>(lastPubTime - transStartTime).count() / 1e3); + pHistTrans->Fill(std::chrono::duration_cast<std::chrono::microseconds>(lastPubTime - transStartTime).count() / 1e3); while (scsc::now() < stopTime) { // /// No general references as member/variable bec. simple example, use directly hardcoded vector "array access" - vHist[0].Add(std::chrono::duration_cast<std::chrono::milliseconds>(scsc::now() - startTime).count() / 1e3); + pHistTest->Fill(std::chrono::duration_cast<std::chrono::milliseconds>(scsc::now() - startTime).count() / 1e3); if (pubint < scsc::now() - lastPubTime) { - LOG(info) << "Pub-hist: " << scsc::now().time_since_epoch().count() << " " << vHist[0].NumEntries(); + LOG(info) << "Pub-hist: " << scsc::now().time_since_epoch().count() << " " << pHistTest->GetEntries(); /// Try to evaluate "time cost" of the histo transmission, including serialization transStartTime = scsc::now(); /// => Histograms serialization and emission - PrepareAndSendMsg(vHist, zmq::send_flags::none); - - /// => Reset all histograms as they are added on the other end! - for (std::vector<cbm::algo::Histo1D>::iterator itHist = vHist.begin(); itHist != vHist.end(); ++itHist) { + qaData.Send(fpSender); - itHist->Clear(); - } lastPubTime = scsc::now(); /// No general references as member/variable bec. simple example, use directly hardcoded vector "array access" - vHist[1].Add(std::chrono::duration_cast<std::chrono::microseconds>(lastPubTime - transStartTime).count() / 1e3); + pHistTrans->Fill(std::chrono::duration_cast<std::chrono::microseconds>(lastPubTime - transStartTime).count() + / 1e3); } std::this_thread::sleep_for(interval); @@ -132,32 +134,8 @@ namespace cbm::services::histserv_tester } /// Final publications - LOG(info) << "Pub-hist: " << scsc::now().time_since_epoch().count() << " " << vHist[0].NumEntries(); + LOG(info) << "Pub-hist: " << scsc::now().time_since_epoch().count() << " " << pHistTest->GetEntries(); /// => Histograms serialization and emission - PrepareAndSendMsg(vHist, zmq::send_flags::none); - /// => Reset all histograms as they are added on the other end! - for (std::vector<cbm::algo::Histo1D>::iterator itHist = vHist.begin(); itHist != vHist.end(); ++itHist) { - itHist->Clear(); - } - } - // ------------------------------------------------------------------------------------------------------------------- - - template<class Object> - void Application::PrepareAndSendMsg(Object& obj, zmq::send_flags flags) - { - /// Needed ressources (serializd string, boost inserter, boost stream, boost binary output archive) - std::string serial_str; - b_io::back_insert_device<std::string> inserter(serial_str); - b_io::stream<b_io::back_insert_device<std::string>> bstream(inserter); - b_ar::binary_oarchive oa(bstream); - - serial_str.clear(); - oa << obj; - bstream.flush(); - - zmq::message_t msg(serial_str.size()); - std::copy_n(static_cast<const char*>(serial_str.data()), msg.size(), static_cast<char*>(msg.data())); - fZmqSocket.send(msg, flags); + qaData.Send(fpSender); } - } // namespace cbm::services::histserv_tester diff --git a/services/histserv/tester/Application.h b/services/histserv/tester/Application.h index 6188785213..ba000e0be4 100644 --- a/services/histserv/tester/Application.h +++ b/services/histserv/tester/Application.h @@ -1,20 +1,20 @@ -/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt +/* Copyright (C) 2023-2024 Facility for Antiproton and Ion Research in Europe, Darmstadt SPDX-License-Identifier: GPL-3.0-only - Authors: Pierre-Alain Loizeau [committer] */ + Authors: Pierre-Alain Loizeau [committer], Sergei Zharko */ #ifndef CBM_SERVICES_HISTSERV_TESTER_APPLICATION_H #define CBM_SERVICES_HISTSERV_TESTER_APPLICATION_H 1 -#include <zmq.hpp> - +#include "HistogramSender.h" #include "ProgramOptions.h" +#include <memory> + namespace cbm::services::histserv_tester { class Application { - public: /** @brief Standard constructor, initialises the application ** @param opt **/ @@ -23,8 +23,14 @@ namespace cbm::services::histserv_tester /** @brief Copy constructor forbidden **/ Application(const Application&) = delete; - /** @brief Assignment operator forbidden **/ - void operator=(const Application&) = delete; + /** @brief Move constructor forbidden **/ + Application(Application&&) = delete; + + /** @brief Copy assignment operator forbidden **/ + Application& operator=(const Application&) = delete; + + /** @brief Move assignment operator forbidden **/ + Application& operator=(Application&&) = delete; /** @brief Destructor **/ ~Application() = default; @@ -32,16 +38,11 @@ namespace cbm::services::histserv_tester /** @brief Run the application **/ void Exec(); - private: - template<class Object> - void PrepareAndSendMsg(Object& obj, zmq::send_flags flags); - private: ProgramOptions const& fOpt; ///< Program options object /// Interface - zmq::context_t fZmqContext {1}; - zmq::socket_t fZmqSocket {fZmqContext, ZMQ_PUSH}; + std::shared_ptr<cbm::algo::HistogramSender> fpSender = nullptr; }; } // namespace cbm::services::histserv_tester -- GitLab