diff --git a/core/qa/CbmQaCmpDrawer.cxx b/core/qa/CbmQaCmpDrawer.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1e117bf50e616b61901e58f2bc4ce0078468a7e5 --- /dev/null +++ b/core/qa/CbmQaCmpDrawer.cxx @@ -0,0 +1,18 @@ +/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// @file CbmQaCmpDrawer.cxx +/// @brief Class for a canvas with a comparison of multiple graphs or histograms (implementation) +/// @since 22.04.2023 +/// @author Sergei Zharko <s.zharko@gsi.de> + +#include "CbmQaCmpDrawer.h" + +#include "TH1F.h" +#include "TProfile.h" + +templateClassImp(CbmQaCmpDrawer); + +template class CbmQaCmpDrawer<TH1F>; +template class CbmQaCmpDrawer<TProfile>; diff --git a/core/qa/CbmQaCmpDrawer.h b/core/qa/CbmQaCmpDrawer.h new file mode 100644 index 0000000000000000000000000000000000000000..d25fce7180f375cd9e8d313472655050be58d392 --- /dev/null +++ b/core/qa/CbmQaCmpDrawer.h @@ -0,0 +1,178 @@ +/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Sergei Zharko [committer] */ + +/// @file CbmQaCmpDrawer.h +/// @brief Class for a canvas with a comparison of multiple graphs or histograms (header) +/// @since 21.04.2023 +/// @author Sergei Zharko <s.zharko@gsi.de> + +#ifndef CbmQaCmpDrawer_h +#define CbmQaCmpDrawer_h 1 + +#include "Logger.h" + +#include "TH1.h" +#include "TH2.h" +#include "TH3.h" +#include "TLegend.h" +#include "TPad.h" + +#include <algorithm> +#include <limits> +#include <type_traits> +#include <vector> + +/// @brief Class to draw a comparison of objects on the provided canvas or pad +/// @tparam Obj Type of underlying objects (TH1D, TGraph, TProfile, ...) +/// +template<class Obj> +class CbmQaCmpDrawer { +public: + /// @brief Default constructor + CbmQaCmpDrawer(); + + /// @brief Destructor + ~CbmQaCmpDrawer() = default; + + /// @brief Copy constructor + CbmQaCmpDrawer(const CbmQaCmpDrawer&) = delete; + + /// @brief Move constructor + CbmQaCmpDrawer(CbmQaCmpDrawer&&) = delete; + + /// @brief Copy assignment operator + CbmQaCmpDrawer& operator=(const CbmQaCmpDrawer&) = delete; + + /// @brief Move assignment operator + CbmQaCmpDrawer& operator=(CbmQaCmpDrawer&&) = delete; + + /// @brief Clears the set of objects + void Clear(); + + /// @brief Registers an object to draw + /// @param pObj Pointer to object + /// @param title Title of object (appears in the legend). + void RegisterObject(const Obj* pObj, const char* title = nullptr); + + /// @brief Draw objects + /// @param opt Drawing option: + /// TODO: Specify options + void Draw(Option_t* opt) const; + + /// @brief Sets minimum of the histogram/graph + /// @param min Minimum + /// + /// If the minimum is not set with this function, it will be set to 0 or the minimal value of the objects + void SetMinimum(double min) { fMinimum = min; } + + /// @brief Sets maximum of the histogram/graph + /// @param max Maximum + /// + /// If the maximum is not set with this function, it will be set to the maximum value of the objects, multiplied + /// by the value (1. + kIndentFromMax), which is 1.1 by default + void SetMaximum(double max) { fMaximum = max; } + +private: + // Some constant expressions (TODO: move to a separate header) + static constexpr double kLegEntryHight = 0.06; ///< Hight of one legend entry in Y axis + static constexpr double kLegEntryWidth = 0.35; ///< Width of the legend + static constexpr double kLegRightBound = 0.99; ///< Right bound of the legend + static constexpr double kLegTopBound = 0.90; ///< Top bound of the legend + static constexpr double kLegTextSize = 0.04; ///< Text size of the legend entries + static constexpr double kIndentFromMax = 0.1; ///< Indent from the maximum (percentage from (max - min)) + + double fMinimum = std::numeric_limits<double>::signaling_NaN(); + double fMaximum = std::numeric_limits<double>::signaling_NaN(); + + std::vector<Obj*> fvpObjects; ///< Set of objects to be drawn + std::vector<TString> fvsLegEntries; ///< Entries to legend +}; + + +// **************************** +// ** Implementation ** +// **************************** + +// --------------------------------------------------------------------------------------------------------------------- +// +template<class Obj> +CbmQaCmpDrawer<Obj>::CbmQaCmpDrawer() +{ +} + +// --------------------------------------------------------------------------------------------------------------------- +// +template<class Obj> +void CbmQaCmpDrawer<Obj>::Clear() +{ + fvpObjects.clear(); + fvsLegEntries.clear(); + fMinimum = std::numeric_limits<double>::signaling_NaN(); + fMaximum = std::numeric_limits<double>::signaling_NaN(); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +template<class Obj> +void CbmQaCmpDrawer<Obj>::RegisterObject(const Obj* pObj, const char* title) +{ + if (!pObj) { + LOG(info) << "CbmQaCmpDrawer: attempt to register a nullptr (" << title << "), ignored"; + return; + } + + // Add entry to objects array + auto* pObjClone = static_cast<Obj*>(pObj->Clone()); + fvpObjects.push_back(pObjClone); + + // Add entry to legend + TString legEntryName = title ? title : pObj->GetTitle(); + fvsLegEntries.push_back(legEntryName); +} + +// --------------------------------------------------------------------------------------------------------------------- +// +template<class Obj> +void CbmQaCmpDrawer<Obj>::Draw(Option_t* /*opt*/) const +{ + // TH1, TProfile + if constexpr (std::is_base_of_v<TH1, Obj> && !std::is_base_of_v<TH2, Obj> && !std::is_base_of_v<TH3, Obj>) { + // Maximum and minimum + double maxY = fMaximum; + if (std::isnan(maxY)) { + auto HistMax = [](const Obj* lhs, const Obj* rhs) { return lhs->GetMaximum() < rhs->GetMaximum(); }; + maxY = (*std::max_element(fvpObjects.cbegin(), fvpObjects.cend(), HistMax))->GetMaximum(); + maxY *= (1. + kIndentFromMax); + } + double minY = fMinimum; + if (std::isnan(minY)) { + auto HistMin = [](const Obj* lhs, const Obj* rhs) { return lhs->GetMinimum() < rhs->GetMinimum(); }; + minY = (*std::min_element(fvpObjects.cbegin(), fvpObjects.cend(), HistMin))->GetMaximum(); + minY = (minY < 0.) ? minY : 0.; + } + + // Draw a stack of histograms + for (auto it = fvpObjects.begin(); it != fvpObjects.end(); ++it) { + (*it)->SetStats(false); + (*it)->SetMinimum(minY); + (*it)->SetMaximum(maxY); + (*it)->Draw(it == fvpObjects.begin() ? "" : "same"); + } + } + + // Draw legend + double legX0 = kLegRightBound - kLegEntryWidth; + double legX1 = kLegRightBound; + double legY0 = kLegTopBound - kLegEntryHight * fvpObjects.size(); + double legY1 = kLegTopBound; + + auto* pLeg = new TLegend(legX0, legY0, legX1, legY1); + pLeg->SetTextSize(kLegTextSize); + for (int iObj = 0; iObj < (int) fvpObjects.size(); ++iObj) { + pLeg->AddEntry(fvpObjects[iObj], fvsLegEntries[iObj], "lp"); + } + pLeg->Draw(); +} + +#endif // CbmQaCmpDrawer_h diff --git a/core/qa/CbmQaIO.cxx b/core/qa/CbmQaIO.cxx index da8aac99a56f3f19332f48d434d65f1990ab8e04..f414c3f2b802755e8ca7fd48b0a9753b5668e191 100644 --- a/core/qa/CbmQaIO.cxx +++ b/core/qa/CbmQaIO.cxx @@ -34,3 +34,11 @@ CbmQaIO::~CbmQaIO() fpFolderRoot = nullptr; } } + +// --------------------------------------------------------------------------------------------------------------------- +// +void CbmQaIO::SetHistoProperties(TH1* pHist) +{ + pHist->SetStats(true); + pHist->Sumw2(); +} diff --git a/core/qa/CbmQaIO.h b/core/qa/CbmQaIO.h index b6ea8acdb5ff9b2778bd06d45d38774c7ca0b3f2..424ca1c3ffd870f9bc0da71fe985d37d0192fc9f 100644 --- a/core/qa/CbmQaIO.h +++ b/core/qa/CbmQaIO.h @@ -87,6 +87,10 @@ public: CbmQaTable* MakeTable(const char* name, Args... args); protected: + /// @brief Applies properties on the histogram created with MakeHisto funciton + /// @param pHist Pointer to histogram + virtual void SetHistoProperties(TH1* /*pHits*/); + TString fsRootFolderName = ""; ///< Name of root folder TString fsPrefix = ""; ///< Unique prefix for all writeable root @@ -172,8 +176,7 @@ T* CbmQaIO::MakeHisto(const char* nameBase, Args... args) } T* pHist = new T(name, args...); - pHist->SetStats(kTRUE); - pHist->Sumw2(); + SetHistoProperties(pHist); // Register histogram in the folder if (fStoringMode == EStoringMode::kSUBDIR) { diff --git a/reco/L1/CbmL1Track.h b/reco/L1/CbmL1Track.h index d89fd5cedcebee8da48387dc1b07a1f90b60ec27..bad57d9da3990d770c9103b6f3e7adc3aa486388 100644 --- a/reco/L1/CbmL1Track.h +++ b/reco/L1/CbmL1Track.h @@ -64,6 +64,9 @@ public: /// Gets Chi-square of track fit model double GetChiSq() const { return chi2; } + /// @brief Gets pseudo-rapidity + double GetEta() const { return -std::log(std::tan(GetTheta() * 0.5)); } + /// @brief Gets first hit index int GetFirstHitIndex() const { return Hits.front(); } diff --git a/reco/L1/catools/CaToolsMCTrack.h b/reco/L1/catools/CaToolsMCTrack.h index 3c474af8012bc113f4e3895f6ecc9a74839bac05..a9ab5286ee5d1e0944a3c0a17aeb3d069cb00872 100644 --- a/reco/L1/catools/CaToolsMCTrack.h +++ b/reco/L1/catools/CaToolsMCTrack.h @@ -92,6 +92,9 @@ namespace ca::tools /// Gets kinetic energy [GeV] double GetEkin() const { return GetE() - fMass; } + /// Gets pseudo-rapidity + double GetEta() const { return -std::log(std::tan(GetTheta() * 0.5)); } + /// Gets index of MC event containing this track in external data structures int GetEventId() const { return fLinkKey.fEvent; } diff --git a/reco/L1/qa/CbmCaOutputQa.cxx b/reco/L1/qa/CbmCaOutputQa.cxx index af42719b282bd283fc7439ba8e4557612913fd5a..220f69a16710728e92f3cc5f3914b207504db16a 100644 --- a/reco/L1/qa/CbmCaOutputQa.cxx +++ b/reco/L1/qa/CbmCaOutputQa.cxx @@ -9,9 +9,14 @@ #include "CbmCaOutputQa.h" +#include "CbmQaCanvas.h" + #include "FairRootManager.h" #include "Logger.h" +#include "THStack.h" +#include "TPad.h" + #include "L1InitManager.h" using ca::tools::Debugger; @@ -27,20 +32,38 @@ OutputQa::OutputQa(int verbose, bool isMCUsed) : CbmQaTask("CbmCaOutputQa", "cao AddTrackType(ETrackType::kGhost); AddTrackType(ETrackType::kPrim); AddTrackType(ETrackType::kSec); + AddTrackType(ETrackType::kPrimE); + AddTrackType(ETrackType::kPrimPI); + AddTrackType(ETrackType::kPrimK); + AddTrackType(ETrackType::kPrimMU); + AddTrackType(ETrackType::kPrimPPBAR); + AddTrackType(ETrackType::kSecE); + AddTrackType(ETrackType::kSecPI); + AddTrackType(ETrackType::kSecK); + AddTrackType(ETrackType::kSecMU); + AddTrackType(ETrackType::kSecPPBAR); + AddTrackType(ETrackType::kPrimPIP); AddTrackType(ETrackType::kPrimPIM); AddTrackType(ETrackType::kSecPIP); AddTrackType(ETrackType::kSecPIM); - AddTrackType(ETrackType::kPrimMUP); - AddTrackType(ETrackType::kPrimMUM); - AddTrackType(ETrackType::kSecMUP); - AddTrackType(ETrackType::kSecMUM); + AddTrackType(ETrackType::kPrimKP); + AddTrackType(ETrackType::kPrimKM); + AddTrackType(ETrackType::kSecKP); + AddTrackType(ETrackType::kSecKM); + AddTrackType(ETrackType::kPrimP); + AddTrackType(ETrackType::kPrimPBAR); + AddTrackType(ETrackType::kSecP); + AddTrackType(ETrackType::kSecPBAR); //AddTrackType(ETrackType::kAllE); //AddTrackType(ETrackType::kAllMU); //AddTrackType(ETrackType::kAllPI); //AddTrackType(ETrackType::kAllK); //AddTrackType(ETrackType::kAllPPBAR); + + // Init track type histograms drawing attributes + InitDrawingAttributes(); } // --------------------------------------------------------------------------------------------------------------------- @@ -75,7 +98,7 @@ void OutputQa::FillHistograms() if (fvpTrackHistograms[iType]->IsMCUsed()) { fvpTrackHistograms[iType]->FillMCTracks(); } } // if track type ID filled } // track type ID - } + } // kEXPTRACKFILL = true else { for (size_t iTrkReco = 0; iTrkReco < fvRecoTracks.size(); ++iTrkReco) { const auto& recoTrk = fvRecoTracks[iTrkReco]; @@ -83,12 +106,12 @@ void OutputQa::FillHistograms() // Reject tracks, which do not contain hits if (recoTrk.GetNofHits() < 1) { continue; } - if (fvbTrackTypeOn[ETrackType::kAll]) { fvpTrackHistograms[ETrackType::kAll]->FillRecoTrack(iTrkReco); } + FillRecoTrack(ETrackType::kAll, iTrkReco); if (IsMCUsed()) { - if (fvbTrackTypeOn[ETrackType::kGhost] && recoTrk.IsGhost()) { - fvpTrackHistograms[ETrackType::kGhost]->FillRecoTrack(iTrkReco); - } + // NOTE: The ghost status of track is now defined by its purity, thus it can still contain MC information + if (recoTrk.IsGhost()) { FillRecoTrack(ETrackType::kGhost, iTrkReco); } + int iTrkMC = recoTrk.GetMatchedMCTrackIndex(); if (iTrkMC > -1) { const auto& mcTrk = fMCData.GetTrack(iTrkMC); @@ -98,33 +121,7 @@ void OutputQa::FillHistograms() // Cut tracks, which did not leave hits in tracker if (mcTrk.GetNofHits() == 0) { continue; } - if (isPrimary) { - if (fvbTrackTypeOn[ETrackType::kPrim]) { fvpTrackHistograms[ETrackType::kPrim]->FillRecoTrack(iTrkReco); } - - if (fvbTrackTypeOn[ETrackType::kPrimPI] && std::abs(pdg) == 211) { - fvpTrackHistograms[ETrackType::kPrimPI]->FillRecoTrack(iTrkReco); - } - - if (fvbTrackTypeOn[ETrackType::kPrimPIP] && pdg == +211) { - fvpTrackHistograms[ETrackType::kPrimPIP]->FillRecoTrack(iTrkReco); - } - - if (fvbTrackTypeOn[ETrackType::kPrimPIM] && pdg == -211) { - fvpTrackHistograms[ETrackType::kPrimPIM]->FillRecoTrack(iTrkReco); - } - - if (fvbTrackTypeOn[ETrackType::kPrimMU] && std::abs(pdg) == 13) { - fvpTrackHistograms[ETrackType::kPrimMU]->FillRecoTrack(iTrkReco); - } - - if (fvbTrackTypeOn[ETrackType::kPrimMUP] && pdg == +13) { - fvpTrackHistograms[ETrackType::kPrimMUP]->FillRecoTrack(iTrkReco); - } - - if (fvbTrackTypeOn[ETrackType::kPrimMUM] && pdg == -13) { - fvpTrackHistograms[ETrackType::kPrimMUM]->FillRecoTrack(iTrkReco); - } - } + if (isPrimary) { FillRecoTrack(ETrackType::kPrim, iTrkReco); } else { if (fvbTrackTypeOn[ETrackType::kSec]) { fvpTrackHistograms[ETrackType::kSec]->FillRecoTrack(iTrkReco); } @@ -152,6 +149,65 @@ void OutputQa::FillHistograms() fvpTrackHistograms[ETrackType::kSecMUM]->FillRecoTrack(iTrkReco); } } + + // Track distributions for different particle species + switch (std::abs(pdg)) { + case 211: // pion + FillRecoTrack(ETrackType::kAllPI, iTrkReco); + if (isPrimary) { + FillRecoTrack(ETrackType::kPrimPI, iTrkReco); + FillRecoTrack((pdg > 0) ? ETrackType::kPrimPIP : ETrackType::kPrimPIM, iTrkReco); + } + else { + FillRecoTrack(ETrackType::kSecPI, iTrkReco); + FillRecoTrack((pdg > 0) ? ETrackType::kSecPIP : ETrackType::kSecPIM, iTrkReco); + } + break; + case 2212: // proton + FillRecoTrack(ETrackType::kAllPPBAR, iTrkReco); + if (isPrimary) { + FillRecoTrack(ETrackType::kPrimPPBAR, iTrkReco); + FillRecoTrack((pdg > 0) ? ETrackType::kPrimP : ETrackType::kPrimPBAR, iTrkReco); + } + else { + FillRecoTrack(ETrackType::kSecPPBAR, iTrkReco); + FillRecoTrack((pdg > 0) ? ETrackType::kSecP : ETrackType::kSecPBAR, iTrkReco); + } + break; + case 321: // kaon + FillRecoTrack(ETrackType::kAllK, iTrkReco); + if (isPrimary) { + FillRecoTrack(ETrackType::kPrimK, iTrkReco); + FillRecoTrack((pdg > 0) ? ETrackType::kPrimKP : ETrackType::kPrimKM, iTrkReco); + } + else { + FillRecoTrack(ETrackType::kSecK, iTrkReco); + FillRecoTrack((pdg > 0) ? ETrackType::kSecKP : ETrackType::kSecKM, iTrkReco); + } + break; + case 11: // electron + FillRecoTrack(ETrackType::kAllE, iTrkReco); + if (isPrimary) { + FillRecoTrack(ETrackType::kPrimE, iTrkReco); + FillRecoTrack((pdg < 0) ? ETrackType::kPrimEP : ETrackType::kPrimEM, iTrkReco); + } + else { + FillRecoTrack(ETrackType::kSecE, iTrkReco); + FillRecoTrack((pdg < 0) ? ETrackType::kSecEP : ETrackType::kSecEM, iTrkReco); + } + break; + case 13: // muon + FillRecoTrack(ETrackType::kAllMU, iTrkReco); + if (isPrimary) { + FillRecoTrack(ETrackType::kPrimMU, iTrkReco); + FillRecoTrack((pdg > 0) ? ETrackType::kPrimMUP : ETrackType::kPrimMUM, iTrkReco); + } + else { + FillRecoTrack(ETrackType::kSecMU, iTrkReco); + FillRecoTrack((pdg > 0) ? ETrackType::kSecMUP : ETrackType::kSecMUM, iTrkReco); + } + break; + } // switch abs(pdg): end } } } // loop over recoTrk: end @@ -161,86 +217,176 @@ void OutputQa::FillHistograms() // ** Fill distributions of MC-tracks ** // ************************************* if (IsMCUsed()) { - - for (int iTrkMC = 0; iTrkMC < fMCData.GetNofTracks(); ++iTrkMC) { const auto& mcTrk = fMCData.GetTrack(iTrkMC); // Cut tracks, which did not leave hits in tracker if (mcTrk.GetNofHits() == 0) { continue; } - // Fill different track categories - if (fvbTrackTypeOn[ETrackType::kAll]) { fvpTrackHistograms[ETrackType::kAll]->FillMCTrack(iTrkMC); } - int pdg = mcTrk.GetPdgCode(); bool isPrimary = mcTrk.IsPrimary(); - if (isPrimary) { - if (fvbTrackTypeOn[ETrackType::kPrim]) { fvpTrackHistograms[ETrackType::kPrim]->FillMCTrack(iTrkMC); } + // Fill different track categories + FillMCTrack(ETrackType::kAll, iTrkMC); + if (isPrimary) { FillMCTrack(ETrackType::kPrim, iTrkMC); } + else { + FillMCTrack(ETrackType::kSec, iTrkMC); + } - if (fvbTrackTypeOn[ETrackType::kPrimPI] && std::abs(pdg) == 211) { - fvpTrackHistograms[ETrackType::kPrimPI]->FillMCTrack(iTrkMC); - } + // Track distributions for different particle species + switch (std::abs(pdg)) { + case 211: // pion + FillMCTrack(ETrackType::kAllPI, iTrkMC); + if (isPrimary) { + FillMCTrack(ETrackType::kPrimPI, iTrkMC); + FillMCTrack((pdg > 0) ? ETrackType::kPrimPIP : ETrackType::kPrimPIM, iTrkMC); + } + else { + FillMCTrack(ETrackType::kSecPI, iTrkMC); + FillMCTrack((pdg > 0) ? ETrackType::kSecPIP : ETrackType::kSecPIM, iTrkMC); + } + break; + case 2212: // proton + FillMCTrack(ETrackType::kAllPPBAR, iTrkMC); + if (isPrimary) { + FillMCTrack(ETrackType::kPrimPPBAR, iTrkMC); + FillMCTrack((pdg > 0) ? ETrackType::kPrimP : ETrackType::kPrimPBAR, iTrkMC); + } + else { + FillMCTrack(ETrackType::kSecPPBAR, iTrkMC); + FillMCTrack((pdg > 0) ? ETrackType::kSecP : ETrackType::kSecPBAR, iTrkMC); + } + break; + case 321: // kaon + FillMCTrack(ETrackType::kAllK, iTrkMC); + if (isPrimary) { + FillMCTrack(ETrackType::kPrimK, iTrkMC); + FillMCTrack((pdg > 0) ? ETrackType::kPrimKP : ETrackType::kPrimKM, iTrkMC); + } + else { + FillMCTrack(ETrackType::kSecK, iTrkMC); + FillMCTrack((pdg > 0) ? ETrackType::kSecKP : ETrackType::kSecKM, iTrkMC); + } + break; + case 11: // electron + FillMCTrack(ETrackType::kAllE, iTrkMC); + if (isPrimary) { + FillMCTrack(ETrackType::kPrimE, iTrkMC); + FillMCTrack((pdg < 0) ? ETrackType::kPrimEP : ETrackType::kPrimEM, iTrkMC); + } + else { + FillMCTrack(ETrackType::kSecE, iTrkMC); + FillMCTrack((pdg < 0) ? ETrackType::kSecEP : ETrackType::kSecEM, iTrkMC); + } + break; + case 13: // muon + FillMCTrack(ETrackType::kAllMU, iTrkMC); + if (isPrimary) { + FillMCTrack(ETrackType::kPrimMU, iTrkMC); + FillMCTrack((pdg > 0) ? ETrackType::kPrimMUP : ETrackType::kPrimMUM, iTrkMC); + } + else { + FillMCTrack(ETrackType::kSecMU, iTrkMC); + FillMCTrack((pdg > 0) ? ETrackType::kSecMUP : ETrackType::kSecMUM, iTrkMC); + } + break; + } // switch abs(pdg): end + } // iTrkMC + } // IsMCUsed() + } // kEXPTRACKFILL = false +} - if (fvbTrackTypeOn[ETrackType::kPrimPIP] && pdg == +211) { - fvpTrackHistograms[ETrackType::kPrimPIP]->FillMCTrack(iTrkMC); - } +// --------------------------------------------------------------------------------------------------------------------- +// +InitStatus OutputQa::InitCanvases() +{ + /// Set of track types to compare + std::vector<ETrackType> vCmpTypesGeneral = {kAll, kPrim, kSec}; + std::vector<ETrackType> vCmpTypesPrim = {kPrim, kPrimE, kPrimMU, kPrimPI, kPrimK, kPrimPPBAR}; + std::vector<ETrackType> vCmpTypesSec = {kSec, kSecE, kSecMU, kSecPI, kSecK, kSecPPBAR}; + std::vector<ETrackType> vCmpTypesPions = {kAllPI, kPrimPIP, kPrimPIM, kSecPIP, kSecPIM}; + std::vector<ETrackType> vCmpTypesKaons = {kAllK, kPrimKP, kPrimKM, kSecKP, kSecKM}; + 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); + pCanv->cd(1); + gPad->SetLogy(); + DrawSetOf<TH1F>(vCmpTypesGeneral, Hist); + pCanv->cd(2); + gPad->SetLogy(); + DrawSetOf<TH1F>(vCmpTypesPrim, Hist); + pCanv->cd(3); + gPad->SetLogy(); + DrawSetOf<TH1F>(vCmpTypesSec, Hist); + pCanv->cd(4); + gPad->SetLogy(); + DrawSetOf<TH1F>(vCmpTypesPions, Hist); + pCanv->cd(5); + gPad->SetLogy(); + DrawSetOf<TH1F>(vCmpTypesKaons, Hist); + pCanv->cd(6); + gPad->SetLogy(); + DrawSetOf<TH1F>(vCmpTypesProtons, Hist); + }; - if (fvbTrackTypeOn[ETrackType::kPrimPIM] && pdg == -211) { - fvpTrackHistograms[ETrackType::kPrimPIM]->FillMCTrack(iTrkMC); - } + /// @brief Function to draw generic canvas of efficiencies comparison + auto DrawTrackEfficiens = [&](CbmQaCanvas* pCanv, std::function<TProfile*(ETrackType)> Prof) { + pCanv->Divide2D(3); + pCanv->cd(1); + DrawSetOf<TProfile>(vCmpTypesGeneral, Prof); + pCanv->cd(2); + DrawSetOf<TProfile>(vCmpTypesPrim, Prof); + pCanv->cd(3); + DrawSetOf<TProfile>(vCmpTypesSec, Prof); + }; - if (fvbTrackTypeOn[ETrackType::kPrimMU] && std::abs(pdg) == 13) { - fvpTrackHistograms[ETrackType::kPrimMU]->FillMCTrack(iTrkMC); - } - if (fvbTrackTypeOn[ETrackType::kPrimMUP] && pdg == +13) { - fvpTrackHistograms[ETrackType::kPrimMUP]->FillMCTrack(iTrkMC); - } + if (IsMCUsed()) { + // ** Reconstructed track distributions ** + // Reconstructed pseudorapidity + auto* pc_reco_eta = + MakeCanvas<CbmQaCanvas>("reco_eta", "Reconstructed track pseudorapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); + DrawTrackDistributions(pc_reco_eta, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_reco_eta; }); - if (fvbTrackTypeOn[ETrackType::kPrimMUM] && pdg == -13) { - fvpTrackHistograms[ETrackType::kPrimMUM]->FillMCTrack(iTrkMC); - } - } - else { - if (fvbTrackTypeOn[ETrackType::kSec]) { fvpTrackHistograms[ETrackType::kSec]->FillMCTrack(iTrkMC); } + // MC pseudorapidity + auto* pc_reco_etaMC = + MakeCanvas<CbmQaCanvas>("reco_etaMC", "Reconstructed track MC pseudorapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); + DrawTrackDistributions(pc_reco_etaMC, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_reco_etaMC; }); - if (fvbTrackTypeOn[ETrackType::kSecPIP] && std::abs(pdg) == 211) { - fvpTrackHistograms[ETrackType::kSecPIP]->FillMCTrack(iTrkMC); - } + // MC momentum + auto* pc_reco_pMC = + MakeCanvas<CbmQaCanvas>("reco_pMC", "Reconstructed track MC momentum", kCXSIZEPX * 3, kCYSIZEPX * 2); + DrawTrackDistributions(pc_reco_pMC, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_reco_pMC; }); - if (fvbTrackTypeOn[ETrackType::kSecPIP] && pdg == +211) { - fvpTrackHistograms[ETrackType::kPrimPIP]->FillMCTrack(iTrkMC); - } + // MC rapidity + auto* pc_reco_yMC = + MakeCanvas<CbmQaCanvas>("reco_yMC", "Reconstructed track MC rapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); + DrawTrackDistributions(pc_reco_yMC, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_reco_yMC; }); - if (fvbTrackTypeOn[ETrackType::kSecPIM] && pdg == -211) { - fvpTrackHistograms[ETrackType::kPrimPIM]->FillMCTrack(iTrkMC); - } + // ** MC track distributions ** - if (fvbTrackTypeOn[ETrackType::kSecMU] && std::abs(pdg) == 13) { - fvpTrackHistograms[ETrackType::kSecMU]->FillMCTrack(iTrkMC); - } + // MC momentum + auto* pc_mc_pMC = + MakeCanvas<CbmQaCanvas>("mc_pMC", "MC reconstructable track MC momentum", kCXSIZEPX * 3, kCYSIZEPX * 2); + DrawTrackDistributions(pc_mc_pMC, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_mc_pMC; }); - if (fvbTrackTypeOn[ETrackType::kSecMUP] && pdg == +13) { - fvpTrackHistograms[ETrackType::kSecMUP]->FillMCTrack(iTrkMC); - } + // MC rapidity + auto* pc_mc_yMC = + MakeCanvas<CbmQaCanvas>("mc_yMC", "MC reconstructable track MC rapidity", kCXSIZEPX * 3, kCYSIZEPX * 2); + DrawTrackDistributions(pc_mc_yMC, [&](ETrackType t) -> TH1F* { return fvpTrackHistograms[t]->fph_mc_yMC; }); - if (fvbTrackTypeOn[ETrackType::kSecMUM] && pdg == -13) { - fvpTrackHistograms[ETrackType::kSecMUM]->FillMCTrack(iTrkMC); - } - } - } - } - } -} -// --------------------------------------------------------------------------------------------------------------------- -// -InitStatus OutputQa::InitCanvases() -{ - // *************************** - // ** Track distributions + // ** Efficiencies ** + + // MC momentum + auto* pc_eff_pMC = MakeCanvas<CbmQaCanvas>("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 = MakeCanvas<CbmQaCanvas>("eff_yMC", "Tracking Eff. vs. MC rapidity", kCXSIZEPX * 3, kCYSIZEPX); + DrawTrackEfficiens(pc_eff_yMC, [&](ETrackType t) -> TProfile* { return fvpTrackHistograms[t]->fph_eff_yMC; }); + } return kSUCCESS; } @@ -313,15 +459,16 @@ InitStatus OutputQa::InitDataBranches() // InitStatus OutputQa::InitHistograms() { - auto RegisterTrackQa = [&](const char* typeName, ETrackType type, bool bSuppressMC = false) { + auto RegisterTrackQa = [&](const char* typeName, const char* title, ETrackType type, bool bSuppressMC = false) { if (!fvbTrackTypeOn[type]) { return; } bool bUseMC = IsMCUsed() && !bSuppressMC; fvpTrackHistograms[type] = std::make_unique<TrackTypeQa>(typeName, fsPrefix.Data(), bUseMC, fpFolderRoot); + fvpTrackHistograms[type]->SetTitle(title); fvpTrackHistograms[type]->RegisterParameters(fpParameters); fvpTrackHistograms[type]->RegisterRecoHits(fvHits); fvpTrackHistograms[type]->RegisterRecoTracks(fvRecoTracks); fvpTrackHistograms[type]->RegisterMCData(fMCData); - + fvpTrackHistograms[type]->SetDrawAtt(fvTrackDrawAtts[type].fColor, fvTrackDrawAtts[type].fMarker); if constexpr (kEXPTRACKFILL) { // Define track cuts switch (type) { @@ -487,6 +634,7 @@ InitStatus OutputQa::InitHistograms() fvpTrackHistograms[type]->SetMCTrackCut( [](const MCTrack& t) -> bool { return !t.IsPrimary() && t.GetPdgCode() == -2212; }); break; + case kEND: break; } } @@ -497,46 +645,46 @@ InitStatus OutputQa::InitHistograms() LOG(info) << i << ' ' << fvpTrackHistograms[i].get() << ' ' << fvbTrackTypeOn[i]; } - RegisterTrackQa("all", ETrackType::kAll); + RegisterTrackQa("all", "all", ETrackType::kAll); if (IsMCUsed()) { - RegisterTrackQa("ghost", ETrackType::kGhost, /*suppress MC*/ true); - RegisterTrackQa("prim", ETrackType::kPrim); - RegisterTrackQa("sec", ETrackType::kSec); - RegisterTrackQa("all_pi", ETrackType::kAllPI); - RegisterTrackQa("prim_pi", ETrackType::kPrimPI); - RegisterTrackQa("prim_pip", ETrackType::kPrimPIP); - RegisterTrackQa("prim_pim", ETrackType::kPrimPIM); - RegisterTrackQa("sec_pi", ETrackType::kSecPI); - RegisterTrackQa("sec_pip", ETrackType::kSecPIP); - RegisterTrackQa("sec_pim", ETrackType::kSecPIM); - RegisterTrackQa("all_e", ETrackType::kAllE); - RegisterTrackQa("prim_e", ETrackType::kPrimE); - RegisterTrackQa("prim_ep", ETrackType::kPrimEP); - RegisterTrackQa("prim_em", ETrackType::kPrimEM); - RegisterTrackQa("sec_e", ETrackType::kSecE); - RegisterTrackQa("sec_ep", ETrackType::kSecEP); - RegisterTrackQa("sec_em", ETrackType::kSecEM); - RegisterTrackQa("all_mu", ETrackType::kAllMU); - RegisterTrackQa("prim_mu", ETrackType::kPrimMU); - RegisterTrackQa("prim_mup", ETrackType::kPrimMUP); - RegisterTrackQa("prim_mum", ETrackType::kPrimMUM); - RegisterTrackQa("sec_mu", ETrackType::kSecMU); - RegisterTrackQa("sec_mup", ETrackType::kSecMUP); - RegisterTrackQa("sec_mum", ETrackType::kSecMUM); - RegisterTrackQa("all_k", ETrackType::kAllK); - RegisterTrackQa("prim_k", ETrackType::kPrimK); - RegisterTrackQa("prim_kp", ETrackType::kPrimKP); - RegisterTrackQa("prim_km", ETrackType::kPrimKM); - RegisterTrackQa("sec_k", ETrackType::kSecK); - RegisterTrackQa("sec_kp", ETrackType::kSecKP); - RegisterTrackQa("sec_km", ETrackType::kSecKM); - RegisterTrackQa("all_ppbar", ETrackType::kAllPPBAR); - RegisterTrackQa("prim_ppbar", ETrackType::kPrimPPBAR); - RegisterTrackQa("prim_p", ETrackType::kPrimP); - RegisterTrackQa("prim_pbar", ETrackType::kPrimPBAR); - RegisterTrackQa("sec_ppbar", ETrackType::kSecPPBAR); - RegisterTrackQa("sec_p", ETrackType::kSecP); - RegisterTrackQa("sec_pbar", ETrackType::kSecPBAR); + RegisterTrackQa("ghost", "ghost", ETrackType::kGhost, true); + RegisterTrackQa("prim", "primary", ETrackType::kPrim); + RegisterTrackQa("sec", "secondary", ETrackType::kSec); + RegisterTrackQa("all_pi", "all #pi^{#pm}", ETrackType::kAllPI); + RegisterTrackQa("prim_pi", "primary #pi^{#pm}", ETrackType::kPrimPI); + RegisterTrackQa("prim_pip", "primary #pi^{#plus}", ETrackType::kPrimPIP); + RegisterTrackQa("prim_pim", "primary #pi^{#minus}", ETrackType::kPrimPIM); + RegisterTrackQa("sec_pi", "secondary #pi^{#pm}", ETrackType::kSecPI); + RegisterTrackQa("sec_pip", "secondary #pi^{#plus}", ETrackType::kSecPIP); + RegisterTrackQa("sec_pim", "secondary #pi^{#minus}", ETrackType::kSecPIM); + RegisterTrackQa("all_e", "all e^{#pm}", ETrackType::kAllE); + RegisterTrackQa("prim_e", "primary e^{#pm}", ETrackType::kPrimE); + RegisterTrackQa("prim_ep", "primary e^{#plus}", ETrackType::kPrimEP); + RegisterTrackQa("prim_em", "primary e^{#minus}", ETrackType::kPrimEM); + RegisterTrackQa("sec_e", "secondary e^{#pm}", ETrackType::kSecE); + RegisterTrackQa("sec_ep", "secondary e^{#plus}", ETrackType::kSecEP); + RegisterTrackQa("sec_em", "secondary e^{#minus}", ETrackType::kSecEM); + RegisterTrackQa("all_mu", "all #mu^{#pm}", ETrackType::kAllMU); + RegisterTrackQa("prim_mu", "primary #mu^{#pm}", ETrackType::kPrimMU); + RegisterTrackQa("prim_mup", "primary #mu^{#plus}", ETrackType::kPrimMUP); + RegisterTrackQa("prim_mum", "primary #mu^{#minus}", ETrackType::kPrimMUM); + RegisterTrackQa("sec_mu", "secondary #mu^{#pm}", ETrackType::kSecMU); + RegisterTrackQa("sec_mup", "secondary #mu^{#plus}", ETrackType::kSecMUP); + RegisterTrackQa("sec_mum", "secondary #mu^{#minus}", ETrackType::kSecMUM); + RegisterTrackQa("all_k", "all K^{#pm}", ETrackType::kAllK); + RegisterTrackQa("prim_k", "primary K^{#pm}", ETrackType::kPrimK); + RegisterTrackQa("prim_kp", "primary K^{#plus}", ETrackType::kPrimKP); + RegisterTrackQa("prim_km", "primary K^{#minus}", ETrackType::kPrimKM); + RegisterTrackQa("sec_k", "secondary K^{#pm}", ETrackType::kSecK); + RegisterTrackQa("sec_kp", "secondary K^{#plus}", ETrackType::kSecKP); + RegisterTrackQa("sec_km", "secondary K^{#minus}", ETrackType::kSecKM); + RegisterTrackQa("all_ppbar", "all p/#bar{p}", ETrackType::kAllPPBAR); + RegisterTrackQa("prim_ppbar", "primary p/#bar{p}", ETrackType::kPrimPPBAR); + RegisterTrackQa("prim_p", "primary p", ETrackType::kPrimP); + RegisterTrackQa("prim_pbar", "primary #bar{p}", ETrackType::kPrimPBAR); + RegisterTrackQa("sec_ppbar", "secondary p/#bar{p}", ETrackType::kSecPPBAR); + RegisterTrackQa("sec_p", "secondary p", ETrackType::kSecP); + RegisterTrackQa("sec_pbar", "secondary #bar{p}", ETrackType::kSecPBAR); } return kSUCCESS; @@ -582,3 +730,53 @@ void OutputQa::ReadParameters(const char* filename) LOG(info) << fpParameters->ToString(0); } + +// --------------------------------------------------------------------------------------------------------------------- +// +void OutputQa::InitDrawingAttributes() +{ + fvTrackDrawAtts[ETrackType::kAll] = {1, 20}; + fvTrackDrawAtts[ETrackType::kGhost] = {kGray, 20}; + fvTrackDrawAtts[ETrackType::kPrim] = {kGray + 3, 21}; + fvTrackDrawAtts[ETrackType::kSec] = {kGray + 2, 25}; + + fvTrackDrawAtts[ETrackType::kAllPI] = {kRed - 4, 20}; + fvTrackDrawAtts[ETrackType::kPrimPI] = {kRed - 2, 21}; + fvTrackDrawAtts[ETrackType::kPrimPIP] = {kRed - 1, 22}; + fvTrackDrawAtts[ETrackType::kPrimPIM] = {kRed - 3, 23}; + fvTrackDrawAtts[ETrackType::kSecPI] = {kRed - 8, 25}; + fvTrackDrawAtts[ETrackType::kSecPIP] = {kRed - 6, 26}; + fvTrackDrawAtts[ETrackType::kSecPIM] = {kRed - 10, 32}; + + fvTrackDrawAtts[ETrackType::kAllK] = {kBlue - 4, 20}; + fvTrackDrawAtts[ETrackType::kPrimK] = {kBlue - 2, 21}; + fvTrackDrawAtts[ETrackType::kPrimKP] = {kBlue - 1, 22}; + fvTrackDrawAtts[ETrackType::kPrimKM] = {kBlue - 3, 23}; + fvTrackDrawAtts[ETrackType::kSecK] = {kBlue - 8, 25}; + fvTrackDrawAtts[ETrackType::kSecKP] = {kBlue - 6, 26}; + fvTrackDrawAtts[ETrackType::kSecKM] = {kBlue - 10, 32}; + + fvTrackDrawAtts[ETrackType::kAllPPBAR] = {kGreen - 4, 20}; + fvTrackDrawAtts[ETrackType::kPrimPPBAR] = {kGreen - 2, 21}; + fvTrackDrawAtts[ETrackType::kPrimP] = {kGreen - 1, 22}; + fvTrackDrawAtts[ETrackType::kPrimPBAR] = {kGreen - 3, 23}; + fvTrackDrawAtts[ETrackType::kSecPPBAR] = {kGreen - 8, 25}; + fvTrackDrawAtts[ETrackType::kSecP] = {kGreen - 6, 26}; + fvTrackDrawAtts[ETrackType::kSecPBAR] = {kGreen - 10, 32}; + + fvTrackDrawAtts[ETrackType::kAllE] = {kCyan - 4, 20}; + fvTrackDrawAtts[ETrackType::kPrimE] = {kCyan - 2, 21}; + fvTrackDrawAtts[ETrackType::kPrimEP] = {kCyan - 1, 22}; + fvTrackDrawAtts[ETrackType::kPrimEM] = {kCyan - 3, 23}; + fvTrackDrawAtts[ETrackType::kSecE] = {kCyan - 8, 25}; + fvTrackDrawAtts[ETrackType::kSecEP] = {kCyan - 6, 26}; + fvTrackDrawAtts[ETrackType::kSecEM] = {kCyan - 10, 32}; + + fvTrackDrawAtts[ETrackType::kAllMU] = {kMagenta - 4, 20}; + fvTrackDrawAtts[ETrackType::kPrimMU] = {kMagenta - 2, 21}; + fvTrackDrawAtts[ETrackType::kPrimMUP] = {kMagenta - 1, 22}; + fvTrackDrawAtts[ETrackType::kPrimMUM] = {kMagenta - 3, 23}; + fvTrackDrawAtts[ETrackType::kSecMU] = {kMagenta - 8, 25}; + fvTrackDrawAtts[ETrackType::kSecMUP] = {kMagenta - 6, 26}; + fvTrackDrawAtts[ETrackType::kSecMUM] = {kMagenta - 10, 32}; +} diff --git a/reco/L1/qa/CbmCaOutputQa.h b/reco/L1/qa/CbmCaOutputQa.h index 2cac1f21bc4c6d637c0dc8a918714d852c74eccb..95e84669861249594c74741a0c917a89a2bbeda1 100644 --- a/reco/L1/qa/CbmCaOutputQa.h +++ b/reco/L1/qa/CbmCaOutputQa.h @@ -15,6 +15,7 @@ #include "CbmCaTrackTypeQa.h" #include "CbmL1DetectorID.h" #include "CbmL1Hit.h" +#include "CbmQaCmpDrawer.h" #include "CbmQaTask.h" #include <array> @@ -96,6 +97,16 @@ namespace cbm::ca // 3) Experimental approach runs in ~10% slower, then the standard static constexpr bool kEXPTRACKFILL = false; + /// Array for track type properties + template<typename T> + using TTypeArr_t = std::array<T, ETrackType::kEND>; + + /// @brief Structure to keep drawing attributes of histograms + struct DrawAtt { + Color_t fColor = 1; ///< Marker and line color + Style_t fMarker = 1; ///< Marker style + }; + public: /// @brief Constructor from parameters /// @param verbose Verbosity level @@ -185,6 +196,33 @@ namespace cbm::ca void FillTrackTypeHistograms(); private: + /// @brief Fills reconstructed track by its index + /// @param type Track type + /// @param iTrkReco Index of reconstructed track + [[gnu::always_inline]] void FillRecoTrack(ETrackType type, int iTrkReco) + { + if (fvbTrackTypeOn[type]) { fvpTrackHistograms[type]->FillRecoTrack(iTrkReco); } + } + + /// @brief Fills MC track by its index + /// @param type Track type + /// @param iTrkReco Index of MC track + [[gnu::always_inline]] void FillMCTrack(ETrackType type, int iTrkMC) + { + if (fvbTrackTypeOn[type]) { fvpTrackHistograms[type]->FillMCTrack(iTrkMC); } + } + + /// @brief Utility function to draw a generic comparison of histograms from different track types + /// @tparam TObj Type of ROOT object + /// @param vTypes Vector of types to draw + /// @param GetObj Function, returning an object of a given type + template<class TObj> + void DrawSetOf(const std::vector<ETrackType>& vTypes, std::function<TObj*(ETrackType)> GetObj); + + + /// @brief Defines drawing attributes for histograms of different track types + void InitDrawingAttributes(); + // Flags for detector subsystems being used bool fbUseMvd = false; ///< is MVD used bool fbUseSts = false; ///< is STS used @@ -212,11 +250,36 @@ namespace cbm::ca // ** List of histograms ** // ************************* - /// Histograms of different track types - std::array<std::unique_ptr<TrackTypeQa>, ETrackType::kEND> fvpTrackHistograms; - std::array<bool, ETrackType::kEND> fvbTrackTypeOn = {0}; ///< Track type is on + TTypeArr_t<std::unique_ptr<TrackTypeQa>> fvpTrackHistograms; ///< Histogrammers for different track types + TTypeArr_t<bool> fvbTrackTypeOn = {0}; ///< Usage flag for different track types + TTypeArr_t<DrawAtt> fvTrackDrawAtts; ///< Drawing attributes for track types + + // ************************************ + // ** Drawing options and properties ** + // ************************************ + + static constexpr int kCXSIZEPX = 600; ///< Canvas size along x-axis [px] + static constexpr int kCYSIZEPX = 600; ///< Canvas size along y-axis [px] }; } // namespace cbm::ca +// ********************** +// ** Implementation ** +// ********************** + +template<class TObj> +void cbm::ca::OutputQa::DrawSetOf(const std::vector<ETrackType>& vTypes, std::function<TObj*(ETrackType)> GetObj) +{ + CbmQaCmpDrawer<TObj> drawer; + for (auto type : vTypes) { + if (!fvbTrackTypeOn[type] || !fvpTrackHistograms[type]->IsMCUsed()) { continue; } + drawer.RegisterObject(GetObj(type), fvpTrackHistograms[type]->GetTitle()); + } + if constexpr (std::is_same_v<TH1F, TObj>) { drawer.SetMinimum(1.e-1); } + drawer.Draw(""); + drawer.Clear(); +} + + #endif // CbmCaOutputQa_h diff --git a/reco/L1/qa/CbmCaTrackFitQa.h b/reco/L1/qa/CbmCaTrackFitQa.h index 4f2ce84f430f9d51264d80d1b84b6212a337570f..7211c325f86cfc579a7b7b22c7e37f507d3567cc 100644 --- a/reco/L1/qa/CbmCaTrackFitQa.h +++ b/reco/L1/qa/CbmCaTrackFitQa.h @@ -129,11 +129,11 @@ namespace cbm::ca double fUpRESVI = +2.; ///< Upper boundary, residual of inverse speed [1/c] int fBinsPULLX = 200; ///< Number of bins, pull of x - double fLoPULLX = -1.; ///< Lower boundary, pull of x [cm] - double fUpPULLX = +1.; ///< Upper boundary, pull of x [cm] + double fLoPULLX = -4.; ///< Lower boundary, pull of x [cm] + double fUpPULLX = +4.; ///< Upper boundary, pull of x [cm] int fBinsPULLY = 200; ///< Number of bins, pull of y - double fLoPULLY = -1.; ///< Lower boundary, pull of y [cm] - double fUpPULLY = +1.; ///< Upper boundary, pull of y [cm] + double fLoPULLY = -4.; ///< Lower boundary, pull of y [cm] + double fUpPULLY = +4.; ///< Upper boundary, pull of y [cm] int fBinsPULLTX = 200; ///< Number of bins, pull of slope along x-axis double fLoPULLTX = -4.; ///< Lower boundary, pull of slope along x-axis double fUpPULLTX = +4.; ///< Upper boundary, pull of slope along x-axis diff --git a/reco/L1/qa/CbmCaTrackTypeQa.cxx b/reco/L1/qa/CbmCaTrackTypeQa.cxx index 77a329d086ea4634bb07e57baf92a1d53199f387..8e2514d3dc89bc5ba84f7104f7fdc5270c21179d 100644 --- a/reco/L1/qa/CbmCaTrackTypeQa.cxx +++ b/reco/L1/qa/CbmCaTrackTypeQa.cxx @@ -48,41 +48,47 @@ void TrackTypeQa::Init() fph_reco_tx = MakeHisto<TH1F>("reco_tx", "", kBinsTX, kLoTX, kUpTX); fph_reco_ty = MakeHisto<TH1F>("reco_ty", "", kBinsTY, kLoTY, kUpTY); fph_reco_fhitR = MakeHisto<TH1F>("reco_fhitR", "", kBinsFHITR, kLoFHITR, kUpFHITR); - fph_reco_nhits = MakeHisto<TH1F>("reco_nhits", "", kBinsNHITS, kLoNHITS, kUpNHITS); // TODO: ... - fph_reco_p->SetTitle("Total momentum of reconstructed track;p^{reco} [GeV/c]"); - fph_reco_pt->SetTitle("Transverse momentum of reconstructed track;p_{T}^{reco} [GeV/c]"); - fph_reco_phi->SetTitle("Azimuthal angle of reconstructed track;#phi^{reco} [rad]"); - fph_reco_theta->SetTitle("Polar angle of reconstructed track;#theta^{reco} [rad]"); - fph_reco_tx->SetTitle("Slope along x-axis of reconstructed tracks;t_{x}^{reco}"); - fph_reco_ty->SetTitle("Slope along y-axis of reconstructed tracks;t_{y}^{reco}"); - fph_reco_fhitR->SetTitle("Distance of the first hit from z-axis for reconstructed tracks"); - fph_reco_nhits->SetTitle("Hit number of reconstructed tracks"); + fph_reco_p->SetTitle("Total momentum of reconstructed track;p^{reco} [GeV/c];Counts"); + fph_reco_pt->SetTitle("Transverse momentum of reconstructed track;p_{T}^{reco} [GeV/c];Counts"); + fph_reco_phi->SetTitle("Azimuthal angle of reconstructed track;#phi^{reco} [rad];Counts"); + fph_reco_eta->SetTitle("Pseudorapidity of reconstructed track;#eta^{reco};Counts"); + fph_reco_theta->SetTitle("Polar angle of reconstructed track;#theta^{reco} [rad];Counts"); + fph_reco_tx->SetTitle("Slope along x-axis of reconstructed tracks;t_{x}^{reco};Counts"); + fph_reco_ty->SetTitle("Slope along y-axis of reconstructed tracks;t_{y}^{reco};Counts"); + fph_reco_fhitR->SetTitle("Distance of the first hit from z-axis for reconstructed tracks;R^{reco} [cm];Counts"); if (fbUseMC) { // // ** Distributions of reconstructed tracks vs. MC quantities ** // fph_reco_pMC = MakeHisto<TH1F>("reco_pMC", "", kBinsP, kLoP, kUpP); + fph_reco_etaMC = MakeHisto<TH1F>("reco_etaMC", "", kBinsETA, kLoETA, kUpETA); fph_reco_yMC = MakeHisto<TH1F>("reco_yMC", "", kBinsY, kLoY, kUpY); fph_reco_pMC_yMC = MakeHisto<TH2F>("reco_pMC_yMC", "", kBinsY, kLoY, kUpY, kBinsP, kLoP, kUpP); fph_reco_phiMC = MakeHisto<TH1F>("reco_phiMC", "", kBinsPHI, kLoPHI, kUpPHI); fph_reco_thetaMC = MakeHisto<TH1F>("reco_thetaMC", "", kBinsTHETA, kLoTHETA, kUpTHETA); + fph_reco_nhits = MakeHisto<TH1F>("reco_nhits", "", kBinsNHITS, kLoNHITS, kUpNHITS); + + fph_reco_pMC->SetTitle("MC total momentum of reconstructed track;p^{MC} [GeV/c];Counts"); + fph_reco_yMC->SetTitle("MC rapidity of reconstructed track;y^{MC};Counts"); + fph_reco_etaMC->SetTitle("MC pseudorapidity of reconstructed track;#eta^{MC};Counts"); + fph_reco_pMC_yMC->SetTitle("Transverse momentum of reconstructed track;y^{MC};p_{T}^{MC} [GeV/c];Counts"); + fph_reco_phiMC->SetTitle("Azimuthal angle of reconstructed track;#phi^{MC} [rad];Counts"); + fph_reco_thetaMC->SetTitle("Polar angle of reconstructed track;#theta^{MC} [rad];Counts"); + fph_reco_nhits->SetTitle("Hit number of reconstructed tracks;N^{MC}_{hits};Counts"); - fph_reco_pMC->SetTitle("MC total momentum of reconstructed track;p^{MC} [GeV/c]"); - fph_reco_yMC->SetTitle("MC rapidity of reconstructed track;y^{MC}"); - fph_reco_pMC_yMC->SetTitle("Transverse momentum of reconstructed track;y^{MC};p_{T}^{MC} [GeV/c]"); - fph_reco_phiMC->SetTitle("Azimuthal angle of reconstructed track;#phi^{MC} [rad]"); - fph_reco_thetaMC->SetTitle("Polar angle of reconstructed track;#theta^{MC} [rad]"); fph_mc_pMC = MakeHisto<TH1F>("mc_pMC", "", kBinsP, kLoP, kUpP); + fph_mc_etaMC = MakeHisto<TH1F>("mc_etaMC", "", kBinsETA, kLoETA, kUpETA); fph_mc_yMC = MakeHisto<TH1F>("mc_yMC", "", kBinsY, kLoY, kUpY); fph_mc_pMC_yMC = MakeHisto<TH2F>("mc_pMC_yMC", "", kBinsY, kLoY, kUpY, kBinsP, kLoP, kUpP); - fph_mc_pMC->SetTitle("MC total momentum of MC tracks;p^{MC} [GeV/c]"); - fph_mc_yMC->SetTitle("MC rapidity of MC tracks;y^{MC}"); - fph_mc_pMC_yMC->SetTitle("MC total momentum vs. MC rapidity of MC tracks;y^{MC};p^{MC} [GeV/c]"); + fph_mc_pMC->SetTitle("MC total momentum of MC tracks;p^{MC} [GeV/c];Counts"); + fph_mc_yMC->SetTitle("MC rapidity of MC tracks;y^{MC};Counts"); + fph_mc_etaMC->SetTitle("MC pseudorapidity of MC track;#eta^{MC};Counts"); + fph_mc_pMC_yMC->SetTitle("MC total momentum vs. MC rapidity of MC tracks;y^{MC};p^{MC} [GeV/c];Counts"); // // ** Efficiencies ** @@ -119,6 +125,10 @@ void TrackTypeQa::Init() fpFitQaLastHit = std::make_unique<TrackFitQa>("lst_hit", fsPrefix, fpFolderRoot); fpFitQaLastHit->SetTitle("Last hit"); + fpFitQaLastHit->fLoRESX = -0.4; + fpFitQaLastHit->fUpRESX = +0.4; + fpFitQaLastHit->fLoRESY = -0.8; + fpFitQaLastHit->fUpRESY = +0.8; fpFitQaLastHit->Init(); fpFitQaVertex = std::make_unique<TrackFitQa>("vertex", fsPrefix, fpFolderRoot); @@ -134,6 +144,7 @@ void TrackTypeQa::FillRecoTrack(int iTrkReco, double weight) const auto& recoTrack = (*fpvRecoTracks)[iTrkReco]; fph_reco_p->Fill(recoTrack.GetP(), weight); fph_reco_pt->Fill(recoTrack.GetPt(), weight); + fph_reco_eta->Fill(recoTrack.GetEta(), weight); fph_reco_phi->Fill(recoTrack.GetPhi(), weight); fph_reco_theta->Fill(recoTrack.GetTheta(), weight); fph_reco_tx->Fill(recoTrack.GetTx(), weight); @@ -144,6 +155,7 @@ void TrackTypeQa::FillRecoTrack(int iTrkReco, double weight) /// TODO: fill mass hypothesis into CbmL1Track const auto& mcTrack = fpMCData->GetTrack(iTrkMC); fph_reco_pMC->Fill(mcTrack.GetP(), weight); + fph_reco_etaMC->Fill(mcTrack.GetEta(), weight); fph_reco_yMC->Fill(mcTrack.GetRapidity(), weight); fph_reco_pMC_yMC->Fill(mcTrack.GetRapidity(), mcTrack.GetP(), weight); @@ -219,6 +231,7 @@ void TrackTypeQa::FillMCTrack(int iTrkMC, double weight) // ** Distributions ** fph_mc_pMC->Fill(mcTrack.GetP(), weight); + fph_mc_etaMC->Fill(mcTrack.GetEta(), weight); fph_mc_yMC->Fill(mcTrack.GetRapidity(), weight); fph_mc_pMC_yMC->Fill(mcTrack.GetRapidity(), mcTrack.GetP(), weight); @@ -247,7 +260,8 @@ void TrackTypeQa::FillMCTracks() const auto& mcTrk = fpMCData->GetTrack(iTrkMC); // Cut tracks, which did not leave hits in tracker - if (mcTrk.GetNofHits() == 0) { continue; } + //if (mcTrk.GetNofHits() == 0) { continue; } + if (!mcTrk.IsReconstructable()) { continue; } // Cut tracks, which do not pass the applied cut if (!fMCTrackCut(mcTrk)) { continue; } @@ -259,3 +273,27 @@ void TrackTypeQa::FillMCTracks() this->FillMCTrack(iTrkMC); } } + +// --------------------------------------------------------------------------------------------------------------------- +// +void TrackTypeQa::SetDrawAtt(Color_t markerCol, Style_t markerSty, Color_t lineCol, Style_t lineSty) +{ + fMarkerColor = markerCol; + fMarkerStyle = markerSty; + fLineColor = (lineCol > -1) ? lineCol : markerCol; + fLineStyle = lineSty; +} + +// --------------------------------------------------------------------------------------------------------------------- +// +void TrackTypeQa::SetHistoProperties(TH1* pHist) +{ + pHist->SetStats(true); + pHist->Sumw2(); + if (!pHist->InheritsFrom("TH2") && !pHist->InheritsFrom("TH3")) { + 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 73d284fcd74c8d0def7c4fff747495589f5f175c..a933122d45019ee65952b31d38f54e9009551d8a 100644 --- a/reco/L1/qa/CbmCaTrackTypeQa.h +++ b/reco/L1/qa/CbmCaTrackTypeQa.h @@ -39,7 +39,7 @@ namespace cbm::ca /// /// The class provides set of histograms, counters, and efficiencies for monitoring tracks of a particular type /// (reco_fast_long, mc_pi, reco_ghost) - class TrackTypeQa : public CbmQaIO { + class TrackTypeQa : virtual public CbmQaIO { public: /// @brief Constructor /// @param typeName Name of tracks type (used as a prefix for histogram) @@ -65,7 +65,7 @@ namespace cbm::ca TrackTypeQa& operator=(TrackTypeQa&&) = delete; /// @brief Gets title of track group - const char* GetTitle() const { return fsTitle; } + const char* GetTitle() const { return fsTitle.Data(); } /// @brief Initializes histograms void Init(); @@ -111,6 +111,13 @@ namespace cbm::ca /// @param pParameters A shared pointer to the parameters object void RegisterParameters(std::shared_ptr<L1Parameters>& pParameters) { fpParameters = pParameters; } + /// @brief Sets drawing attributes for histograms + /// @param markerCol Marker color + /// @param markerSty Marker style + /// @param lineCol Line color (-1: the same color as marker) + /// @param lineSty Line style + void SetDrawAtt(Color_t markerCol = 1, Style_t markerSty = 20, Color_t lineCol = -1, Style_t lineSty = 1); + /// @brief Sets title, which is to be reflected on legends and titles /// @param title Title of track type void SetTitle(const char* title) { fsTitle = title; } @@ -195,6 +202,11 @@ namespace cbm::ca // TODO: Provide integrated efficiencies 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); + + bool fbUseMC = false; ///< Flag: true - MC information is used TString fsTitle = ""; ///< Title of the track category @@ -217,9 +229,9 @@ namespace cbm::ca // ************************** // ** Binning ** - static constexpr int kBinsP = 150; ///< Number of bins, total momentum + static constexpr int kBinsP = 100; ///< Number of bins, total momentum static constexpr double kLoP = 0.; ///< Lower boundary, total momentum [GeV/c] - static constexpr double kUpP = 15.; ///< Upper boundary, total momentum [GeV/c] + static constexpr double kUpP = 10.; ///< Upper boundary, total momentum [GeV/c] static constexpr int kBinsPT = 100; ///< Number of bins, transverse momentum static constexpr double kLoPT = 0.; ///< Lower boundary, transverse momentum [GeV/c] static constexpr double kUpPT = 10.; ///< Upper boundary, transverse momentum [GeV/c] @@ -247,6 +259,12 @@ namespace cbm::ca static constexpr int kBinsFHITR = 50; ///< Number of bins, transverse distance of the 1st hit from z-axis static constexpr double kLoFHITR = 0.; ///< Lower boundary, transverse distance of the 1st hit from z-axis [cm] static constexpr double kUpFHITR = 150.; ///< Upper boundary, transverse distance of the 1st hit from z-axis [cm] + + // ** Drawing attributes ** + Color_t fMarkerColor = 1; ///< Marker color + Style_t fMarkerStyle = 20; ///< Marker style + Color_t fLineColor = 1; ///< Line color + Style_t fLineStyle = 1; ///< Line style }; } // namespace cbm::ca