From 5a7ebd6f6fe1c016c3f9aebd899d5027fb0d01eb Mon Sep 17 00:00:00 2001 From: Sebastian Bysiak Date: Mon, 4 Oct 2021 17:58:06 +0200 Subject: [PATCH 1/3] FT0: add configuration options to BasicPPTask --- Modules/FT0/include/FT0/BasicPPTask.h | 4 +++ Modules/FT0/src/BasicPPTask.cxx | 41 +++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/Modules/FT0/include/FT0/BasicPPTask.h b/Modules/FT0/include/FT0/BasicPPTask.h index 4c4b387d11..ad7f9f40e7 100644 --- a/Modules/FT0/include/FT0/BasicPPTask.h +++ b/Modules/FT0/include/FT0/BasicPPTask.h @@ -39,11 +39,15 @@ class BasicPPTask final : public quality_control::postprocessing::PostProcessing public: BasicPPTask() = default; ~BasicPPTask() override; + void configure(std::string, const boost::property_tree::ptree&); void initialize(quality_control::postprocessing::Trigger, framework::ServiceRegistry&) override; void update(quality_control::postprocessing::Trigger, framework::ServiceRegistry&) override; void finalize(quality_control::postprocessing::Trigger, framework::ServiceRegistry&) override; private: + std::string mCycleDurationMoName; + int mNumOrbitsInTF; + o2::quality_control::repository::DatabaseInterface* mDatabase = nullptr; std::unique_ptr mRateOrA; std::unique_ptr mRateOrC; diff --git a/Modules/FT0/src/BasicPPTask.cxx b/Modules/FT0/src/BasicPPTask.cxx index 7fd220abb8..08ff4a146a 100644 --- a/Modules/FT0/src/BasicPPTask.cxx +++ b/Modules/FT0/src/BasicPPTask.cxx @@ -16,6 +16,7 @@ #include "FT0/BasicPPTask.h" #include "QualityControl/QcInfoLogger.h" +#include "CommonConstants/LHCConstants.h" #include #include @@ -36,6 +37,29 @@ BasicPPTask::~BasicPPTask() delete mTime; } +void BasicPPTask::configure(std::string, const boost::property_tree::ptree& config) +{ + const char* configPath = Form("qc.postprocessing.%s", getName().c_str()); + ILOG(Warning) << "configPath = " << configPath << ENDM; + auto node = config.get_child_optional(Form("%s.custom.numOrbitsInTF", configPath)); + if (node) { + mNumOrbitsInTF = std::stoi(node.get_ptr()->get_child("").get_value()); + ILOG(Info, Support) << "configure() : using numOrbitsInTF = " << mNumOrbitsInTF << ENDM; + } else { + mNumOrbitsInTF = 256; + ILOG(Info, Support) << "configure() : using default numOrbitsInTF = " << mNumOrbitsInTF << ENDM; + } + + node = config.get_child_optional(Form("%s.custom.cycleDurationMoName", configPath)); + if (node) { + mCycleDurationMoName = node.get_ptr()->get_child("").get_value(); + ILOG(Info, Support) << "configure() : using cycleDurationMoName = \"" << mCycleDurationMoName << "\"" << ENDM; + } else { + mCycleDurationMoName = "CycleDurationNTF"; + ILOG(Info, Support) << "configure() : using default cycleDurationMoName = \"" << mCycleDurationMoName << "\"" << ENDM; + } +} + void BasicPPTask::initialize(Trigger, framework::ServiceRegistry& services) { mDatabase = &services.get(); @@ -86,17 +110,22 @@ void BasicPPTask::update(Trigger, framework::ServiceRegistry&) auto mo = mDatabase->retrieveMO("qc/FT0/MO/DigitQcTask/", "Triggers"); auto hTriggers = (TH1F*)mo->getObject(); if (!hTriggers) { - ILOG(Error) << "\nMO \"Triggers\" NOT retrieved!!!\n" - << ENDM; + ILOG(Error) << "MO \"Triggers\" NOT retrieved!!!" << ENDM; } - auto mo2 = mDatabase->retrieveMO("qc/FT0/MO/DigitQcTask/", "CycleDuration"); + auto mo2 = mDatabase->retrieveMO("qc/FT0/MO/DigitQcTask/", mCycleDurationMoName); auto hCycleDuration = (TH1D*)mo2->getObject(); if (!hCycleDuration) { - ILOG(Error) << "\nMO \"CycleDuration\" NOT retrieved!!!\n" - << ENDM; + ILOG(Error) << "MO \"" << mCycleDurationMoName << "\" NOT retrieved!!!" << ENDM; } - double cycleDurationMS = hCycleDuration->GetBinContent(1) / 1e6; // ns -> ms + + double cycleDurationMS = 0; + if (mCycleDurationMoName == "CycleDuration" || mCycleDurationMoName == "CycleDurationRange") + // assume MO stores cycle duration in ns + cycleDurationMS = hCycleDuration->GetBinContent(1) / 1e6; // ns -> ms + else if (mCycleDurationMoName == "CycleDurationNTF") + // assume MO stores cycle duration in number of TF + cycleDurationMS = hCycleDuration->GetBinContent(1) * mNumOrbitsInTF * o2::constants::lhc::LHCOrbitNS / 1e6; // ns ->ms int n = mRateOrA->GetN(); From 35e0d11fbdfb7f9ff068445e73e08f79ac31e201 Mon Sep 17 00:00:00 2001 From: Sebastian Bysiak Date: Mon, 4 Oct 2021 22:33:17 +0200 Subject: [PATCH 2/3] FT0: fix warning logging --- Modules/FT0/src/BasicPPTask.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/FT0/src/BasicPPTask.cxx b/Modules/FT0/src/BasicPPTask.cxx index 08ff4a146a..b24c8ec299 100644 --- a/Modules/FT0/src/BasicPPTask.cxx +++ b/Modules/FT0/src/BasicPPTask.cxx @@ -40,7 +40,7 @@ BasicPPTask::~BasicPPTask() void BasicPPTask::configure(std::string, const boost::property_tree::ptree& config) { const char* configPath = Form("qc.postprocessing.%s", getName().c_str()); - ILOG(Warning) << "configPath = " << configPath << ENDM; + ILOG(Info, Support) << "configPath = " << configPath << ENDM; auto node = config.get_child_optional(Form("%s.custom.numOrbitsInTF", configPath)); if (node) { mNumOrbitsInTF = std::stoi(node.get_ptr()->get_child("").get_value()); From 192d269ff09046ae119f085591fa78270af20996 Mon Sep 17 00:00:00 2001 From: Sebastian Bysiak Date: Mon, 4 Oct 2021 22:39:52 +0200 Subject: [PATCH 3/3] FV0: pilot beams (copy from FT0) --- Modules/FV0/CMakeLists.txt | 14 +- Modules/FV0/include/FV0/BasicPPTask.h | 66 ++++++ Modules/FV0/include/FV0/CFDEffCheck.h | 51 +++++ Modules/FV0/include/FV0/DigitQcTask.h | 46 +++- Modules/FV0/include/FV0/LinkDef.h | 8 +- Modules/FV0/include/FV0/OutOfBunchCollCheck.h | 53 +++++ Modules/FV0/include/FV0/OutOfBunchCollTask.h | 72 +++++++ Modules/FV0/src/BasicPPTask.cxx | 197 ++++++++++++++++++ Modules/FV0/src/CFDEffCheck.cxx | 149 +++++++++++++ Modules/FV0/src/DigitQcTask.cxx | 192 +++++++++++++++-- Modules/FV0/src/OutOfBunchCollCheck.cxx | 145 +++++++++++++ Modules/FV0/src/OutOfBunchCollTask.cxx | 111 ++++++++++ 12 files changed, 1075 insertions(+), 29 deletions(-) create mode 100644 Modules/FV0/include/FV0/BasicPPTask.h create mode 100644 Modules/FV0/include/FV0/CFDEffCheck.h create mode 100644 Modules/FV0/include/FV0/OutOfBunchCollCheck.h create mode 100644 Modules/FV0/include/FV0/OutOfBunchCollTask.h create mode 100644 Modules/FV0/src/BasicPPTask.cxx create mode 100644 Modules/FV0/src/CFDEffCheck.cxx create mode 100644 Modules/FV0/src/OutOfBunchCollCheck.cxx create mode 100644 Modules/FV0/src/OutOfBunchCollTask.cxx diff --git a/Modules/FV0/CMakeLists.txt b/Modules/FV0/CMakeLists.txt index dcd2f5e81b..318ae07672 100644 --- a/Modules/FV0/CMakeLists.txt +++ b/Modules/FV0/CMakeLists.txt @@ -2,7 +2,13 @@ add_library(O2QcFV0) -target_sources(O2QcFV0 PRIVATE src/DigitQcTask.cxx ) +target_sources(O2QcFV0 PRIVATE src/DigitQcTask.cxx + src/CFDEffCheck.cxx + src/BasicPPTask.cxx + src/OutOfBunchCollTask.cxx + src/OutOfBunchCollCheck.cxx + #src/TriggerQcTask.cxx + ) target_include_directories( O2QcFV0 @@ -21,6 +27,11 @@ add_root_dictionary(O2QcFV0 HEADERS include/FV0/DigitQcTask.h include/FV0/Helper.h + include/FV0/CFDEffCheck.h + include/FV0/BasicPPTask.h + include/FV0/OutOfBunchCollTask.h + include/FV0/OutOfBunchCollCheck.h + #include/FV0/TriggerQcTask.h LINKDEF include/FV0/LinkDef.h BASENAME O2QcFV0) @@ -40,4 +51,3 @@ foreach(test ${TEST_SRCS}) PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests) set_tests_properties(${test_name} PROPERTIES TIMEOUT 20) endforeach() - diff --git a/Modules/FV0/include/FV0/BasicPPTask.h b/Modules/FV0/include/FV0/BasicPPTask.h new file mode 100644 index 0000000000..24d75b8a90 --- /dev/null +++ b/Modules/FV0/include/FV0/BasicPPTask.h @@ -0,0 +1,66 @@ +// 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 BasicPPTask.h +/// \author Sebastian Bysiak sbysiak@cern.ch +/// + +#ifndef QC_MODULE_FV0_BASICPPTASK_H +#define QC_MODULE_FV0_BASICPPTASK_H + +#include "QualityControl/PostProcessingInterface.h" +#include "QualityControl/DatabaseInterface.h" +#include "FV0Base/Constants.h" +#include +#include + +class TH1F; +class TGraph; +class TCanvas; +class TLegend; +class TProfile; + +namespace o2::quality_control_modules::fv0 +{ + +/// \brief Basic Postprocessing Task for FV0, computes among others the trigger rates +/// \author Sebastian Bysiak sbysiak@cern.ch +class BasicPPTask final : public quality_control::postprocessing::PostProcessingInterface +{ + public: + BasicPPTask() = default; + ~BasicPPTask() override; + void configure(std::string, const boost::property_tree::ptree&); + void initialize(quality_control::postprocessing::Trigger, framework::ServiceRegistry&) override; + void update(quality_control::postprocessing::Trigger, framework::ServiceRegistry&) override; + void finalize(quality_control::postprocessing::Trigger, framework::ServiceRegistry&) override; + + constexpr static std::size_t sNCHANNELS_PM = 60; //48(for PM) + 12(just in case for possible PM-LCS) + + private: + std::string mCycleDurationMoName; + int mNumOrbitsInTF; + + o2::quality_control::repository::DatabaseInterface* mDatabase = nullptr; + std::unique_ptr mRateMinBias; + std::unique_ptr mRateOuterRing; + std::unique_ptr mRateNChannels; + std::unique_ptr mRateCharge; + std::unique_ptr mRateInnerRing; + std::unique_ptr mRatesCanv; + TProfile* mAmpl = nullptr; + TProfile* mTime = nullptr; +}; + +} // namespace o2::quality_control_modules::fv0 + +#endif //QC_MODULE_FV0_BASICPPTASK_H diff --git a/Modules/FV0/include/FV0/CFDEffCheck.h b/Modules/FV0/include/FV0/CFDEffCheck.h new file mode 100644 index 0000000000..3249b8b76e --- /dev/null +++ b/Modules/FV0/include/FV0/CFDEffCheck.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. + +/// +/// \file CFDEffCheck.h +/// \author Sebastian Bysiak sbysiak@cern.ch +/// + +#ifndef QC_MODULE_FV0_FV0CFDEFFCHECK_H +#define QC_MODULE_FV0_FV0CFDEFFCHECK_H + +#include "QualityControl/CheckInterface.h" + +namespace o2::quality_control_modules::fv0 +{ + +/// \brief checks if CFD efficiency is below threshold +/// \author Sebastian Bysiak sbysiak@cern.ch +class CFDEffCheck : public o2::quality_control::checker::CheckInterface +{ + public: + CFDEffCheck() = default; + ~CFDEffCheck() override = default; + + void configure(std::string name) override; + Quality check(std::map>* moMap) override; + void beautify(std::shared_ptr mo, Quality checkResult = Quality::Null) override; + std::string getAcceptedType() override; + + constexpr static int sNCHANNELS_PM = 48; //48(for PM), nothing more + + ClassDefOverride(CFDEffCheck, 1); + + private: + float mThreshWarning; + float mThreshError; + int mNumWarnings; + int mNumErrors; +}; + +} // namespace o2::quality_control_modules::fv0 + +#endif // QC_MODULE_FV0_FV0CFDEFFCHECK_H diff --git a/Modules/FV0/include/FV0/DigitQcTask.h b/Modules/FV0/include/FV0/DigitQcTask.h index fba81fbee0..baacd53671 100644 --- a/Modules/FV0/include/FV0/DigitQcTask.h +++ b/Modules/FV0/include/FV0/DigitQcTask.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "TH1.h" #include "TH2.h" #include "TList.h" @@ -62,6 +63,18 @@ class DigitQcTask final : public TaskInterface constexpr static uint8_t sLaserBitPos = 5; private: + // three ways of computing cycle duration: + // 1) number of time frames + // 2) time in ns from InteractionRecord: total range (totalMax - totalMin) + // 3) time in ns from InteractionRecord: sum of each TF duration + // later on choose the best and remove others + double mTimeMinNS = 0.; + double mTimeMaxNS = 0.; + double mTimeCurNS = 0.; + int mTfCounter = 0; + double mTimeSum = 0.; + const float mCFDChannel2NS = 0.01302; // CFD channel width in ns + template ::value || std::is_same::value || (std::is_integral::value && !std::is_same::value)>::type> @@ -82,12 +95,31 @@ class DigitQcTask final : public TaskInterface return vecResult; } + void rebinFromConfig(); + + TList* mListHistGarbage; + std::set mSetAllowedChIDs; + std::array mStateLastIR2Ch; + std::map mMapDigitTrgNames; + std::map mMapChTrgNames; + std::unique_ptr mHistNumADC; + std::unique_ptr mHistNumCFD; + + // temp + enum ETrgMenu { kMinBias, + kOuterRing, + kNChannels, + kCharge, + kInnerRing + }; + // Object which will be published std::unique_ptr mHistAmp2Ch; std::unique_ptr mHistTime2Ch; std::unique_ptr mHistEventDensity2Ch; - std::unique_ptr mHistOrbit2BC; std::unique_ptr mHistChDataBits; + std::unique_ptr mHistOrbit2BC; + std::unique_ptr mHistBC; std::unique_ptr mHistTriggers; std::unique_ptr mHistNchA; std::unique_ptr mHistNchC; @@ -96,15 +128,17 @@ class DigitQcTask final : public TaskInterface std::unique_ptr mHistAverageTimeA; std::unique_ptr mHistAverageTimeC; std::unique_ptr mHistChannelID; - std::array mStateLastIR2Ch; - std::map mMapChTrgNames; - std::map mMapDigitTrgNames; - TList* mListHistGarbage; + std::unique_ptr mHistCFDEff; + // std::unique_ptr mHistTimeSum2Diff; + std::unique_ptr mHistTriggersCorrelation; + std::unique_ptr mHistCycleDuration; + std::unique_ptr mHistCycleDurationNTF; + std::unique_ptr mHistCycleDurationRange; std::map mMapHistAmp1D; std::map mMapHistTime1D; std::map mMapHistPMbits; std::map mMapHistAmpVsTime; - std::set mSetAllowedChIDs; + std::map mMapTrgBcOrbit; }; } // namespace o2::quality_control_modules::fv0 diff --git a/Modules/FV0/include/FV0/LinkDef.h b/Modules/FV0/include/FV0/LinkDef.h index 5f46347271..5e010a2ad5 100644 --- a/Modules/FV0/include/FV0/LinkDef.h +++ b/Modules/FV0/include/FV0/LinkDef.h @@ -3,5 +3,11 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::quality_control_modules::fv0::DigitQcTask+; +#pragma link C++ class o2::quality_control_modules::fv0::DigitQcTask + ; +#pragma link C++ class o2::quality_control_modules::fv0::BasicPPTask + ; +#pragma link C++ class o2::quality_control_modules::fv0::OutOfBunchCollTask + ; +#pragma link C++ class o2::quality_control_modules::fv0::CFDEffCheck + ; +// #pragma link C++ class o2::quality_control_modules::fv0::TriggerQcTask + ; +#pragma link C++ class o2::quality_control_modules::fv0::OutOfBunchCollCheck + ; + #endif diff --git a/Modules/FV0/include/FV0/OutOfBunchCollCheck.h b/Modules/FV0/include/FV0/OutOfBunchCollCheck.h new file mode 100644 index 0000000000..f8e4f20c42 --- /dev/null +++ b/Modules/FV0/include/FV0/OutOfBunchCollCheck.h @@ -0,0 +1,53 @@ +// 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 OutOfBunchCollCheck.h +/// \author Sebastian Bysiak sbysiak@cern.ch +/// + +#ifndef QC_MODULE_FV0_FV0OUTOFBUNCHCOLLCHECK_H +#define QC_MODULE_FV0_FV0OUTOFBUNCHCOLLCHECK_H + +#include "QualityControl/CheckInterface.h" + +namespace o2::quality_control_modules::fv0 +{ + +/// \brief Checks what fraction of collisions is out of bunch +/// \author Sebastian Bysiak sbysiak@cern.ch +class OutOfBunchCollCheck : public o2::quality_control::checker::CheckInterface +{ + public: + /// Default constructor + OutOfBunchCollCheck() = default; + /// Destructor + ~OutOfBunchCollCheck() override = default; + + // Override interface + void configure(std::string name) override; + Quality check(std::map>* moMap) override; + void beautify(std::shared_ptr mo, Quality checkResult = Quality::Null) override; + std::string getAcceptedType() override; + + ClassDefOverride(OutOfBunchCollCheck, 1); + + private: + float mFractionOutOfBunchColl; + int mNumNonEmptyBins; + float mThreshWarning; + float mThreshError; + std::string mTrgName; +}; + +} // namespace o2::quality_control_modules::fv0 + +#endif // QC_MODULE_FV0_FV0OUTOFBUNCHCOLLCHECK_H diff --git a/Modules/FV0/include/FV0/OutOfBunchCollTask.h b/Modules/FV0/include/FV0/OutOfBunchCollTask.h new file mode 100644 index 0000000000..77217c803b --- /dev/null +++ b/Modules/FV0/include/FV0/OutOfBunchCollTask.h @@ -0,0 +1,72 @@ +// 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 OutOfBunchCollTask.h +/// \author Sebastian Bysiak sbysiak@cern.ch +/// + +#ifndef QC_MODULE_FV0_OUTOFBUNCHCOLLTASK_H +#define QC_MODULE_FV0_OUTOFBUNCHCOLLTASK_H + +#include "CommonDataFormat/BunchFilling.h" +#include "QualityControl/PostProcessingInterface.h" +#include "QualityControl/DatabaseInterface.h" +#include "FV0Base/Constants.h" +#include "DataFormatsFT0/Digit.h" // temp, for o2::ft0::Triggers::bitXYZ +#include "DataFormatsFV0/ChannelData.h" +#include "DataFormatsFV0/BCData.h" +#include "CCDB/CcdbApi.h" + +#include "TList.h" +#include "Rtypes.h" + +class TH1F; +class TH2F; + +namespace o2::quality_control_modules::fv0 +{ + +/// \brief PostProcessing task which finds collisions not compatible with BC pattern +/// \author Sebastian Bysiak sbysiak@cern.ch +class OutOfBunchCollTask final : public quality_control::postprocessing::PostProcessingInterface +{ + public: + OutOfBunchCollTask() = default; + ~OutOfBunchCollTask() override; + void initialize(quality_control::postprocessing::Trigger, framework::ServiceRegistry&) override; + void update(quality_control::postprocessing::Trigger, framework::ServiceRegistry&) override; + void finalize(quality_control::postprocessing::Trigger, framework::ServiceRegistry&) override; + void configure(std::string, const boost::property_tree::ptree&) override; + + private: + // temp + enum ETrgMenu { kMinBias, + kOuterRing, + kNChannels, + kCharge, + kInnerRing + }; + + o2::quality_control::repository::DatabaseInterface* mDatabase = nullptr; + std::string mCcdbUrl; + o2::ccdb::CcdbApi mCcdbApi; + TList* mListHistGarbage; + std::map mMapDigitTrgNames; + std::map mMapOutOfBunchColl; + // if storage size matters it can be replaced with TH1 + // and TH2 can be created based on it on the fly, but only TH1 would be stored + std::unique_ptr mHistBcPattern; +}; + +} // namespace o2::quality_control_modules::fv0 + +#endif //QC_MODULE_FV0_OUTOFBUNCHCOLLTASK_H diff --git a/Modules/FV0/src/BasicPPTask.cxx b/Modules/FV0/src/BasicPPTask.cxx new file mode 100644 index 0000000000..498e4645bc --- /dev/null +++ b/Modules/FV0/src/BasicPPTask.cxx @@ -0,0 +1,197 @@ +// 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 BasicPPTask.cxx +/// \author Sebastian Bysiak sbysiak@cern.ch +/// + +#include "FV0/BasicPPTask.h" +#include "QualityControl/QcInfoLogger.h" +#include "CommonConstants/LHCConstants.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace o2::quality_control::postprocessing; + +namespace o2::quality_control_modules::fv0 +{ + +BasicPPTask::~BasicPPTask() +{ + delete mAmpl; + delete mTime; +} + +void BasicPPTask::configure(std::string, const boost::property_tree::ptree& config) +{ + const char* configPath = Form("qc.postprocessing.%s", getName().c_str()); + ILOG(Info, Support) << "configPath = " << configPath << ENDM; + auto node = config.get_child_optional(Form("%s.custom.numOrbitsInTF", configPath)); + if (node) { + mNumOrbitsInTF = std::stoi(node.get_ptr()->get_child("").get_value()); + ILOG(Info, Support) << "configure() : using numOrbitsInTF = " << mNumOrbitsInTF << ENDM; + } else { + mNumOrbitsInTF = 256; + ILOG(Info, Support) << "configure() : using default numOrbitsInTF = " << mNumOrbitsInTF << ENDM; + } + + node = config.get_child_optional(Form("%s.custom.cycleDurationMoName", configPath)); + if (node) { + mCycleDurationMoName = node.get_ptr()->get_child("").get_value(); + ILOG(Info, Support) << "configure() : using cycleDurationMoName = \"" << mCycleDurationMoName << "\"" << ENDM; + } else { + mCycleDurationMoName = "CycleDurationNTF"; + ILOG(Info, Support) << "configure() : using default cycleDurationMoName = \"" << mCycleDurationMoName << "\"" << ENDM; + } +} + +void BasicPPTask::initialize(Trigger, framework::ServiceRegistry& services) +{ + mDatabase = &services.get(); + + mRateMinBias = std::make_unique(0); + mRateOuterRing = std::make_unique(0); + mRateNChannels = std::make_unique(0); + mRateCharge = std::make_unique(0); + mRateInnerRing = std::make_unique(0); + mRatesCanv = std::make_unique("cRates", "trigger rates"); + mAmpl = new TProfile("MeanAmplPerChannel", "mean ampl per channel;Channel;Ampl #mu #pm #sigma", sNCHANNELS_PM, 0, sNCHANNELS_PM); + mTime = new TProfile("MeanTimePerChannel", "mean time per channel;Channel;Time #mu #pm #sigma", sNCHANNELS_PM, 0, sNCHANNELS_PM); + + mRateMinBias->SetNameTitle("rateMinBias", "trg rate: MinBias;cycle;rate [kHz]"); + mRateOuterRing->SetNameTitle("rateOuterRing", "trg rate: OuterRing;cycle;rate [kHz]"); + mRateNChannels->SetNameTitle("rateNChannels", "trg rate: NChannels;cycle;rate [kHz]"); + mRateCharge->SetNameTitle("rateCharge", "trg rate: Charge;cycle;rate [kHz]"); + mRateInnerRing->SetNameTitle("rateInnerRing", "trg rate: InnerRing;cycle;rate [kHz]"); + + mRateMinBias->SetMarkerStyle(24); + mRateOuterRing->SetMarkerStyle(25); + mRateNChannels->SetMarkerStyle(26); + mRateCharge->SetMarkerStyle(27); + mRateInnerRing->SetMarkerStyle(28); + mRateMinBias->SetMarkerColor(kOrange); + mRateOuterRing->SetMarkerColor(kMagenta); + mRateNChannels->SetMarkerColor(kBlack); + mRateCharge->SetMarkerColor(kBlue); + mRateInnerRing->SetMarkerColor(kOrange); + mRateMinBias->SetLineColor(kOrange); + mRateOuterRing->SetLineColor(kMagenta); + mRateNChannels->SetLineColor(kBlack); + mRateCharge->SetLineColor(kBlue); + mRateInnerRing->SetLineColor(kOrange); + + getObjectsManager()->startPublishing(mRateMinBias.get()); + getObjectsManager()->startPublishing(mRateOuterRing.get()); + getObjectsManager()->startPublishing(mRateNChannels.get()); + getObjectsManager()->startPublishing(mRateCharge.get()); + getObjectsManager()->startPublishing(mRateInnerRing.get()); + getObjectsManager()->startPublishing(mRatesCanv.get()); + getObjectsManager()->startPublishing(mAmpl); + getObjectsManager()->startPublishing(mTime); +} + +void BasicPPTask::update(Trigger, framework::ServiceRegistry&) +{ + auto mo = mDatabase->retrieveMO("qc/FV0/MO/DigitQcTask/", "Triggers"); + auto hTriggers = (TH1F*)mo->getObject(); + if (!hTriggers) { + ILOG(Error) << "MO \"Triggers\" NOT retrieved!!!" << ENDM; + } + + auto mo2 = mDatabase->retrieveMO("qc/FV0/MO/DigitQcTask/", mCycleDurationMoName); + auto hCycleDuration = (TH1D*)mo2->getObject(); + if (!hCycleDuration) { + ILOG(Error) << "MO \"" << mCycleDurationMoName << "\" NOT retrieved!!!" << ENDM; + } + + double cycleDurationMS = 0; + if (mCycleDurationMoName == "CycleDuration" || mCycleDurationMoName == "CycleDurationRange") + // assume MO stores cycle duration in ns + cycleDurationMS = hCycleDuration->GetBinContent(1) / 1e6; // ns -> ms + else if (mCycleDurationMoName == "CycleDurationNTF") + // assume MO stores cycle duration in number of TF + cycleDurationMS = hCycleDuration->GetBinContent(1) * mNumOrbitsInTF * o2::constants::lhc::LHCOrbitNS / 1e6; // ns ->ms + + int n = mRateMinBias->GetN(); + + double eps = 1e-8; + if (cycleDurationMS < eps) { + ILOG(Warning) << "cycle duration = " << cycleDurationMS << " ms, almost zero - cannot compute trigger rates!" << ENDM; + } else { + mRateMinBias->SetPoint(n, n, hTriggers->GetBinContent(hTriggers->GetXaxis()->FindBin("MinBias")) / cycleDurationMS); + mRateOuterRing->SetPoint(n, n, hTriggers->GetBinContent(hTriggers->GetXaxis()->FindBin("OuterRing")) / cycleDurationMS); + mRateNChannels->SetPoint(n, n, hTriggers->GetBinContent(hTriggers->GetXaxis()->FindBin("NChannels")) / cycleDurationMS); + mRateCharge->SetPoint(n, n, hTriggers->GetBinContent(hTriggers->GetXaxis()->FindBin("Charge")) / cycleDurationMS); + mRateInnerRing->SetPoint(n, n, hTriggers->GetBinContent(hTriggers->GetXaxis()->FindBin("InnerRing")) / cycleDurationMS); + } + + mRatesCanv->cd(); + float vmin = std::min({ mRateMinBias->GetYaxis()->GetXmin(), mRateOuterRing->GetYaxis()->GetXmin(), mRateNChannels->GetYaxis()->GetXmin(), mRateCharge->GetYaxis()->GetXmin(), mRateInnerRing->GetYaxis()->GetXmin() }); + float vmax = std::max({ mRateMinBias->GetYaxis()->GetXmax(), mRateOuterRing->GetYaxis()->GetXmax(), mRateNChannels->GetYaxis()->GetXmax(), mRateCharge->GetYaxis()->GetXmax(), mRateInnerRing->GetYaxis()->GetXmax() }); + + auto hAxis = mRateMinBias->GetHistogram(); + hAxis->GetYaxis()->SetTitleOffset(1.4); + hAxis->SetMinimum(vmin); + hAxis->SetMaximum(vmax * 1.1); + hAxis->SetTitle("FV0 trigger rates"); + hAxis->SetLineWidth(0); + hAxis->Draw("AXIS"); + + mRateMinBias->Draw("PL,SAME"); + mRateOuterRing->Draw("PL,SAME"); + mRateNChannels->Draw("PL,SAME"); + mRateCharge->Draw("PL,SAME"); + mRateInnerRing->Draw("PL,SAME"); + TLegend* leg = gPad->BuildLegend(); + leg->SetFillStyle(1); + + auto mo3 = mDatabase->retrieveMO("qc/FV0/MO/DigitQcTask/", "AmpPerChannel"); + auto hAmpPerChannel = (TH2D*)mo3->getObject(); + if (!hAmpPerChannel) { + ILOG(Error) << "\nMO \"AmpPerChannel\" NOT retrieved!!!\n" + << ENDM; + } + auto mo4 = mDatabase->retrieveMO("qc/FV0/MO/DigitQcTask/", "TimePerChannel"); + auto hTimePerChannel = (TH2D*)mo4->getObject(); + if (!hTimePerChannel) { + ILOG(Error) << "\nMO \"TimePerChannel\" NOT retrieved!!!\n" + << ENDM; + } + + mAmpl = hAmpPerChannel->ProfileX("MeanAmplPerChannel"); + mTime = hTimePerChannel->ProfileX("MeanTimePerChannel"); + mAmpl->SetErrorOption("s"); + mTime->SetErrorOption("s"); + // for some reason the styling is not preserved after assigning result of ProfileX/Y() to already existing object + mAmpl->SetMarkerStyle(8); + mTime->SetMarkerStyle(8); + mAmpl->SetLineColor(kBlack); + mTime->SetLineColor(kBlack); + mAmpl->SetDrawOption("P"); + mTime->SetDrawOption("P"); + mAmpl->GetXaxis()->SetTitleOffset(1); + mTime->GetXaxis()->SetTitleOffset(1); + mAmpl->GetYaxis()->SetTitleOffset(1); + mTime->GetYaxis()->SetTitleOffset(1); +} + +void BasicPPTask::finalize(Trigger, framework::ServiceRegistry&) +{ +} + +} // namespace o2::quality_control_modules::fv0 diff --git a/Modules/FV0/src/CFDEffCheck.cxx b/Modules/FV0/src/CFDEffCheck.cxx new file mode 100644 index 0000000000..d67ec5385a --- /dev/null +++ b/Modules/FV0/src/CFDEffCheck.cxx @@ -0,0 +1,149 @@ +// 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 CFDEffCheck.cxx +/// \author Sebastian Bysiak sbysiak@cern.ch +/// + +#include "FV0/CFDEffCheck.h" +#include "QualityControl/MonitorObject.h" +#include "QualityControl/Quality.h" +#include "QualityControl/QcInfoLogger.h" +// ROOT +#include +#include +#include +#include + +#include + +using namespace std; +using namespace o2::quality_control; + +namespace o2::quality_control_modules::fv0 +{ + +void CFDEffCheck::configure(std::string) +{ + if (auto param = mCustomParameters.find("thresholdWarning"); param != mCustomParameters.end()) { + mThreshWarning = stof(param->second); + ILOG(Info, Support) << "configure() : using thresholdWarning = " << mThreshWarning << ENDM; + } else { + mThreshWarning = 0.999; + ILOG(Info, Support) << "configure() : using default thresholdWarning = " << mThreshWarning << ENDM; + } + + if (auto param = mCustomParameters.find("thresholdError"); param != mCustomParameters.end()) { + mThreshError = stof(param->second); + ILOG(Info, Support) << "configure() : using thresholdError = " << mThreshError << ENDM; + } else { + mThreshError = 0.9; + ILOG(Info, Support) << "configure() : using default thresholdError = " << mThreshError << ENDM; + } +} + +Quality CFDEffCheck::check(std::map>* moMap) +{ + Quality result = Quality::Null; + + for (auto& [moName, mo] : *moMap) { + (void)moName; + if (mo->getName() == "CFD_efficiency") { + auto* h = dynamic_cast(mo->getObject()); + + result = Quality::Good; + mNumErrors = 0; + mNumWarnings = 0; + for (int i = 1; i < sNCHANNELS_PM + 1; i++) { + if (h->GetBinContent(i) < mThreshError) { + if (result.isBetterThan(Quality::Bad)) + // result = Quality::Bad; // setting quality like this clears reasons + result.set(Quality::Bad); + mNumErrors++; + // keep reasons short because they will be displayed on plot + // long reasons make font size too small + result.addReason(FlagReasonFactory::Unknown(), + "CFD eff. < \"Error\" threshold in channel " + std::to_string(i)); + // no need to check medium threshold + // but don't `break` because we want to add other reasons + continue; + } else if (h->GetBinContent(i) < mThreshWarning) { + if (result.isBetterThan(Quality::Medium)) + result.set(Quality::Medium); + mNumWarnings++; + result.addReason(FlagReasonFactory::Unknown(), + "CFD eff. < \"Warning\" threshold in channel " + std::to_string(i)); + } + } + } + } + result.addMetadata("nErrors", std::to_string(mNumErrors)); + result.addMetadata("nWarnings", std::to_string(mNumWarnings)); + return result; +} + +std::string CFDEffCheck::getAcceptedType() { return "TH1"; } + +void CFDEffCheck::beautify(std::shared_ptr mo, Quality checkResult) +{ + if (mo->getName() == "CFD_efficiency") { + auto* h = dynamic_cast(mo->getObject()); + + TPaveText* msg = new TPaveText(0.15, 0.15, 0.85, 0.4, "NDC"); + h->GetListOfFunctions()->Add(msg); + msg->SetName(Form("%s_msg", mo->GetName())); + msg->Clear(); + msg->AddText("CFDEffCheck"); + msg->AddText(Form("(Warning < %.6f, Error < %.6f)", mThreshWarning, mThreshError)); + + if (checkResult == Quality::Good) { + msg->AddText(">> Quality::Good <<"); + msg->SetFillColor(kGreen); + } else if (checkResult == Quality::Bad) { + auto reasons = checkResult.getReasons(); + msg->SetFillColor(kRed); + msg->SetY2(std::min(0.7, 0.4 + reasons.size() * 0.01)); + msg->AddText(">> Quality::Bad <<"); + msg->AddText(("N channels with errors = " + checkResult.getMetadata("nErrors")).c_str()); + msg->AddText(("N channels with warnings = " + checkResult.getMetadata("nWarnings")).c_str()); + for (int i = 0; i < int(reasons.size()); i++) + msg->AddText((reasons[i].first.getName() + ": " + reasons[i].second).c_str()); + } else if (checkResult == Quality::Medium) { + auto reasons = checkResult.getReasons(); + msg->SetFillColor(kOrange); + msg->SetY2(std::min(0.7, 0.4 + reasons.size() * 0.01)); + msg->AddText(">> Quality::Medium <<"); + msg->AddText(("N channels with errors = " + checkResult.getMetadata("nErrors")).c_str()); + msg->AddText(("N channels with warnings = " + checkResult.getMetadata("nWarnings")).c_str()); + for (int i = 0; i < int(reasons.size()); i++) + msg->AddText((reasons[i].first.getName() + ": " + reasons[i].second).c_str()); + } else if (checkResult == Quality::Null) { + msg->AddText(">> Quality::Null <<"); + msg->SetFillColor(kGray); + } + // add threshold lines + Double_t xMin = h->GetXaxis()->GetXmin(); + Double_t xMax = h->GetXaxis()->GetXmax(); + auto* lineError = new TLine(xMin, mThreshError, xMax, mThreshError); + auto* lineWarning = new TLine(xMin, mThreshWarning, xMax, mThreshWarning); + lineError->SetLineWidth(2); + lineWarning->SetLineWidth(2); + lineError->SetLineStyle(2); + lineWarning->SetLineStyle(2); + lineError->SetLineColor(kRed); + lineWarning->SetLineStyle(kOrange); + h->GetListOfFunctions()->Add(lineError); + h->GetListOfFunctions()->Add(lineWarning); + } +} + +} // namespace o2::quality_control_modules::fv0 diff --git a/Modules/FV0/src/DigitQcTask.cxx b/Modules/FV0/src/DigitQcTask.cxx index 0e1d8a6f64..fe4bc27b1b 100644 --- a/Modules/FV0/src/DigitQcTask.cxx +++ b/Modules/FV0/src/DigitQcTask.cxx @@ -17,6 +17,8 @@ #include #include +#include + #include "QualityControl/QcInfoLogger.h" #include "FV0/DigitQcTask.h" #include @@ -30,6 +32,56 @@ DigitQcTask::~DigitQcTask() delete mListHistGarbage; } +void DigitQcTask::rebinFromConfig() +{ + /* Examples: + "binning_SumAmpC": "100, 0, 100" + "binning_BcOrbitMap_TrgOrA": "25, 0, 256, 10, 0, 3564" + hashtag = all channel IDs (mSetAllowedChIDs), e.g. + "binning_Amp_channel#": "5,-10,90" + is equivalent to: + "binning_Amp_channel0": "5,-10,90" + "binning_Amp_channel1": "5,-10,90" + "binning_Amp_channel2": "5,-10,90" ... + */ + auto rebinHisto = [](std::string hName, std::string binning) { + vector tokenizedBinning; + boost::split(tokenizedBinning, binning, boost::is_any_of(",")); + if (tokenizedBinning.size() == 3) { // TH1 + ILOG(Debug) << "config: rebinning TH1 " << hName << " -> " << binning << ENDM; + auto htmp = (TH1F*)gROOT->FindObject(hName.data()); + htmp->SetBins(std::atof(tokenizedBinning[0].c_str()), std::atof(tokenizedBinning[1].c_str()), std::atof(tokenizedBinning[2].c_str())); + } else if (tokenizedBinning.size() == 6) { // TH2 + auto htmp = (TH2F*)gROOT->FindObject(hName.data()); + ILOG(Debug) << "config: rebinning TH2 " << hName << " -> " << binning << ENDM; + htmp->SetBins(std::atof(tokenizedBinning[0].c_str()), std::atof(tokenizedBinning[1].c_str()), std::atof(tokenizedBinning[2].c_str()), + std::atof(tokenizedBinning[3].c_str()), std::atof(tokenizedBinning[4].c_str()), std::atof(tokenizedBinning[5].c_str())); + } else { + ILOG(Warning) << "config: invalid binning parameter: " << hName << " -> " << binning << ENDM; + } + }; + + const std::string rebinKeyword = "binning"; + const char* channelIdPlaceholder = "#"; + for (auto& param : mCustomParameters) { + if (param.first.rfind(rebinKeyword, 0) != 0) + continue; + std::string hName = param.first.substr(rebinKeyword.length() + 1); + std::string binning = param.second.c_str(); + if (hName.find(channelIdPlaceholder) != std::string::npos) { + for (const auto& chID : mSetAllowedChIDs) { + std::string hNameCur = hName.substr(0, hName.find(channelIdPlaceholder)) + std::to_string(chID) + hName.substr(hName.find(channelIdPlaceholder) + 1); + rebinHisto(hNameCur, binning); + } + } else if (!gROOT->FindObject(hName.data())) { + ILOG(Warning) << "config: histogram named \"" << hName << "\" not found" << ENDM; + continue; + } else { + rebinHisto(hName, binning); + } + } +} + void DigitQcTask::initialize(o2::framework::InitContext& /*ctx*/) { ILOG(Info, Support) << "initialize DigitQcTask" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. @@ -44,7 +96,7 @@ void DigitQcTask::initialize(o2::framework::InitContext& /*ctx*/) mMapChTrgNames.insert({ o2::fv0::ChannelData::kIsAmpHigh, "IsAmpHigh" }); mMapChTrgNames.insert({ o2::fv0::ChannelData::kIsEventInTVDC, "IsEventInTVDC" }); mMapChTrgNames.insert({ o2::fv0::ChannelData::kIsTimeInfoLost, "IsTimeInfoLost" }); - + mMapDigitTrgNames.insert({ o2::fv0::Triggers::bitA, "OrA" }); mMapDigitTrgNames.insert({ o2::fv0::Triggers::bitC, "OrC" }); mMapDigitTrgNames.insert({ o2::fv0::Triggers::bitVertex, "Vertex" }); @@ -60,21 +112,22 @@ void DigitQcTask::initialize(o2::framework::InitContext& /*ctx*/) mMapChTrgNames.insert({ 6, "IsEventInTVDC" }); mMapChTrgNames.insert({ 7, "IsTimeInfoLost" }); - mMapDigitTrgNames.insert({ 0, "OrA" }); - mMapDigitTrgNames.insert({ 1, "OrC" }); - mMapDigitTrgNames.insert({ 2, "Vertex" }); - mMapDigitTrgNames.insert({ 3, "Central" }); - mMapDigitTrgNames.insert({ 4, "SemiCentral" }); + mMapDigitTrgNames.insert({ ETrgMenu::kMinBias, "MinBias" }); + mMapDigitTrgNames.insert({ ETrgMenu::kOuterRing, "OuterRing" }); + mMapDigitTrgNames.insert({ ETrgMenu::kNChannels, "NChannels" }); + mMapDigitTrgNames.insert({ ETrgMenu::kCharge, "Charge" }); + mMapDigitTrgNames.insert({ ETrgMenu::kInnerRing, "InnerRing" }); mMapDigitTrgNames.insert({ 5, "Laser" }); mMapDigitTrgNames.insert({ 6, "OutputsAreBlocked" }); mMapDigitTrgNames.insert({ 7, "DataIsValid" }); - mHistTime2Ch = std::make_unique("TimePerChannel", "Time vs Channel;Time;Channel;", 4100, -2050, 2050, sNCHANNELS_PM, 0, sNCHANNELS_PM); + mHistTime2Ch = std::make_unique("TimePerChannel", "Time vs Channel;Channel;Time", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4100, -2050, 2050); mHistTime2Ch->SetOption("colz"); - mHistAmp2Ch = std::make_unique("AmpPerChannel", "Amplitude vs Channel;Amp;Channel;", 4200, -100, 4100, sNCHANNELS_PM, 0, sNCHANNELS_PM); + mHistAmp2Ch = std::make_unique("AmpPerChannel", "Amplitude vs Channel;Channel;Amp", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4200, -100, 4100); mHistAmp2Ch->SetOption("colz"); mHistOrbit2BC = std::make_unique("OrbitPerBC", "BC-Orbit map;Orbit;BC;", 256, 0, 256, 3564, 0, 3564); mHistOrbit2BC->SetOption("colz"); + mHistBC = std::make_unique("BC", "BC;BC;counts;", 3564, 0, 3564); mHistEventDensity2Ch = std::make_unique("EventDensityPerChannel", "Event density(in BC) per Channel;Channel;BC;", sNCHANNELS_PM, 0, sNCHANNELS_PM, 10000, 0, 1e5); mHistEventDensity2Ch->SetOption("colz"); @@ -85,10 +138,23 @@ void DigitQcTask::initialize(o2::framework::InitContext& /*ctx*/) for (const auto& entry : mMapChTrgNames) { mHistChDataBits->GetYaxis()->SetBinLabel(entry.first + 1, entry.second.c_str()); } - + mHistTriggersCorrelation = std::make_unique("TriggersCorrelation", "Correlation of triggers from TCM", mMapDigitTrgNames.size(), 0, mMapDigitTrgNames.size(), mMapDigitTrgNames.size(), 0, mMapDigitTrgNames.size()); + mHistTriggersCorrelation->SetOption("colz"); mHistTriggers = std::make_unique("Triggers", "Triggers from TCM", mMapDigitTrgNames.size(), 0, mMapDigitTrgNames.size()); + + mListHistGarbage = new TList(); + mListHistGarbage->SetOwner(kTRUE); for (const auto& entry : mMapDigitTrgNames) { mHistTriggers->GetXaxis()->SetBinLabel(entry.first + 1, entry.second.c_str()); + mHistTriggersCorrelation->GetXaxis()->SetBinLabel(entry.first + 1, entry.second.c_str()); + mHistTriggersCorrelation->GetYaxis()->SetBinLabel(entry.first + 1, entry.second.c_str()); + + auto pairTrgBcOrbit = mMapTrgBcOrbit.insert({ entry.first, new TH2F(Form("BcOrbitMap_Trg%s", entry.second.c_str()), Form("BC-orbit map: %s fired;Orbit;BC", entry.second.c_str()), 256, 0, 256, 3564, 0, 3564) }); + if (pairTrgBcOrbit.second) { + getObjectsManager()->startPublishing(pairTrgBcOrbit.first->second); + pairTrgBcOrbit.first->second->SetOption("colz"); + mListHistGarbage->Add(pairTrgBcOrbit.first->second); + } } mHistNchA = std::make_unique("NumChannelsA", "Number of channels(TCM), side A;Nch", sNCHANNELS_PM, 0, sNCHANNELS_PM); mHistNchC = std::make_unique("NumChannelsC", "Number of channels(TCM), side C;Nch", sNCHANNELS_PM, 0, sNCHANNELS_PM); @@ -96,9 +162,16 @@ void DigitQcTask::initialize(o2::framework::InitContext& /*ctx*/) mHistSumAmpC = std::make_unique("SumAmpC", "Sum of amplitudes(TCM), side C;", 1000, 0, 1e4); mHistAverageTimeA = std::make_unique("AverageTimeA", "Average time(TCM), side A", 4100, -2050, 2050); mHistAverageTimeC = std::make_unique("AverageTimeC", "Average time(TCM), side C", 4100, -2050, 2050); + //mHistTimeSum2Diff = std::make_unique("timeSumVsDiff", "time A/C side: sum VS diff;(TOC-TOA)/2 [ns];(TOA+TOC)/2 [ns]", 400, -52.08, 52.08, 400, -52.08, 52.08); // range of 52.08 ns = 4000*13.02ps = 4000 channels + //mHistTimeSum2Diff->SetOption("colz"); mHistChannelID = std::make_unique("StatChannelID", "ChannelID statistics;ChannelID", sNCHANNELS_PM, 0, sNCHANNELS_PM); - mListHistGarbage = new TList(); - mListHistGarbage->SetOwner(kTRUE); + mHistNumADC = std::make_unique("HistNumADC", "HistNumADC", sNCHANNELS_PM, 0, sNCHANNELS_PM); + mHistNumCFD = std::make_unique("HistNumCFD", "HistNumCFD", sNCHANNELS_PM, 0, sNCHANNELS_PM); + mHistCFDEff = std::make_unique("CFD_efficiency", "CFD efficiency;ChannelID;efficiency", sNCHANNELS_PM, 0, sNCHANNELS_PM); + mHistCycleDuration = std::make_unique("CycleDuration", "Cycle Duration;;time [ns]", 1, 0, 2); + mHistCycleDurationNTF = std::make_unique("CycleDurationNTF", "Cycle Duration;;time [TimeFrames]", 1, 0, 2); + mHistCycleDurationRange = std::make_unique("CycleDurationRange", "Cycle Duration (total cycle range);;time [ns]", 1, 0, 2); + std::vector vecChannelIDs; if (auto param = mCustomParameters.find("ChannelIDs"); param != mCustomParameters.end()) { const auto chIDs = param->second; @@ -128,20 +201,22 @@ void DigitQcTask::initialize(o2::framework::InitContext& /*ctx*/) mListHistGarbage->Add(pairHistTime.first->second); getObjectsManager()->startPublishing(pairHistTime.first->second); } - if (pairHistBits.second) { mListHistGarbage->Add(pairHistBits.first->second); - //getObjectsManager()->startPublishing(pairHistBits.first->second); + //getObjectsManager()->startPublishing(pairHistBits.first->second); // TODO: why commented out } - if (pairHistAmpVsTime.second) { mListHistGarbage->Add(pairHistAmpVsTime.first->second); getObjectsManager()->startPublishing(pairHistAmpVsTime.first->second); } } + + rebinFromConfig(); + getObjectsManager()->startPublishing(mHistTime2Ch.get()); getObjectsManager()->startPublishing(mHistAmp2Ch.get()); getObjectsManager()->startPublishing(mHistOrbit2BC.get()); + getObjectsManager()->startPublishing(mHistBC.get()); getObjectsManager()->startPublishing(mHistEventDensity2Ch.get()); //getObjectsManager()->startPublishing(mHistChDataBits.get()); getObjectsManager()->startPublishing(mHistTriggers.get()); @@ -152,6 +227,12 @@ void DigitQcTask::initialize(o2::framework::InitContext& /*ctx*/) //getObjectsManager()->startPublishing(mHistAverageTimeA.get()); //getObjectsManager()->startPublishing(mHistAverageTimeC.get()); getObjectsManager()->startPublishing(mHistChannelID.get()); + getObjectsManager()->startPublishing(mHistCFDEff.get()); + getObjectsManager()->startPublishing(mHistTriggersCorrelation.get()); + //getObjectsManager()->startPublishing(mHistTimeSum2Diff.get()); + getObjectsManager()->startPublishing(mHistCycleDuration.get()); + getObjectsManager()->startPublishing(mHistCycleDurationNTF.get()); + getObjectsManager()->startPublishing(mHistCycleDurationRange.get()); } void DigitQcTask::startOfActivity(Activity& activity) @@ -160,6 +241,7 @@ void DigitQcTask::startOfActivity(Activity& activity) mHistTime2Ch->Reset(); mHistAmp2Ch->Reset(); mHistOrbit2BC->Reset(); + mHistBC->Reset(); mHistEventDensity2Ch->Reset(); mHistChDataBits->Reset(); mHistTriggers->Reset(); @@ -170,6 +252,14 @@ void DigitQcTask::startOfActivity(Activity& activity) mHistAverageTimeA->Reset(); mHistAverageTimeC->Reset(); mHistChannelID->Reset(); + mHistCFDEff->Reset(); + mHistNumADC->Reset(); + mHistNumCFD->Reset(); + mHistTriggersCorrelation->Reset(); + //mHistTimeSum2Diff->Reset(); + mHistCycleDuration->Reset(); + mHistCycleDurationNTF->Reset(); + mHistCycleDurationRange->Reset(); for (auto& entry : mMapHistAmp1D) { entry.second->Reset(); } @@ -182,33 +272,61 @@ void DigitQcTask::startOfActivity(Activity& activity) for (auto& entry : mMapHistAmpVsTime) { entry.second->Reset(); } + for (auto& entry : mMapTrgBcOrbit) { + entry.second->Reset(); + } } void DigitQcTask::startOfCycle() { ILOG(Info, Support) << "startOfCycle" << ENDM; + mTimeMinNS = -1; + mTimeMaxNS = 0.; + mTimeCurNS = 0.; + mTfCounter = 0; + mTimeSum = 0.; } void DigitQcTask::monitorData(o2::framework::ProcessingContext& ctx) { + double curTfTimeMin = -1; + double curTfTimeMax = 0; + mTfCounter++; auto channels = ctx.inputs().get>("channels"); auto digits = ctx.inputs().get>("digits"); //bool isFirst = true; //uint32_t firstOrbit; + for (auto& digit : digits) { const auto& vecChData = digit.getBunchChannelData(channels); bool isTCM = true; + mTimeCurNS = o2::InteractionRecord::bc2ns(digit.getIntRecord().bc, digit.getIntRecord().orbit); + if (mTimeMinNS < 0) + mTimeMinNS = mTimeCurNS; /* if (isFirst == true) { //firstOrbit = digit.getIntRecord().orbit; isFirst = false; } */ + if (mTimeCurNS < mTimeMinNS) + mTimeMinNS = mTimeCurNS; + if (mTimeCurNS > mTimeMaxNS) + mTimeMaxNS = mTimeCurNS; + + if (curTfTimeMin < 0) + curTfTimeMin = mTimeCurNS; + if (mTimeCurNS < curTfTimeMin) + curTfTimeMin = mTimeCurNS; + if (mTimeCurNS > curTfTimeMax) + curTfTimeMax = mTimeCurNS; /* if (digit.getTriggers().amplA == -5000 && digit.getTriggers().amplC == -5000 && digit.getTriggers().timeA == -5000 && digit.getTriggers().timeC == -5000) isTCM = false; */ mHistOrbit2BC->Fill(digit.getIntRecord().orbit % sOrbitsPerTF, digit.getIntRecord().bc); + mHistBC->Fill(digit.getIntRecord().bc); + if (isTCM && !(digit.getTriggers().triggerSignals & (1 << sLaserBitPos))) { mHistNchA->Fill(digit.mTriggers.nChanA); //mHistNchC->Fill(digit.mTriggers.nChanC); @@ -216,26 +334,38 @@ void DigitQcTask::monitorData(o2::framework::ProcessingContext& ctx) //mHistSumAmpC->Fill(digit.mTriggers.amplC); //mHistAverageTimeA->Fill(digit.mTriggers.timeA); //mHistAverageTimeC->Fill(digit.mTriggers.timeC); - + //mHistTimeSum2Diff->Fill((digit.mTriggers.timeC - digit.mTriggers.timeA) * mCFDChannel2NS / 2, (digit.mTriggers.timeC + digit.mTriggers.timeA) * mCFDChannel2NS / 2); for (const auto& entry : mMapDigitTrgNames) { if (digit.getTriggers().triggerSignals & (1 << entry.first)) mHistTriggers->Fill(static_cast(entry.first)); + for (const auto& entry2 : mMapDigitTrgNames) { + if ((digit.getTriggers().triggerSignals & (1 << entry.first)) && (digit.getTriggers().triggerSignals & (1 << entry2.first))) + mHistTriggersCorrelation->Fill(static_cast(entry.first), static_cast(entry2.first)); + } + } + for (auto& entry : mMapTrgBcOrbit) { + if (digit.getTriggers().triggerSignals & (1 << entry.first)) { + entry.second->Fill(digit.getIntRecord().orbit % sOrbitsPerTF, digit.getIntRecord().bc); + } } } for (const auto& chData : vecChData) { - mHistTime2Ch->Fill(static_cast(chData.time), static_cast(ch_data::getChId(chData))); - mHistAmp2Ch->Fill(static_cast(ch_data::getCharge(chData)), static_cast(ch_data::getChId(chData))); + mHistTime2Ch->Fill(static_cast(ch_data::getChId(chData)), static_cast(chData.time)); + mHistAmp2Ch->Fill(static_cast(ch_data::getChId(chData)), static_cast(ch_data::getCharge(chData))); mHistEventDensity2Ch->Fill(static_cast(ch_data::getChId(chData)), static_cast(digit.getIntRecord().differenceInBC(mStateLastIR2Ch[ch_data::getChId(chData)]))); mStateLastIR2Ch[ch_data::getChId(chData)] = digit.getIntRecord(); mHistChannelID->Fill(ch_data::getChId(chData)); + if (ch_data::getCharge(chData) > 0) + mHistNumADC->Fill(ch_data::getChId(chData)); + mHistNumCFD->Fill(ch_data::getChId(chData)); if (mSetAllowedChIDs.find(static_cast(ch_data::getChId(chData))) != mSetAllowedChIDs.end()) { mMapHistAmp1D[ch_data::getChId(chData)]->Fill(ch_data::getCharge(chData)); mMapHistTime1D[ch_data::getChId(chData)]->Fill(chData.time); mMapHistAmpVsTime[ch_data::getChId(chData)]->Fill(ch_data::getCharge(chData), chData.time); /* for (const auto& entry : mMapChTrgNames) { - if ((chData.ChainQTC & (1 << entry.first))) { + if ((ch_data::getCharge(chData) & (1 << entry.first))) { mMapHistPMbits[ch_data::getChId(chData)]->Fill(entry.first); } } @@ -249,12 +379,24 @@ void DigitQcTask::monitorData(o2::framework::ProcessingContext& ctx) } */ } + mHistCFDEff->Reset(); + mHistCFDEff->Divide(mHistNumADC.get(), mHistNumCFD.get()); } + mTimeSum += curTfTimeMax - curTfTimeMin; } void DigitQcTask::endOfCycle() { ILOG(Info, Support) << "endOfCycle" << ENDM; + // one has to set num. of entries manually because + // default TH1Reductor gets only mean,stddev and entries (no integral) + mHistCycleDurationRange->SetBinContent(1., mTimeMaxNS - mTimeMinNS); + mHistCycleDurationRange->SetEntries(mTimeMaxNS - mTimeMinNS); + mHistCycleDurationNTF->SetBinContent(1., mTfCounter); + mHistCycleDurationNTF->SetEntries(mTfCounter); + mHistCycleDuration->SetBinContent(1., mTimeSum); + mHistCycleDuration->SetEntries(mTimeSum); + ILOG(Debug) << "Cycle duration: NTF=" << mTfCounter << ", range = " << (mTimeMaxNS - mTimeMinNS) / 1e6 / mTfCounter << " ms/TF, sum = " << mTimeSum / 1e6 / mTfCounter << " ms/TF" << ENDM; } void DigitQcTask::endOfActivity(Activity& /*activity*/) @@ -265,11 +407,11 @@ void DigitQcTask::endOfActivity(Activity& /*activity*/) void DigitQcTask::reset() { // clean all the monitor objects here - ILOG(Info, Support) << "Resetting the histogram" << ENDM; mHistTime2Ch->Reset(); mHistAmp2Ch->Reset(); mHistOrbit2BC->Reset(); + mHistBC->Reset(); mHistEventDensity2Ch->Reset(); mHistChDataBits->Reset(); mHistTriggers->Reset(); @@ -280,6 +422,14 @@ void DigitQcTask::reset() mHistAverageTimeA->Reset(); mHistAverageTimeC->Reset(); mHistChannelID->Reset(); + mHistCFDEff->Reset(); + mHistNumADC->Reset(); + mHistNumCFD->Reset(); + mHistTriggersCorrelation->Reset(); + //mHistTimeSum2Diff->Reset(); + mHistCycleDuration->Reset(); + mHistCycleDurationNTF->Reset(); + mHistCycleDurationRange->Reset(); for (auto& entry : mMapHistAmp1D) { entry.second->Reset(); } @@ -289,10 +439,12 @@ void DigitQcTask::reset() for (auto& entry : mMapHistPMbits) { entry.second->Reset(); } - for (auto& entry : mMapHistAmpVsTime) { entry.second->Reset(); } + for (auto& entry : mMapTrgBcOrbit) { + entry.second->Reset(); + } } } // namespace o2::quality_control_modules::fv0 diff --git a/Modules/FV0/src/OutOfBunchCollCheck.cxx b/Modules/FV0/src/OutOfBunchCollCheck.cxx new file mode 100644 index 0000000000..4c03aa0e3f --- /dev/null +++ b/Modules/FV0/src/OutOfBunchCollCheck.cxx @@ -0,0 +1,145 @@ +// 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 OutOfBunchCollCheck.cxx +/// \author Sebastian Bysiak sbysiak@cern.ch +/// + +#include "FV0/OutOfBunchCollCheck.h" +#include "QualityControl/MonitorObject.h" +#include "QualityControl/Quality.h" +#include "QualityControl/QcInfoLogger.h" +// ROOT +#include +#include +#include +#include + +#include + +using namespace std; +using namespace o2::quality_control; + +namespace o2::quality_control_modules::fv0 +{ + +void OutOfBunchCollCheck::configure(std::string) +{ + if (auto param = mCustomParameters.find("thresholdWarning"); param != mCustomParameters.end()) { + mThreshWarning = stof(param->second); + ILOG(Info, Support) << "configure() : using thresholdWarning = " << mThreshWarning << ENDM; + } else { + mThreshWarning = 1e-3; + ILOG(Info, Support) << "configure() : using default thresholdWarning = " << mThreshWarning << ENDM; + } + + if (auto param = mCustomParameters.find("thresholdError"); param != mCustomParameters.end()) { + mThreshError = stof(param->second); + ILOG(Info, Support) << "configure() : using thresholdError = " << mThreshError << ENDM; + } else { + mThreshError = 0.1; + ILOG(Info, Support) << "configure() : using default thresholdError = " << mThreshError << ENDM; + } +} + +Quality OutOfBunchCollCheck::check(std::map>* moMap) +{ + Quality result = Quality::Null; + TH2F* hOutOfBunchColl = 0; + float countsBcOrbitMap = 0; + float countsOutOfBunchColl = 0; + bool metadataFound = false; + std::string metadataKey = "BcOrbitMapIntegral"; + + for (auto& [moName, mo] : *moMap) { + (void)moName; + if (mo->getName().find("OutOfBunchColl") != std::string::npos) { + hOutOfBunchColl = dynamic_cast(mo->getObject()); + for (auto metainfo : mo->getMetadataMap()) { + if (metainfo.first == metadataKey) { + countsBcOrbitMap = std::stof(metainfo.second); + metadataFound = true; + } + } + } + } + std::string reason = ""; + if (!countsBcOrbitMap) + reason = Form("Cannot compute quality due to zero counts in BcOrbitMap"); + if (!metadataFound) + reason = Form("Cannot compute quality due to missing metadata: %s", metadataKey.c_str()); + if (!hOutOfBunchColl) + reason = Form("Cannot compute quality due to problem with retieving MO"); + if (reason != "") { + result.set(Quality::Null); + result.addReason(FlagReasonFactory::Unknown(), reason); + ILOG(Warning) << reason << ENDM; + return result; + } + + result = Quality::Good; + mFractionOutOfBunchColl = 0; + mNumNonEmptyBins = 0; + + countsOutOfBunchColl = hOutOfBunchColl->Integral(); + mFractionOutOfBunchColl = countsOutOfBunchColl / countsBcOrbitMap; + if (mFractionOutOfBunchColl > mThreshError) { + result.set(Quality::Bad); + result.addReason(FlagReasonFactory::Unknown(), + Form("fraction of out of bunch collisions (%.2e) is above \"Error\" threshold (%.2e)", + mFractionOutOfBunchColl, mThreshError)); + } else if (mFractionOutOfBunchColl > mThreshWarning) { + result.set(Quality::Medium); + result.addReason(FlagReasonFactory::Unknown(), + Form("fraction of out of bunch collisions (%.2e) is above \"Warning\" threshold (%.2e)", + mFractionOutOfBunchColl, mThreshWarning)); + } + + for (int i = 1; i < hOutOfBunchColl->GetNbinsX() + 1; i++) { + for (int j = 1; j < hOutOfBunchColl->GetNbinsY() + 1; j++) { + if (hOutOfBunchColl->GetBinContent(i, j)) + mNumNonEmptyBins++; + } + } + result.addMetadata("numNonEmptyBins", std::to_string(mNumNonEmptyBins)); + return result; +} + +std::string OutOfBunchCollCheck::getAcceptedType() { return "TH2"; } + +void OutOfBunchCollCheck::beautify(std::shared_ptr mo, Quality checkResult) +{ + auto* h = dynamic_cast(mo->getObject()); + + TPaveText* msg = new TPaveText(0.1, 0.9, 0.9, 0.95, "NDC"); + h->GetListOfFunctions()->Add(msg); + msg->SetName(Form("%s_msg", mo->GetName())); + msg->Clear(); + msg->SetTextAlign(12); + std::string prefix = Form("Fraction of out of bunch collisions = %.2e (Warning > %.2e, Error > %.2e) ", mFractionOutOfBunchColl, mThreshWarning, mThreshError); + + if (checkResult == Quality::Good) { + msg->SetFillColor(kGreen); + msg->AddText((prefix + ">> Quality::Good <<").c_str()); + } else if (checkResult == Quality::Bad) { + msg->SetFillColor(kRed); + msg->AddText((prefix + ">> Quality::Bad <<").c_str()); + } else if (checkResult == Quality::Medium) { + msg->SetFillColor(kOrange); + msg->AddText((prefix + ">> Quality::Medium <<").c_str()); + } else if (checkResult == Quality::Null) { + msg->SetFillColor(kGray); + msg->AddText((prefix + ">> Quality::Null <<").c_str()); + } +} + +} // namespace o2::quality_control_modules::fv0 diff --git a/Modules/FV0/src/OutOfBunchCollTask.cxx b/Modules/FV0/src/OutOfBunchCollTask.cxx new file mode 100644 index 0000000000..b5d9a9fc3c --- /dev/null +++ b/Modules/FV0/src/OutOfBunchCollTask.cxx @@ -0,0 +1,111 @@ +// 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 OutOfBunchCollTask.cxx +/// \author Sebastian Bysiak sbysiak@cern.ch +/// PostProcessing task which finds collisions not compatible with BC pattern + +#include "CommonDataFormat/BunchFilling.h" +#include "QualityControl/QcInfoLogger.h" +#include "QualityControl/DatabaseInterface.h" +#include "FV0/OutOfBunchCollTask.h" + +#include +#include +#include +#include "Rtypes.h" + +using namespace o2::quality_control::postprocessing; + +namespace o2::quality_control_modules::fv0 +{ + +OutOfBunchCollTask::~OutOfBunchCollTask() +{ + delete mListHistGarbage; +} + +void OutOfBunchCollTask::configure(std::string, const boost::property_tree::ptree& config) +{ + mCcdbUrl = config.get_child("qc.config.conditionDB.url").get_value(); +} + +void OutOfBunchCollTask::initialize(Trigger, framework::ServiceRegistry& services) +{ + mDatabase = &services.get(); + mCcdbApi.init(mCcdbUrl); + + mMapDigitTrgNames.insert({ ETrgMenu::kMinBias, "MinBias" }); + mMapDigitTrgNames.insert({ ETrgMenu::kOuterRing, "OuterRing" }); + mMapDigitTrgNames.insert({ ETrgMenu::kNChannels, "NChannels" }); + mMapDigitTrgNames.insert({ ETrgMenu::kCharge, "Charge" }); + mMapDigitTrgNames.insert({ ETrgMenu::kInnerRing, "InnerRing" }); + + mListHistGarbage = new TList(); + mListHistGarbage->SetOwner(kTRUE); + for (const auto& entry : mMapDigitTrgNames) { + auto pairOutOfBunchColl = mMapOutOfBunchColl.insert({ entry.first, new TH2F(Form("OutOfBunchColl_Trg%s", entry.second.c_str()), Form("BC-orbit map for out-of-bunch collisions: %s fired;Orbit;BC", entry.second.c_str()), 256, 0, 256, 3564, 0, 3564) }); + if (pairOutOfBunchColl.second) { + getObjectsManager()->startPublishing(pairOutOfBunchColl.first->second); + mListHistGarbage->Add(pairOutOfBunchColl.first->second); + } + } + for (auto& entry : mMapOutOfBunchColl) { + entry.second->SetOption("colz"); + } + mHistBcPattern = std::make_unique("bcPattern", "BC pattern", 256, 0, 256, 3564, 0, 3564); + mHistBcPattern->SetOption("colz"); + getObjectsManager()->startPublishing(mHistBcPattern.get()); +} + +void OutOfBunchCollTask::update(Trigger, framework::ServiceRegistry&) +{ + std::map metadata; + std::map headers; + const auto* bcPattern = mCcdbApi.retrieveFromTFileAny("GLO/GRP/BunchFilling", metadata, -1, &headers); + if (!bcPattern) { + ILOG(Error) << "\nMO \"BunchFilling\" NOT retrieved!!!\n" + << ENDM; + } + const int nBc = 3564; + const int nOrbits = 256; + mHistBcPattern->Reset(); + for (int j = 0; j < nOrbits + 1; j++) + for (int i = 0; i < nBc + 1; i++) + mHistBcPattern->SetBinContent(j + 1, i + 1, bcPattern->testBC(i)); + + for (auto& entry : mMapOutOfBunchColl) { + auto moName = Form("BcOrbitMap_Trg%s", mMapDigitTrgNames.at(entry.first).c_str()); + auto mo = mDatabase->retrieveMO("qc/FV0/MO/DigitQcTask/", moName); + auto hBcOrbitMapTrg = (TH2F*)mo->getObject(); + if (!hBcOrbitMapTrg) { + ILOG(Error) << "\nMO \"" << moName << "\" NOT retrieved!!!\n" + << ENDM; + } + entry.second->Reset(); + // scale bc pattern by vmax to make sure the difference is non positive + float vmax = hBcOrbitMapTrg->GetBinContent(hBcOrbitMapTrg->GetMaximumBin()); + entry.second->Add(hBcOrbitMapTrg, mHistBcPattern.get(), 1, -1 * vmax); + for (int j = 0; j < nOrbits + 1; j++) + for (int i = 0; i < nBc + 1; i++) + if (entry.second->GetBinContent(j + 1, i + 1) < 0) + entry.second->SetBinContent(j + 1, i + 1, 0); // is it too slow? + entry.second->SetEntries(entry.second->Integral()); + getObjectsManager()->addMetadata(entry.second->GetName(), "BcOrbitMapIntegral", std::to_string(hBcOrbitMapTrg->Integral())); + } +} + +void OutOfBunchCollTask::finalize(Trigger, framework::ServiceRegistry&) +{ +} + +} // namespace o2::quality_control_modules::fv0