From 4f52d6453cf892b182f8f29acbdf5af45766eaa0 Mon Sep 17 00:00:00 2001 From: aferrero2707 Date: Thu, 22 Feb 2024 15:28:08 +0100 Subject: [PATCH 1/2] [MUON] added forward tracks post-processing The post-processing is used to compute the matching efficiency for different MFT/MCH/MID combinations. See Readme.md file for more details. --- Modules/MUON/Common/CMakeLists.txt | 8 + Modules/MUON/Common/Readme.md | 215 +++++++++ .../Common/include/MUONCommon/HistPlotter.h | 5 + .../MUON/Common/include/MUONCommon/LinkDef.h | 2 + .../MUONCommon/MatchingEfficiencyCheck.h | 89 ++++ .../Common/include/MUONCommon/MuonTrack.h | 95 +++- .../Common/include/MUONCommon/TrackPlotter.h | 138 ++++-- .../include/MUONCommon/TracksPostProcessing.h | 95 ++++ .../MUONCommon/TracksPostProcessingConfig.h | 90 ++++ .../Common/include/MUONCommon/TracksTask.h | 30 ++ Modules/MUON/Common/src/HistPlotter.cxx | 19 +- .../Common/src/MatchingEfficiencyCheck.cxx | 253 ++++++++++ Modules/MUON/Common/src/MuonTrack.cxx | 290 +++++++++++- Modules/MUON/Common/src/TrackPlotter.cxx | 444 ++++++++++++++---- .../MUON/Common/src/TracksPostProcessing.cxx | 221 +++++++++ .../Common/src/TracksPostProcessingConfig.cxx | 87 ++++ Modules/MUON/Common/src/TracksTask.cxx | 192 +++++++- 17 files changed, 2095 insertions(+), 178 deletions(-) create mode 100644 Modules/MUON/Common/Readme.md create mode 100644 Modules/MUON/Common/include/MUONCommon/MatchingEfficiencyCheck.h create mode 100644 Modules/MUON/Common/include/MUONCommon/TracksPostProcessing.h create mode 100644 Modules/MUON/Common/include/MUONCommon/TracksPostProcessingConfig.h create mode 100644 Modules/MUON/Common/src/MatchingEfficiencyCheck.cxx create mode 100644 Modules/MUON/Common/src/TracksPostProcessing.cxx create mode 100644 Modules/MUON/Common/src/TracksPostProcessingConfig.cxx diff --git a/Modules/MUON/Common/CMakeLists.txt b/Modules/MUON/Common/CMakeLists.txt index d9aaf0e1dc..ef6fac7ee4 100644 --- a/Modules/MUON/Common/CMakeLists.txt +++ b/Modules/MUON/Common/CMakeLists.txt @@ -9,6 +9,9 @@ set(SRCS src/TrackPlotter.cxx src/TracksCheck.cxx src/TracksTask.cxx + src/TracksPostProcessing.cxx + src/TracksPostProcessingConfig.cxx + src/MatchingEfficiencyCheck.cxx ) set(HEADERS @@ -17,6 +20,9 @@ set(HEADERS include/MUONCommon/TrackCheck.h include/MUONCommon/TrackPlotter.h include/MUONCommon/TracksTask.h + include/MUONCommon/TracksPostProcessing.h + include/MUONCommon/TracksPostProcessingConfig.h + include/MUONCommon/MatchingEfficiencyCheck.h ) # ---- Library ---- @@ -51,6 +57,8 @@ add_root_dictionary(${MODULE_NAME} HEADERS include/MUONCommon/TrackPlotter.h include/MUONCommon/TracksCheck.h include/MUONCommon/TracksTask.h + include/MUONCommon/TracksPostProcessing.h + include/MUONCommon/MatchingEfficiencyCheck.h LINKDEF include/MUONCommon/LinkDef.h) # ---- Tests ---- diff --git a/Modules/MUON/Common/Readme.md b/Modules/MUON/Common/Readme.md new file mode 100644 index 0000000000..df161c0443 --- /dev/null +++ b/Modules/MUON/Common/Readme.md @@ -0,0 +1,215 @@ +# Muon Tracks QC + +## TracksTask + +The tracks task processes the forward muon tracks and produces a number of plots showing the kinematics and time distributions of the tracks. +The type of tracks that are processed is controlled via the `GID` list in the task configuration. The following options can be selected: +* `MCH`: all standalone MCH tracks are considered, independently of their matching with MFT and MID +* `MFT-MCH`: tracks matched from MFT to MCH, independently of their matching with MID +* `MCH-MID`: tracks matched from MCH to MID, independently of their matching with MFT +* `MFT-MCH-MID`: global forward tracks matched to all three detectors + +For each selection listed in the `GID` parameter, two sets of similar plots are produced, one for all the tracks, the second only considering the tracks that pass some standard cuts, namely: +* `cutRAbsMin < RAbs < cutRAbsMax` +* `cutEtaMin < eta < cutEtaMax` +* `pT > cutPtMin` +* `sigmaPDCA < nSigmaPDCA` +* `chi2 < cutChi2Max` + +All the cuts are computed using the standalone MCH tracks parameters, regardless of the matching, in order to have a consistent selection for all track types. + +In addition to the single-track cuts listed above, a cut (`diMuonTimeCut`) on the time difference (in nanoseconds) between track pairs is applied when filling the di-muon invariant mass plot. + +For each selection, the following histograms are filled: +* track kinematic parameters (pT, eta, phi) and their correlations +* distribution of the BC ids associated to the tracks +* tracks multiplicity per TF +* track quality parameters (chi2, RAbs, P*DCA, matching chi2 and probablity) +* 2-D distributions of the MCH track impact points at the MFT exit and MID entrance planes + +The plots are saved in sub-folders inside `GLO/MUONTracks`, one folder for each `GID`. An additional sub-folder is aslo created for the plots after selection cuts. +In the example below, the folder structure would look like this: + +``` +GLO/MUONTracks/MFT-MCH/ +GLO/MUONTracks/MFT-MCH/WithCuts/ +GLO/MUONTracks/MCH-MID/ +GLO/MUONTracks/MCH-MID/WithCuts/ +GLO/MUONTracks/MFT-MCH-MID/ +GLO/MUONTracks/MFT-MCH-MID/WithCuts/ +``` + +#### Configuration +```json +{ + "qc": { + "tasks": { + "TaskMUONTracks": { + "active": "true", + "className": "o2::quality_control_modules::muon::TracksTask", + "moduleName": "QcMUONCommon", + "detectorName": "GLO", + "taskName": "MUONTracks", + "cycleDurationSeconds": "300", + "maxNumberCycles": "-1", + "dataSource": { + "type": "direct", + "query": "trackMCH:MCH/TRACKS;trackMCHROF:MCH/TRACKROFS;trackMCHTRACKCLUSTERS:MCH/TRACKCLUSTERS;mchtrackdigits:MCH/CLUSTERDIGITS;trackMFT:MFT/TRACKS;trackMFTROF:MFT/MFTTrackROF;trackMFTClIdx:MFT/TRACKCLSID;alpparMFT:MFT/ALPIDEPARAM;trackMID:MID/TRACKS;trackMIDROF:MID/TRACKROFS;trackMIDTRACKCLUSTERS:MID/TRACKCLUSTERS;trackClMIDROF:MID/TRCLUSROFS;matchMCHMID:GLO/MTC_MCHMID;fwdtracks:GLO/GLFWD" + }, + "taskParameters": { + "maxTracksPerTF": "600", + "cutRAbsMin": "17.6", + "cutRAbsMax": "89.5", + "cutEtaMin": "-4.0", + "cutEtaMax": "-2.5", + "cutPtMin": "0.5", + "cutPtMin": "0.5", + "nSigmaPDCA": "6", + "cutChi2Max": "1000", + "diMuonTimeCut": "100", + "fullHistos": "0", + "GID" : "MFT-MCH,MCH-MID,MFT-MCH-MID" + }, + "grpGeomRequest": { + "geomRequest": "Aligned", + "askGRPECS": "true", + "askGRPLHCIF": "false", + "askGRPMagField": "true", + "askMatLUT": "false", + "askTime": "false", + "askOnceAllButField": "false", + "needPropagatorD": "false" + }, + "location": "remote" + } + } + } +} +``` + +## Tracks Post-processing + +The tracks post-processing task takes the plots produced by the tracks task and computes the matching efficiency from their ratios. +Each data source in the task configuration specifies the path of the plots from matched tracks(numerator), the path of the reference plots from un-matched tracks (denominator), and the path where to store the matching efficiency plots (ratios). The data source also contains a `names` parameter with the list of plots to be compared. Each plot name can be followed by an optional number, separated by a semi-colon, that indicates the rebinning factor to be applied to the plots before computing the ratio. + +#### Configuration + +```json +{ + "qc": { + "postprocessing": { + "MUONTracks": { + "active": "true", + "className": "o2::quality_control_modules::muon::TracksPostProcessing", + "moduleName": "QcMUONCommon", + "detectorName": "GLO", + "dataSources": [ + { + "plotsPath": "GLO/MO/MUONTracks/MCH-MID/WithCuts", + "refsPath": "MCH/MO/Tracks/WithCuts", + "outputPath": "MCH-MID/WithCuts/MatchEff", + "names": [ "TrackPt:5", "TrackEta:5", "TrackPhi:10", "TrackEtaPt", "TrackPhiPt", "TrackPosAtMID" ] + }, + { + "plotsPath": "GLO/MO/MUONTracks/MCH-MID/WithCuts", + "refsPath": "MCH/MO/Tracks/WithCuts", + "outputPath": "MCH-MID/WithCuts/MatchEff", + "names": [ "TrackPt:5", "TrackEta:5", "TrackPhi:10", "TrackEtaPt", "TrackPhiPt", "TrackPosAtMID" ] + }, + { + "plotsPath": "GLO/MO/MUONTracks/MFT-MCH-MID", + "refsPath": "MCH/MO/Tracks", + "outputPath": "MFT-MCH-MID/MatchEff-MCH", + "names": [ "TrackPt:5", "TrackEta:5", "TrackPhi:10", "TrackEtaPt", "TrackPhiPt", "TrackPosAtMID", "TrackPosAtMFT" ] + }, + { + "plotsPath": "GLO/MO/MUONTracks/MFT-MCH-MID", + "refsPath": "GLO/MO/MUONTracks/MCH-MID", + "outputPath": "MFT-MCH-MID/MatchEff-MCH-MID", + "names": [ "TrackPt:5", "TrackEta:5", "TrackPhi:10", "TrackEtaPt", "TrackPhiPt", "TrackPosAtMID", "TrackPosAtMFT" ] + }, + { + "plotsPath": "GLO/MO/MUONTracks/MFT-MCH-MID/WithCuts", + "refsPath": "MCH/MO/Tracks/WithCuts", + "outputPath": "MFT-MCH-MID/WithCuts/MatchEff-MCH", + "names": [ "TrackPt:5", "TrackEta:5", "TrackPhi:10", "TrackEtaPt", "TrackPhiPt", "TrackPosAtMID", "TrackPosAtMFT" ] + }, + { + "plotsPath": "GLO/MO/MUONTracks/MFT-MCH-MID/WithCuts", + "refsPath": "GLO/MO/MUONTracks/MCH-MID/WithCuts", + "outputPath": "MFT-MCH-MID/WithCuts/MatchEff-MCH-MID", + "names": [ "TrackPt:5", "TrackEta:5", "TrackPhi:10", "TrackEtaPt", "TrackPhiPt", "TrackPosAtMID", "TrackPosAtMFT" ] + } + ], + "initTrigger": [ + "userorcontrol" + ], + "updateTrigger": [ + "newobject:qcdb:GLO/MO/MUONTracks/MCH-MID/TrackPt" + ], + "stopTrigger": [ + "userorcontrol" + ] + } + } + } +} +``` + +## Matching Efficiency Checker + +The matching efficiency checker takes the output of the tracks post-processing and verifies that the efficiency values in each plot are within configurable limits. The limits are defined separately for each histogram, or group of histograms, whose name matches a given string. +For 1-D plots, the check can be additionally restricetd to one or more ranges in the x variable, in case some kinematical regions need to be excluded. + +For example, the following line corresponds to an acceptable range, for the plots named `TrackEta`, of `[0.3,1.0]` and only checked within the eta ranges `[-4.0,-3.5]` and `[-3.0,-2.5]`: + +``` +"range:TrackEta": "0.3,1.0:-4.0,-3.5:-3.0,-2.5" +``` + +If no limit is specified for a given plot, the corresponding values are not checked and the plot is only beautified. + +For 2-D plots, the beautification only consists in fixing the z-axis range to `[0.0,1.2]`. +For 1-D plots, the acceptable range is also indicated with horizontal lines, and the plot is painted in red if the quality is judged to be bad. + +#### Configuration + +```json +{ + "qc": { + "checks": { + "MUONMatchCheck": { + "active": "true", + "className": "o2::quality_control_modules::muon::MatchingEfficiencyCheck", + "moduleName": "QcMUONCommon", + "detectorName": "GLO", + "policy": "OnAll", + "extendedCheckParameters": { + "default": { + "default": { + "range:TrackEta": "0.3,1.0:-4.0,-3.5:-3.0,-2.5", + "range:TrackPt": "0.4,1.0:0.5,2.0", + "range:WithCuts": "0.4,1.0" + } + } + }, + "dataSource": [ + { + "type": "PostProcessing", + "name": "MUONTracks", + "MOs" : [ + "MCH-MID/MatchEff/TrackPhi", + "MCH-MID/MatchEff/TrackPt", + "MCH-MID/MatchEff/TrackEta", + "MCH-MID/WithCuts/MatchEff/TrackPhi", + "MCH-MID/WithCuts/MatchEff/TrackPt", + "MCH-MID/WithCuts/MatchEff/TrackEta", + "MCH-MID/WithCuts/MatchEff/TrackPosAtMID" + ] + } + ] + } + } + } +} +``` \ No newline at end of file diff --git a/Modules/MUON/Common/include/MUONCommon/HistPlotter.h b/Modules/MUON/Common/include/MUONCommon/HistPlotter.h index 342415b86b..f37c00a44a 100644 --- a/Modules/MUON/Common/include/MUONCommon/HistPlotter.h +++ b/Modules/MUON/Common/include/MUONCommon/HistPlotter.h @@ -36,13 +36,18 @@ class HistPlotter /** reset all histograms */ void reset(); + virtual void endOfCycle() {} + std::vector& histograms() { return mHistograms; } const std::vector& histograms() const { return mHistograms; } virtual void publish(std::shared_ptr objectsManager); + virtual void publish(std::shared_ptr objectsManager, HistInfo& hinfo); + virtual void unpublish(std::shared_ptr objectsManager); private: std::vector mHistograms; + std::vector mPublishedHistograms; }; } // namespace o2::quality_control_modules::muon diff --git a/Modules/MUON/Common/include/MUONCommon/LinkDef.h b/Modules/MUON/Common/include/MUONCommon/LinkDef.h index 5649c2b455..3148492dc2 100644 --- a/Modules/MUON/Common/include/MUONCommon/LinkDef.h +++ b/Modules/MUON/Common/include/MUONCommon/LinkDef.h @@ -6,5 +6,7 @@ #pragma link C++ class o2::quality_control_modules::muon::TrackPlotter + ; #pragma link C++ class o2::quality_control_modules::muon::TracksTask + ; #pragma link C++ class o2::quality_control_modules::muon::TracksCheck + ; +#pragma link C++ class o2::quality_control_modules::muon::TracksPostProcessing + ; +#pragma link C++ class o2::quality_control_modules::muon::MatchingEfficiencyCheck + ; #endif diff --git a/Modules/MUON/Common/include/MUONCommon/MatchingEfficiencyCheck.h b/Modules/MUON/Common/include/MUONCommon/MatchingEfficiencyCheck.h new file mode 100644 index 0000000000..87e0632bbf --- /dev/null +++ b/Modules/MUON/Common/include/MUONCommon/MatchingEfficiencyCheck.h @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file MatchingEfficiencyCheck.h +/// \author Andrea Ferrero +/// + +#ifndef QC_MODULE_MUON_MATCHINGEFFICIENCYCHECK_H +#define QC_MODULE_MUON_MATCHINGEFFICIENCYCHECK_H + +#include "QualityControl/CheckInterface.h" + +#include + +namespace o2::quality_control_modules::muon +{ + +/// \brief Check whether a plot is empty or not. +/// +/// \author Andrea Ferrero +class MatchingEfficiencyCheck : public o2::quality_control::checker::CheckInterface +{ + public: + /// Default constructor + MatchingEfficiencyCheck() = default; + /// Destructor + ~MatchingEfficiencyCheck() override = default; + + void configure() override; + Quality check(std::map>* moMap) override; + void beautify(std::shared_ptr mo, Quality checkResult = Quality::Null) override; + std::string getAcceptedType() override; + + void startOfActivity(const Activity& activity) override; + void endOfActivity(const Activity& activity) override; + + ClassDefOverride(MatchingEfficiencyCheck, 1); + + private: + template + T getParameter(std::string parName, const T defaultValue, const o2::quality_control::core::Activity& activity); + template + T getParameter(std::string parName, const T defaultValue); + + void initRange(std::string key); + std::optional> getRange(std::string key); + + Activity mActivity; + std::map> mRanges; + std::map>> mIntervals; + std::map mQualities; +}; + +template +T MatchingEfficiencyCheck::getParameter(std::string parName, const T defaultValue, const o2::quality_control::core::Activity& activity) +{ + T result = defaultValue; + auto parOpt = mCustomParameters.atOptional(parName, activity); + if (parOpt.has_value()) { + std::stringstream ss(parOpt.value()); + ss >> result; + } + return result; +} + +template +T MatchingEfficiencyCheck::getParameter(std::string parName, const T defaultValue) +{ + T result = defaultValue; + auto parOpt = mCustomParameters.atOptional(parName); + if (parOpt.has_value()) { + std::stringstream ss(parOpt.value()); + ss >> result; + } + return result; +} + +} // namespace o2::quality_control_modules::muon + +#endif // QC_MODULE_MUON_MATCHINGEFFICIENCYCHECK_H diff --git a/Modules/MUON/Common/include/MUONCommon/MuonTrack.h b/Modules/MUON/Common/include/MUONCommon/MuonTrack.h index 84923a0bbe..90af9d9205 100644 --- a/Modules/MUON/Common/include/MUONCommon/MuonTrack.h +++ b/Modules/MUON/Common/include/MUONCommon/MuonTrack.h @@ -15,8 +15,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include @@ -27,22 +30,46 @@ namespace o2::quality_control_modules::muon class MuonTrack { public: - MuonTrack(const o2::mch::TrackMCH* track, const o2::globaltracking::RecoContainer& recoCont); - MuonTrack(const o2::dataformats::TrackMCHMID* track, const o2::globaltracking::RecoContainer& recoCont); - MuonTrack(const o2::dataformats::GlobalFwdTrack* track, const o2::globaltracking::RecoContainer& recoCont); + using Time = o2::dataformats::TimeStampWithError; + + public: + MuonTrack() = default; + MuonTrack(const o2::mch::TrackMCH* track, int trackID, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit); + MuonTrack(const o2::dataformats::TrackMCHMID* track, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit); + MuonTrack(const o2::dataformats::GlobalFwdTrack* track, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit); void init(); ROOT::Math::PxPyPzMVector getMuonMomentum() const { return mMuonMomentum; } ROOT::Math::PxPyPzMVector getMuonMomentumAtVertex() const { return mMuonMomentumAtVertex; } - double getP() const - { - return mMuonMomentum.P(); - } + ROOT::Math::PxPyPzMVector getMuonMomentumMCH() const { return mMuonMomentumMCH; } + ROOT::Math::PxPyPzMVector getMuonMomentumAtVertexMCH() const { return mMuonMomentumAtVertexMCH; } + double getP() const; + double getPt() const; + double getEta() const; + double getPhi() const; double getDCA() const { return mDCA; } - double getPDCAMCH() const { return mPDCAMCH; } + double getPDCA() const { return getMuonMomentum().P() * mDCA; } + double getPMCH() const; + double getPtMCH() const; + double getEtaMCH() const; + double getPhiMCH() const; + double getDCAMCH() const { return mDCAMCH; } + double getPDCAMCH() const { return getMuonMomentumMCH().P() * mDCAMCH; } double getRAbs() const { return mRAbs; } double getChi2OverNDF() const { return mChi2OverNDF; } + double getChi2OverNDFMFT() const { return mChi2OverNDFMFT; } + double getChi2OverNDFMCH() const { return mChi2OverNDFMCH; } + double getChi2OverNDFMID() const { return mChi2OverNDFMID; } + + /// get the track x position + double getXMid() const { return mTrackParametersAtMID.getNonBendingCoor(); } + /// get the track y position + double getYMid() const { return mTrackParametersAtMID.getBendingCoor(); } + /// get the track z position where the parameters are evaluated + double getZMid() const { return mTrackParametersAtMID.getZ(); } + + const o2::dataformats::MatchInfoFwd& getMatchInfoFwd() const { return mMatchInfoFwd; } /// get the interaction record associated to this track InteractionRecord getIR() const { return mIR; } @@ -53,6 +80,16 @@ class MuonTrack /// get the interaction record associated to the MID track InteractionRecord getIRMID() const { return mIRMID; } + Time getTime() const { return mTime; } + Time getTimeMFT() const { return mTimeMFT; } + Time getTimeMCH() const { return mTimeMCH; } + Time getTimeMID() const { return mTimeMID; } + + /// get the ROF associated to the MCH track + o2::mch::ROFRecord getRofMCH() const { return mRofMCH; } + + Time getRofTimeMCH() const { return mRofTimeMCH; } + /// get the interaction record associated to the MFT track int getTrackIdMFT() const { return mTrackIdMFT; } /// get the interaction record associated to the MCH track @@ -60,6 +97,21 @@ class MuonTrack /// get the interaction record associated to the MID track int getTrackIdMID() const { return mTrackIdMID; } + /// get the interaction record associated to the MCH track + const o2::mft::TrackMFT* getTrackMFT() const { return mTrackMFT; } + /// get the interaction record associated to the MCH track + const o2::mch::TrackMCH* getTrackMCH() const { return mTrackMCH; } + /// get the interaction record associated to the MID track + const o2::mid::Track* getTrackMID() const { return mTrackMID; } + + const o2::mch::TrackParam& getTrackParamMFT() const { return mTrackParametersMFT; } + const o2::mch::TrackParam& getTrackParamMCH() const { return mTrackParametersMCH; } + const o2::mch::TrackParam& getTrackParamMID() const { return mTrackParametersMID; } + + bool extrapToZMFT(o2::mch::TrackParam& trackParam, float z) const; + bool extrapToZMCH(o2::mch::TrackParam& trackParam, float z) const; + bool extrapToZMID(o2::mch::TrackParam& trackParam, float z) const; + bool hasMFT() const { return (mTrackIdMFT >= 0); } bool hasMCH() const { return (mTrackIdMCH >= 0); } bool hasMID() const { return (mTrackIdMID >= 0); } @@ -67,30 +119,55 @@ class MuonTrack /// get the muon sign short getSign() const { return mSign; } + bool canBeMuon() const; + static constexpr double sAbsZBeg = -90.; ///< Position of the begining of the absorber (cm) static constexpr double sAbsZEnd = -505.; ///< Position of the end of the absorber (cm) private: + o2::dataformats::MatchInfoFwd mMatchInfoFwd; + o2::mch::TrackParam mTrackParameters; + o2::mch::TrackParam mTrackParametersMFT; o2::mch::TrackParam mTrackParametersMCH; + o2::mch::TrackParam mTrackParametersMID; + o2::mch::TrackParam mTrackParametersAtMID; ROOT::Math::PxPyPzMVector mMuonMomentum; ROOT::Math::PxPyPzMVector mMuonMomentumAtVertex; + ROOT::Math::PxPyPzMVector mMuonMomentumMCH; + ROOT::Math::PxPyPzMVector mMuonMomentumAtVertexMCH; float mDCA{ 0 }; - float mPDCAMCH{ 0 }; + float mDCAMCH{ 0 }; float mRAbs{ 0 }; float mChi2OverNDF{ 0 }; + float mChi2OverNDFMFT{ 0 }; + float mChi2OverNDFMCH{ 0 }; + float mChi2OverNDFMID{ 0 }; InteractionRecord mIR{}; ///< associated interaction record InteractionRecord mIRMFT{}; ///< MFT interaction record InteractionRecord mIRMCH{}; ///< MCH interaction record InteractionRecord mIRMID{}; ///< MID interaction record + Time mTime; + Time mTimeMFT; + Time mTimeMCH; + Time mTimeMID; + + o2::mch::ROFRecord mRofMCH{}; + + Time mRofTimeMCH; + int mTrackIdMFT{ -1 }; int mTrackIdMCH{ -1 }; int mTrackIdMID{ -1 }; + o2::mft::TrackMFT* mTrackMFT{ nullptr }; + o2::mch::TrackMCH* mTrackMCH{ nullptr }; + o2::mid::Track* mTrackMID{ nullptr }; + short mSign; }; diff --git a/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h b/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h index cec8bafd1e..9de9f064b5 100644 --- a/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h +++ b/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h @@ -14,11 +14,15 @@ #include "MUONCommon/HistPlotter.h" #include "MUONCommon/MuonTrack.h" +#include "Common/TH1Ratio.h" +#include "Common/TH2Ratio.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include +#include "MFTTracking/Constants.h" #include +#include #include #include @@ -26,34 +30,38 @@ #include #include #include -/* -namespace o2::mch -{ -class Cluster; -class ROFRecord; -class TrackMCH; -class Digit; -} // namespace o2::mch -namespace o2::dataformats -{ -class TrackMCHMID; -class GlobalFwdTrack; -} -*/ using GID = o2::dataformats::GlobalTrackID; +using namespace o2::quality_control_modules::common; + +using MuonCutFunc = std::function; +using DiMuonCutFunc = std::function; + namespace o2::quality_control_modules::muon { class TrackPlotter : public HistPlotter { public: - TrackPlotter(int maxTracksPerTF, GID::Source source, std::string path); + static constexpr Double_t sLastMFTPlaneZ = o2::mft::constants::mft::LayerZCoordinate()[9]; + + TrackPlotter(int maxTracksPerTF, GID::Source source, std::string path, bool fullHistos = false); ~TrackPlotter() = default; public: + void setMuonCuts(const std::vector& cuts) { mMuonCuts = cuts; } + void setDiMuonCuts(const std::vector& cuts) { mDiMuonCuts = cuts; } + + void addMuonCut(const MuonCutFunc f) { mMuonCuts.push_back(f); } + void addDiMuonCut(const DiMuonCutFunc f) { mDiMuonCuts.push_back(f); } + void fillHistograms(const o2::globaltracking::RecoContainer& recoCont); + void setFirstTForbit(int orbit) { mFirstTForbit = orbit; } + + void endOfCycle(); + + const std::vector>& getMuonTracks() const { return mMuonTracks; } private: /** create histograms related to tracks */ @@ -65,41 +73,111 @@ class TrackPlotter : public HistPlotter template std::unique_ptr createHisto(const char* name, const char* title, int nbins, double xmin, double xmax, + bool optional, + bool statBox = false, + const char* drawOptions = "", + const char* displayHints = ""); + template + std::unique_ptr createHisto(const char* name, const char* title, + int nbins, double xmin, double xmax, + int nbinsy, double ymin, double ymax, + bool optional, bool statBox = false, const char* drawOptions = "", const char* displayHints = ""); /** fill histograms related to a single track */ - bool fillTrackHistos(const MuonTrack& track); + void fillTrackHistos(const MuonTrack& track); /** fill histograms for track pairs */ - void fillTrackPairHistos(gsl::span tracks); + void fillTrackPairHistos(gsl::span> tracks); + + void normalizePlot(TH1* h); GID::Source mSrc; std::string mPath; - std::unique_ptr mTrackBC; ///< BC associated to the track - std::unique_ptr mTrackBCWidth; ///< BC width associated to the track - std::unique_ptr mTrackDT; ///< time difference between MFT/MCH/MID tracks segments - std::array, 3> mNofTracksPerTF; ///< number of tracks per TF - std::array, 3> mTrackDCA; ///< DCA (cm) of the track - std::array, 3> mTrackEta; ///< eta of the track - std::array, 3> mTrackPDCA; ///< p (GeV/c) x DCA (cm) of the track - std::array, 3> mTrackPhi; ///< phi (in degrees) of the track - std::array, 3> mTrackPt; ///< Pt (Gev/c^2) of the track - std::array, 3> mTrackRAbs; ///< R at absorber end of the track - - std::unique_ptr mMinv; ///< invariant mass of unlike-sign track pairs + bool mFullHistos; + + uint32_t mFirstTForbit{ 0 }; + int mNOrbitsPerTF{ -1 }; + + std::vector> mMuonTracks; + + std::vector mMuonCuts; + std::vector mDiMuonCuts; + + std::unique_ptr mTrackBC; ///< BC associated to the track + std::unique_ptr mTrackDT; ///< time difference between MCH/MID tracks segments + std::array, 3> mNofTracksPerTF; ///< number of tracks per TF + std::array, 3> mTrackChi2OverNDF; ///< chi2/ndf for the track + std::array, 3> mTrackDCA; ///< DCA (cm) of the track + std::array, 3> mTrackEta; ///< eta of the track + std::array, 3> mTrackPDCA; ///< p (GeV/c) x DCA (cm) of the track + std::array, 3> mTrackPhi; ///< phi (in degrees) of the track + std::array, 3> mTrackPt; ///< Pt (Gev/c) of the track + std::unique_ptr mTrackQOverPt; ///< Q / Pt of the track + std::array, 3> mTrackRAbs; ///< R at absorber end of the track + std::array, 3> mTrackEtaPhi; ///< phi (in degrees) vs. eta of the track + std::array, 3> mTrackEtaPt; ///< Pt (Gev/c) vs. eta of the track + std::array, 3> mTrackPhiPt; ///< Pt (Gev/c) vs. phi (in degrees) of the track + + std::unique_ptr mTrackPosAtMFT; ///< MCH track poisiton at MFT exit + std::unique_ptr mTrackPosAtMID; ///< MCH track poisiton at MID entrance + + std::unique_ptr mMatchChi2MCHMID; + + // plots specific to MFT-MCH(-MID) matched tracks + std::unique_ptr mMatchNMFTCandidates; + std::unique_ptr mMatchScoreMFTMCH; + std::unique_ptr mMatchChi2MFTMCH; + std::array, 3> mTrackEtaCorr; ///< correlation between MCH and global track parameters - eta + std::array, 3> mTrackDEtaVsEta; ///< deviation between MCH and global track parameters - eta + std::array, 3> mTrackPhiCorr; ///< correlation between MCH and global track parameters - phi + std::array, 3> mTrackDPhiVsPhi; ///< deviation between MCH and global track parameters - phi + std::array, 3> mTrackPtCorr; ///< correlation between MCH and global track parameters - pT + std::array, 3> mTrackDPtVsPt; ///< deviation between MCH and global track parameters - pT + + std::unique_ptr mMinvFull; ///< invariant mass of unlike-sign track pairs + std::unique_ptr mMinv; ///< invariant mass background of unlike-sign track pairs + std::unique_ptr mMinvBgd; ///< invariant mass background of unlike-sign, out-of-time track pairs + std::unique_ptr mDimuonDT; ///< time difference between di-muon tracks }; template std::unique_ptr TrackPlotter::createHisto(const char* name, const char* title, int nbins, double xmin, double xmax, + bool optional, bool statBox, const char* drawOptions, const char* displayHints) { - auto h = std::make_unique(name, title, nbins, xmin, xmax); + if (optional && !mFullHistos) { + return nullptr; + } + std::string fullTitle = std::string("[") + GID::getSourceName(mSrc) + "] " + title; + auto h = std::make_unique(name, fullTitle.c_str(), nbins, xmin, xmax); + if (!statBox) { + h->SetStats(0); + } + histograms().emplace_back(HistInfo{ h.get(), drawOptions, displayHints }); + return h; +} + +template +std::unique_ptr TrackPlotter::createHisto(const char* name, const char* title, + int nbins, double xmin, double xmax, + int nbinsy, double ymin, double ymax, + bool optional, + bool statBox, + const char* drawOptions, + const char* displayHints) +{ + if (optional && !mFullHistos) { + return nullptr; + } + std::string fullTitle = std::string("[") + GID::getSourceName(mSrc) + "] " + title; + auto h = std::make_unique(name, fullTitle.c_str(), nbins, xmin, xmax, nbinsy, ymin, ymax); if (!statBox) { h->SetStats(0); } diff --git a/Modules/MUON/Common/include/MUONCommon/TracksPostProcessing.h b/Modules/MUON/Common/include/MUONCommon/TracksPostProcessing.h new file mode 100644 index 0000000000..0e4be94b6f --- /dev/null +++ b/Modules/MUON/Common/include/MUONCommon/TracksPostProcessing.h @@ -0,0 +1,95 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file TracksPostProcessing.h +/// \author Andrea Ferrero andrea.ferrero@cern.ch +/// \brief Post-processing of the MUON tracks +/// + +#ifndef QC_MODULE_MUON_COMMON_PP_TRACKS_H +#define QC_MODULE_MUON_COMMON_PP_TRACKS_H + +#include "MUONCommon/HistPlotter.h" +#include "MUONCommon/TracksPostProcessingConfig.h" +#include "QualityControl/PostProcessingInterface.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include +#include +#include + +namespace o2::quality_control::core +{ +class Activity; +} + +namespace o2::quality_control::repository +{ +class DatabaseInterface; +} + +using namespace o2::quality_control; +using namespace o2::quality_control::postprocessing; + +namespace o2::quality_control_modules::muon +{ + +using namespace o2::quality_control::core; +using GID = o2::dataformats::GlobalTrackID; + +class MatchingEfficiencyPlotterInterface : public HistPlotter +{ + public: + MatchingEfficiencyPlotterInterface() = default; + virtual void update(repository::DatabaseInterface& qcdb, Trigger t, std::shared_ptr objectsManager) = 0; +}; + +template +class MatchingEfficiencyPlotter : public MatchingEfficiencyPlotterInterface +{ + public: + MatchingEfficiencyPlotter(std::string pathMatched, std::string pathMCH, std::string path, std::string plotName, int rebin); + + void update(repository::DatabaseInterface& qcdb, Trigger t, std::shared_ptr objectsManager) override; + + private: + std::string mPlotPath[2]; + std::string mPlotName[2]; + uint64_t mTimestamp[2]; + std::string mName; + std::shared_ptr mHistMatchingEff; + int mRebin; +}; + +/// \brief A post-processing task which processes and trends MCH digits and produces plots. +class TracksPostProcessing : public PostProcessingInterface +{ + public: + TracksPostProcessing() = default; + ~TracksPostProcessing() override = default; + + void configure(const boost::property_tree::ptree& config) override; + void initialize(Trigger, framework::ServiceRegistryRef) override; + void update(Trigger, framework::ServiceRegistryRef) override; + void finalize(Trigger, framework::ServiceRegistryRef) override; + + private: + void createTrackHistos(); + void updateTrackHistos(Trigger t, repository::DatabaseInterface* qcdb); + + std::unique_ptr mConfig; + + std::vector> mMatchingEfficiencyPlotters; +}; + +} // namespace o2::quality_control_modules::muon + +#endif // QC_MODULE_MUON_COMMON_PP_TRACKS_H diff --git a/Modules/MUON/Common/include/MUONCommon/TracksPostProcessingConfig.h b/Modules/MUON/Common/include/MUONCommon/TracksPostProcessingConfig.h new file mode 100644 index 0000000000..1961b2b731 --- /dev/null +++ b/Modules/MUON/Common/include/MUONCommon/TracksPostProcessingConfig.h @@ -0,0 +1,90 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file TracksPostProcessingConfig.h +/// \author Andrea Ferrero andrea.ferrero@cern.ch +/// \brief Header file for the configuration of MCH post-processing tasks +/// \since 16/06/2022 +/// + +#ifndef QC_MODULE_MUON_TRACKS_PP_CONF_H +#define QC_MODULE_MUON_TRACKS_PP_CONF_H + +#include "QualityControl/PostProcessingConfig.h" +#include +#include +#include +#include + +using namespace o2::quality_control::postprocessing; +namespace o2::quality_control_modules::muon +{ + +/// \brief MCH trending configuration structure +struct TracksPostProcessingConfig : PostProcessingConfig { + TracksPostProcessingConfig() = default; + TracksPostProcessingConfig(std::string name, const boost::property_tree::ptree& config); + ~TracksPostProcessingConfig() = default; + + const bool hasParameter(std::string name) const + { + auto entry = parameters.find(name); + return (entry != parameters.end()); + } + + template + const T getParameter(std::string name) const; + + template + const T getParameter(std::string name, T defaultValue) const; + + struct DataSource { + std::string plotsPath; + std::string refsPath; + std::string outputPath; + std::string name; + int rebin{ 1 }; + }; + + std::map parameters; + std::vector dataSources; +}; + +template +const T TracksPostProcessingConfig::getParameter(std::string name) const +{ + T result{}; + auto entry = parameters.find(name); + if (entry != parameters.end()) { + std::istringstream istr(entry->second); + istr >> result; + } + + return result; +} + +template +const T TracksPostProcessingConfig::getParameter(std::string name, T defaultValue) const +{ + T result = defaultValue; + auto entry = parameters.find(name); + if (entry != parameters.end()) { + std::istringstream istr(entry->second); + istr >> result; + } + + return result; +} + +} // namespace o2::quality_control_modules::muon + +#endif // QC_MODULE_MUON_TRACKS_PP_CONF_H diff --git a/Modules/MUON/Common/include/MUONCommon/TracksTask.h b/Modules/MUON/Common/include/MUONCommon/TracksTask.h index bffe5d2ee5..7d6e7b149e 100644 --- a/Modules/MUON/Common/include/MUONCommon/TracksTask.h +++ b/Modules/MUON/Common/include/MUONCommon/TracksTask.h @@ -52,8 +52,14 @@ class TracksTask /*final*/ : public TaskInterface bool assertInputs(o2::framework::ProcessingContext& ctx); bool getBooleanParam(const char* paramName) const; + template + T getParameter(std::string parName, const T defaultValue, const o2::quality_control::core::Activity& activity); + template + T getParameter(std::string parName, const T defaultValue); + private: std::map> mTrackPlotters; + std::map> mTrackPlottersWithCuts; std::shared_ptr mDataRequest; o2::globaltracking::RecoContainer mRecoCont; GID::mask_t mSrc = GID::getSourcesMask("MCH-MID"); @@ -67,6 +73,30 @@ class TracksTask /*final*/ : public TaskInterface gsl::span mMFTMCHMIDTracks; }; +template +T TracksTask::getParameter(std::string parName, const T defaultValue, const o2::quality_control::core::Activity& activity) +{ + T result = defaultValue; + auto parOpt = mCustomParameters.atOptional(parName, activity); + if (parOpt.has_value()) { + std::stringstream ss(parOpt.value()); + ss >> result; + } + return result; +} + +template +T TracksTask::getParameter(std::string parName, const T defaultValue) +{ + T result = defaultValue; + auto parOpt = mCustomParameters.atOptional(parName); + if (parOpt.has_value()) { + std::stringstream ss(parOpt.value()); + ss >> result; + } + return result; +} + } // namespace o2::quality_control_modules::muon #endif diff --git a/Modules/MUON/Common/src/HistPlotter.cxx b/Modules/MUON/Common/src/HistPlotter.cxx index e25eab4e71..5a5065b5d4 100644 --- a/Modules/MUON/Common/src/HistPlotter.cxx +++ b/Modules/MUON/Common/src/HistPlotter.cxx @@ -17,12 +17,25 @@ namespace o2::quality_control_modules::muon { +void HistPlotter::publish(std::shared_ptr objectsManager, HistInfo& hinfo) +{ + objectsManager->startPublishing(hinfo.object); + objectsManager->setDefaultDrawOptions(hinfo.object, hinfo.drawOptions); + objectsManager->setDisplayHint(hinfo.object, hinfo.displayHints); + mPublishedHistograms.push_back(hinfo); +} + void HistPlotter::publish(std::shared_ptr objectsManager) { for (auto hinfo : mHistograms) { - objectsManager->startPublishing(hinfo.object); - objectsManager->setDefaultDrawOptions(hinfo.object, hinfo.drawOptions); - objectsManager->setDisplayHint(hinfo.object, hinfo.displayHints); + publish(objectsManager, hinfo); + } +} + +void HistPlotter::unpublish(std::shared_ptr objectsManager) +{ + for (auto hinfo : mPublishedHistograms) { + objectsManager->stopPublishing(hinfo.object); } } diff --git a/Modules/MUON/Common/src/MatchingEfficiencyCheck.cxx b/Modules/MUON/Common/src/MatchingEfficiencyCheck.cxx new file mode 100644 index 0000000000..d1e95f74c7 --- /dev/null +++ b/Modules/MUON/Common/src/MatchingEfficiencyCheck.cxx @@ -0,0 +1,253 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file MatchingEfficiencyCheck.cxx +/// \author Andrea Ferrero +/// + +#include "MUONCommon/MatchingEfficiencyCheck.h" +#include "QualityControl/MonitorObject.h" +#include "QualityControl/Quality.h" +#include +#include + +namespace o2::quality_control_modules::muon +{ + +template <> +std::string MatchingEfficiencyCheck::getParameter(std::string parName, const std::string defaultValue, const o2::quality_control::core::Activity& activity) +{ + std::string result = defaultValue; + auto parOpt = mCustomParameters.atOptional(parName, activity); + if (parOpt.has_value()) { + result = parOpt.value(); + } + return result; +} + +template <> +std::string MatchingEfficiencyCheck::getParameter(std::string parName, const std::string defaultValue) +{ + std::string result = defaultValue; + auto parOpt = mCustomParameters.atOptional(parName); + if (parOpt.has_value()) { + result = parOpt.value(); + } + return result; +} + +void MatchingEfficiencyCheck::configure() {} + +void MatchingEfficiencyCheck::startOfActivity(const Activity& activity) +{ + mActivity = activity; +} + +void MatchingEfficiencyCheck::endOfActivity(const Activity& activity) +{ + mActivity = Activity{}; + mRanges.clear(); + mIntervals.clear(); + mQualities.clear(); +} + +static std::string getBaseName(std::string name) +{ + auto pos = name.rfind("/"); + return ((pos < std::string::npos) ? name.substr(pos + 1) : name); +} + +static std::vector getTokens(std::string str, std::string sep) +{ + std::vector result; + size_t pos = 0; + while (pos < str.size()) { + size_t pos2 = str.find(sep, pos); + size_t count = pos2 - pos; + auto token = str.substr(pos, count); + pos = (pos2 == std::string::npos) ? pos2 : pos2 + 1; + result.push_back(token); + } + return result; +} + +void MatchingEfficiencyCheck::initRange(std::string key) +{ + // Get acceptable range for this histogram + auto iter = mRanges.find(key); + if (iter != mRanges.end()) { + return; + } + + std::string parKey = std::string("range:") + key; + std::string parValue = getParameter(parKey, "", mActivity); + + auto tokens = getTokens(parValue, ":"); + if (tokens.empty()) { + return; + } + + auto range = getTokens(tokens[0], ","); + if (range.size() == 2) { + double min = std::stod(range[0]); + double max = std::stod(range[1]); + iter = mRanges.insert(std::pair{ key, std::make_pair(min, max) }).first; + } + + if (tokens.size() > 1) { + std::vector> intervals; + for (size_t ti = 1; ti < tokens.size(); ti++) { + auto interval = getTokens(tokens[ti], ","); + if (interval.size() == 2) { + double xmin = std::stod(interval[0]); + double xmax = std::stod(interval[1]); + intervals.push_back(std::make_pair(xmin, xmax)); + } + } + mIntervals[key] = intervals; + } +} + +std::optional> MatchingEfficiencyCheck::getRange(std::string key) +{ + std::optional> result; + + // Get acceptable range for this histogram + auto iter = mRanges.find(key); + if (iter != mRanges.end()) { + result = iter->second; + } + + return result; +} + +Quality MatchingEfficiencyCheck::check(std::map>* moMap) +{ + for (auto& [moKey, mo] : *moMap) { + + auto moName = mo->getName(); + + TH1* hist = dynamic_cast(mo->getObject()); + if (!hist) { + continue; + } + + auto key = getBaseName(moName); + + initRange(key); + auto range = getRange(key); + if (!range) { + continue; + } + + // Get list of bin intervals, if any + std::vector> binIntervals; + auto iter = mIntervals.find(key); + if (iter == mIntervals.end()) { + // No range specified for this histogram, all bins are considered + binIntervals.emplace_back(std::make_pair(1, hist->GetNbinsX())); + } else { + // Collect all bin ranges that have to be checked for this histogram + double epsilon = 0.001 * hist->GetXaxis()->GetBinWidth(1); + for (auto i : iter->second) { + int binMin = hist->GetXaxis()->FindBin(i.first + epsilon); + int binMax = hist->GetXaxis()->FindBin(i.second - epsilon); + binIntervals.push_back(std::make_pair(binMin, binMax)); + } + } + + // Quality is good by default, unless the average is outside the acceptable range + // in at least one of the bin intervals + mQualities[moName] = Quality::Good; + + // Loop over bin intervals, compute the average bin value in each interval, + // and compare it to the acceptable range + // If outside, set the quality to Bad + for (auto i : binIntervals) { + // Set the quality to Null if the interval is invalid + if (i.second < i.first) { + mQualities[moName] = Quality::Null; + break; + } + + for (int bin = i.first; bin <= i.second; bin++) { + if (hist->GetBinContent(bin) < range->first || hist->GetBinContent(bin) > range->second) { + mQualities[moName] = Quality::Bad; + break; + } + } + } + } + + Quality result = mQualities.empty() ? Quality::Null : Quality::Good; + for (auto& [key, q] : mQualities) { + if (q.isWorseThan(result)) { + result = q; + } + } + + return result; +} + +std::string MatchingEfficiencyCheck::getAcceptedType() { return "TH1"; } + +void MatchingEfficiencyCheck::beautify(std::shared_ptr mo, Quality checkResult) +{ + TH1* hist = dynamic_cast(mo->getObject()); + if (!hist) { + return; + } + + hist->SetMinimum(0); + hist->SetMaximum(1.2); + + auto moName = mo->getName(); + auto quality = mQualities[moName]; + if (quality == Quality::Bad) { + hist->SetLineColor(kRed); + hist->SetMarkerColor(kRed); + } + + auto key = getBaseName(moName); + auto range = getRange(key); + if (!range) { + return; + } + + // Get list of bin intervals, if any + std::vector> intervals; + auto iter = mIntervals.find(key); + if (iter == mIntervals.end()) { + // No range specified for this histogram, full X range considered + intervals.emplace_back(std::make_pair(hist->GetXaxis()->GetXmin(), hist->GetXaxis()->GetXmax())); + } else { + // Collect bin ranges that have to be checked for this histogram + intervals = iter->second; + } + + for (auto i : intervals) { + // draw horizontal limits + double xmin = i.first; + double xmax = i.second; + TLine* l1 = new TLine(xmin, range->first, xmax, range->first); + l1->SetLineColor(kBlue); + l1->SetLineStyle(kDotted); + hist->GetListOfFunctions()->Add(l1); + + TLine* l2 = new TLine(xmin, range->second, xmax, range->second); + l2->SetLineColor(kBlue); + l2->SetLineStyle(kDotted); + hist->GetListOfFunctions()->Add(l2); + } +} + +} // namespace o2::quality_control_modules::muon diff --git a/Modules/MUON/Common/src/MuonTrack.cxx b/Modules/MUON/Common/src/MuonTrack.cxx index c45f27f7c6..ac0bc46fb6 100644 --- a/Modules/MUON/Common/src/MuonTrack.cxx +++ b/Modules/MUON/Common/src/MuonTrack.cxx @@ -42,6 +42,8 @@ using InteractionRecord = o2::InteractionRecord; namespace { +using namespace o2::quality_control_modules::muon; + constexpr double muonMass = 0.1056584; constexpr double muonMass2 = muonMass * muonMass; @@ -59,6 +61,23 @@ static InteractionRecord getMFTTrackIR(int iTrack, const o2::globaltracking::Rec return InteractionRecord{}; } +static MuonTrack::Time getMFTTrackTime(int iTrack, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit) +{ + // if the MID track is present, use the time from MID + auto rofs = recoCont.getMFTTracksROFRecords(); + for (const auto& rof : rofs) { + if (iTrack < rof.getFirstEntry() || iTrack >= (rof.getFirstEntry() + rof.getNEntries())) { + continue; + } + auto bcDiff = rof.getBCData().differenceInBC(InteractionRecord{ 0, firstTForbit }); + float tMean = (bcDiff + 0.5) * o2::constants::lhc::LHCBunchSpacingMUS; + float tErr = 1.0 * o2::constants::lhc::LHCBunchSpacingMUS; + return { tMean, tErr }; + } + + return MuonTrack::Time{}; +} + static InteractionRecord getMIDTrackIR(int iTrack, const o2::globaltracking::RecoContainer& recoCont) { // if the MID track is present, use the time from MID @@ -73,8 +92,47 @@ static InteractionRecord getMIDTrackIR(int iTrack, const o2::globaltracking::Rec return InteractionRecord{}; } -static InteractionRecord getMCHTrackIR(int iTrack, const o2::globaltracking::RecoContainer& recoCont) +static MuonTrack::Time getMIDTrackTime(int iTrack, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit) { + // if the MID track is present, use the time from MID + auto rofs = recoCont.getMIDTracksROFRecords(); + for (const auto& rof : rofs) { + if (iTrack < rof.firstEntry || iTrack >= (rof.firstEntry + rof.nEntries)) { + continue; + } + auto time = rof.getTimeMUS(InteractionRecord{ 0, firstTForbit }); + if (time.second) { + return time.first; + } else { + return MuonTrack::Time{}; + } + } + + return MuonTrack::Time{}; +} + +static o2::mch::ROFRecord getMCHTrackROF(int iTrack, const o2::globaltracking::RecoContainer& recoCont) +{ + // if the MID track is present, use the time from MID + auto rofs = recoCont.getMCHTracksROFRecords(); + for (const auto& rof : rofs) { + if (iTrack < rof.getFirstIdx() || iTrack > rof.getLastIdx()) { + continue; + } + return rof; + } + + return o2::mch::ROFRecord{}; +} + +static InteractionRecord getMCHTrackIR(int iTrack, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit) +{ + auto tracksMCH = recoCont.getMCHTracks(); + if (iTrack < 0 || iTrack >= tracksMCH.size()) { + return InteractionRecord{}; + } + return tracksMCH[iTrack].getMeanIR(firstTForbit); + // if the MID track is present, use the time from MID auto rofs = recoCont.getMCHTracksROFRecords(); for (const auto& rof : rofs) { @@ -87,8 +145,10 @@ static InteractionRecord getMCHTrackIR(int iTrack, const o2::globaltracking::Rec return InteractionRecord{}; } -static InteractionRecord getMCHTrackIR(const o2::mch::TrackMCH* track, const o2::globaltracking::RecoContainer& recoCont) +static InteractionRecord getMCHTrackIR(const o2::mch::TrackMCH* track, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit) { + return track->getMeanIR(firstTForbit); + // if the MID track is present, use the time from MID auto tracksMCH = recoCont.getMCHTracks(); int iMCH{ -1 }; @@ -99,13 +159,27 @@ static InteractionRecord getMCHTrackIR(const o2::mch::TrackMCH* track, const o2: } } if (iMCH >= 0) { - return getMCHTrackIR(iMCH, recoCont); + return getMCHTrackIR(iMCH, recoCont, firstTForbit); } return InteractionRecord{}; } -static InteractionRecord getGlobalFwdTrackIR(const GlobalFwdTrack* track, const o2::globaltracking::RecoContainer& recoCont) +static MuonTrack::Time getMCHTrackTime(int iTrack, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit) +{ + auto tracksMCH = recoCont.getMCHTracks(); + if (iTrack < 0 || iTrack >= tracksMCH.size()) { + return MuonTrack::Time{}; + } + return tracksMCH[iTrack].getTimeMUS(); +} + +static MuonTrack::Time getMCHTrackTime(const o2::mch::TrackMCH* track, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit) +{ + return track->getTimeMUS(); +} + +static InteractionRecord getGlobalFwdTrackIR(const GlobalFwdTrack* track, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit) { auto iMID = track->getMIDTrackID(); auto tracksMID = recoCont.getMIDTracks(); @@ -118,12 +192,31 @@ static InteractionRecord getGlobalFwdTrackIR(const GlobalFwdTrack* track, const auto tracksMCH = recoCont.getMCHTracks(); if (iMCH >= 0 && iMCH < tracksMCH.size()) { // if the MID track is present, use the time from MID - return getMCHTrackIR(iMCH, recoCont); + return getMCHTrackIR(iMCH, recoCont, firstTForbit); } return InteractionRecord{}; } +static MuonTrack::Time getGlobalFwdTrackTime(const GlobalFwdTrack* track, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit) +{ + auto iMID = track->getMIDTrackID(); + auto tracksMID = recoCont.getMIDTracks(); + if (iMID >= 0 && iMID < tracksMID.size()) { + // if the MID track is present, use the time from MID + return getMIDTrackTime(iMID, recoCont, firstTForbit); + } + + auto iMCH = track->getMCHTrackID(); + auto tracksMCH = recoCont.getMCHTracks(); + if (iMCH >= 0 && iMCH < tracksMCH.size()) { + // if the MID track is present, use the time from MID + return getMCHTrackTime(iMCH, recoCont, firstTForbit); + } + + return MuonTrack::Time{}; +} + static bool getParametersAtVertex(o2::mch::TrackParam& trackParamAtVertex, bool correctForMCS = true) { bool result = false; @@ -213,6 +306,28 @@ static o2::mch::TrackParam forwardTrackToMCHTrack(const o2::track::TrackParFwd& return { track.getZ(), params.data(), cov.data() }; } +static o2::mch::TrackParam forwardTrackToMCHTrack(const o2::track::TrackParCovFwd& track) +{ + const auto phi = track.getPhi(); + const auto sinPhi = std::sin(phi); + const auto tgL = track.getTgl(); + + const auto SlopeX = std::cos(phi) / tgL; + const auto SlopeY = sinPhi / tgL; + const auto InvP_yz = track.getInvQPt() / std::sqrt(sinPhi * sinPhi + tgL * tgL); + + const std::array params{ track.getX(), SlopeX, track.getY(), SlopeY, InvP_yz }; + const std::array cov{ + 1, + 0, 1, + 0, 0, 1, + 0, 0, 0, 1, + 0, 0, 0, 0, 1 + }; + + return { track.getZ(), params.data(), cov.data() }; +} + } // namespace //_________________________________________________________________________________________________________ @@ -220,23 +335,39 @@ static o2::mch::TrackParam forwardTrackToMCHTrack(const o2::track::TrackParFwd& namespace o2::quality_control_modules::muon { -MuonTrack::MuonTrack(const o2::mch::TrackMCH* track, const o2::globaltracking::RecoContainer& recoCont) +MuonTrack::MuonTrack(const o2::mch::TrackMCH* track, int trackID, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit) { + mTrackMCH = const_cast(track); + + mTrackIdMCH = trackID; + mChi2OverNDF = track->getChi2OverNDF(); - mIR = getMCHTrackIR(track, recoCont); + mIR = getMCHTrackIR(track, recoCont, firstTForbit); mIRMCH = mIR; + mTime = track->getTimeMUS(); + mTimeMCH = mTime; + + o2::InteractionRecord startIR{ 0, firstTForbit }; + mRofMCH = getMCHTrackROF(mTrackIdMCH, recoCont); + mRofTimeMCH = mRofMCH.getTimeMUS(startIR, 32).first; + mTrackParameters.setZ(track->getZ()); mTrackParameters.setParameters(track->getParameters()); mTrackParametersMCH.setZ(track->getZ()); mTrackParametersMCH.setParameters(track->getParameters()); + mTrackParametersAtMID.setZ(track->getZAtMID()); + mTrackParametersAtMID.setParameters(track->getParametersAtMID()); + + mChi2OverNDFMCH = mTrackMCH->getChi2OverNDF(); + init(); } -MuonTrack::MuonTrack(const TrackMCHMID* track, const o2::globaltracking::RecoContainer& recoCont) +MuonTrack::MuonTrack(const TrackMCHMID* track, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit) { auto tracksMCH = recoCont.getMCHTracks(); auto tracksMID = recoCont.getMIDTracks(); @@ -244,7 +375,6 @@ MuonTrack::MuonTrack(const TrackMCHMID* track, const o2::globaltracking::RecoCon auto iMCH = track->getMCHRef().getIndex(); auto iMID = track->getMIDRef().getIndex(); - // std::cout << fmt::format("iMCH={} ({}) iMID={} ({})", iMCH, tracksMCH.size(), iMID, tracksMID.size()) << std::endl; if (iMCH >= 0 && iMCH >= tracksMCH.size()) { throw std::length_error(fmt::format("[MuonTrackImpl] bad MCH track index: iMCH={} tracksMCH.size()={}", iMCH, tracksMCH.size())); } @@ -255,18 +385,38 @@ MuonTrack::MuonTrack(const TrackMCHMID* track, const o2::globaltracking::RecoCon mTrackIdMCH = iMCH; mTrackIdMID = iMID; + mTrackMCH = const_cast(&(tracksMCH[iMCH])); + mTrackMID = const_cast(&(tracksMID[iMID])); + + mIR = track->getIR(); + auto trackTimeMUS = track->getTimeMUS(InteractionRecord{ 0, firstTForbit }, 128, true); + if (trackTimeMUS.second) { + mTime = trackTimeMUS.first; + } + + auto& trackMCH = tracksMCH[iMCH]; + if (iMCH >= 0) { // mTrackMCH = &(tracksMCH[iMCH]); - mIRMCH = getMCHTrackIR(iMCH, recoCont); + mIRMCH = getMCHTrackIR(iMCH, recoCont, firstTForbit); + mTimeMCH = trackMCH.getTimeMUS(); + + o2::InteractionRecord startIR{ 0, firstTForbit }; + mRofMCH = getMCHTrackROF(mTrackIdMCH, recoCont); + mRofTimeMCH = mRofMCH.getTimeMUS(startIR, 32).first; + + mChi2OverNDFMCH = mTrackMCH->getChi2OverNDF(); } if (iMID >= 0) { // mTrackMID = &(tracksMID[iMID]); mIRMID = getMIDTrackIR(iMID, recoCont); - } + if (trackTimeMUS.second) { + mTimeMID = trackTimeMUS.first; + } - mIR = track->getIR(); + mChi2OverNDFMID = mTrackMID->getChi2OverNDF(); + } - auto& trackMCH = tracksMCH[iMCH]; mChi2OverNDF = trackMCH.getChi2OverNDF(); mTrackParameters.setZ(trackMCH.getZ()); @@ -275,10 +425,13 @@ MuonTrack::MuonTrack(const TrackMCHMID* track, const o2::globaltracking::RecoCon mTrackParametersMCH.setZ(trackMCH.getZ()); mTrackParametersMCH.setParameters(trackMCH.getParameters()); + mTrackParametersAtMID.setZ(trackMCH.getZAtMID()); + mTrackParametersAtMID.setParameters(trackMCH.getParametersAtMID()); + init(); } -MuonTrack::MuonTrack(const GlobalFwdTrack* track, const o2::globaltracking::RecoContainer& recoCont) : mTrackParameters(forwardTrackToMCHTrack(*track)) +MuonTrack::MuonTrack(const GlobalFwdTrack* track, const o2::globaltracking::RecoContainer& recoCont, uint32_t firstTForbit) : mTrackParameters(forwardTrackToMCHTrack(*track)) { auto tracksMFT = recoCont.getMFTTracks(); auto tracksMCH = recoCont.getMCHTracks(); @@ -288,10 +441,6 @@ MuonTrack::MuonTrack(const GlobalFwdTrack* track, const o2::globaltracking::Reco auto iMCH = track->getMCHTrackID(); auto iMID = track->getMIDTrackID(); - // if (iMID >= 0) { - // std::cout << fmt::format("[TOTO] [MuonTrackImpl] iMFT={} ({}) iMCH={} ({}) iMID={} ({})", - // iMFT, tracksMFT.size(), iMCH, tracksMCH.size(), iMID, tracksMID.size()) << std::endl; - // } if (iMFT >= 0 && iMFT >= tracksMFT.size()) { throw std::length_error(fmt::format("[MuonTrack(GlobalFwdTrack)] bad MFT track index: iMFT={} tracksMFT.size()={}", iMFT, tracksMFT.size())); } @@ -302,26 +451,50 @@ MuonTrack::MuonTrack(const GlobalFwdTrack* track, const o2::globaltracking::Reco throw std::length_error(fmt::format("[MuonTrack(GlobalFwdTrack)] bad MID track index: iMID={} tracksMID.size()={}", iMID, tracksMID.size())); } + mMatchInfoFwd = *track; + mTrackIdMFT = iMFT; mTrackIdMCH = iMCH; mTrackIdMID = iMID; if (iMFT >= 0) { + mTrackMFT = const_cast(&(tracksMFT[iMFT])); mIRMFT = getMFTTrackIR(iMFT, recoCont); + mTimeMFT = getMFTTrackTime(iMFT, recoCont, firstTForbit); + mTrackParametersMFT.setZ(tracksMFT[iMFT].getOutParam().getZ()); + mTrackParametersMFT.setParameters(forwardTrackToMCHTrack(tracksMFT[iMFT].getOutParam()).getParameters()); } if (iMCH >= 0) { + mTrackMCH = const_cast(&(tracksMCH[iMCH])); auto& trackMCH = tracksMCH[iMCH]; mTrackParametersMCH.setZ(trackMCH.getZ()); mTrackParametersMCH.setParameters(trackMCH.getParameters()); - mIRMCH = getMCHTrackIR(iMCH, recoCont); + + mTrackParametersAtMID.setZ(trackMCH.getZAtMID()); + mTrackParametersAtMID.setParameters(trackMCH.getParametersAtMID()); + + mIRMCH = getMCHTrackIR(iMCH, recoCont, firstTForbit); + mTimeMCH = getMCHTrackTime(iMCH, recoCont, firstTForbit); + + o2::InteractionRecord startIR{ 0, firstTForbit }; + mRofMCH = getMCHTrackROF(mTrackIdMCH, recoCont); + mRofTimeMCH = mRofMCH.getTimeMUS(startIR, 32).first; + + mChi2OverNDFMCH = mTrackMCH->getChi2OverNDF(); } if (iMID >= 0) { + mTrackMID = const_cast(&(tracksMID[iMID])); mIRMID = getMIDTrackIR(iMID, recoCont); + mTimeMID = getMIDTrackTime(iMID, recoCont, firstTForbit); + + mChi2OverNDFMID = mTrackMID->getChi2OverNDF(); } - mIR = ::getGlobalFwdTrackIR(track, recoCont); + mIR = ::getGlobalFwdTrackIR(track, recoCont, firstTForbit); + mTime = ::getGlobalFwdTrackTime(track, recoCont, firstTForbit); - mChi2OverNDF = track->getTrackChi2(); + // mChi2OverNDF = track->getTrackChi2(); + mChi2OverNDF = mTrackMCH->getChi2OverNDF(); init(); } @@ -333,9 +506,82 @@ void MuonTrack::init() mMuonMomentum = ::getMuonMomentum(mTrackParameters); mMuonMomentumAtVertex = ::getMuonMomentumAtVertex(mTrackParameters); + mMuonMomentumMCH = ::getMuonMomentum(mTrackParametersMCH); + mMuonMomentumAtVertexMCH = ::getMuonMomentumAtVertex(mTrackParametersMCH); + mDCA = ::getDCA(mTrackParameters); - mPDCAMCH = ::getPDCA(mTrackParametersMCH); + mDCAMCH = ::getDCA(mTrackParametersMCH); mRAbs = getRAbsMCH(mTrackParametersMCH); } +bool MuonTrack::extrapToZMFT(o2::mch::TrackParam& trackParam, float z) const +{ + trackParam = mTrackParametersMFT; + return o2::mch::TrackExtrap::extrapToZ(trackParam, z); +} + +bool MuonTrack::extrapToZMCH(o2::mch::TrackParam& trackParam, float z) const +{ + trackParam = mTrackParametersMCH; + return o2::mch::TrackExtrap::extrapToZ(trackParam, z); +} + +bool MuonTrack::extrapToZMID(o2::mch::TrackParam& trackParam, float z) const +{ + trackParam = mTrackParametersMID; + return o2::mch::TrackExtrap::extrapToZ(trackParam, z); +} + +double MuonTrack::getP() const +{ + return mMuonMomentumAtVertex.P(); +} + +double MuonTrack::getPt() const +{ + return mMuonMomentumAtVertex.Pt(); +} + +double MuonTrack::getEta() const +{ + return mMuonMomentumAtVertex.eta(); +} + +double MuonTrack::getPhi() const +{ + return mMuonMomentumAtVertex.phi() * TMath::RadToDeg(); +} + +double MuonTrack::getPMCH() const +{ + return mMuonMomentumAtVertexMCH.P(); +} + +double MuonTrack::getPtMCH() const +{ + return mMuonMomentumAtVertexMCH.Pt(); +} + +double MuonTrack::getEtaMCH() const +{ + return mMuonMomentumAtVertexMCH.eta(); +} + +double MuonTrack::getPhiMCH() const +{ + return mMuonMomentumAtVertexMCH.phi() * TMath::RadToDeg(); +} + +bool MuonTrack::canBeMuon() const +{ + bool inABS = (mRAbs > 17.6) && (mRAbs < 89.5); + bool inHoleMID = (std::abs(getXMid()) < 50) && (std::abs(getYMid()) < 50); + bool outOfMID = (std::abs(getXMid()) > 250) || (std::abs(getYMid()) > 300); + bool inMID = (!inHoleMID) && (!outOfMID); + // return (inABS); + return (inABS && inMID); + // return true; + // return (mRAbs > 17.6 && mRAbs < 89.5 && std::abs(getXMid()) > 50 && std::abs(getXMid()) < 250 && std::abs(getYMid()) > 50 && std::abs(getYMid()) < 300); +} + } // namespace o2::quality_control_modules::muon diff --git a/Modules/MUON/Common/src/TrackPlotter.cxx b/Modules/MUON/Common/src/TrackPlotter.cxx index 5cb2df6392..89a159cb4f 100644 --- a/Modules/MUON/Common/src/TrackPlotter.cxx +++ b/Modules/MUON/Common/src/TrackPlotter.cxx @@ -11,11 +11,17 @@ #include "MUONCommon/TrackPlotter.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include +#include #include #include #include +#include +#include #include #include +#include #include #include #include @@ -32,6 +38,42 @@ static void setXAxisLabels(TProfile* h) } } +template +static void Fill(std::unique_ptr& hist, double x) +{ + if (!hist) { + return; + } + hist->Fill(x); +} + +template +static void Fill(std::unique_ptr& hist, double x, double y) +{ + if (!hist) { + return; + } + hist->Fill(x, y); +} + +template <> +void Fill(std::unique_ptr& hist, double x) +{ + if (!hist) { + return; + } + hist->getNum()->Fill(x); +} + +template <> +void Fill(std::unique_ptr& hist, double x, double y) +{ + if (!hist) { + return; + } + hist->getNum()->Fill(x, y); +} + } // namespace using namespace o2::dataformats; @@ -39,195 +81,413 @@ using namespace o2::dataformats; namespace o2::quality_control_modules::muon { -TrackPlotter::TrackPlotter(int maxTracksPerTF, GID::Source source, std::string path) : mSrc(source), mPath(path) +TrackPlotter::TrackPlotter(int maxTracksPerTF, GID::Source source, std::string path, bool fullHistos) : mSrc(source), + mPath(path), + mFullHistos(fullHistos) { createTrackHistos(maxTracksPerTF); createTrackPairHistos(); } +template <> +std::unique_ptr TrackPlotter::createHisto(const char* name, const char* title, + int nbins, double xmin, double xmax, + bool optional, + bool statBox, + const char* drawOptions, + const char* displayHints) +{ + if (optional && !mFullHistos) { + return nullptr; + } + std::string fullTitle = GID::getSourceName(mSrc) + " " + title; + auto h = std::make_unique(name, fullTitle.c_str(), nbins, xmin, xmax, true); + if (!statBox) { + h->SetStats(0); + } + histograms().emplace_back(HistInfo{ h.get(), drawOptions, displayHints }); + return h; +} + +template <> +std::unique_ptr TrackPlotter::createHisto(const char* name, const char* title, + int nbins, double xmin, double xmax, + int nbinsy, double ymin, double ymax, + bool optional, + bool statBox, + const char* drawOptions, + const char* displayHints) +{ + if (optional && !mFullHistos) { + return nullptr; + } + std::string fullTitle = GID::getSourceName(mSrc) + " " + title; + auto h = std::make_unique(name, fullTitle.c_str(), nbins, xmin, xmax, nbinsy, ymin, ymax, true); + if (!statBox) { + h->SetStats(0); + } + histograms().emplace_back(HistInfo{ h.get(), drawOptions, displayHints }); + return h; +} + void TrackPlotter::createTrackHistos(int maxTracksPerTF) { - mNofTracksPerTF[0] = createHisto(TString::Format("%sPositive/TracksPerTF", mPath.c_str()), "Number of tracks per TimeFrame (+);Number of tracks per TF", maxTracksPerTF, 0, maxTracksPerTF, true, "logy"); - mNofTracksPerTF[1] = createHisto(TString::Format("%sNegative/TracksPerTF", mPath.c_str()), "Number of tracks per TimeFrame (-);Number of tracks per TF", maxTracksPerTF, 0, maxTracksPerTF, true, "logy"); - mNofTracksPerTF[2] = createHisto(TString::Format("%sTracksPerTF", mPath.c_str()), "Number of tracks per TimeFrame;Number of tracks per TF", maxTracksPerTF, 0, maxTracksPerTF, true, "logy"); + mNofTracksPerTF[0] = createHisto(TString::Format("%sPositive/TracksPerTF", mPath.c_str()), "Number of tracks per TimeFrame (+);Number of tracks per TF", maxTracksPerTF, 0, maxTracksPerTF, true, true, "logy"); + mNofTracksPerTF[1] = createHisto(TString::Format("%sNegative/TracksPerTF", mPath.c_str()), "Number of tracks per TimeFrame (-);Number of tracks per TF", maxTracksPerTF, 0, maxTracksPerTF, true, true, "logy"); + mNofTracksPerTF[2] = createHisto(TString::Format("%sTracksPerTF", mPath.c_str()), "Number of tracks per TimeFrame;Number of tracks per TF", maxTracksPerTF, 0, maxTracksPerTF, false, true, "logy"); - mTrackDCA[0] = createHisto(TString::Format("%sPositive/TrackDCA", mPath.c_str()), "Track DCA (+);DCA (cm)", 500, 0, 500); - mTrackDCA[1] = createHisto(TString::Format("%sNegative/TrackDCA", mPath.c_str()), "Track DCA (-);DCA (cm)", 500, 0, 500); - mTrackDCA[2] = createHisto(TString::Format("%sTrackDCA", mPath.c_str()), "Track DCA;DCA (cm)", 500, 0, 500); + mTrackChi2OverNDF[0] = createHisto(TString::Format("%sPositive/TrackMCHChi2OverNDF", mPath.c_str()), "Track #chi^{2}/ndf (MCH +);#chi^{2}/ndf;entries/s", 500, 0, 50, true, false, "hist"); + mTrackChi2OverNDF[1] = createHisto(TString::Format("%sNegative/TrackMCHChi2OverNDF", mPath.c_str()), "Track #chi^{2}/ndf (MCH -);#chi^{2}/ndf;entries/s", 500, 0, 50, true, false, "hist"); + mTrackChi2OverNDF[2] = createHisto(TString::Format("%sTrackMCHChi2OverNDF", mPath.c_str()), "Track #chi^{2}/ndf (MCH);#chi^{2}/ndf;entries/s", 500, 0, 50, false, false, "hist"); - mTrackPDCA[0] = createHisto(TString::Format("%sPositive/TrackPDCA", mPath.c_str()), "Track p#timesDCA (+);p#timesDCA (GeVcm/c)", 5000, 0, 5000); - mTrackPDCA[1] = createHisto(TString::Format("%sNegative/TrackPDCA", mPath.c_str()), "Track p#timesDCA (-);p#timesDCA (GeVcm/c)", 5000, 0, 5000); - mTrackPDCA[2] = createHisto(TString::Format("%sTrackPDCA", mPath.c_str()), "Track p#timesDCA;p#timesDCA (GeVcm/c)", 5000, 0, 5000); + mTrackDCA[0] = createHisto(TString::Format("%sPositive/TrackDCA", mPath.c_str()), "Track DCA (+);DCA (cm);entries/s", 500, 0, 500, true, false, "hist"); + mTrackDCA[1] = createHisto(TString::Format("%sNegative/TrackDCA", mPath.c_str()), "Track DCA (-);DCA (cm);entries/s", 500, 0, 500, true, false, "hist"); + mTrackDCA[2] = createHisto(TString::Format("%sTrackDCA", mPath.c_str()), "Track DCA;DCA (cm);entries/s", 500, 0, 500, false, false, "hist"); - mTrackPt[0] = createHisto(TString::Format("%sPositive/TrackPt", mPath.c_str()), "Track p_{T} (+);p_{T} (GeV/c)", 300, 0, 30, false, "logy"); - mTrackPt[1] = createHisto(TString::Format("%sNegative/TrackPt", mPath.c_str()), "Track p_{T} (-);p_{T} (GeV/c)", 300, 0, 30, false, "logy"); - mTrackPt[2] = createHisto(TString::Format("%sTrackPt", mPath.c_str()), "Track p_{T};p_{T} (GeV/c)", 300, 0, 30, false, "logy"); + mTrackPDCA[0] = createHisto(TString::Format("%sPositive/TrackPDCA", mPath.c_str()), "Track p#timesDCA (+);p#timesDCA (GeVcm/c);entries/s", 5000, 0, 5000, true, false, "hist"); + mTrackPDCA[1] = createHisto(TString::Format("%sNegative/TrackPDCA", mPath.c_str()), "Track p#timesDCA (-);p#timesDCA (GeVcm/c);entries/s", 5000, 0, 5000, true, false, "hist"); + mTrackPDCA[2] = createHisto(TString::Format("%sTrackPDCA", mPath.c_str()), "Track p#timesDCA;p#timesDCA (GeVcm/c);entries/s", 5000, 0, 5000, false, false, "hist"); - mTrackEta[0] = createHisto(TString::Format("%sPositive/TrackEta", mPath.c_str()), "Track #eta (+);#eta", 200, -4.5, -2); - mTrackEta[1] = createHisto(TString::Format("%sNegative/TrackEta", mPath.c_str()), "Track #eta (-);#eta", 200, -4.5, -2); - mTrackEta[2] = createHisto(TString::Format("%sTrackEta", mPath.c_str()), "Track #eta;#eta", 200, -4.5, -2); + mTrackPt[0] = createHisto(TString::Format("%sPositive/TrackPt", mPath.c_str()), "Track p_{T} (+);p_{T} (GeV/c);entries/s", 300, 0, 30, true, false, "hist logy"); + mTrackPt[1] = createHisto(TString::Format("%sNegative/TrackPt", mPath.c_str()), "Track p_{T} (-);p_{T} (GeV/c);entries/s", 300, 0, 30, true, false, "hist logy"); + mTrackPt[2] = createHisto(TString::Format("%sTrackPt", mPath.c_str()), "Track p_{T};p_{T} (GeV/c);entries/s", 300, 0, 30, false, false, "hist logy"); - mTrackPhi[0] = createHisto(TString::Format("%sPositive/TrackPhi", mPath.c_str()), "Track #phi (+);#phi (deg)", 360, 0, 360); - mTrackPhi[1] = createHisto(TString::Format("%sNegative/TrackPhi", mPath.c_str()), "Track #phi (-);#phi (deg)", 360, 0, 360); - mTrackPhi[2] = createHisto(TString::Format("%sTrackPhi", mPath.c_str()), "Track #phi;#phi (deg)", 360, 0, 360); + mTrackQOverPt = createHisto(TString::Format("%sTrackQOverPt", mPath.c_str()), "Track q/p_{T};q/p_{T} (GeV/c)^{-1};entries/s", 200, -10, 10, false, false, "hist logy"); - mTrackRAbs[0] = createHisto(TString::Format("%sPositive/TrackRAbs", mPath.c_str()), "Track R_{abs} (+);R_{abs} (cm)", 1000, 0, 100); - mTrackRAbs[1] = createHisto(TString::Format("%sNegative/TrackRAbs", mPath.c_str()), "Track R_{abs} (-);R_{abs} (cm)", 1000, 0, 100); - mTrackRAbs[2] = createHisto(TString::Format("%sTrackRAbs", mPath.c_str()), "Track R_{abs};R_{abs} (cm)", 1000, 0, 100); + mTrackEta[0] = createHisto(TString::Format("%sPositive/TrackEta", mPath.c_str()), "Track #eta (+);#eta;entries/s", 200, -4.5, -2, true, false, "hist"); + mTrackEta[1] = createHisto(TString::Format("%sNegative/TrackEta", mPath.c_str()), "Track #eta (-);#eta;entries/s", 200, -4.5, -2, true, false, "hist"); + mTrackEta[2] = createHisto(TString::Format("%sTrackEta", mPath.c_str()), "Track #eta;#eta;entries/s", 200, -4.5, -2, false, false, "hist"); - mTrackBC = createHisto(TString::Format("%sTrackBC", mPath.c_str()), "Track BC;BC", o2::constants::lhc::LHCMaxBunches, 0, o2::constants::lhc::LHCMaxBunches); - mTrackBCWidth = createHisto(TString::Format("%sTrackBCWidth", mPath.c_str()), "Track BCWidth;BC Width", 400, 0, 400); + mTrackPhi[0] = createHisto(TString::Format("%sPositive/TrackPhi", mPath.c_str()), "Track #phi (+);#phi (deg);entries/s", 360, -180, 180, true, false, "hist"); + mTrackPhi[1] = createHisto(TString::Format("%sNegative/TrackPhi", mPath.c_str()), "Track #phi (-);#phi (deg);entries/s", 360, -180, 180, true, false, "hist"); + mTrackPhi[2] = createHisto(TString::Format("%sTrackPhi", mPath.c_str()), "Track #phi;#phi (deg);entries/s", 360, -180, 180, false, false, "hist"); - if (mSrc == GID::MFTMCHMID) { - mTrackDT = std::make_unique(TString::Format("%sTrackDT", mPath.c_str()), "Track Time Correlation (MID-MCH vs MFT-MCH);BC;BC", 1000, -500, 500, 1000, -500, 500); - histograms().emplace_back(HistInfo{ mTrackDT.get(), "col", "logz" }); - } else { - std::string titleStr; - if (mSrc == GID::MFTMCH) { - titleStr = "(MFT-MCH)"; - } - if (mSrc == GID::MCHMID) { - titleStr = "(MID-MCH)"; - } - mTrackDT = std::make_unique(TString::Format("%sTrackDT", mPath.c_str()), - TString::Format("Track Time Correlation %s;BC", titleStr.c_str()), - 2000, -1000, 1000); - histograms().emplace_back(HistInfo{ mTrackDT.get(), "hist", "logy" }); + mTrackRAbs[0] = createHisto(TString::Format("%sPositive/TrackRAbs", mPath.c_str()), "Track R_{abs} (+);R_{abs} (cm);entries/s", 1000, 0, 100, true, false, "hist"); + mTrackRAbs[1] = createHisto(TString::Format("%sNegative/TrackRAbs", mPath.c_str()), "Track R_{abs} (-);R_{abs} (cm);entries/s", 1000, 0, 100, true, false, "hist"); + mTrackRAbs[2] = createHisto(TString::Format("%sTrackRAbs", mPath.c_str()), "Track R_{abs};R_{abs} (cm);entries/s", 1000, 0, 100, false, false, "hist"); + + mTrackEtaPhi[0] = createHisto(TString::Format("%sPositive/TrackEtaPhi", mPath.c_str()), "Track #phi vs #eta (+);#eta;#phi", 50, -4.5, -2, 40, -180, 180, true, false, "colz"); + mTrackEtaPhi[1] = createHisto(TString::Format("%sNegative/TrackEtaPhi", mPath.c_str()), "Track #phi vs #eta (-);#eta;#phi", 50, -4.5, -2, 40, -180, 180, true, false, "colz"); + mTrackEtaPhi[2] = createHisto(TString::Format("%sTrackEtaPhi", mPath.c_str()), "Track #phi vs #eta;#eta;#phi", 50, -4.5, -2, 40, -180, 180, false, false, "colz"); + + mTrackEtaPt[0] = createHisto(TString::Format("%sPositive/TrackEtaPt", mPath.c_str()), "Track p_{T} vs #eta (+);#eta;p_{T} (GeV/c)", 50, -4.5, -2, 50, 0, 30, true, false, "colz"); + mTrackEtaPt[1] = createHisto(TString::Format("%sNegative/TrackEtaPt", mPath.c_str()), "Track p_{T} vs #eta (-);#eta;p_{T} (GeV/c)", 50, -4.5, -2, 50, 0, 30, true, false, "colz"); + mTrackEtaPt[2] = createHisto(TString::Format("%sTrackEtaPt", mPath.c_str()), "Track p_{T} vs #eta;#eta;p_{T} (GeV/c)", 50, -4.5, -2, 50, 0, 30, false, false, "colz"); + + mTrackPhiPt[0] = createHisto(TString::Format("%sPositive/TrackPhiPt", mPath.c_str()), "Track p_{T} vs #phi (+);#phi;p_{T} (GeV/c)", 40, -180, 180, 50, 0, 30, true, false, "colz"); + mTrackPhiPt[1] = createHisto(TString::Format("%sNegative/TrackPhiPt", mPath.c_str()), "Track p_{T} vs #phi (-);#phi;p_{T} (GeV/c)", 40, -180, 180, 50, 0, 30, true, false, "colz"); + mTrackPhiPt[2] = createHisto(TString::Format("%sTrackPhiPt", mPath.c_str()), "Track p_{T} vs #phi;#phi;p_{T} (GeV/c)", 40, -180, 180, 50, 0, 30, false, false, "colz"); + + mTrackBC = createHisto(TString::Format("%sTrackBC", mPath.c_str()), "Track BC;BC;entries/s", o2::constants::lhc::LHCMaxBunches, 0, o2::constants::lhc::LHCMaxBunches, false, false, "hist"); + + if (mSrc == GID::MFTMCH || mSrc == GID::MFTMCHMID) { + mMatchScoreMFTMCH = createHisto(TString::Format("%sMatchScoreMFTMCH", mPath.c_str()), "Match Score MFT-MCH;score", 1000, 0, 100, false, false, "hist"); + mMatchChi2MFTMCH = createHisto(TString::Format("%sMatchChi2MFTMCH", mPath.c_str()), "Match #chi^{2} MFT-MCH;#chi^{2}", 1000, 0, 100, false, false, "hist"); + mMatchNMFTCandidates = createHisto(TString::Format("%sMatchNMFTCandidates", mPath.c_str()), "MFT Candidates;candidates", 1000, 0, 1000, false, false, "hist"); + + mTrackEtaCorr[0] = createHisto(TString::Format("%sPositive/TrackEtaCorr", mPath.c_str()), "Track #eta - GLO vs MCH (+);#eta^{MCH};#eta^{GLO}", 50, -4.5, -2, 50, -4.5, -2, true, false, "colz"); + mTrackEtaCorr[1] = createHisto(TString::Format("%sNegative/TrackEtaCorr", mPath.c_str()), "Track #eta - GLO vs MCH (-);#eta^{MCH};#eta^{GLO}", 50, -4.5, -2, 50, -4.5, -2, true, false, "colz"); + mTrackEtaCorr[2] = createHisto(TString::Format("%sTrackEtaCorr", mPath.c_str()), "Track #eta - GLO vs MCH;#eta^{MCH};#eta^{GLO}", 50, -4.5, -2, 50, -4.5, -2, false, false, "colz"); + + mTrackDEtaVsEta[0] = createHisto(TString::Format("%sPositive/TrackDEtaVsEta", mPath.c_str()), "Track #eta^{GLO}-#eta^{MCH} vs #eta^{MCH} (+);#eta^{MCH};#eta^{GLO}-#eta^{MCH}", 50, -4.5, -2, 200, -1, 1, true, false, "colz"); + mTrackDEtaVsEta[1] = createHisto(TString::Format("%sNegative/TrackDEtaVsEta", mPath.c_str()), "Track #eta^{GLO}-#eta^{MCH} vs #eta^{MCH} (-);#eta^{MCH};#eta^{GLO}-#eta^{MCH}", 50, -4.5, -2, 200, -1, 1, true, false, "colz"); + mTrackDEtaVsEta[2] = createHisto(TString::Format("%sTrackDEtaVsEta", mPath.c_str()), "Track #eta^{GLO}-#eta^{MCH} vs #eta^{MCH};#eta^{MCH};#eta^{GLO}-#eta^{MCH}", 50, -4.5, -2, 200, -1, 1, false, false, "colz"); + + mTrackPhiCorr[0] = createHisto(TString::Format("%sPositive/TrackPhiCorr", mPath.c_str()), "Track #phi - GLO vs MCH (+);#phi^{MCH};#phi^{GLO}", 40, -180, 180, 40, -180, 180, true, false, "colz"); + mTrackPhiCorr[1] = createHisto(TString::Format("%sNegative/TrackPhiCorr", mPath.c_str()), "Track #phi - GLO vs MCH (-);#phi^{MCH};#phi^{GLO}", 40, -180, 180, 40, -180, 180, true, false, "colz"); + mTrackPhiCorr[2] = createHisto(TString::Format("%sTrackPhiCorr", mPath.c_str()), "Track #phi - GLO vs MCH;#phi^{MCH};#phi^{GLO}", 40, -180, 180, 40, -180, 180, false, false, "colz"); + + mTrackDPhiVsPhi[0] = createHisto(TString::Format("%sPositive/TrackDPhiVsPhi", mPath.c_str()), "Track #phi^{GLO}-#phi^{MCH} vs #phi^{MCH} (+);#phi^{MCH};#phi^{GLO}-#phi^{MCH}", 40, -180, 180, 200, -100, 100, true, false, "colz"); + mTrackDPhiVsPhi[1] = createHisto(TString::Format("%sNegative/TrackDPhiVsPhi", mPath.c_str()), "Track #phi^{GLO}-#phi^{MCH} vs #phi^{MCH} (-);#phi^{MCH};#phi^{GLO}-#phi^{MCH}", 40, -180, 180, 200, -100, 100, true, false, "colz"); + mTrackDPhiVsPhi[2] = createHisto(TString::Format("%sTrackDPhiVsPhi", mPath.c_str()), "Track #phi^{GLO}-#phi^{MCH} vs #phi^{MCH};#phi^{MCH};#phi^{GLO}-#phi^{MCH}", 40, -180, 180, 200, -100, 100, false, false, "colz"); + + mTrackPtCorr[0] = createHisto(TString::Format("%sPositive/TrackPtCorr", mPath.c_str()), "Track p_{T} - GLO vs MCH (+);p_{T}^{MCH};p_{T}^{GLO}", 50, 0, 30, 50, 0, 30, true, false, "colz"); + mTrackPtCorr[1] = createHisto(TString::Format("%sNegative/TrackPtCorr", mPath.c_str()), "Track p_{T} - GLO vs MCH (-);p_{T}^{MCH};p_{T}^{GLO}", 50, 0, 30, 50, 0, 30, true, false, "colz"); + mTrackPtCorr[2] = createHisto(TString::Format("%sTrackPtCorr", mPath.c_str()), "Track p_{T} - GLO vs MCH;p_{T}^{MCH};p_{T}^{GLO}", 50, 0, 30, 50, 0, 30, false, false, "colz"); + + mTrackDPtVsPt[0] = createHisto(TString::Format("%sPositive/TrackDPtVsPt", mPath.c_str()), "Track p_{T}^{GLO}-p_{T}^{MCH} vs p_{T}^{MCH} (+);p_{T}^{MCH};p_{T}^{GLO}-p_{T}^{MCH}", 50, 0, 30, 200, -10, 10, true, false, "colz"); + mTrackDPtVsPt[1] = createHisto(TString::Format("%sNegative/TrackDPtVsPt", mPath.c_str()), "Track p_{T}^{GLO}-p_{T}^{MCH} vs p_{T}^{MCH} (-);p_{T}^{MCH};p_{T}^{GLO}-p_{T}^{MCH}", 50, 0, 30, 200, -10, 10, true, false, "colz"); + mTrackDPtVsPt[2] = createHisto(TString::Format("%sTrackDPtVsPt", mPath.c_str()), "Track p_{T}^{GLO}-p_{T}^{MCH} vs p_{T}^{MCH};p_{T}^{MCH};p_{T}^{GLO}-p_{T}^{MCH}", 50, 0, 30, 200, -10, 10, false, false, "colz"); + } + + if (mSrc == GID::MCHMID || mSrc == GID::MFTMCHMID) { + mMatchChi2MCHMID = createHisto(TString::Format("%sMatchChi2MCHMID", mPath.c_str()), "Match #chi^{2} MCH-MID;#chi^{2}", 1000, 0, 100, false, true, "hist"); + mTrackDT = createHisto(TString::Format("%sTrackDT", mPath.c_str()), "MCH-MID time correlation;ns", 4000, -500, 500, false, true, "hist"); } + + mTrackPosAtMFT = createHisto(TString::Format("%sTrackPosAtMFT", mPath.c_str()), "MCH Track position at MFT exit;X (cm);Y (cm)", 100, -50, 50, 100, -50, 50, false, false, "colz"); + mTrackPosAtMID = createHisto(TString::Format("%sTrackPosAtMID", mPath.c_str()), "MCH Track position at MID entrance;X (cm);Y (cm)", 80, -400, 400, 80, -400, 400, false, false, "colz"); } void TrackPlotter::createTrackPairHistos() { - mMinv = createHisto(TString::Format("%sMinv", mPath.c_str()), "#mu^{+}#mu^{-} invariant mass;M_{#mu^{+}#mu^{-}} (GeV/c^{2})", 300, 0, 6); + mMinvFull = createHisto(TString::Format("%sMinvFull", mPath.c_str()), "#mu^{+}#mu^{-} invariant mass;M_{#mu^{+}#mu^{-}} (GeV/c^{2})", 5000, 0, 100, false, true, "hist"); + mMinv = createHisto(TString::Format("%sMinv", mPath.c_str()), "#mu^{+}#mu^{-} invariant mass;M_{#mu^{+}#mu^{-}} (GeV/c^{2})", 200, 1, 5, false, true, "hist"); + mMinvBgd = createHisto(TString::Format("%sMinvBgd", mPath.c_str()), "#mu^{+}#mu^{-} inv. mass background;M_{#mu^{+}#mu^{-}} (GeV/c^{2})", 200, 1, 5, true, true, "hist"); + mDimuonDT = createHisto(TString::Format("%sDimuonTimeDiff", mPath.c_str()), "#mu^{+}#mu^{-} time difference;ns", 4000, -2000, 2000, false, true, "hist"); } -void TrackPlotter::fillTrackPairHistos(gsl::span tracks) +void TrackPlotter::normalizePlot(TH1* hist) +{ + static constexpr double sOrbitLengthInSeconds = o2::constants::lhc::LHCOrbitMUS / 1000000; + + TH1DRatio* h1 = dynamic_cast(hist); + if (h1) { + h1->getDen()->Fill((Double_t)0, sOrbitLengthInSeconds * mNOrbitsPerTF); + } else { + TH2DRatio* h2 = dynamic_cast(hist); + if (h2) { + h2->getDen()->Fill((Double_t)0, (Double_t)0, sOrbitLengthInSeconds * mNOrbitsPerTF); + } + } +} + +void TrackPlotter::fillTrackPairHistos(gsl::span> tracks) { if (tracks.size() > 1) { for (auto i = 0; i < tracks.size(); i++) { - auto ti = tracks[i].getMuonMomentumAtVertex(); + if (!(tracks[i].second)) { + continue; + } + const MuonTrack& ti = tracks[i].first; + auto pi = ti.getMuonMomentumAtVertex(); + for (auto j = i + 1; j < tracks.size(); j++) { - if (tracks[i].getSign() == tracks[j].getSign()) { + if (!(tracks[j].second)) { continue; } - auto dt = tracks[j].getIR().differenceInBCNS(tracks[i].getIR()); - if (std::abs(dt) > 1000) { + const MuonTrack& tj = tracks[j].first; + + if (ti.getSign() == tj.getSign()) { continue; } - auto tj = tracks[j].getMuonMomentumAtVertex(); - auto p = ti + tj; - mMinv->Fill(p.M()); + + auto dt = (ti.getIR() - tj.getIR()).bc2ns(); + auto dtMUS = ti.getTime().getTimeStamp() - tj.getTime().getTimeStamp(); + Fill(mDimuonDT, dtMUS * 1000); + + bool diMuonOK = true; + for (auto& cut : mDiMuonCuts) { + if (!cut(ti, tj)) { + diMuonOK = false; + break; + } + } + // tracks are considered to be correlated if they are closer than 1 us in time + auto pj = tj.getMuonMomentumAtVertex(); + auto p = pi + pj; + if (diMuonOK) { + Fill(mMinv, p.M()); + Fill(mMinvFull, p.M()); + } + // the shape of the combinatorial background is derived by combining tracks + // than belong to different orbits (more than 90 us apart) + if (std::abs(dtMUS) > 1) { + Fill(mMinvBgd, p.M()); + } } } } } -bool TrackPlotter::fillTrackHistos(const MuonTrack& track) +void TrackPlotter::fillTrackHistos(const MuonTrack& track) { int q = (track.getSign() < 0) ? 1 : 0; - mTrackBC->Fill(track.getIR().bc); + Fill(mTrackBC, track.getIR().bc); + + auto dtMUS = track.getTimeMID().getTimeStamp() - track.getTimeMCH().getTimeStamp(); + Fill(mTrackDT, dtMUS * 1000); switch (mSrc) { case GID::MCHMID: { - auto dt = track.getIRMID().toLong() - track.getIRMCH().toLong(); - mTrackDT->Fill(dt); + Fill(mMatchChi2MCHMID, track.getMatchInfoFwd().getMIDMatchingChi2()); break; } case GID::MFTMCH: { - auto dt = track.getIRMFT().toLong() - track.getIRMCH().toLong(); - mTrackDT->Fill(dt); + Fill(mMatchScoreMFTMCH, track.getMatchInfoFwd().getMFTMCHMatchingScore()); + Fill(mMatchChi2MFTMCH, track.getMatchInfoFwd().getMFTMCHMatchingChi2()); + Fill(mMatchNMFTCandidates, track.getMatchInfoFwd().getNMFTCandidates()); break; } case GID::MFTMCHMID: { - auto dt1 = track.getIRMFT().toLong() - track.getIRMCH().toLong(); - auto dt2 = track.getIRMID().toLong() - track.getIRMCH().toLong(); - auto* htemp = dynamic_cast(mTrackDT.get()); - if (htemp) { - htemp->Fill(dt1, dt2); - } + Fill(mMatchScoreMFTMCH, track.getMatchInfoFwd().getMFTMCHMatchingScore()); + Fill(mMatchChi2MFTMCH, track.getMatchInfoFwd().getMFTMCHMatchingChi2()); + Fill(mMatchChi2MCHMID, track.getMatchInfoFwd().getMIDMatchingChi2()); + Fill(mMatchNMFTCandidates, track.getMatchInfoFwd().getNMFTCandidates()); break; } default: break; } + double chi2 = track.getChi2OverNDF(); + Fill(mTrackChi2OverNDF[q], chi2); + Fill(mTrackChi2OverNDF[2], chi2); + double dca = track.getDCA(); - mTrackDCA[q]->Fill(dca); - mTrackDCA[2]->Fill(dca); + Fill(mTrackDCA[q], dca); + Fill(mTrackDCA[2], dca); double pdca = track.getPDCAMCH(); - mTrackPDCA[q]->Fill(pdca); - mTrackPDCA[2]->Fill(pdca); - - auto muon = track.getMuonMomentumAtVertex(); - - mTrackEta[q]->Fill(muon.eta()); - mTrackEta[2]->Fill(muon.eta()); - mTrackPhi[q]->Fill(muon.phi() * TMath::RadToDeg() + 180); - mTrackPhi[2]->Fill(muon.phi() * TMath::RadToDeg() + 180); - mTrackPt[q]->Fill(muon.pt()); - mTrackPt[2]->Fill(muon.pt()); + Fill(mTrackPDCA[q], pdca); + Fill(mTrackPDCA[2], pdca); + + double eta = track.getEta(); + double etaMCH = track.hasMCH() ? track.getEtaMCH() : 0; + Fill(mTrackEta[q], eta); + Fill(mTrackEta[2], eta); + Fill(mTrackEtaCorr[q], etaMCH, eta); + Fill(mTrackEtaCorr[2], etaMCH, eta); + Fill(mTrackDEtaVsEta[q], etaMCH, eta - etaMCH); + Fill(mTrackDEtaVsEta[2], etaMCH, eta - etaMCH); + + double phi = track.getPhi(); + double phiMCH = track.hasMCH() ? track.getPhiMCH() : 0; + Fill(mTrackPhi[q], phi); + Fill(mTrackPhi[2], phi); + Fill(mTrackPhiCorr[q], phiMCH, phi); + Fill(mTrackPhiCorr[2], phiMCH, phi); + Fill(mTrackDPhiVsPhi[q], phiMCH, phi - phiMCH); + Fill(mTrackDPhiVsPhi[2], phiMCH, phi - phiMCH); + + Fill(mTrackEtaPhi[q], eta, phi); + Fill(mTrackEtaPhi[2], eta, phi); + + double pt = track.getPt(); + double ptMCH = track.hasMCH() ? track.getPtMCH() : 0; + Fill(mTrackPt[q], pt); + Fill(mTrackPt[2], pt); + Fill(mTrackPtCorr[q], ptMCH, pt); + Fill(mTrackPtCorr[2], ptMCH, pt); + Fill(mTrackDPtVsPt[q], ptMCH, pt - ptMCH); + Fill(mTrackDPtVsPt[2], ptMCH, pt - ptMCH); + + Fill(mTrackEtaPt[q], eta, pt); + Fill(mTrackEtaPt[2], eta, pt); + + Fill(mTrackPhiPt[q], phi, pt); + Fill(mTrackPhiPt[2], phi, pt); + + if (track.getSign() != 0 && pt != 0) { + double qOverPt = track.getSign() / pt; + Fill(mTrackQOverPt, qOverPt); + } auto rAbs = track.getRAbs(); - mTrackRAbs[q]->Fill(rAbs); - mTrackRAbs[2]->Fill(rAbs); + Fill(mTrackRAbs[q], rAbs); + Fill(mTrackRAbs[2], rAbs); + + o2::mch::TrackParam trackParamAtMFT; + float zMFT = sLastMFTPlaneZ; + track.extrapToZMCH(trackParamAtMFT, zMFT); + double xMCH = trackParamAtMFT.getNonBendingCoor(); + double yMCH = trackParamAtMFT.getBendingCoor(); + Fill(mTrackPosAtMFT, trackParamAtMFT.getNonBendingCoor(), trackParamAtMFT.getBendingCoor()); - return true; + Fill(mTrackPosAtMID, track.getXMid(), track.getYMid()); } void TrackPlotter::fillHistograms(const o2::globaltracking::RecoContainer& recoCont) { - std::vector muonTracks; + static bool sFirst = true; + + if (sFirst) { + o2::mch::TrackExtrap::setField(); + sFirst = false; + } + + if (mNOrbitsPerTF < 0) { + mNOrbitsPerTF = o2::base::GRPGeomHelper::instance().getNHBFPerTF(); + } + + mMuonTracks.clear(); + if (mSrc == GID::MCH) { auto tracksMCH = recoCont.getMCHTracks(); + int trackID = 0; for (auto& t : tracksMCH) { - muonTracks.emplace_back(&t, recoCont); + mMuonTracks.emplace_back(std::make_pair({ &t, trackID, recoCont, mFirstTForbit }, true)); + trackID += 1; } } if (mSrc == GID::MFTMCH || mSrc == GID::MFTMCHMID) { auto tracksFwd = recoCont.getGlobalFwdTracks(); for (auto& t : tracksFwd) { - MuonTrack mt(&t, recoCont); + MuonTrack mt(&t, recoCont, mFirstTForbit); // skip tracks without MID if full matching is requested if (mSrc == GID::MFTMCHMID && !mt.hasMID()) { continue; } - muonTracks.emplace_back(&t, recoCont); + mMuonTracks.emplace_back(std::make_pair({ &t, recoCont, mFirstTForbit }, true)); } } if (mSrc == GID::MCHMID) { auto tracksMCHMID = recoCont.getMCHMIDMatches(); for (auto& t : tracksMCHMID) { - muonTracks.emplace_back(&t, recoCont); + mMuonTracks.emplace_back(std::make_pair({ &t, recoCont, mFirstTForbit }, true)); } } int nPos{ 0 }; int nNeg{ 0 }; + int nTot{ 0 }; + + for (auto& t : mMuonTracks) { + bool ok = true; + for (auto& cut : mMuonCuts) { + if (!cut(t.first)) { + ok = false; + break; + } + } + t.second = ok; + if (!t.second) { + continue; + } - for (auto& t : muonTracks) { - if (t.getSign() < 0) { + nTot += 1; + if (t.first.getSign() < 0) { nNeg += 1; } else { nPos += 1; } } - mNofTracksPerTF[0]->Fill(nPos); - mNofTracksPerTF[1]->Fill(nNeg); - mNofTracksPerTF[2]->Fill(muonTracks.size()); + Fill(mNofTracksPerTF[0], nPos); + Fill(mNofTracksPerTF[1], nNeg); + Fill(mNofTracksPerTF[2], nTot); - decltype(muonTracks.size()) nok{ 0 }; + for (const auto& mt : mMuonTracks) { + if (!mt.second) { + continue; + } + fillTrackHistos(mt.first); + } - for (const auto& mt : muonTracks) { - bool ok = fillTrackHistos(mt); - if (ok) { - ++nok; + fillTrackPairHistos(mMuonTracks); + + for (auto hinfo : histograms()) { + TH1* h1 = dynamic_cast(hinfo.object); + if (h1) { + normalizePlot(h1); } } +} - fillTrackPairHistos(muonTracks); +void TrackPlotter::endOfCycle() +{ + for (auto hinfo : histograms()) { + TH1DRatio* h1 = dynamic_cast(hinfo.object); + if (h1) { + h1->update(); + } else { + TH2DRatio* h2 = dynamic_cast(hinfo.object); + if (h2) { + h2->update(); + } + } + } } } // namespace o2::quality_control_modules::muon diff --git a/Modules/MUON/Common/src/TracksPostProcessing.cxx b/Modules/MUON/Common/src/TracksPostProcessing.cxx new file mode 100644 index 0000000000..acd7c1ca7b --- /dev/null +++ b/Modules/MUON/Common/src/TracksPostProcessing.cxx @@ -0,0 +1,221 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file TracksPostProcessing.cxx +/// \author Andrea Ferrero andrea.ferrero@cern.ch +/// \brief Post-processing of the MUON tracks +/// + +#include "MUONCommon/TracksPostProcessing.h" + +#include "QualityControl/QcInfoLogger.h" +#include "QualityControl/DatabaseInterface.h" +#include "QualityControl/CcdbDatabase.h" +#include "QualityControl/ObjectMetadataKeys.h" +#include "QualityControl/ActivityHelpers.h" + +#include +#include +#include +#include + +using namespace o2::quality_control_modules::muon; +using namespace o2::quality_control::repository; + +//_________________________________________________________________________________________ +// Helper function for retrieving a MonitorObject from the QCDB, in the form of a std::pair, bool> +// A non-null MO is returned in the first element of the pair if the MO is found in the QCDB +// The second element of the pair is set to true if the MO has a time stamp more recent than the last retrieved one + +static std::pair, bool> getMO(repository::DatabaseInterface& qcdb, std::string path, std::string name, Trigger t, uint64_t& timeStamp, int maxShiftMs = 1000 * 600) +{ + auto ts = t.timestamp; + const auto objFullPath = t.activity.mProvenance + "/" + path + "/" + name; + const auto filterMetadata = activity_helpers::asDatabaseMetadata(t.activity, false); + const auto objectValidity = qcdb.getLatestObjectValidity(objFullPath, filterMetadata); + if (objectValidity.isValid() && t.timestamp >= objectValidity.getMin() - maxShiftMs && t.timestamp <= objectValidity.getMax() + maxShiftMs) { + ts = objectValidity.getMax() - 1; + } else { + ILOG(Warning, Devel) << "Could not find an object '" << objFullPath << "' in the proximity of timestamp " + << t.timestamp << " with max shift of " << maxShiftMs << "ms" << ENDM; + return { nullptr, false }; + } + + // retrieve MO from CCDB + auto mo = qcdb.retrieveMO(path, name, ts, t.activity); + if (!mo) { + return { nullptr, false }; + } + // get the MO creation time stamp + long newTimeStamp{ 0 }; + auto iter = mo->getMetadataMap().find(metadata_keys::created); + if (iter != mo->getMetadataMap().end()) { + newTimeStamp = std::stol(iter->second); + } + // check if the object is newer than the last visited one + if (newTimeStamp <= timeStamp) { + return { mo, false }; + } + + // update the time stamp of the last visited object + timeStamp = newTimeStamp; + + // check if the object is not older than a given number of milliseconds + long elapsed = static_cast(t.timestamp) - ts; + if (elapsed > maxShiftMs) { + return { mo, false }; + } + + return { mo, true }; +} + +template +T* getPlotFromMO(std::shared_ptr mo) +{ + // Get ROOT object + TObject* obj = mo ? mo->getObject() : nullptr; + if (!obj) { + return nullptr; + } + + // Get histogram object + T* h = dynamic_cast(obj); + return h; +} + +template +MatchingEfficiencyPlotter::MatchingEfficiencyPlotter(std::string pathMatched, std::string pathMCH, std::string path, std::string plotName, int rebin) + : MatchingEfficiencyPlotterInterface(), mRebin(rebin) +{ + mPlotPath[0] = pathMCH; + mPlotName[0] = plotName; + mPlotPath[1] = pathMatched; + mPlotName[1] = plotName; + + mTimestamp[0] = 0; + mTimestamp[1] = 0; + + mName = path + "/" + mPlotName[1]; +} + +template +void MatchingEfficiencyPlotter::update(repository::DatabaseInterface& qcdb, Trigger t, std::shared_ptr objectsManager) +{ + std::string pathMCH = mPlotPath[0]; + auto moMCH = getMO(qcdb, pathMCH, mPlotName[0], t, mTimestamp[0]); + std::string pathMatched = mPlotPath[1]; + auto moMatched = getMO(qcdb, pathMatched, mPlotName[1], t, mTimestamp[1]); + // check if both MOs are existing and updated + if (!moMCH.second || !moMatched.second) { + return; + } + + auto hMCH = getPlotFromMO(moMCH.first); + auto hMatched = getPlotFromMO(moMatched.first); + // check if both plots are valid + if (!hMCH || !hMatched) { + return; + } + + TString name = mName.c_str(); + auto title = TString::Format("%s - matching eff.", hMatched->GetTitle()); + + if (!mHistMatchingEff) { + HIST* h = dynamic_cast(hMatched->Clone()); + if (!h) { + return; + } + h->Rebin(mRebin); + mHistMatchingEff.reset(h); + mHistMatchingEff->Sumw2(); + mHistMatchingEff->SetStats(0); + mHistMatchingEff->SetNameTitle(name, title); + mHistMatchingEff->SetMarkerSize(0.25); + mHistMatchingEff->SetLineColor(kBlack); + std::string option; + if (mHistMatchingEff->InheritsFrom(TH2::Class())) { + option = "colz"; + } else { + option = "PE"; + } + histograms().emplace_back(HistInfo{ mHistMatchingEff.get(), option, "" }); + publish(objectsManager, histograms().back()); + } + + if (mRebin != 1) { + HIST* h1 = dynamic_cast(hMatched->Clone()); + HIST* h2 = dynamic_cast(hMCH->Clone()); + h1->Rebin(mRebin); + h2->Rebin(mRebin); + mHistMatchingEff->Divide(h1, h2); + delete h1; + delete h2; + } else { + mHistMatchingEff->Divide(hMatched, hMCH); + } + mHistMatchingEff->SetNameTitle(name, title); +} + +//_________________________________________________________________________________________ + +void TracksPostProcessing::createTrackHistos() +{ + for (auto& dataSource : mConfig->dataSources) { + auto pathMatched = dataSource.plotsPath; + auto pathRef = dataSource.refsPath; + auto path = dataSource.outputPath; + mMatchingEfficiencyPlotters.emplace_back(std::make_unique>(dataSource.plotsPath, dataSource.refsPath, dataSource.outputPath, dataSource.name, dataSource.rebin)); + } + + for (auto& plot : mMatchingEfficiencyPlotters) { + plot->publish(getObjectsManager()); + } +} + +//_________________________________________________________________________________________ + +void TracksPostProcessing::configure(const boost::property_tree::ptree& config) +{ + mConfig = std::make_unique(getID(), config); + + createTrackHistos(); +} + +//_________________________________________________________________________________________ + +void TracksPostProcessing::initialize(Trigger, framework::ServiceRegistryRef) +{ +} + +//_________________________________________________________________________________________ + +void TracksPostProcessing::updateTrackHistos(Trigger t, repository::DatabaseInterface* qcdb) +{ + for (auto& plot : mMatchingEfficiencyPlotters) { + plot->update(*qcdb, t, getObjectsManager()); + } +} + +//_________________________________________________________________________________________ + +void TracksPostProcessing::update(Trigger t, framework::ServiceRegistryRef services) +{ + auto& qcdb = services.get(); + + updateTrackHistos(t, &qcdb); +} + +//_________________________________________________________________________________________ + +void TracksPostProcessing::finalize(Trigger t, framework::ServiceRegistryRef) +{ +} diff --git a/Modules/MUON/Common/src/TracksPostProcessingConfig.cxx b/Modules/MUON/Common/src/TracksPostProcessingConfig.cxx new file mode 100644 index 0000000000..995592a341 --- /dev/null +++ b/Modules/MUON/Common/src/TracksPostProcessingConfig.cxx @@ -0,0 +1,87 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file TracksPostProcessingConfig.cxx +/// \author Andrea Ferrero andrea.ferrero@cern.ch +/// \brief File for the configuration of MCH post-processing tasks +/// \since 05/10/2021 +/// + +#include "MUONCommon/TracksPostProcessingConfig.h" +#include +#include + +using namespace o2::quality_control::postprocessing; +namespace o2::quality_control_modules::muon +{ + +TracksPostProcessingConfig::TracksPostProcessingConfig(std::string name, const boost::property_tree::ptree& config) + : PostProcessingConfig(name, config) +{ + // parameters + if (const auto& customConfigs = config.get_child_optional("qc.postprocessing." + name + ".customization"); customConfigs.has_value()) { + for (const auto& customConfig : customConfigs.value()) { + if (const auto& customNames = customConfig.second.get_child_optional("name"); customNames.has_value()) { + parameters.insert(std::make_pair(customConfig.second.get("name"), customConfig.second.get("value"))); + } + } + } + + // Data source configuration + for (const auto& dataSourceConfig : config.get_child("qc.postprocessing." + name + ".dataSources")) { + if (const auto& sourceNames = dataSourceConfig.second.get_child_optional("names"); sourceNames.has_value()) { + auto plotsPath = dataSourceConfig.second.get("plotsPath"); + auto refsPath = dataSourceConfig.second.get("refsPath"); + auto outputPath = dataSourceConfig.second.get("outputPath"); + for (const auto& sourceName : sourceNames.value()) { + int rebin = 1; + std::string nameFull = sourceName.second.data(); + std::string name = nameFull; + auto pos = name.find(":"); + if (pos < std::string::npos) { + name = nameFull.substr(0, pos); + auto rebinStr = nameFull.substr(pos + 1); + rebin = std::stoi(rebinStr); + } + dataSources.push_back({ plotsPath, refsPath, outputPath, name, rebin }); + } + } else { + throw std::runtime_error("No 'name' value or a 'names' vector in the path 'qc.postprocessing." + name + ".dataSources'"); + } + } +} + +template <> +const std::string TracksPostProcessingConfig::getParameter(std::string name) const +{ + std::string result; + auto entry = parameters.find(name); + if (entry != parameters.end()) { + result = entry->second; + } + + return result; +} + +template <> +const std::string TracksPostProcessingConfig::getParameter(std::string name, std::string defaultValue) const +{ + std::string result = defaultValue; + auto entry = parameters.find(name); + if (entry != parameters.end()) { + result = entry->second; + } + + return result; +} + +} // namespace o2::quality_control_modules::muon diff --git a/Modules/MUON/Common/src/TracksTask.cxx b/Modules/MUON/Common/src/TracksTask.cxx index 3195e65a2f..14a1ac0d6b 100644 --- a/Modules/MUON/Common/src/TracksTask.cxx +++ b/Modules/MUON/Common/src/TracksTask.cxx @@ -13,11 +13,22 @@ #include "MUONCommon/Helpers.h" #include "QualityControl/ObjectsManager.h" +#include +#include +#include +#include +#include #include "QualityControl/QcInfoLogger.h" #include #include +#include +#include +#include +#include #include +#include + namespace o2::quality_control_modules::muon { @@ -27,6 +38,28 @@ TracksTask::TracksTask() TracksTask::~TracksTask() = default; +template <> +std::string TracksTask::getParameter(std::string parName, const std::string defaultValue, const o2::quality_control::core::Activity& activity) +{ + std::string result = defaultValue; + auto parOpt = mCustomParameters.atOptional(parName, activity); + if (parOpt.has_value()) { + result = parOpt.value(); + } + return result; +} + +template <> +std::string TracksTask::getParameter(std::string parName, const std::string defaultValue) +{ + std::string result = defaultValue; + auto parOpt = mCustomParameters.atOptional(parName); + if (parOpt.has_value()) { + result = parOpt.value(); + } + return result; +} + bool TracksTask::getBooleanParam(const char* paramName) const { if (auto param = mCustomParameters.find(paramName); param != mCustomParameters.end()) { @@ -42,10 +75,14 @@ GID::mask_t adaptSource(GID::mask_t src) if (src[GID::Source::MFTMCHMID] == 1) { src.reset(GID::Source::MFTMCHMID); // does not exist src.set(GID::Source::MFTMCH); + // ensure we request the individual tracks as we use their information in the plotter + src.set(GID::Source::MFT); + src.set(GID::Source::MCH); src.set(GID::Source::MID); } if (src[GID::Source::MCHMID] == 1) { - // ensure we request MID tracks as we use their information in the plotter + // ensure we request the individual tracks as we use their information in the plotter + src.set(GID::Source::MCH); src.set(GID::Source::MID); } return src; @@ -55,12 +92,24 @@ void TracksTask::initialize(o2::framework::InitContext& /*ic*/) { ILOG(Debug, Devel) << "initialize TracksTask" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. - double maxTracksPerTF = 400; - - if (auto param = mCustomParameters.find("maxTracksPerTF"); param != mCustomParameters.end()) { - maxTracksPerTF = std::stof(param->second); + ILOG(Info, Support) << "loading geometry" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. + if (!o2::base::GeometryManager::isGeometryLoaded()) { + TaskInterface::retrieveConditionAny("GLO/Config/Geometry"); } + bool fullHistos = getParameter("fullHistos", 0) == 1; + + double maxTracksPerTF = getParameter("maxTracksPerTF", 400); + double cutRAbsMin = getParameter("cutRAbsMin", 17.6); + double cutRAbsMax = getParameter("cutRAbsMax", 89.5); + double cutEtaMin = getParameter("cutEtaMin", -4.0); + double cutEtaMax = getParameter("cutEtaMax", -2.5); + double cutPtMin = getParameter("cutPtMin", 0.5); + double cutChi2Min = getParameter("cutChi2Min", 0); + double cutChi2Max = getParameter("cutChi2Max", 1000); + double nSigmaPDCA = getParameter("nSigmaPDCA", 6); + double diMuonTimeCut = getParameter("diMuonTimeCut", 100) / 1000; + ILOG(Info, Support) << "loading sources" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. auto srcFixed = mSrc; @@ -76,22 +125,87 @@ void TracksTask::initialize(o2::framework::InitContext& /*ic*/) ILOG(Info, Devel) << "Sources for data request = " << srcFixed << " " << GID::getSourcesNames(srcFixed) << ENDM; } - ILOG(Info, Devel) << "Will do DataRequest for " << GID::getSourcesNames(srcFixed) << ENDM; + ILOG(Info, Support) << "Will do DataRequest for " << GID::getSourcesNames(srcFixed) << ENDM; + if (srcFixed[GID::Source::MFTMCHMID] == 1) { + srcFixed.reset(GID::Source::MFTMCHMID); + srcFixed.set(GID::Source::MFTMCH); + } mDataRequest = std::make_shared(); mDataRequest->requestTracks(srcFixed, false); + //====================================== + // Track plotters without cuts + auto createPlotter = [&](GID::Source source, std::string path) { if (mSrc[source] == 1) { ILOG(Info, Devel) << "Creating plotter for path " << path << ENDM; - mTrackPlotters[source] = std::make_unique(maxTracksPerTF, source, path); + mTrackPlotters[source] = std::make_unique(maxTracksPerTF, source, path, fullHistos); mTrackPlotters[source]->publish(getObjectsManager()); } }; - createPlotter(GID::Source::MCH, "MCH/"); + createPlotter(GID::Source::MCH, ""); createPlotter(GID::Source::MCHMID, "MCH-MID/"); createPlotter(GID::Source::MFTMCH, "MFT-MCH/"); createPlotter(GID::Source::MFTMCHMID, "MFT-MCH-MID/"); + + //====================================== + // Track plotters with cuts + + std::vector muonCuts{ + // Rabs cut + [cutRAbsMin, cutRAbsMax](const MuonTrack& t) { return ((t.getRAbs() >= cutRAbsMin) && (t.getRAbs() <= cutRAbsMax)); }, + // Eta cut + [cutEtaMin, cutEtaMax](const MuonTrack& t) { return ((t.getMuonMomentumAtVertexMCH().eta() >= cutEtaMin) && (t.getMuonMomentumAtVertexMCH().eta() <= cutEtaMax)); }, + // Pt cut + [cutPtMin](const MuonTrack& t) { return ((t.getMuonMomentumAtVertexMCH().Pt() >= cutPtMin)); }, + // pDCA cut + [nSigmaPDCA](const MuonTrack& t) { + static const double sigmaPDCA23 = 80.; + static const double sigmaPDCA310 = 54.; + static const double relPRes = 0.0004; + static const double slopeRes = 0.0005; + + double thetaAbs = TMath::ATan(t.getRAbs() / 505.) * TMath::RadToDeg(); + + double pUncorr = t.getTrackParamMCH().p(); + double p = t.getMuonMomentumAtVertexMCH().P(); + + double pDCA = pUncorr * t.getDCAMCH(); + double sigmaPDCA = (thetaAbs < 3) ? sigmaPDCA23 : sigmaPDCA310; + double nrp = nSigmaPDCA * relPRes * p; + double pResEffect = sigmaPDCA / (1. - nrp / (1. + nrp)); + double slopeResEffect = 535. * slopeRes * p; + double sigmaPDCAWithRes = TMath::Sqrt(pResEffect * pResEffect + slopeResEffect * slopeResEffect); + if (pDCA > nSigmaPDCA * sigmaPDCAWithRes) { + return false; + } + + return true; + }, + // MCH chi2 cut + [cutChi2Min, cutChi2Max](const MuonTrack& t) { return ((t.getChi2OverNDFMCH() >= cutChi2Min) && (t.getChi2OverNDFMCH() <= cutChi2Max)); } + }; + + std::vector diMuonCuts{ + // cut on time difference between the two muon tracks + [diMuonTimeCut](const MuonTrack& t1, const MuonTrack& t2) { return (std::abs(t1.getTime().getTimeStamp() - t2.getTime().getTimeStamp()) < diMuonTimeCut); } + }; + + auto createPlotterWithCuts = [&](GID::Source source, std::string path) { + if (mSrc[source] == 1) { + ILOG(Info, Devel) << "Creating plotter for path " << path << ENDM; + mTrackPlottersWithCuts[source] = std::make_unique(maxTracksPerTF, source, path, fullHistos); + mTrackPlottersWithCuts[source]->setMuonCuts(muonCuts); + mTrackPlottersWithCuts[source]->setDiMuonCuts(diMuonCuts); + mTrackPlottersWithCuts[source]->publish(getObjectsManager()); + } + }; + + createPlotterWithCuts(GID::Source::MCH, "WithCuts/"); + createPlotterWithCuts(GID::Source::MCHMID, "MCH-MID/WithCuts/"); + createPlotterWithCuts(GID::Source::MFTMCH, "MFT-MCH/WithCuts/"); + createPlotterWithCuts(GID::Source::MFTMCHMID, "MFT-MCH-MID/WithCuts/"); } void TracksTask::startOfActivity(const Activity& activity) @@ -118,6 +232,10 @@ bool TracksTask::assertInputs(o2::framework::ProcessingContext& ctx) ILOG(Info, Support) << "no mch track clusters available on input" << ENDM; return false; } + if (!ctx.inputs().isValid("mchtrackdigits")) { + ILOG(Info, Support) << "no mch track digits available on input" << ENDM; + return false; + } if (mSrc[GID::Source::MCHMID] == 1) { if (!ctx.inputs().isValid("matchMCHMID")) { ILOG(Info, Support) << "no muon (mch+mid) track available on input" << ENDM; @@ -145,42 +263,63 @@ bool TracksTask::assertInputs(o2::framework::ProcessingContext& ctx) void TracksTask::monitorData(o2::framework::ProcessingContext& ctx) { - ILOG(Info, Devel) << "Debug: MonitorData" << ENDM; + ILOG(Debug, Devel) << "Debug: MonitorData" << ENDM; + + int firstTForbit = ctx.services().get().firstTForbit; + ILOG(Debug, Devel) << "Debug: firstTForbit=" << firstTForbit << ENDM; if (!assertInputs(ctx)) { return; } - ILOG(Info, Devel) << "Debug: Asserted inputs" << ENDM; + auto tracksMCH = ctx.inputs().get>("trackMCH"); + auto clusters = ctx.inputs().get>("trackMCHTRACKCLUSTERS"); + + ILOG(Debug, Devel) << "Debug: Asserted inputs" << ENDM; mRecoCont.collectData(ctx, *mDataRequest.get()); - ILOG(Info, Devel) << "Debug: Collected data" << ENDM; + ILOG(Debug, Devel) << "Debug: Collected data" << ENDM; + + for (auto& p : mTrackPlotters) { + if (p.second) { + p.second->setFirstTForbit(firstTForbit); + } + } + for (auto& p : mTrackPlottersWithCuts) { + if (p.second) { + p.second->setFirstTForbit(firstTForbit); + } + } if (mSrc[GID::MCH] == 1) { - ILOG(Info, Devel) << "Debug: MCH requested" << ENDM; - if (mRecoCont.isTrackSourceLoaded(GID::MCH)) { - ILOG(Info, Devel) << "Debug: MCH source loaded " << mRecoCont.isTrackSourceLoaded(GID::MCH) << ENDM; + ILOG(Debug, Devel) << "Debug: MCH requested" << ENDM; + if (true || mRecoCont.isTrackSourceLoaded(GID::MCH)) { + ILOG(Debug, Devel) << "Debug: MCH source loaded" << ENDM; mTrackPlotters[GID::MCH]->fillHistograms(mRecoCont); + mTrackPlottersWithCuts[GID::MCH]->fillHistograms(mRecoCont); } } if (mSrc[GID::MCHMID] == 1) { - ILOG(Info, Devel) << "Debug: MCHMID requested" << ENDM; - if (mRecoCont.isMatchSourceLoaded(GID::MCHMID)) { - ILOG(Info, Devel) << "Debug: MCHMID source loaded " << mRecoCont.isMatchSourceLoaded(GID::MCHMID) << ENDM; + ILOG(Debug, Devel) << "Debug: MCHMID requested" << ENDM; + if (true || mRecoCont.isMatchSourceLoaded(GID::MCHMID)) { + ILOG(Debug, Devel) << "Debug: MCHMID source loaded" << ENDM; mTrackPlotters[GID::MCHMID]->fillHistograms(mRecoCont); + mTrackPlottersWithCuts[GID::MCHMID]->fillHistograms(mRecoCont); } } if (mSrc[GID::MFTMCH] == 1) { - ILOG(Info, Devel) << "Debug: MFTMCH requested" << ENDM; - if (mRecoCont.isTrackSourceLoaded(GID::MFTMCH)) { + ILOG(Debug, Devel) << "Debug: MFTMCH requested" << ENDM; + if (true || mRecoCont.isTrackSourceLoaded(GID::MFTMCH)) { mTrackPlotters[GID::MFTMCH]->fillHistograms(mRecoCont); + mTrackPlottersWithCuts[GID::MFTMCH]->fillHistograms(mRecoCont); } } if (mSrc[GID::MFTMCHMID] == 1) { - ILOG(Info, Devel) << "Debug: MFTMCHMID requested" << ENDM; - if (mRecoCont.isTrackSourceLoaded(GID::MFTMCH)) { + ILOG(Debug, Devel) << "Debug: MFTMCHMID requested" << ENDM; + if (true || mRecoCont.isTrackSourceLoaded(GID::MFTMCH)) { mTrackPlotters[GID::MFTMCHMID]->fillHistograms(mRecoCont); + mTrackPlottersWithCuts[GID::MFTMCHMID]->fillHistograms(mRecoCont); } } } @@ -188,6 +327,12 @@ void TracksTask::monitorData(o2::framework::ProcessingContext& ctx) void TracksTask::endOfCycle() { ILOG(Debug, Devel) << "endOfCycle" << ENDM; + for (auto& p : mTrackPlotters) { + p.second->endOfCycle(); + } + for (auto& p : mTrackPlottersWithCuts) { + p.second->endOfCycle(); + } } void TracksTask::endOfActivity(const Activity& /*activity*/) @@ -197,10 +342,13 @@ void TracksTask::endOfActivity(const Activity& /*activity*/) void TracksTask::reset() { - ILOG(Info, Support) << "reset" << ENDM; + ILOG(Debug, Devel) << "reset" << ENDM; for (auto& p : mTrackPlotters) { p.second->reset(); } + for (auto& p : mTrackPlottersWithCuts) { + p.second->reset(); + } } } // namespace o2::quality_control_modules::muon From 3d3bb4648eac7caf47a29dc4e4e70051b0805d05 Mon Sep 17 00:00:00 2001 From: aferrero2707 Date: Wed, 6 Mar 2024 13:50:43 +0100 Subject: [PATCH 2/2] [MUON] PR review comments --- .../MUON/Common/include/MUONCommon/Helpers.h | 26 +++++ .../Common/include/MUONCommon/HistPlotter.h | 2 +- .../MUONCommon/MatchingEfficiencyCheck.h | 31 +----- .../Common/include/MUONCommon/TrackPlotter.h | 5 +- .../include/MUONCommon/TracksPostProcessing.h | 28 +---- .../Common/include/MUONCommon/TracksTask.h | 38 +------ Modules/MUON/Common/src/Helpers.cxx | 24 +++++ .../Common/src/MatchingEfficiencyCheck.cxx | 49 ++------- Modules/MUON/Common/src/TrackPlotter.cxx | 87 ++++++++------- .../MUON/Common/src/TracksPostProcessing.cxx | 61 ++++++++--- Modules/MUON/Common/src/TracksTask.cxx | 101 +++++++++--------- 11 files changed, 213 insertions(+), 239 deletions(-) diff --git a/Modules/MUON/Common/include/MUONCommon/Helpers.h b/Modules/MUON/Common/include/MUONCommon/Helpers.h index 336704baba..7a13f68fad 100644 --- a/Modules/MUON/Common/include/MUONCommon/Helpers.h +++ b/Modules/MUON/Common/include/MUONCommon/Helpers.h @@ -12,6 +12,7 @@ #ifndef QC_MODULE_MUON_COMMON_HELPERS_H #define QC_MODULE_MUON_COMMON_HELPERS_H +#include "QualityControl/CustomParameters.h" #include class TH1; @@ -19,6 +20,31 @@ class TLine; namespace o2::quality_control_modules::muon { +template +T getConfigurationParameter(o2::quality_control::core::CustomParameters customParameters, std::string parName, const T defaultValue) +{ + T result = defaultValue; + auto parOpt = customParameters.atOptional(parName); + if (parOpt.has_value()) { + std::stringstream ss(parOpt.value()); + ss >> result; + } + return result; +} + +template +T getConfigurationParameter(o2::quality_control::core::CustomParameters customParameters, std::string parName, const T defaultValue, const o2::quality_control::core::Activity& activity) +{ + auto parOpt = customParameters.atOptional(parName, activity); + if (parOpt.has_value()) { + T result; + std::stringstream ss(parOpt.value()); + ss >> result; + return result; + } + return getConfigurationParameter(customParameters, parName, defaultValue); +} + TLine* addHorizontalLine(TH1& histo, double y, int lineColor = 1, int lineStyle = 10, int lineWidth = 1); diff --git a/Modules/MUON/Common/include/MUONCommon/HistPlotter.h b/Modules/MUON/Common/include/MUONCommon/HistPlotter.h index f37c00a44a..82fe7749f4 100644 --- a/Modules/MUON/Common/include/MUONCommon/HistPlotter.h +++ b/Modules/MUON/Common/include/MUONCommon/HistPlotter.h @@ -24,7 +24,7 @@ class HistPlotter { public: HistPlotter() = default; - ~HistPlotter() = default; + virtual ~HistPlotter() = default; public: struct HistInfo { diff --git a/Modules/MUON/Common/include/MUONCommon/MatchingEfficiencyCheck.h b/Modules/MUON/Common/include/MUONCommon/MatchingEfficiencyCheck.h index 87e0632bbf..38158470f9 100644 --- a/Modules/MUON/Common/include/MUONCommon/MatchingEfficiencyCheck.h +++ b/Modules/MUON/Common/include/MUONCommon/MatchingEfficiencyCheck.h @@ -24,7 +24,7 @@ namespace o2::quality_control_modules::muon { -/// \brief Check whether a plot is empty or not. +/// \brief Check whether the matching efficiency is within some configurable limits /// /// \author Andrea Ferrero class MatchingEfficiencyCheck : public o2::quality_control::checker::CheckInterface @@ -46,11 +46,6 @@ class MatchingEfficiencyCheck : public o2::quality_control::checker::CheckInterf ClassDefOverride(MatchingEfficiencyCheck, 1); private: - template - T getParameter(std::string parName, const T defaultValue, const o2::quality_control::core::Activity& activity); - template - T getParameter(std::string parName, const T defaultValue); - void initRange(std::string key); std::optional> getRange(std::string key); @@ -60,30 +55,6 @@ class MatchingEfficiencyCheck : public o2::quality_control::checker::CheckInterf std::map mQualities; }; -template -T MatchingEfficiencyCheck::getParameter(std::string parName, const T defaultValue, const o2::quality_control::core::Activity& activity) -{ - T result = defaultValue; - auto parOpt = mCustomParameters.atOptional(parName, activity); - if (parOpt.has_value()) { - std::stringstream ss(parOpt.value()); - ss >> result; - } - return result; -} - -template -T MatchingEfficiencyCheck::getParameter(std::string parName, const T defaultValue) -{ - T result = defaultValue; - auto parOpt = mCustomParameters.atOptional(parName); - if (parOpt.has_value()) { - std::stringstream ss(parOpt.value()); - ss >> result; - } - return result; -} - } // namespace o2::quality_control_modules::muon #endif // QC_MODULE_MUON_MATCHINGEFFICIENCYCHECK_H diff --git a/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h b/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h index 9de9f064b5..8c989a8e8e 100644 --- a/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h +++ b/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h @@ -30,6 +30,7 @@ #include #include #include +#include using GID = o2::dataformats::GlobalTrackID; @@ -46,7 +47,7 @@ class TrackPlotter : public HistPlotter public: static constexpr Double_t sLastMFTPlaneZ = o2::mft::constants::mft::LayerZCoordinate()[9]; - TrackPlotter(int maxTracksPerTF, GID::Source source, std::string path, bool fullHistos = false); + TrackPlotter(int maxTracksPerTF, int etaBins, int phiBins, int ptBins, GID::Source source, std::string path, bool fullHistos = false); ~TrackPlotter() = default; public: @@ -65,7 +66,7 @@ class TrackPlotter : public HistPlotter private: /** create histograms related to tracks */ - void createTrackHistos(int maxTracksPerTF); + void createTrackHistos(int maxTracksPerTF, int etaBins, int phiBins, int ptBins); /** create histograms related to track pairs */ void createTrackPairHistos(); diff --git a/Modules/MUON/Common/include/MUONCommon/TracksPostProcessing.h b/Modules/MUON/Common/include/MUONCommon/TracksPostProcessing.h index 0e4be94b6f..15cd36c0f5 100644 --- a/Modules/MUON/Common/include/MUONCommon/TracksPostProcessing.h +++ b/Modules/MUON/Common/include/MUONCommon/TracksPostProcessing.h @@ -44,30 +44,7 @@ namespace o2::quality_control_modules::muon using namespace o2::quality_control::core; using GID = o2::dataformats::GlobalTrackID; - -class MatchingEfficiencyPlotterInterface : public HistPlotter -{ - public: - MatchingEfficiencyPlotterInterface() = default; - virtual void update(repository::DatabaseInterface& qcdb, Trigger t, std::shared_ptr objectsManager) = 0; -}; - -template -class MatchingEfficiencyPlotter : public MatchingEfficiencyPlotterInterface -{ - public: - MatchingEfficiencyPlotter(std::string pathMatched, std::string pathMCH, std::string path, std::string plotName, int rebin); - - void update(repository::DatabaseInterface& qcdb, Trigger t, std::shared_ptr objectsManager) override; - - private: - std::string mPlotPath[2]; - std::string mPlotName[2]; - uint64_t mTimestamp[2]; - std::string mName; - std::shared_ptr mHistMatchingEff; - int mRebin; -}; +class MatchingEfficiencyPlotterInterface; /// \brief A post-processing task which processes and trends MCH digits and produces plots. class TracksPostProcessing : public PostProcessingInterface @@ -83,11 +60,12 @@ class TracksPostProcessing : public PostProcessingInterface private: void createTrackHistos(); + void removeTrackHistos(); void updateTrackHistos(Trigger t, repository::DatabaseInterface* qcdb); std::unique_ptr mConfig; - std::vector> mMatchingEfficiencyPlotters; + std::vector> mMatchingEfficiencyPlotters; }; } // namespace o2::quality_control_modules::muon diff --git a/Modules/MUON/Common/include/MUONCommon/TracksTask.h b/Modules/MUON/Common/include/MUONCommon/TracksTask.h index 7d6e7b149e..97091dd41a 100644 --- a/Modules/MUON/Common/include/MUONCommon/TracksTask.h +++ b/Modules/MUON/Common/include/MUONCommon/TracksTask.h @@ -30,12 +30,6 @@ using GID = o2::dataformats::GlobalTrackID; class TracksTask /*final*/ : public TaskInterface { public: - enum matchType : int8_t { MCH = 0, - MCHMID, - MFTMCH, - MFTMCHMID, - SIZE }; - TracksTask(); ~TracksTask() override; @@ -50,12 +44,8 @@ class TracksTask /*final*/ : public TaskInterface private: /** check whether all the expected inputs are present.*/ bool assertInputs(o2::framework::ProcessingContext& ctx); - bool getBooleanParam(const char* paramName) const; - - template - T getParameter(std::string parName, const T defaultValue, const o2::quality_control::core::Activity& activity); - template - T getParameter(std::string parName, const T defaultValue); + void createTrackHistos(const o2::quality_control::core::Activity& activity); + void removeTrackHistos(); private: std::map> mTrackPlotters; @@ -73,30 +63,6 @@ class TracksTask /*final*/ : public TaskInterface gsl::span mMFTMCHMIDTracks; }; -template -T TracksTask::getParameter(std::string parName, const T defaultValue, const o2::quality_control::core::Activity& activity) -{ - T result = defaultValue; - auto parOpt = mCustomParameters.atOptional(parName, activity); - if (parOpt.has_value()) { - std::stringstream ss(parOpt.value()); - ss >> result; - } - return result; -} - -template -T TracksTask::getParameter(std::string parName, const T defaultValue) -{ - T result = defaultValue; - auto parOpt = mCustomParameters.atOptional(parName); - if (parOpt.has_value()) { - std::stringstream ss(parOpt.value()); - ss >> result; - } - return result; -} - } // namespace o2::quality_control_modules::muon #endif diff --git a/Modules/MUON/Common/src/Helpers.cxx b/Modules/MUON/Common/src/Helpers.cxx index a96785a5b2..da008fc92f 100644 --- a/Modules/MUON/Common/src/Helpers.cxx +++ b/Modules/MUON/Common/src/Helpers.cxx @@ -19,6 +19,30 @@ namespace o2::quality_control_modules::muon { +template <> +std::string getConfigurationParameter(o2::quality_control::core::CustomParameters customParameters, std::string parName, const std::string defaultValue) +{ + std::string result = defaultValue; + auto parOpt = customParameters.atOptional(parName); + if (parOpt.has_value()) { + result = parOpt.value(); + } + return result; +} + +template <> +std::string getConfigurationParameter(o2::quality_control::core::CustomParameters customParameters, std::string parName, const std::string defaultValue, const o2::quality_control::core::Activity& activity) +{ + auto parOpt = customParameters.atOptional(parName, activity); + if (parOpt.has_value()) { + std::string result = parOpt.value(); + return result; + } + return getConfigurationParameter(customParameters, parName, defaultValue); +} + +//_________________________________________________________________________________________ + TLine* addHorizontalLine(TH1& histo, double y, int lineColor, int lineStyle, int lineWidth) diff --git a/Modules/MUON/Common/src/MatchingEfficiencyCheck.cxx b/Modules/MUON/Common/src/MatchingEfficiencyCheck.cxx index d1e95f74c7..48e1811b55 100644 --- a/Modules/MUON/Common/src/MatchingEfficiencyCheck.cxx +++ b/Modules/MUON/Common/src/MatchingEfficiencyCheck.cxx @@ -15,36 +15,16 @@ /// #include "MUONCommon/MatchingEfficiencyCheck.h" +#include "MUONCommon/Helpers.h" #include "QualityControl/MonitorObject.h" #include "QualityControl/Quality.h" +#include +#include #include #include namespace o2::quality_control_modules::muon { - -template <> -std::string MatchingEfficiencyCheck::getParameter(std::string parName, const std::string defaultValue, const o2::quality_control::core::Activity& activity) -{ - std::string result = defaultValue; - auto parOpt = mCustomParameters.atOptional(parName, activity); - if (parOpt.has_value()) { - result = parOpt.value(); - } - return result; -} - -template <> -std::string MatchingEfficiencyCheck::getParameter(std::string parName, const std::string defaultValue) -{ - std::string result = defaultValue; - auto parOpt = mCustomParameters.atOptional(parName); - if (parOpt.has_value()) { - result = parOpt.value(); - } - return result; -} - void MatchingEfficiencyCheck::configure() {} void MatchingEfficiencyCheck::startOfActivity(const Activity& activity) @@ -66,20 +46,6 @@ static std::string getBaseName(std::string name) return ((pos < std::string::npos) ? name.substr(pos + 1) : name); } -static std::vector getTokens(std::string str, std::string sep) -{ - std::vector result; - size_t pos = 0; - while (pos < str.size()) { - size_t pos2 = str.find(sep, pos); - size_t count = pos2 - pos; - auto token = str.substr(pos, count); - pos = (pos2 == std::string::npos) ? pos2 : pos2 + 1; - result.push_back(token); - } - return result; -} - void MatchingEfficiencyCheck::initRange(std::string key) { // Get acceptable range for this histogram @@ -89,14 +55,14 @@ void MatchingEfficiencyCheck::initRange(std::string key) } std::string parKey = std::string("range:") + key; - std::string parValue = getParameter(parKey, "", mActivity); + std::string parValue = getConfigurationParameter(mCustomParameters, parKey, "", mActivity); - auto tokens = getTokens(parValue, ":"); + auto tokens = o2::utils::Str::tokenize(parValue, ':', false, true); if (tokens.empty()) { return; } - auto range = getTokens(tokens[0], ","); + auto range = o2::utils::Str::tokenize(tokens[0], ',', false, true); if (range.size() == 2) { double min = std::stod(range[0]); double max = std::stod(range[1]); @@ -106,7 +72,7 @@ void MatchingEfficiencyCheck::initRange(std::string key) if (tokens.size() > 1) { std::vector> intervals; for (size_t ti = 1; ti < tokens.size(); ti++) { - auto interval = getTokens(tokens[ti], ","); + auto interval = o2::utils::Str::tokenize(tokens[ti], ',', false, true); if (interval.size() == 2) { double xmin = std::stod(interval[0]); double xmax = std::stod(interval[1]); @@ -182,6 +148,7 @@ Quality MatchingEfficiencyCheck::check(std::mapGetBinContent(bin) < range->first || hist->GetBinContent(bin) > range->second) { mQualities[moName] = Quality::Bad; + mQualities[moName].addReason(o2::quality_control::FlagReasonFactory::BadTracking(), "Matching efficiency not in the expected range"); break; } } diff --git a/Modules/MUON/Common/src/TrackPlotter.cxx b/Modules/MUON/Common/src/TrackPlotter.cxx index 89a159cb4f..fd0d73805c 100644 --- a/Modules/MUON/Common/src/TrackPlotter.cxx +++ b/Modules/MUON/Common/src/TrackPlotter.cxx @@ -81,11 +81,16 @@ using namespace o2::dataformats; namespace o2::quality_control_modules::muon { -TrackPlotter::TrackPlotter(int maxTracksPerTF, GID::Source source, std::string path, bool fullHistos) : mSrc(source), - mPath(path), - mFullHistos(fullHistos) +TrackPlotter::TrackPlotter(int maxTracksPerTF, + int etaBins, int phiBins, int ptBins, + GID::Source source, + std::string path, + bool fullHistos) + : mSrc(source), + mPath(path), + mFullHistos(fullHistos) { - createTrackHistos(maxTracksPerTF); + createTrackHistos(maxTracksPerTF, etaBins, phiBins, ptBins); createTrackPairHistos(); } @@ -130,7 +135,7 @@ std::unique_ptr TrackPlotter::createHisto(const char* name, const cha return h; } -void TrackPlotter::createTrackHistos(int maxTracksPerTF) +void TrackPlotter::createTrackHistos(int maxTracksPerTF, int etaBins, int phiBins, int ptBins) { mNofTracksPerTF[0] = createHisto(TString::Format("%sPositive/TracksPerTF", mPath.c_str()), "Number of tracks per TimeFrame (+);Number of tracks per TF", maxTracksPerTF, 0, maxTracksPerTF, true, true, "logy"); mNofTracksPerTF[1] = createHisto(TString::Format("%sNegative/TracksPerTF", mPath.c_str()), "Number of tracks per TimeFrame (-);Number of tracks per TF", maxTracksPerTF, 0, maxTracksPerTF, true, true, "logy"); @@ -148,35 +153,35 @@ void TrackPlotter::createTrackHistos(int maxTracksPerTF) mTrackPDCA[1] = createHisto(TString::Format("%sNegative/TrackPDCA", mPath.c_str()), "Track p#timesDCA (-);p#timesDCA (GeVcm/c);entries/s", 5000, 0, 5000, true, false, "hist"); mTrackPDCA[2] = createHisto(TString::Format("%sTrackPDCA", mPath.c_str()), "Track p#timesDCA;p#timesDCA (GeVcm/c);entries/s", 5000, 0, 5000, false, false, "hist"); - mTrackPt[0] = createHisto(TString::Format("%sPositive/TrackPt", mPath.c_str()), "Track p_{T} (+);p_{T} (GeV/c);entries/s", 300, 0, 30, true, false, "hist logy"); - mTrackPt[1] = createHisto(TString::Format("%sNegative/TrackPt", mPath.c_str()), "Track p_{T} (-);p_{T} (GeV/c);entries/s", 300, 0, 30, true, false, "hist logy"); - mTrackPt[2] = createHisto(TString::Format("%sTrackPt", mPath.c_str()), "Track p_{T};p_{T} (GeV/c);entries/s", 300, 0, 30, false, false, "hist logy"); + mTrackPt[0] = createHisto(TString::Format("%sPositive/TrackPt", mPath.c_str()), "Track p_{T} (+);p_{T} (GeV/c);entries/s", ptBins, 0, 30, true, false, "hist logy"); + mTrackPt[1] = createHisto(TString::Format("%sNegative/TrackPt", mPath.c_str()), "Track p_{T} (-);p_{T} (GeV/c);entries/s", ptBins, 0, 30, true, false, "hist logy"); + mTrackPt[2] = createHisto(TString::Format("%sTrackPt", mPath.c_str()), "Track p_{T};p_{T} (GeV/c);entries/s", ptBins, 0, 30, false, false, "hist logy"); mTrackQOverPt = createHisto(TString::Format("%sTrackQOverPt", mPath.c_str()), "Track q/p_{T};q/p_{T} (GeV/c)^{-1};entries/s", 200, -10, 10, false, false, "hist logy"); - mTrackEta[0] = createHisto(TString::Format("%sPositive/TrackEta", mPath.c_str()), "Track #eta (+);#eta;entries/s", 200, -4.5, -2, true, false, "hist"); - mTrackEta[1] = createHisto(TString::Format("%sNegative/TrackEta", mPath.c_str()), "Track #eta (-);#eta;entries/s", 200, -4.5, -2, true, false, "hist"); - mTrackEta[2] = createHisto(TString::Format("%sTrackEta", mPath.c_str()), "Track #eta;#eta;entries/s", 200, -4.5, -2, false, false, "hist"); + mTrackEta[0] = createHisto(TString::Format("%sPositive/TrackEta", mPath.c_str()), "Track #eta (+);#eta;entries/s", etaBins, -4.5, -2, true, false, "hist"); + mTrackEta[1] = createHisto(TString::Format("%sNegative/TrackEta", mPath.c_str()), "Track #eta (-);#eta;entries/s", etaBins, -4.5, -2, true, false, "hist"); + mTrackEta[2] = createHisto(TString::Format("%sTrackEta", mPath.c_str()), "Track #eta;#eta;entries/s", etaBins, -4.5, -2, false, false, "hist"); - mTrackPhi[0] = createHisto(TString::Format("%sPositive/TrackPhi", mPath.c_str()), "Track #phi (+);#phi (deg);entries/s", 360, -180, 180, true, false, "hist"); - mTrackPhi[1] = createHisto(TString::Format("%sNegative/TrackPhi", mPath.c_str()), "Track #phi (-);#phi (deg);entries/s", 360, -180, 180, true, false, "hist"); - mTrackPhi[2] = createHisto(TString::Format("%sTrackPhi", mPath.c_str()), "Track #phi;#phi (deg);entries/s", 360, -180, 180, false, false, "hist"); + mTrackPhi[0] = createHisto(TString::Format("%sPositive/TrackPhi", mPath.c_str()), "Track #phi (+);#phi (deg);entries/s", phiBins, -180, 180, true, false, "hist"); + mTrackPhi[1] = createHisto(TString::Format("%sNegative/TrackPhi", mPath.c_str()), "Track #phi (-);#phi (deg);entries/s", phiBins, -180, 180, true, false, "hist"); + mTrackPhi[2] = createHisto(TString::Format("%sTrackPhi", mPath.c_str()), "Track #phi;#phi (deg);entries/s", phiBins, -180, 180, false, false, "hist"); mTrackRAbs[0] = createHisto(TString::Format("%sPositive/TrackRAbs", mPath.c_str()), "Track R_{abs} (+);R_{abs} (cm);entries/s", 1000, 0, 100, true, false, "hist"); mTrackRAbs[1] = createHisto(TString::Format("%sNegative/TrackRAbs", mPath.c_str()), "Track R_{abs} (-);R_{abs} (cm);entries/s", 1000, 0, 100, true, false, "hist"); mTrackRAbs[2] = createHisto(TString::Format("%sTrackRAbs", mPath.c_str()), "Track R_{abs};R_{abs} (cm);entries/s", 1000, 0, 100, false, false, "hist"); - mTrackEtaPhi[0] = createHisto(TString::Format("%sPositive/TrackEtaPhi", mPath.c_str()), "Track #phi vs #eta (+);#eta;#phi", 50, -4.5, -2, 40, -180, 180, true, false, "colz"); - mTrackEtaPhi[1] = createHisto(TString::Format("%sNegative/TrackEtaPhi", mPath.c_str()), "Track #phi vs #eta (-);#eta;#phi", 50, -4.5, -2, 40, -180, 180, true, false, "colz"); - mTrackEtaPhi[2] = createHisto(TString::Format("%sTrackEtaPhi", mPath.c_str()), "Track #phi vs #eta;#eta;#phi", 50, -4.5, -2, 40, -180, 180, false, false, "colz"); + mTrackEtaPhi[0] = createHisto(TString::Format("%sPositive/TrackEtaPhi", mPath.c_str()), "Track #phi vs #eta (+);#eta;#phi", etaBins / 5, -4.5, -2, phiBins / 5, -180, 180, true, false, "colz"); + mTrackEtaPhi[1] = createHisto(TString::Format("%sNegative/TrackEtaPhi", mPath.c_str()), "Track #phi vs #eta (-);#eta;#phi", etaBins / 5, -4.5, -2, phiBins / 5, -180, 180, true, false, "colz"); + mTrackEtaPhi[2] = createHisto(TString::Format("%sTrackEtaPhi", mPath.c_str()), "Track #phi vs #eta;#eta;#phi", etaBins / 5, -4.5, -2, phiBins / 5, -180, 180, false, false, "colz"); - mTrackEtaPt[0] = createHisto(TString::Format("%sPositive/TrackEtaPt", mPath.c_str()), "Track p_{T} vs #eta (+);#eta;p_{T} (GeV/c)", 50, -4.5, -2, 50, 0, 30, true, false, "colz"); - mTrackEtaPt[1] = createHisto(TString::Format("%sNegative/TrackEtaPt", mPath.c_str()), "Track p_{T} vs #eta (-);#eta;p_{T} (GeV/c)", 50, -4.5, -2, 50, 0, 30, true, false, "colz"); - mTrackEtaPt[2] = createHisto(TString::Format("%sTrackEtaPt", mPath.c_str()), "Track p_{T} vs #eta;#eta;p_{T} (GeV/c)", 50, -4.5, -2, 50, 0, 30, false, false, "colz"); + mTrackEtaPt[0] = createHisto(TString::Format("%sPositive/TrackEtaPt", mPath.c_str()), "Track p_{T} vs #eta (+);#eta;p_{T} (GeV/c)", etaBins / 5, -4.5, -2, ptBins / 5, 0, 30, true, false, "colz"); + mTrackEtaPt[1] = createHisto(TString::Format("%sNegative/TrackEtaPt", mPath.c_str()), "Track p_{T} vs #eta (-);#eta;p_{T} (GeV/c)", etaBins / 5, -4.5, -2, ptBins / 5, 0, 30, true, false, "colz"); + mTrackEtaPt[2] = createHisto(TString::Format("%sTrackEtaPt", mPath.c_str()), "Track p_{T} vs #eta;#eta;p_{T} (GeV/c)", etaBins / 5, -4.5, -2, ptBins / 5, 0, 30, false, false, "colz"); - mTrackPhiPt[0] = createHisto(TString::Format("%sPositive/TrackPhiPt", mPath.c_str()), "Track p_{T} vs #phi (+);#phi;p_{T} (GeV/c)", 40, -180, 180, 50, 0, 30, true, false, "colz"); - mTrackPhiPt[1] = createHisto(TString::Format("%sNegative/TrackPhiPt", mPath.c_str()), "Track p_{T} vs #phi (-);#phi;p_{T} (GeV/c)", 40, -180, 180, 50, 0, 30, true, false, "colz"); - mTrackPhiPt[2] = createHisto(TString::Format("%sTrackPhiPt", mPath.c_str()), "Track p_{T} vs #phi;#phi;p_{T} (GeV/c)", 40, -180, 180, 50, 0, 30, false, false, "colz"); + mTrackPhiPt[0] = createHisto(TString::Format("%sPositive/TrackPhiPt", mPath.c_str()), "Track p_{T} vs #phi (+);#phi;p_{T} (GeV/c)", phiBins / 5, -180, 180, ptBins / 5, 0, 30, true, false, "colz"); + mTrackPhiPt[1] = createHisto(TString::Format("%sNegative/TrackPhiPt", mPath.c_str()), "Track p_{T} vs #phi (-);#phi;p_{T} (GeV/c)", phiBins / 5, -180, 180, ptBins / 5, 0, 30, true, false, "colz"); + mTrackPhiPt[2] = createHisto(TString::Format("%sTrackPhiPt", mPath.c_str()), "Track p_{T} vs #phi;#phi;p_{T} (GeV/c)", phiBins / 5, -180, 180, ptBins / 5, 0, 30, false, false, "colz"); mTrackBC = createHisto(TString::Format("%sTrackBC", mPath.c_str()), "Track BC;BC;entries/s", o2::constants::lhc::LHCMaxBunches, 0, o2::constants::lhc::LHCMaxBunches, false, false, "hist"); @@ -185,29 +190,29 @@ void TrackPlotter::createTrackHistos(int maxTracksPerTF) mMatchChi2MFTMCH = createHisto(TString::Format("%sMatchChi2MFTMCH", mPath.c_str()), "Match #chi^{2} MFT-MCH;#chi^{2}", 1000, 0, 100, false, false, "hist"); mMatchNMFTCandidates = createHisto(TString::Format("%sMatchNMFTCandidates", mPath.c_str()), "MFT Candidates;candidates", 1000, 0, 1000, false, false, "hist"); - mTrackEtaCorr[0] = createHisto(TString::Format("%sPositive/TrackEtaCorr", mPath.c_str()), "Track #eta - GLO vs MCH (+);#eta^{MCH};#eta^{GLO}", 50, -4.5, -2, 50, -4.5, -2, true, false, "colz"); - mTrackEtaCorr[1] = createHisto(TString::Format("%sNegative/TrackEtaCorr", mPath.c_str()), "Track #eta - GLO vs MCH (-);#eta^{MCH};#eta^{GLO}", 50, -4.5, -2, 50, -4.5, -2, true, false, "colz"); - mTrackEtaCorr[2] = createHisto(TString::Format("%sTrackEtaCorr", mPath.c_str()), "Track #eta - GLO vs MCH;#eta^{MCH};#eta^{GLO}", 50, -4.5, -2, 50, -4.5, -2, false, false, "colz"); + mTrackEtaCorr[0] = createHisto(TString::Format("%sPositive/TrackEtaCorr", mPath.c_str()), "Track #eta - GLO vs MCH (+);#eta^{MCH};#eta^{GLO}", etaBins / 5, -4.5, -2, etaBins / 5, -4.5, -2, true, false, "colz"); + mTrackEtaCorr[1] = createHisto(TString::Format("%sNegative/TrackEtaCorr", mPath.c_str()), "Track #eta - GLO vs MCH (-);#eta^{MCH};#eta^{GLO}", etaBins / 5, -4.5, -2, etaBins / 5, -4.5, -2, true, false, "colz"); + mTrackEtaCorr[2] = createHisto(TString::Format("%sTrackEtaCorr", mPath.c_str()), "Track #eta - GLO vs MCH;#eta^{MCH};#eta^{GLO}", etaBins / 5, -4.5, -2, etaBins / 5, -4.5, -2, false, false, "colz"); - mTrackDEtaVsEta[0] = createHisto(TString::Format("%sPositive/TrackDEtaVsEta", mPath.c_str()), "Track #eta^{GLO}-#eta^{MCH} vs #eta^{MCH} (+);#eta^{MCH};#eta^{GLO}-#eta^{MCH}", 50, -4.5, -2, 200, -1, 1, true, false, "colz"); - mTrackDEtaVsEta[1] = createHisto(TString::Format("%sNegative/TrackDEtaVsEta", mPath.c_str()), "Track #eta^{GLO}-#eta^{MCH} vs #eta^{MCH} (-);#eta^{MCH};#eta^{GLO}-#eta^{MCH}", 50, -4.5, -2, 200, -1, 1, true, false, "colz"); - mTrackDEtaVsEta[2] = createHisto(TString::Format("%sTrackDEtaVsEta", mPath.c_str()), "Track #eta^{GLO}-#eta^{MCH} vs #eta^{MCH};#eta^{MCH};#eta^{GLO}-#eta^{MCH}", 50, -4.5, -2, 200, -1, 1, false, false, "colz"); + mTrackDEtaVsEta[0] = createHisto(TString::Format("%sPositive/TrackDEtaVsEta", mPath.c_str()), "Track #eta^{GLO}-#eta^{MCH} vs #eta^{MCH} (+);#eta^{MCH};#eta^{GLO}-#eta^{MCH}", etaBins / 5, -4.5, -2, 200, -1, 1, true, false, "colz"); + mTrackDEtaVsEta[1] = createHisto(TString::Format("%sNegative/TrackDEtaVsEta", mPath.c_str()), "Track #eta^{GLO}-#eta^{MCH} vs #eta^{MCH} (-);#eta^{MCH};#eta^{GLO}-#eta^{MCH}", etaBins / 5, -4.5, -2, 200, -1, 1, true, false, "colz"); + mTrackDEtaVsEta[2] = createHisto(TString::Format("%sTrackDEtaVsEta", mPath.c_str()), "Track #eta^{GLO}-#eta^{MCH} vs #eta^{MCH};#eta^{MCH};#eta^{GLO}-#eta^{MCH}", etaBins / 5, -4.5, -2, 200, -1, 1, false, false, "colz"); - mTrackPhiCorr[0] = createHisto(TString::Format("%sPositive/TrackPhiCorr", mPath.c_str()), "Track #phi - GLO vs MCH (+);#phi^{MCH};#phi^{GLO}", 40, -180, 180, 40, -180, 180, true, false, "colz"); - mTrackPhiCorr[1] = createHisto(TString::Format("%sNegative/TrackPhiCorr", mPath.c_str()), "Track #phi - GLO vs MCH (-);#phi^{MCH};#phi^{GLO}", 40, -180, 180, 40, -180, 180, true, false, "colz"); - mTrackPhiCorr[2] = createHisto(TString::Format("%sTrackPhiCorr", mPath.c_str()), "Track #phi - GLO vs MCH;#phi^{MCH};#phi^{GLO}", 40, -180, 180, 40, -180, 180, false, false, "colz"); + mTrackPhiCorr[0] = createHisto(TString::Format("%sPositive/TrackPhiCorr", mPath.c_str()), "Track #phi - GLO vs MCH (+);#phi^{MCH};#phi^{GLO}", phiBins / 5, -180, 180, phiBins / 5, -180, 180, true, false, "colz"); + mTrackPhiCorr[1] = createHisto(TString::Format("%sNegative/TrackPhiCorr", mPath.c_str()), "Track #phi - GLO vs MCH (-);#phi^{MCH};#phi^{GLO}", phiBins / 5, -180, 180, phiBins / 5, -180, 180, true, false, "colz"); + mTrackPhiCorr[2] = createHisto(TString::Format("%sTrackPhiCorr", mPath.c_str()), "Track #phi - GLO vs MCH;#phi^{MCH};#phi^{GLO}", phiBins / 5, -180, 180, phiBins / 5, -180, 180, false, false, "colz"); - mTrackDPhiVsPhi[0] = createHisto(TString::Format("%sPositive/TrackDPhiVsPhi", mPath.c_str()), "Track #phi^{GLO}-#phi^{MCH} vs #phi^{MCH} (+);#phi^{MCH};#phi^{GLO}-#phi^{MCH}", 40, -180, 180, 200, -100, 100, true, false, "colz"); - mTrackDPhiVsPhi[1] = createHisto(TString::Format("%sNegative/TrackDPhiVsPhi", mPath.c_str()), "Track #phi^{GLO}-#phi^{MCH} vs #phi^{MCH} (-);#phi^{MCH};#phi^{GLO}-#phi^{MCH}", 40, -180, 180, 200, -100, 100, true, false, "colz"); - mTrackDPhiVsPhi[2] = createHisto(TString::Format("%sTrackDPhiVsPhi", mPath.c_str()), "Track #phi^{GLO}-#phi^{MCH} vs #phi^{MCH};#phi^{MCH};#phi^{GLO}-#phi^{MCH}", 40, -180, 180, 200, -100, 100, false, false, "colz"); + mTrackDPhiVsPhi[0] = createHisto(TString::Format("%sPositive/TrackDPhiVsPhi", mPath.c_str()), "Track #phi^{GLO}-#phi^{MCH} vs #phi^{MCH} (+);#phi^{MCH};#phi^{GLO}-#phi^{MCH}", phiBins / 5, -180, 180, 200, -100, 100, true, false, "colz"); + mTrackDPhiVsPhi[1] = createHisto(TString::Format("%sNegative/TrackDPhiVsPhi", mPath.c_str()), "Track #phi^{GLO}-#phi^{MCH} vs #phi^{MCH} (-);#phi^{MCH};#phi^{GLO}-#phi^{MCH}", phiBins / 5, -180, 180, 200, -100, 100, true, false, "colz"); + mTrackDPhiVsPhi[2] = createHisto(TString::Format("%sTrackDPhiVsPhi", mPath.c_str()), "Track #phi^{GLO}-#phi^{MCH} vs #phi^{MCH};#phi^{MCH};#phi^{GLO}-#phi^{MCH}", phiBins / 5, -180, 180, 200, -100, 100, false, false, "colz"); - mTrackPtCorr[0] = createHisto(TString::Format("%sPositive/TrackPtCorr", mPath.c_str()), "Track p_{T} - GLO vs MCH (+);p_{T}^{MCH};p_{T}^{GLO}", 50, 0, 30, 50, 0, 30, true, false, "colz"); - mTrackPtCorr[1] = createHisto(TString::Format("%sNegative/TrackPtCorr", mPath.c_str()), "Track p_{T} - GLO vs MCH (-);p_{T}^{MCH};p_{T}^{GLO}", 50, 0, 30, 50, 0, 30, true, false, "colz"); - mTrackPtCorr[2] = createHisto(TString::Format("%sTrackPtCorr", mPath.c_str()), "Track p_{T} - GLO vs MCH;p_{T}^{MCH};p_{T}^{GLO}", 50, 0, 30, 50, 0, 30, false, false, "colz"); + mTrackPtCorr[0] = createHisto(TString::Format("%sPositive/TrackPtCorr", mPath.c_str()), "Track p_{T} - GLO vs MCH (+);p_{T}^{MCH};p_{T}^{GLO}", ptBins / 5, 0, 30, ptBins / 5, 0, 30, true, false, "colz"); + mTrackPtCorr[1] = createHisto(TString::Format("%sNegative/TrackPtCorr", mPath.c_str()), "Track p_{T} - GLO vs MCH (-);p_{T}^{MCH};p_{T}^{GLO}", ptBins / 5, 0, 30, ptBins / 5, 0, 30, true, false, "colz"); + mTrackPtCorr[2] = createHisto(TString::Format("%sTrackPtCorr", mPath.c_str()), "Track p_{T} - GLO vs MCH;p_{T}^{MCH};p_{T}^{GLO}", ptBins / 5, 0, 30, ptBins / 5, 0, 30, false, false, "colz"); - mTrackDPtVsPt[0] = createHisto(TString::Format("%sPositive/TrackDPtVsPt", mPath.c_str()), "Track p_{T}^{GLO}-p_{T}^{MCH} vs p_{T}^{MCH} (+);p_{T}^{MCH};p_{T}^{GLO}-p_{T}^{MCH}", 50, 0, 30, 200, -10, 10, true, false, "colz"); - mTrackDPtVsPt[1] = createHisto(TString::Format("%sNegative/TrackDPtVsPt", mPath.c_str()), "Track p_{T}^{GLO}-p_{T}^{MCH} vs p_{T}^{MCH} (-);p_{T}^{MCH};p_{T}^{GLO}-p_{T}^{MCH}", 50, 0, 30, 200, -10, 10, true, false, "colz"); - mTrackDPtVsPt[2] = createHisto(TString::Format("%sTrackDPtVsPt", mPath.c_str()), "Track p_{T}^{GLO}-p_{T}^{MCH} vs p_{T}^{MCH};p_{T}^{MCH};p_{T}^{GLO}-p_{T}^{MCH}", 50, 0, 30, 200, -10, 10, false, false, "colz"); + mTrackDPtVsPt[0] = createHisto(TString::Format("%sPositive/TrackDPtVsPt", mPath.c_str()), "Track p_{T}^{GLO}-p_{T}^{MCH} vs p_{T}^{MCH} (+);p_{T}^{MCH};p_{T}^{GLO}-p_{T}^{MCH}", ptBins / 5, 0, 30, 200, -10, 10, true, false, "colz"); + mTrackDPtVsPt[1] = createHisto(TString::Format("%sNegative/TrackDPtVsPt", mPath.c_str()), "Track p_{T}^{GLO}-p_{T}^{MCH} vs p_{T}^{MCH} (-);p_{T}^{MCH};p_{T}^{GLO}-p_{T}^{MCH}", ptBins / 5, 0, 30, 200, -10, 10, true, false, "colz"); + mTrackDPtVsPt[2] = createHisto(TString::Format("%sTrackDPtVsPt", mPath.c_str()), "Track p_{T}^{GLO}-p_{T}^{MCH} vs p_{T}^{MCH};p_{T}^{MCH};p_{T}^{GLO}-p_{T}^{MCH}", ptBins / 5, 0, 30, 200, -10, 10, false, false, "colz"); } if (mSrc == GID::MCHMID || mSrc == GID::MFTMCHMID) { diff --git a/Modules/MUON/Common/src/TracksPostProcessing.cxx b/Modules/MUON/Common/src/TracksPostProcessing.cxx index acd7c1ca7b..d1b18e6cd6 100644 --- a/Modules/MUON/Common/src/TracksPostProcessing.cxx +++ b/Modules/MUON/Common/src/TracksPostProcessing.cxx @@ -31,6 +31,9 @@ using namespace o2::quality_control_modules::muon; using namespace o2::quality_control::repository; +namespace o2::quality_control_modules::muon +{ + //_________________________________________________________________________________________ // Helper function for retrieving a MonitorObject from the QCDB, in the form of a std::pair, bool> // A non-null MO is returned in the first element of the pair if the MO is found in the QCDB @@ -83,15 +86,35 @@ T* getPlotFromMO(std::shared_ptr mo) { // Get ROOT object TObject* obj = mo ? mo->getObject() : nullptr; - if (!obj) { - return nullptr; - } - - // Get histogram object - T* h = dynamic_cast(obj); - return h; + return dynamic_cast(obj); } +class MatchingEfficiencyPlotterInterface : public HistPlotter +{ + public: + MatchingEfficiencyPlotterInterface() = default; + ~MatchingEfficiencyPlotterInterface() = default; + virtual void update(repository::DatabaseInterface& qcdb, Trigger t, std::shared_ptr objectsManager) = 0; +}; + +template +class MatchingEfficiencyPlotter : public MatchingEfficiencyPlotterInterface +{ + public: + MatchingEfficiencyPlotter(std::string pathMatched, std::string pathMCH, std::string path, std::string plotName, int rebin); + ~MatchingEfficiencyPlotter() = default; + + void update(repository::DatabaseInterface& qcdb, Trigger t, std::shared_ptr objectsManager) override; + + private: + std::string mPlotPath[2]; + std::string mPlotName[2]; + uint64_t mTimestamp[2]; + std::string mName; + std::shared_ptr mHistMatchingEff; + int mRebin; +}; + template MatchingEfficiencyPlotter::MatchingEfficiencyPlotter(std::string pathMatched, std::string pathMCH, std::string path, std::string plotName, int rebin) : MatchingEfficiencyPlotterInterface(), mRebin(rebin) @@ -134,9 +157,11 @@ void MatchingEfficiencyPlotter::update(repository::DatabaseInterface& qcdb if (!h) { return; } - h->Rebin(mRebin); + + if (mRebin != 1) { + h->Rebin(mRebin); + } mHistMatchingEff.reset(h); - mHistMatchingEff->Sumw2(); mHistMatchingEff->SetStats(0); mHistMatchingEff->SetNameTitle(name, title); mHistMatchingEff->SetMarkerSize(0.25); @@ -173,7 +198,7 @@ void TracksPostProcessing::createTrackHistos() auto pathMatched = dataSource.plotsPath; auto pathRef = dataSource.refsPath; auto path = dataSource.outputPath; - mMatchingEfficiencyPlotters.emplace_back(std::make_unique>(dataSource.plotsPath, dataSource.refsPath, dataSource.outputPath, dataSource.name, dataSource.rebin)); + mMatchingEfficiencyPlotters.emplace_back(std::make_shared>(dataSource.plotsPath, dataSource.refsPath, dataSource.outputPath, dataSource.name, dataSource.rebin)); } for (auto& plot : mMatchingEfficiencyPlotters) { @@ -183,17 +208,27 @@ void TracksPostProcessing::createTrackHistos() //_________________________________________________________________________________________ +void TracksPostProcessing::removeTrackHistos() +{ + for (auto& plot : mMatchingEfficiencyPlotters) { + plot->unpublish(getObjectsManager()); + } + mMatchingEfficiencyPlotters.clear(); +} + +//_________________________________________________________________________________________ + void TracksPostProcessing::configure(const boost::property_tree::ptree& config) { mConfig = std::make_unique(getID(), config); - - createTrackHistos(); } //_________________________________________________________________________________________ void TracksPostProcessing::initialize(Trigger, framework::ServiceRegistryRef) { + removeTrackHistos(); + createTrackHistos(); } //_________________________________________________________________________________________ @@ -219,3 +254,5 @@ void TracksPostProcessing::update(Trigger t, framework::ServiceRegistryRef servi void TracksPostProcessing::finalize(Trigger t, framework::ServiceRegistryRef) { } + +} // namespace o2::quality_control_modules::muon diff --git a/Modules/MUON/Common/src/TracksTask.cxx b/Modules/MUON/Common/src/TracksTask.cxx index 14a1ac0d6b..2da29f8629 100644 --- a/Modules/MUON/Common/src/TracksTask.cxx +++ b/Modules/MUON/Common/src/TracksTask.cxx @@ -38,38 +38,6 @@ TracksTask::TracksTask() TracksTask::~TracksTask() = default; -template <> -std::string TracksTask::getParameter(std::string parName, const std::string defaultValue, const o2::quality_control::core::Activity& activity) -{ - std::string result = defaultValue; - auto parOpt = mCustomParameters.atOptional(parName, activity); - if (parOpt.has_value()) { - result = parOpt.value(); - } - return result; -} - -template <> -std::string TracksTask::getParameter(std::string parName, const std::string defaultValue) -{ - std::string result = defaultValue; - auto parOpt = mCustomParameters.atOptional(parName); - if (parOpt.has_value()) { - result = parOpt.value(); - } - return result; -} - -bool TracksTask::getBooleanParam(const char* paramName) const -{ - if (auto param = mCustomParameters.find(paramName); param != mCustomParameters.end()) { - std::string p = param->second; - std::transform(p.begin(), p.end(), p.begin(), ::toupper); - return p == "TRUE"; - } - return false; -} - GID::mask_t adaptSource(GID::mask_t src) { if (src[GID::Source::MFTMCHMID] == 1) { @@ -97,19 +65,6 @@ void TracksTask::initialize(o2::framework::InitContext& /*ic*/) TaskInterface::retrieveConditionAny("GLO/Config/Geometry"); } - bool fullHistos = getParameter("fullHistos", 0) == 1; - - double maxTracksPerTF = getParameter("maxTracksPerTF", 400); - double cutRAbsMin = getParameter("cutRAbsMin", 17.6); - double cutRAbsMax = getParameter("cutRAbsMax", 89.5); - double cutEtaMin = getParameter("cutEtaMin", -4.0); - double cutEtaMax = getParameter("cutEtaMax", -2.5); - double cutPtMin = getParameter("cutPtMin", 0.5); - double cutChi2Min = getParameter("cutChi2Min", 0); - double cutChi2Max = getParameter("cutChi2Max", 1000); - double nSigmaPDCA = getParameter("nSigmaPDCA", 6); - double diMuonTimeCut = getParameter("diMuonTimeCut", 100) / 1000; - ILOG(Info, Support) << "loading sources" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. auto srcFixed = mSrc; @@ -132,6 +87,27 @@ void TracksTask::initialize(o2::framework::InitContext& /*ic*/) } mDataRequest = std::make_shared(); mDataRequest->requestTracks(srcFixed, false); +} + +void TracksTask::createTrackHistos(const Activity& activity) +{ + bool fullHistos = getConfigurationParameter(mCustomParameters, "fullHistos", 0, activity) == 1; + + double maxTracksPerTF = getConfigurationParameter(mCustomParameters, "maxTracksPerTF", 400, activity); + double cutRAbsMin = getConfigurationParameter(mCustomParameters, "cutRAbsMin", 17.6, activity); + double cutRAbsMax = getConfigurationParameter(mCustomParameters, "cutRAbsMax", 89.5, activity); + double cutEtaMin = getConfigurationParameter(mCustomParameters, "cutEtaMin", -4.0, activity); + double cutEtaMax = getConfigurationParameter(mCustomParameters, "cutEtaMax", -2.5, activity); + double cutPtMin = getConfigurationParameter(mCustomParameters, "cutPtMin", 0.5, activity); + double cutChi2Min = getConfigurationParameter(mCustomParameters, "cutChi2Min", 0, activity); + double cutChi2Max = getConfigurationParameter(mCustomParameters, "cutChi2Max", 1000, activity); + double nSigmaPDCA = getConfigurationParameter(mCustomParameters, "nSigmaPDCA", 6, activity); + double matchScoreMaxMFT = getConfigurationParameter(mCustomParameters, "matchScoreMaxMFT", 1000, activity); + double diMuonTimeCut = getConfigurationParameter(mCustomParameters, "diMuonTimeCut", 100, activity) / 1000; + + int etaBins = getConfigurationParameter(mCustomParameters, "etaBins", 200, activity); + int phiBins = getConfigurationParameter(mCustomParameters, "phiBins", 180, activity); + int ptBins = getConfigurationParameter(mCustomParameters, "ptBins", 300, activity); //====================================== // Track plotters without cuts @@ -139,7 +115,7 @@ void TracksTask::initialize(o2::framework::InitContext& /*ic*/) auto createPlotter = [&](GID::Source source, std::string path) { if (mSrc[source] == 1) { ILOG(Info, Devel) << "Creating plotter for path " << path << ENDM; - mTrackPlotters[source] = std::make_unique(maxTracksPerTF, source, path, fullHistos); + mTrackPlotters[source] = std::make_unique(maxTracksPerTF, etaBins, phiBins, ptBins, source, path, fullHistos); mTrackPlotters[source]->publish(getObjectsManager()); } }; @@ -183,6 +159,12 @@ void TracksTask::initialize(o2::framework::InitContext& /*ic*/) return true; }, + // MFT-MCH match score + [matchScoreMaxMFT](const MuonTrack& t) { + if (t.hasMFT() && t.hasMCH() && t.getMatchInfoFwd().getMFTMCHMatchingScore() > matchScoreMaxMFT) + return false; + return true; + }, // MCH chi2 cut [cutChi2Min, cutChi2Max](const MuonTrack& t) { return ((t.getChi2OverNDFMCH() >= cutChi2Min) && (t.getChi2OverNDFMCH() <= cutChi2Max)); } }; @@ -195,7 +177,7 @@ void TracksTask::initialize(o2::framework::InitContext& /*ic*/) auto createPlotterWithCuts = [&](GID::Source source, std::string path) { if (mSrc[source] == 1) { ILOG(Info, Devel) << "Creating plotter for path " << path << ENDM; - mTrackPlottersWithCuts[source] = std::make_unique(maxTracksPerTF, source, path, fullHistos); + mTrackPlottersWithCuts[source] = std::make_unique(maxTracksPerTF, etaBins, phiBins, ptBins, source, path, fullHistos); mTrackPlottersWithCuts[source]->setMuonCuts(muonCuts); mTrackPlottersWithCuts[source]->setDiMuonCuts(diMuonCuts); mTrackPlottersWithCuts[source]->publish(getObjectsManager()); @@ -208,9 +190,25 @@ void TracksTask::initialize(o2::framework::InitContext& /*ic*/) createPlotterWithCuts(GID::Source::MFTMCHMID, "MFT-MCH-MID/WithCuts/"); } +void TracksTask::removeTrackHistos() +{ + ILOG(Debug, Devel) << "Un-publishing objects" << ENDM; + for (auto& p : mTrackPlotters) { + p.second->unpublish(getObjectsManager()); + } + for (auto& p : mTrackPlottersWithCuts) { + p.second->unpublish(getObjectsManager()); + } + + ILOG(Debug, Devel) << "Destroying objects" << ENDM; + mTrackPlotters.clear(); + mTrackPlottersWithCuts.clear(); +} + void TracksTask::startOfActivity(const Activity& activity) { ILOG(Debug, Devel) << "startOfActivity : " << activity << ENDM; + createTrackHistos(activity); } void TracksTask::startOfCycle() @@ -294,7 +292,7 @@ void TracksTask::monitorData(o2::framework::ProcessingContext& ctx) if (mSrc[GID::MCH] == 1) { ILOG(Debug, Devel) << "Debug: MCH requested" << ENDM; - if (true || mRecoCont.isTrackSourceLoaded(GID::MCH)) { + if (mRecoCont.isTrackSourceLoaded(GID::MCH)) { ILOG(Debug, Devel) << "Debug: MCH source loaded" << ENDM; mTrackPlotters[GID::MCH]->fillHistograms(mRecoCont); mTrackPlottersWithCuts[GID::MCH]->fillHistograms(mRecoCont); @@ -302,7 +300,7 @@ void TracksTask::monitorData(o2::framework::ProcessingContext& ctx) } if (mSrc[GID::MCHMID] == 1) { ILOG(Debug, Devel) << "Debug: MCHMID requested" << ENDM; - if (true || mRecoCont.isMatchSourceLoaded(GID::MCHMID)) { + if (mRecoCont.isMatchSourceLoaded(GID::MCHMID)) { ILOG(Debug, Devel) << "Debug: MCHMID source loaded" << ENDM; mTrackPlotters[GID::MCHMID]->fillHistograms(mRecoCont); mTrackPlottersWithCuts[GID::MCHMID]->fillHistograms(mRecoCont); @@ -310,14 +308,14 @@ void TracksTask::monitorData(o2::framework::ProcessingContext& ctx) } if (mSrc[GID::MFTMCH] == 1) { ILOG(Debug, Devel) << "Debug: MFTMCH requested" << ENDM; - if (true || mRecoCont.isTrackSourceLoaded(GID::MFTMCH)) { + if (mRecoCont.isTrackSourceLoaded(GID::MFTMCH)) { mTrackPlotters[GID::MFTMCH]->fillHistograms(mRecoCont); mTrackPlottersWithCuts[GID::MFTMCH]->fillHistograms(mRecoCont); } } if (mSrc[GID::MFTMCHMID] == 1) { ILOG(Debug, Devel) << "Debug: MFTMCHMID requested" << ENDM; - if (true || mRecoCont.isTrackSourceLoaded(GID::MFTMCH)) { + if (mRecoCont.isTrackSourceLoaded(GID::MFTMCH)) { mTrackPlotters[GID::MFTMCHMID]->fillHistograms(mRecoCont); mTrackPlottersWithCuts[GID::MFTMCHMID]->fillHistograms(mRecoCont); } @@ -338,6 +336,7 @@ void TracksTask::endOfCycle() void TracksTask::endOfActivity(const Activity& /*activity*/) { ILOG(Debug, Devel) << "endOfActivity" << ENDM; + removeTrackHistos(); } void TracksTask::reset()