diff --git a/core/qa/CMakeLists.txt b/core/qa/CMakeLists.txt index 456a3b7adf1dd2b256972f835ee8655cf342ca97..65783ad554c6cdead7ada990c35f83bc33c80c3b 100644 --- a/core/qa/CMakeLists.txt +++ b/core/qa/CMakeLists.txt @@ -1,5 +1,6 @@ set(INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/checker + ${CMAKE_CURRENT_SOURCE_DIR}/report ${CMAKE_CURRENT_SOURCE_DIR} ) @@ -22,10 +23,21 @@ set(SRCS checker/CbmQaCheckerObjectHandler.cxx checker/CbmQaCheckerProfile1DHandler.cxx checker/CbmQaCheckerObjectDB.cxx + report/CbmQaReportBuilder.cxx + report/CbmQaReportLatexEngine.cxx + report/CbmQaReportHtmlEngine.cxx + report/CbmQaReportSection.cxx + report/CbmQaReportTable.cxx ) set(HEADERS CbmQaConstants.h + report/CbmQaReportDefines.h + report/CbmQaReportElement.h + report/CbmQaReportEngine.h + report/CbmQaReportFigure.h + report/CbmQaReportHeader.h + report/CbmQaReportTail.h ) set(LIBRARY_NAME CbmQaBase) @@ -38,6 +50,8 @@ set(PUBLIC_DEPENDENCIES ROOT::Core ROOT::Gpad ROOT::Hist + Boost::filesystem + fmt::fmt ) set(PRIVATE_DEPENDENCIES @@ -65,6 +79,18 @@ Install(FILES CbmQaConstants.h CbmQaCmpDrawer.h checker/CbmQaCheckerTypedefs.h + + report/CbmQaReportDefines.h + report/CbmQaReportBuilder.h + report/CbmQaReportLatexEngine.h + report/CbmQaReportHtmlEngine.h + report/CbmQaReportSection.h + report/CbmQaReportTable.h + report/CbmQaReportElement.h + report/CbmQaReportEngine.h + report/CbmQaReportFigure.h + report/CbmQaReportHeader.h + report/CbmQaReportTail.h DESTINATION include ) diff --git a/core/qa/CbmQaBaseLinkDef.h b/core/qa/CbmQaBaseLinkDef.h index 2d33214ac1ed04ddfd13d9b57853a683aacdbfd3..e0b53833439f0432f0eb984883f89be29c6a0a53 100644 --- a/core/qa/CbmQaBaseLinkDef.h +++ b/core/qa/CbmQaBaseLinkDef.h @@ -31,6 +31,7 @@ #pragma link C++ class CbmQaTable + ; #pragma link C++ class CbmQaTask + ; #pragma link C++ class CbmQaManager + ; + #pragma link C++ class cbm::qa::checker::Core + ; #pragma link C++ class cbm::qa::checker::FileHandler + ; #pragma link C++ class cbm::qa::checker::Hist1DHandler + ; @@ -39,4 +40,15 @@ #pragma link C++ class cbm::qa::checker::ObjectHandler + ; #pragma link C++ class cbm::qa::checker::ObjectDB + ; +#pragma link C++ class cbm::qa::report::Builder + ; +#pragma link C++ class cbm::qa::report::Element + ; +#pragma link C++ class cbm::qa::report::CollapsibleElement + ; +#pragma link C++ class cbm::qa::report::Engine + ; +#pragma link C++ class cbm::qa::report::Figure + ; +#pragma link C++ class cbm::qa::report::Header + ; +#pragma link C++ class cbm::qa::report::Section + ; +#pragma link C++ class cbm::qa::report::Table + ; +#pragma link C++ class cbm::qa::report::Tail + ; +#pragma link C++ class cbm::qa::report::LatexEngine + ; + #endif diff --git a/core/qa/CbmQaIO.cxx b/core/qa/CbmQaIO.cxx index e0635994de7933262d51e7d8e6babb654aa7eb1d..a5f91d42c7c823ca9352b7a791232ad83c397f40 100644 --- a/core/qa/CbmQaIO.cxx +++ b/core/qa/CbmQaIO.cxx @@ -30,11 +30,13 @@ CbmQaIO::CbmQaIO(TString prefixName, std::shared_ptr<ObjList_t> pObjList) : fsPr // CbmQaIO::~CbmQaIO() {} + // --------------------------------------------------------------------------------------------------------------------- // -void CbmQaIO::SetTH1Properties(TH1* pHist) +void CbmQaIO::SetTH1Properties(TH1* pHist) const { // Set default histo properties + pHist->GetYaxis()->SetLabelOffset(0.95); TPaveStats* stats = cbm::qa::util::GetHistStats(pHist); assert(stats); @@ -45,12 +47,13 @@ void CbmQaIO::SetTH1Properties(TH1* pHist) // --------------------------------------------------------------------------------------------------------------------- // -void CbmQaIO::SetTH2Properties(TH2* pHist) +void CbmQaIO::SetTH2Properties(TH2* pHist) const { // Set default histo properties pHist->SetOption("colz"); pHist->SetStats(false); + pHist->GetYaxis()->SetLabelOffset(0.95); /* TPaveStats* stats = cbm::qa::util::GetHistStats(pHist); assert(stats); @@ -61,10 +64,11 @@ void CbmQaIO::SetTH2Properties(TH2* pHist) // --------------------------------------------------------------------------------------------------------------------- // -void CbmQaIO::SetTProfile2DProperties(TProfile2D* pHist) +void CbmQaIO::SetTProfile2DProperties(TProfile2D* pHist) const { // Set default histo properties + pHist->GetYaxis()->SetLabelOffset(0.95); pHist->SetOption("colz"); pHist->SetStats(false); /* @@ -77,9 +81,9 @@ void CbmQaIO::SetTProfile2DProperties(TProfile2D* pHist) // --------------------------------------------------------------------------------------------------------------------- // -void CbmQaIO::SetCanvasProperties(TCanvas* pCanv) +void CbmQaIO::SetCanvasProperties(TCanvas* pCanv) const { - constexpr double left = 0.15; + constexpr double left = 0.18; constexpr double bottom = 0.15; constexpr double right = 0.10; constexpr double top = 0.10; diff --git a/core/qa/CbmQaIO.h b/core/qa/CbmQaIO.h index ab6f83317d7db3025328a7c3f12656c1ebe68b8a..146df13b95e57fbea7bb596e88f48f26265f4eba 100644 --- a/core/qa/CbmQaIO.h +++ b/core/qa/CbmQaIO.h @@ -121,19 +121,19 @@ class CbmQaIO { /// \brief Applies properties on the histogram created with the MakeQaObject function /// \param pHist Pointer to the histogram - virtual void SetTH1Properties(TH1* pHist); + virtual void SetTH1Properties(TH1* pHist) const; /// \brief Applies properties on the histogram created with the MakeQaObject function /// \param pHist Pointer to the histogram - virtual void SetTH2Properties(TH2* pHist); + virtual void SetTH2Properties(TH2* pHist) const; /// \brief Applies properties on the profile 2D created with the MakeQaObject function /// \param pHist Pointer to the profile - void SetTProfile2DProperties(TProfile2D* pHist); + virtual void SetTProfile2DProperties(TProfile2D* pHist) const; /// \brief Applies properties on the canvas created with the MakeQaObject funciton /// \param pCanv Pointer to the canvas - virtual void SetCanvasProperties(TCanvas* pCanv); + virtual void SetCanvasProperties(TCanvas* pCanv) const; /// \brief Writes objects into file /// \param pOutFile Pointer to output ROOT file @@ -200,7 +200,7 @@ T* CbmQaIO::ConstructAndRegisterQaObject(TString sName, Args... args) } // apply user-defined properties - if constexpr (std::is_same_v<TH1F, T> || std::is_same_v<TH1D, T>) { // histograms + if constexpr (std::is_same_v<TH1F, T> || std::is_same_v<TH1D, T> || std::is_same_v<TProfile, T>) { // histograms SetTH1Properties(pObj); } else if constexpr (std::is_same_v<TH2F, T> || std::is_same_v<TH2D, T>) { // histograms diff --git a/core/qa/CbmQaTable.h b/core/qa/CbmQaTable.h index ecbaa171ccae5482f38ad3dc0a650380239581c7..3f17907761c6e85cab3b1abc248c3c07cc69beba 100644 --- a/core/qa/CbmQaTable.h +++ b/core/qa/CbmQaTable.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt +/* Copyright (C) 2022-2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt SPDX-License-Identifier: GPL-3.0-only Authors: Sergey Gorbunov, Sergei Zharko [committer] */ @@ -10,8 +10,8 @@ /// Provides a ROOT Class to handle a numeric table /// -#ifndef CbmQaTable_h -#define CbmQaTable_h 1 +#pragma once + #include "TH2D.h" #include "TROOT.h" @@ -101,5 +101,3 @@ class CbmQaTable : public TH2D { ClassDef(CbmQaTable, 1); }; - -#endif // CbmQaTable_h diff --git a/core/qa/report/CbmQaReportBuilder.cxx b/core/qa/report/CbmQaReportBuilder.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5990142ff434c46e1d44221f3ccb3514726534db --- /dev/null +++ b/core/qa/report/CbmQaReportBuilder.cxx @@ -0,0 +1,76 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportBuilder.h +/// \brief Base class for the report builder (implementation) +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 23.02.2024 + +#include "CbmQaReportBuilder.h" + +#include "CbmQaReportFigure.h" +#include "Logger.h" +#include "TCanvas.h" + +#include <fstream> + + +using cbm::qa::report::Builder; +using cbm::qa::report::Engine; +using cbm::qa::report::Figure; +using cbm::qa::report::Header; +using cbm::qa::report::Tail; + +namespace fs = cbm::qa::report::fs; + +// --------------------------------------------------------------------------------------------------------------------- +// +Builder::Builder(std::string_view title, fs::path outPath) + : fpHeader(std::make_shared<Header>()) + , fpTail(std::make_shared<Tail>()) +{ + fScriptsPath = fs::weakly_canonical(outPath); + fFiguresPath = fs::weakly_canonical(fScriptsPath / "figures"); + fs::create_directories(fScriptsPath); + fs::create_directories(fFiguresPath); + + LOG(info) << "Initializing report builder for a document " << title << ". The scripts path is " + << fScriptsPath.string(); + fpHeader->SetTitle(title); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void Builder::CreateScript(Engine& engine, bool bCompile) +{ + std::string outName = (fScriptsPath / (fmt::format("{}.{}", ksSourceName, engine.ScriptExtention()))).string(); + LOG(info) << "\nCreating source script \"" << outName << "\" using " << engine.MyName(); + + std::ofstream script(outName); + + script << fpHeader->GetBody(engine); + for (const auto& pSection : fvpSections) { + script << pSection->GetBody(engine); + } + script << fpTail->GetBody(engine); + script.close(); + + if (bCompile) { + engine.Compile(outName); + } +} + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string Builder::SaveCanvas(const TCanvas* canv, const std::string& relPath) const +{ + if (!canv) { + LOG(fatal) << "cbm::qa::report::Builder::SaveCanvas(): a nullptr canvas is passed to the function. The provided " + << "relative path is \"" << relPath << "\""; + } + fs::path absPath = this->AbsFigurePath(relPath + "." + fsFigureExtention); + fs::create_directories(absPath.parent_path()); + canv->SaveAs(absPath.string().c_str()); + return this->PathInSource(absPath); +} diff --git a/core/qa/report/CbmQaReportBuilder.h b/core/qa/report/CbmQaReportBuilder.h new file mode 100644 index 0000000000000000000000000000000000000000..aae766ebdbac86bd3383ba94d9c4a866b88294f6 --- /dev/null +++ b/core/qa/report/CbmQaReportBuilder.h @@ -0,0 +1,76 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportBuilder.h +/// \brief Base class for the report builder +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 23.02.2024 + +#pragma once + +#include "CbmQaReportDefines.h" +#include "CbmQaReportEngine.h" +#include "CbmQaReportHeader.h" +#include "CbmQaReportSection.h" +#include "CbmQaReportTail.h" + +class TCanvas; + +namespace cbm::qa::report +{ + /// \class Builder + /// \brief Report builder + class Builder { + public: + /// \brief Constructor + /// \param title Report title + /// \param outPath Output path + Builder(std::string_view title, fs::path outPath); + + /// \brief Destructor + virtual ~Builder() = default; + + /// \brief Adds section + void AddSection(std::shared_ptr<Section> pSection) { fvpSections.push_back(pSection); } + + /// \brief Gets header + std::shared_ptr<Header> GetHeader() { return fpHeader; } + + /// \brief Gets tail + std::shared_ptr<Tail> GetTail() { return fpTail; } + + /// \brief Saves script + /// \param engine Engine of the document + /// \param bCompile Flag: true - script will be compiled, if the compilation rule is defined by engine + void CreateScript(Engine& engine, bool bCompile = true); + + /// \brief Converts path of the object in the code to one in the document source + /// \param path Path to the object + std::string PathInSource(fs::path path) const { return fs::relative(path, fScriptsPath).string(); } + + /// \brief Returns absolute path to the figure + /// \param relPath Relative path to the figure + std::string AbsFigurePath(fs::path relPath) const { return (fFiguresPath / relPath).string(); } + + /// \brief Saves canvas + /// \param canv Pointer to canvas + /// \param relPath Relative path to the canvas image + /// \return Path to canvas in source + /// \note Creates the directory, if it does not exist + std::string SaveCanvas(const TCanvas* canv, const std::string& relPath) const; + + /// \brief Sets figure extention + void SetFigureExtention(std::string_view figExtention) { fsFigureExtention = figExtention; } + + private: + static constexpr std::string_view ksSourceName = "source"; ///< Name of source + + std::vector<std::shared_ptr<Section>> fvpSections; ///< List of report sections + std::string fsFigureExtention = "pdf"; ///< Figure extention + fs::path fScriptsPath; ///< Scripts path + fs::path fFiguresPath; ///< Figures path + std::shared_ptr<Header> fpHeader = nullptr; ///< Header of the report + std::shared_ptr<Tail> fpTail = nullptr; ///< Tail of the report + }; +} // namespace cbm::qa::report diff --git a/core/qa/report/CbmQaReportDefines.h b/core/qa/report/CbmQaReportDefines.h new file mode 100644 index 0000000000000000000000000000000000000000..8ef47aa1745ca8a0acb1cd66cdccdc587f388bb3 --- /dev/null +++ b/core/qa/report/CbmQaReportDefines.h @@ -0,0 +1,20 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportDefines.h +/// \brief Common definitions for cbm::qa::report +/// \author S. Zharko <s.zharko@gsi.de> +/// \since 25.02.2024 + +#pragma once + +//#include <filesystem> +#include <boost/filesystem.hpp> + +namespace cbm::qa::report +{ + // Filesystem + //namespace fs = std::filesystem; + namespace fs = boost::filesystem; +} // namespace cbm::qa::report diff --git a/core/qa/report/CbmQaReportElement.h b/core/qa/report/CbmQaReportElement.h new file mode 100644 index 0000000000000000000000000000000000000000..7ce9595a73acdd09fd682678a6caac4f7511bd42 --- /dev/null +++ b/core/qa/report/CbmQaReportElement.h @@ -0,0 +1,72 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportElement.h +/// \brief Base class for the report element (header) +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 21.02.2024 + +#pragma once + +#include "CbmQaReportDefines.h" + +#include <memory> +#include <string> +#include <vector> + +namespace cbm::qa::report +{ + class Engine; + + /// \class Element + /// \brief Interface for the report element + /// + class Element { + public: + /// \brief Constructor + /// \param label Label of section + Element(std::string_view label) : fsLabel(label) {} + + /// \brief Default constructor + Element() = default; + + /// \brief Destructor + virtual ~Element() = default; + + /// \brief Gets body of the element + /// \param engine A concrete implementation of the Engine to get the element body + virtual std::string GetBody(const Engine& engine) const = 0; + + /// \brief Gets label + const std::string& GetLabel() const { return fsLabel; } + + /// \brief Sets label + void SetLabel(std::string_view label) { fsLabel = label; } + + private: + // TODO: Add check for multiple label definition + std::string fsLabel = ""; ///< Label for referencing + }; + + /// \class CollapsibleElement + /// \brief Interface to the element, which can contain daughter elements + /// + class CollapsibleElement : public Element { + public: + using Element::Element; + + /// \brief Destructor + virtual ~CollapsibleElement() = default; + + /// \brief Adds element + // TODO: Check for label + virtual void Add(std::shared_ptr<Element> pElement) { fvDaughterElements.push_back(pElement); } + + /// \brief Get daughter elements + const std::vector<std::shared_ptr<Element>> GetDaughterElements() const { return fvDaughterElements; } + + private: + std::vector<std::shared_ptr<Element>> fvDaughterElements; ///< Daughter elements + }; +} // namespace cbm::qa::report diff --git a/core/qa/report/CbmQaReportEngine.h b/core/qa/report/CbmQaReportEngine.h new file mode 100644 index 0000000000000000000000000000000000000000..2e11a0a3e063210fd8be5ce224314cc5eaf1e0aa --- /dev/null +++ b/core/qa/report/CbmQaReportEngine.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportElementFactory.h +/// \brief An abstract factory for the report elements +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 23.02.2024 + +#pragma once + +#include <string> +#include <string_view> + +namespace cbm::qa::report +{ + class Figure; + class Header; + class Section; + class Table; + class Tail; + + /// \class Engine + /// \brief A base abstract class to provide an interface for element body (a visitor in the Visitor pattern) + /// + /// Each method of the class provides interface to create the body of the document element. The body + /// is returned as a string. + class Engine { + public: + /// \brief Destructor + virtual ~Engine() = default; + + /// \brief Creates a body for figure + /// \param figure Reference to figure + /// \return Figure body + virtual std::string FigureBody(const Figure& figure) const = 0; + + /// \brief Creates a body for header + /// \param header Reference to header + /// \return Header body + virtual std::string HeaderBody(const Header& header) const = 0; + + /// \brief Creates a body for section + /// \param section Reference to section + /// \return Section body + virtual std::string SectionBody(const Section& section) const = 0; + + /// \brief Creates a body for table + /// \param table Reference to table + /// \return Table body + virtual std::string TableBody(const Table& table) const = 0; + + /// \brief Creates a body for tail + /// \param tail Reference to tail + /// \return Figure body + virtual std::string TailBody(const Tail& tail) const = 0; + + /// \brief Returns script extention + virtual std::string ScriptExtention() const = 0; + + /// \brief Returns engine name + virtual std::string MyName() const = 0; + + /// \brief Defines the compilation rule (can be omitted) + /// \param source Path to the source + virtual void Compile(const std::string& /*source*/) const {}; + }; +} // namespace cbm::qa::report diff --git a/core/qa/report/CbmQaReportFigure.h b/core/qa/report/CbmQaReportFigure.h new file mode 100644 index 0000000000000000000000000000000000000000..03d93018be6a72afa4e6772e5152d31147758990 --- /dev/null +++ b/core/qa/report/CbmQaReportFigure.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportFigure.h +/// \brief Base class for the report figure (header) +/// \author S. Zharko <s.zharko@gsi.de> +/// \since 21.02.2024 + +#pragma once + +#include "CbmQaReportElement.h" +#include "CbmQaReportEngine.h" + +namespace cbm::qa::report +{ + /// \class Figure + /// \brief Figure in the report + class Figure : public Element { + public: + /// \brief Constructor + /// \param label Label of the element + Figure(std::string_view label) : Element(std::string("fig:") + std::string(label)) {} + + /// \brief Destructor + virtual ~Figure() = default; + + /// \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); } + + /// \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 Sets path to the figure + /// \param path to the figure, which will be represented in + void SetPath(std::string_view path) { fsPath = path; } + + /// \brief Sets caption + void SetCaption(std::string_view caption) { fsCaption = caption; } + + private: + std::string fsPath = ""; ///< Relative path + std::string fsCaption = ""; ///< Figure caption + }; +} // namespace cbm::qa::report diff --git a/core/qa/report/CbmQaReportHeader.h b/core/qa/report/CbmQaReportHeader.h new file mode 100644 index 0000000000000000000000000000000000000000..7b457f7ee2e38d1f5662fd747e11b4ce02622913 --- /dev/null +++ b/core/qa/report/CbmQaReportHeader.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportHeader.h +/// \brief Base class for the report header (header) +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 23.02.2024 + +#pragma once + +#include "CbmQaReportEngine.h" + +#include <string> +#include <string_view> + +namespace cbm::qa::report +{ + /// \class Header + /// \brief Header of the report + class Header { + public: + /// \brief Destructor + virtual ~Header() = default; + + /// \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 { return engine.HeaderBody(*this); } + + /// \brief Gets author + const std::string& GetAuthor() const { return fsAuthor; } + + /// \brief Gets page header + const std::string& GetPageHeader() const { return fsPageHeader; } + + /// \brief Gets setup + const std::string& GetSetup() const { return fsSetup; } + + /// \brief Gets subtitle + const std::string& GetSubtitle() const { return fsSubtitle; } + + /// \brief Gets title + const std::string& GetTitle() const { return fsTitle; } + + /// \brief Sets author + void SetAuthor(std::string_view author) { fsAuthor = author; } + + /// \brief Sets page header + void SetPageHeader(std::string_view pageHeader) { fsPageHeader = pageHeader; } + + /// \brief Sets setup + void SetSetup(std::string_view setup) { fsSetup = setup; } + + /// \brief Sets subtitle + void SetSubtitle(std::string_view subtitle) { fsSubtitle = subtitle; } + + /// \brief Sets title + void SetTitle(std::string_view title) { fsTitle = title; } + + private: + std::string fsAuthor = ""; + std::string fsSetup = ""; + std::string fsSubtitle = ""; + std::string fsTitle = ""; + std::string fsPageHeader = ""; ///< Placed on top/bottom of the page + }; +} // namespace cbm::qa::report diff --git a/core/qa/report/CbmQaReportHtmlEngine.cxx b/core/qa/report/CbmQaReportHtmlEngine.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f4be356eb8bba9357da7c49733f2c94f0d311199 --- /dev/null +++ b/core/qa/report/CbmQaReportHtmlEngine.cxx @@ -0,0 +1,152 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportHtmlEngine.h +/// \brief HTML document engine for the cbm::qa::report (source) +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 23.02.2024 + +#include "CbmQaReportHtmlEngine.h" + +#include "CbmQaReportFigure.h" +#include "CbmQaReportHeader.h" +#include "CbmQaReportSection.h" +#include "CbmQaReportTable.h" +#include "CbmQaReportTail.h" + +using cbm::qa::report::Figure; +using cbm::qa::report::Header; +using cbm::qa::report::HtmlEngine; +using cbm::qa::report::Section; +using cbm::qa::report::Table; +using cbm::qa::report::Tail; + +#include <algorithm> +#include <chrono> +#include <ctime> +#include <iomanip> +#include <sstream> +//#include <regex> + +#include <fmt/format.h> + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string HtmlEngine::FigureBody(const Figure& figure) const +{ + std::stringstream out; + out << "<figure>\n"; + out << " <embed src=\"" << figure.GetPath() << "\" style=\"width:" << kFigureWidth << "\">\n"; + if (!figure.GetCaption().empty()) { + out << " <figcaption>Fig.[" << figure.GetLabel() << "]: " << figure.GetCaption() << "</figcaption>\n"; + } + out << "</figure>\n"; + + return out.str(); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string HtmlEngine::HeaderBody(const Header& header) const +{ + std::stringstream out; + + // TODO: Move these definitions to text-file (?) + // Settings + out << "<!DOCTYPE html>\n"; + out << "<html>\n"; + out << "<style>\n"; + out << "table {\n boarder-collapse: collapse;\n width: 100%;\n" + << "}\n"; + out << "th, td {\n text-align: " << kTableTextAlign << ";\n padding: " << kTablePadding << "px;\n" + << "}\n"; + out << "tr:nth-child(even) {\n background-color: #EEEEEE;\n}\n"; + out << "</style>\n"; + out << "<head>\n"; + out << " <title>" << header.GetTitle() << "</title>\n"; + out << "</head>\n\n"; + out << "<body>\n"; + out << "<h1>" << header.GetTitle() << "</h1>\n\n"; + if (!header.GetSubtitle().empty()) { + out << "<h2>" << header.GetSubtitle() << "</h2>\n\n"; + } + auto timeNow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + out << "<table style=\"width:1\">\n"; + out << " <tr>\n"; + out << " <td>Generated on:</td>\n"; + out << " <td>" << std::put_time(std::localtime(&timeNow), "%a %d.%m.%Y, %X") << "</td>\n"; + out << " </tr>\n"; + out << " <tr>\n"; + out << " <td>Author:</td>\n"; + out << " <td>" << header.GetAuthor() << "</td>\n"; + out << " </tr>\n"; + if (!header.GetSetup().empty()) { + out << " <tr>\n"; + out << " <td>Setup:</td>\n"; + out << " <td>" << header.GetSetup() << "</td>\n"; + out << " </tr>\n"; + } + out << "</table>\n\n"; + + return out.str(); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string HtmlEngine::SectionBody(const Section& section) const +{ + std::stringstream out; + std::string sSectionTag = fmt::format("h{}", std::min((section.GetLevel() + 2), 6)); + + out << '<' << sSectionTag << '>' << section.GetTitle() << "</" << sSectionTag << ">\n\n"; + for (const auto& pElement : section.GetDaughterElements()) { + out << pElement->GetBody(*this) << '\n'; + } + out << '\n'; + return out.str(); +} + + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string HtmlEngine::TableBody(const Table& table) const +{ + std::stringstream out; + int nRows = table.GetNofRows(); + int nCols = table.GetNofCols(); + + out << "<table>\n"; + // tabular header + if (!table.GetCaption().empty()) { + out << " <tablecaption>Table: " << table.GetCaption() << "</tablecaption>\n"; + } + // table header + out << " <tr>\n"; + for (int iCol = 0; iCol < nCols; ++iCol) { + out << " <th>" << table.GetColumnTitle(iCol) << "</th>\n"; + } + out << " </tr>\n"; + // table body + for (int iRow = 0; iRow < nRows; ++iRow) { + out << " <tr>\n"; + for (int iCol = 0; iCol < nCols; ++iCol) { + out << " <td>" << table(iRow, iCol) << "</td>\n"; + } + out << " </tr>\n"; + } + out << "</table>\n"; + return out.str(); +} + + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string HtmlEngine::TailBody(const Tail&) const +{ + std::stringstream out; + out << '\n'; + out << "</body>\n"; + out << "</html>\n"; + return out.str(); +} diff --git a/core/qa/report/CbmQaReportHtmlEngine.h b/core/qa/report/CbmQaReportHtmlEngine.h new file mode 100644 index 0000000000000000000000000000000000000000..0d06dffa2ea74d074006677f0c196a743fc15e04 --- /dev/null +++ b/core/qa/report/CbmQaReportHtmlEngine.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportHtmlEngine.h +/// \brief HTML document engine for the cbm::qa::report +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 24.02.2024 + +#pragma once + +#include "CbmQaReportEngine.h" + +#include <string> +#include <string_view> + +namespace cbm::qa::report +{ + /// \class HtmlEngine + /// \brief HTML document engine + class HtmlEngine : public Engine { + public: + /// \brief Creates a body for figure + /// \param figure Reference to figure + /// \return Figure body + std::string FigureBody(const Figure& figure) const override; + + /// \brief Creates a body for header + /// \param header Reference to header + /// \return Header body + std::string HeaderBody(const Header& header) const override; + + /// \brief Creates a body for section + /// \param section Reference to section + /// \return Section body + std::string SectionBody(const Section& section) const override; + + /// \brief Creates a body for table + /// \param table Reference to table + /// \return Table body + std::string TableBody(const Table& table) const override; + + /// \brief Creates a body for tail + /// \param tail Reference to tail + /// \return Figure body + std::string TailBody(const Tail& tail) const override; + + /// \brief Returns script extention + std::string ScriptExtention() const override { return "html"; }; + + /// \brief Returns engine name + std::string MyName() const override { return "HTML engine"; } + + private: + // TODO: control with config + static constexpr double kFigureWidth = 0.9; ///< Figure width [in page width] + static constexpr std::string_view kTableTextAlign = "left"; ///< Table: align + static constexpr int kTablePadding = 4; ///< Table: rows padding [px] + }; +} // namespace cbm::qa::report diff --git a/core/qa/report/CbmQaReportLatexEngine.cxx b/core/qa/report/CbmQaReportLatexEngine.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9b5214189ba7ea23b9e8b8c4efa1cf63a79908cd --- /dev/null +++ b/core/qa/report/CbmQaReportLatexEngine.cxx @@ -0,0 +1,233 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportLatexEngine.h +/// \brief LaTeX plain document engine for the cbm::qa::report (source) +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 23.02.2024 + +#include "CbmQaReportLatexEngine.h" + +#include "CbmQaReportFigure.h" +#include "CbmQaReportHeader.h" +#include "CbmQaReportSection.h" +#include "CbmQaReportTable.h" +#include "CbmQaReportTail.h" +#include "Logger.h" + +#include <chrono> +#include <ctime> +#include <iomanip> +#include <regex> +#include <sstream> + +using cbm::qa::report::Figure; +using cbm::qa::report::Header; +using cbm::qa::report::LatexEngine; +using cbm::qa::report::LatexFormat; +using cbm::qa::report::Section; +using cbm::qa::report::Table; +using cbm::qa::report::Tail; + + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string LatexFormat::Apply(std::string_view input) +{ + auto output = std::string(input); + + // Replace all underscores with "\_" + // TODO: ignore replacing in LaTeX formulas + { + std::regex rex("_"); + output = std::regex_replace(output, rex, "\\_"); + } + + return output; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string LatexEngine::FigureBody(const Figure& figure) const +{ + std::stringstream out; + out << "\\begin{figure}[H]\n"; + out << " \\centering\n"; + out << " \\includegraphics[width=" << LatexEngine::kFigureWidth << "\\textwidth]{" << figure.GetPath() << "}\n"; + if (!figure.GetCaption().empty()) { + out << " \\caption{" << LatexFormat::Apply(figure.GetCaption()) << "}\n"; + } + out << " \\label{" << figure.GetLabel() << "}\n"; + out << "\\end{figure}\n"; + return out.str(); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string LatexEngine::HeaderBody(const Header& header) const +{ + std::stringstream out; + + // TODO: Move these definitions to text-file (?) + // Settings + out << "\\documentclass[12pt]{article}\n"; + out << "\\usepackage[english]{babel}\n"; + out << "\\usepackage{array}\n"; + out << "\\usepackage{graphicx}\n"; + out << "\\usepackage{float}\n"; + out << "\\usepackage{longtable}\n"; + out << "\\usepackage{helvet}\n"; + out << "\\usepackage{sansmath}\n\\sansmath\n"; + out << "\\usepackage{geometry}\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"; + //out << "\\usepackage{color}\n"; + //out << "\\definecolor{hrefcolor}{rgb}{0.2, 0.2, 0.6}\n"; + //out << "\\hypersetup{color}{colorlinks=true, urlcolor=hrefcolor,linkcolor=black,citecolor=hrefcolor}\n"; + if (!header.GetPageHeader().empty()) { + //out << "\\usepackage{fancyhdr}\n\\pagestyle{fancy}\n\\lhead{" + // << LatexFormat::Apply(header.GetPageHeader()) << "}\n"; + } + out << "\n"; + out << "\\newcolumntype{L}[1]{>{\\flushleft\\arraybackslash}p{#1}}\n"; + + // Title page settings + out << "\\title{" << LatexFormat::Apply(header.GetTitle()) << "\\\\ \\vspace{1cm} \\Large " + << LatexFormat::Apply(header.GetSubtitle()) << "}\n"; + out << "\\author{Author: " << LatexFormat::Apply(header.GetAuthor()) << "}\n"; + auto timeNow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + out << "\\date{Generated on " << std::put_time(std::localtime(&timeNow), "%a %d.%m.%Y, %X") << "}\n"; + + + // Title page + out << "\\begin{document}\n"; + out << "\\begin{titlepage}\n"; + out << " \\maketitle\n"; + out << " \\thispagestyle{empty}\n"; + out << " \\vfill\n"; + //out << " \\centering\n"; + out << " Setup: " << LatexFormat::Apply(header.GetSetup()) << "\\\\\n"; + out << "\\end{titlepage}\n"; + out << "\\newpage\n"; + out << "\\tableofcontents\n"; + out << "\\newpage\n"; + + out << '\n'; + return out.str(); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string LatexEngine::SectionBody(const Section& section) const +{ + std::stringstream out; + std::string sSectionType = ""; + if (section.GetLevel() == 0) { + sSectionType = "section"; + } + else if (section.GetLevel() == 1) { + sSectionType = "subsection"; + } + else { + sSectionType = "subsubsection"; + } + + if (section.GetLevel() == 0) { + out << "\\newpage\n"; + } + out << "\\" << sSectionType << "{" << section.GetTitle() << "}\n\n"; + for (const auto& pElement : section.GetDaughterElements()) { + out << pElement->GetBody(*this) << '\n'; + } + out << '\n'; + return out.str(); +} + + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string LatexEngine::TableBody(const Table& table) const +{ + std::stringstream out; + int nRows = table.GetNofRows(); + int nCols = table.GetNofCols(); + + + out << "\\begin{table}\n"; + out << "\\footnotesize\n"; + // tabular header + if (!table.GetCaption().empty()) { + out << " \\caption{" << LatexFormat::Apply(table.GetCaption()) << "}\n"; + } + out << " \\begin{longtable}{" << std::string(nCols, 'c') << "}\n"; + // table header + out << " \\hline\n"; + out << " "; + for (int iCol = 0; iCol < nCols; ++iCol) { + out << table.GetColumnTitle(iCol) << ((iCol < nCols - 1) ? " & " : " \\\\\n"); + } + out << " \\hline\n"; + // table body + for (int iRow = 0; iRow < nRows; ++iRow) { + out << " "; + for (int iCol = 0; iCol < nCols; ++iCol) { + out << table(iRow, iCol) << ((iCol < nCols - 1) ? " & " : " \\\\\n"); + } + } + out << " \\hline\n"; + + out << " \\end{longtable}\n"; + out << " \\label{" << table.GetLabel() << "}\n"; + out << "\\end{table}\n"; + return out.str(); +} + + +// --------------------------------------------------------------------------------------------------------------------- +// +std::string LatexEngine::TailBody(const Tail&) const +{ + std::stringstream out; + out << "\\end{document}\n"; + return out.str(); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void LatexEngine::Compile(const std::string& source) const +{ + // Search for compiler program in path + std::string compiler = fsLatexCompiler.substr(0, fsLatexCompiler.find_first_of(' ')); // compiler name without opts + int bCompilerFonud = false; + { + std::stringstream stream(getenv("PATH")); + std::string dir; + while (!bCompilerFonud && std::getline(stream, dir, ':')) { + bCompilerFonud = fs::exists(fs::path(dir) / compiler); + } + } + + if (!bCompilerFonud) { + LOG(error) << "cbm::qa::report::LatexEngine::Compile(): compiler \"" << fsLatexCompiler << "\" not found in PATH. " + << "Please use another compiler or compile the sourec in external program"; + return; + } + + // Execute compiler + fs::path sourceDir = fs::path(source).parent_path(); + fs::path currPath = fs::current_path(); + fs::current_path(sourceDir); + + std::string logFile = compiler + ".log"; + std::string command = fmt::format("{} {} > {}", fsLatexCompiler, source, logFile); + command = command + ";" + command; // compile two times to get contents + + LOG(info) << "cbm::qa::report::LatexEngine::Compile(): executing command: \n\t" << command; + int res = std::system(command.c_str()); + fs::current_path(currPath); + + LOG(info) << "cbm::qa::report::LatexEngine::Compile(): compillation " << (res == 0 ? "succeed" : "failed") + << "(compiler log: \"" << logFile << "\")"; +} diff --git a/core/qa/report/CbmQaReportLatexEngine.h b/core/qa/report/CbmQaReportLatexEngine.h new file mode 100644 index 0000000000000000000000000000000000000000..0eeeb5573191fae04c39e97eda9fcc41c09a1e50 --- /dev/null +++ b/core/qa/report/CbmQaReportLatexEngine.h @@ -0,0 +1,76 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportLatexEngine.h +/// \brief LaTeX document engine for the cbm::qa::report +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 23.02.2024 + +#pragma once + +#include "CbmQaReportEngine.h" + +#include <string> +#include <string_view> + +namespace cbm::qa::report +{ + // Latex formatting collection + /// \class LatexFormat + class LatexFormat { + public: + /// \brief Applies a LaTeX-friendly formatting + static std::string Apply(std::string_view input); + }; + + /// \class LatexEngine + /// \brief Plain LaTeX document engine + class LatexEngine : public Engine { + public: + /// \brief Creates a body for figure + /// \param figure Reference to figure + /// \return Figure body + std::string FigureBody(const Figure& figure) const override; + + /// \brief Creates a body for header + /// \param header Reference to header + /// \return Header body + std::string HeaderBody(const Header& header) const override; + + /// \brief Creates a body for section + /// \param section Reference to section + /// \return Section body + std::string SectionBody(const Section& section) const override; + + /// \brief Creates a body for table + /// \param table Reference to table + /// \return Table body + std::string TableBody(const Table& table) const override; + + /// \brief Creates a body for tail + /// \param tail Reference to tail + /// \return Figure body + std::string TailBody(const Tail& tail) const override; + + /// \brief Returns script extention + std::string ScriptExtention() const override { return "tex"; }; + + /// \brief Returns engine name + std::string MyName() const override { return "LaTeX plain document engine"; } + + /// \brief Compiles source + /// \param source Source path + void Compile(const std::string& source) const override; + + /// \brief Sets the LaTeX compilation program name + /// \param latexCompiler A LaTeX compiler + /// \note The compiler can contain options + void SetLatexCompiler(std::string_view latexCompiler) { fsLatexCompiler = latexCompiler; } + + private: + static constexpr double kFigureWidth = 1.0; ///< Figure width [in textwidth] + + std::string fsLatexCompiler = "pdflatex -interaction=nonstopmode"; + }; +} // namespace cbm::qa::report diff --git a/core/qa/report/CbmQaReportLatexFormat.h b/core/qa/report/CbmQaReportLatexFormat.h new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/core/qa/report/CbmQaReportLinkDef.h b/core/qa/report/CbmQaReportLinkDef.h new file mode 100644 index 0000000000000000000000000000000000000000..54de0d4e8381caa3b11973b6e4f266e84a0ddacb --- /dev/null +++ b/core/qa/report/CbmQaReportLinkDef.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportLinkDef.h +/// \brief Linkage definitions for using in ROOT +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 24.02.2024 + +#ifdef __CINT__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ nestedclasses; +#pragma link C++ nestedtypedef; + +#pragma link C++ class cbm::qa::report::Builder + ; +#pragma link C++ class cbm::qa::report::Element + ; +#pragma link C++ class cbm::qa::report::CollapsibleElement + ; +#pragma link C++ class cbm::qa::report::ElementFactory + ; +#pragma link C++ class cbm::qa::report::Figure + ; +#pragma link C++ class cbm::qa::report::Header + ; +#pragma link C++ class cbm::qa::report::Section + ; +#pragma link C++ class cbm::qa::report::Table + ; +#pragma link C++ class cbm::qa::report::Tail + ; +#pragma link C++ class cbm::qa::report::LatexFactory + ; +#pragma link C++ class cbm::qa::report::LatexFormat + ; +#pragma link C++ class cbm::qa::report::LatexFigure + ; +#pragma link C++ class cbm::qa::report::LatexHeader + ; +#pragma link C++ class cbm::qa::report::LatexSection + ; +#pragma link C++ class cbm::qa::report::LatexTable + ; +#pragma link C++ class cbm::qa::report::LatexTail + ; + + +#endif + diff --git a/core/qa/report/CbmQaReportSection.cxx b/core/qa/report/CbmQaReportSection.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f55ea983bd8938943c714858fdf79a7e2b2639d1 --- /dev/null +++ b/core/qa/report/CbmQaReportSection.cxx @@ -0,0 +1,33 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportSection.h +/// \brief Base class for the report section (header) +/// \author S. Zharko <s.zharko@gsi.de> +/// \since 23.02.2024 + +#include "CbmQaReportSection.h" + +using cbm::qa::report::CollapsibleElement; +using cbm::qa::report::Element; +using cbm::qa::report::Section; + +// --------------------------------------------------------------------------------------------------------------------- +// +Section::Section(std::string_view label, std::string_view title) + : CollapsibleElement(std::string("section") + std::string(label)) + , fsTitle(title) +{ +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void Section::Add(std::shared_ptr<Element> pElement) +{ + // Add level to the section + if (auto* pSubSection = dynamic_cast<Section*>(pElement.get())) { + pSubSection->SetLevel(this->fLevel + 1); + } + this->CollapsibleElement::Add(pElement); +} diff --git a/core/qa/report/CbmQaReportSection.h b/core/qa/report/CbmQaReportSection.h new file mode 100644 index 0000000000000000000000000000000000000000..0f50ab69b7e02229ac79a2c37ec200a412009ab5 --- /dev/null +++ b/core/qa/report/CbmQaReportSection.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportSection.h +/// \brief Base class for the report section (header) +/// \author S. Zharko <s.zharko@gsi.de> +/// \since 23.02.2024 + +#pragma once + +#include "CbmQaReportElement.h" +#include "CbmQaReportEngine.h" + +#include <string> +#include <string_view> + +namespace cbm::qa::report +{ + /// \class Section + /// \brief Section of the report + class Section : public CollapsibleElement { + public: + /// \brief Constructor + /// \param label Label of section + /// \param title Title + Section(std::string_view label, std::string_view title); + + /// \brief Default constructor + Section() = default; + + /// \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.SectionBody(*this); } + + /// \brief Destructor + virtual ~Section() = default; + + /// \brief Adds daughter element + void Add(std::shared_ptr<Element> pElement) override; + + /// \brief Gets level of the section + int GetLevel() const { return fLevel; } + + /// \brief Gets title + const std::string& GetTitle() const { return fsTitle; } + + /// \brief Sets title + void SetTitle(std::string_view title) { fsTitle = title; } + + protected: + /// \brief Sets level of the section + /// \param level Level of the section (is it section, subsection etc.) + /// \note The level is assigned in the adding a new section + void SetLevel(int level) { fLevel = level; } + + private: + std::string fsTitle = ""; ///< Title of the section + int fLevel = 0; ///< Level of the section + }; +} // namespace cbm::qa::report diff --git a/core/qa/report/CbmQaReportTable.cxx b/core/qa/report/CbmQaReportTable.cxx new file mode 100644 index 0000000000000000000000000000000000000000..581ee5462ac7747f907a5d4b4706a112ff359ef0 --- /dev/null +++ b/core/qa/report/CbmQaReportTable.cxx @@ -0,0 +1,106 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportTable.cxx +/// \brief Base class for the report table (source) +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 23.02.2024 + +#include "CbmQaReportTable.h" + +#include "CbmQaTable.h" +#include "Logger.h" + +using cbm::qa::report::Table; + +#include <algorithm> +#include <sstream> + +// --------------------------------------------------------------------------------------------------------------------- +// +Table::Table(std::string_view label) : Table(label, 0, 0) {} + +// --------------------------------------------------------------------------------------------------------------------- +// +Table::Table(std::string_view label, int nRows, int nCols) + : Element(std::string("tab:") + std::string(label)) + , fNofRows(nRows) + , fNofCols(nCols) +{ + fvsTable.clear(); + fvsTable.resize(fNofRows * fNofCols); + fvsTableHeader.clear(); + fvsTableHeader.resize(fNofCols); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void Table::Set(const CbmQaTable* pQaTable, const std::string& cellFormat) +{ + if (!pQaTable) { + LOG(fatal) << "cbm::qa::report::Table::Set(): A nullptr QA-table is passed to the function. The table label is \"" + << GetLabel() << '\"'; + } + + // Define table size + fvsTable.clear(); + fvsTableHeader.clear(); + int nRowsQa = pQaTable->GetNrows(); + int nColsQa = pQaTable->GetNcols(); + fsCaption = pQaTable->GetTitle(); + + bool bRowsHaveTitles = false; + for (int iRow = 0; iRow < nRowsQa; ++iRow) { + if (!std::string(pQaTable->GetXaxis()->GetBinLabel(nRowsQa - iRow)).empty()) { + bRowsHaveTitles = true; + } + } + fNofRows = nRowsQa; + fNofCols = nColsQa + static_cast<int>(bRowsHaveTitles); // Extra column comes from row names + + // Parse row format + // NOTE: If the sequence of formats was passed, and it is shorter, than number of columns, then the last + // columns will be formated with default format, which is {:.3}. + bool bCommonRowFormat = cellFormat.find_first_of('|') == std::string::npos; + std::vector<std::string> vCellFormat(nColsQa, bCommonRowFormat ? cellFormat : std::string(kDefaultFormat)); + if (!bCommonRowFormat) { + std::stringstream stream(cellFormat); + int iCol = 0; + while (iCol < nColsQa && std::getline(stream, vCellFormat[iCol], '|')) { + if (vCellFormat.empty()) { + vCellFormat[iCol] = "{}"; + } + ++iCol; + } + } + + // Test formatting: + for (auto& entry : vCellFormat) { + try { + std::string sTest = fmt::format(entry, 0.); + } + catch (const std::runtime_error& err) { + LOG(error) << "cbm::qa::report::Table(): Inacceptable format \"" << entry << "\" is passed, using default"; + entry = kDefaultFormat; + } + } + + // Filling the table + fvsTable.resize(fNofCols * fNofRows); + fvsTableHeader.resize(fNofCols); + for (int iCol = static_cast<int>(bRowsHaveTitles); iCol < fNofCols; ++iCol) { + this->SetColumnTitle(iCol, std::string(pQaTable->GetXaxis()->GetBinLabel(iCol))); + } + for (int iRow = 0; iRow < fNofRows; ++iRow) { + // Print row title + if (bRowsHaveTitles) { + this->SetCell(iRow, 0, pQaTable->GetYaxis()->GetBinLabel(fNofRows - iRow)); + } + for (int iColQa = 0; iColQa < nColsQa; ++iColQa) { + double entry = pQaTable->GetCell(iRow, iColQa); + int iCol = iColQa + static_cast<int>(bRowsHaveTitles); + this->SetCell(iRow, iCol, fmt::format(vCellFormat[iColQa], entry)); + } + } +} diff --git a/core/qa/report/CbmQaReportTable.h b/core/qa/report/CbmQaReportTable.h new file mode 100644 index 0000000000000000000000000000000000000000..1d65d3bdb51e89c0cdaa42f46362538121122ec8 --- /dev/null +++ b/core/qa/report/CbmQaReportTable.h @@ -0,0 +1,109 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportTable.h +/// \brief Base class for the report table (header) +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 21.02.2024 + +#pragma once + +#include "CbmQaReportElement.h" +#include "CbmQaReportEngine.h" + +class CbmQaTable; + +namespace cbm::qa::report +{ + /// \class Table + /// \brief Table element in the report + class Table : public Element { + private: + static constexpr std::string_view kDefaultFormat = "{:.3}"; ///< Default format of double entries + + public: + /// \brief Constructor + /// \param label Label of the element + explicit Table(std::string_view label); + + /// \brief Constructor + /// \param label Label of the element + /// \param nRows Number of rows + /// \param nCols Number of columns + Table(std::string_view label, int nRows, int nCols); + + /// \brief Destructor + virtual ~Table(){}; + + /// \brief Cell access operator + /// \param iRow Index of row + /// \param iCol Index of column + const std::string& operator()(int iRow, int iCol) const { return fvsTable[GetIndex(iRow, iCol)]; } + + /// \brief Cell access operator + /// \param iRow Index of row + /// \param iCol Index of column + std::string& operator()(int iRow, int iCol) { return fvsTable[GetIndex(iRow, iCol)]; } + + /// \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.TableBody(*this); } + + /// \brief Gets caption + const std::string& GetCaption() const { return fsCaption; } + + /// \brief Gets cell + /// \param iRow Index of row + /// \param iCol Index of column + const std::string& GetCell(int iRow, int iCol) const { return fvsTable[GetIndex(iRow, iCol)]; } + + /// \brief Gets column title + /// \param iCol Index of column + const std::string& GetColumnTitle(int iCol) const { return fvsTableHeader[iCol]; } + + /// \brief Gets number of rows + int GetNofRows() const { return fNofRows; } + + /// \brief Gets number of columns + int GetNofCols() const { return fNofCols; } + + /// \brief Sets caption + /// \param caption Table caption + void SetCaption(std::string_view caption) { fsCaption = caption; } + + /// \brief Sets a table from CbmQaTable + /// \param pQaTable Pointer to the QA-table object + /// \param cellFormat Defines format of the rows in fmt::format formating scheme + /// + /// The parameter format provides ether a common format for all cells of the CbmQaTabl, or individual + /// formats for each column (excluding the first row, if it is defined with the QA-table row names). + /// For latter one have to pass a sequence of the formats, separated by the bar symbol: + /// "<format_0>|<format_1>|<...>|<format_n>". + /// Each of the <format_i> entries represents a fmt::format formatting line. For example, "{:.2}" + /// formats a double into two digits after floating point, "{:.2e}" converts the number in + /// the scientific format. + void Set(const CbmQaTable* pQaTable, const std::string& cellFormat = std::string(kDefaultFormat)); + + /// \brief Sets cell + /// \param iRow Index of row + /// \param iCol Index of column + /// \param cell Cell + void SetCell(int iRow, int iCol, std::string_view cell) { fvsTable[GetIndex(iRow, iCol)] = cell; } + + /// \brief Sets column title + /// \param iCol Index of column + void SetColumnTitle(int iCol, std::string_view title) { fvsTableHeader[iCol] = title; }; + + protected: + /// \brief Gets index of cell in the table vector + inline int GetIndex(int iRow, int iCol) const { return iRow * fNofCols + iCol; } + + private: + std::vector<std::string> fvsTable; + std::vector<std::string> fvsTableHeader; + std::string fsCaption = ""; + int fNofRows = 0; + int fNofCols = 0; + }; +} // namespace cbm::qa::report diff --git a/core/qa/report/CbmQaReportTail.h b/core/qa/report/CbmQaReportTail.h new file mode 100644 index 0000000000000000000000000000000000000000..125775f9f019a165705a770416adee7d43240ff9 --- /dev/null +++ b/core/qa/report/CbmQaReportTail.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// \file CbmQaReportHeader.h +/// \brief Base class for the report tail (header) +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 23.02.2024 + +#pragma once + +#include "CbmQaReportEngine.h" + +#include <string> +#include <string_view> + +namespace cbm::qa::report +{ + /// \class Tail + /// \brief Tail of the report + class Tail { + public: + /// \brief Destructor + virtual ~Tail() = default; + + /// \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 { return engine.TailBody(*this); } + }; +} // namespace cbm::qa::report diff --git a/macro/qa/report_example.C b/macro/qa/report_example.C new file mode 100644 index 0000000000000000000000000000000000000000..750281b1d1011986acdaaa7102d547f712420cb2 --- /dev/null +++ b/macro/qa/report_example.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 report_example.h +/// \brief Macro to illustrate usage of CbmQaReport library +/// \author Sergei Zharko <s.zharko@gsi.de> +/// \since 24.02.2024 + +/* clang-format off */ +void report_example( + TString qaFile = "", + TString setup = "" +) +/* 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"); + pReport->GetHeader()->SetSubtitle("The CBM Collaboration"); + pReport->GetHeader()->SetAuthor(gSystem->Getenv("USER")); + pReport->GetHeader()->SetSetup(setup.Data()); + pReport->SetFigureExtention("png"); + + // ----- 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->SetPath(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->SetPath(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->SetPath(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->SetPath(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_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); + } + } + // 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) { + 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); + } + } + } + + cbm::qa::report::LatexEngine latex; + pReport->CreateScript(latex); + + cbm::qa::report::HtmlEngine html; + pReport->CreateScript(html); +} diff --git a/reco/L1/qa/CbmCaInputQaBase.cxx b/reco/L1/qa/CbmCaInputQaBase.cxx index a6802c860a444768354988cb4d0d732134fec509..80a15ad140e379f636dfa4c3b7fcd33af4a133a9 100644 --- a/reco/L1/qa/CbmCaInputQaBase.cxx +++ b/reco/L1/qa/CbmCaInputQaBase.cxx @@ -20,7 +20,6 @@ #include "CbmMuchPoint.h" #include "CbmMvdHit.h" #include "CbmMvdPoint.h" -#include "CbmQaCanvas.h" #include "CbmQaTable.h" #include "CbmQaUtil.h" #include "CbmStsCluster.h" @@ -37,6 +36,7 @@ #include "FairRootManager.h" #include "Logger.h" #include "TBox.h" +#include "TCanvas.h" #include "TClonesArray.h" #include "TEllipse.h" #include "TF1.h" @@ -163,14 +163,14 @@ void CbmCaInputQaBase<DetID>::Check() { LOG(info) << "-- Hit efficiency integrated over hit distance from station center"; - auto* pEffTable = MakeQaObject<CbmQaTable>("vs Station/eff_table", "Efficiency table", nSt, 2); - pEffTable->SetNamesOfCols({"Station ID", "Efficiency"}); + auto* pEffTable = MakeQaObject<CbmQaTable>("vs Station/eff_table", "Efficiency table", nSt, 1); + pEffTable->SetNamesOfCols({"Efficiency"}); pEffTable->SetColWidth(20); for (int iSt = 0; iSt < nSt; ++iSt) { auto eff = fvph_reco_eff[iSt]->GetMean(); - pEffTable->SetCell(iSt, 0, iSt); - pEffTable->SetCell(iSt, 1, eff); + pEffTable->SetRowName(iSt, Form("station %d", iSt)); + pEffTable->SetCell(iSt, 0, eff); bool res = CheckRange("Hit finder efficiency in station " + std::to_string(iSt), eff, fEffThrsh, 1.000); StoreCheckResult(Form("hit_efficiency_station_%d", iSt), res); } @@ -181,8 +181,8 @@ void CbmCaInputQaBase<DetID>::Check() // Check hits for potential biases from central values { auto* pResidualsTable = - MakeQaObject<CbmQaTable>("vs Station/residuals_mean", "Residual mean values in different stations", nSt, 4); - pResidualsTable->SetNamesOfCols({"Station ID", "Residual(x) [cm]", "Residual(y) [cm]", "Residual(t) [ns]"}); + MakeQaObject<CbmQaTable>("vs Station/residuals_mean", "Residual mean values in different stations", nSt, 3); + pResidualsTable->SetNamesOfCols({"Residual(x) [cm]", "Residual(y) [cm]", "Residual(t) [ns]"}); pResidualsTable->SetColWidth(20); // Fit residuals @@ -192,10 +192,10 @@ void CbmCaInputQaBase<DetID>::Check() cbm::qa::util::SetLargeStats(fvph_res_y[iSt]); cbm::qa::util::SetLargeStats(fvph_res_t[iSt]); - pResidualsTable->SetCell(iSt, 0, iSt); - pResidualsTable->SetCell(iSt, 1, fvph_res_x[iSt]->GetStdDev()); - pResidualsTable->SetCell(iSt, 2, fvph_res_y[iSt]->GetStdDev()); - pResidualsTable->SetCell(iSt, 3, fvph_res_t[iSt]->GetStdDev()); + pResidualsTable->SetRowName(iSt, Form("station %d", iSt)); + pResidualsTable->SetCell(iSt, 0, fvph_res_x[iSt]->GetStdDev()); + pResidualsTable->SetCell(iSt, 1, fvph_res_y[iSt]->GetStdDev()); + pResidualsTable->SetCell(iSt, 2, fvph_res_t[iSt]->GetStdDev()); } LOG(info) << '\n' << pResidualsTable->ToString(8); } @@ -209,7 +209,7 @@ void CbmCaInputQaBase<DetID>::Check() { auto* pPullsTable = MakeQaObject<CbmQaTable>("vs Station/pulls_rms", "Pulls std. dev. values in different stations", nSt, 4); - pPullsTable->SetNamesOfCols({"Station ID", "Pull(x) sigm", "Pull(y) sigm", "Pull(t) sigm"}); + pPullsTable->SetNamesOfCols({"Pull(x) sigm", "Pull(y) sigm", "Pull(t) sigm"}); pPullsTable->SetColWidth(20); for (int iSt = 0; iSt < nSt + 1; ++iSt) { @@ -225,10 +225,10 @@ void CbmCaInputQaBase<DetID>::Check() StoreCheckResult(Form("pull_y_station_%d", iSt), CheckRangePull(fvph_pull_y[iSt])); StoreCheckResult(Form("pull_t_station_%d", iSt), CheckRangePull(fvph_pull_t[iSt])); - pPullsTable->SetCell(iSt, 0, iSt); - pPullsTable->SetCell(iSt, 1, fvph_pull_x[iSt]->GetStdDev()); - pPullsTable->SetCell(iSt, 2, fvph_pull_y[iSt]->GetStdDev()); - pPullsTable->SetCell(iSt, 3, fvph_pull_t[iSt]->GetStdDev()); + pPullsTable->SetRowName(iSt, Form("station %d", iSt)); + pPullsTable->SetCell(iSt, 0, fvph_pull_x[iSt]->GetStdDev()); + pPullsTable->SetCell(iSt, 1, fvph_pull_y[iSt]->GetStdDev()); + pPullsTable->SetCell(iSt, 2, fvph_pull_t[iSt]->GetStdDev()); } LOG(info) << '\n' << pPullsTable->ToString(3); @@ -1070,6 +1070,23 @@ InitStatus CbmCaInputQaBase<DetID>::InitHistograms() template<ca::EDetectorID DetID> InitStatus CbmCaInputQaBase<DetID>::InitCanvases() { + /// TODO: Move this fuction somewhere on top of the class + auto DivideCanvas = [](TCanvas* pCanv, int nPads) { + if (nPads < 1) { + nPads = 1; + } + int rows = static_cast<int>(std::sqrt(nPads)); + int cols = nPads / rows; + if (cols * rows < nPads) { + cols++; + } + int newSizeX = cols * 600; + int newSizeY = rows * 600; + pCanv->SetCanvasSize(newSizeX, newSizeY); + pCanv->SetWindowSize(newSizeX, newSizeY); + pCanv->Divide(cols, rows, 0, 0); + }; + gStyle->SetOptFit(1); int nSt = fpDetInterface->GetNtrackingStations(); @@ -1086,8 +1103,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() // ** summary for all stations { - auto* canv = MakeQaObject<CbmQaCanvas>("occ_hit", "Hit Occupancy", 1600, 800); - canv->Divide2D(3); + auto* canv = MakeQaObject<TCanvas>("occ_hit", "Hit Occupancy", 1600, 800); + DivideCanvas(canv, 3); canv->cd(1); fvph_hit_xy[nSt]->DrawCopy("colz", ""); canv->cd(2); @@ -1097,8 +1114,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { - auto* canv = MakeQaObject<CbmQaCanvas>("occ_point", "Point Occupancy", 1600, 800); - canv->Divide2D(3); + auto* canv = MakeQaObject<TCanvas>("occ_point", "Point Occupancy", 1600, 800); + DivideCanvas(canv, 3); canv->cd(1); fvph_point_xy[nSt]->DrawCopy("colz", ""); @@ -1109,8 +1126,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { - auto* canv = MakeQaObject<CbmQaCanvas>("residual", "Hit Residuals", 1600, 800); - canv->Divide2D(6); + auto* canv = MakeQaObject<TCanvas>("residual", "Hit Residuals", 1600, 800); + DivideCanvas(canv, 6); canv->cd(1); fvph_res_x[nSt]->DrawCopy("colz", ""); canv->cd(2); @@ -1124,8 +1141,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { - auto* canv = MakeQaObject<CbmQaCanvas>("pull", "Hit Pulls", 1600, 800); - canv->Divide2D(6); + auto* canv = MakeQaObject<TCanvas>("pull", "Hit Pulls", 1600, 800); + DivideCanvas(canv, 6); canv->cd(1); fvph_pull_x[nSt]->DrawCopy("colz", ""); canv->cd(2); @@ -1139,8 +1156,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { - auto* canv = MakeQaObject<CbmQaCanvas>("eff", "Hit Reconstruction Efficiency", 1600, 800); - canv->Divide2D(2); + auto* canv = MakeQaObject<TCanvas>("eff", "Hit Reconstruction Efficiency", 1600, 800); + DivideCanvas(canv, 2); canv->cd(1); fvpe_reco_eff_vs_xy[nSt]->DrawCopy("colz", ""); canv->cd(2); @@ -1148,8 +1165,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { - auto* canv = MakeQaObject<CbmQaCanvas>("err", "Hit Errors", 1600, 800); - canv->Divide2D(6); + auto* canv = MakeQaObject<TCanvas>("err", "Hit Errors", 1600, 800); + DivideCanvas(canv, 6); canv->cd(1); fvph_hit_dx[nSt]->DrawCopy(); canv->cd(2); @@ -1165,8 +1182,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { - auto* canv = MakeQaObject<CbmQaCanvas>("other", "Other histograms", 1600, 800); - canv->Divide2D(3); + auto* canv = MakeQaObject<TCanvas>("other", "Other histograms", 1600, 800); + DivideCanvas(canv, 3); canv->cd(1); fvph_n_points_per_hit[nSt]->DrawCopy("colz", ""); canv->cd(2); @@ -1180,8 +1197,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() // ** Hit occupancies { // ** Occupancy in XY plane - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/hit_xy", "", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/hit_xy", "", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_hit_xy[iSt]->DrawCopy("colz", ""); @@ -1202,7 +1219,7 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // ** Occupancy in XZ plane - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/hit_zx", "", 1600, 800); + auto* canv = MakeQaObject<TCanvas>("vs Station/hit_zx", "", 1600, 800); canv->cd(); fvph_hit_zx[nSt]->DrawCopy("colz", ""); for (int iSt = 0; iSt < nSt; ++iSt) { @@ -1222,7 +1239,7 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // ** Occupancy in YZ plane - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/hit_zy", "", 1600, 800); + auto* canv = MakeQaObject<TCanvas>("vs Station/hit_zy", "", 1600, 800); canv->cd(); fvph_hit_zy[nSt]->DrawCopy("colz", ""); for (int iSt = 0; iSt < nSt; ++iSt) { @@ -1250,8 +1267,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() // ** Point occupancies { // ** Occupancy in XY plane - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/point_xy", "", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/point_xy", "", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_point_xy[iSt]->DrawCopy("colz", ""); @@ -1272,7 +1289,7 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // ** Occupancy in XZ plane - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/point_zx", "", 1600, 800); + auto* canv = MakeQaObject<TCanvas>("vs Station/point_zx", "", 1600, 800); canv->cd(); fvph_point_zx[nSt]->DrawCopy("colz", ""); for (int iSt = 0; iSt < nSt; ++iSt) { @@ -1292,7 +1309,7 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // ** Occupancy in YZ plane - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/point_zy", "", 1600, 800); + auto* canv = MakeQaObject<TCanvas>("vs Station/point_zy", "", 1600, 800); canv->cd(); fvph_point_zy[nSt]->DrawCopy("colz", ""); for (int iSt = 0; iSt < nSt; ++iSt) { @@ -1315,8 +1332,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() // ** Residuals { // x-coordinate - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/res_x", "Residuals for x coordinate", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/res_x", "Residuals for x coordinate", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_res_x[iSt]->DrawCopy("", ""); @@ -1324,8 +1341,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // y-coordinate - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/res_y", "Residuals for y coordinate", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/res_y", "Residuals for y coordinate", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_res_y[iSt]->DrawCopy("", ""); @@ -1333,8 +1350,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // u-coordinate - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/res_u", "Residuals for u coordinate", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/res_u", "Residuals for u coordinate", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_res_u[iSt]->DrawCopy("", ""); @@ -1342,8 +1359,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // v-coordinate - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/res_v", "Residuals for v coordinate", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/res_v", "Residuals for v coordinate", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_res_v[iSt]->DrawCopy("", ""); @@ -1351,8 +1368,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // t-coordinate - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/res_t", "Residuals for time", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/res_t", "Residuals for time", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_res_t[iSt]->DrawCopy("", ""); @@ -1364,8 +1381,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() // ** Pulls { // x-coordinate - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/pull_x", "Pulls for x coordinate", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/pull_x", "Pulls for x coordinate", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_pull_x[iSt]->DrawCopy("", ""); @@ -1373,8 +1390,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // y-coordinate - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/pull_y", "Pulls for y coordinate", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/pull_y", "Pulls for y coordinate", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_pull_y[iSt]->DrawCopy("", ""); @@ -1382,8 +1399,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // u-coordinate - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/pull_u", "Pulls for u coordinate", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/pull_u", "Pulls for u coordinate", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_pull_u[iSt]->DrawCopy("", ""); @@ -1391,8 +1408,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // v-coordinate - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/pull_v", "Pulls for v coordinate", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/pull_v", "Pulls for v coordinate", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_pull_v[iSt]->DrawCopy("", ""); @@ -1400,8 +1417,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { // t-coordinate - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/pull_t", "Pulls for time", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/pull_t", "Pulls for time", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvph_pull_t[iSt]->DrawCopy("", ""); @@ -1412,8 +1429,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() // ** Hit reconstruction efficiencies { - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/reco_eff", "Hit efficiencies in xy bins", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/reco_eff", "Hit efficiencies in xy bins", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); //fvph_reco_eff[iSt]->SetMarkerStyle(20); @@ -1422,8 +1439,8 @@ InitStatus CbmCaInputQaBase<DetID>::InitCanvases() } { - auto* canv = MakeQaObject<CbmQaCanvas>("vs Station/reco_eff_vs_xy", "Hit efficiencies wrt x and y", 1600, 800); - canv->Divide2D(nSt); + auto* canv = MakeQaObject<TCanvas>("vs Station/reco_eff_vs_xy", "Hit efficiencies wrt x and y", 1600, 800); + DivideCanvas(canv, nSt); for (int iSt = 0; iSt < nSt; ++iSt) { canv->cd(iSt + 1); fvpe_reco_eff_vs_xy[iSt]->DrawCopy("colz", ""); diff --git a/reco/L1/qa/CbmCaInputQaSetup.cxx b/reco/L1/qa/CbmCaInputQaSetup.cxx index 64d5f5e833e6432f64c6cc515c1812ded8376d92..4078b7df27758bf9e3396ca288c98ebabcc9c8cf 100644 --- a/reco/L1/qa/CbmCaInputQaSetup.cxx +++ b/reco/L1/qa/CbmCaInputQaSetup.cxx @@ -128,7 +128,7 @@ InitStatus InputQaSetup::InitCanvases() { // Tracking setup by hits { - auto* canv = MakeQaObject<CbmQaCanvas>("c_setup_hits", "Setup by hits", 1000, 1000); + auto* canv = MakeQaObject<TCanvas>("c_setup_hits", "Setup by hits", 1000, 1000); canv->Divide(1, 2, 0.000001, 0.000001); canv->cd(1); gPad->SetLogz(); diff --git a/reco/L1/qa/CbmCaOutputQa.cxx b/reco/L1/qa/CbmCaOutputQa.cxx index bd946878538cd0f48c9dc14f373e7387b107e86d..52c2372af1ee05fe925f4b269e772880b0c796cb 100644 --- a/reco/L1/qa/CbmCaOutputQa.cxx +++ b/reco/L1/qa/CbmCaOutputQa.cxx @@ -644,8 +644,8 @@ InitStatus OutputQa::InitCanvases() std::vector<ETrackType> vCmpTypesProtons = {kAllPPBAR, kPrimP, kPrimPBAR, kSecP, kSecPBAR}; /// @brief Function to draw generic canvas of histogram comparison - auto DrawTrackDistributions = [&](CbmQaCanvas* pCanv, std::function<TH1F*(ETrackType)> Hist) { - pCanv->Divide2D(6); + auto DrawTrackDistributions = [&](TCanvas* pCanv, std::function<TH1F*(ETrackType)> Hist) { + pCanv->Divide(3, 2); pCanv->cd(1); gPad->SetLogy(); DrawSetOf<TH1F>(vCmpTypesGeneral, Hist); @@ -667,8 +667,8 @@ InitStatus OutputQa::InitCanvases() }; /// @brief Function to draw generic canvas of efficiencies comparison - auto DrawTrackEfficiens = [&](CbmQaCanvas* pCanv, std::function<TProfile*(ETrackType)> Prof) { - pCanv->Divide2D(3); + auto DrawTrackEfficiens = [&](TCanvas* pCanv, std::function<TProfile*(ETrackType)> Prof) { + pCanv->Divide(3, 1); pCanv->cd(1); DrawSetOf<TProfile>(vCmpTypesGeneral, Prof); pCanv->cd(2); @@ -682,61 +682,61 @@ InitStatus OutputQa::InitCanvases() // ** Reconstructed track distributions ** // Reconstructed pseudorapidity auto* pc_reco_eta = - MakeQaObject<CbmQaCanvas>("reco_eta", "Reconstructed track pseudorapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); + MakeQaObject<TCanvas>("reco_eta", "Reconstructed track pseudorapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); DrawTrackDistributions(pc_reco_eta, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_reco_eta; }); // MC pseudorapidity auto* pc_reco_etaMC = - MakeQaObject<CbmQaCanvas>("reco_etaMC", "Reconstructed track MC pseudorapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); + MakeQaObject<TCanvas>("reco_etaMC", "Reconstructed track MC pseudorapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); DrawTrackDistributions(pc_reco_etaMC, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_reco_etaMC; }); // MC momentum auto* pc_reco_pMC = - MakeQaObject<CbmQaCanvas>("reco_pMC", "Reconstructed track MC momentum", kCXSIZEPX * 3, kCYSIZEPX * 2); + MakeQaObject<TCanvas>("reco_pMC", "Reconstructed track MC momentum", kCXSIZEPX * 3, kCYSIZEPX * 2); DrawTrackDistributions(pc_reco_pMC, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_reco_pMC; }); // MC rapidity auto* pc_reco_yMC = - MakeQaObject<CbmQaCanvas>("reco_yMC", "Reconstructed track MC rapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); + MakeQaObject<TCanvas>("reco_yMC", "Reconstructed track MC rapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); DrawTrackDistributions(pc_reco_yMC, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_reco_yMC; }); // ** MC track distributions ** // MC momentum auto* pc_mc_pMC = - MakeQaObject<CbmQaCanvas>("mc_pMC", "MC reconstructable track MC momentum", kCXSIZEPX * 3, kCYSIZEPX * 2); + MakeQaObject<TCanvas>("mc_pMC", "MC reconstructable track MC momentum", kCXSIZEPX * 3, kCYSIZEPX * 2); DrawTrackDistributions(pc_mc_pMC, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_mc_pMC; }); // MC rapidity auto* pc_mc_yMC = - MakeQaObject<CbmQaCanvas>("mc_yMC", "MC reconstructable track MC rapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); + MakeQaObject<TCanvas>("mc_yMC", "MC reconstructable track MC rapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); DrawTrackDistributions(pc_mc_yMC, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_mc_yMC; }); // MC rapidity vs. MC momentum // auto* pc_mc_pMC_yMC = - MakeQaObject<CbmQaCanvas>("mc_ptMC_yMC", "MC track MC transverse mom. vs. rapidity ", kCXSIZEPX * 3, kCYSIZEPX * 2); + MakeQaObject<TCanvas>("mc_ptMC_yMC", "MC track MC transverse mom. vs. rapidity ", kCXSIZEPX * 3, kCYSIZEPX * 2); DrawSetOf<TH2F>(vCmpTypesGeneral, [&](ETrackType t) -> TH2F* { return fvpTrackHistograms[t]->fph_reco_ptMC_yMC; }); // ** Efficiencies ** // MC momentum - auto* pc_eff_pMC = MakeQaObject<CbmQaCanvas>("eff_pMC", "Tracking Eff. vs. MC momentum", kCXSIZEPX * 3, kCYSIZEPX); + auto* pc_eff_pMC = MakeQaObject<TCanvas>("eff_pMC", "Tracking Eff. vs. MC momentum", kCXSIZEPX * 3, kCYSIZEPX); DrawTrackEfficiens(pc_eff_pMC, [&](ETrackType t) -> TProfile* { return fvpTrackHistograms[t]->fph_eff_pMC; }); - auto* pc_eff_yMC = MakeQaObject<CbmQaCanvas>("eff_yMC", "Tracking Eff. vs. MC rapidity", kCXSIZEPX * 3, kCYSIZEPX); + auto* pc_eff_yMC = MakeQaObject<TCanvas>("eff_yMC", "Tracking Eff. vs. MC rapidity", kCXSIZEPX * 3, kCYSIZEPX); DrawTrackEfficiens(pc_eff_yMC, [&](ETrackType t) -> TProfile* { return fvpTrackHistograms[t]->fph_eff_yMC; }); auto* pc_eff_thetaMC = - MakeQaObject<CbmQaCanvas>("eff_thetaMC", "Tracking Eff. vs. MC polar angle", kCXSIZEPX * 3, kCYSIZEPX); + MakeQaObject<TCanvas>("eff_thetaMC", "Tracking Eff. vs. MC polar angle", kCXSIZEPX * 3, kCYSIZEPX); DrawTrackEfficiens(pc_eff_thetaMC, [&](ETrackType t) -> TProfile* { return fvpTrackHistograms[t]->fph_eff_thetaMC; }); auto* pc_eff_phiMC = - MakeQaObject<CbmQaCanvas>("eff_phiMC", "Tracking Eff. vs. MC azimuthal angle", kCXSIZEPX * 3, kCYSIZEPX); + MakeQaObject<TCanvas>("eff_phiMC", "Tracking Eff. vs. MC azimuthal angle", kCXSIZEPX * 3, kCYSIZEPX); DrawTrackEfficiens(pc_eff_phiMC, [&](ETrackType t) -> TProfile* { return fvpTrackHistograms[t]->fph_eff_phiMC; }); auto* pc_eff_etaMC = - MakeQaObject<CbmQaCanvas>("eff_etaMC", "Tracking Eff. vs. MC pseudorapidity", kCXSIZEPX * 3, kCYSIZEPX); + MakeQaObject<TCanvas>("eff_etaMC", "Tracking Eff. vs. MC pseudorapidity", kCXSIZEPX * 3, kCYSIZEPX); DrawTrackEfficiens(pc_eff_etaMC, [&](ETrackType t) -> TProfile* { return fvpTrackHistograms[t]->fph_eff_etaMC; }); diff --git a/reco/L1/qa/CbmCaTrackTypeQa.cxx b/reco/L1/qa/CbmCaTrackTypeQa.cxx index f5497a8dd10fbdbbc5df9ffc3e89767541d9d05a..a12ce6b99b1e5fffbe0493de4481d8ad05525516 100644 --- a/reco/L1/qa/CbmCaTrackTypeQa.cxx +++ b/reco/L1/qa/CbmCaTrackTypeQa.cxx @@ -387,14 +387,12 @@ void TrackTypeQa::SetDrawAtt(Color_t markerCol, Style_t markerSty, Color_t lineC // --------------------------------------------------------------------------------------------------------------------- // -void TrackTypeQa::SetHistoProperties(TH1* pHist) +void TrackTypeQa::SetTH1Properties(TH1* pHist) const { pHist->SetStats(true); pHist->Sumw2(); - if (!pHist->InheritsFrom("TH2") && !pHist->InheritsFrom("TH3")) { - pHist->SetMarkerStyle(fMarkerStyle); - pHist->SetLineStyle(fLineStyle); - } + pHist->SetMarkerStyle(fMarkerStyle); + pHist->SetLineStyle(fLineStyle); pHist->SetMarkerColor(fMarkerColor); pHist->SetLineColor(fLineColor); } diff --git a/reco/L1/qa/CbmCaTrackTypeQa.h b/reco/L1/qa/CbmCaTrackTypeQa.h index 38171e3a8db4d8c5dcffc9af3a971b630e88d57f..8b4ab81f5f5e11405efc5267705f079f19056e57 100644 --- a/reco/L1/qa/CbmCaTrackTypeQa.h +++ b/reco/L1/qa/CbmCaTrackTypeQa.h @@ -269,7 +269,7 @@ namespace cbm::ca private: /// @brief Overrided virtual function of the CbmQaIO class, defines properties of the histograms /// @param pHist Pointer to a histogram, which properties are to be set - virtual void SetHistoProperties(TH1* pHist); + virtual void SetTH1Properties(TH1* pHist) const override; // ** Technical profiles and histograms (counters) ** TProfile* fph_rate_reco = nullptr; ///< Rate of reconstructed tracks / mc