diff --git a/Framework/script/RepoCleaner/ReleaseNotes.md b/Framework/script/RepoCleaner/ReleaseNotes.md index 6c2e7890b8..e70adb5e73 100644 --- a/Framework/script/RepoCleaner/ReleaseNotes.md +++ b/Framework/script/RepoCleaner/ReleaseNotes.md @@ -1,5 +1,10 @@ # Release notes +1.7 +- [QC-1144] 1_per_run : Consider RunNumber=0 as no run number (#2238) +- [QC-1142 ]fix object preservation for 1_per_run policy (#2228) +- [QC-996] policy multiple_per_run can delete first and last (#1921) + 1.6 - add option to set adjustableEOV when updating validity - [QC-986] Do not touch the validity any more in rules 1_per_hour and production diff --git a/Framework/script/RepoCleaner/setup.py b/Framework/script/RepoCleaner/setup.py index 1ba19609eb..fe2720f0e7 100644 --- a/Framework/script/RepoCleaner/setup.py +++ b/Framework/script/RepoCleaner/setup.py @@ -5,7 +5,7 @@ setup( name='qcrepocleaner', - version='1.6', + version='1.7', author='Barthelemy von Haller', author_email='bvonhall@cern.ch', url='https://gitlab.cern.ch/AliceO2Group/QualityControl/Framework/script/RepoCleaner', diff --git a/Framework/script/updateCcdbConsul.sh b/Framework/script/updateCcdbConsul.sh index 4324522307..e6e290f723 100755 --- a/Framework/script/updateCcdbConsul.sh +++ b/Framework/script/updateCcdbConsul.sh @@ -49,6 +49,11 @@ for ((nodeIndex = 0; nodeIndex < ${#HEAD_NODES[@]}; nodeIndex++)); do # for each file for file in "${array_files[@]}"; do echo "file: $file" + # avoid touching the repo cleaner file + if [[ $file == *repoCleanerConfig.yaml* ]]; then + echo " it is the repo cleaner config file, we skip it" + continue + fi # download local_file=$(basename $file) diff --git a/Framework/src/AggregatorRunnerFactory.cxx b/Framework/src/AggregatorRunnerFactory.cxx index a2d44f1a56..8e3aa3eb06 100644 --- a/Framework/src/AggregatorRunnerFactory.cxx +++ b/Framework/src/AggregatorRunnerFactory.cxx @@ -77,7 +77,10 @@ AggregatorRunnerConfig AggregatorRunnerFactory::extractRunnerConfig(const core:: commonSpec.activityPeriodName, commonSpec.activityPassName, commonSpec.activityProvenance, - { commonSpec.activityStart, commonSpec.activityEnd } + { commonSpec.activityStart, commonSpec.activityEnd }, + commonSpec.activityBeamType, + commonSpec.activityPartitionName, + commonSpec.activityFillNumber }; return { diff --git a/Framework/src/CheckRunnerFactory.cxx b/Framework/src/CheckRunnerFactory.cxx index fe6f2a41a2..d442b4aacf 100644 --- a/Framework/src/CheckRunnerFactory.cxx +++ b/Framework/src/CheckRunnerFactory.cxx @@ -87,7 +87,10 @@ CheckRunnerConfig CheckRunnerFactory::extractConfig(const CommonSpec& commonSpec commonSpec.activityPeriodName, commonSpec.activityPassName, commonSpec.activityProvenance, - { commonSpec.activityStart, commonSpec.activityEnd } + { commonSpec.activityStart, commonSpec.activityEnd }, + commonSpec.activityBeamType, + commonSpec.activityPartitionName, + commonSpec.activityFillNumber }; return { commonSpec.database, diff --git a/Modules/CTP/include/CTP/CTPTrendingTask.h b/Modules/CTP/include/CTP/CTPTrendingTask.h index 954af84ca8..65f9432088 100644 --- a/Modules/CTP/include/CTP/CTPTrendingTask.h +++ b/Modules/CTP/include/CTP/CTPTrendingTask.h @@ -59,7 +59,7 @@ class CTPTrendingTask : public PostProcessingInterface void trendValues(const Trigger& t, quality_control::repository::DatabaseInterface& qcdb); void generatePlots(); - o2::ctp::CTPConfiguration* mCTPconfig; + o2::ctp::CTPConfiguration* mCTPconfig{ nullptr }; TrendingConfigCTP mConfig; MetaData mMetaData; UInt_t mTime; diff --git a/Modules/EMCAL/CMakeLists.txt b/Modules/EMCAL/CMakeLists.txt index cbab6e40c6..e05fad1dfb 100644 --- a/Modules/EMCAL/CMakeLists.txt +++ b/Modules/EMCAL/CMakeLists.txt @@ -2,7 +2,7 @@ add_library(O2QcEMCAL) -target_sources(O2QcEMCAL PRIVATE src/PedestalTask.cxx src/BCTask.cxx src/RawErrorCheck.cxx src/RawTask.cxx src/RawCheck.cxx src/CellTask.cxx src/CellCheck.cxx src/DigitsQcTask.cxx src/DigitCheck.cxx src/OccupancyReductor.cxx src/ClusterTask.cxx src/RawErrorTask.cxx src/CalibMonitoringTask.cxx src/SupermoduleProjectorTask.cxx src/BadChannelMapReductor.cxx src/TimeCalibParamReductor.cxx src/SupermoduleProjectionReductor.cxx src/SubdetectorProjectionReductor.cxx src/BCVisualization.cxx) +target_sources(O2QcEMCAL PRIVATE src/TriggerTask.cxx src/PedestalTask.cxx src/BCTask.cxx src/RawErrorCheck.cxx src/RawTask.cxx src/RawCheck.cxx src/CellTask.cxx src/CellCheck.cxx src/DigitsQcTask.cxx src/DigitCheck.cxx src/OccupancyReductor.cxx src/ClusterTask.cxx src/RawErrorTask.cxx src/CalibMonitoringTask.cxx src/SupermoduleProjectorTask.cxx src/BadChannelMapReductor.cxx src/TimeCalibParamReductor.cxx src/SupermoduleProjectionReductor.cxx src/SubdetectorProjectionReductor.cxx src/BCVisualization.cxx src/CalibCheck.cxx) target_include_directories( O2QcEMCAL @@ -31,8 +31,10 @@ add_root_dictionary(O2QcEMCAL include/EMCAL/SupermoduleProjectionReductor.h include/EMCAL/SubdetectorProjectionReductor.h include/EMCAL/BCVisualization.h - include/EMCAL/PedestalTask.h - LINKDEF include/EMCAL/LinkDef.h) + include/EMCAL/PedestalTask.h + include/EMCAL/TriggerTask.h + include/EMCAL/CalibCheck.h + LINKDEF include/EMCAL/LinkDef.h) install(TARGETS O2QcEMCAL LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/Modules/EMCAL/include/EMCAL/CalibCheck.h b/Modules/EMCAL/include/EMCAL/CalibCheck.h new file mode 100644 index 0000000000..8dc62c8fc1 --- /dev/null +++ b/Modules/EMCAL/include/EMCAL/CalibCheck.h @@ -0,0 +1,68 @@ +// 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 CalibCheck.h +/// \author Sierra Cantway +/// + +#ifndef QC_MODULE_EMCAL_EMCALCALIBCHECK_H +#define QC_MODULE_EMCAL_EMCALCALIBCHECK_H + +#include "QualityControl/CheckInterface.h" + +namespace o2::quality_control_modules::emcal +{ + +/// \brief Check whether a plot is good or not. +/// +/// \author Sierra Cantway +class CalibCheck : public o2::quality_control::checker::CheckInterface +{ + public: + /// Default constructor + CalibCheck() = default; + /// Destructor + ~CalibCheck() override = default; + + // Override interface + void configure() override; + Quality check(std::map>* moMap) override; + void beautify(std::shared_ptr mo, Quality checkResult = Quality::Null) override; + std::string getAcceptedType() override; + + private: + /************************************************ + * threshold cuts * + ************************************************/ + + float mBadThresholdMaskStatsAll = 10.; ///< Bad Threshold used in the Max Stats All bad and dead channels check + float mBadThresholdTimeCalibCoeff = 10.; ///< Bad Threshold used in the time Calib Coeff points outside of mean check + float mBadThresholdFractionGoodCellsEvent = 0.; ///< Bad Threshold used in the fraction Good Cells per Event check + float mBadThresholdFractionGoodCellsSupermodule = 0.; ///< Bad Threshold used in the fraction Good Cells per Supermodule check + float mBadThresholdCellAmplitudeSupermoduleCalibPHYS = 10.; ///< Bad Threshold used in the PHYS Cell amplitude (Calib) vs. supermodule ID check + float mBadThresholdCellTimeSupermoduleCalibPHYS = 10.; ///< Bad Threshold used in the PHYS Cell Time (Calib) vs. supermodule ID (High gain) check + + float mMedThresholdMaskStatsAll = 10.; ///< Medium Threshold used in the Max Stats All bad and dead channels check + float mMedThresholdTimeCalibCoeff = 10.; ///< Medium Threshold used in the time Calib Coeff points outside of mean check + float mMedThresholdFractionGoodCellsEvent = 10.; ///< Medium Threshold used in the fraction Good Cells per Event check + float mMedThresholdFractionGoodCellsSupermodule = 10.; ///< Medium Threshold used in the fraction Good Cells per Supermodule check + float mMedThresholdCellAmplitudeSupermoduleCalibPHYS = 10.; ///< Medium Threshold used in the PHYS Cell amplitude (Calib) vs. supermodule ID check + float mMedThresholdCellTimeSupermoduleCalibPHYS = 10.; ///< Medium Threshold used in the PHYS Cell Time (Calib) vs. supermodule ID (High gain) check + + float mSigmaTimeCalibCoeff = 2.; ///< Number of sigmas used in the timeCalibCoeff points outside of mean check + + ClassDefOverride(CalibCheck, 1); +}; + +} // namespace o2::quality_control_modules::emcal + +#endif // QC_MODULE_EMCAL_EMCALCALIBCHECK_H diff --git a/Modules/EMCAL/include/EMCAL/LinkDef.h b/Modules/EMCAL/include/EMCAL/LinkDef.h index 3d8c9801a1..578052bd2b 100644 --- a/Modules/EMCAL/include/EMCAL/LinkDef.h +++ b/Modules/EMCAL/include/EMCAL/LinkDef.h @@ -39,6 +39,9 @@ #pragma link C++ class o2::quality_control_modules::emcal::BCTask + ; #pragma link C++ class o2::quality_control_modules::emcal::BCVisualization + ; - #pragma link C++ class o2::quality_control_modules::emcal::PedestalTask+; - - #endif +#pragma link C++ class o2::quality_control_modules::emcal::PedestalTask + ; + +#pragma link C++ class o2::quality_control_modules::emcal::CalibCheck + ; +#pragma link C++ class o2::quality_control_modules::emcal::TriggerTask + ; + +#endif \ No newline at end of file diff --git a/Modules/EMCAL/include/EMCAL/TriggerTask.h b/Modules/EMCAL/include/EMCAL/TriggerTask.h new file mode 100644 index 0000000000..ab4c5d8917 --- /dev/null +++ b/Modules/EMCAL/include/EMCAL/TriggerTask.h @@ -0,0 +1,152 @@ +// 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 TriggerTask.h +/// \author Markus Fasel +/// + +#ifndef QC_MODULE_EMCAL_EMCALTRIGGERTASK_H +#define QC_MODULE_EMCAL_EMCALTRIGGERTASK_H + +#include "QualityControl/TaskInterface.h" +#include "EMCALBase/TriggerMappingV2.h" +#include +#include +#include + +class TH1; +class TH2; +class TProfile2D; + +namespace o2 +{ +class InteractionRecord; +} + +namespace o2::emcal +{ +class CompressedTRU; +class CompressedTriggerPatch; +class CompressedL0TimeSum; +class TriggerRecord; +}; // namespace o2::emcal + +using namespace o2::quality_control::core; + +namespace o2::quality_control_modules::emcal +{ + +/// \class TriggerTask +/// \brief Task monitoring EMCAL trigger observables +/// \author Markus Fasel , Oak Ridge National Laboratory +/// \since April 19, 2024 +/// +/// Task monitoring basic observables of the EMCAL trigger system. The task subscibes to: +/// +/// || Binding || Channel || Information || +/// |---------------|-----------------|---------------------------------------| +/// | truinfo | EMC/TRUS | TRU data | +/// | trurecords | EMC/TRUSTRGR | Trigger records of TRU data | +/// | patchinfos | EMC/PATCHES | Trigger patches | +/// | patchrecords | EMC/PATCHESTRGR | Trigger records of trigger patches | +/// | timesums | EMC/FASTORS | L0 FastOR timesums | +/// |timesumrecords | EMC/FASTORSTRGR | Trigger records of L0 FastOR timesums | +/// +/// Monitoring per timeframe is done in the function monitorData, which delegates +/// the monitoring per trigger to an internal function processEvent. +/// +/// The task defines the following task parameters: +/// - None so far +class TriggerTask final : public TaskInterface +{ + public: + /// \brief Constructor + TriggerTask() = default; + /// \brief Destructor + ~TriggerTask() override; + + /// \brief Initialize task (histograms and trigger mapping) + /// \param ctx InitContenxt + void initialize(o2::framework::InitContext& ctx) override; + + /// \brief Operations performed at the start of activity (start of run) + /// \param activity Activity + void startOfActivity(const Activity& activity) override; + + /// \brief Operations at performed at the start of a new monitoring cycle + void startOfCycle() override; + + /// \brief Monitoring data for a given timeframe + /// \param ctx Processing context with data + /// + /// As the data in EMCAL is organized in triggers within the container the + /// monitoring is delegated to the internal function processEvent. monitorData + /// subscribes to the timeframe-based container of the TRU information, trigger + /// patches and timesums, as well as their corresponding trigger records. Iteration + /// over all BCs found in any of the containers via getAllBCs is performed, and + /// for each trigger the TRU, patch and FastOR information is extracted from the + /// timeframe-based containers. + void monitorData(o2::framework::ProcessingContext& ctx) override; + + /// \brief Operations performed at the end of the current monitoring cycle + void endOfCycle() override; + + /// \brief Operations performed at the end fo the activity (end of run) + /// \param activity Activity + void endOfActivity(const Activity& activity) override; + + /// \brief Reset all histograms + void reset() override; + + private: + /// \brief Fill monitoring histograms for a single event + /// \param trudata TRU data for the event + /// \param triggerpatches Trigger patches found in the event + /// \param timesums L0 timesums found in the event + void processEvent(const gsl::span trudata, const gsl::span triggerpatches, const gsl::span timesums); + + /// \brief Find all BCs with data in either of the components (or all) + /// \param trurecords Trigger records for TRU data + /// \param patchrecords Trigger records for trigger patches + /// \param timesumrecords Trigger records for L0 timesums + /// \return List of found BCs (sorted) + std::vector getAllBCs(const gsl::span trurecords, const gsl::span patchrecords, const gsl::span timesumrecords) const; + + std::unique_ptr mTriggerMapping; ///< Trigger mapping + TH1* mTRUFired = nullptr; ///< Histogram with counters per TRU fired + TH1* mFastORFired = nullptr; ///< Histogram with counters per FastOR fired (in patches) + TH2* mPositionFasORFired = nullptr; ///< Histogram with the position of fired FastORs (in patches) + TH1* mNumberOfTRUsPerEvent = nullptr; ///< Counter histogram for number of fired TRUs per event + TH1* mNumberOfPatchesPerEvent = nullptr; ///< Counter histogram for number of fired patches per event + TH1* mPatchEnergySpectrumPerEvent = nullptr; ///< Histogram for integrated patch energy spectrum + TH1* mLeadingPatchEnergySpectrumPerEvent = nullptr; ///< Histogram for integrated leading patch energy spectrum + TH2* mPatchEnergyTRU = nullptr; ///< Histogram for patch energy spectrum per TRU + TH2* mLeadingPatchEnergyTRU = nullptr; ///< Histogram for leading patch energy spectrum per TRU + TH2* mNumberOfPatchesPerTRU = nullptr; ///< Counter histogram for number of patches per TRU + TH2* mPatchIndexFired = nullptr; ///< Histogram with the fired patch index per TRU + TH2* mPatchIndexLeading = nullptr; ///< Histogram with the leading fired patch index per TRU + TH2* mTRUTime = nullptr; ///< Histogram with TRU time vs TRU index + TH2* mPatchTime = nullptr; ///< Histogram with patch time vs. TRU index + TH2* mLeadingPatchTime = nullptr; ///< Histogram with patch time of the leading patch vs. TRU index + TH1* mNumberTimesumsEvent = nullptr; ///< Counter histogram with number of non-0 FastOR timesums per event + TH1* mL0Timesums = nullptr; ///< ADC spectrum of the FastOR timesums + TH2* mL0TimesumsTRU = nullptr; ///< ADC spectrum of the the FastOR timesums per TRU + TH1* mADCMaxTimesum = nullptr; ///< ADC spectrum of the leading FastOR timesum per event + TH1* mFastORIndexMaxTimesum = nullptr; ///< Index of the leading FastOR timesum per event + TH2* mPositionMaxTimesum = nullptr; ///< Position of teh leading FastOR timsum per event + TH2* mIntegratedTimesums = nullptr; ///< Integrated ADC timesum + TProfile2D* mAverageTimesum = nullptr; ///< Average ADC timesum +}; + +} // namespace o2::quality_control_modules::emcal + +#endif // QC_MODULE_EMCAL_EMCALTRIGGERTASK_H diff --git a/Modules/EMCAL/src/CalibCheck.cxx b/Modules/EMCAL/src/CalibCheck.cxx new file mode 100644 index 0000000000..d2b9f8cc66 --- /dev/null +++ b/Modules/EMCAL/src/CalibCheck.cxx @@ -0,0 +1,344 @@ +// 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 CalibCheck.cxx +/// \author Sierra Cantway +/// + +#include "EMCAL/CalibCheck.h" +#include "QualityControl/MonitorObject.h" +#include "QualityControl/Quality.h" +#include "QualityControl/QcInfoLogger.h" +#include +// ROOT +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace o2::quality_control_modules::emcal +{ + +void CalibCheck::configure() +{ + // configure threshold-based checkers for bad quality + auto nBadThresholdMaskStatsAll = mCustomParameters.find("BadThresholdMaskStatsAll"); + if (nBadThresholdMaskStatsAll != mCustomParameters.end()) { + try { + mBadThresholdMaskStatsAll = std::stof(nBadThresholdMaskStatsAll->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nBadThresholdMaskStatsAll->second.data()) << ENDM; + } + } + + auto nBadThresholdTimeCalibCoeff = mCustomParameters.find("BadThresholdTimeCalibCoeff"); + if (nBadThresholdTimeCalibCoeff != mCustomParameters.end()) { + try { + mBadThresholdTimeCalibCoeff = std::stof(nBadThresholdTimeCalibCoeff->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nBadThresholdTimeCalibCoeff->second.data()) << ENDM; + } + } + + auto nBadThresholdCellAmplitudeSupermoduleCalibPHYS = mCustomParameters.find("BadThresholdCellAmplitudeSupermoduleCalibPHYS"); + if (nBadThresholdCellAmplitudeSupermoduleCalibPHYS != mCustomParameters.end()) { + try { + mBadThresholdCellAmplitudeSupermoduleCalibPHYS = std::stof(nBadThresholdCellAmplitudeSupermoduleCalibPHYS->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nBadThresholdCellAmplitudeSupermoduleCalibPHYS->second.data()) << ENDM; + } + } + + auto nBadThresholdFractionGoodCellsEvent = mCustomParameters.find("BadThresholdFractionGoodCellsEvent"); + if (nBadThresholdFractionGoodCellsEvent != mCustomParameters.end()) { + try { + mBadThresholdFractionGoodCellsEvent = std::stof(nBadThresholdFractionGoodCellsEvent->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nBadThresholdFractionGoodCellsEvent->second.data()) << ENDM; + } + } + + auto nBadThresholdFractionGoodCellsSupermodule = mCustomParameters.find("BadThresholdFractionGoodCellsSupermodule"); + if (nBadThresholdFractionGoodCellsSupermodule != mCustomParameters.end()) { + try { + mBadThresholdFractionGoodCellsSupermodule = std::stof(nBadThresholdFractionGoodCellsSupermodule->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nBadThresholdFractionGoodCellsSupermodule->second.data()) << ENDM; + } + } + + auto nBadThresholdCellTimeSupermoduleCalibPHYS = mCustomParameters.find("BadThresholdCellTimeSupermoduleCalibPHYS"); + if (nBadThresholdCellTimeSupermoduleCalibPHYS != mCustomParameters.end()) { + try { + mBadThresholdCellTimeSupermoduleCalibPHYS = std::stof(nBadThresholdCellTimeSupermoduleCalibPHYS->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nBadThresholdCellTimeSupermoduleCalibPHYS->second.data()) << ENDM; + } + } + + // configure threshold-based checkers for medium quality + auto nMedThresholdMaskStatsAll = mCustomParameters.find("MedThresholdMaskStatsAll"); + if (nMedThresholdMaskStatsAll != mCustomParameters.end()) { + try { + mMedThresholdMaskStatsAll = std::stof(nMedThresholdMaskStatsAll->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nMedThresholdMaskStatsAll->second.data()) << ENDM; + } + } + + auto nMedThresholdTimeCalibCoeff = mCustomParameters.find("MedThresholdTimeCalibCoeff"); + if (nMedThresholdTimeCalibCoeff != mCustomParameters.end()) { + try { + mMedThresholdTimeCalibCoeff = std::stof(nMedThresholdTimeCalibCoeff->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nMedThresholdTimeCalibCoeff->second.data()) << ENDM; + } + } + + auto nMedThresholdCellAmplitudeSupermoduleCalibPHYS = mCustomParameters.find("MedThresholdCellAmplitudeSupermoduleCalibPHYS"); + if (nMedThresholdCellAmplitudeSupermoduleCalibPHYS != mCustomParameters.end()) { + try { + mMedThresholdCellAmplitudeSupermoduleCalibPHYS = std::stof(nMedThresholdCellAmplitudeSupermoduleCalibPHYS->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nMedThresholdCellAmplitudeSupermoduleCalibPHYS->second.data()) << ENDM; + } + } + + auto nMedThresholdFractionGoodCellsEvent = mCustomParameters.find("MedThresholdFractionGoodCellsEvent"); + if (nMedThresholdFractionGoodCellsEvent != mCustomParameters.end()) { + try { + mMedThresholdFractionGoodCellsEvent = std::stof(nMedThresholdFractionGoodCellsEvent->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nMedThresholdFractionGoodCellsEvent->second.data()) << ENDM; + } + } + + auto nMedThresholdFractionGoodCellsSupermodule = mCustomParameters.find("MedThresholdFractionGoodCellsSupermodule"); + if (nMedThresholdFractionGoodCellsSupermodule != mCustomParameters.end()) { + try { + mMedThresholdFractionGoodCellsSupermodule = std::stof(nMedThresholdFractionGoodCellsSupermodule->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nMedThresholdFractionGoodCellsSupermodule->second.data()) << ENDM; + } + } + + auto nMedThresholdCellTimeSupermoduleCalibPHYS = mCustomParameters.find("MedThresholdCellTimeSupermoduleCalibPHYS"); + if (nMedThresholdCellTimeSupermoduleCalibPHYS != mCustomParameters.end()) { + try { + mMedThresholdCellTimeSupermoduleCalibPHYS = std::stof(nMedThresholdCellTimeSupermoduleCalibPHYS->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nMedThresholdCellTimeSupermoduleCalibPHYS->second.data()) << ENDM; + } + } + + // configure nsigma-based checkers + auto nSigmaTimeCalibCoeff = mCustomParameters.find("SigmaTimeCalibCoeff"); + if (nSigmaTimeCalibCoeff != mCustomParameters.end()) { + try { + mSigmaTimeCalibCoeff = std::stof(nSigmaTimeCalibCoeff->second); + } catch (std::exception& e) { + ILOG(Error, Support) << fmt::format("Value {} not a float", nSigmaTimeCalibCoeff->second.data()) << ENDM; + } + } +} + +Quality CalibCheck::check(std::map>* moMap) +{ + auto mo = moMap->begin()->second; + Quality result = Quality::Good; + + if (mo->getName() == "MaskStatsAllHisto") { + auto* h = dynamic_cast(mo->getObject()); + if (h->GetEntries() == 0) { + result = Quality::Medium; + } else { + int bad_bins_total = 0; + if (h->GetNbinsX() >= 3) { + bad_bins_total = h->GetBinContent(2) + h->GetBinContent(3); + } + + Float_t bad_bins_fraction = (float)bad_bins_total / (float)(h->GetEntries()); + + if (bad_bins_fraction > mBadThresholdMaskStatsAll) { + result = Quality::Bad; + } else if (bad_bins_fraction > mMedThresholdMaskStatsAll) { + result = Quality::Medium; + } + } + } + + if (mo->getName() == "timeCalibCoeff") { + auto* h = dynamic_cast(mo->getObject()); + if (h->GetEntries() == 0) { + result = Quality::Medium; + } else { + std::vector smcounts; + for (auto ib : ROOT::TSeqI(0, h->GetXaxis()->GetNbins())) { + auto countSM = h->GetBinContent(ib + 1); + if (countSM > 0) { + smcounts.emplace_back(countSM); + } + } + if (!smcounts.size()) { + result = Quality::Medium; + } else { + TRobustEstimator meanfinder; + double mean, sigma; + meanfinder.EvaluateUni(smcounts.size(), smcounts.data(), mean, sigma); + int outside_counts = 0.0; + for (auto ib : ROOT::TSeqI(0, h->GetXaxis()->GetNbins())) { + if (h->GetBinContent(ib + 1) > (mean + mSigmaTimeCalibCoeff * sigma) || h->GetBinContent(ib + 1) < (mean - mSigmaTimeCalibCoeff * sigma)) { + outside_counts += 1; + } + } + Float_t out_counts_frac = (float)(outside_counts) / (float)(h->GetEntries()); + + if (out_counts_frac > mBadThresholdTimeCalibCoeff) { + result = Quality::Bad; + } else if (out_counts_frac > mMedThresholdTimeCalibCoeff) { + result = Quality::Medium; + } + } + } + } + + if (mo->getName() == "fractionGoodCellsEvent") { + auto* h = dynamic_cast(mo->getObject()); + if (h->GetEntries() == 0) { + result = Quality::Medium; + } else { + for (int j = 1; j <= h->GetNbinsX(); j++) { + auto* h_det = h->ProjectionY(Form("h_det_%d", j), j, j); + if (h_det->GetEntries() == 0) { + continue; + } + + Float_t avg_frac = 0.0; + for (int i = 1; i <= h_det->GetNbinsX(); i++) { + avg_frac += h_det->GetBinContent(i) * h_det->GetBinCenter(i); + } + avg_frac = avg_frac / (h_det->GetEntries()); + + if (avg_frac < mBadThresholdFractionGoodCellsEvent) { + result = Quality::Bad; + break; + } else if (avg_frac < mMedThresholdFractionGoodCellsEvent) { + result = Quality::Medium; + } + } + } + } + + if (mo->getName() == "fractionGoodCellsSupermodule") { + auto* h = dynamic_cast(mo->getObject()); + if (h->GetEntries() == 0) { + result = Quality::Medium; + } else { + for (int j = 1; j <= h->GetNbinsX(); j++) { + auto* h_supermod = h->ProjectionY(Form("h_supermod_%d", j), j, j); + if (h_supermod->GetEntries() == 0) { + continue; + } + + Float_t avg_frac = 0.0; + for (int i = 1; i <= h_supermod->GetNbinsX(); i++) { + avg_frac += h_supermod->GetBinContent(i) * h_supermod->GetBinCenter(i); + } + avg_frac = avg_frac / (h_supermod->GetEntries()); + + if (avg_frac < mBadThresholdFractionGoodCellsSupermodule) { + result = Quality::Bad; + break; + } else if (avg_frac < mMedThresholdFractionGoodCellsSupermodule) { + result = Quality::Medium; + } + } + } + } + + if (mo->getName() == "cellAmplitudeSupermoduleCalib_PHYS") { + auto* h = dynamic_cast(mo->getObject()); + if (h->GetEntries() == 0) { + result = Quality::Medium; + } else { + auto* h_allsupermod_proj = h->ProjectionX("h_allsupermod_proj"); + h_allsupermod_proj->Scale(1.0 / h_allsupermod_proj->Integral()); + for (int i = 1; i <= h->GetNbinsY(); i++) { + auto* h_supermod = h->ProjectionX(Form("h_supermod_%d", i), i, i); + if (h_supermod->GetEntries() == 0) { + result = Quality::Medium; + } else { + h_supermod->Scale(1.0 / h_supermod->Integral()); + + Double_t chi2_SM = h_supermod->Chi2Test(h_allsupermod_proj, "UU NORM CHI2/NDF"); + if (chi2_SM > mBadThresholdCellAmplitudeSupermoduleCalibPHYS) { + result = Quality::Bad; + break; + } else if (chi2_SM > mMedThresholdCellAmplitudeSupermoduleCalibPHYS) { + result = Quality::Medium; + } + } + } + } + } + + if (mo->getName() == "cellTimeSupermoduleCalib_PHYS") { + auto* h = dynamic_cast(mo->getObject()); + if (h->GetEntries() == 0) { + result = Quality::Medium; + } else { + auto* h_allsupermod_proj = h->ProjectionX("h_supermod_proj"); + if (h_allsupermod_proj->GetEntries() == 0) { + result = Quality::Medium; + } else { + Double_t mean_allsupermod = h_allsupermod_proj->GetMean(); + if (TMath::Abs(mean_allsupermod) > mBadThresholdCellTimeSupermoduleCalibPHYS) { + result = Quality::Bad; + } else if (TMath::Abs(mean_allsupermod) > mMedThresholdCellTimeSupermoduleCalibPHYS) { + result = Quality::Medium; + } + + for (int j = 1; j <= h->GetNbinsY(); j++) { + auto* h_supermod = h->ProjectionY(Form("h_supermod_%d", j), j, j); + if (h_supermod->GetEntries() == 0) { + result = Quality::Medium; + } else { + Double_t mean_isupermod = h_supermod->GetMean(); + if (TMath::Abs(mean_isupermod) > mBadThresholdCellTimeSupermoduleCalibPHYS) { + result = Quality::Bad; + break; + } else if (TMath::Abs(mean_isupermod) > mMedThresholdCellTimeSupermoduleCalibPHYS) { + result = Quality::Medium; + } + } + } + } + } + } + return result; +} + +std::string CalibCheck::getAcceptedType() { return "TH1"; } + +void CalibCheck::beautify(std::shared_ptr mo, Quality checkResult) +{ + // To do +} +} // namespace o2::quality_control_modules::emcal diff --git a/Modules/EMCAL/src/TriggerTask.cxx b/Modules/EMCAL/src/TriggerTask.cxx new file mode 100644 index 0000000000..dfcb6f8489 --- /dev/null +++ b/Modules/EMCAL/src/TriggerTask.cxx @@ -0,0 +1,294 @@ +// 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 TriggerTask.cxx +/// \author Markus Fasel +/// + +#include + +#include +#include +#include +#include + +#include "QualityControl/QcInfoLogger.h" +#include "EMCAL/TriggerTask.h" +#include "DataFormatsEMCAL/CompressedTriggerData.h" +#include "DataFormatsEMCAL/TriggerRecord.h" +#include +#include + +namespace o2::quality_control_modules::emcal +{ + +TriggerTask::~TriggerTask() +{ + delete mTRUFired; + delete mFastORFired; + delete mPositionFasORFired; + delete mNumberOfTRUsPerEvent; + delete mNumberOfPatchesPerEvent; + delete mPatchEnergySpectrumPerEvent; + delete mLeadingPatchEnergySpectrumPerEvent; + delete mPatchEnergyTRU; + delete mLeadingPatchEnergyTRU; + delete mNumberOfPatchesPerTRU; + delete mPatchIndexFired; + delete mPatchIndexLeading; + delete mTRUTime; + delete mPatchTime; + delete mNumberTimesumsEvent; + delete mL0Timesums; + delete mL0TimesumsTRU; + delete mADCMaxTimesum; + delete mFastORIndexMaxTimesum; + delete mPositionMaxTimesum; + delete mIntegratedTimesums; + delete mAverageTimesum; +} + +void TriggerTask::initialize(o2::framework::InitContext& /*ctx*/) +{ + mTRUFired = new TH1F("NumberOfFiredTRUs", "Number of triggers per TRU; TRU index; Number of triggers", o2::emcal::TriggerMappingV2::ALLTRUS, -0.5, o2::emcal::TriggerMappingV2::ALLTRUS - 0.5); + getObjectsManager()->startPublishing(mTRUFired); + mFastORFired = new TH1F("NumberOfPatchesWithFastOR", "Number of patches per FastOR; FastOR abs. ID; Number of patches", o2::emcal::TriggerMappingV2::ALLFASTORS, -0.5, o2::emcal::TriggerMappingV2::ALLFASTORS - 0.5); + getObjectsManager()->startPublishing(mFastORFired); + mPositionFasORFired = new TH2F("PositionFastOrInPatch", "Position of FastORs in patches; column; row", o2::emcal::TriggerMappingV2::FASTORSETA, -0.5, o2::emcal::TriggerMappingV2::FASTORSETA - 0.5, o2::emcal::TriggerMappingV2::FASTORSPHI, -0.5, o2::emcal::TriggerMappingV2::FASTORSPHI - 0.5); + getObjectsManager()->startPublishing(mPositionFasORFired); + mNumberOfTRUsPerEvent = new TH1F("NumberOfTRUsPerEvent", "Number of fired TRUs per event; Number of TRUs; Number of events", 20, -0.5, 19.5); + getObjectsManager()->startPublishing(mNumberOfTRUsPerEvent); + mNumberOfPatchesPerEvent = new TH1F("NumberOfPatchesPerEvent", "Number of patches per event; Number of L0 patches; Number of events", 100, -0.5, 99.5); + getObjectsManager()->startPublishing(mNumberOfPatchesPerEvent); + mPatchEnergySpectrumPerEvent = new TH1F("PatchEnergySpectrum", "Patch energy spectrum; Patch ADC; Yield", 2000, 0., 2000); + getObjectsManager()->startPublishing(mPatchEnergySpectrumPerEvent); + mLeadingPatchEnergySpectrumPerEvent = new TH1F("LeadingPatchEnergySpectrum", "Leading patch energy spectrum; Patch ADC; Yield", 2000, 0., 2000); + getObjectsManager()->startPublishing(mLeadingPatchEnergySpectrumPerEvent); + mPatchEnergyTRU = new TH2F("PatchEnergySpectrumTRU", "Patch energy spectrum; Patch ADC; TRU index", 2000, 0., 2000, o2::emcal::TriggerMappingV2::ALLTRUS, -0.5, o2::emcal::TriggerMappingV2::ALLTRUS - 0.5); + getObjectsManager()->startPublishing(mPatchEnergyTRU); + mLeadingPatchEnergyTRU = new TH2F("LeadingPatchEnergySpectrumTRU", "Leading patch energy spectrum; Patch ADC; TRU index", 2000, 0., 2000, o2::emcal::TriggerMappingV2::ALLTRUS, -0.5, o2::emcal::TriggerMappingV2::ALLTRUS - 0.5); + getObjectsManager()->startPublishing(mLeadingPatchEnergyTRU); + mNumberOfPatchesPerTRU = new TH2F("NumberOfPatchesPerTRU", "Number of trigger patches per TRU and event; Patch ADC; TRU index", 20, -0.5, 19.5, o2::emcal::TriggerMappingV2::ALLTRUS, -0.5, o2::emcal::TriggerMappingV2::ALLTRUS - 0.5); + getObjectsManager()->startPublishing(mNumberOfPatchesPerTRU); + mPatchIndexFired = new TH2F("PatchIndexFired", "Fired trigger patches; Patch index; TRU index", o2::emcal::TriggerMappingV2::PATCHESINTRU, -0.5, o2::emcal::TriggerMappingV2::PATCHESINTRU - 0.5, o2::emcal::TriggerMappingV2::ALLTRUS, -0.5, o2::emcal::TriggerMappingV2::ALLTRUS - 0.5); + getObjectsManager()->startPublishing(mPatchIndexFired); + mPatchIndexLeading = new TH2F("LeadingPatchIndexFired", "Leading trigger patches; Patch index; TRU index", o2::emcal::TriggerMappingV2::PATCHESINTRU, -0.5, o2::emcal::TriggerMappingV2::PATCHESINTRU - 0.5, o2::emcal::TriggerMappingV2::ALLTRUS, -0.5, o2::emcal::TriggerMappingV2::ALLTRUS - 0.5); + getObjectsManager()->startPublishing(mPatchIndexLeading); + mTRUTime = new TH2F("TRUTime", "TRU time; TRU time sample; TRU index", 12, -0.5, 11.5, o2::emcal::TriggerMappingV2::ALLTRUS, -0.5, o2::emcal::TriggerMappingV2::ALLTRUS - 0.5); + getObjectsManager()->startPublishing(mTRUTime); + mPatchTime = new TH2F("PatchTime", "Patch time; Patch time sample; TRU index", 12, -0.5, 11.5, o2::emcal::TriggerMappingV2::ALLTRUS, -0.5, o2::emcal::TriggerMappingV2::ALLTRUS - 0.5); + getObjectsManager()->startPublishing(mPatchTime); + mLeadingPatchTime = new TH2F("LeadingPatchTime", "Leading patch time; Patch time sample; TRU index", 12, -0.5, 11.5, o2::emcal::TriggerMappingV2::ALLTRUS, -0.5, o2::emcal::TriggerMappingV2::ALLTRUS - 0.5); + getObjectsManager()->startPublishing(mLeadingPatchTime); + mNumberTimesumsEvent = new TH1F("NumberL0TimesumsEvent", "Number of L0 timesums per event; Number of L0 timesums; Number of events", 1000, 0., 1000.); + getObjectsManager()->startPublishing(mNumberTimesumsEvent); + mL0Timesums = new TH1F("L0Timesums", "L0 timesums; L0 timesum (ADC counts); yield", 2048, 0., 2048); + getObjectsManager()->startPublishing(mL0Timesums); + mL0TimesumsTRU = new TH2F("L0TimesumsTRU", "L0 timesums per TRU; L0 timesum (ADC counts); TRU index", 2048, 0., 2048, o2::emcal::TriggerMappingV2::ALLTRUS, -0.5, o2::emcal::TriggerMappingV2::ALLTRUS - 0.5); + getObjectsManager()->startPublishing(mL0TimesumsTRU); + mADCMaxTimesum = new TH1F("MaxL0Timesum", "Max. L0 timesum per event; L0 timesum (ADC counts); Yield", 2048, 0., 2048); + getObjectsManager()->startPublishing(mADCMaxTimesum); + mFastORIndexMaxTimesum = new TH1F("FastORMaxTimesum", "FastOR ID of the max. L0 timesum; FastOR abs. ID; Yield", o2::emcal::TriggerMappingV2::ALLFASTORS, -0.5, o2::emcal::TriggerMappingV2::ALLFASTORS - 0.5); + getObjectsManager()->startPublishing(mFastORIndexMaxTimesum); + mPositionMaxTimesum = new TH2F("PositionMaxTimesum", "FastOR position of the max. L0 timesum; column; row", o2::emcal::TriggerMappingV2::FASTORSETA, -0.5, o2::emcal::TriggerMappingV2::FASTORSETA - 0.5, o2::emcal::TriggerMappingV2::FASTORSPHI, -0.5, o2::emcal::TriggerMappingV2::FASTORSPHI - 0.5); + getObjectsManager()->startPublishing(mPositionMaxTimesum); + mIntegratedTimesums = new TH2F("IntegratedTimesums", "Integrated L0 timesums per FastOR; column; row", o2::emcal::TriggerMappingV2::FASTORSETA, -0.5, o2::emcal::TriggerMappingV2::FASTORSETA - 0.5, o2::emcal::TriggerMappingV2::FASTORSPHI, -0.5, o2::emcal::TriggerMappingV2::FASTORSPHI - 0.5); + getObjectsManager()->startPublishing(mIntegratedTimesums); + mAverageTimesum = new TProfile2D("AverageTimesums", "Average L0 timesums per FastOR; column; row", o2::emcal::TriggerMappingV2::FASTORSETA, -0.5, o2::emcal::TriggerMappingV2::FASTORSETA - 0.5, o2::emcal::TriggerMappingV2::FASTORSPHI, -0.5, o2::emcal::TriggerMappingV2::FASTORSPHI - 0.5); + getObjectsManager()->startPublishing(mAverageTimesum); + + mTriggerMapping = std::make_unique(); +} + +void TriggerTask::startOfActivity(const Activity& activity) +{ + // THIS FUNCTION BODY IS AN EXAMPLE. PLEASE REMOVE EVERYTHING YOU DO NOT NEED. + ILOG(Debug, Devel) << "startOfActivity " << activity.mId << ENDM; + reset(); +} + +void TriggerTask::startOfCycle() +{ + // THUS FUNCTION BODY IS AN EXAMPLE. PLEASE REMOVE EVERYTHING YOU DO NOT NEED. + ILOG(Debug, Devel) << "startOfCycle" << ENDM; +} + +void TriggerTask::monitorData(o2::framework::ProcessingContext& ctx) +{ + auto trus = ctx.inputs().get>("truinfo"); + auto trurecords = ctx.inputs().get>("trurecords"); + auto patches = ctx.inputs().get>("patchinfos"); + auto patchrecords = ctx.inputs().get>("patchrecords"); + auto timesums = ctx.inputs().get>("timesums"); + auto timesumrecords = ctx.inputs().get>("timesumrecords"); + ILOG(Debug, Devel) << "Found " << trurecords.size() << " TRU trigger records for " << trus.size() << " TRU info objects ..." << ENDM; + ILOG(Debug, Devel) << "Found " << patchrecords.size() << " patch trigger records for " << patches.size() << " patch objects ..." << ENDM; + ILOG(Debug, Devel) << "Found " << timesumrecords.size() << " timesum trigger records for " << timesums.size() << " L0 timesums ..." << ENDM; + + for (const auto& bc : getAllBCs(trurecords, patchrecords, timesumrecords)) { + gsl::span eventTRUs; + gsl::span eventPatches; + gsl::span eventTimesums; + auto recordfinder = [&bc](const o2::emcal::TriggerRecord& rec) { + return bc == rec.getBCData(); + }; + auto trurecfound = std::find_if(trurecords.begin(), trurecords.end(), recordfinder); + auto patchrecfound = std::find_if(patchrecords.begin(), patchrecords.end(), recordfinder); + auto timesumrecfound = std::find_if(timesumrecords.begin(), timesumrecords.end(), recordfinder); + if (trurecfound != trurecords.end()) { + eventTRUs = trus.subspan(trurecfound->getFirstEntry(), trurecfound->getNumberOfObjects()); + } + if (patchrecfound != patchrecords.end()) { + eventPatches = patches.subspan(patchrecfound->getFirstEntry(), patchrecfound->getNumberOfObjects()); + } + if (timesumrecfound != timesumrecords.end()) { + eventTimesums = timesums.subspan(timesumrecfound->getFirstEntry(), timesumrecfound->getNumberOfObjects()); + } + processEvent(eventTRUs, eventPatches, eventTimesums); + } +} + +void TriggerTask::endOfCycle() +{ + ILOG(Debug, Devel) << "endOfCycle" << ENDM; +} + +void TriggerTask::endOfActivity(const Activity& /*activity*/) +{ + ILOG(Debug, Devel) << "endOfActivity" << ENDM; +} + +void TriggerTask::reset() +{ + // clean all the monitor objects here + + ILOG(Debug, Devel) << "Resetting the histograms" << ENDM; + mTRUFired->Reset(); + mFastORFired->Reset(); + mPositionFasORFired->Reset(); + mNumberOfTRUsPerEvent->Reset(); + mNumberOfPatchesPerEvent->Reset(); + mPatchEnergySpectrumPerEvent->Reset(); + mLeadingPatchEnergySpectrumPerEvent->Reset(); + mPatchEnergyTRU->Reset(); + mLeadingPatchEnergyTRU->Reset(); + mNumberOfPatchesPerTRU->Reset(); + mPatchIndexFired->Reset(); + mPatchIndexLeading->Reset(); + mTRUTime->Reset(); + mPatchTime->Reset(); + mLeadingPatchTime->Reset(); + mNumberTimesumsEvent->Reset(); + mL0Timesums->Reset(); + mL0TimesumsTRU->Reset(); + mADCMaxTimesum->Reset(); + mFastORIndexMaxTimesum->Reset(); + mPositionMaxTimesum->Reset(); + mIntegratedTimesums->Reset(); + mAverageTimesum->Reset(); +} + +std::vector TriggerTask::getAllBCs(const gsl::span trurecords, const gsl::span patchrecords, const gsl::span timesumrecords) const +{ + std::vector result; + auto add_to_result = [&result](const o2::emcal::TriggerRecord& rec) { + if (std::find(result.begin(), result.end(), rec.getBCData()) == result.end()) { + result.emplace_back(rec.getBCData()); + } + }; + for (const auto& trurecord : trurecords) { + result.emplace_back(trurecord.getBCData()); + } + for (const auto& patchrecord : patchrecords) { + add_to_result(patchrecord); + } + for (const auto& timesumrecord : timesumrecords) { + add_to_result(timesumrecord); + } + + std::sort(result.begin(), result.end(), std::less<>()); + return result; +} + +void TriggerTask::processEvent(const gsl::span trudata, const gsl::span triggerpatches, const gsl::span timesums) +{ + uint8_t numFiredTRU = 0; + for (const auto& tru : trudata) { + if (tru.mFired) { + mTRUFired->Fill(tru.mTRUIndex); + mTRUTime->Fill(tru.mTriggerTime, tru.mTRUIndex); + numFiredTRU++; + } + } + mNumberOfTRUsPerEvent->Fill(numFiredTRU); + mNumberOfPatchesPerEvent->Fill(triggerpatches.size()); + uint16_t leadingadc = 0; + uint8_t timeleading = UCHAR_MAX, + indexleading = UCHAR_MAX, + indexTRUleading = UCHAR_MAX; + std::array numpatches; + std::fill(numpatches.begin(), numpatches.end(), 0); + for (auto& patch : triggerpatches) { + numpatches[patch.mTRUIndex]++; + mPatchIndexFired->Fill(patch.mPatchIndexInTRU, patch.mTRUIndex); + mPatchEnergySpectrumPerEvent->Fill(patch.mADC); + mPatchEnergyTRU->Fill(patch.mADC, patch.mTRUIndex); + mPatchTime->Fill(patch.mTime, patch.mTRUIndex); + auto fastORs = mTriggerMapping->getFastORIndexFromL0Index(patch.mTRUIndex, patch.mPatchIndexInTRU, 4); + for (auto fastor : fastORs) { + mFastORFired->Fill(fastor); + auto [col, row] = mTriggerMapping->getPositionInEMCALFromAbsFastORIndex(fastor); + mPositionFasORFired->Fill(col, row); + } + if (patch.mADC > leadingadc) { + leadingadc = patch.mADC; + indexleading = patch.mPatchIndexInTRU; + indexTRUleading = patch.mTRUIndex; + timeleading = patch.mTime; + } + } + if (indexleading < UCHAR_MAX) { + mLeadingPatchEnergySpectrumPerEvent->Fill(leadingadc); + mLeadingPatchEnergyTRU->Fill(leadingadc, indexTRUleading); + mPatchIndexLeading->Fill(indexleading, indexTRUleading); + mLeadingPatchTime->Fill(timeleading, indexTRUleading); + } + for (auto itru = 0; itru < 52; itru++) { + if (numpatches[itru]) { + mNumberOfPatchesPerTRU->Fill(numpatches[itru], itru); + } + } + + uint16_t maxtimesum = 0, + indexMaxTimesum = USHRT_MAX; + mNumberTimesumsEvent->Fill(timesums.size()); + for (const auto& timesum : timesums) { + mL0Timesums->Fill(timesum.mTimesum); + auto [indexTRU, indexInTRU] = mTriggerMapping->getTRUFromAbsFastORIndex(timesum.mIndex); + mL0TimesumsTRU->Fill(timesum.mTimesum, indexTRU); + auto [col, row] = mTriggerMapping->getPositionInEMCALFromAbsFastORIndex(timesum.mIndex); + mIntegratedTimesums->Fill(col, row, timesum.mTimesum); + mAverageTimesum->Fill(col, row, timesum.mTimesum); + if (timesum.mTimesum > maxtimesum) { + maxtimesum = timesum.mTimesum; + indexMaxTimesum = timesum.mIndex; + } + } + if (indexMaxTimesum < USHRT_MAX) { + mADCMaxTimesum->Fill(maxtimesum); + mFastORIndexMaxTimesum->Fill(indexMaxTimesum); + auto [col, row] = mTriggerMapping->getPositionInEMCALFromAbsFastORIndex(indexMaxTimesum); + mPositionMaxTimesum->Fill(col, row); + } +} + +} // namespace o2::quality_control_modules::emcal diff --git a/Modules/GLO/CMakeLists.txt b/Modules/GLO/CMakeLists.txt index d4f0a931c6..3bafa5982c 100644 --- a/Modules/GLO/CMakeLists.txt +++ b/Modules/GLO/CMakeLists.txt @@ -1,8 +1,9 @@ # ---- Library ---- +# add_compile_options(-O0 -g -fPIC) add_library(O2QcGLO) -target_sources(O2QcGLO PRIVATE src/MeanVertexPostProcessing.cxx src/MeanVertexCheck.cxx src/VertexingQcTask.cxx src/ITSTPCMatchingTask.cxx src/DataCompressionQcTask.cxx src/CTFSizeTask.cxx) +target_sources(O2QcGLO PRIVATE src/ITSTPCmatchingCheck.cxx src/MeanVertexPostProcessing.cxx src/MeanVertexCheck.cxx src/VertexingQcTask.cxx src/ITSTPCMatchingTask.cxx src/DataCompressionQcTask.cxx src/CTFSizeTask.cxx) target_include_directories( O2QcGLO @@ -46,7 +47,8 @@ add_root_dictionary(O2QcGLO include/GLO/ITSTPCMatchingTask.h include/GLO/DataCompressionQcTask.h include/GLO/CTFSizeTask.h - LINKDEF include/GLO/LinkDef.h) + include/GLO/ITSTPCmatchingCheck.h + LINKDEF include/GLO/LinkDef.h) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/GLO DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/QualityControl") diff --git a/Modules/GLO/glo-itstpc-mtch-qcmn-test.json b/Modules/GLO/glo-itstpc-mtch-qcmn-test.json new file mode 100644 index 0000000000..a82c200256 --- /dev/null +++ b/Modules/GLO/glo-itstpc-mtch-qcmn-test.json @@ -0,0 +1,99 @@ +{ + "qc": { + "config": { + "database": { + "implementation": "CCDB", + "host": "ccdb-test.cern.ch:8080", + "username": "not_applicable", + "password": "not_applicable", + "name": "not_applicable", + "maxObjectSize": "20000000" + }, + "Activity": { + "number": "43", + "type": "2" + }, + "monitoring": { + "url": "infologger:///debug?qc" + }, + "consul": { + "url": "" + }, + "conditionDB": { + "url": "alice-ccdb.cern.ch" + }, + "infologger": { + "filterDiscardDebug": "false", + "filterDiscardLevel": "0" + } + }, + "tasks": { + "ITSTPCMatchingTask": { + "active": "true", + "className": "o2::quality_control_modules::glo::ITSTPCMatchingTask", + "moduleName": "QcGLO", + "detectorName": "GLO", + "cycleDurationSeconds": "60", + "maxNumberCycles": "-1", + "dataSource": { + "type": "direct", + "query_comment": "checking every matched track", + "query": "trackITSTPC:GLO/TPCITS/0;trackITSTPCABREFS:GLO/TPCITSAB_REFS/0;trackITSTPCABCLID:GLO/TPCITSAB_CLID/0;trackTPC:TPC/TRACKS;trackTPCClRefs:TPC/CLUSREFS;trackITS:ITS/TRACKS/0;trackITSROF:ITS/ITSTrackROF/0;trackITSClIdx:ITS/TRACKCLSID/0;alpparITS:ITS/ALPIDEPARAM/0?lifetime=condition&ccdb-path=ITS/Config/AlpideParam" + }, + "taskParameters": { + "GID": "ITS-TPC,ITS", + "verbose": "false", + "minPtCut": "0.1f", + "etaCut": "1.4f", + "minNTPCClustersCut": "60", + "minDCACut": "100.f", + "minDCACutY": "10.f" + }, + "grpGeomRequest": { + "geomRequest": "None", + "askGRPECS": "false", + "askGRPLHCIF": "false", + "askGRPMagField": "true", + "askMatLUT": "false", + "askTime": "false", + "askOnceAllButField": "true", + "needPropagatorD": "false" + }, + "saveObjectsToFile": "ITSTPCmatched.root", + "": "For debugging, path to the file where to save. If empty or missing it won't save." + } + }, + "checks": { + "ITSTPCMatchingCheck": { + "active": "true", + "className": "o2::quality_control_modules::glo::ITSTPCmatchingCheck", + "moduleName": "QcGLO", + "policy": "OnAny", + "detectorName": "GLO", + "dataSource": [ + { + "type": "Task", + "name": "ITSTPCMatchingTask", + "MOs": [ + "mFractionITSTPCmatch_ITS", + "mFractionITSTPCmatchPhi_ITS", + "mFractionITSTPCmatchEta_ITS" + ] + } + ], + "extendedCheckParameters": { + "default": { + "default": { + "showPt": "true", + "thresholdPt": "0.9", + "showPhi": "true", + "thresholdPhi": "0.3", + "showEta": "1", + "thresholdEta": "0.4" + } + } + } + } + } + } +} diff --git a/Modules/GLO/include/GLO/ITSTPCmatchingCheck.h b/Modules/GLO/include/GLO/ITSTPCmatchingCheck.h new file mode 100644 index 0000000000..45b9c52ae5 --- /dev/null +++ b/Modules/GLO/include/GLO/ITSTPCmatchingCheck.h @@ -0,0 +1,63 @@ +// 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 ITSTPCmatchingCheck.h +/// \author felix.schlepper@cern.ch +/// + +#ifndef QC_MODULE_GLO_GLOITSTPCMATCHINGCHECK_H +#define QC_MODULE_GLO_GLOITSTPCMATCHINGCHECK_H + +#include "QualityControl/CheckInterface.h" +#include "QualityControl/Quality.h" + +#include +#include + +namespace o2::quality_control_modules::glo +{ + +/// \brief Check for ITS-TPC sync. matching efficiency +/// \author felix.schlepper@cern.ch +class ITSTPCmatchingCheck : public o2::quality_control::checker::CheckInterface +{ + public: + Quality check(std::map>* moMap) override; + void beautify(std::shared_ptr mo, Quality checkResult = Quality::Null) override; + void startOfActivity(const Activity& activity) override; + + private: + std::vector> findRanges(const std::vector& nums); + std::shared_ptr mActivity; + + // Pt + bool mShowPt{ true }; + float mMinPt{ 1. }; + float mMaxPt{ 1.999 }; + float mThresholdPt{ 0.5 }; + + // Phi + bool mShowPhi{ true }; + float mThresholdPhi{ 0.3 }; + + // Eta + bool mShowEta{ false }; + float mThresholdEta{ 0.4 }; + float mMinEta{ -0.8 }; + float mMaxEta{ 0.8 }; + + ClassDefOverride(ITSTPCmatchingCheck, 1); +}; + +} // namespace o2::quality_control_modules::glo + +#endif // QC_MODULE_GLO_GLOITSTPCMATCHINGCHECK_H diff --git a/Modules/GLO/include/GLO/LinkDef.h b/Modules/GLO/include/GLO/LinkDef.h index c22c927dcd..20d5a93905 100644 --- a/Modules/GLO/include/GLO/LinkDef.h +++ b/Modules/GLO/include/GLO/LinkDef.h @@ -11,4 +11,6 @@ #pragma link C++ class o2::quality_control_modules::glo::MeanVertexCheck + ; #pragma link C++ class o2::quality_control_modules::glo::CTFSize + ; +#pragma link C++ class o2::quality_control_modules::glo::ITSTPCmatchingCheck + ; + #endif diff --git a/Modules/GLO/src/ITSTPCmatchingCheck.cxx b/Modules/GLO/src/ITSTPCmatchingCheck.cxx new file mode 100644 index 0000000000..4517fedb02 --- /dev/null +++ b/Modules/GLO/src/ITSTPCmatchingCheck.cxx @@ -0,0 +1,564 @@ +// 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 ITSTPCmatchingCheck.cxx +/// \author felix.schlepper@cern.ch +/// + +#include "GLO/ITSTPCmatchingCheck.h" +#include "QualityControl/MonitorObject.h" +#include "QualityControl/Quality.h" +#include "QualityControl/QcInfoLogger.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include "fmt/format.h" + +using namespace std; +using namespace o2::quality_control; + +namespace o2::quality_control_modules::glo +{ + +Quality ITSTPCmatchingCheck::check(std::map>* moMap) +{ + Quality result = Quality::Null; + Quality ptQual = Quality::Good; + Quality phiQual = Quality::Good; + Quality etaQual = Quality::Good; + + for (auto& [moName, mo] : *moMap) { + (void)moName; + + if (mShowPt && mo->getName() == "mFractionITSTPCmatch_ITS") { + auto* eff = dynamic_cast(mo->getObject()); + if (eff == nullptr) { + ILOG(Error) << "Failed cast for ITSTPCmatch_ITS check!" << ENDM; + continue; + } + auto binLow = eff->FindFixBin(mMinPt), binUp = eff->FindFixBin(mMaxPt); + + ptQual = Quality::Good; + result.addMetadata("checkPtQuality", "good"); + result.addMetadata("checkPtBins", ""); + result.addMetadata("checkPtDen", "good"); + result.addMetadata("checkPtNum", "good"); + if (eff->GetTotalHistogram()->GetEntries() == 0) { + ptQual = Quality::Null; + result.updateMetadata("checkPtDen", "null"); + } else if (eff->GetPassedHistogram()->GetEntries() == 0) { + ptQual = Quality::Bad; + result.updateMetadata("checkPtNum", "bad"); + } else { + std::vector badBins; + for (int iBin = binLow; iBin <= binUp; ++iBin) { + if (eff->GetEfficiency(iBin) < mThresholdPt) { + ptQual = Quality::Bad; + badBins.push_back(iBin); + } + } + auto ranges = findRanges(badBins); + if (ptQual == Quality::Bad) { + result.addReason(FlagReasonFactory::BadTracking(), "Check vdrift online calibration and ITS/TPC QC"); + result.updateMetadata("checkPtQuality", "bad"); + + std::string cBins{ "Bad matching efficiency in: " }; + for (const auto& [binLow, binUp] : ranges) { + float low = eff->GetPassedHistogram()->GetXaxis()->GetBinLowEdge(binLow), up = eff->GetPassedHistogram()->GetXaxis()->GetBinUpEdge(binUp); + cBins += fmt::format("{:.1f}-{:.1f},", low, up); + } + cBins.pop_back(); // remove last `,` + cBins += " (GeV/c)"; + result.updateMetadata("checkPtBins", cBins); + } + } + } + + if (mShowPhi && mo->getName() == "mFractionITSTPCmatchPhi_ITS") { + auto* eff = dynamic_cast(mo->getObject()); + if (eff == nullptr) { + ILOG(Error) << "Failed cast for ITSTPCmatchPhi_ITS check!" << ENDM; + continue; + } + + phiQual = Quality::Good; + result.addMetadata("checkPhiQuality", "good"); + result.addMetadata("checkPhiBins", ""); + result.addMetadata("checkPhiDen", "good"); + result.addMetadata("checkPhiNum", "good"); + if (eff->GetTotalHistogram()->GetEntries() == 0) { + phiQual = Quality::Null; + result.updateMetadata("checkPhiDen", "null"); + } else if (eff->GetPassedHistogram()->GetEntries() == 0) { + phiQual = Quality::Bad; + result.updateMetadata("checkPhiNum", "bad"); + } else { + std::vector badBins; + for (int iBin{ 1 }; iBin <= eff->GetPassedHistogram()->GetNbinsX(); ++iBin) { + if (eff->GetEfficiency(iBin) < mThresholdPhi) { + phiQual = Quality::Bad; + badBins.push_back(iBin); + } + } + auto ranges = findRanges(badBins); + if (phiQual == Quality::Bad) { + result.addReason(FlagReasonFactory::BadTracking(), "Check TPC sectors or ITS staves QC!"); + result.updateMetadata("checkPhiQuality", "bad"); + + std::string cBins{ "Bad matching efficiency in: " }; + for (const auto& [binLow, binUp] : ranges) { + float low = eff->GetPassedHistogram()->GetXaxis()->GetBinLowEdge(binLow), up = eff->GetPassedHistogram()->GetXaxis()->GetBinUpEdge(binUp); + cBins += fmt::format("{:.1f}-{:.1f},", low, up); + } + cBins.pop_back(); // remove last `,` + cBins += " (rad)"; + result.updateMetadata("checkPhiBins", cBins); + } + } + } + + if (mShowEta && mo->getName() == "mFractionITSTPCmatchEta_ITS") { + auto* eff = dynamic_cast(mo->getObject()); + if (eff == nullptr) { + ILOG(Error) << "Failed cast for ITSTPCmatchEta_ITS check!" << ENDM; + continue; + } + auto binLow = eff->FindFixBin(mMinEta), binUp = eff->FindFixBin(mMaxEta); + + etaQual = Quality::Good; + result.addMetadata("checkEtaQuality", "good"); + result.addMetadata("checkEtaBins", ""); + result.addMetadata("checkEtaDen", "good"); + result.addMetadata("checkEtaNum", "good"); + if (eff->GetTotalHistogram()->GetEntries() == 0) { + ptQual = Quality::Null; + result.updateMetadata("checkEtaDen", "null"); + } else if (eff->GetPassedHistogram()->GetEntries() == 0) { + ptQual = Quality::Bad; + result.updateMetadata("checkEtaNum", "bad"); + } else { + std::vector badBins; + for (int iBin = binLow; iBin <= binUp; ++iBin) { + if (eff->GetEfficiency(iBin) < mThresholdEta) { + ptQual = Quality::Bad; + badBins.push_back(iBin); + } + } + auto ranges = findRanges(badBins); + if (ptQual == Quality::Bad) { + result.updateMetadata("checkEtaQuality", "bad"); + + std::string cBins{ "Bad matching efficiency in: " }; + for (const auto& [binLow, binUp] : ranges) { + float low = eff->GetPassedHistogram()->GetXaxis()->GetBinLowEdge(binLow), up = eff->GetPassedHistogram()->GetXaxis()->GetBinUpEdge(binUp); + cBins += fmt::format("{:.1f}-{:.1f},", low, up); + } + cBins.pop_back(); // remove last `,` + result.updateMetadata("checkEtaBins", cBins); + } + } + } + } + + // Overall Quality + auto isWorse = [](Quality const& a, Quality const& b) { + return a.isWorseThan(b) ? a : b; + }; + auto findWorst = [&](const T& first, Args... args) + { + return isWorse(first, isWorse(args...)); + }; + result.set(findWorst(ptQual, etaQual, phiQual)); + + return result; +} + +void ITSTPCmatchingCheck::beautify(std::shared_ptr mo, Quality checkResult) +{ + if (mo == nullptr) { + ILOG(Error) << "Received nullptr from upstream, returning..." << ENDM; + return; + } + + if (mShowPt && mo->getName() == "mFractionITSTPCmatch_ITS") { + auto* eff = dynamic_cast(mo->getObject()); + if (eff == nullptr) { + ILOG(Error) << "Failed cast for ITSTPCmatch_ITS beautify!" << ENDM; + return; + } + // Draw threshold lines + float xmin = eff->GetPassedHistogram()->GetXaxis()->GetXmin(); + float xmax = eff->GetPassedHistogram()->GetXaxis()->GetXmax(); + float xminT = mMinPt; + float xmaxT = mMaxPt; + auto* l1 = new TLine(xmin, mThresholdPt, xmax, mThresholdPt); + l1->SetLineStyle(kDashed); + l1->SetLineWidth(4); + l1->SetLineColor(kCyan - 7); + auto* l2 = new TLine(xminT, 0, xminT, 1.1); + l2->SetLineStyle(kDashed); + l2->SetLineWidth(4); + l2->SetLineColor(kCyan - 7); + auto* l3 = new TLine(xmaxT, 0, xmaxT, 1.1); + l3->SetLineStyle(kDashed); + l3->SetLineWidth(4); + l3->SetLineColor(kCyan - 7); + auto* tt = new TText(xminT + 0.1, 1.05, "Checked Range"); + tt->SetTextSize(0.04); + auto* ttt = new TText(xmaxT + 0.9, mThresholdPt + 0.012, "Threshold"); + auto* aa = new TArrow(xminT + 0.01, 1.02, xmaxT - 0.01, 1.02, 0.02, "<|>"); + if (checkResult.getMetadata("checkPtQuality") == "good") { + l1->SetLineColor(kCyan - 7); + l2->SetLineColor(kCyan - 7); + l3->SetLineColor(kCyan - 7); + aa->SetFillColor(kCyan - 7); + aa->SetLineColor(kCyan - 7); + } else { + l1->SetLineColor(kRed - 4); + l2->SetLineColor(kRed - 4); + l3->SetLineColor(kRed - 4); + aa->SetFillColor(kRed - 4); + aa->SetLineColor(kRed - 4); + } + eff->GetListOfFunctions()->Add(l1); + eff->GetListOfFunctions()->Add(l2); + eff->GetListOfFunctions()->Add(l3); + eff->GetListOfFunctions()->Add(tt); + eff->GetListOfFunctions()->Add(ttt); + eff->GetListOfFunctions()->Add(aa); + + // Color Bins in Window + int cG{ 0 }, cB{ 0 }; + auto* good = new TPolyMarker(); + good->SetMarkerColor(kGreen); + good->SetMarkerStyle(25); + good->SetMarkerSize(2); + auto* bad = new TPolyMarker(); + bad->SetMarkerColor(kRed); + bad->SetMarkerStyle(25); + bad->SetMarkerSize(2); + auto* leg = new TLegend(0.7, 0.13, 0.89, 0.3); + leg->SetNColumns(2); + leg->SetHeader("Threshold Checks"); + leg->AddEntry(good, "Good", "P"); + leg->AddEntry(bad, "Bad", "P"); + auto binLow = eff->FindFixBin(mMinPt), binUp = eff->FindFixBin(mMaxPt); + for (int iBin = binLow; iBin <= binUp; ++iBin) { + auto x = eff->GetPassedHistogram()->GetBinCenter(iBin); + auto y = eff->GetEfficiency(iBin); + if (eff->GetEfficiency(iBin) < mThresholdPt) { + bad->SetPoint(cB++, x, y); + } else { + good->SetPoint(cG++, x, y); + } + } + eff->GetListOfFunctions()->Add(good); + eff->GetListOfFunctions()->Add(bad); + eff->GetListOfFunctions()->Add(leg); + + // Quality + auto* msg = new TPaveText(0.12, 0.12, 0.5, 0.3, "NDC;NB"); + if (checkResult.getMetadata("checkPtQuality") == "good") { + msg->AddText("Quality: Good"); + msg->SetFillColor(kGreen); + } else if (checkResult.getMetadata("checkPtQuality") == "bad") { + msg->AddText("Quality: Bad"); + msg->SetFillColor(kRed); + msg->AddText("Check vdrift online calibration and ITS/TPC QC"); + msg->AddText(checkResult.getMetadata("checkPtBins").c_str()); + msg->SetTextColor(kWhite); + } else if (checkResult.getMetadata("checkPtQuality") == "null") { + msg->SetFillColor(kWhite); + msg->AddText("Quality: Null"); + msg->AddText("No ITS tracks in denominator!"); + msg->AddText(checkResult.getMetadata("checkPtBins").c_str()); + msg->SetTextColor(kBlack); + } else { + msg->AddText("Quality: Undefined"); + msg->AddText("Not-handled Quality flag, don't panic..."); + } + eff->GetListOfFunctions()->Add(msg); + } + + if (mShowPhi && mo->getName() == "mFractionITSTPCmatchPhi_ITS") { + auto* eff = dynamic_cast(mo->getObject()); + if (eff == nullptr) { + ILOG(Error) << "Failed cast for ITSTPCmatchPhi_ITS beautify!" << ENDM; + return; + } + // Draw threshold lines + auto* l1 = new TLine(0, mThresholdPhi, 2 * TMath::Pi(), mThresholdPhi); + l1->SetLineStyle(kDashed); + l1->SetLineWidth(4); + l1->SetLineColor(kCyan - 7); + auto* tt = new TText(TMath::Pi() - 1., 1.05, "Checked Range"); + tt->SetTextSize(0.04); + auto* ttt = new TText(2 * TMath::Pi() - 0.9, mThresholdPhi + 0.012, "Threshold"); + auto* aa = new TArrow(0.01, 1.02, 2 * TMath::Pi() - 0.01, 1.02, 0.02, "<|>"); + if (checkResult.getMetadata("checkPhiQuality") == "good") { + l1->SetLineColor(kCyan - 7); + aa->SetFillColor(kCyan - 7); + aa->SetLineColor(kCyan - 7); + } else { + l1->SetLineColor(kRed - 4); + aa->SetFillColor(kRed - 4); + aa->SetLineColor(kRed - 4); + } + eff->GetListOfFunctions()->Add(l1); + eff->GetListOfFunctions()->Add(tt); + eff->GetListOfFunctions()->Add(ttt); + eff->GetListOfFunctions()->Add(aa); + + // Color Bins in Window + int cG{ 0 }, cB{ 0 }; + auto* good = new TPolyMarker(); + good->SetMarkerColor(kGreen); + good->SetMarkerStyle(25); + good->SetMarkerSize(1); + auto* bad = new TPolyMarker(); + bad->SetMarkerColor(kRed); + bad->SetMarkerStyle(25); + bad->SetMarkerSize(1); + auto* leg = new TLegend(0.7, 0.13, 0.89, 0.3); + leg->SetNColumns(2); + leg->SetHeader("Threshold Checks"); + leg->AddEntry(good, "Good", "P"); + leg->AddEntry(bad, "Bad", "P"); + for (int iBin{ 1 }; iBin <= eff->GetPassedHistogram()->GetNbinsX(); ++iBin) { + auto x = eff->GetPassedHistogram()->GetBinCenter(iBin); + auto y = eff->GetEfficiency(iBin); + if (eff->GetEfficiency(iBin) < mThresholdPhi) { + bad->SetPoint(cB++, x, y); + } else { + good->SetPoint(cG++, x, y); + } + } + eff->GetListOfFunctions()->Add(good); + eff->GetListOfFunctions()->Add(bad); + eff->GetListOfFunctions()->Add(leg); + + // Quality + auto* msg = new TPaveText(0.12, 0.12, 0.5, 0.3, "NDC;NB"); + if (checkResult.getMetadata("checkPhiQuality") == "good") { + msg->AddText("Quality: Good"); + msg->SetFillColor(kGreen); + } else if (checkResult.getMetadata("checkPhiQuality") == "bad") { + msg->AddText("Quality: Bad"); + msg->SetFillColor(kRed); + msg->AddText("Check TPC sector or ITS staves!"); + msg->AddText(checkResult.getMetadata("checkPhiBins").c_str()); + msg->SetTextColor(kWhite); + } else if (checkResult.getMetadata("checkPhiQuality") == "null") { + msg->SetFillColor(kWhite); + msg->AddText("Quality: Null"); + msg->AddText("No ITS tracks in denominator!"); + msg->SetTextColor(kBlack); + } else { + msg->AddText("Quality: Undefined"); + msg->AddText("Not-handled Quality flag, don't panic..."); + } + eff->GetListOfFunctions()->Add(msg); + } + + if (mShowEta && mo->getName() == "mFractionITSTPCmatchEta_ITS") { + auto* eff = dynamic_cast(mo->getObject()); + if (eff == nullptr) { + ILOG(Error) << "Failed cast for ITSTPCmatchEta_ITS beautify!" << ENDM; + return; + } + // Draw threshold lines + float xmin = eff->GetPassedHistogram()->GetXaxis()->GetXmin(); + float xmax = eff->GetPassedHistogram()->GetXaxis()->GetXmax(); + float xminT = mMinEta; + float xmaxT = mMaxEta; + auto* l1 = new TLine(xmin, mThresholdEta, xmax, mThresholdEta); + l1->SetLineStyle(kDashed); + l1->SetLineWidth(4); + l1->SetLineColor(kCyan - 7); + auto* l2 = new TLine(xminT - 0.02, 0, xminT - 0.02, 1.1); + l2->SetLineStyle(kDashed); + l2->SetLineWidth(4); + l2->SetLineColor(kCyan - 7); + auto* l3 = new TLine(xmaxT + 0.02, 0, xmaxT + 0.02, 1.1); + l3->SetLineStyle(kDashed); + l3->SetLineWidth(4); + l3->SetLineColor(kCyan - 7); + auto* tt = new TText(xminT + 0.1, 1.05, "Checked Range"); + tt->SetTextSize(0.04); + auto* ttt = new TText(xmaxT + 0.4, mThresholdEta + 0.012, "Threshold"); + auto* aa = new TArrow(xminT + 0.01, 1.02, xmaxT - 0.01, 1.02, 0.02, "<|>"); + if (checkResult.getMetadata("checkEtaQuality") == "good") { + l1->SetLineColor(kCyan - 7); + l2->SetLineColor(kCyan - 7); + l3->SetLineColor(kCyan - 7); + aa->SetFillColor(kCyan - 7); + aa->SetLineColor(kCyan - 7); + } else { + l1->SetLineColor(kRed - 4); + l2->SetLineColor(kRed - 4); + l3->SetLineColor(kRed - 4); + aa->SetFillColor(kRed - 4); + aa->SetLineColor(kRed - 4); + } + eff->GetListOfFunctions()->Add(l1); + eff->GetListOfFunctions()->Add(l2); + eff->GetListOfFunctions()->Add(l3); + eff->GetListOfFunctions()->Add(tt); + eff->GetListOfFunctions()->Add(ttt); + eff->GetListOfFunctions()->Add(aa); + + // Color Bins in Window + int cG{ 0 }, cB{ 0 }; + auto* good = new TPolyMarker(); + good->SetMarkerColor(kGreen); + good->SetMarkerStyle(25); + good->SetMarkerSize(1); + auto* bad = new TPolyMarker(); + bad->SetMarkerColor(kRed); + bad->SetMarkerStyle(25); + bad->SetMarkerSize(1); + auto* leg = new TLegend(0.7, 0.13, 0.89, 0.3); + leg->SetNColumns(2); + leg->SetHeader("Threshold Checks"); + leg->AddEntry(good, "Good", "P"); + leg->AddEntry(bad, "Bad", "P"); + auto binLow = eff->FindFixBin(mMinEta), binUp = eff->FindFixBin(mMaxEta); + for (int iBin = binLow; iBin <= binUp; ++iBin) { + auto x = eff->GetPassedHistogram()->GetBinCenter(iBin); + auto y = eff->GetEfficiency(iBin); + if (eff->GetEfficiency(iBin) < mThresholdEta) { + bad->SetPoint(cB++, x, y); + } else { + good->SetPoint(cG++, x, y); + } + } + eff->GetListOfFunctions()->Add(good); + eff->GetListOfFunctions()->Add(bad); + eff->GetListOfFunctions()->Add(leg); + + // Quality + auto* msg = new TPaveText(0.12, 0.12, 0.5, 0.3, "NDC;NB"); + if (checkResult.getMetadata("checkEtaQuality") == "good") { + msg->AddText("Quality: Good"); + msg->SetFillColor(kGreen); + } else if (checkResult.getMetadata("checkEtaQuality") == "bad") { + msg->AddText("Quality: Bad"); + msg->SetFillColor(kRed); + msg->AddText(checkResult.getMetadata("checkEtaBins").c_str()); + msg->SetTextColor(kWhite); + } else if (checkResult.getMetadata("checkEtaQuality") == "null") { + msg->SetFillColor(kWhite); + msg->AddText("Quality: Null"); + msg->AddText("No ITS tracks in denominator!"); + msg->SetTextColor(kBlack); + } else { + msg->AddText("Quality: Undefined"); + msg->AddText("Not-handled Quality flag, don't panic..."); + } + eff->GetListOfFunctions()->Add(msg); + } +} + +void ITSTPCmatchingCheck::startOfActivity(const Activity& activity) +{ + mActivity = make_shared(activity); + + // Casting function with error handling + auto ccast = [](T& p, const std::string& par) -> void { + try { + if constexpr (std::is_floating_point_v) { + p = static_cast(std::stof(par)); + } else if constexpr (std::is_integral_v) { + if (par != "true" && par != "false") { + p = static_cast(std::stoi(par)); + } else { + p = par == "true"; + } + } else { + p = static_cast(par); + } + } catch (std::exception& err) { + ILOG(Error) << "Cannot cast parameter in config file " << par << " " << err.what() << "'; using default..." << ENDM; + } + }; + + // Parse a generic parameter + auto parseParam = [&](T& p, const std::string& name, const std::string& def) -> void { + std::string parameter; + if (auto param = mCustomParameters.atOptional(name, activity)) { + parameter = param.value(); + } else { + parameter = mCustomParameters.atOrDefaultValue(name, def); + } + ccast(p, parameter); + }; + + // Pt + parseParam(mShowPt, "showPt", "true"); + if (mShowPt) { + parseParam(mThresholdPt, "thresholdPt", "0.5"); + parseParam(mMinPt, "minPt", "1.0"); + parseParam(mMaxPt, "maxPt", "1.999"); + } + + // Phi + parseParam(mShowPhi, "showPhi", "true"); + if (mShowPhi) { + parseParam(mThresholdPhi, "thresholdPhi", "0.3"); + } + + // Eta + parseParam(mShowEta, "showEta", "false"); + if (mShowEta) { + parseParam(mThresholdEta, "thresholdEta", "0.4"); + parseParam(mMinEta, "minEta", "-0.8"); + parseParam(mMaxEta, "maxEta", "0.8"); + } +} + +std::vector> ITSTPCmatchingCheck::findRanges(const std::vector& nums) +{ + std::vector> ranges; + if (nums.empty()) + return ranges; + + int start = nums[0]; + int end = start; + + for (size_t i = 1; i < nums.size(); ++i) { + if (nums[i] == end + 1) { + end = nums[i]; + } else { + ranges.push_back(std::make_pair(start, end)); + start = end = nums[i]; + } + } + ranges.push_back(std::make_pair(start, end)); // Add the last range + return ranges; +} + +} // namespace o2::quality_control_modules::glo diff --git a/Modules/TPC/include/TPC/CheckOfSlices.h b/Modules/TPC/include/TPC/CheckOfSlices.h index e19ce1bb88..ab16896c08 100644 --- a/Modules/TPC/include/TPC/CheckOfSlices.h +++ b/Modules/TPC/include/TPC/CheckOfSlices.h @@ -55,6 +55,7 @@ class CheckOfSlices : public o2::quality_control::checker::CheckInterface double mRangeMedium; double mRangeBad; bool mSliceTrend; + std::vector mMaskedPoints; double mMean = 0; double mStdev; diff --git a/Modules/TPC/include/TPC/ClusterVisualizer.h b/Modules/TPC/include/TPC/ClusterVisualizer.h index 1ca259e52f..880a0e1f8b 100644 --- a/Modules/TPC/include/TPC/ClusterVisualizer.h +++ b/Modules/TPC/include/TPC/ClusterVisualizer.h @@ -66,7 +66,7 @@ class ClusterVisualizer final : public quality_control::postprocessing::PostProc void finalize(quality_control::postprocessing::Trigger, framework::ServiceRegistryRef) override; template - void makeRadialProfile(o2::tpc::CalDet& calDet, TCanvas* canv, int nbinsY, float yMin, float yMax); + void makeRadialProfile(const o2::tpc::CalDet& calDet, TCanvas* canv); template void fillRadialHisto(TH2D& h2D, const o2::tpc::CalDet& calDet, const o2::tpc::Side side); diff --git a/Modules/TPC/include/TPC/Utility.h b/Modules/TPC/include/TPC/Utility.h index 3478a6268d..18f505200f 100644 --- a/Modules/TPC/include/TPC/Utility.h +++ b/Modules/TPC/include/TPC/Utility.h @@ -73,7 +73,7 @@ void getTimestamp(const std::string& metaInfo, std::vector& timeStamps); /// \param limit Most recent timestamp to be processed std::vector getDataTimestamps(const o2::ccdb::CcdbApi& cdbApi, const std::string_view path, const unsigned int nFiles, const long limit); -/// \brief Calculates mean and stddev from yValues of a TGraph +/// \brief Calculates mean and stddev from yValues of a TGraph. Overloaded function, actual calculation in retrieveStatistics /// \param yValues const double* pointer to yValues of TGraph (via TGraph->GetY()) /// \param yErrors const double* pointer to y uncertainties of TGraph (via TGraph->GetEY()) /// \param useErrors bool whether uncertainties should be used in calculation of mean and stddev of mean @@ -82,5 +82,24 @@ std::vector getDataTimestamps(const o2::ccdb::CcdbApi& cdbApi, const std:: /// \param mean double&, reference to double that should store mean /// \param stddevOfMean double&, reference to double that should store stddev of mean void calculateStatistics(const double* yValues, const double* yErrors, bool useErrors, const int firstPoint, const int lastPoint, double& mean, double& stddevOfMean); + +/// \brief Calculates mean and stddev from yValues of a TGraph. Overloaded function +/// \param yValues const double* pointer to yValues of TGraph (via TGraph->GetY()) +/// \param yErrors const double* pointer to y uncertainties of TGraph (via TGraph->GetEY()) +/// \param useErrors bool whether uncertainties should be used in calculation of mean and stddev of mean +/// \param firstPoint const int, first point of yValues to include in calculation +/// \param lastPoint const int, last point of yValues to include in calculation +/// \param mean double&, reference to double that should store mean +/// \param stddevOfMean double&, reference to double that should store stddev of mean +/// \param maskPoints std::vector&, points of the selected TGraph-points that should be masked +void calculateStatistics(const double* yValues, const double* yErrors, bool useErrors, const int firstPoint, const int lastPoint, double& mean, double& stddevOfMean, std::vector& maskPoints); + +/// \brief Calculates mean and stddev from yValues of a TGraph. Overloaded function, actual calculation in retrieveStatistics +/// \param values std::vector& vector that contains the data points +/// \param errors std::vector& vector that contains the data errors +/// \param useErrors bool whether uncertainties should be used in calculation of mean and stddev of mean +/// \param mean double&, reference to double that should store mean +/// \param stddevOfMean double&, reference to double that should store stddev of mean +void retrieveStatistics(std::vector& values, std::vector& errors, bool useErrors, double& mean, double& stddevOfMean); } // namespace o2::quality_control_modules::tpc #endif // QUALITYCONTROL_TPCUTILITY_H \ No newline at end of file diff --git a/Modules/TPC/run/tpcQCClusters_direct.json b/Modules/TPC/run/tpcQCClusters_direct.json index e8444598e2..3d1426d070 100644 --- a/Modules/TPC/run/tpcQCClusters_direct.json +++ b/Modules/TPC/run/tpcQCClusters_direct.json @@ -29,7 +29,6 @@ "moduleName": "QcTPC", "detectorName": "TPC", "cycleDurationSeconds": "60", - "maxNumberCycles": "-1", "resetAfterCycles": "5", "dataSource": { "type": "direct", @@ -45,6 +44,16 @@ "TimeBinNBins": "1000", "TimeBinXMin": "0", "TimeBinXMax": "100000", "OccupancyNBins": "1000", "OccupancyXMin": "0", "OccupancyXMax": "0.00001" }, + "grpGeomRequest" : { + "geomRequest": "None", + "askGRPECS": "false", + "askGRPLHCIF": "false", + "askGRPMagField": "true", + "askMatLUT": "true", + "askTime": "false", + "askOnceAllButField": "true", + "needPropagatorD": "false" + }, "location": "local", "localMachines": [ "localhost" @@ -53,6 +62,62 @@ "remotePort": "32626", "mergingMode": "delta" } + }, + "postprocessing": { + "Clusters": { + "active": "true", + "className": "o2::quality_control_modules::tpc::ClusterVisualizer", + "moduleName": "QcTPC", + "detectorName": "TPC", + "dataSourceURL": "ccdb-test.cern.ch:8080", + "timestamps_comment": [ "Put the timestamp of the corresponding file you want to look for in the timestamps array.", + "You can either put a timestamp for every object or leave the array empty to take the latest file from the CCDB.", + "An empty array to get the the latest version will be the main use case.", + "The array is mapped to the output objects sequentially", + "If you want to pick the latest file in the CCDB manually, you can use -1." + ], + "timestamps": [ + ], + "lookupMetaData_comment": [ "With this array you can filter your search via meta data.", + "The array is mapped sequentially to the output objects.", + "If you leave only one entry in the array this is used for all objects in outputCalPadMaps and outputCalPads.", + "If you want no meta data simply remove 'keys' and 'values' completely and leave only {}", + "Every entry above (outputCalPads.size() + outputCalPadMaps.size()) is ignored.", + "The keys and values that are set by default are only there to serve as an example." + ], + "lookupMetaData": [ + { + } + ], + "storeMetaData_comment": "For how-to, see 'lookupMetaData_comment'.", + "storeMetaData": [ + { + } + ], + "histogramRanges_comment" : [ "nBins", "min", "max" ], + "histogramRanges": [ + { "N_Clusters" : [ "100", "0", "100" ] }, + { "Q_Max" : [ "200", "0", "200" ] }, + { "Q_Tot" : [ "600", "0", "600" ] }, + { "Sigma_Time" : [ "200", "0", "2" ] }, + { "Sigma_Pad" : [ "200", "0", "2" ] }, + { "Time_Bin" : [ "1000", "0", "100000" ] } + ], + "path_comment": "This is the path of the ClustersData object that shall be visualized.", + "path": "qc/TPC/MO/Clusters/ClusterData", + "dataType_comment": "This is the switch for 'RawDigits' or 'Clusters' task. Choose 'raw' or 'clusters'.", + "dataType": "clusters", + "initTrigger": [ + "userorcontrol" + ], + "updateTrigger_comment": "To trigger on a specific file being updated, use e.g. 'newobject:qcdb:TPC/Calib/Noise'", + "updateTrigger": [ + "newobject:ccdb:qc/TPC/MO/Clusters/ClusterData" + ], + "stopTrigger": [ + "userorcontrol" + ] + } } }, "dataSamplingPolicies": [ diff --git a/Modules/TPC/run/tpcQCSACs.json b/Modules/TPC/run/tpcQCSACs.json index 5074c112e0..1ee020eaca 100644 --- a/Modules/TPC/run/tpcQCSACs.json +++ b/Modules/TPC/run/tpcQCSACs.json @@ -40,7 +40,7 @@ "If you want to pick the latest file in the CCDB manually, you can use -1." ], "timestamps": [ - { "SACZero":"1686390443945" }, + { "SACZero":"-1" }, { "SACOne":"-1" }, { "SACDelta":"-1" }, { "SACFourierCoeffs":"-1" } diff --git a/Modules/TPC/run/tpcQCTracks_sampled.json b/Modules/TPC/run/tpcQCTracks_sampled.json index 4a20c21ea1..9a29db7ede 100644 --- a/Modules/TPC/run/tpcQCTracks_sampled.json +++ b/Modules/TPC/run/tpcQCTracks_sampled.json @@ -9,7 +9,7 @@ "name": "not_applicable" }, "Activity": { - "number": "592390" + "number": "303000" }, "monitoring": { "url": "infologger:///debug?qc" diff --git a/Modules/TPC/src/CheckOfSlices.cxx b/Modules/TPC/src/CheckOfSlices.cxx index b075982751..f281d39596 100644 --- a/Modules/TPC/src/CheckOfSlices.cxx +++ b/Modules/TPC/src/CheckOfSlices.cxx @@ -21,6 +21,7 @@ #include #include "Common/Utils.h" #include "TPC/Utility.h" +#include "Algorithm/RangeTokenizer.h" #include #include @@ -32,6 +33,7 @@ #include #include +#include namespace o2::quality_control_modules::tpc { @@ -98,6 +100,12 @@ void CheckOfSlices::configure() } mExpectedPhysicsValue = common::getFromConfig(mCustomParameters, "expectedPhysicsValue", 1); } + + std::string maskingValues = common::getFromConfig(mCustomParameters, "maskedPoints", ""); + mMaskedPoints.clear(); + if (maskingValues != "") { + mMaskedPoints = RangeTokenizer::tokenize(maskingValues); + } } Quality CheckOfSlices::check(std::map>* moMap) @@ -168,7 +176,7 @@ Quality CheckOfSlices::check(std::mapgetClusters(); - auto& calDet = clusters.getNClusters(); - auto vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); - o2::tpc::painter::makeSummaryCanvases(calDet, int(mRanges[calDet.getName()].at(0)), mRanges[calDet.getName()].at(1), mRanges[calDet.getName()].at(2), false, &vecPtr); - calDetIter++; - calDet = clusters.getQMax(); - vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); - o2::tpc::painter::makeSummaryCanvases(calDet, int(mRanges[calDet.getName()].at(0)), mRanges[calDet.getName()].at(1), mRanges[calDet.getName()].at(2), false, &vecPtr); - calDetIter++; - if (mIsClusters) { - calDet = clusters.getQTot(); - vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); - o2::tpc::painter::makeSummaryCanvases(calDet, int(mRanges[calDet.getName()].at(0)), mRanges[calDet.getName()].at(1), mRanges[calDet.getName()].at(2), false, &vecPtr); - calDetIter++; + ////////////-------------------------check lambda expression--- + auto fillCanvases = [&calDetIter, this](const auto& calDet) { + auto vecPtr = toVector(mCalDetCanvasVec.at(calDetIter++)); + const auto& ranges = mRanges[calDet.getName()]; + o2::tpc::painter::makeSummaryCanvases(calDet, int(ranges.at(0)), ranges.at(1), ranges.at(2), false, &vecPtr); +}; - calDet = clusters.getSigmaPad(); - vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); - o2::tpc::painter::makeSummaryCanvases(calDet, int(mRanges[calDet.getName()].at(0)), mRanges[calDet.getName()].at(1), mRanges[calDet.getName()].at(2), false, &vecPtr); - calDetIter++; + fillCanvases(clusters.getNClusters()); + fillCanvases(clusters.getQMax()); - calDet = clusters.getSigmaTime(); - vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); - o2::tpc::painter::makeSummaryCanvases(calDet, int(mRanges[calDet.getName()].at(0)), mRanges[calDet.getName()].at(1), mRanges[calDet.getName()].at(2), false, &vecPtr); - calDetIter++; + if (mIsClusters) { + fillCanvases(clusters.getQTot()); + fillCanvases(clusters.getSigmaPad()); + fillCanvases(clusters.getSigmaTime()); } - calDet = clusters.getTimeBin(); - vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); - o2::tpc::painter::makeSummaryCanvases(calDet, int(mRanges[calDet.getName()].at(0)), mRanges[calDet.getName()].at(1), mRanges[calDet.getName()].at(2), false, &vecPtr); - calDetIter++; - - calDet = clusters.getOccupancy(); - vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); - o2::tpc::painter::makeSummaryCanvases(calDet, int(mRanges[calDet.getName()].at(0)), mRanges[calDet.getName()].at(1), mRanges[calDet.getName()].at(2), false, &vecPtr); - calDetIter++; - vecPtr = toVector(mCalDetCanvasVec.at(calDetIter)); - makeRadialProfile(calDet, vecPtr.at(0), int(mRanges[calDet.getName()].at(0)), mRanges[calDet.getName()].at(1), mRanges[calDet.getName()].at(2)); - calDetIter++; + fillCanvases(clusters.getTimeBin()); + fillCanvases(clusters.getOccupancy()); + + + makeRadialProfile(clusters.getOccupancy(), mCalDetCanvasVec.at(calDetIter++).at(0).get()); } void ClusterVisualizer::finalize(Trigger t, framework::ServiceRegistryRef) @@ -237,10 +222,14 @@ void ClusterVisualizer::finalize(Trigger t, framework::ServiceRegistryRef) } } -template -void ClusterVisualizer::makeRadialProfile(o2::tpc::CalDet& calDet, TCanvas* canv, int nbinsY, float yMin, float yMax) +template void ClusterVisualizer::makeRadialProfile(const o2::tpc::CalDet& calDet, TCanvas* canv) { const std::string_view calName = calDet.getName(); + const auto& ranges = mRanges[calName.data()]; + + const int nbinsY = int(ranges.at(0)); + const float yMin = ranges.at(1); + const float yMax = ranges.at(2); const auto radialBinning = o2::tpc::painter::getRowBinningCM(); auto hAside2D = new TH2D(fmt::format("h_{}_radialProfile_Aside", calName).data(), fmt::format("{}: Radial profile (A-Side)", calName).data(), radialBinning.size() - 1, radialBinning.data(), nbinsY, yMin, yMax); diff --git a/Modules/TPC/src/Clusters.cxx b/Modules/TPC/src/Clusters.cxx index 10936bbddc..2143d146b7 100644 --- a/Modules/TPC/src/Clusters.cxx +++ b/Modules/TPC/src/Clusters.cxx @@ -20,6 +20,8 @@ #include "DataFormatsTPC/ClusterNative.h" #include "TPCBase/Painter.h" #include "Framework/InputRecordWalker.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "DetectorsBase/GRPGeomHelper.h" // QC includes #include "QualityControl/QcInfoLogger.h" @@ -148,11 +150,19 @@ void Clusters::monitorData(ProcessingContext& ctx) { mQCClusters.getClusters().denormalize(); + //get grpECS object here grpecs:GRP/GRPECS + //auto const& grpECS = ctx.inputs().get("grpecs"); + const auto nHBF = o2::base::GRPGeomHelper::instance().getNHBFPerTF(); + std::cout<<" NHBFs = ""<< nHBF" << std::endl; + std::cout<<" NHBFs = "<< nHBF << std::endl; + std::cout<<" NHBFs = ""<< nHBF" << std::endl; + mQCClusters.getClusters().setnHBFperTF(nHBF); processClusterNative(ctx.inputs()); processKrClusters(ctx.inputs()); if (!mIsMergeable) { mQCClusters.getClusters().normalize(); + mQCClusters.getClusters().normalize(); fillCanvases(mQCClusters.getClusters().getNClusters(), mNClustersCanvasVec, mCustomParameters, "NClusters"); fillCanvases(mQCClusters.getClusters().getQMax(), mQMaxCanvasVec, mCustomParameters, "Qmax"); diff --git a/Modules/TPC/src/Utility.cxx b/Modules/TPC/src/Utility.cxx index 13a77a7c1b..d538581e0e 100644 --- a/Modules/TPC/src/Utility.cxx +++ b/Modules/TPC/src/Utility.cxx @@ -30,6 +30,7 @@ // external includes #include #include +#include namespace o2::quality_control_modules::tpc { @@ -210,25 +211,82 @@ void calculateStatistics(const double* yValues, const double* yErrors, bool useE return; } + if (useErrors && !yErrors) { + ILOG(Error, Support) << "In calculateStatistics(): requested to use errors of data but TGraph does not contain errors." << ENDM; + useErrors = false; + } + + std::vector v(yValues + firstPoint, yValues + lastPoint); + std::vector vErr; + + if (useErrors) { + const std::vector vErr_temp(yErrors + firstPoint, yErrors + lastPoint); + for (int i = 0; i < vErr_temp.size(); i++) { + vErr.push_back(vErr_temp[i]); + } + } + + retrieveStatistics(v, vErr, useErrors, mean, stddevOfMean); +} + +void calculateStatistics(const double* yValues, const double* yErrors, bool useErrors, const int firstPoint, const int lastPoint, double& mean, double& stddevOfMean, std::vector& maskPoints) +{ + // yErrors returns nullptr for TGraph (no errors) + if (lastPoint - firstPoint <= 0) { + ILOG(Error, Support) << "In calculateStatistics(), the first and last point of the range have to differ!" << ENDM; + return; + } + + if (useErrors && !yErrors) { + ILOG(Error, Support) << "In calculateStatistics(): requested to use errors of data but TGraph does not contain errors." << ENDM; + useErrors = false; + } + + std::vector v; + const std::vector v_temp(yValues + firstPoint, yValues + lastPoint); + for (int i = 0; i < v_temp.size(); i++) { + if (std::find(maskPoints.begin(), maskPoints.end(), i) == maskPoints.end()) { // i is not in the masked points + v.push_back(v_temp[i]); + } + } + + std::vector vErr; + if (useErrors) { + const std::vector vErr_temp(yErrors + firstPoint, yErrors + lastPoint); + for (int i = 0; i < vErr_temp.size(); i++) { + if (std::find(maskPoints.begin(), maskPoints.end(), i) == maskPoints.end()) { // i is not in the masked points + vErr.push_back(vErr_temp[i]); + } + } + } + + retrieveStatistics(v, vErr, useErrors, mean, stddevOfMean); +} + +void retrieveStatistics(std::vector& values, std::vector& errors, bool useErrors, double& mean, double& stddevOfMean) +{ + if ((errors.size() != values.size()) && useErrors) { + ILOG(Error, Support) << "In retrieveStatistics(): errors do not match data points, omitting errors" << ENDM; + useErrors = false; + } + double sum = 0.; double sumSquare = 0.; double sumOfWeights = 0.; // sum w_i double sumOfSquaredWeights = 0.; // sum (w_i)^2 double weight = 0.; - const std::vector v(yValues + firstPoint, yValues + lastPoint); if (!useErrors) { // In case of no errors, we set our weights equal to 1 - sum = std::accumulate(v.begin(), v.end(), 0.0); - sumOfWeights = v.size(); - sumOfSquaredWeights = v.size(); + sum = std::accumulate(values.begin(), values.end(), 0.0); + sumOfWeights = values.size(); + sumOfSquaredWeights = values.size(); } else { // In case of errors, we set our weights equal to 1/sigma_i^2 - const std::vector vErr(yErrors + firstPoint, yErrors + lastPoint); - for (size_t i = 0; i < v.size(); i++) { - weight = 1. / std::pow(vErr[i], 2.); - sum += v[i] * weight; - sumSquare += v[i] * v[i] * weight; + for (size_t i = 0; i < values.size(); i++) { + weight = 1. / std::pow(errors[i], 2.); + sum += values[i] * weight; + sumSquare += values[i] * values[i] * weight; sumOfWeights += weight; sumOfSquaredWeights += weight * weight; } @@ -236,7 +294,7 @@ void calculateStatistics(const double* yValues, const double* yErrors, bool useE mean = sum / sumOfWeights; - if (v.size() == 1) { // we only have one point, we keep it's uncertainty + if (values.size() == 1) { // we only have one point, we keep it's uncertainty if (!useErrors) { stddevOfMean = 0.; } else { @@ -244,10 +302,10 @@ void calculateStatistics(const double* yValues, const double* yErrors, bool useE } } else { // for >= 2 points, we calculate the spread if (!useErrors) { - std::vector diff(v.size()); - std::transform(v.begin(), v.end(), diff.begin(), [mean](double x) { return x - mean; }); + std::vector diff(values.size()); + std::transform(values.begin(), values.end(), diff.begin(), [mean](double x) { return x - mean; }); double sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0); - stddevOfMean = std::sqrt(sq_sum / (v.size() * (v.size() - 1.))); + stddevOfMean = std::sqrt(sq_sum / (values.size() * (values.size() - 1.))); } else { double ratioSumWeight = sumOfSquaredWeights / (sumOfWeights * sumOfWeights); stddevOfMean = sqrt((sumSquare / sumOfWeights - mean * mean) * (1. / (1. - ratioSumWeight)) * ratioSumWeight);