diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx index a58d419693a676998a2cd0eae25f8d17dbe30b27..96063d31866e1a179eaee06f035598df5050aed9 100644 --- a/algo/global/Reco.cxx +++ b/algo/global/Reco.cxx @@ -270,6 +270,7 @@ RecoResults Reco::Run(const fles::Timeslice& ts) if (fSender != nullptr && Opts().Has(Subsystem::STS)) { fStsDigiQa->RegisterDigiData(&digis.fSts); fStsDigiQa->RegisterAuxDigiData(&auxDigis.fSts); + fStsDigiQa->SetTimesliceIndex(ts.index()); fStsDigiQa->Exec(); } } diff --git a/algo/qa/Histogram.h b/algo/qa/Histogram.h index c3179618c3853a7aa726d36a2a649e5d4413e6fa..852d9cf91bc86f3aeed64edd7ed7530aae8d3743 100644 --- a/algo/qa/Histogram.h +++ b/algo/qa/Histogram.h @@ -54,8 +54,8 @@ namespace cbm::algo::qa /// \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 + StoreVsTsId = 0b00000001, ///< Store the histogram vs timeslice index + OmitIntegrated = 0b00000010 ///< Omits storing integrated histogram }; /// \class HistogramMetadata diff --git a/algo/qa/HistogramContainer.h b/algo/qa/HistogramContainer.h index 3816c0bc88ee80028d2bdeb67e9ff5b95ebca571..3ccdbf263ab7ee8fc81ea13ac2cdc1c23d989282 100644 --- a/algo/qa/HistogramContainer.h +++ b/algo/qa/HistogramContainer.h @@ -24,7 +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 + uint64_t fTimesliceId = 0; ///< Index of the timeslice /// \brief Resets the histograms void Reset(); @@ -38,7 +38,7 @@ namespace cbm::algo::qa ar& fvH2; ar& fvP1; ar& fvP2; - ar& fTimeSliceId; + ar& fTimesliceId; } }; } // namespace cbm::algo::qa diff --git a/algo/qa/QaData.cxx b/algo/qa/QaData.cxx index 81c53f5e8e253b2df0e700d2d6c1c56ed1f10dca..ea184f35c101a0e0ca31bc2622374e3fb9d16a96 100644 --- a/algo/qa/QaData.cxx +++ b/algo/qa/QaData.cxx @@ -28,10 +28,7 @@ void Data::Init(std::shared_ptr<HistogramSender> histSender) nHistograms += std::distance(fHistograms.fvP2.begin(), fHistograms.fvP2.end()); vHistCfgs.reserve(nHistograms); - auto RegHist = [&](const auto& h) { - //vHistCfgs.emplace_back(h.GetName() + "!" + h.GetMetadataString(), fsName); - vHistCfgs.emplace_back(h.GetName(), fsName); - }; + auto RegHist = [&](const auto& h) { vHistCfgs.emplace_back(h.GetName() + "!" + h.GetMetadataString(), fsName); }; std::for_each(fHistograms.fvH1.begin(), fHistograms.fvH1.end(), RegHist); std::for_each(fHistograms.fvH2.begin(), fHistograms.fvH2.end(), RegHist); diff --git a/algo/qa/QaData.h b/algo/qa/QaData.h index 4eb94575f522557c437cf154c3662ce00e1e4123..b8347363368de0f8ba2a7fdce3ed98aeab23fd69 100644 --- a/algo/qa/QaData.h +++ b/algo/qa/QaData.h @@ -50,10 +50,6 @@ namespace cbm::algo::qa /// \param canvas A CanvasConfig object void AddCanvasConfig(const CanvasConfig& canvas) { fvsCanvCfgs.push_back(canvas.ToString()); } - /// \brief Creates a QA-object and returns the pointer to it - template<class Obj, typename... Args> - Obj* MakeObj(Args... args); - /// \brief Gets module name std::string_view GetName() const { return fsName; } @@ -61,6 +57,10 @@ namespace cbm::algo::qa /// \param histoSender A pointer to the histogram sender void Init(std::shared_ptr<HistogramSender> histoSender); + /// \brief Creates a QA-object and returns the pointer to it + template<class Obj, typename... Args> + Obj* MakeObj(Args... args); + /// \brief Resets the histograms void Reset() { fHistograms.Reset(); } @@ -69,6 +69,10 @@ namespace cbm::algo::qa /// \note Calls this->Reset() after sending the message to the histogram server void Send(std::shared_ptr<HistogramSender> histoSender); + /// \brief Updates the timeslice index + /// \param timesliceId Timeslice index + void SetTimesliceId(uint64_t timesliceId) { fHistograms.fTimesliceId = timesliceId; } + private: std::string fsName; ///< Name of the QA module (used as a directory name) qa::HistogramContainer fHistograms; ///< Histograms container diff --git a/algo/qa/unpack/QaBase.h b/algo/qa/unpack/QaBase.h index f63d652f2f18b0ec1cc43e9040b4219d1c7b7f2c..4e47eeb27731c15b3256714df8855d2eb3872acb 100644 --- a/algo/qa/unpack/QaBase.h +++ b/algo/qa/unpack/QaBase.h @@ -64,11 +64,14 @@ namespace cbm::algo::sts } } + /// \brief Register read-out setup config + void RegisterReadoutSetup(const ReadoutSetup& setup) { fpReadoutSetup = std::make_shared<ReadoutSetup>(setup); } + /// \brief Sets usage of auxiliary data void SetUseAuxData(bool bAux = true) { fbAux = bAux; } - /// \brief Register read-out setup config - void RegisterReadoutSetup(const ReadoutSetup& setup) { fpReadoutSetup = std::make_shared<ReadoutSetup>(setup); } + /// \brief Sets timeslice index + void SetTimesliceIndex(uint64_t tsIndex) { fQaData.SetTimesliceId(tsIndex); } protected: qa::Data fQaData; ///< QA data diff --git a/algo/qa/unpack/StsDigiQa.cxx b/algo/qa/unpack/StsDigiQa.cxx index 3f9a181c84b296181cfe40ccfcd9b34809fb5a23..8cb7a9ce0bd3f399233891e3c632cec1ae423889 100644 --- a/algo/qa/unpack/StsDigiQa.cxx +++ b/algo/qa/unpack/StsDigiQa.cxx @@ -22,6 +22,7 @@ void DigiQa::Init() { using cbm::algo::qa::CanvasConfig; using cbm::algo::qa::Data; + using cbm::algo::qa::EHistFlag; using cbm::algo::qa::H1D; using cbm::algo::qa::H2D; using cbm::algo::qa::PadConfig; @@ -69,6 +70,9 @@ void DigiQa::Init() auto name = format("sts_digi_{}_channel", aName); auto titl = format("Number of digis per channel for module {};channel;N_{{digis}}", aTitl); fvphAddressChannel[iM] = fQaData.MakeObj<H1D>(name, titl, 2048, -0.5, 2047.5); + if (fbAux) { + fvphAddressChannel[iM]->SetFlag(EHistFlag::StoreVsTsId); + } pad.RegisterHistogram(fvphAddressChannel[iM], "hist"); canv.AddPadConfig(pad); } diff --git a/core/qa/CbmQaOnlineInterface.cxx b/core/qa/CbmQaOnlineInterface.cxx index 0b5823b10a0326365cefa128ecd0d7cef69b5d0e..2554020e60290b5c6c5c6784f61a4e73534ea458 100644 --- a/core/qa/CbmQaOnlineInterface.cxx +++ b/core/qa/CbmQaOnlineInterface.cxx @@ -22,25 +22,40 @@ using cbm::algo::qa::Prof2D; using cbm::qa::OnlineInterface; using cbm::qa::RootHistogramAccessor; +// --------------------------------------------------------------------------------------------------------------------- +// +void OnlineInterface::AddSlice(const H1D& src, double value, TH2D* dst) +{ + auto* pDst = static_cast<RootHistogramAccessor<TH2D>*>(dst); + pDst->AddSliceFromQaHistogram<H1D>(src, value); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void OnlineInterface::AddSlice(const Prof1D& src, double value, TProfile2D* dst) +{ + auto* pDst = static_cast<RootHistogramAccessor<TProfile2D>*>(dst); + pDst->AddSliceFromQaHistogram<Prof1D>(src, value); +} // --------------------------------------------------------------------------------------------------------------------- // -TH1D* OnlineInterface::ROOTHistogram(const cbm::algo::qa::H1D& hist) +TH1D* OnlineInterface::ROOTHistogram(const H1D& hist) { int nBins = hist.GetNbinsX(); double xMin = hist.GetMinX(); double xMax = hist.GetMaxX(); bool add = TH1::AddDirectoryStatus(); TH1::AddDirectory(false); - auto* pRes = new RootHistogramAccessor<TH1D, H1D>(hist.GetName().c_str(), hist.GetTitle().c_str(), nBins, xMin, xMax); + auto* pRes = new RootHistogramAccessor<TH1D>(hist.GetName().c_str(), hist.GetTitle().c_str(), nBins, xMin, xMax); TH1::AddDirectory(add); - pRes->SetFromQaHistogram(hist); + pRes->SetFromQaHistogram<H1D>(hist); return pRes; } // --------------------------------------------------------------------------------------------------------------------- // -TH2D* OnlineInterface::ROOTHistogram(const cbm::algo::qa::H2D& hist) +TH2D* OnlineInterface::ROOTHistogram(const H2D& hist) { int nBinsX = hist.GetNbinsX(); double xMin = hist.GetMinX(); @@ -50,10 +65,10 @@ TH2D* OnlineInterface::ROOTHistogram(const cbm::algo::qa::H2D& hist) double yMax = hist.GetMaxY(); bool add = TH1::AddDirectoryStatus(); TH1::AddDirectory(false); - auto* pRes = new RootHistogramAccessor<TH2D, H2D>(hist.GetName().c_str(), hist.GetTitle().c_str(), nBinsX, xMin, xMax, - nBinsY, yMin, yMax); + auto* pRes = new RootHistogramAccessor<TH2D>(hist.GetName().c_str(), hist.GetTitle().c_str(), nBinsX, xMin, xMax, + nBinsY, yMin, yMax); TH1::AddDirectory(add); - pRes->SetFromQaHistogram(hist); + pRes->SetFromQaHistogram<H2D>(hist); return pRes; } @@ -70,9 +85,9 @@ TProfile* OnlineInterface::ROOTHistogram(const Prof1D& prof) double yMax = prof.GetMaxY(); bool add = TH1::AddDirectoryStatus(); TH1::AddDirectory(false); - auto* pRes = new RootHistogramAccessor<TProfile, Prof1D>(name, titl, nBinsX, xMin, xMax, yMin, yMax); + auto* pRes = new RootHistogramAccessor<TProfile>(name, titl, nBinsX, xMin, xMax, yMin, yMax); TH1::AddDirectory(add); - pRes->SetFromQaHistogram(prof); + pRes->SetFromQaHistogram<Prof1D>(prof); return pRes; } @@ -92,9 +107,8 @@ TProfile2D* OnlineInterface::ROOTHistogram(const Prof2D& prof) double zMax = prof.GetMaxZ(); bool add = TH1::AddDirectoryStatus(); TH1::AddDirectory(false); - auto* pRes = - new RootHistogramAccessor<TProfile2D, Prof2D>(name, titl, nBinsX, xMin, xMax, nBinsY, yMin, yMax, zMin, zMax); + auto* pRes = new RootHistogramAccessor<TProfile2D>(name, titl, nBinsX, xMin, xMax, nBinsY, yMin, yMax, zMin, zMax); TH1::AddDirectory(add); - pRes->SetFromQaHistogram(prof); + pRes->SetFromQaHistogram<Prof2D>(prof); return pRes; } diff --git a/core/qa/CbmQaOnlineInterface.h b/core/qa/CbmQaOnlineInterface.h index 462c90fb20d6e997394014e3424f14e625947ae1..64a48f8440a4ca48e09f5fa09c67de417952e047 100644 --- a/core/qa/CbmQaOnlineInterface.h +++ b/core/qa/CbmQaOnlineInterface.h @@ -21,6 +21,13 @@ #include <log.hpp> #include <type_traits> +namespace +{ + using cbm::algo::qa::H1D; + using cbm::algo::qa::H2D; + using cbm::algo::qa::Prof1D; + using cbm::algo::qa::Prof2D; +} // namespace namespace cbm::qa { @@ -30,7 +37,7 @@ namespace cbm::qa /// The ROOT TProfile classes do not alow to set a profile from outside, so we need to set all the /// fields directly. Also the access to TH1/TH2 protected fields is needed in order to set the /// total sums of w*x, w*x*x, w*y, w*x*y, and w*y*y. - template<class RootHistogram, class QaHistogram> + template<class RootHistogram> class RootHistogramAccessor : public RootHistogram { public: @@ -39,7 +46,16 @@ namespace cbm::qa { } + /// \brief Sets slice from the lower-dimension histogram + /// \tparam Source histogram type + /// \param src Source histogram + /// \param val Target value on the additional axis + template<class SourceQaHistogram> + void AddSliceFromQaHistogram(const SourceQaHistogram& histo, double val); + /// \brief Sets fields from qa histogram + /// \param histo Source histogram + template<class QaHistogram> void SetFromQaHistogram(const QaHistogram& histo); }; @@ -47,25 +63,38 @@ namespace cbm::qa /// \brief A collection of tools for online QA object conversions class OnlineInterface { public: + // TODO: generalize + /// \brief Fills a slice of a histogram of a higher dimension for a given value (....) + /// \param src 1D source histogram + /// \param value Slice coordinate + /// \param dst Destination 2D-histogram + static void AddSlice(const H1D& src, double value, TH2D* dst); + + /// \brief Fills a slice of a profile of a higher dimension for a given value (....) + /// \param src 1D source profile + /// \param value Slice coordinate + /// \param dst Destination 2D-profile + static void AddSlice(const Prof1D& src, double value, TProfile2D* dst); + /// \brief Converts histogram H1D to ROOT histogram TH1D /// \param hist 1D-histogram /// \note Allocates memory on heap for the ROOT histogram - static TH1D* ROOTHistogram(const cbm::algo::qa::H1D& hist); + static TH1D* ROOTHistogram(const H1D& hist); /// \brief Converts histogram H2D to ROOT histogram TH2D /// \param hist 1D-histogram /// \note Allocates memory on heap for the ROOT histogram - static TH2D* ROOTHistogram(const cbm::algo::qa::H2D& hist); + static TH2D* ROOTHistogram(const H2D& hist); /// \brief Converts profile Prof1D to ROOT TProfile /// \param prof 1D-profile /// \note Allocates memory on heap for the ROOT histogram - static TProfile* ROOTHistogram(const cbm::algo::qa::Prof1D& prof); + static TProfile* ROOTHistogram(const Prof1D& prof); /// \brief Converts profile Prof2D to ROOT TProfile2D /// \param prof 2D-profile /// \note Allocates memory on heap for the ROOT histogram - static TProfile2D* ROOTHistogram(const cbm::algo::qa::Prof2D& prof); + static TProfile2D* ROOTHistogram(const Prof2D& prof); }; } // namespace cbm::qa @@ -74,8 +103,49 @@ namespace cbm::qa { // ------------------------------------------------------------------------------------------------------------------- // - template<class RootHistogram, class QaHistogram> - void RootHistogramAccessor<RootHistogram, QaHistogram>::SetFromQaHistogram(const QaHistogram& hist) + template<class RootHistogram> + template<class QaHistogram> + void RootHistogramAccessor<RootHistogram>::AddSliceFromQaHistogram(const QaHistogram& src, double val) + { + constexpr bool IsDstH2D = std::is_same_v<RootHistogram, TH2D>; + constexpr bool IsDstProf2D = std::is_same_v<RootHistogram, TProfile2D>; + constexpr bool IsSrcH1D = std::is_same_v<QaHistogram, H1D>; + constexpr bool IsSrcProf1D = std::is_same_v<QaHistogram, Prof1D>; + + static_assert((IsDstH2D && IsSrcH1D) || (IsDstProf2D && IsSrcProf1D), + "function not implemented for a given (RootHistogram, QaHistogram) pair"); + + auto iBinX = this->GetXaxis()->FindBin(val); + for (int iBinY = 0; iBinY <= this->GetNbinsY() + 1; ++iBinY) { + int iGlobBin = this->GetBin(iBinX, iBinY); + auto binSrc = src.GetBinAccumulator(iBinY); + if constexpr (IsSrcH1D) { + this->fArray[iGlobBin] += binSrc.value(); + if (this->fSumw2.fN) { + this->fSumw2.fArray[iGlobBin] += binSrc.variance(); + } + } + else if constexpr (IsSrcProf1D) { + this->fArray[iGlobBin] += binSrc.GetSumWV(); + this->fBinEntries.fArray[iGlobBin] += binSrc.GetSumW(); + this->fSumw2.fArray[iGlobBin] += binSrc.GetSumWV2(); + this->fBinSumw2.fArray[iGlobBin] += binSrc.GetSumW2(); + this->fTsumwz += binSrc.GetSumWV(); + this->fTsumwz2 += binSrc.GetSumWV2(); + } + } + this->fTsumw += src.GetTotSumW(); + this->fTsumw2 += src.GetTotSumW2(); + this->fTsumwx += src.GetTotSumWX(); + this->fTsumwx2 += src.GetTotSumWX2(); + this->SetEntries(this->GetEntries() + src.GetEntries()); + } + + // ------------------------------------------------------------------------------------------------------------------- + // + template<class RootHistogram> + template<class QaHistogram> + void RootHistogramAccessor<RootHistogram>::SetFromQaHistogram(const QaHistogram& hist) { // Set individual bin properties if constexpr (std::is_same_v<RootHistogram, TProfile> || std::is_same_v<RootHistogram, TProfile2D>) { diff --git a/services/histserv/app/Application.cxx b/services/histserv/app/Application.cxx index bb763da0e7e68463e93a2b8ab0f46c990a57bbfb..2e698f8b9b8219e45298092d8362cd2611216698 100644 --- a/services/histserv/app/Application.cxx +++ b/services/histserv/app/Application.cxx @@ -44,6 +44,11 @@ namespace b_ar = boost::archive; using cbm::services::histserv::Application; +using cbm::algo::qa::H1D; +using cbm::algo::qa::H2D; +using cbm::algo::qa::Prof1D; +using cbm::algo::qa::Prof2D; + // --------------------------------------------------------------------------------------------------------------------- // Application::Application(ProgramOptions const& opt, volatile sig_atomic_t* signalStatus) @@ -167,6 +172,31 @@ void Application::UpdateHttpServer() } } +// --------------------------------------------------------------------------------------------------------------------- +// +//template<class HistoSrc> +//bool Appliaction::CollectHistograms(const std::forward_list<HistoSrc>& container) +//{ +// for (const auto& hist : container) { +// if (!hist.GetFlag(cbm::algo::qa::EHistFlag::OmitIntegrated)) { +// if (!ReadHistogram<TH1>(hist)) { +// return false; +// } +// } +// if (hist.GetFlag(cbm::algo::qa::EHistFlag::StoreVsTsId)) { +// if constexpr (std::is_same_v<HistSrc, H1D> || std::is_same_v<HistSrc, Prof1D>) { +// if (!ReadHistogramExtendedTsId(hist, timesliceId)) { +// return false; +// } +// } +// else { +// LOG(warn) << "Histogram " << rHist.GetName() << " cannot be plotted vs. TS index. Ignoring"; +// } +// } +// } +// return true; +//} + // --------------------------------------------------------------------------------------------------------------------- // bool Application::ReceiveData(zmq::message_t& msg) @@ -201,24 +231,45 @@ bool Application::ReceiveData(zmq::message_t& msg) /// 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)." + auto timesliceId = vHist.fTimesliceId; - // Collect histograms - 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; + // Collects 1D-histograms (with possible extention vs. TS) + auto CollectHistogram1D = [&](const auto& container) -> bool { + for (const auto& hist : container) { + if (!hist.GetFlag(cbm::algo::qa::EHistFlag::OmitIntegrated)) { + if (!ReadHistogram<TH1>(hist)) { + return false; + } + } + if (hist.GetFlag(cbm::algo::qa::EHistFlag::StoreVsTsId)) { + if (!ReadHistogramExtendedTsId(hist, timesliceId)) { + return false; + } + } + } + return true; + }; + + // Collects 2D-histograms + // TODO: Add a possibility to store multiple histograms vs each time-slice depending on the StoreVsTsId flag + // NOTE: TProfile2D can be extended to TProfile3D, and TH2D can be extended to TH3D. Should we provide such a possibility, + // or it does not make sence? (SZh) + auto CollectHistogram2D = [&](const auto& container) -> bool { + for (const auto& hist : container) { + if (!hist.GetFlag(cbm::algo::qa::EHistFlag::OmitIntegrated)) { + if (!ReadHistogram<TH1>(hist)) { + return false; + } } - delete hist; } 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 (!CollectHistogram1D(vHist.fvH1)) return false; + if (!CollectHistogram2D(vHist.fvH2)) return false; + if (!CollectHistogram1D(vHist.fvP1)) return false; + if (!CollectHistogram2D(vHist.fvP2)) return false; + /// If new histos received, try to prepare as many canvases as possible /// Should be expensive on start and cheap afterward @@ -333,12 +384,10 @@ bool Application::ReceiveHistoConfig(zmq::message_t& msg) } // 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); + auto metadata = HistogramMetadata(metadataMsg); if (!metadata.GetFlag(EHistFlag::OmitIntegrated)) { // Main (integrated over time) histogram @@ -497,13 +546,14 @@ bool Application::ReceiveConfigAndData(std::vector<zmq::message_t>& vMsg) // --------------------------------------------------------------------------------------------------------------------- // -template<class HistoT> -bool Application::ReadHistogram(HistoT* pHist) +template<class HistoDst, class HistoSrc> +bool Application::ReadHistogram(const HistoSrc& rHist) { + HistoDst* pHist = cbm::qa::OnlineInterface::ROOTHistogram(rHist); int index1 = FindHistogram(pHist->GetName()); if (-1 == index1) { // ----- Creating new histogram - HistoT* histogram_new = static_cast<HistoT*>(pHist->Clone()); + HistoDst* histogram_new = static_cast<HistoDst*>(pHist->Clone()); fArrayHisto.Add(histogram_new); LOG(info) << "Received new histo " << pHist->GetName(); @@ -543,15 +593,110 @@ bool Application::ReadHistogram(HistoT* pHist) else { // ----- Update histogram LOG(debug) << "Received update for: " << pHist->GetName(); - HistoT* histogram_existing = dynamic_cast<HistoT*>(fArrayHisto.At(index1)); + HistoDst* histogram_existing = dynamic_cast<HistoDst*>(fArrayHisto.At(index1)); if (nullptr == histogram_existing) { LOG(error) << "CbmMqHistoServer::ReadHistogram => " << "Incompatible type found during update for histo " << pHist->GetName(); + delete pHist; return false; } // if( nullptr == histogram_existing ) histogram_existing->Add(pHist); } // else of if (-1 == index1) + delete pHist; + return true; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +template<class HistoSrc> +bool Application::ReadHistogramExtendedTsId(const HistoSrc& rHist, uint64_t tsIndex) +{ + constexpr bool IsSrcH1D = std::is_same_v<HistoSrc, H1D>; + constexpr bool IsSrcProf1D = std::is_same_v<HistoSrc, Prof1D>; + + if constexpr (IsSrcH1D || IsSrcProf1D) { + /* clang-format off */ + using HistoDst_t = typename std::conditional<IsSrcH1D, TH2D, TProfile2D>::type; + /* clang-format on */ + + std::string sHistoName = rHist.GetName() + std::string(ksTsIdSuffix); + int index1 = FindHistogram(sHistoName.c_str()); + if (-1 == index1) { + // ----- Creating new histogram + HistoDst_t* histogram_new = nullptr; + { + std::string title = rHist.GetTitle(); + title.insert(title.find_first_of(';'), " vs. TS index;TS index"); + int nBinsX = fConfig.fNofTsToStore; + double minX = static_cast<double>(tsIndex) - 0.5; + double maxX = static_cast<double>(tsIndex + nBinsX) - 0.5; + int nBinsY = rHist.GetNbinsX(); + double minY = rHist.GetMinX(); + double maxY = rHist.GetMaxX(); + if constexpr (IsSrcH1D) { + histogram_new = new TH2D(sHistoName.c_str(), title.c_str(), nBinsX, minX, maxX, nBinsY, minY, maxY); + } + else if constexpr (IsSrcProf1D) { + double minZ = rHist.GetMinY(); + double maxZ = rHist.GetMaxY(); + histogram_new = + new TProfile2D(sHistoName.c_str(), title.c_str(), nBinsX, minX, maxX, nBinsY, minY, maxY, minZ, maxZ); + } + } + cbm::qa::OnlineInterface::AddSlice(rHist, double(tsIndex), histogram_new); + fArrayHisto.Add(histogram_new); + + LOG(info) << "Received new histo " << sHistoName; + + /// If new histo received, try to register it if configuration available + if (!fbAllHistosRegistered) { + for (uint32_t uHist = 0; uHist < fvpsHistosFolder.size(); ++uHist) { + /// Jump histos already ready + if (fvbHistoRegistered[uHist]) { // + continue; + } + + /// Check if name matches one in config for others + if (fvpsHistosFolder[uHist].first == histogram_new->GetName()) { + fvHistos[uHist] = std::pair<TNamed*, std::string>(histogram_new, fvpsHistosFolder[uHist].second); + fServer->Register(Form("/%s", fvHistos[uHist].second.data()), fvHistos[uHist].first); + fvbHistoRegistered[uHist] = true; + + LOG(info) << "registered histo " << fvHistos[uHist].first->GetName() << " in folder " + << fvHistos[uHist].second; + + + /// Update flag telling whether all known histos are registered + fbAllHistosRegistered = true; + for (uint32_t uIdx = 0; uIdx < fvbHistoRegistered.size(); ++uIdx) { + if (!fvbHistoRegistered[uIdx]) { + fbAllHistosRegistered = false; + break; + } // if( !fvbHistoRegistered[ uIdx ] ) + } // for( uint32_t uIdx = 0; uIdx < fvbHistoRegistered.size(); ++uIdx ) + + break; + } // if( fvpsHistosFolder[ uHist ].first == histogram_new->GetName() ) + } // for( uint32_t uCanv = 0; uCanv < fvpsCanvasConfig.size(); ++uCanv ) + } // if( !fbAllCanvasReady ) + } // if (-1 == index1) + else { + // ----- Update histogram + LOG(debug) << "Received update for: " << sHistoName; + HistoDst_t* histogram_existing = dynamic_cast<HistoDst_t*>(fArrayHisto.At(index1)); + if (nullptr == histogram_existing) { + LOG(error) << "CbmMqHistoServer::ReadHistogram => " + << "Incompatible type found during update for histo " << sHistoName; + return false; + } // if( nullptr == histogram_existing ) + cbm::qa::OnlineInterface::AddSlice(rHist, double(tsIndex), histogram_existing); + } // else of if (-1 == index1) + } + else { + LOG(warn) << "Histogram " << rHist.GetName() << " cannot be plotted vs. TS index. Ignoring"; + } + return true; } diff --git a/services/histserv/app/Application.h b/services/histserv/app/Application.h index 7d7d55d22ea5814b232b80c0f4264e026d06f1a7..53cbdc848397df4a36582cd393e288fc07f09253 100644 --- a/services/histserv/app/Application.h +++ b/services/histserv/app/Application.h @@ -12,6 +12,7 @@ #include "ui_callbacks.h" #include <csignal> +#include <forward_list> #include <memory> #include <string> #include <string_view> @@ -23,6 +24,12 @@ class TNamed; namespace cbm::services::histserv { + /// \struct AppConfig + /// \brief Application configuarion + struct AppConfig { + int fNofTsToStore = 400; ///< Number of consequent timeslices to store + }; + class Application { static constexpr std::string_view ksTsIdSuffix = "_ts_id"; ///< Suffix of additional histograms vs. TS index @@ -46,6 +53,12 @@ namespace cbm::services::histserv void UpdateHttpServer(); private: + /// \brief Collects histograms of the same type from the histogram list + /// \tparam HistoSrc Histogram type + /// \param container List of histograms + //template<class HistoSrc> + //bool CollectHistograms(const std::forward_list<HistoSrc>& container); + //const std::string& ConfigFile() const; /// \param name A name of the histogram int FindHistogram(const std::string& name); @@ -54,10 +67,18 @@ namespace cbm::services::histserv bool ResetHistograms(); /// \brief Read a histogram - /// \tparam HistoT Histogram type - /// \param pHist Pointer to the histogram - template<class HistoT> - bool ReadHistogram(HistoT* pHist); + /// \tparam HistoDst Destination histogram type + /// \tparam HistoSrc Source histogram type + /// \param rHist Reference to the source histogram + template<class HistoDst, class HistoSrc> + bool ReadHistogram(const HistoSrc& rHist); + + /// \brief Reads a histogram slice for an extended histogram with the TS ID + /// \tparam HistoSrc Source histogram type + /// \param rHistSrc Reference to the source histogram + /// \param tsIndex Index of timeslice + template<class HistoSrc> + bool ReadHistogramExtendedTsId(const HistoSrc& pHistSrc, uint64_t tsIndex); /// \brief Find histogram index in the histogram array /// \brief Receives histograms @@ -117,6 +138,7 @@ namespace cbm::services::histserv std::vector<std::pair<std::string, std::string>> fvpsCanvasConfig = {}; std::vector<bool> fvbCanvasReady = {}; bool fbAllCanvasReady = false; + AppConfig fConfig; std::vector<std::pair<TNamed*, std::string>> fvHistos = {}; ///< Vector of Histos pointers and folder path std::vector<bool> fvbHistoRegistered = {};