From 0da6d651e752bfc1306b70120a8d332013494f0e Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Sun, 3 Mar 2024 22:27:28 +0100 Subject: [PATCH] online-qa: Histogram-server setup for accepting TProfile and TProfile2D objects --- algo/ca/qa/CaInputQa.cxx | 41 ++++++++++++++++--- algo/ca/qa/CaInputQa.h | 2 + algo/ca/qa/CaOutputQa.cxx | 2 +- algo/ca/qa/CaQaBase.h | 2 +- algo/qa/HistogramContainer.cxx | 12 +++--- algo/qa/HistogramContainer.h | 12 +++--- algo/qa/QaData.cxx | 13 +++++- algo/qa/QaData.h | 6 +++ services/histserv/app/Application.cxx | 58 +++++++++++---------------- services/histserv/app/CMakeLists.txt | 2 + 10 files changed, 95 insertions(+), 55 deletions(-) diff --git a/algo/ca/qa/CaInputQa.cxx b/algo/ca/qa/CaInputQa.cxx index ec3eba9e6c..b8e6352854 100644 --- a/algo/ca/qa/CaInputQa.cxx +++ b/algo/ca/qa/CaInputQa.cxx @@ -33,6 +33,7 @@ void InputQa::Init() using cbm::algo::qa::H1D; using cbm::algo::qa::H2D; using cbm::algo::qa::PadConfig; + using cbm::algo::qa::Prof2D; using fmt::format; if (!fpSender.get()) { @@ -53,6 +54,7 @@ void InputQa::Init() fvphHitOccupXY.resize(nSt); fvphHitOccupZX.resize(nSt); fvphHitOccupZY.resize(nSt); + fvphHitUsageXY.resize(nSt); // Station sizes in transverse plane std::vector<double> vMinX(nSt); @@ -114,6 +116,12 @@ void InputQa::Init() fvphHitOccupZY[iSt][hitSet] = fQaData.MakeObj<H2D>(name, titl, nBinsZ, zMinA, zMaxA, nBinsXY, yMinA, yMaxA); } } + { + auto name = format("hit_usage_xy_sta_{}", iSt); + auto titl = format("Hit usage in XY plane for station {} ({}{});x [cm];y [cm]", iSt, kDetName[detID], iStLoc); + fvphHitUsageXY[iSt] = + fQaData.MakeObj<Prof2D>(name, titl, nBinsXY, vMinX[iSt], vMaxX[iSt], nBinsXY, vMinY[iSt], vMaxY[iSt], 0., 1.); + } } } @@ -155,6 +163,18 @@ void InputQa::Init() fQaData.AddCanvasConfig(canv); } } + // Hit usage profiles + { + auto name = format("ca_hit_usage_xy"); + auto titl = format("Hit usage in different stations in XY plane"); + auto canv = CanvasConfig(name, titl); + for (int iSt = 0; iSt < nSt; ++iSt) { + auto pad = PadConfig(); + pad.RegisterHistogram(fvphHitUsageXY[iSt], "colz"); + canv.AddPadConfig(pad); + } + fQaData.AddCanvasConfig(canv); + } } fQaData.Init(fpSender); } @@ -172,14 +192,25 @@ void InputQa::Exec() assert(false); } + int nHitsInput = fpInputData->GetHits().size(); + // Map: if hit used in tracking + std::vector<unsigned char> vbHitUsed(nHitsInput, false); + for (int iH : (*fpvRecoHits)) { + vbHitUsed[iH] = true; + } + // Fill input hit histograms { - for (const auto& hit : fpInputData->GetHits()) { + for (int iH = 0; iH < nHitsInput; ++iH) { + const auto& hit = fpInputData->GetHit(iH); FillHitDistributionsForHitSet(EHitSet::Input, hit); - } - - for (int iH : (*fpvRecoHits)) { - FillHitDistributionsForHitSet(EHitSet::Used, fpInputData->GetHit(iH)); + if (vbHitUsed[iH]) { + FillHitDistributionsForHitSet(EHitSet::Used, hit); + } + int iSt = hit.Station(); + double x = hit.X(); + double y = hit.Y(); + fvphHitUsageXY[iSt]->Fill(x, y, static_cast<double>(vbHitUsed[iH])); } } diff --git a/algo/ca/qa/CaInputQa.h b/algo/ca/qa/CaInputQa.h index baeedcb976..47b355395c 100644 --- a/algo/ca/qa/CaInputQa.h +++ b/algo/ca/qa/CaInputQa.h @@ -78,5 +78,7 @@ namespace cbm::algo::ca OccupHistContainer_t fvphHitOccupXY; ///< hist: Hit occupancy in different stations in XY plane OccupHistContainer_t fvphHitOccupZX; ///< hist: Hit occupancy in different stations in ZX plane OccupHistContainer_t fvphHitOccupZY; ///< hist: Hit occupancy in different stations in ZY plane + + std::vector<qa::Prof2D*> fvphHitUsageXY; ///< prof: Hit usage in different stations in XY plane }; } // namespace cbm::algo::ca diff --git a/algo/ca/qa/CaOutputQa.cxx b/algo/ca/qa/CaOutputQa.cxx index d9c8fd0cc3..9957c745a5 100644 --- a/algo/ca/qa/CaOutputQa.cxx +++ b/algo/ca/qa/CaOutputQa.cxx @@ -2,7 +2,7 @@ SPDX-License-Identifier: GPL-3.0-only Authors: Sergei Zharko [committer] */ -/// \file CaQaOutputQa.cxx +/// \file CaOutputQa.cxx /// \date 20.11.2023 /// \brief A QA module for CA tracking (implementation) /// \author S.Zharko <s.zharko@gsi.de> diff --git a/algo/ca/qa/CaQaBase.h b/algo/ca/qa/CaQaBase.h index 3a85a06f6a..e1fbeb6d1c 100644 --- a/algo/ca/qa/CaQaBase.h +++ b/algo/ca/qa/CaQaBase.h @@ -2,7 +2,7 @@ SPDX-License-Identifier: GPL-3.0-only Authors: Sergei Zharko [committer] */ -/// \file QaBase.h +/// \file CaQaBase.h /// \date 29.02.2024 /// \brief Base class for tracking QA (header) /// \author Sergei Zharko <s.zharko@gsi.de> diff --git a/algo/qa/HistogramContainer.cxx b/algo/qa/HistogramContainer.cxx index 08ef1af72a..8db32a09a1 100644 --- a/algo/qa/HistogramContainer.cxx +++ b/algo/qa/HistogramContainer.cxx @@ -21,10 +21,10 @@ void HistogramContainer::Reset() for (auto& h : fvH2) { h.Reset(); } - //for (auto& h : fvP1) { - // h.Reset(); - //} - //for (auto& h : fvP2) { - // h.Reset(); - //} + for (auto& h : fvP1) { + h.Reset(); + } + for (auto& h : fvP2) { + h.Reset(); + } } diff --git a/algo/qa/HistogramContainer.h b/algo/qa/HistogramContainer.h index 0420d87e8d..eb8630a6ca 100644 --- a/algo/qa/HistogramContainer.h +++ b/algo/qa/HistogramContainer.h @@ -20,10 +20,10 @@ 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 - //std::forward_list<qa::Prof1D> fvP1 = {}; ///< List of 1D-profiles - //std::forward_list<qa::Prof2D> fvP2 = {}; ///< List of 2D-profiles + std::forward_list<qa::H1D> fvH1 = {}; ///< List of 1D-histograms + 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 /// \brief Resets the histograms void Reset(); @@ -35,8 +35,8 @@ namespace cbm::algo::qa { ar& fvH1; ar& fvH2; - //ar& fvP1; - //ar& fvP2; + ar& fvP1; + ar& fvP2; } }; } // namespace cbm::algo::qa diff --git a/algo/qa/QaData.cxx b/algo/qa/QaData.cxx index 90151fe66a..da0ed39365 100644 --- a/algo/qa/QaData.cxx +++ b/algo/qa/QaData.cxx @@ -22,6 +22,8 @@ void Data::Init(std::shared_ptr<HistogramSender> histSender) // 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()); + 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); @@ -29,6 +31,12 @@ void Data::Init(std::shared_ptr<HistogramSender> histSender) 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); + } // Forming a canvas config message std::vector<std::pair<std::string, std::string>> vCanvCfgs; @@ -57,6 +65,9 @@ void Data::Send(std::shared_ptr<HistogramSender> histoSender) 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"; + auto nP1 = std::distance(fHistograms.fvP1.begin(), fHistograms.fvP1.end()); + auto nP2 = std::distance(fHistograms.fvP2.begin(), fHistograms.fvP2.end()); + L_(info) << fsName << ": Published " << nH1 << " 1D- and " << nH2 << " 2D-histograms, " << nP1 << " 1D- and " << nP2 + << "2D-profiles"; this->Reset(); } diff --git a/algo/qa/QaData.h b/algo/qa/QaData.h index e4fcc5c170..4eb94575f5 100644 --- a/algo/qa/QaData.h +++ b/algo/qa/QaData.h @@ -86,6 +86,12 @@ namespace cbm::algo::qa else if constexpr (std::is_same_v<Obj, cbm::algo::qa::H2D>) { return &(fHistograms.fvH2.emplace_front(args...)); } + else if constexpr (std::is_same_v<Obj, cbm::algo::qa::Prof1D>) { + return &(fHistograms.fvP1.emplace_front(args...)); + } + else if constexpr (std::is_same_v<Obj, cbm::algo::qa::Prof2D>) { + return &(fHistograms.fvP2.emplace_front(args...)); + } return nullptr; } } // namespace cbm::algo diff --git a/services/histserv/app/Application.cxx b/services/histserv/app/Application.cxx index 0964416f9f..2882c42ed7 100644 --- a/services/histserv/app/Application.cxx +++ b/services/histserv/app/Application.cxx @@ -5,6 +5,7 @@ #include "Application.h" #include "CbmFlesCanvasTools.h" +#include "CbmQaOnlineInterface.h" #include "HistogramContainer.h" #include "TCanvas.h" #include "TEnv.h" @@ -15,6 +16,7 @@ #include "TMessage.h" #include "TObjArray.h" #include "TProfile.h" +#include "TProfile2D.h" #include "TRootSniffer.h" #include "TSystem.h" @@ -166,57 +168,40 @@ namespace cbm::services::histserv /// 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 + // Collect 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()); + TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source); 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 - 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 binX = 0; binX <= nBinsX + 1; binX++) { - for (uint32_t binY = 0; binY <= nBinsY + 1; binY++) { - result->SetBinContent(binX, binY, source.GetBinContent(binX, binY)); - } + 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; } - result->SetEntries(source.GetEntries()); + delete result; + } + for (auto& source : vHist.fvP2) { + TH1* result = cbm::qa::OnlineInterface::ROOTHistogram(source); if (!ReadHistogram<TH1>(result)) { // return false; } delete result; } + /// If new histos received, try to prepare as many canvases as possible /// Should be expensive on start and cheap afterward if (!fbAllCanvasReady) { @@ -555,7 +540,10 @@ namespace cbm::services::histserv if ("nullptr" != sName) { TObject* pObj = fArrayHisto[FindHistogram(sName)]; - if (nullptr != dynamic_cast<TProfile*>(pObj)) { + if (nullptr != dynamic_cast<TProfile2D*>(pObj)) { + dynamic_cast<TProfile2D*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); + } // if( nullptr != dynamic_cast< TProfile *>( pObj ) ) + else if (nullptr != dynamic_cast<TProfile*>(pObj)) { dynamic_cast<TProfile*>(pObj)->Draw(conf.GetOption(uPadIdx, uObjIdx).data()); } // if( nullptr != dynamic_cast< TProfile *>( pObj ) ) else if (nullptr != dynamic_cast<TH2*>(pObj)) { diff --git a/services/histserv/app/CMakeLists.txt b/services/histserv/app/CMakeLists.txt index 3d24099563..1435a08a01 100644 --- a/services/histserv/app/CMakeLists.txt +++ b/services/histserv/app/CMakeLists.txt @@ -5,6 +5,7 @@ set(INCLUDE_DIRECTORIES ${INCLUDE_DIRECTORIES} ${CMAKE_CURRENT_SOURCE_DIR} ${CBMROOT_SOURCE_DIR}/algo/qa/ + ${CBMROOT_SOURCE_DIR}/core/qa/ ) set(SRCS @@ -28,6 +29,7 @@ add_executable(histserv_nofairmq ${SRCS} ${HEADERS}) target_link_libraries(histserv_nofairmq PUBLIC Algo + CbmQaBase CbmFlibFlesTools CbmServicesHistServ PRIVATE -- GitLab