From a8ecffeabb898fd923a1b44f64d82103d85b900f Mon Sep 17 00:00:00 2001 From: "s.zharko@gsi.de" <s.zharko@gsi.de> Date: Thu, 18 Apr 2024 18:46:18 +0200 Subject: [PATCH] qa-report: subfigures support --- algo/ca/qa/CaOutputQa.cxx | 8 +- core/qa/report/CbmQaReportFigure.h | 54 +++++- core/qa/report/CbmQaReportHtmlEngine.cxx | 4 +- core/qa/report/CbmQaReportLatexEngine.cxx | 75 +++++++- macro/qa/CMakeLists.txt | 2 +- macro/qa/qa_report_ca_offline.C | 211 ++++++++++++++++++++++ macro/qa/report_example.C | 100 +++++----- 7 files changed, 395 insertions(+), 59 deletions(-) create mode 100644 macro/qa/qa_report_ca_offline.C diff --git a/algo/ca/qa/CaOutputQa.cxx b/algo/ca/qa/CaOutputQa.cxx index a23de73d2e..ee728fed70 100644 --- a/algo/ca/qa/CaOutputQa.cxx +++ b/algo/ca/qa/CaOutputQa.cxx @@ -64,8 +64,8 @@ void OutputQa::Init() double xMin = -0.5; double xMax = double(knStaMax) - 0.5; { - auto sName = "track_fst_lst_sta"; - auto sTitl = "First vs. last station index;ID^{last}_{station};ID^{first}_{station}"; + auto sName = "track_fst_lst_sta"; + auto sTitl = "First vs. last station index;ID^{last}_{station};ID^{first}_{station}"; fphTrkFstLstSta = fQaData.MakeObj<H2D>(sName, sTitl, nBins, xMin, xMax, nBins, xMin, xMax); } fphTrkNofHits = fQaData.MakeObj<H1D>("n_hits", "Number of hits;N_{hit}", nBins, xMin, xMax); @@ -114,14 +114,14 @@ void OutputQa::Init() { auto canv = CanvasConfig("ca_nhits_in_trk", "Number of hit in track"); { - auto pad = PadConfig(); + auto pad = PadConfig(); pad.SetGrid(true, true); pad.SetLog(false, true); pad.RegisterHistogram(fphTrkNofHits, "hist"); canv.AddPadConfig(pad); } { - auto pad = PadConfig(); + auto pad = PadConfig(); pad.SetGrid(true, true); pad.SetLog(false, false, true); pad.RegisterHistogram(fphTrkFstLstSta, "colz"); diff --git a/core/qa/report/CbmQaReportFigure.h b/core/qa/report/CbmQaReportFigure.h index b152ae9820..fc6037df0d 100644 --- a/core/qa/report/CbmQaReportFigure.h +++ b/core/qa/report/CbmQaReportFigure.h @@ -18,6 +18,24 @@ namespace cbm::qa::report /// \brief Figure in the report class Figure : public Element { public: + /// \struct Plot + /// \brief A structure to handle the plot details + struct Plot { + Plot() = default; + + /// \brief Constructor + Plot(std::string_view path, std::string_view caption, std::string_view label) + : fsPath(path) + , fsCaption(caption) + , fsLabel(label) + { + } + + std::string fsPath = ""; + std::string fsCaption = ""; + std::string fsLabel = ""; + }; + /// \brief Constructor /// \param label Label of the element /// \param title Title @@ -29,6 +47,15 @@ namespace cbm::qa::report /// \brief Destructor virtual ~Figure() = default; + /// \brief Add plot + /// \param path to the plot + /// \param caption caption of the plot + /// \param label label of the plot + void AddPlot(std::string_view path, std::string_view caption = "", std::string_view label = "") + { + fvsPlots.emplace_back(path, caption, label); + } + /// \brief Gets body of the element /// \param engine A concrete implementation of the Engine to get the element body std::string GetBody(const Engine& engine) const override { return engine.FigureBody(*this); } @@ -36,18 +63,31 @@ namespace cbm::qa::report /// \brief Gets caption const std::string& GetCaption() const { return fsCaption; } - /// \brief Gets path suffix to the figure - const std::string& GetPath() const { return fsPath; } + /// \brief Gets plot grid + const std::vector<size_t>& GetPlotGrid() const { return fvGrid; } - /// \brief Sets path to the figure - /// \param path to the figure, which will be represented in - void SetPath(std::string_view path) { fsPath = path; } + /// \brief Gets plot vector + const std::vector<Plot>& GetPlots() const { return fvsPlots; } /// \brief Sets caption void SetCaption(std::string_view caption) { fsCaption = caption; } + /// \brief Sets plot grid + /// \param nX Number of plots along the horizontal direction + /// \param nY Number of plots along the vertical direction + void SetPlotGrid(size_t nX, size_t nY) + { + fvGrid.clear(); + fvGrid.resize(nY, nX); + } + + /// \brief Set plot grid + /// \param grid Grid {X1, X2, ..., Xn}, where Xi -- number of plots in the ith line + void SetPlotGrid(const std::vector<size_t>& grid) { fvGrid = grid; } + private: - std::string fsPath = ""; ///< Relative path - std::string fsCaption = ""; ///< Figure caption + std::vector<Plot> fvsPlots{}; ///< Vector of plots (subfigures) + std::vector<size_t> fvGrid{}; ///< Plot grid + std::string fsCaption{}; ///< Figure caption }; } // namespace cbm::qa::report diff --git a/core/qa/report/CbmQaReportHtmlEngine.cxx b/core/qa/report/CbmQaReportHtmlEngine.cxx index f4be356eb8..1a0c32d16b 100644 --- a/core/qa/report/CbmQaReportHtmlEngine.cxx +++ b/core/qa/report/CbmQaReportHtmlEngine.cxx @@ -37,7 +37,9 @@ std::string HtmlEngine::FigureBody(const Figure& figure) const { std::stringstream out; out << "<figure>\n"; - out << " <embed src=\"" << figure.GetPath() << "\" style=\"width:" << kFigureWidth << "\">\n"; + for (const auto& plot : figure.GetPlots()) { + out << " <embed src=\"" << plot.fsPath << "\" style=\"width:" << kFigureWidth << "\">\n"; + } if (!figure.GetCaption().empty()) { out << " <figcaption>Fig.[" << figure.GetLabel() << "]: " << figure.GetCaption() << "</figcaption>\n"; } diff --git a/core/qa/report/CbmQaReportLatexEngine.cxx b/core/qa/report/CbmQaReportLatexEngine.cxx index b2e95e6262..d010a78ca4 100644 --- a/core/qa/report/CbmQaReportLatexEngine.cxx +++ b/core/qa/report/CbmQaReportLatexEngine.cxx @@ -20,6 +20,7 @@ #include <chrono> #include <ctime> #include <iomanip> +#include <numeric> #include <regex> #include <sstream> @@ -36,10 +37,81 @@ using cbm::qa::report::Tail; // std::string LatexEngine::FigureBody(const Figure& figure) const { + size_t nPlots = figure.GetPlots().size(); + if (nPlots == 0) { + LOG(warn) << "No plots provided for figure " << figure.GetLabel() << ". Ignoring."; + return ""; + } + std::stringstream out; out << "\\begin{figure}[H]\n"; out << " \\centering\n"; - out << " \\includegraphics[width=" << LatexEngine::kFigureWidth << "\\textwidth]{" << figure.GetPath() << "}\n"; + if (nPlots == 1) { + out << " \\includegraphics[width=" << LatexEngine::kFigureWidth << "\\textwidth]{" << figure.GetPlots()[0].fsPath + << "}\n"; + } + else { + std::vector<size_t> vPlotGrid; + bool bDefineDefaultGrid = figure.GetPlotGrid().empty(); + if (!bDefineDefaultGrid) { + size_t nPlotsByGrid = std::accumulate(figure.GetPlotGrid().begin(), figure.GetPlotGrid().end(), 0); + if (nPlotsByGrid < nPlots) { + LOG(warn) << "Figure " << figure.GetLabel() + << ": provided grid does not fit the subfigures, define the default one"; + bDefineDefaultGrid = true; + } + } + + if (bDefineDefaultGrid) { + constexpr size_t nX = 3; + auto nY = static_cast<size_t>(std::ceil(static_cast<double>(nPlots) / nX)); + vPlotGrid.resize(nY, nX); + } + else { + vPlotGrid = figure.GetPlotGrid(); + } + + for (auto& i : vPlotGrid) { + LOG(info) << "- " << i; + } + + size_t iPlot = 0; + for (size_t iY = 0; iY < vPlotGrid.size(); ++iY) { + if (iPlot >= nPlots) { + break; + } + size_t nX = vPlotGrid[iY]; + if (nX == 0) { + continue; + } + double wSize = 0.90 / std::min(nX, nPlots - iPlot); + for (size_t iX = 0; iX < nX; ++iX) { + if (iPlot >= nPlots) { + break; + } + const auto& plot = figure.GetPlots()[iPlot]; + out << " \\begin{subfigure}[t]{" << wSize << "\\textwidth}\n"; + out << " \\centering\n"; + out << " \\includegraphics[width=\\linewidth]{" << plot.fsPath << "}\n"; + out << " \\caption{" << plot.fsCaption << "}\n"; + if (!plot.fsLabel.empty()) { + out << " \\label{" << figure.GetLabel() << ":" << plot.fsLabel << "}\n"; + } + out << " \\end{subfigure}\n"; + if (iX == nX - 1) { + out << '\n'; + if (iY != vPlotGrid.size() - 1) { + out << "\\vspace{3mm}\n"; + } + } + else { + out << "\\quad\n"; + } + ++iPlot; + } + } + } + if (!figure.GetCaption().empty()) { out << " \\caption{" << LatexFormat::Apply(figure.GetCaption()) << "}\n"; } @@ -65,6 +137,7 @@ std::string LatexEngine::HeaderBody(const Header& header) const out << "\\usepackage{helvet}\n"; out << "\\usepackage{sansmath}\n\\sansmath\n"; out << "\\usepackage{geometry}\n"; + out << "\\usepackage{subcaption}\n"; out << "\\geometry{a4paper, total={170mm,257mm}, left=25mm, right=25mm, top=30mm, bottom=30mm}\n"; //out << "\\setlength{\\parindent}{0cm}\n"; out << "\\usepackage{hyperref}\n"; diff --git a/macro/qa/CMakeLists.txt b/macro/qa/CMakeLists.txt index 5fab9636a0..3f283fd157 100644 --- a/macro/qa/CMakeLists.txt +++ b/macro/qa/CMakeLists.txt @@ -99,7 +99,7 @@ foreach(setup IN LISTS cbm_setup) endforeach(setup IN LISTS cbm_setup) # ============================================================================ -Install(FILES ../run/.rootrc qa_compare.C +Install(FILES ../run/.rootrc qa_compare.C ./qa_report_ca_offline.C DESTINATION share/cbmroot/macro/qa ) #Install(CODE "FILE(MAKE_DIRECTORY \${CMAKE_INSTALL_PREFIX}/share/cbmroot/macro/run/data)") diff --git a/macro/qa/qa_report_ca_offline.C b/macro/qa/qa_report_ca_offline.C new file mode 100644 index 0000000000..353ac5ba11 --- /dev/null +++ b/macro/qa/qa_report_ca_offline.C @@ -0,0 +1,211 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file qa_report_ca_offline.C +/// \brief QA report for CA tracking (offline) +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 18.04.2024 + +/* clang-format off */ +void qa_report_ca_offline( + TString qaFile = "", + TString setup = "", + TString report = "./report" +) +/* clang-format on */ +{ + using cbm::qa::report::Builder; + using cbm::qa::report::Figure; + using cbm::qa::report::Section; + using cbm::qa::report::Table; + + if (qaFile.Length() == 0) { + return; + } + + TFile* pFile = TFile::Open(qaFile.Data(), "READONLY"); + if (!pFile->IsOpen()) { + std::cerr << "- E: Input file \"" << qaFile << "\" cannot be opened\n"; + } + + // Report header + auto pReport = std::make_unique<Builder>("CA Tracking QA Status", report.Data()); + pReport->GetHeader()->SetSubtitle("The CBM Collaboration"); + pReport->GetHeader()->SetAuthor(gSystem->Getenv("USER")); + pReport->GetHeader()->SetSetup(setup.Data()); + pReport->SetFigureExtention("pdf"); + + // ----- Setup + { + std::string sTaskName = "CbmCaInputQaSetup"; + + auto pSection = std::make_shared<Section>(sTaskName, "CA Tracking Setup"); + pReport->AddSection(pSection); + { + auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/c_setup_hits").c_str()); + auto pFig = std::make_shared<Figure>("setup"); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/setup_hits")); + pSection->Add(pFig); + } + } + + // ----- Input QA + { + std::vector<std::pair<std::string, std::string>> vDetNames = {{"Mvd", "MVD"}, + {"Sts", "STS"}, + {"Much", "MuCh"}, + {"Trd", "TRD"}, + {"Tof", "TOF"}}; + for (const auto& [detTag, detName] : vDetNames) { + std::string sTaskName = Form("CbmCaInputQa%s", detTag.c_str()); + if (pFile->Get(sTaskName.c_str())) { + int nStations = 0; + while (pFile->Get(Form("%s/Station %d", sTaskName.c_str(), nStations))) { + ++nStations; + } + std::string sectionName = Form("CA Tracking Input QA for %s", detName.c_str()); + auto pSection = std::make_shared<Section>(sTaskName, sectionName); + pReport->AddSection(pSection); + + // Occupancy + { + std::string secLabel = Form("%s:occupancy", sTaskName.c_str()); + auto pSubSection = std::make_shared<Section>(secLabel, "Hits and MC Points occupancy"); + pSection->Add(pSubSection); + std::vector<std::pair<std::string, std::string>> vFigAtts = { + {"hit_xy", Form("%s hit occupancy in xy-plane.", detName.c_str())}, + {"hit_zx", Form("%s hit occupancy in xz-plane.", detName.c_str())}, + {"hit_zy", Form("%s hit occupancy in yz-plane.", detName.c_str())}, + {"point_xy", Form("%s MC-point occupancy in xy-plane.", detName.c_str())}, + {"point_zx", Form("%s MC-point occupancy in xz-plane.", detName.c_str())}, + {"point_zy", Form("%s MC-point occupancy in yz-plane.", detName.c_str())}}; + for (const auto& [name, caption] : vFigAtts) { + auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/vs Station/" + name).c_str()); + std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); + auto pFig = std::make_shared<Figure>(label); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); + pFig->SetCaption(caption); + pSubSection->Add(pFig); + } + } + // Efficiencies + { + std::string secLabel = Form("%s:efficiency", sTaskName.c_str()); + auto pSubSection = std::make_shared<Section>(secLabel, "Detector efficiency"); + pSection->Add(pSubSection); + + { + std::string name = "reco_eff_vs_xy"; + std::string caption = "Hit efficency in xy-plane."; + std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); + auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/vs Station/" + name).c_str()); + auto pFig = std::make_shared<Figure>(label); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); + pFig->SetCaption(caption); + pSubSection->Add(pFig); + } + + { + std::string name = "eff_table"; + std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); + auto* pQaTable = pFile->Get<CbmQaTable>((sTaskName + "/Summary/vs Station/" + name).c_str()); + auto pTable = std::make_shared<Table>(label); + pTable->Set(pQaTable); + pSubSection->Add(pTable); + } + } + // Residuals and pulls + { + std::string secLabel = Form("%s:pulls", sTaskName.c_str()); + auto pSubSection = std::make_shared<Section>(secLabel, "Residuals and pulls"); + pSection->Add(pSubSection); + + std::vector<std::pair<std::string, std::string>> vFigAtts = { + {"res_x", Form("Hit residuals for hit x-coordinate in %s", detName.c_str())}, + {"res_y", Form("Hit residuals for hit y-coordinate in %s", detName.c_str())}, + {"res_t", Form("Hit residuals for hit time in %s", detName.c_str())}, + {"pull_x", Form("Hit pulls for hit x-coordinate in %s", detName.c_str())}, + {"pull_y", Form("Hit pulls for hit y-coordinate in %s", detName.c_str())}, + {"pull_t", Form("Hit pulls for hit time in %s", detName.c_str())}}; + for (const auto& [name, caption] : vFigAtts) { + auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/vs Station/" + name).c_str()); + std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); + auto pFig = std::make_shared<Figure>(label); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); + pFig->SetCaption(caption); + pSubSection->Add(pFig); + } + + for (const std::string& name : {"residuals_mean", "pulls_rms"}) { + std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); + auto* pQaTable = pFile->Get<CbmQaTable>((sTaskName + "/Summary/vs Station/" + name).c_str()); + auto pTable = std::make_shared<Table>(label); + pTable->Set(pQaTable); + pSubSection->Add(pTable); + } + } + } + } + } + + // ----- Output QA + if (pFile->Get("CbmCaOutputQa")) { + std::string sTaskName = "CbmCaOutputQa"; + auto pSection = std::make_shared<Section>(sTaskName, "CA Tracking Output QA"); + pReport->AddSection(pSection); + + // Tracking summary table + { + auto pSubSection = std::make_shared<Section>("ca::Summary", "Tracking summary"); + pSection->Add(pSubSection); + auto* pSummaryTable = pFile->Get<CbmQaTable>((sTaskName + "/Summary/summary_table").c_str()); + auto pTable = std::make_shared<Table>("casummary"); + pTable->Set(pSummaryTable, "{:.04}|{:.02}|{:.02}|{:.02}|{:.02}|{:.02}|{:.02}|{:.02}"); + pSubSection->Add(pTable); + } + // Track distributions + { + auto pSubSection = std::make_shared<Section>("ca::trkDistr", "Track Distributions"); + pSection->Add(pSubSection); + std::vector<std::pair<std::string, std::string>> vFigAtts = { + {"reco_eta", "Pseudorapidity distributions of reconstructed tracks for different track groups."}, + {"reco_etaMC", "MC pseudorapidity distributions of reconstructed tracks for different track groups."}, + {"reco_pMC", "MC momentum distributions of reconstructed tracks for different track groups."}, + {"reco_yMC", "MC rapidity distributions of reconstructed tracks for different track groups."}, + {"mc_pMC", "MC momentum distributions of MC-tracks for different track groups."}, + {"mc_yMC", "MC rapidity distributions of MC-tracks for different track groups."}, + {"mc_ptMC_yMC", "MC tracks vs. MC transverse momentum and MC rapidity."}}; + for (const auto& [name, caption] : vFigAtts) { + if (auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/" + name).c_str())) { + auto pFig = std::make_shared<Figure>(name); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); + pFig->SetCaption(caption); + pSubSection->Add(pFig); + } + } + } + // Track distributions + { + auto pSubSection = std::make_shared<Section>("ca::Eff", "Tracking Efficiency"); + pSection->Add(pSubSection); + std::vector<std::pair<std::string, std::string>> vFigAtts = { + {"eff_pMC", "Tracking efficiency vs. MC momentum for different track groups."}, + {"eff_yMC", "Tracking efficiency vs. MC rapidity for different track groups."}, + {"eff_thetaMC", "Tracking efficiency vs. MC theta for different track groups."}, + {"eff_phiMC", "Tracking efficiency vs. MC azimuthal angle for different track groups."}, + {"eff_etaMC", "Tracking efficiency vs. MC pseudorapidity for different track groups."}}; + for (const auto& [name, caption] : vFigAtts) { + if (auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/" + name).c_str())) { + auto pFig = std::make_shared<Figure>(name); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); + pFig->SetCaption(caption); + pSubSection->Add(pFig); + } + } + } + } + + cbm::qa::report::LatexEngine latex; + pReport->CreateScript(latex); +} diff --git a/macro/qa/report_example.C b/macro/qa/report_example.C index 750281b1d1..515479074f 100644 --- a/macro/qa/report_example.C +++ b/macro/qa/report_example.C @@ -10,7 +10,8 @@ /* clang-format off */ void report_example( TString qaFile = "", - TString setup = "" + TString setup = "", + TString report = "./report", ) /* clang-format on */ { @@ -29,7 +30,7 @@ void report_example( } // Report header - auto pReport = std::make_unique<Builder>("CA Tracking QA Status", "./report"); + auto pReport = std::make_unique<Builder>("CA Tracking QA Status", report); pReport->GetHeader()->SetSubtitle("The CBM Collaboration"); pReport->GetHeader()->SetAuthor(gSystem->Getenv("USER")); pReport->GetHeader()->SetSetup(setup.Data()); @@ -42,10 +43,11 @@ void report_example( auto pSection = std::make_shared<Section>(sTaskName, "CA Tracking Setup"); pReport->AddSection(pSection); { - auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/c_setup_hits").c_str()); - auto pFig = std::make_shared<Figure>("setup"); - pFig->SetPath(pReport->SaveCanvas(pCanv, sTaskName + "/setup_hits")); - pSection->Add(pFig); + if (auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/c_setup_hits").c_str())) { + auto pFig = std::make_shared<Figure>("setup"); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/setup_hits")); + pSection->Add(pFig); + } } } @@ -80,12 +82,13 @@ void report_example( {"point_zx", Form("%s MC-point occupancy in xz-plane.", detName.c_str())}, {"point_zy", Form("%s MC-point occupancy in yz-plane.", detName.c_str())}}; for (const auto& [name, caption] : vFigAtts) { - auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/vs Station/" + name).c_str()); - std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); - auto pFig = std::make_shared<Figure>(label); - pFig->SetPath(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); - pFig->SetCaption(caption); - pSubSection->Add(pFig); + if (auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/vs Station/" + name).c_str())) { + std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); + auto pFig = std::make_shared<Figure>(label); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); + pFig->SetCaption(caption); + pSubSection->Add(pFig); + } } } // Efficiencies @@ -98,20 +101,22 @@ void report_example( std::string name = "reco_eff_vs_xy"; std::string caption = "Hit efficency in xy-plane."; std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); - auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/vs Station/" + name).c_str()); - auto pFig = std::make_shared<Figure>(label); - pFig->SetPath(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); - pFig->SetCaption(caption); - pSubSection->Add(pFig); + if (auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/vs Station/" + name).c_str())) { + auto pFig = std::make_shared<Figure>(label); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); + pFig->SetCaption(caption); + pSubSection->Add(pFig); + } } { std::string name = "eff_table"; std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); - auto* pQaTable = pFile->Get<CbmQaTable>((sTaskName + "/Summary/vs Station/" + name).c_str()); - auto pTable = std::make_shared<Table>(label); - pTable->Set(pQaTable); - pSubSection->Add(pTable); + if (auto* pQaTable = pFile->Get<CbmQaTable>((sTaskName + "/Summary/vs Station/" + name).c_str())) { + auto pTable = std::make_shared<Table>(label); + pTable->Set(pQaTable); + pSubSection->Add(pTable); + } } } // Residuals and pulls @@ -128,20 +133,22 @@ void report_example( {"pull_y", Form("Hit pulls for hit y-coordinate in %s", detName.c_str())}, {"pull_t", Form("Hit pulls for hit time in %s", detName.c_str())}}; for (const auto& [name, caption] : vFigAtts) { - auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/vs Station/" + name).c_str()); - std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); - auto pFig = std::make_shared<Figure>(label); - pFig->SetPath(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); - pFig->SetCaption(caption); - pSubSection->Add(pFig); + if (auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/vs Station/" + name).c_str())) { + std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); + auto pFig = std::make_shared<Figure>(label); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); + pFig->SetCaption(caption); + pSubSection->Add(pFig); + } } for (const std::string& name : {"residuals_mean", "pulls_rms"}) { std::string label = Form("%s:%s", sTaskName.c_str(), name.c_str()); - auto* pQaTable = pFile->Get<CbmQaTable>((sTaskName + "/Summary/vs Station/" + name).c_str()); - auto pTable = std::make_shared<Table>(label); - pTable->Set(pQaTable); - pSubSection->Add(pTable); + if (auto* pQaTable = pFile->Get<CbmQaTable>((sTaskName + "/Summary/vs Station/" + name).c_str())) { + auto pTable = std::make_shared<Table>(label); + pTable->Set(pQaTable); + pSubSection->Add(pTable); + } } } } @@ -158,10 +165,11 @@ void report_example( { auto pSubSection = std::make_shared<Section>("ca::Summary", "Tracking summary"); pSection->Add(pSubSection); - auto* pSummaryTable = pFile->Get<CbmQaTable>((sTaskName + "/Summary/summary_table").c_str()); - auto pTable = std::make_shared<Table>("casummary"); - pTable->Set(pSummaryTable, "{:.04}|{:.02}|{:.02}|{:.02}|{:.02}|{:.02}|{:.02}|{:.02}"); - pSubSection->Add(pTable); + if (auto* pSummaryTable = pFile->Get<CbmQaTable>((sTaskName + "/Summary/summary_table").c_str())) { + auto pTable = std::make_shared<Table>("casummary"); + pTable->Set(pSummaryTable, "{:.04}|{:.02}|{:.02}|{:.02}|{:.02}|{:.02}|{:.02}|{:.02}"); + pSubSection->Add(pTable); + } } // Track distributions { @@ -176,11 +184,12 @@ void report_example( {"mc_yMC", "MC rapidity distributions of MC-tracks for different track groups."}, {"mc_pMC_yMC", "MC tracks vs. MC momentum and MC rapidity."}}; for (const auto& [name, caption] : vFigAtts) { - auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/" + name).c_str()); - auto pFig = std::make_shared<Figure>(name); - pFig->SetPath(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); - pFig->SetCaption(caption); - pSubSection->Add(pFig); + if (auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/" + name).c_str())) { + auto pFig = std::make_shared<Figure>(name); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); + pFig->SetCaption(caption); + pSubSection->Add(pFig); + } } } // Track distributions @@ -194,11 +203,12 @@ void report_example( {"eff_phiMC", "Tracking efficiency vs. MC azimuthal angle for different track groups."}, {"eff_etaMC", "Tracking efficiency vs. MC pseudorapidity for different track groups."}}; for (const auto& [name, caption] : vFigAtts) { - auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/" + name).c_str()); - auto pFig = std::make_shared<Figure>(name); - pFig->SetPath(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); - pFig->SetCaption(caption); - pSubSection->Add(pFig); + if (auto* pCanv = pFile->Get<TCanvas>((sTaskName + "/Summary/" + name).c_str())) { + auto pFig = std::make_shared<Figure>(name); + pFig->AddPlot(pReport->SaveCanvas(pCanv, sTaskName + "/" + name)); + pFig->SetCaption(caption); + pSubSection->Add(pFig); + } } } } -- GitLab