diff --git a/Modules/MUON/Common/CMakeLists.txt b/Modules/MUON/Common/CMakeLists.txt index a75f50c96e..f7ec4dc9a9 100644 --- a/Modules/MUON/Common/CMakeLists.txt +++ b/Modules/MUON/Common/CMakeLists.txt @@ -6,6 +6,8 @@ set(SRCS src/Helpers.cxx src/MergeableTH1Ratio.cxx src/MergeableTH2Ratio.cxx + src/HistPlotter.cxx + src/MuonTrack.cxx src/TrackPlotter.cxx src/TracksCheck.cxx src/TracksTask.cxx @@ -14,6 +16,8 @@ set(SRCS set(HEADERS include/MUONCommon/MergeableTH1Ratio.h include/MUONCommon/MergeableTH2Ratio.h + include/MUONCommon/HistPlotter.h + include/MUONCommon/MuonTrack.h include/MUONCommon/TrackCheck.h include/MUONCommon/TrackPlotter.h include/MUONCommon/TracksTask.h @@ -29,7 +33,7 @@ target_include_directories( PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src ) -target_link_libraries(${MODULE_NAME} PUBLIC O2QualityControl O2::MCHMappingImpl4 O2::DataFormatsMCH O2::MCHTracking O2::MCHRawElecMap O2::ReconstructionDataFormats O2::MCHGeometryTransformer) +target_link_libraries(${MODULE_NAME} PUBLIC O2QualityControl O2::MCHMappingImpl4 O2::DataFormatsMCH O2::MCHTracking O2::MCHRawElecMap O2::ReconstructionDataFormats O2::MCHGeometryTransformer O2::DataFormatsGlobalTracking) # Digit.h is moving from MCHBase to DataFormatsMCH : let's handle both # gracefully for the moment... diff --git a/Modules/MUON/Common/etc/qc-tracks-mchmid.json b/Modules/MUON/Common/etc/qc-tracks-mchmid.json new file mode 100644 index 0000000000..02c08e4c9c --- /dev/null +++ b/Modules/MUON/Common/etc/qc-tracks-mchmid.json @@ -0,0 +1,36 @@ +{ + "qc": { + "config": { + "database": { + "implementation": "CCDB", + "host": "ccdb-test.cern.ch:8080", + "username": "not_applicable", + "password": "not_applicable", + "name": "not_applicable" + }, + "Activity": { + "number": "42", + "type": "2" + } + }, + "tasks": { + "MUONTracks": { + "active": "true", + "className": "o2::quality_control_modules::muon::TracksTask", + "moduleName": "QcMUONCommon", + "detectorName": "GLO", + "cycleDurationSeconds": "600", + "maxNumberCycles": "-1", + "dataSource": { + "type": "direct", + "query": "trackMCH:MCH/TRACKS;trackMCHROF:MCH/TRACKROFS;trackMCHTRACKCLUSTERS:MCH/TRACKCLUSTERS;mchtrackdigits:MCH/CLUSTERDIGITS;trackMID:MID/TRACKS;trackMIDROF:MID/TRACKROFS;trackMIDTRACKCLUSTERS:MID/TRACKCLUSTERS;trackClMIDROF:MID/TRCLUSROFS;matchMCHMID:GLO/MTC_MCHMID" + }, + "taskParameters": { + "maxTracksPerTF": "600", + "GID" : "MCH,MID,MCH-MID" + }, + "location": "remote" + } + } + } +} diff --git a/Modules/MUON/Common/etc/qc-tracks-mftmch.json b/Modules/MUON/Common/etc/qc-tracks-mftmch.json new file mode 100644 index 0000000000..1f6775972e --- /dev/null +++ b/Modules/MUON/Common/etc/qc-tracks-mftmch.json @@ -0,0 +1,36 @@ +{ + "qc": { + "config": { + "database": { + "implementation": "CCDB", + "host": "ccdb-test.cern.ch:8080", + "username": "not_applicable", + "password": "not_applicable", + "name": "not_applicable" + }, + "Activity": { + "number": "42", + "type": "2" + } + }, + "tasks": { + "MUONTracks": { + "active": "true", + "className": "o2::quality_control_modules::muon::TracksTask", + "moduleName": "QcMUONCommon", + "detectorName": "GLO", + "cycleDurationSeconds": "600", + "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;fwdtracks:GLO/GLFWD" + }, + "taskParameters": { + "maxTracksPerTF": "600", + "GID" : "MCH,MFT,MFT-MCH" + }, + "location": "remote" + } + } + } +} diff --git a/Modules/MUON/Common/etc/qc-tracks-mftmchmid.json b/Modules/MUON/Common/etc/qc-tracks-mftmchmid.json new file mode 100644 index 0000000000..0b0657adc8 --- /dev/null +++ b/Modules/MUON/Common/etc/qc-tracks-mftmchmid.json @@ -0,0 +1,36 @@ +{ + "qc": { + "config": { + "database": { + "implementation": "CCDB", + "host": "ccdb-test.cern.ch:8080", + "username": "not_applicable", + "password": "not_applicable", + "name": "not_applicable" + }, + "Activity": { + "number": "42", + "type": "2" + } + }, + "tasks": { + "MUONTracks": { + "active": "true", + "className": "o2::quality_control_modules::muon::TracksTask", + "moduleName": "QcMUONCommon", + "detectorName": "GLO", + "cycleDurationSeconds": "600", + "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", + "GID" : "MCH,MFT,MID,MFT-MCH,MCH-MID,MFT-MCH-MID" + }, + "location": "remote" + } + } + } +} diff --git a/Modules/MUON/Common/include/MUONCommon/HistPlotter.h b/Modules/MUON/Common/include/MUONCommon/HistPlotter.h new file mode 100644 index 0000000000..d82afcbeb0 --- /dev/null +++ b/Modules/MUON/Common/include/MUONCommon/HistPlotter.h @@ -0,0 +1,51 @@ +// 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. + +#ifndef QC_MODULE_MUON_COMMON_HIST_PLOTTER_H +#define QC_MODULE_MUON_COMMON_HIST_PLOTTER_H + +#include "QualityControl/ObjectsManager.h" +#include +#include +#include + +namespace o2::quality_control_modules::muon +{ + +class HistPlotter +{ + public: + HistPlotter() = default; + ~HistPlotter() = default; + + public: + struct HistInfo { + TObject* object; + std::string drawOptions; + std::string displayHints; + }; + + /** reset all histograms */ + void reset(); + + std::vector& histograms() { return mHistograms; } + + const std::vector& histograms() const { return mHistograms; } + + void publish(std::shared_ptr objectsManager); + + private: + std::vector mHistograms; +}; + +} // namespace o2::quality_control_modules::muon + +#endif diff --git a/Modules/MUON/Common/include/MUONCommon/MuonTrack.h b/Modules/MUON/Common/include/MUONCommon/MuonTrack.h new file mode 100644 index 0000000000..84923a0bbe --- /dev/null +++ b/Modules/MUON/Common/include/MUONCommon/MuonTrack.h @@ -0,0 +1,99 @@ +// 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. + +#ifndef QC_MODULE_MUON_COMMON_TRACK_H +#define QC_MODULE_MUON_COMMON_TRACK_H + +#include +#include +#include +#include +#include +#include +#include +#include + +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); + + void init(); + + ROOT::Math::PxPyPzMVector getMuonMomentum() const { return mMuonMomentum; } + ROOT::Math::PxPyPzMVector getMuonMomentumAtVertex() const { return mMuonMomentumAtVertex; } + double getP() const + { + return mMuonMomentum.P(); + } + double getDCA() const { return mDCA; } + double getPDCAMCH() const { return mPDCAMCH; } + double getRAbs() const { return mRAbs; } + double getChi2OverNDF() const { return mChi2OverNDF; } + + /// get the interaction record associated to this track + InteractionRecord getIR() const { return mIR; } + /// get the interaction record associated to the MFT track + InteractionRecord getIRMFT() const { return mIRMFT; } + /// get the interaction record associated to the MCH track + InteractionRecord getIRMCH() const { return mIRMCH; } + /// get the interaction record associated to the MID track + InteractionRecord getIRMID() const { return mIRMID; } + + /// get the interaction record associated to the MFT track + int getTrackIdMFT() const { return mTrackIdMFT; } + /// get the interaction record associated to the MCH track + int getTrackIdMCH() const { return mTrackIdMCH; } + /// get the interaction record associated to the MID track + int getTrackIdMID() const { return mTrackIdMID; } + + bool hasMFT() const { return (mTrackIdMFT >= 0); } + bool hasMCH() const { return (mTrackIdMCH >= 0); } + bool hasMID() const { return (mTrackIdMID >= 0); } + + /// get the muon sign + short getSign() const { return mSign; } + + 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::mch::TrackParam mTrackParameters; + o2::mch::TrackParam mTrackParametersMCH; + + ROOT::Math::PxPyPzMVector mMuonMomentum; + ROOT::Math::PxPyPzMVector mMuonMomentumAtVertex; + + float mDCA{ 0 }; + float mPDCAMCH{ 0 }; + float mRAbs{ 0 }; + float mChi2OverNDF{ 0 }; + + InteractionRecord mIR{}; ///< associated interaction record + InteractionRecord mIRMFT{}; ///< MFT interaction record + InteractionRecord mIRMCH{}; ///< MCH interaction record + InteractionRecord mIRMID{}; ///< MID interaction record + + int mTrackIdMFT{ -1 }; + int mTrackIdMCH{ -1 }; + int mTrackIdMID{ -1 }; + + short mSign; +}; + +} // namespace o2::quality_control_modules::muon + +#endif diff --git a/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h b/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h index 8c7c45ed49..9c2b29c4af 100644 --- a/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h +++ b/Modules/MUON/Common/include/MUONCommon/TrackPlotter.h @@ -12,16 +12,21 @@ #ifndef QC_MODULE_MUON_COMMON_TRACK_PLOTTER_H #define QC_MODULE_MUON_COMMON_TRACK_PLOTTER_H -#include "MCHGeometryTransformer/Transformations.h" -#include +#include "MUONCommon/HistPlotter.h" +#include "MUONCommon/MuonTrack.h" + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include + #include #include + #include #include #include #include #include - +/* namespace o2::mch { class Cluster; @@ -33,47 +38,28 @@ class Digit; namespace o2::dataformats { class TrackMCHMID; +class GlobalFwdTrack; } -class TH1F; +*/ +using GID = o2::dataformats::GlobalTrackID; namespace o2::quality_control_modules::muon { -class TrackPlotter +class TrackPlotter : public HistPlotter { public: - TrackPlotter(o2::mch::geo::TransformationCreator transformation, int maxTracksPerTF); + TrackPlotter(int maxTracksPerTF, GID::Source source, std::string path); ~TrackPlotter() = default; public: - void fillHistograms(gsl::span rofs, - gsl::span tracks, - gsl::span clusters, - gsl::span digits); - - void fillHistograms(gsl::span rofs, - gsl::span tracks, - gsl::span clusters, - gsl::span digits, - gsl::span muonTracks); - - struct HistInfo { - TH1* histo; - std::string drawOptions; - std::string displayHints; - }; - - const std::vector& histograms() const { return mHistograms; } - - /** reset all histograms */ - void reset(); + void fillHistograms(const o2::globaltracking::RecoContainer& recoCont); private: - void fill(gsl::span rofs, - gsl::span tracks, - gsl::span clusters, - gsl::span digits, - const std::vector& selectedTracks); + /** create histograms related to tracks */ + void createTrackHistos(int maxTracksPerTF); + /** create histograms related to track pairs */ + void createTrackPairHistos(); /** create one histogram with relevant drawing options / stat box status.*/ template @@ -83,52 +69,28 @@ class TrackPlotter const char* drawOptions = "", const char* displayHints = ""); - /** create histograms related to clusters (those attached to tracks) */ - void createClusterHistos(); - /** create histograms related to tracks */ - void createTrackHistos(int maxTracksPerTF); - /** create histograms related to track pairs */ - void createTrackPairHistos(); - - /** fill histogram related to each cluster */ - void fillClusterHistos(gsl::span clusters, - gsl::span digits); - /** fill histograms related to a single track */ - bool fillTrackHistos(const o2::mch::TrackMCH& track, - gsl::span clusters, - gsl::span digits); + bool fillTrackHistos(const MuonTrack& track); /** fill histograms for track pairs */ - void fillTrackPairHistos(gsl::span tracks); - - int dsbinx(int deid, int dsid) const; - - std::unique_ptr mNofTracksPerTF; ///< number of tracks per TF - std::unique_ptr mTrackBC; ///< BC associated to the track - std::unique_ptr mTrackBCWidth; ///< BC width associated to the track - std::unique_ptr mTrackChi2OverNDF; ///< chi2/ndf for the track - std::unique_ptr mTrackDCA; ///< DCA (cm) of the track - std::unique_ptr mTrackEta; ///< eta of the track - std::unique_ptr mTrackPDCA; ///< p (GeV/c) x DCA (cm) of the track - std::unique_ptr mTrackPhi; ///< phi (in degrees) of the track - std::unique_ptr mTrackPt; ///< Pt (Gev/c^2) of the track - std::unique_ptr mTrackRAbs; ///< R at absorber end of the track - - std::unique_ptr mNofClustersPerDualSampa; //< aka cluster map - std::unique_ptr mNofClustersPerTrack; ///< number of clusters per track - std::unique_ptr mClusterBendingSizePerChamber; ///< mean cluster size in bending direction (y) per chamber - std::unique_ptr mClusterNonBendingSizePerChamber; ///< mean cluster size in non-bending direction (x) per chamber - std::unique_ptr mClusterSizePerChamber; ///< mean cluster size per chamber - std::unique_ptr mNofClustersPerChamber; ///< mean number of clusters per chamber + void fillTrackPairHistos(gsl::span tracks); + + 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> 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^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 - - o2::mch::raw::Det2ElecMapper mDet2ElecMapper; - o2::mch::raw::Solar2FeeLinkMapper mSolar2FeeLinkMapper; - - std::vector mHistograms; - o2::mch::geo::TransformationCreator mTransformation; ///< creator of local to global transformations }; template @@ -142,7 +104,7 @@ std::unique_ptr TrackPlotter::createHisto(const char* name, const char* title if (!statBox) { h->SetStats(0); } - mHistograms.emplace_back(HistInfo{ h.get(), drawOptions, displayHints }); + histograms().emplace_back(HistInfo{ h.get(), drawOptions, displayHints }); return h; } diff --git a/Modules/MUON/Common/include/MUONCommon/TracksTask.h b/Modules/MUON/Common/include/MUONCommon/TracksTask.h index 44308b9d13..231d84ab5d 100644 --- a/Modules/MUON/Common/include/MUONCommon/TracksTask.h +++ b/Modules/MUON/Common/include/MUONCommon/TracksTask.h @@ -13,6 +13,7 @@ #define QC_MODULE_MUON_COMMON_TRACKS_TASK_H #include "QualityControl/TaskInterface.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" #include #include "MUONCommon/TrackPlotter.h" #include @@ -23,9 +24,18 @@ using namespace o2::quality_control::core; namespace o2::quality_control_modules::muon { +using namespace o2::quality_control::core; +using GID = o2::dataformats::GlobalTrackID; + class TracksTask /*final*/ : public TaskInterface { public: + enum matchType : int8_t { MCH = 0, + MCHMID, + MFTMCH, + MFTMCHMID, + SIZE }; + TracksTask(); ~TracksTask() override; @@ -40,12 +50,21 @@ class TracksTask /*final*/ : public TaskInterface private: /** check whether all the expected inputs are present.*/ bool assertInputs(o2::framework::ProcessingContext& ctx); - void publish(const TrackPlotter& tp); bool getBooleanParam(const char* paramName) const; private: - std::unique_ptr mTrackPlotter; - bool mUseMatchedMCHMIDTracks{ false }; + std::map> mTrackPlotters; + std::shared_ptr mDataRequest; + o2::globaltracking::RecoContainer mRecoCont; + GID::mask_t mSrc = GID::getSourcesMask("MCH-MID"); + GID::mask_t mAllowedSources = GID::getSourcesMask("MFT,MCH,MID,MCH-MID,MFT-MCH,MFT-MCH-MID"); + + // MCH-MID + gsl::span mMCHMIDTracks; + // MFT-MCH + gsl::span mMFTMCHTracks; + // MFT-MCH-MID + gsl::span mMFTMCHMIDTracks; }; } // namespace o2::quality_control_modules::muon diff --git a/Modules/MUON/Common/src/HistPlotter.cxx b/Modules/MUON/Common/src/HistPlotter.cxx new file mode 100644 index 0000000000..e25eab4e71 --- /dev/null +++ b/Modules/MUON/Common/src/HistPlotter.cxx @@ -0,0 +1,54 @@ +// 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. + +#include "MUONCommon/HistPlotter.h" + +#include +#include + +namespace o2::quality_control_modules::muon +{ + +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); + } +} + +void HistPlotter::reset() +{ + for (auto hinfo : mHistograms) { + TH1* histo = dynamic_cast(hinfo.object); + if (histo) { + histo->Reset(); + } else { + TCanvas* c = dynamic_cast(hinfo.object); + if (c) { + TObject* obj; + TIter next(c->GetListOfPrimitives()); + while ((obj = next())) { + if (!obj->InheritsFrom("TH1")) { + continue; + } + histo = dynamic_cast(obj); + if (histo) { + histo->Reset(); + } + } + } + } + } +} + +} // namespace o2::quality_control_modules::muon diff --git a/Modules/MUON/Common/src/MuonTrack.cxx b/Modules/MUON/Common/src/MuonTrack.cxx new file mode 100644 index 0000000000..9d0e273b11 --- /dev/null +++ b/Modules/MUON/Common/src/MuonTrack.cxx @@ -0,0 +1,341 @@ +// 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. + +#include "MUONCommon/MuonTrack.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace o2::dataformats; +using TrackMFT = o2::mft::TrackMFT; +using TrackMCH = o2::mch::TrackMCH; +using TrackMID = o2::mid::Track; +using InteractionRecord = o2::InteractionRecord; + +namespace +{ + +constexpr double muonMass = 0.1056584; +constexpr double muonMass2 = muonMass * muonMass; + +static InteractionRecord getMFTTrackIR(int iTrack, const o2::globaltracking::RecoContainer& recoCont) +{ + // 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; + } + return rof.getBCData(); + } + + return InteractionRecord{}; +} + +static InteractionRecord getMIDTrackIR(int iTrack, const o2::globaltracking::RecoContainer& recoCont) +{ + // 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; + } + return rof.interactionRecord; + } + + return InteractionRecord{}; +} + +static InteractionRecord getMCHTrackIR(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.getBCData(); + } + + return InteractionRecord{}; +} + +static InteractionRecord getMCHTrackIR(const o2::mch::TrackMCH* track, const o2::globaltracking::RecoContainer& recoCont) +{ + // if the MID track is present, use the time from MID + auto tracksMCH = recoCont.getMCHTracks(); + int iMCH{ -1 }; + for (int i = 0; i < tracksMCH.size(); i++) { + if (track == (&(tracksMCH[i]))) { + iMCH = i; + break; + } + } + if (iMCH >= 0) { + return getMCHTrackIR(iMCH, recoCont); + } + + return InteractionRecord{}; +} + +static InteractionRecord getGlobalFwdTrackIR(const GlobalFwdTrack* track, const o2::globaltracking::RecoContainer& recoCont) +{ + 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 getMIDTrackIR(iMID, recoCont); + } + + 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 getMCHTrackIR(iMCH, recoCont); + } + + return InteractionRecord{}; +} + +static bool getParametersAtVertex(o2::mch::TrackParam& trackParamAtVertex, bool correctForMCS = true) +{ + bool result = false; + if (trackParamAtVertex.getZ() > o2::quality_control_modules::muon::MuonTrack::sAbsZBeg) { + result = o2::mch::TrackExtrap::extrapToZ(trackParamAtVertex, 0); + } else { + if (correctForMCS) { + result = o2::mch::TrackExtrap::extrapToVertex(trackParamAtVertex, 0.0, 0.0, 0.0, 0.0, 0.0); + } else { + result = o2::mch::TrackExtrap::extrapToVertexWithoutBranson(trackParamAtVertex, 0.0); + } + } + return result; +} + +static ROOT::Math::PxPyPzMVector getMuonMomentum(const o2::mch::TrackParam& par) +{ + return { par.px(), par.py(), par.pz(), muonMass }; +} + +static ROOT::Math::PxPyPzMVector getMuonMomentumAtVertex(const o2::mch::TrackParam& par) +{ + o2::mch::TrackParam trackParamAtVertex = par; + bool result = getParametersAtVertex(trackParamAtVertex); + if (!result) { + std::cerr << "Track extrap failed\n"; + return ROOT::Math::PxPyPzMVector(); + } + + double px = trackParamAtVertex.px(); + double py = trackParamAtVertex.py(); + double pz = trackParamAtVertex.pz(); + return { px, py, pz, muonMass }; +} + +static float getDCA(const o2::mch::TrackParam& par) +{ + o2::mch::TrackParam trackParamAtDCA = par; + bool result = getParametersAtVertex(trackParamAtDCA, false); + if (!result) { + std::cerr << "Track extrap failed\n"; + return 0; + } + + double dcaX = trackParamAtDCA.getBendingCoor(); + double dcaY = trackParamAtDCA.getNonBendingCoor(); + return std::sqrt(dcaX * dcaX + dcaY * dcaY); +} + +static float getPDCA(const o2::mch::TrackParam& par) +{ + auto p = par.p(); + auto dca = getDCA(par); + return (p * dca); +} + +static float getRAbsMCH(const o2::mch::TrackParam& par) +{ + o2::mch::TrackParam trackParamAtAbs = par; + if (!o2::mch::TrackExtrap::extrapToZ(trackParamAtAbs, o2::quality_control_modules::muon::MuonTrack::sAbsZEnd)) { + return 0; + } + double xAbs = trackParamAtAbs.getNonBendingCoor(); + double yAbs = trackParamAtAbs.getBendingCoor(); + return std::sqrt(xAbs * xAbs + yAbs * yAbs); +} + +static o2::mch::TrackParam forwardTrackToMCHTrack(const o2::track::TrackParFwd& 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 + +//_________________________________________________________________________________________________________ + +namespace o2::quality_control_modules::muon +{ + +MuonTrack::MuonTrack(const o2::mch::TrackMCH* track, const o2::globaltracking::RecoContainer& recoCont) +{ + mChi2OverNDF = track->getChi2OverNDF(); + + mIR = getMCHTrackIR(track, recoCont); + mIRMCH = mIR; + + mTrackParameters.setZ(track->getZ()); + mTrackParameters.setParameters(track->getParameters()); + + mTrackParametersMCH.setZ(track->getZ()); + mTrackParametersMCH.setParameters(track->getParameters()); + + init(); +} + +MuonTrack::MuonTrack(const TrackMCHMID* track, const o2::globaltracking::RecoContainer& recoCont) +{ + auto tracksMCH = recoCont.getMCHTracks(); + auto tracksMID = recoCont.getMIDTracks(); + + 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())); + } + if (iMID >= 0 && iMID >= tracksMID.size()) { + throw std::length_error(fmt::format("[MuonTrackImpl] bad MID track index: iMID={} tracksMID.size()={}", iMID, tracksMID.size())); + } + + mTrackIdMCH = iMCH; + mTrackIdMID = iMID; + + if (iMCH >= 0) { + // mTrackMCH = &(tracksMCH[iMCH]); + mIRMCH = getMCHTrackIR(iMCH, recoCont); + } + if (iMID >= 0) { + // mTrackMID = &(tracksMID[iMID]); + mIRMID = getMIDTrackIR(iMID, recoCont); + } + + mIR = track->getIR(); + + auto& trackMCH = tracksMCH[iMCH]; + mChi2OverNDF = trackMCH.getChi2OverNDF(); + + mTrackParameters.setZ(trackMCH.getZ()); + mTrackParameters.setParameters(trackMCH.getParameters()); + + mTrackParametersMCH.setZ(trackMCH.getZ()); + mTrackParametersMCH.setParameters(trackMCH.getParameters()); + + init(); +} + +MuonTrack::MuonTrack(const GlobalFwdTrack* track, const o2::globaltracking::RecoContainer& recoCont) : mTrackParameters(forwardTrackToMCHTrack(*track)) +{ + auto tracksMFT = recoCont.getMFTTracks(); + auto tracksMCH = recoCont.getMCHTracks(); + auto tracksMID = recoCont.getMIDTracks(); + + auto iMFT = track->getMFTTrackID(); + 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())); + } + if (iMCH >= 0 && iMCH >= tracksMCH.size()) { + throw std::length_error(fmt::format("[MuonTrack(GlobalFwdTrack)] bad MCH track index: iMCH={} tracksMCH.size()={}", iMCH, tracksMCH.size())); + } + if (iMID >= 0 && iMID >= tracksMID.size()) { + throw std::length_error(fmt::format("[MuonTrack(GlobalFwdTrack)] bad MID track index: iMID={} tracksMID.size()={}", iMID, tracksMID.size())); + } + + mTrackIdMFT = iMFT; + mTrackIdMCH = iMCH; + mTrackIdMID = iMID; + + if (iMFT >= 0) { + mIRMFT = getMFTTrackIR(iMFT, recoCont); + } + if (iMCH >= 0) { + auto& trackMCH = tracksMCH[iMCH]; + mTrackParametersMCH.setZ(trackMCH.getZ()); + mTrackParametersMCH.setParameters(trackMCH.getParameters()); + mIRMCH = getMCHTrackIR(iMCH, recoCont); + } + if (iMID >= 0) { + mIRMID = getMIDTrackIR(iMID, recoCont); + } + + mIR = ::getGlobalFwdTrackIR(track, recoCont); + + mChi2OverNDF = track->getTrackChi2(); + + init(); +} + +void MuonTrack::init() +{ + mSign = mTrackParameters.getCharge(); + + mMuonMomentum = ::getMuonMomentum(mTrackParameters); + mMuonMomentumAtVertex = ::getMuonMomentumAtVertex(mTrackParameters); + + mDCA = ::getDCA(mTrackParameters); + mPDCAMCH = ::getPDCA(mTrackParametersMCH); + mRAbs = getRAbsMCH(mTrackParametersMCH); +} + +} // namespace o2::quality_control_modules::muon diff --git a/Modules/MUON/Common/src/TrackPlotter.cxx b/Modules/MUON/Common/src/TrackPlotter.cxx index a9dba1086c..93028ce756 100644 --- a/Modules/MUON/Common/src/TrackPlotter.cxx +++ b/Modules/MUON/Common/src/TrackPlotter.cxx @@ -11,31 +11,19 @@ #include "MUONCommon/TrackPlotter.h" -#include "CommonConstants/LHCConstants.h" -#include -#include -#include #include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include namespace { -constexpr double muonMass = 0.1056584; -constexpr double muonMass2 = muonMass * muonMass; - static void setXAxisLabels(TProfile* h) { TAxis* axis = h->GetXaxis(); @@ -45,193 +33,93 @@ static void setXAxisLabels(TProfile* h) } } -uint16_t computeDsBinX(int feeId, int linkId, int elinkId) -{ - constexpr uint64_t maxLinkId = 12; - constexpr uint64_t maxElinkId = 40; - - int v = feeId * maxLinkId * maxElinkId + - (linkId % maxLinkId) * maxElinkId + elinkId + 1; - return static_cast(v & 0xFFFF); -} - -std::array getClustersPerChamber(gsl::span clusters) -{ - std::array clustersPerChamber; - clustersPerChamber.fill(0); - for (const auto& cluster : clusters) { - int chamberId = cluster.getChamberId(); - clustersPerChamber[chamberId]++; - } - return clustersPerChamber; -} - } // namespace +using namespace o2::dataformats; + namespace o2::quality_control_modules::muon { -TrackPlotter::TrackPlotter(o2::mch::geo::TransformationCreator transformation, int maxTracksPerTF) : mTransformation(transformation) +TrackPlotter::TrackPlotter(int maxTracksPerTF, GID::Source source, std::string path) : mSrc(source), mPath(path) { - createClusterHistos(); createTrackHistos(maxTracksPerTF); createTrackPairHistos(); - mDet2ElecMapper = o2::mch::raw::createDet2ElecMapper(); - mSolar2FeeLinkMapper = o2::mch::raw::createSolar2FeeLinkMapper(); -} - -void TrackPlotter::createClusterHistos() -{ - mNofClustersPerTrack = createHisto("ClustersPerTrack", "Number of clusters per track;Mean number of clusters per track", 30, 0, 30); - mNofClustersPerDualSampa = createHisto("ClustersPerDualSampa", "Number of clusters per dual sampa;Number of clusters per DS", 30720, 0, 30719); - - mNofClustersPerChamber = createHisto("ClustersPerChamber", "Clusters per chamber;;Number of clusters", 10, 1, 11); - setXAxisLabels(mNofClustersPerChamber.get()); - mClusterSizePerChamber = createHisto("ClusterSizePerChamber", "Cluster size per chamber;;Mean number of pads per cluster", 10, 1, 11); - mClusterBendingSizePerChamber = createHisto("ClusterBendingSizePerChamber", "Cluster size in bending direction (y) per chamber;;Mean number of pads per cluster", 10, 1, 11); - mClusterNonBendingSizePerChamber = createHisto("ClusterNonBendingSizePerChamber", "Cluster size in non-bending direction (x) per chamber;;Mean number of pads per cluster", 10, 1, 11); - setXAxisLabels(mClusterSizePerChamber.get()); - setXAxisLabels(mClusterBendingSizePerChamber.get()); - setXAxisLabels(mClusterNonBendingSizePerChamber.get()); } 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 = createHisto("TracksPerTF", "Number of tracks per TimeFrame;Number of tracks per TF", maxTracksPerTF, 0, maxTracksPerTF, true, "logy"); - - mTrackDCA = createHisto("TrackDCA", "Track DCA;DCA (cm)", 500, 0, 500); - mTrackPDCA = createHisto("TrackPDCA", "Track p#timesDCA;p#timesDCA (GeVcm/c)", 5000, 0, 5000); - mTrackPt = createHisto("TrackPt", "Track p_{T};p_{T} (GeV/c)", 300, 0, 30, false, "logy"); - mTrackEta = createHisto("TrackEta", "Track #eta;#eta", 200, -4.5, -2); - mTrackPhi = createHisto("TrackPhi", "Track #phi;#phi (deg)", 360, 0, 360); - mTrackRAbs = createHisto("TrackRAbs", "Track R_{abs};R_{abs} (cm)", 1000, 0, 100); - mTrackBC = createHisto("TrackBC", "Track BC;BC", o2::constants::lhc::LHCMaxBunches, 0, o2::constants::lhc::LHCMaxBunches); - mTrackBCWidth = createHisto("TrackBCWidth", "Track BCWidth;BC Width", 400, 0, 400); - mTrackChi2OverNDF = createHisto("TrackChi2OverNDF", "Track #chi^{2}/ndf;#chi^{2}/ndf", 500, 0, 50); -} + 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); -void TrackPlotter::createTrackPairHistos() -{ - mMinv = createHisto("Minv", "#mu^{+}#mu^{-} invariant mass;M_{#mu^{+}#mu^{-}} (GeV/c^{2})", 300, 0, 6); -} + 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); -int TrackPlotter::dsbinx(int deid, int dsid) const -{ - o2::mch::raw::DsDetId det{ deid, dsid }; - auto elec = mDet2ElecMapper(det); - if (!elec.has_value()) { - std::cerr << "mapping is wrong somewhere..."; - return -1; - } - auto eLinkId = elec->elinkId(); - auto solarId = elec->solarId(); - auto s2f = mSolar2FeeLinkMapper(solarId); - if (!s2f.has_value()) { - std::cerr << "mapping is wrong somewhere..."; - return -1; - } - auto feeId = s2f->feeId(); - auto linkId = s2f->linkId(); + 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"); - return computeDsBinX(feeId, linkId, eLinkId); -} + 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); -ROOT::Math::PxPyPzMVector getMomentum4D(const o2::mch::TrackParam& trackParam) -{ - double px = trackParam.px(); - double py = trackParam.py(); - double pz = trackParam.pz(); - return { px, py, pz, muonMass }; -} + 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); -ROOT::Math::PxPyPzMVector getMomentum4D(const o2::mch::TrackMCH& track) -{ - o2::mch::TrackParam trackParamAtVertex(track.getZ(), track.getParameters()); - double vz = 0.0; - if (!o2::mch::TrackExtrap::extrapToVertex(trackParamAtVertex, 0.0, 0.0, 0.0, 0.0, 0.0)) { - std::cerr << "Track extrap failed\n"; - return { 0, 0, 0, 0 }; - } - return getMomentum4D(trackParamAtVertex); -} + 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); -namespace -{ -struct PadSize { - double dx, dy; -}; -const bool operator<(const PadSize& s1, const PadSize& s2) -{ - if (s1.dx == s2.dx) { - return s1.dy < s2.dy; - } - return s1.dx < s2.dx; -}; -} // namespace + mTrackChi2OverNDF[0] = createHisto(TString::Format("%sPositive/TrackChi2OverNDF", mPath.c_str()), "Track #chi^{2}/ndf (+);#chi^{2}/ndf", 500, 0, 50); + mTrackChi2OverNDF[1] = createHisto(TString::Format("%sNegative/TrackChi2OverNDF", mPath.c_str()), "Track #chi^{2}/ndf (-);#chi^{2}/ndf", 500, 0, 50); + mTrackChi2OverNDF[2] = createHisto(TString::Format("%sTrackChi2OverNDF", mPath.c_str()), "Track #chi^{2}/ndf;#chi^{2}/ndf", 500, 0, 50); -void TrackPlotter::fillClusterHistos(gsl::span clusters, - gsl::span digits) -{ + 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); - auto padPosCompare = [](double a, double b) { - constexpr double smallestPadSize = 0.21; - if (std::fabs(a - b) < smallestPadSize) { - return false; - } - return a < b; - }; - - for (const auto& cluster : clusters) { - int deId = cluster.getDEId(); - const auto& seg = o2::mch::mapping::segmentation(deId); - int b, nb; - o2::math_utils::Point3D global{ cluster.getX(), - cluster.getY(), cluster.getZ() }; - auto t = mTransformation(deId).Inverse(); - auto local = t(global); - - seg.findPadPairByPosition(local.X(), local.Y(), b, nb); - if (b >= 0) { - int dsId = seg.padDualSampaId(b); - mNofClustersPerDualSampa->Fill(dsbinx(deId, dsId)); + 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 (nb >= 0) { - int dsId = seg.padDualSampaId(nb); - mNofClustersPerDualSampa->Fill(dsbinx(deId, dsId)); + if (mSrc == GID::MCHMID) { + titleStr = "(MID-MCH)"; } - int chamberId = cluster.getChamberId(); - mClusterSizePerChamber->Fill(chamberId + 1, cluster.nDigits); - std::set padSizes; - std::set xpos(padPosCompare); - std::set ypos(padPosCompare); - for (int dix = cluster.firstDigit; dix < cluster.firstDigit + cluster.nDigits; ++dix) { - const auto& digit = digits[dix]; - auto padid = digit.getPadID(); - PadSize padSize{ seg.padSizeX(padid), - seg.padSizeY(padid) }; - padSizes.emplace(padSize); - if (seg.isBendingPad(padid)) { - ypos.emplace(seg.padPositionY(padid)); - } else { - xpos.emplace(seg.padPositionX(padid)); - } - } - mClusterBendingSizePerChamber->Fill(chamberId + 1, ypos.size()); - mClusterNonBendingSizePerChamber->Fill(chamberId + 1, xpos.size()); + 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" }); } } -void TrackPlotter::fillTrackPairHistos(gsl::span tracks) +void TrackPlotter::createTrackPairHistos() +{ + mMinv = createHisto(TString::Format("%sMinv", mPath.c_str()), "#mu^{+}#mu^{-} invariant mass;M_{#mu^{+}#mu^{-}} (GeV/c^{2})", 300, 0, 6); +} + +void TrackPlotter::fillTrackPairHistos(gsl::span tracks) { if (tracks.size() > 1) { for (auto i = 0; i < tracks.size(); i++) { - auto ti = getMomentum4D(tracks[i]); + auto ti = tracks[i].getMuonMomentumAtVertex(); for (auto j = i + 1; j < tracks.size(); j++) { if (tracks[i].getSign() == tracks[j].getSign()) { continue; } - auto tj = getMomentum4D(tracks[j]); + auto dt = (tracks[i].getIR() - tracks[j].getIR()).bc2ns(); + if (std::abs(dt) > 1000) { + continue; + } + auto tj = tracks[j].getMuonMomentumAtVertex(); auto p = ti + tj; mMinv->Fill(p.M()); } @@ -239,139 +127,112 @@ void TrackPlotter::fillTrackPairHistos(gsl::span tracks } } -bool TrackPlotter::fillTrackHistos(const o2::mch::TrackMCH& track, - gsl::span clusters, - gsl::span digits) +bool TrackPlotter::fillTrackHistos(const MuonTrack& track) { - mNofClustersPerTrack->Fill(track.getNClusters()); - mTrackChi2OverNDF->Fill(track.getChi2OverNDF()); - - const auto trackClusters = clusters.subspan(track.getFirstClusterIdx(), track.getNClusters()); - fillClusterHistos(trackClusters, digits); + int q = (track.getSign() < 0) ? 1 : 0; - auto clustersPerChamber = getClustersPerChamber(trackClusters); + mTrackBC->Fill(track.getIR().bc); - for (auto i = 0; i < clustersPerChamber.size(); i++) { - mNofClustersPerChamber->Fill(i + 1, clustersPerChamber[i]); + switch (mSrc) { + case GID::MCHMID: { + auto dt = track.getIRMID().toLong() - track.getIRMCH().toLong(); + mTrackDT->Fill(dt); + break; + } + case GID::MFTMCH: { + auto dt = track.getIRMFT().toLong() - track.getIRMCH().toLong(); + mTrackDT->Fill(dt); + 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); + } + break; + } + default: + break; } - auto p = track.getP(); // uncorrected p - - o2::mch::TrackParam trackParamAtDCA(track.getZ(), track.getParameters()); - if (!o2::mch::TrackExtrap::extrapToVertexWithoutBranson(trackParamAtDCA, 0.0)) { - return false; - } + double dca = track.getDCA(); + mTrackDCA[q]->Fill(dca); + mTrackDCA[2]->Fill(dca); - o2::mch::TrackParam trackParamAtOrigin(track.getZ(), track.getParameters()); - if (!o2::mch::TrackExtrap::extrapToVertex(trackParamAtOrigin, 0.0, 0.0, 0.0, 0.0, 0.0)) { - return false; - } - double dcaX = trackParamAtDCA.getBendingCoor(); - double dcaY = trackParamAtDCA.getNonBendingCoor(); - double dca = std::sqrt(dcaX * dcaX + dcaY * dcaY); - mTrackDCA->Fill(dca); - mTrackPDCA->Fill(p * dca); + double pdca = track.getPDCAMCH(); + mTrackPDCA[q]->Fill(pdca); + mTrackPDCA[2]->Fill(pdca); - auto muon = getMomentum4D(trackParamAtOrigin); + auto muon = track.getMuonMomentumAtVertex(); - mTrackEta->Fill(muon.eta()); - mTrackPhi->Fill(muon.phi() * TMath::RadToDeg() + 180); - mTrackPt->Fill(muon.pt()); + 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()); - o2::mch::TrackExtrap::extrapToZ(trackParamAtOrigin, -505.); - double xAbs = trackParamAtOrigin.getNonBendingCoor(); - double yAbs = trackParamAtOrigin.getBendingCoor(); - auto rAbs = std::sqrt(xAbs * xAbs + yAbs * yAbs); - mTrackRAbs->Fill(rAbs); + auto rAbs = track.getRAbs(); + mTrackRAbs[q]->Fill(rAbs); + mTrackRAbs[2]->Fill(rAbs); return true; } -void TrackPlotter::fillHistograms(gsl::span rofs, - gsl::span tracks, - gsl::span clusters, - gsl::span digits, - gsl::span muonTracks) -{ - - if (muonTracks.size() == 0) { - return; - } - - std::vector matchedTracks; - matchedTracks.resize(tracks.size(), false); - - for (const auto& mt : muonTracks) { - auto ix = mt.getMCHRef().getIndex(); - matchedTracks[ix] = true; - } - fill(rofs, tracks, clusters, digits, - matchedTracks); -} -void TrackPlotter::fillHistograms(gsl::span rofs, - gsl::span tracks, - gsl::span clusters, - gsl::span digits) +void TrackPlotter::fillHistograms(const o2::globaltracking::RecoContainer& recoCont) { - std::vector selectedTracks; - selectedTracks.resize(tracks.size(), true); - fill(rofs, tracks, clusters, digits, selectedTracks); -} - -void TrackPlotter::fill(gsl::span rofs, - gsl::span tracks, - gsl::span clusters, - gsl::span digits, - const std::vector& selectedTracks) -{ - - auto ntracks = std::count_if(selectedTracks.begin(), selectedTracks.end(), - [](bool v) { return v; }); - - mNofTracksPerTF->Fill(ntracks); - - for (const auto& rof : rofs) { - for (auto ix = rof.getFirstIdx(); ix <= rof.getLastIdx(); ix++) { - if (selectedTracks[ix]) { - mTrackBC->Fill(rof.getBCData().bc); - mTrackBCWidth->Fill(rof.getBCWidth()); + std::vector muonTracks; + if (mSrc == GID::MCH) { + auto tracksMCH = recoCont.getMCHTracks(); + for (auto& t : tracksMCH) { + muonTracks.emplace_back(&t, recoCont); + } + } + if (mSrc == GID::MFTMCH || mSrc == GID::MFTMCHMID) { + auto tracksFwd = recoCont.getGlobalFwdTracks(); + for (auto& t : tracksFwd) { + MuonTrack mt(&t, recoCont); + // skip tracks without MID if full matching is requested + if (mSrc == GID::MFTMCHMID && !mt.hasMID()) { + continue; } + muonTracks.emplace_back(&t, recoCont); + } + } + if (mSrc == GID::MCHMID) { + auto tracksMCHMID = recoCont.getMCHMIDMatches(); + for (auto& t : tracksMCHMID) { + muonTracks.emplace_back(&t, recoCont); } } - decltype(tracks.size()) nok{ 0 }; + int nPos{ 0 }; + int nNeg{ 0 }; - for (auto ix = 0; ix < tracks.size(); ix++) { - if (selectedTracks[ix]) { - bool ok = fillTrackHistos(tracks[ix], clusters, digits); - if (ok) { - ++nok; - } + for (auto& t : muonTracks) { + if (t.getSign() < 0) { + nNeg += 1; + } else { + nPos += 1; } } - if (nok != ntracks) { - std::cout << "Could only extrapolate " << nok << " tracks over " << ntracks << "\n"; - } + mNofTracksPerTF[0]->Fill(nPos); + mNofTracksPerTF[1]->Fill(nNeg); + mNofTracksPerTF[2]->Fill(muonTracks.size()); - for (const auto& rof : rofs) { - if (rof.getNEntries() > 0) { - std::vector rtracks; - for (auto ix = rof.getFirstIdx(); ix <= rof.getLastIdx(); ix++) { - if (selectedTracks[ix]) { - rtracks.emplace_back(tracks[ix]); - } - } - fillTrackPairHistos(rtracks); + decltype(muonTracks.size()) nok{ 0 }; + + for (const auto& mt : muonTracks) { + bool ok = fillTrackHistos(mt); + if (ok) { + ++nok; } } -} -void TrackPlotter::reset() -{ - for (auto hinfo : mHistograms) { - hinfo.histo->Reset(); - } + fillTrackPairHistos(muonTracks); } } // namespace o2::quality_control_modules::muon diff --git a/Modules/MUON/Common/src/TracksTask.cxx b/Modules/MUON/Common/src/TracksTask.cxx index e681bf1fc1..ba649ad0c9 100644 --- a/Modules/MUON/Common/src/TracksTask.cxx +++ b/Modules/MUON/Common/src/TracksTask.cxx @@ -22,6 +22,7 @@ #include #include #include +#include #include namespace o2::quality_control_modules::muon @@ -47,34 +48,47 @@ void TracksTask::initialize(o2::framework::InitContext& /*ic*/) { ILOG(Info, Support) << "initialize TracksTask" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. + 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"); } - auto transformation = o2::mch::geo::transformationFromTGeoManager(*gGeoManager); - double maxTracksPerTF = 400; if (auto param = mCustomParameters.find("maxTracksPerTF"); param != mCustomParameters.end()) { maxTracksPerTF = std::stof(param->second); } - mUseMatchedMCHMIDTracks = getBooleanParam("matchedMCHMIDTracks"); - - mTrackPlotter = std::make_unique(transformation, maxTracksPerTF); - - publish(*(mTrackPlotter.get())); -} - -void TracksTask::publish(const TrackPlotter& tp) -{ - auto hinfos = tp.histograms(); + ILOG(Info, Support) << "loading sources" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. + // For track type selection + if (auto param = mCustomParameters.find("GID"); param != mCustomParameters.end()) { + ILOG(Info, Devel) << "[TOTO] Custom parameter - GID (= sources by user): " << param->second << ENDM; + ILOG(Info, Devel) << "[TOTO] Allowed Sources = " << mAllowedSources << ENDM; + mSrc = mAllowedSources & GID::getSourcesMask(param->second); + ILOG(Info, Devel) << "Final requested sources = " << mSrc << ENDM; + } - for (auto hinfo : hinfos) { - getObjectsManager()->startPublishing(hinfo.histo); - getObjectsManager()->setDefaultDrawOptions(hinfo.histo, hinfo.drawOptions); - getObjectsManager()->setDisplayHint(hinfo.histo, hinfo.displayHints); + ILOG(Info, Devel) << "[TOTO] Debug: Will do DataRequest" << ENDM; + auto srcFixed = mSrc; + if (srcFixed[GID::Source::MFTMCHMID] == 1) { + srcFixed.reset(GID::Source::MFTMCHMID); + srcFixed.set(GID::Source::MFTMCH); } + mDataRequest = std::make_shared(); + mDataRequest->requestTracks(srcFixed, false); + + auto createPlotter = [&](GID::Source source, std::string path) { + if (mSrc[source] == 1) { + std::cout << "[TOTO] Creating plotter for path " << path << std::endl; + mTrackPlotters[source] = std::make_unique(maxTracksPerTF, source, path); + mTrackPlotters[source]->publish(getObjectsManager()); + } + }; + + createPlotter(GID::Source::MCH, "MCH/"); + createPlotter(GID::Source::MCHMID, "MCH-MID/"); + createPlotter(GID::Source::MFTMCH, "MFT-MCH/"); + createPlotter(GID::Source::MFTMCHMID, "MFT-MCH-MID/"); } void TracksTask::startOfActivity(Activity& activity) @@ -89,15 +103,15 @@ void TracksTask::startOfCycle() bool TracksTask::assertInputs(o2::framework::ProcessingContext& ctx) { - if (!ctx.inputs().isValid("mchtracks")) { + if (!ctx.inputs().isValid("trackMCH")) { ILOG(Info, Support) << "no mch tracks available on input" << ENDM; return false; } - if (!ctx.inputs().isValid("mchtrackrofs")) { + if (!ctx.inputs().isValid("trackMCHROF")) { ILOG(Info, Support) << "no mch track rofs available on input" << ENDM; return false; } - if (!ctx.inputs().isValid("mchtrackclusters")) { + if (!ctx.inputs().isValid("trackMCHTRACKCLUSTERS")) { ILOG(Info, Support) << "no mch track clusters available on input" << ENDM; return false; } @@ -105,31 +119,71 @@ bool TracksTask::assertInputs(o2::framework::ProcessingContext& ctx) ILOG(Info, Support) << "no mch track digits available on input" << ENDM; return false; } - if (mUseMatchedMCHMIDTracks) { - if (!ctx.inputs().isValid("muontracks")) { + if (mSrc[GID::Source::MCHMID] == 1) { + if (!ctx.inputs().isValid("matchMCHMID")) { ILOG(Info, Support) << "no muon (mch+mid) track available on input" << ENDM; return false; } } + if (mSrc[GID::Source::MFTMCH] == 1) { + if (!ctx.inputs().isValid("fwdtracks")) { + ILOG(Info, Support) << "no muon (mch+mft) track available on input" << ENDM; + return false; + } + } + if (mSrc[GID::Source::MFTMCHMID] == 1) { + if (!ctx.inputs().isValid("fwdtracks")) { + ILOG(Info, Support) << "no muon (mch+mft+mid) track available on input" << ENDM; + return false; + } + } return true; } void TracksTask::monitorData(o2::framework::ProcessingContext& ctx) { + ILOG(Info, Devel) << "Debug: MonitorData" << ENDM; + + mRecoCont.collectData(ctx, *mDataRequest.get()); + + ILOG(Info, Devel) << "Debug: Collected data" << ENDM; + if (!assertInputs(ctx)) { return; } - auto tracks = ctx.inputs().get>("mchtracks"); - auto rofs = ctx.inputs().get>("mchtrackrofs"); - auto clusters = ctx.inputs().get>("mchtrackclusters"); + ILOG(Info, Devel) << "Debug: Asserted inputs" << ENDM; + + auto tracks = mRecoCont.getMCHTracks(); + auto rofs = mRecoCont.getMCHTracksROFRecords(); + auto clusters = mRecoCont.getMCHTrackClusters(); auto digits = ctx.inputs().get>("mchtrackdigits"); - if (mUseMatchedMCHMIDTracks) { - auto muonTracks = ctx.inputs().get>("muontracks"); - mTrackPlotter->fillHistograms(rofs, tracks, clusters, digits, muonTracks); - } else { - mTrackPlotter->fillHistograms(rofs, tracks, clusters, digits); + if (mSrc[GID::MCH] == 1) { + ILOG(Info, Devel) << "Debug: MCH requested" << ENDM; + if (true || mRecoCont.isTrackSourceLoaded(GID::MCH)) { + ILOG(Info, Devel) << "Debug: MCH source loaded" << ENDM; + mTrackPlotters[GID::MCH]->fillHistograms(mRecoCont); + } + } + if (mSrc[GID::MCHMID] == 1) { + ILOG(Info, Devel) << "Debug: MCHMID requested" << ENDM; + if (true || mRecoCont.isMatchSourceLoaded(GID::MCHMID)) { + ILOG(Info, Devel) << "Debug: MCHMID source loaded" << ENDM; + mTrackPlotters[GID::MCHMID]->fillHistograms(mRecoCont); + } + } + if (mSrc[GID::MFTMCH] == 1) { + ILOG(Info, Devel) << "Debug: MFTMCH requested" << ENDM; + if (true || mRecoCont.isTrackSourceLoaded(GID::MFTMCH)) { + mTrackPlotters[GID::MFTMCH]->fillHistograms(mRecoCont); + } + } + if (mSrc[GID::MFTMCHMID] == 1) { + ILOG(Info, Devel) << "Debug: MFTMCHMID requested" << ENDM; + if (true || mRecoCont.isTrackSourceLoaded(GID::MFTMCH)) { + mTrackPlotters[GID::MFTMCHMID]->fillHistograms(mRecoCont); + } } } @@ -146,7 +200,9 @@ void TracksTask::endOfActivity(Activity& /*activity*/) void TracksTask::reset() { ILOG(Info, Support) << "reset" << ENDM; - mTrackPlotter->reset(); + for (auto& p : mTrackPlotters) { + p.second->reset(); + } } } // namespace o2::quality_control_modules::muon