From 476441187bb4d26bac85468b19fb0e4cda8ba33e Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Wed, 12 Jun 2024 03:34:56 +0200 Subject: [PATCH] QA online: possibility to add the TS index axis --- algo/qa/Histogram.h | 235 ++++++++++++++++++-------- algo/qa/HistogramContainer.cxx | 19 +-- algo/qa/HistogramContainer.h | 2 + algo/qa/QaData.cxx | 36 ++-- core/qa/report/CbmQaReportElement.h | 2 +- services/histserv/app/Application.cxx | 115 +++++++------ services/histserv/app/Application.h | 92 +++++----- 7 files changed, 310 insertions(+), 191 deletions(-) diff --git a/algo/qa/Histogram.h b/algo/qa/Histogram.h index d05b17bc38..c3179618c3 100644 --- a/algo/qa/Histogram.h +++ b/algo/qa/Histogram.h @@ -4,7 +4,7 @@ /// \file Histogram.h /// \date 27.02.2024 -/// \brief Interface to 1D histogram +/// \brief ROOT-free implementation of a histogram /// \author Sergei Zharko <s.zharko@gsi.de> #pragma once @@ -27,6 +27,8 @@ #include <tuple> #include <type_traits> +#include <fmt/format.h> + namespace cbm::algo::qa { namespace bh = boost::histogram; @@ -48,6 +50,79 @@ namespace cbm::algo::qa Z }; + /// \enum EHistFlag + /// \brief Histogram control flags (bit masks) + enum class EHistFlag : uint8_t + { + StoreVsTsId = 0b00000001, ///< Store the histogram with the additional timeslice evolution axis + OmitIntegrated = 0b00000010 ///< Omits storing integrated histogram + }; + + /// \class HistogramMetadata + /// \brief Metadata of the histogram + /// \note To be sent with a configuration to the histogram server + class HistogramMetadata { + public: + using Flags_t = std::underlying_type_t<EHistFlag>; + + /// \brief Default constructor + HistogramMetadata() = default; + + /// \brief Constructor from the metadata string representation + /// \param msg Metadata string representation + explicit HistogramMetadata(const std::string& msg) + { + if (!msg.empty()) { + fFlags = std::stoi(msg, nullptr, 16); + } + } + + /// \brief Destructor + ~HistogramMetadata() = default; + + /// \brief Get flag + /// \param key Flag key from the EHistFlag enumeration + bool GetFlag(EHistFlag key) const { return static_cast<bool>(fFlags & static_cast<Flags_t>(key)); } + + /// \brief Get flag + /// \param key Flag key from the EHistFlag enumeration + /// \param flag Flag value + void SetFlag(EHistFlag key, bool flag = true) + { + flag ? (fFlags |= static_cast<Flags_t>(key)) : (fFlags &= ~static_cast<Flags_t>(key)); + } + + /// \brief Converts the metadata to a string + /// + /// Current implementation of the metadata string: <flags> + /// Future implementation with additional fields: <flags>;<...>;<...>;...;<...> + std::string ToString() const { return fmt::format("{0:02x}", fFlags); } + + /// \brief Separates a name and metadata of histogram + /// \return std::pair<std::string, std::string>: (name, metadata) + static std::pair<std::string, std::string> SeparateNameAndMetadata(const std::string& msg) + { + size_t pos = msg.find_last_of('!'); + if (pos != msg.npos) { + return std::make_pair(msg.substr(0, pos), msg.substr(pos + 1)); + } + else { + return std::make_pair(msg, ""); + } + } + + private: + friend class boost::serialization::access; + template<class Archive> + /// \brief Serialization rule + void serialize(Archive& ar, const unsigned int /*version*/) + { + ar& fFlags; + } + + Flags_t fFlags{}; ///< Flags collection for the histogram + }; + /// \class TotalSums1D /// \brief Storage for total sums of weights, squared weights, weights over x, weights over squared x class TotalSums1D { @@ -64,18 +139,6 @@ namespace cbm::algo::qa /// \brief Gets total sum of weight over squared x products double GetTotSumWX2() const { return fTotSumWX2; } - private: - /// \brief Serialization rule - friend class boost::serialization::access; - template<class Archive> - void serialize(Archive& ar, const unsigned int /*version*/) - { - ar& fTotSumW; - ar& fTotSumW2; - ar& fTotSumWX; - ar& fTotSumWX2; - } - protected: /// \brief Updates the sums /// \param x X value @@ -101,6 +164,18 @@ namespace cbm::algo::qa double fTotSumW2 = 0.; ///< Total sum (over all bins) of squared weights double fTotSumWX = 0.; ///< Total sum (over all bins) of weight over x products double fTotSumWX2 = 0.; ///< Total sum (over all bins) of weight over square x products + + private: + /// \brief Serialization rule + friend class boost::serialization::access; + template<class Archive> + void serialize(Archive& ar, const unsigned int /*version*/) + { + ar& fTotSumW; + ar& fTotSumW2; + ar& fTotSumWX; + ar& fTotSumWX2; + } }; /// \class TotalSums2D @@ -116,18 +191,6 @@ namespace cbm::algo::qa /// \brief Gets total sum of weight over squared y products double GetTotSumWY2() const { return fTotSumWY2; } - private: - /// \brief Serialization rule - friend class boost::serialization::access; - template<class Archive> - void serialize(Archive& ar, const unsigned int /*version*/) - { - ar& boost::serialization::base_object<TotalSums1D>(*this); - ar& fTotSumWXY; - ar& fTotSumWY; - ar& fTotSumWY2; - } - protected: /// \brief Resets the sums void Reset() @@ -153,6 +216,18 @@ namespace cbm::algo::qa double fTotSumWY = 0.; ///< Total sum (over all bins) of weight over y products double fTotSumWXY = 0.; ///< Total sum (over all bins) of weight over square x products double fTotSumWY2 = 0.; ///< Total sum (over all bins) of weight over x over y products + + private: + /// \brief Serialization rule + friend class boost::serialization::access; + template<class Archive> + void serialize(Archive& ar, const unsigned int /*version*/) + { + ar& boost::serialization::base_object<TotalSums1D>(*this); + ar& fTotSumWXY; + ar& fTotSumWY; + ar& fTotSumWY2; + } }; @@ -171,16 +246,21 @@ namespace cbm::algo::qa /// \brief Destructor ~Histogram() = default; - /// \brief Gets number of entries - // TODO: Gives different results, if weights are not 1 (investigate!) - double GetEntries() const + /// \brief Gets range lower bound of the selected axis + /// \tparam AxisType An axis + template<EAxis A, unsigned IA = static_cast<unsigned>(A), std::enable_if_t<(IA < Rank), bool> = true> + double GetAxisMin() const { - // return bh::algorithm::sum(fHistogram); // -> effective entries (but different to the ROOT ones: if w != 1) - return fEntries; + return fHistogram.template axis<IA>().value(0.); } - /// \brief Gets name - const std::string& GetName() const { return fName; } + /// \brief Gets range upper bound of the selected axis + /// \tparam AxisType An axis + template<EAxis A, unsigned IA = static_cast<unsigned>(A), std::enable_if_t<(IA < Rank), bool> = true> + double GetAxisMax() const + { + return fHistogram.template axis<IA>().value(static_cast<double>(GetAxisNbins<A>())); + } /// \brief Gets number of bins in axis /// \tparam AxisT An axis @@ -191,21 +271,26 @@ namespace cbm::algo::qa return fHistogram.template axis<IA>().size(); } - /// \brief Gets range lower bound of the selected axis - /// \tparam AxisType An axis - template<EAxis A, unsigned IA = static_cast<unsigned>(A), std::enable_if_t<(IA < Rank), bool> = true> - double GetAxisMin() const + /// \brief Gets number of entries + // TODO: Gives different results, if weights are not 1 (investigate!) + double GetEntries() const { - return fHistogram.template axis<IA>().value(0.); + // return bh::algorithm::sum(fHistogram); // -> effective entries (but different to the ROOT ones: if w != 1) + return fEntries; } - /// \brief Gets range upper bound of the selected axis - /// \tparam AxisType An axis - template<EAxis A, unsigned IA = static_cast<unsigned>(A), std::enable_if_t<(IA < Rank), bool> = true> - double GetAxisMax() const - { - return fHistogram.template axis<IA>().value(static_cast<double>(GetAxisNbins<A>())); - } + /// \brief Get flag + /// \param key Flag key from the EHistFlag enumeration + bool GetFlag(EHistFlag key) const { return fMetadata.GetFlag(key); } + + /// \brief Gets name + const std::string& GetName() const { return fName; } + + /// \brief Gets metadata instance + const HistogramMetadata& GetMetadata() const { return fMetadata; } + + /// \brief Gets metadata string + std::string GetMetadataString() const { return fMetadata.ToString(); } /// \brief Gets number of bins for x axis uint32_t GetNbinsX() const { return GetAxisNbins<EAxis::X>(); } @@ -260,6 +345,11 @@ namespace cbm::algo::qa fEntries = 0; } + /// \brief Get flag + /// \param key Flag key from the EHistFlag enumeration + /// \param flag Flag value + void SetFlag(EHistFlag key, bool flag = true) { fMetadata.SetFlag(key, flag); } + /// \brief Sets name /// \param name Histogram name void SetName(const std::string& name) { fName = name; } @@ -276,23 +366,11 @@ namespace cbm::algo::qa // msg << //} - private: - friend class boost::serialization::access; - template<class Archive> - /// \brief Serialization rule - void serialize(Archive& ar, const unsigned int /*version*/) - { - ar& boost::serialization::base_object<TotalSums>(*this); - ar& fHistogram; - ar& fName; - ar& fTitle; - ar& fEntries; - } - protected: /// \brief Default constructor Histogram() = default; + /// \brief Copy constructor explicit Histogram(const Histogram<Axes, Storage, TotalSums>& h) = default; //explicit Histogram(const Histogram<Axes, Storage>& h) @@ -312,6 +390,7 @@ namespace cbm::algo::qa , fName(name) , fTitle(title) , fEntries(0) + , fMetadata(HistogramMetadata()) { } @@ -320,10 +399,26 @@ namespace cbm::algo::qa /// \return Bin in boost histogram inline static int GetBinBH(uint32_t iBin) { return (iBin > 0) ? iBin - 1 : -1; } - Hist_t fHistogram; - std::string fName = ""; - std::string fTitle = ""; - int fEntries = 0; ///< Number of entries + Hist_t fHistogram; ///< Underlying boost histogram + std::string fName = ""; ///< Name of the histogram + std::string fTitle = ""; ///< Title of the histogram + int fEntries = 0; ///< Number of histogram entries + HistogramMetadata fMetadata; ///< Meta-data for histogram + + + private: + friend class boost::serialization::access; + template<class Archive> + /// \brief Serialization rule + void serialize(Archive& ar, const unsigned int /*version*/) + { + ar& boost::serialization::base_object<TotalSums>(*this); + ar& fHistogram; + ar& fName; + ar& fTitle; + ar& fEntries; + ar& fMetadata; + } }; using BaseH1D = Histogram<Axes1D_t, HistStorage_t, TotalSums1D>; @@ -378,6 +473,10 @@ namespace cbm::algo::qa return iBin; } + /// \brief Gets underlying bin accumulator + /// \param iBin Bin index + auto GetBinAccumulator(uint32_t iBin) const { return fHistogram.at(Histogram::GetBinBH(iBin)); } + /// \brief Gets bin content /// \param iBin Bin index double GetBinContent(uint32_t iBin) const { return fHistogram.at(Histogram::GetBinBH(iBin)).value(); } @@ -386,10 +485,6 @@ namespace cbm::algo::qa /// \param iBin Bin index double GetBinError(uint32_t iBin) const { return std::sqrt(fHistogram.at(Histogram::GetBinBH(iBin)).variance()); } - /// \brief Gets underlying bin accumulator - /// \param iBin Bin index - auto GetBinAccumulator(uint32_t iBin) const { return fHistogram.at(Histogram::GetBinBH(iBin)); } - private: /// \brief Serialization function friend class boost::serialization::access; @@ -493,7 +588,7 @@ namespace cbm::algo::qa } }; - // NOTE: Boost::histogram by default uses a different error calculation approach as ROOT TProfile. TODO: investigate + // TODO: Boost::histogram by default uses a different error calculation approach as ROOT TProfile. TODO: investigate class Prof1D : public BaseProf1D { public: @@ -587,8 +682,8 @@ namespace cbm::algo::qa ar& fYmax; } - double fYmin = 0.; - double fYmax = 0.; + double fYmin = 0.; ///< Lower bound of the profile y-axis + double fYmax = 0.; ///< Upper bound of the profile y-axis }; class Prof2D : public BaseProf2D { @@ -710,8 +805,8 @@ namespace cbm::algo::qa ar& fZmax; } - double fZmin = 0.; - double fZmax = 0.; + double fZmin = 0.; ///< Lower bound of the profile z-axis + double fZmax = 0.; ///< Upper bound of the profile z-axis }; } // namespace cbm::algo::qa diff --git a/algo/qa/HistogramContainer.cxx b/algo/qa/HistogramContainer.cxx index 8db32a09a1..b70cb5f371 100644 --- a/algo/qa/HistogramContainer.cxx +++ b/algo/qa/HistogramContainer.cxx @@ -9,22 +9,17 @@ #include "HistogramContainer.h" +#include <algorithm> + using cbm::algo::qa::HistogramContainer; // --------------------------------------------------------------------------------------------------------------------- // void HistogramContainer::Reset() { - for (auto& h : fvH1) { - h.Reset(); - } - for (auto& h : fvH2) { - h.Reset(); - } - for (auto& h : fvP1) { - h.Reset(); - } - for (auto& h : fvP2) { - h.Reset(); - } + constexpr auto ResetHistograms = [&](auto& h) { h.Reset(); }; + std::for_each(fvH1.begin(), fvH1.end(), ResetHistograms); + std::for_each(fvH2.begin(), fvH2.end(), ResetHistograms); + std::for_each(fvP1.begin(), fvP1.end(), ResetHistograms); + std::for_each(fvP2.begin(), fvP2.end(), ResetHistograms); } diff --git a/algo/qa/HistogramContainer.h b/algo/qa/HistogramContainer.h index eb8630a6ca..3816c0bc88 100644 --- a/algo/qa/HistogramContainer.h +++ b/algo/qa/HistogramContainer.h @@ -24,6 +24,7 @@ namespace cbm::algo::qa std::forward_list<qa::H2D> fvH2 = {}; ///< List of 2D-histograms std::forward_list<qa::Prof1D> fvP1 = {}; ///< List of 1D-profiles std::forward_list<qa::Prof2D> fvP2 = {}; ///< List of 2D-profiles + int fTimeSliceId = 0; ///< Index of the time-slice /// \brief Resets the histograms void Reset(); @@ -37,6 +38,7 @@ namespace cbm::algo::qa ar& fvH2; ar& fvP1; ar& fvP2; + ar& fTimeSliceId; } }; } // namespace cbm::algo::qa diff --git a/algo/qa/QaData.cxx b/algo/qa/QaData.cxx index 7ab94afa0f..81c53f5e8e 100644 --- a/algo/qa/QaData.cxx +++ b/algo/qa/QaData.cxx @@ -9,6 +9,8 @@ #include "QaData.h" +#include <algorithm> + using cbm::algo::qa::Data; // --------------------------------------------------------------------------------------------------------------------- @@ -25,18 +27,16 @@ void Data::Init(std::shared_ptr<HistogramSender> histSender) nHistograms += std::distance(fHistograms.fvP1.begin(), fHistograms.fvP1.end()); nHistograms += std::distance(fHistograms.fvP2.begin(), fHistograms.fvP2.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); - } - for (const auto& hist : fHistograms.fvP1) { - vHistCfgs.emplace_back(hist.GetName(), fsName); - } - for (const auto& hist : fHistograms.fvP2) { - vHistCfgs.emplace_back(hist.GetName(), fsName); - } + + auto RegHist = [&](const auto& h) { + //vHistCfgs.emplace_back(h.GetName() + "!" + h.GetMetadataString(), fsName); + vHistCfgs.emplace_back(h.GetName(), fsName); + }; + + std::for_each(fHistograms.fvH1.begin(), fHistograms.fvH1.end(), RegHist); + std::for_each(fHistograms.fvH2.begin(), fHistograms.fvH2.end(), RegHist); + std::for_each(fHistograms.fvP1.begin(), fHistograms.fvP1.end(), RegHist); + std::for_each(fHistograms.fvP2.begin(), fHistograms.fvP2.end(), RegHist); // Forming a canvas config message std::vector<std::pair<std::string, std::string>> vCanvCfgs; @@ -47,12 +47,12 @@ void Data::Init(std::shared_ptr<HistogramSender> histSender) histSender->PrepareAndSendMsg(std::pair<uint32_t, uint32_t>(vHistCfgs.size(), vCanvCfgs.size()), zmq::send_flags::sndmore); - for (const auto& cfg : vHistCfgs) { - histSender->PrepareAndSendMsg(cfg, zmq::send_flags::sndmore); - } - for (const auto& cfg : vCanvCfgs) { - histSender->PrepareAndSendMsg(cfg, zmq::send_flags::sndmore); - } + + auto RegCfg = [&](const auto& cfg) { histSender->PrepareAndSendMsg(cfg, zmq::send_flags::sndmore); }; + + std::for_each(vHistCfgs.begin(), vHistCfgs.end(), RegCfg); + std::for_each(vCanvCfgs.begin(), vCanvCfgs.end(), RegCfg); + // Histograms serialization and emission to close multi-part message histSender->PrepareAndSendMsg(qa::HistogramContainer{}, zmq::send_flags::none); } diff --git a/core/qa/report/CbmQaReportElement.h b/core/qa/report/CbmQaReportElement.h index e469f10425..ef4d84315e 100644 --- a/core/qa/report/CbmQaReportElement.h +++ b/core/qa/report/CbmQaReportElement.h @@ -54,7 +54,7 @@ namespace cbm::qa::report void SetTitle(std::string_view title) { fsTitle = title; } /// \brief Gets mother element - const Element* const GetMother() const { return fpMother; } + const Element* GetMother() const { return fpMother; } private: void AssignMother(const Element* pMother) { fpMother = pMother; } diff --git a/services/histserv/app/Application.cxx b/services/histserv/app/Application.cxx index 39597c6832..bb763da0e7 100644 --- a/services/histserv/app/Application.cxx +++ b/services/histserv/app/Application.cxx @@ -203,35 +203,22 @@ bool Application::ReceiveData(zmq::message_t& msg) /// FIXME: Lead to "Warning in <TROOT::Append>: Replacing existing TH1: xxxxxx (Potential memory leak)." // Collect histograms - for (auto& source : vHist.fvH1) { - TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source); - if (!ReadHistogram<TH1>(result)) { // - return false; - } - delete result; - } - for (auto& source : vHist.fvH2) { - TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source); - if (!ReadHistogram<TH1>(result)) { // - return false; - } - delete result; - } - for (auto& source : vHist.fvP1) { - TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source); - if (!ReadHistogram<TH1>(result)) { // - return false; - } - delete result; - } - for (auto& source : vHist.fvP2) { - TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source); - if (!ReadHistogram<TH1>(result)) { // - return false; + auto CollectHistogram = [&](const auto& container) -> bool { + for (auto& source : container) { + TH1* hist = cbm::qa::OnlineInterface::ROOTHistogram(source); + if (!ReadHistogram<TH1>(hist)) { + delete hist; + return false; + } + delete hist; } - delete result; - } + return true; + }; + if (!CollectHistogram(vHist.fvH1)) return false; + if (!CollectHistogram(vHist.fvH2)) return false; + if (!CollectHistogram(vHist.fvP1)) return false; + if (!CollectHistogram(vHist.fvP2)) return false; /// If new histos received, try to prepare as many canvases as possible /// Should be expensive on start and cheap afterward @@ -321,6 +308,8 @@ bool Application::ReceiveData(zmq::message_t& msg) // bool Application::ReceiveHistoConfig(zmq::message_t& msg) { + using cbm::algo::qa::EHistFlag; + using cbm::algo::qa::HistogramMetadata; /// FIXME: Something to replace FairMQ and extract the config!!!! // BoostSerializer<std::pair<std::string, std::string>>().Deserialize(msg, tempObject); b_io::basic_array_source<char> device(static_cast<char*>(msg.data()), msg.size()); @@ -343,29 +332,22 @@ bool Application::ReceiveHistoConfig(zmq::message_t& msg) iarch >> tempObject; } - LOG(debug) << " Received configuration for histo " << tempObject.first << " : " << tempObject.second; - - /// Check if histo name already received in previous messages - /// Linear search should be ok as config is shared only at startup - UInt_t uPrevHist = 0; - for (uPrevHist = 0; uPrevHist < fvpsHistosFolder.size(); ++uPrevHist) { - if (fvpsHistosFolder[uPrevHist].first == tempObject.first) { // - break; - } - } // for( UInt_t uPrevHist = 0; uPrevHist < fvpsHistosFolder.size(); ++uPrevHist ) - - if (uPrevHist < fvpsHistosFolder.size()) { - LOG(debug) << " Ignored new configuration for histo " << tempObject.first - << " due to previously received one: " << tempObject.second; - /// Not sure if we should return false here... - } // if( uPrevHist < fvpsHistosFolder.size() ) - else { - fvpsHistosFolder.push_back(tempObject); - fvHistos.push_back(std::pair<TNamed*, std::string>(nullptr, "")); - fvbHistoRegistered.push_back(false); - fbAllHistosRegistered = false; - LOG(info) << " Stored configuration for histo " << tempObject.first << " : " << tempObject.second; - } // else of if( uPrevHist < fvpsHistosFolder.size() ) + // Parse metadata + LOG(info) << "\n\n\n!!!!!! tempObect-1: " << tempObject.first << ", " << tempObject.second << "\n\n"; + std::string& name = tempObject.first; + std::string metadataMsg{}; + std::tie(name, metadataMsg) = HistogramMetadata::SeparateNameAndMetadata(name); + LOG(info) << "\n\n\n!!!!!! tempObect-2: " << tempObject.first << ", " << tempObject.second << "\n\n"; + auto metadata = HistogramMetadata(metadataMsg); + + if (!metadata.GetFlag(EHistFlag::OmitIntegrated)) { + // Main (integrated over time) histogram + this->RegisterHistoConfig(tempObject); + } + if (metadata.GetFlag(EHistFlag::StoreVsTsId)) { + // Histogram vs. TS id + this->RegisterHistoConfig(std::make_pair(name + std::string(ksTsIdSuffix), tempObject.second)); + } return true; } @@ -520,6 +502,7 @@ bool Application::ReadHistogram(HistoT* pHist) { int index1 = FindHistogram(pHist->GetName()); if (-1 == index1) { + // ----- Creating new histogram HistoT* histogram_new = static_cast<HistoT*>(pHist->Clone()); fArrayHisto.Add(histogram_new); @@ -558,6 +541,7 @@ bool Application::ReadHistogram(HistoT* pHist) } // if( !fbAllCanvasReady ) } // if (-1 == index1) else { + // ----- Update histogram LOG(debug) << "Received update for: " << pHist->GetName(); HistoT* histogram_existing = dynamic_cast<HistoT*>(fArrayHisto.At(index1)); if (nullptr == histogram_existing) { @@ -571,6 +555,37 @@ bool Application::ReadHistogram(HistoT* pHist) return true; } +// --------------------------------------------------------------------------------------------------------------------- +// +bool Application::RegisterHistoConfig(const std::pair<std::string, std::string>& config) +{ + LOG(debug) << " Received configuration for histo " << config.first << " : " << config.second; + + /// Check if histo name already received in previous messages + /// Linear search should be ok as config is shared only at startup + UInt_t uPrevHist = 0; + for (uPrevHist = 0; uPrevHist < fvpsHistosFolder.size(); ++uPrevHist) { + if (fvpsHistosFolder[uPrevHist].first == config.first) { // + break; + } + } // for( UInt_t uPrevHist = 0; uPrevHist < fvpsHistosFolder.size(); ++uPrevHist ) + + if (uPrevHist < fvpsHistosFolder.size()) { + LOG(debug) << " Ignored new configuration for histo " << config.first + << " due to previously received one: " << config.second; + /// Not sure if we should return false here... + } // if( uPrevHist < fvpsHistosFolder.size() ) + else { + fvpsHistosFolder.push_back(config); + fvHistos.push_back(std::pair<TNamed*, std::string>(nullptr, "")); + fvbHistoRegistered.push_back(false); + fbAllHistosRegistered = false; + LOG(info) << " Stored configuration for histo " << config.first << " : " << config.second; + } // else of if( uPrevHist < fvpsHistosFolder.size() ) + + return true; +} + // --------------------------------------------------------------------------------------------------------------------- // int Application::FindHistogram(const std::string& name) diff --git a/services/histserv/app/Application.h b/services/histserv/app/Application.h index 2a14d8124b..7d7d55d22e 100644 --- a/services/histserv/app/Application.h +++ b/services/histserv/app/Application.h @@ -5,6 +5,7 @@ #ifndef CBM_SERVICES_HISTSERV_APP_APPLICATION_H #define CBM_SERVICES_HISTSERV_APP_APPLICATION_H 1 +#include "Histogram.h" #include "ProgramOptions.h" #include "THttpServer.h" #include "TObjArray.h" @@ -13,6 +14,7 @@ #include <csignal> #include <memory> #include <string> +#include <string_view> #include <thread> #include <zmq.hpp> @@ -22,67 +24,77 @@ class TNamed; namespace cbm::services::histserv { class Application { - public: + static constexpr std::string_view ksTsIdSuffix = "_ts_id"; ///< Suffix of additional histograms vs. TS index + + public: /** @brief Standard constructor, initialises the application ** @param opt **/ - explicit Application(ProgramOptions const& opt, volatile sig_atomic_t* signalStatus); + explicit Application(ProgramOptions const& opt, volatile sig_atomic_t* signalStatus); - /** @brief Copy constructor forbidden **/ - Application(const Application&) = delete; + /** @brief Copy constructor forbidden **/ + Application(const Application&) = delete; - /** @brief Assignment operator forbidden **/ - void operator=(const Application&) = delete; + /** @brief Assignment operator forbidden **/ + void operator=(const Application&) = delete; - /** @brief Destructor **/ - ~Application(); + /** @brief Destructor **/ + ~Application(); - /** @brief Run the application **/ - void Exec(); + /** @brief Run the application **/ + void Exec(); - void UpdateHttpServer(); + void UpdateHttpServer(); - private: + private: //const std::string& ConfigFile() const; + /// \param name A name of the histogram + int FindHistogram(const std::string& name); - /// \brief Receives histograms - bool ReceiveData(zmq::message_t& msg); + /// \brief Resets handled histograms + bool ResetHistograms(); - /// \brief Receives histogram configuration - bool ReceiveHistoConfig(zmq::message_t& msg); + /// \brief Read a histogram + /// \tparam HistoT Histogram type + /// \param pHist Pointer to the histogram + template<class HistoT> + bool ReadHistogram(HistoT* pHist); - /// \brief Receives canvas configuration - bool ReceiveCanvasConfig(zmq::message_t& msg); + /// \brief Find histogram index in the histogram array + /// \brief Receives histograms + bool ReceiveData(zmq::message_t& msg); - /// \brief Receives a list of canvases and histograms - /// \param vMsg Message with the histograms and canvases list - bool ReceiveConfigAndData(std::vector<zmq::message_t>& vMsg); + /// \brief Receives histogram configuration + bool ReceiveHistoConfig(zmq::message_t& msg); - /// \brief Read a histogram - /// \tparam HistoT Histogram type - /// \param pHist Pointer to the histogram - template<class HistoT> - bool ReadHistogram(HistoT* pHist); + /// \brief Receives canvas configuration + bool ReceiveCanvasConfig(zmq::message_t& msg); - /// \brief Find histogram index in the histogram array - /// \param name A name of the histogram - int FindHistogram(const std::string& name); + /// \brief Receives a list of canvases and histograms + /// \param vMsg Message with the histograms and canvases list + bool ReceiveConfigAndData(std::vector<zmq::message_t>& vMsg); - /// \brief Prepares canvases using received canvas configuration - /// \param uCanvIdx Index of canvas - bool PrepareCanvas(uint32_t uCanvIdx); + /// \brief Register a histogram config in the histogram server + /// \param config A pair (histogram name, histogram directory) + /// + /// This function should be called after the metadata is extracted from the config. + bool RegisterHistoConfig(const std::pair<std::string, std::string>& config); - /// \brief Resets handled histograms - bool ResetHistograms(); + /// \brief Register a histogram in the histogram server + /// \param hist A pointer to histogram + bool RegisterHistogram(const TNamed* hist); - /// \brief Saves handled histograms - bool SaveHistograms(); + /// \brief Prepares canvases using received canvas configuration + /// \param uCanvIdx Index of canvas + bool PrepareCanvas(uint32_t uCanvIdx); - /// \brief A handler for system signals - /// \param signal Signal ID - //static void SignalHandler(int signal); + /// \brief Saves handled histograms + bool SaveHistograms(); + /// \brief A handler for system signals + /// \param signal Signal ID + //static void SignalHandler(int signal); - private: + private: ProgramOptions const& fOpt; ///< Program options object volatile sig_atomic_t* fSignalStatus; ///< Global signal status THttpServer* fServer = nullptr; ///< ROOT Histogram server (JSroot) -- GitLab