diff --git a/Modules/FIT/FT0/CMakeLists.txt b/Modules/FIT/FT0/CMakeLists.txt index 4ae5f80d72..8ae5c2bc4f 100644 --- a/Modules/FIT/FT0/CMakeLists.txt +++ b/Modules/FIT/FT0/CMakeLists.txt @@ -2,8 +2,7 @@ add_library(O2QcFT0) -target_sources(O2QcFT0 PRIVATE src/TH1ReductorLaser.cxx - src/DigitQcTaskLaser.cxx +target_sources(O2QcFT0 PRIVATE src/AgingLaserTask.cxx src/DigitQcTask.cxx src/GenericCheck.cxx src/CFDEffCheck.cxx @@ -32,8 +31,7 @@ install(TARGETS O2QcFT0 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) add_root_dictionary(O2QcFT0 - HEADERS include/FT0/TH1ReductorLaser.h - include/FT0/DigitQcTaskLaser.h + HEADERS include/FT0/AgingLaserTask.h include/FT0/DigitQcTask.h include/FT0/PostProcTask.h include/FT0/CFDEffCheck.h @@ -70,7 +68,6 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/FT0 # RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} #) - # ---- Test(s) ---- #set(TEST_SRCS test/testQcFT0.cxx) # uncomment to reenable the test which was empty @@ -91,6 +88,7 @@ endforeach() # ----- Configs ------- install(FILES ft0-reconstruction-config.json + etc/ft0-aging-laser.json DESTINATION etc) get_property(dirs diff --git a/Modules/FIT/FT0/README.md b/Modules/FIT/FT0/README.md new file mode 100644 index 0000000000..a96c101768 --- /dev/null +++ b/Modules/FIT/FT0/README.md @@ -0,0 +1,33 @@ +# FT0 quality control + +## Aging monitoring + +The aging monitoring of FT0 is performed by 1 minute long laser runs that should be launched after each beam dump. A dedicated QC task is analyzing the laser data: `o2::quality_control_modules::ft0::AgingLaserTask`. + +At the moment the QC task is adapted to the FT0 laser calibration system (LCS) and the monitoring of the FT0 aging. If needed, the task can be generalized to work with other FIT detectors. + +### Monitoring principles + +The schematics of the LCS is shown below. Per laser pulse, there will be two signals in each reference channel and one signal in each detector channel. The signals are separated in time by well defined delays, so one can identify them by BC ID. + + + +More information about the LCS and the hardware side of the aging monitoring can be found [here](https://indico.cern.ch/event/1229241/contributions/5172798/attachments/2561719/4420583/Ageing-related%20tasks.pdf). + +### `AgingLaserTask` configuration + +An example configuration can be found in `etc/ft0-aging-laser.json`. The task parameters are: + +- `detectorChannelIDs`: list of detector channels to be monitored. Omit this parameter to use all. +- `referenceChannelIDs`: the reference channel IDs, should be: "208, 209, 210, 211". +- `detectorAmpCut`: Lower cut on the detector amplitude in ADC ch, default "0". **TODO**: this has no effect at the moment. +- `referenceAmpCut`: Lower cut on the reference channel amplitude in ADC ch to ignore cross talk, default "100". +- `laserTriggerBCs`: list of BCs when the laser fires, should be "0, 1783". +- `detectorBCdelay`: amount of BCs after the laser trigger BCs when the laser pulse is expected in the detector, should be "131". +- `referencePeak1BCdelays`: amount of BCs after the laser trigger BCs when the first laser pulse is expected in the reference channels, should be "115, 115, 115, 115". One value per reference channel, even though they will be the same with the current LCS setup. +- `referencePeak2BCdelays`: amount of BCs after the laser trigger BCs when the second laser pulse is expected in the reference channels, should be "136, 142, 135, 141". One value per reference channel. +- `debug`: If true, an additional set of plots can be produced for debugging purposes, default "false". + +The channel ID and BC values delays are rather fixed and should not change unless the LCS changes significantly. + +**TODO**: should we apply the amplitude cuts in the SliceTrendingTask instead? diff --git a/Modules/FIT/FT0/etc/ft0-aging-laser.json b/Modules/FIT/FT0/etc/ft0-aging-laser.json new file mode 100644 index 0000000000..3686779058 --- /dev/null +++ b/Modules/FIT/FT0/etc/ft0-aging-laser.json @@ -0,0 +1,51 @@ +{ + "qc": { + "config": { + "database": { + "implementation": "CCDB", + "#host": "ccdb-test.cern.ch:8080", + "host": "http://localhost:8080", + "username": "not_applicable", + "password": "not_applicable", + "name": "not_applicable" + }, + "monitoring": { + "url": "infologger:///debug?qc" + }, + "consul": { + "url": "" + }, + "conditionDB": { + "url": "alice-ccdb.cern.ch" + }, + "bookkeeping": { + "url": "" + } + }, + "tasks": { + "AgingLaser": { + "active": "true", + "className": "o2::quality_control_modules::ft0::AgingLaserTask", + "moduleName": "QcFT0", + "detectorName": "FT0", + "cycleDurationSeconds": "300", + "maxNumberCycles": "-1", + "dataSource": { + "type": "direct", + "query": "digits:FT0/DIGITSBC/0;channels:FT0/DIGITSCH/0" + }, + "taskParameters": { + "#detectorChannelIDs": "omit to use all", + "referenceChannelIDs": "208, 209, 210, 211", + "detectorAmpCut": "0", + "referenceAmpCut": "100", + "laserTriggerBCs": "0, 1783", + "detectorBCdelay": "131", + "referencePeak1BCdelays": "115, 115, 115, 115", + "referencePeak2BCdelays": "136, 142, 135, 141", + "debug": "false" + } + } + } + } +} \ No newline at end of file diff --git a/Modules/FIT/FT0/images/lcs.png b/Modules/FIT/FT0/images/lcs.png new file mode 100644 index 0000000000..90b5432a3c Binary files /dev/null and b/Modules/FIT/FT0/images/lcs.png differ diff --git a/Modules/FIT/FT0/include/FT0/AgingLaserTask.h b/Modules/FIT/FT0/include/FT0/AgingLaserTask.h new file mode 100644 index 0000000000..37172b56bb --- /dev/null +++ b/Modules/FIT/FT0/include/FT0/AgingLaserTask.h @@ -0,0 +1,171 @@ +// 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 AgingLaserTask.h +/// \author Andreas Molander , Sandor Lokos , Edmundo Garcia-Solis +/// + +#ifndef QC_MODULE_FT0_AGINGLASERTASK_H +#define QC_MODULE_FT0_AGINGLASERTASK_H + +#include "QualityControl/TaskInterface.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace o2::quality_control::core; + +namespace o2::quality_control_modules::ft0 +{ + +class AgingLaserTask final : public TaskInterface +{ + public: + AgingLaserTask() = default; + ~AgingLaserTask() override; + + void initialize(o2::framework::InitContext& ctx) override; + void startOfActivity(const Activity& activity) override; + void startOfCycle() override; + void monitorData(o2::framework::ProcessingContext& ctx) override; + void endOfCycle() override; + void endOfActivity(const Activity& activity) override; + void reset() override; + + private: + /// Check if the laser was triggered for this BC + /// \param bc BC to check + /// \param bcDelay Expected BC delay from trigger to signal + /// \return True if the laser was triggered + bool bcIsTrigger(int bc, int bcDelay) const; + + /// Check if a detector signal is expected for this BC + /// \param bc BC to check + /// \return True if a detector signal is expected + bool bcIsDetector(int bc) const; + + /// Check if the first reference signal is expected for this BC + /// \param bc BC to check + /// \param refChId Rerernce channel where signal is seen + /// \return True if the first reference signal is expected for this BC + bool bcIsPeak1(int bc, int refChId) const; + + /// Check if the second reference signal is expected for this BC + /// \param bc BC to check + /// \param refChId Rerernce channel where signal is seen + /// \return True if the second reference signal is expected for this BC + bool bcIsPeak2(int bc, int refChId) const; + + // Constants + constexpr static std::size_t sNCHANNELS_PM = o2::ft0::Constants::sNCHANNELS_PM; ///< Max number of FT0 channels + constexpr static std::size_t sMaxBC = o2::constants::lhc::LHCMaxBunches; ///< Max number of BCs + + // Task parameters + std::vector mDetectorChIDs; ///< Enabled detector channels + std::vector mReferenceChIDs; ///< Enabled reference channels + int mDetectorAmpCut; ///< Amplitude cut for detector channels + int mReferenceAmpCut; ///< Amplitude cut for reference channels + std::vector mLaserTriggerBCs; ///< BCs in which the laser is triggered + int mDetectorBCdelay; ///< BC delay for detector channels (same for all) + std::map mReferencePeak1BCdelays; ///< BC delays for reference channel peak 1 (per channel) + std::map mReferencePeak2BCdelays; ///< BC delays for reference channel peak 2 (per channel) + + bool mDebug = false; ///< Enable more histograms in debug mode + + // Histograms + + // Amplitude per channel + std::unique_ptr mHistAmpVsChADC0; ///< Amplitude per channel for ADC0 (detector + reference channels) + std::unique_ptr mHistAmpVsChADC1; ///< Amplitude per channel for ADC1 (detector + reference channels) + std::unique_ptr mHistAmpVsChPeak1ADC0; ///< Amplitude per channel for peak 1 for ADC0 (reference channels) + std::unique_ptr mHistAmpVsChPeak1ADC1; ///< Amplitude per channel for peak 1 for ADC1 (reference channels) + std::unique_ptr mHistAmpVsChPeak2ADC0; ///< Amplitude per channel for peak 2 for ADC0 (reference channels) + std::unique_ptr mHistAmpVsChPeak2ADC1; ///< Amplitude per channel for peak 2 for ADC1 (reference channels) + + // // Time per channel + std::unique_ptr mHistTimeVsCh; ///< Time per channel (detector + reference channels) + std::unique_ptr mHistTimeVsChPeak1; ///< Time per channel for peak 1 (reference channels, both ADCs) + std::unique_ptr mHistTimeVsChPeak2; ///< Time per channel for peak 2 (reference channels, both ADCs) + + // Debug histograms + + // Ampltiude per channel + std::unique_ptr mDebugHistAmpVsCh; ///< Amplitude per channel (detector + reference channels) + + // Ampltidue histograms for reference channel peaks + std::map> mMapDebugHistAmp; ///< Amplitude (both ADCs and peaks) + std::map> mMapDebugHistAmpADC0; ///< Ampltidue for ADC0 + std::map> mMapDebugHistAmpADC1; ///< Ampltidue for ADC1 + std::map> mMapDebugHistAmpPeak1; ///< Amplitude for peak 1 + std::map> mMapDebugHistAmpPeak2; ///< Amplitude for peak 2 + std::map> mMapDebugHistAmpPeak1ADC0; ///< Amplitude for peak 1 for ADC0 + std::map> mMapDebugHistAmpPeak1ADC1; ///< Amplitude for peak 1 for ADC1 + std::map> mMapDebugHistAmpPeak2ADC0; ///< Amplitude for peak 2 for ADC0 + std::map> mMapDebugHistAmpPeak2ADC1; ///< Amplitude for peak 2 for ADC1 + + // Time per channel + std::unique_ptr mDebugHistTimeVsChADC0; ///< Time per channel for ADC0 (detector + reference channels) + std::unique_ptr mDebugHistTimeVsChADC1; ///< Time per channel for ADC1 (detector + reference channels) + std::unique_ptr mDebugHistTimeVsChPeak1ADC0; ///< Time per channel for peak 1 for ADC0 (reference channels) + std::unique_ptr mDebugHistTimeVsChPeak1ADC1; ///< Time per channel for peak 1 for ADC1 (reference channels) + std::unique_ptr mDebugHistTimeVsChPeak2ADC0; ///< Time per channel for peak 2 for ADC0 (reference channels) + std::unique_ptr mDebugHistTimeVsChPeak2ADC1; ///< Time per channel for peak 2 for ADC1 (reference channels) + + // Time histograms for reference channel peaks + // TODO: add mMapDebugHistTime, mMapDebugHistTimeADC0, mMapDebugHistTimeADC1 + std::map> mMapDebugHistTimePeak1; + std::map> mMapDebugHistTimePeak2; + std::map> mMapDebugHistTimePeak1ADC0; + std::map> mMapDebugHistTimePeak1ADC1; + std::map> mMapDebugHistTimePeak2ADC0; + std::map> mMapDebugHistTimePeak2ADC1; + + // BC + std::unique_ptr mDebugHistBC; ///< All BCs + std::unique_ptr mDebugHistBCDetector; ///< Detector channel BCs + std::unique_ptr mDebugHistBCReference; ///< Reference channel BCs + std::unique_ptr mDebugHistBCAmpCut; ///< All BCs with amplitude cut + std::unique_ptr mDebugHistBCAmpCutADC0; ///< All BCs with amplitude cut for ADC0 + std::unique_ptr mDebugHistBCAmpCutADC1; ///< All BCs with amplitude cut for ADC1 + std::unique_ptr mDebugHistBCDetectorAmpCut; ///< Detector channel BCs with amplitude cut + std::unique_ptr mDebugHistBCDetectorAmpCutADC0; ///< Detector channel BCs with amplitude cut for ADC0 + std::unique_ptr mDebugHistBCDetectorAmpCutADC1; ///< Detector channel BCs with amplitude cut for ADC1 + std::unique_ptr mDebugHistBCReferenceAmpCut; ///< Reference channel BCs with amplitude cut + std::unique_ptr mDebugHistBCReferenceAmpCutADC0; ///< Reference channel BCs with amplitude cut for ADC0 + std::unique_ptr mDebugHistBCReferenceAmpCutADC1; ///< Reference channel BCs with amplitude cut for ADC1 + + // Amplitude per BC for reference channels + std::map> mMapDebugHistAmpVsBC; ///< Amplitude vs BC (both ADCs and peaks = 4 peaks) + std::map> mMapDebugHistAmpVsBCADC0; ///< Amplitude vs BC for ADC0 (both peaks) + std::map> mMapDebugHistAmpVsBCADC1; ///< Amplitude vs BC for ADC1 (both peaks) + + // Including the histograms below will produce 'object of class TObjArray read too many bytes' in --local-batch mode + + // // Time per BC for reference channels + // std::map> mMapDebugHistTimeVsBC; ///< Time vs BC (both ADCs and peaks = 4 peaks) + // std::map> mMapDebugHistTimeVsBCADC0; ///< Time vs BC for ADC0 (both peaks) + // std::map> mMapDebugHistTimeVsBCADC1; ///< Time vs BC for ADC1 (both peaks) +}; + +} // namespace o2::quality_control_modules::ft0 + +#endif // QC_MODULE_FT0_AGINGLASERTASK_H diff --git a/Modules/FIT/FT0/include/FT0/DigitQcTaskLaser.h b/Modules/FIT/FT0/include/FT0/DigitQcTaskLaser.h deleted file mode 100644 index ec38fbec57..0000000000 --- a/Modules/FIT/FT0/include/FT0/DigitQcTaskLaser.h +++ /dev/null @@ -1,176 +0,0 @@ -// 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 DigitQcTaskLaser.h -/// \author Artur Furs afurs@cern.ch, developed further for laser QC by Sandor Lokos (sandor.lokos@cern.ch) -/// \brief Quality Control DPL Task for FT0's digit visualization for laser events only - -#ifndef QC_MODULE_FT0_FT0DIGITQCTASKLASER_H -#define QC_MODULE_FT0_FT0DIGITQCTASKLASER_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "TH1.h" -#include "TH2.h" -#include "TList.h" -#include "Rtypes.h" - -#include "CommonConstants/LHCConstants.h" - -#include "QualityControl/TaskInterface.h" -#include "QualityControl/QcInfoLogger.h" - -#include "FT0Base/Constants.h" -#include "FT0Base/Geometry.h" -#include "DataFormatsFT0/Digit.h" -#include "DataFormatsFT0/ChannelData.h" - -using namespace o2::quality_control::core; - -namespace o2::quality_control_modules::ft0 -{ -class DigitQcTaskLaser final : public TaskInterface -{ - public: - /// \brief Constructor - DigitQcTaskLaser() : mHashedBitBinPos(fillHashedBitBinPos()) {} - /// Destructor - ~DigitQcTaskLaser() override; - // Definition of the methods for the template method pattern - void initialize(o2::framework::InitContext& ctx) override; - void startOfActivity(const Activity& activity) override; - void startOfCycle() override; - void monitorData(o2::framework::ProcessingContext& ctx) override; - void endOfCycle() override; - void endOfActivity(const Activity& activity) override; - void reset() override; - constexpr static std::size_t sNCHANNELS_PM = o2::ft0::Constants::sNCHANNELS_PM; - constexpr static std::size_t sNCHANNELS_A = o2::ft0::Geometry::NCellsA * 4; - constexpr static std::size_t sNCHANNELS_C = o2::ft0::Geometry::NCellsC * 4; - constexpr static std::size_t sOrbitsPerTF = 256; - constexpr static std::size_t sBCperOrbit = o2::constants::lhc::LHCMaxBunches; - - constexpr static float sCFDChannel2NS = 0.01302; // CFD channel width in ns - - private: - template ::value || - std::is_same::value || - (std::is_integral::value && !std::is_same::value)>::type> - auto parseParameters(const std::string& param, const std::string& del) - { - std::regex reg(del); - std::sregex_token_iterator first{ param.begin(), param.end(), reg, -1 }, last; - std::vector vecResult; - for (auto it = first; it != last; it++) { - if constexpr (std::is_integral::value && !std::is_same::value) { - vecResult.push_back(std::stoi(*it)); - } else if constexpr (std::is_floating_point::value) { - vecResult.push_back(std::stod(*it)); - } else if constexpr (std::is_same::value) { - vecResult.push_back(*it); - } - } - return vecResult; - } - - void rebinFromConfig(); - unsigned int getModeParameter(std::string, unsigned int, std::map); - int getNumericalParameter(std::string, int); - - TList* mListHistGarbage; - std::set mSetAllowedChIDs; - std::set mSetAllowedChIDsAmpVsTime; - std::array mStateLastIR2Ch; - std::array mChID2PMhash; // map chID->hashed PM value - uint8_t mTCMhash; // hash value for TCM, and bin position in hist - std::map mMapDigitTrgNames; - std::map mMapChTrgNames; - std::unique_ptr mHistNumADC; - std::unique_ptr mHistNumCFD; - - std::map mMapTrgSoftware; - enum TrgModeSide { kAplusC, - kAandC, - kA, - kC - }; - enum TrgModeThresholdVar { kAmpl, - kNchannels - }; - enum TrgComparisonResult { kSWonly, - kTCMonly, - kNone, - kBoth - }; - const int mNChannelsA = 96; - // trigger parameters: - // - modes - unsigned int mTrgModeThresholdVar; - unsigned int mTrgModeSide; - // - time window for vertex trigger - int mTrgThresholdTimeLow; - int mTrgThresholdTimeHigh; - // - parameters for (Semi)Central triggers - // same parameters re-used for both Ampl and Nchannels thresholds - int mTrgThresholdCenA; - int mTrgThresholdCenC; - int mTrgThresholdCenSum; - int mTrgThresholdSCenA; - int mTrgThresholdSCenC; - int mTrgThresholdSCenSum; - - // Objects which will be published - std::unique_ptr mHistAmp2Ch; - std::unique_ptr mHistTime2Ch; - std::unique_ptr mHistChDataBits; - std::unique_ptr mHistBC; - std::unique_ptr mHistCFDEff; - std::unique_ptr mHistTimeSum2Diff; - std::map mMapHistAmp1D; - std::map mMapHistTime1D; - std::map mMapHistPMbits; - std::map mMapHistAmpVsTime; - std::unique_ptr mHistBCvsFEEmodules; - std::unique_ptr mHistOrbitVsTrg; - std::unique_ptr mHistOrbitVsFEEmodules; - std::unique_ptr mHistTriggersSw; - std::unique_ptr mHistTriggersSoftwareVsTCM; - - // Hashed maps - static const size_t mapSize = 256; - const std::array, mapSize> mHashedBitBinPos; // map with bit position for 1 byte trg signal, for 1 Dim hists; - static std::array, mapSize> fillHashedBitBinPos() - { - std::array, mapSize> hashedBitBinPos{}; - for (int iByteValue = 0; iByteValue < hashedBitBinPos.size(); iByteValue++) { - auto& vec = hashedBitBinPos[iByteValue]; - for (int iBit = 0; iBit < 8; iBit++) { - if (iByteValue & (1 << iBit)) { - vec.push_back(iBit); - } - } - } - return hashedBitBinPos; - } -}; - -} // namespace o2::quality_control_modules::ft0 - -#endif // QC_MODULE_FT0_FT0DIGITQCTASKLASER_H diff --git a/Modules/FIT/FT0/include/FT0/LinkDef.h b/Modules/FIT/FT0/include/FT0/LinkDef.h index a7d45b2591..7933a1aec0 100644 --- a/Modules/FIT/FT0/include/FT0/LinkDef.h +++ b/Modules/FIT/FT0/include/FT0/LinkDef.h @@ -4,7 +4,6 @@ #pragma link off all functions; #pragma link C++ class o2::quality_control_modules::ft0::EventWithChannelData + ; - #pragma link C++ class o2::quality_control_modules::ft0::DigitQcTask + ; #pragma link C++ class o2::quality_control_modules::ft0::MergedTreeCheck + ; #pragma link C++ class o2::quality_control_modules::ft0::PostProcTask + ; @@ -14,6 +13,6 @@ #pragma link C++ class o2::quality_control_modules::ft0::OutOfBunchCollCheck + ; #pragma link C++ class o2::quality_control_modules::ft0::RecPointsQcTask + ; -#pragma link C++ class o2::quality_control_modules::ft0::DigitQcTaskLaser + ; -#pragma link C++ class o2::quality_control_modules::ft0::TH1ReductorLaser + ; +#pragma link C++ class o2::quality_control_modules::ft0::AgingLaserTask + ; + #endif diff --git a/Modules/FIT/FT0/include/FT0/TH1ReductorLaser.h b/Modules/FIT/FT0/include/FT0/TH1ReductorLaser.h deleted file mode 100644 index 71227a9818..0000000000 --- a/Modules/FIT/FT0/include/FT0/TH1ReductorLaser.h +++ /dev/null @@ -1,56 +0,0 @@ -// 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 TH1ReductorLaser.h -/// \author Piotr Konopka, developed to laser QC by Sandor Lokos -/// (sandor.lokos@cern.ch) -/// -#ifndef QUALITYCONTROL_TH1REDUCTORLASER_H -#define QUALITYCONTROL_TH1REDUCTORLASER_H - -#include "QualityControl/ReductorTObject.h" - -namespace o2::quality_control_modules::ft0 -{ - -/// \brief A Reductor which obtains the most popular characteristics of TH1. -/// -/// A Reductor which obtains the most popular characteristics of TH1. -/// It produces a branch in the format: "mean/D:stddev:entries" -class TH1ReductorLaser : public quality_control::postprocessing::ReductorTObject -{ - public: - TH1ReductorLaser() = default; - ~TH1ReductorLaser() = default; - - void* getBranchAddress() override; - const char* getBranchLeafList() override; - void update(TObject* obj) override; - - private: - static constexpr int NChannel = 208; - struct { - Double_t validity1; - Double_t validity2; - Double_t mean1; - Double_t mean2; - Double_t mean[NChannel]; - Double_t stddev1; - Double_t stddev2; - Double_t stddev[NChannel]; - - } mStats; -}; - -} // namespace o2::quality_control_modules::ft0 - -#endif // QUALITYCONTROL_TH1REDUCTORLASER_H \ No newline at end of file diff --git a/Modules/FIT/FT0/src/AgingLaserTask.cxx b/Modules/FIT/FT0/src/AgingLaserTask.cxx new file mode 100644 index 0000000000..07823ecb45 --- /dev/null +++ b/Modules/FIT/FT0/src/AgingLaserTask.cxx @@ -0,0 +1,599 @@ +// 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 AgingLaserTask.cxx +/// \author Andreas Molander , Sandor Lokos , Edmundo Garcia-Solis +/// + +#include "FT0/AgingLaserTask.h" + +#include "Common/Utils.h" +#include "FITCommon/HelperCommon.h" +#include "QualityControl/QcInfoLogger.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace o2::quality_control_modules::ft0 +{ + +AgingLaserTask::~AgingLaserTask() +{ +} + +void AgingLaserTask::initialize(o2::framework::InitContext&) +{ + // Read task parameters + + // Enabled detector channels + const std::string detectorChannels = o2::quality_control_modules::common::getFromConfig(mCustomParameters, "detectorChannelIDs", ""); + if (detectorChannels.size()) { + mDetectorChIDs = fit::helper::parseParameters(detectorChannels, ","); + } else { + // Not specified, enable all + for (uint8_t chId = 0; chId < sNCHANNELS_PM; chId++) { + mDetectorChIDs.push_back(chId); + } + } + + // Enabled reference channels + const std::string referenceChannels = o2::quality_control_modules::common::getFromConfig(mCustomParameters, "referenceChannelIDs", ""); + if (referenceChannels.size()) { + mReferenceChIDs = fit::helper::parseParameters(referenceChannels, ","); + } else { + // Not specified, enable all + // TODO: return with fatal if not specified, to avoid hard coded numbers? + for (uint8_t chId = 208; chId < 211; chId++) { + mReferenceChIDs.push_back(chId); + } + } + + mDetectorAmpCut = o2::quality_control_modules::common::getFromConfig(mCustomParameters, "detectorAmpCut", 0); + mReferenceAmpCut = o2::quality_control_modules::common::getFromConfig(mCustomParameters, "referenceAmpCut", 100); + + // BCs + + // Laser trigger BCs + const std::string laserTriggerBCs = o2::quality_control_modules::common::getFromConfig(mCustomParameters, "laserTriggerBCs", ""); + if (laserTriggerBCs.size()) { + const auto vecParams = fit::helper::parseParameters(laserTriggerBCs, ","); + for (const int bc : vecParams) { + mLaserTriggerBCs.push_back(bc); + } + } + if (mLaserTriggerBCs.size() == 0) { + LOG(fatal) << "No laser trigger BCs specified in QC config!"; + } + + // BC delay for detector channels + mDetectorBCdelay = o2::quality_control_modules::common::getFromConfig(mCustomParameters, "detectorBCdelay", -1); + if (mDetectorBCdelay < 0) { + LOG(fatal) << "No detector BC delay specified in QC config!"; + } + + // BC delay for reference channels peak1 + const std::string referencePeak1BCdelays = o2::quality_control_modules::common::getFromConfig(mCustomParameters, "referencePeak1BCdelays", ""); + if (referencePeak1BCdelays.size()) { + const auto vecParams = fit::helper::parseParameters(referencePeak1BCdelays, ","); + if (vecParams.size() != mReferenceChIDs.size()) { + LOG(fatal) << "Number of reference channels and reference peak 1 BC delays do not match!"; + } + for (int i = 0; i < mReferenceChIDs.size(); i++) { + mReferencePeak1BCdelays.insert({ mReferenceChIDs.at(i), vecParams.at(i) }); + } + } else { + LOG(fatal) << "No reference peak 1 BC delays specified in QC config!"; + } + + // BC delay for reference channels peak2 + const std::string referencePeak2BCdelays = o2::quality_control_modules::common::getFromConfig(mCustomParameters, "referencePeak2BCdelays", ""); + if (referencePeak2BCdelays.size()) { + const auto vecParams = fit::helper::parseParameters(referencePeak2BCdelays, ","); + if (vecParams.size() != mReferenceChIDs.size()) { + LOG(fatal) << "Number of reference channels and reference peak 2 BC delays do not match!"; + } + for (int i = 0; i < mReferenceChIDs.size(); i++) { + mReferencePeak2BCdelays.insert({ mReferenceChIDs.at(i), vecParams.at(i) }); + } + } else { + LOG(fatal) << "No reference peak 2 BC delays specified in QC config!"; + } + + mDebug = o2::quality_control_modules::common::getFromConfig(mCustomParameters, "debug", false); + if (mDebug) { + LOG(warning) << "Running in debug mode!"; + } + + // Initialize histograms + + // Amplitude per channel + mHistAmpVsChADC0 = std::make_unique("AmpPerChannelADC0", "Amplitude vs channel (ADC0);Channel;Amp", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4200, -100, 4100); + mHistAmpVsChADC1 = std::make_unique("AmpPerChannelADC1", "Amplitude vs channel (ADC1);Channel;Amp", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4200, -100, 4100); + mHistAmpVsChPeak1ADC0 = std::make_unique("AmpPerChannelPeak1ADC0", "Amplitude vs channel (peak 1, ADC0);Channel;Amp", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4200, -100, 4100); + mHistAmpVsChPeak1ADC1 = std::make_unique("AmpPerChannelPeak1ADC1", "Amplitude vs channel (peak 1, ADC1);Channel;Amp", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4200, -100, 4100); + mHistAmpVsChPeak2ADC0 = std::make_unique("AmpPerChannelPeak2ADC0", "Amplitude vs channel (peak 2, ADC0);Channel;Amp", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4200, -100, 4100); + mHistAmpVsChPeak2ADC1 = std::make_unique("AmpPerChannelPeak2ADC1", "Amplitude vs channel (peak 2, ADC1);Channel;Amp", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4200, -100, 4100); + getObjectsManager()->startPublishing(mHistAmpVsChADC0.get()); + getObjectsManager()->startPublishing(mHistAmpVsChADC1.get()); + getObjectsManager()->startPublishing(mHistAmpVsChPeak1ADC0.get()); + getObjectsManager()->startPublishing(mHistAmpVsChPeak1ADC1.get()); + getObjectsManager()->startPublishing(mHistAmpVsChPeak2ADC0.get()); + getObjectsManager()->startPublishing(mHistAmpVsChPeak2ADC1.get()); + getObjectsManager()->setDefaultDrawOptions(mHistAmpVsChADC0.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mHistAmpVsChADC1.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mHistAmpVsChPeak1ADC0.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mHistAmpVsChPeak1ADC1.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mHistAmpVsChPeak2ADC0.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mHistAmpVsChPeak2ADC1.get(), "COLZ"); + + // Time per channel + mHistTimeVsCh = std::make_unique("TimePerChannel", "Time vs channel;Channel;Time", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4100, -2050, 2050); + mHistTimeVsChPeak1 = std::make_unique("TimePerChannelPeak1", "Time vs channel (peak 1);Channel;Time", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4100, -2050, 2050); + mHistTimeVsChPeak2 = std::make_unique("TimePerChannelPeak2", "Time vs channel (peak 2);Channel;Time", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4100, -2050, 2050); + getObjectsManager()->startPublishing(mHistTimeVsCh.get()); + getObjectsManager()->startPublishing(mHistTimeVsChPeak1.get()); + getObjectsManager()->startPublishing(mHistTimeVsChPeak2.get()); + getObjectsManager()->setDefaultDrawOptions(mHistTimeVsCh.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mHistTimeVsChPeak1.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mHistTimeVsChPeak2.get(), "COLZ"); + + // Debug histograms + + // Amplitude per channel + mDebugHistAmpVsCh = std::make_unique("AmpPerChannel", "Amplitude vs channel;Channel;Amp", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4200, -100, 4100); + + // Time per channel + mDebugHistTimeVsChADC0 = std::make_unique("TimePerChannelADC0", "Time vs channel (ADC0);Channel;Time", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4100, -2050, 2050); + mDebugHistTimeVsChADC1 = std::make_unique("TimePerChannelADC1", "Time vs channel (ADC1);Channel;Time", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4100, -2050, 2050); + mDebugHistTimeVsChPeak1ADC0 = std::make_unique("TimePerChannelPeak1ADC0", "Time vs channel (peak 1, ADC0);Channel;Time", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4100, -2050, 2050); + mDebugHistTimeVsChPeak1ADC1 = std::make_unique("TimePerChannelPeak1ADC1", "Time vs channel (peak 1, ADC1);Channel;Time", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4100, -2050, 2050); + mDebugHistTimeVsChPeak2ADC0 = std::make_unique("TimePerChannelPeak2ADC0", "Time vs channel (peak 2, ADC0);Channel;Time", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4100, -2050, 2050); + mDebugHistTimeVsChPeak2ADC1 = std::make_unique("TimePerChannelPeak2ADC1", "Time vs channel (peak 2, ADC1);Channel;Time", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4100, -2050, 2050); + + // BC + mDebugHistBC = std::make_unique("BC", "BC;BC;", sMaxBC, 0, sMaxBC); + mDebugHistBCDetector = std::make_unique("BC_detector", "BC detector channels;BC;", sMaxBC, 0, sMaxBC); + mDebugHistBCReference = std::make_unique("BC_reference", "BC reference channels;BC;", sMaxBC, 0, sMaxBC); + mDebugHistBCAmpCut = std::make_unique("BC_ampcut", "BC (amp cut);BC;", sMaxBC, 0, sMaxBC); + mDebugHistBCAmpCutADC0 = std::make_unique("BC_ampcut_ADC0", "BC (amp cut) ADC0;BC;", sMaxBC, 0, sMaxBC); + mDebugHistBCAmpCutADC1 = std::make_unique("BC_ampcut_ADC1", "BC (amp cut) ADC1;BC;", sMaxBC, 0, sMaxBC); + mDebugHistBCDetectorAmpCut = std::make_unique("BC_detector_ampcut", "BC detector channels (amp cut);BC;", sMaxBC, 0, sMaxBC); + mDebugHistBCDetectorAmpCutADC0 = std::make_unique("BC_detector_ampcut_ADC0", "BC detector channels (amp cut) ADC0;BC;", sMaxBC, 0, sMaxBC); + mDebugHistBCDetectorAmpCutADC1 = std::make_unique("BC_detector_ampcut_ADC1", "BC detector channels (amp cut) ADC1;BC;", sMaxBC, 0, sMaxBC); + mDebugHistBCReferenceAmpCut = std::make_unique("BC_reference_ampcut", "BC reference channels (amp cut);BC;", sMaxBC, 0, sMaxBC); + mDebugHistBCReferenceAmpCutADC0 = std::make_unique("BC_reference_ampcut_ADC0", "BC reference channels (amp cut) ADC0;BC;", sMaxBC, 0, sMaxBC); + mDebugHistBCReferenceAmpCutADC1 = std::make_unique("BC_reference_ampcut_ADC1", "BC reference channels (amp cut) ADC1;BC;", sMaxBC, 0, sMaxBC); + + // Reference channel histograms + for (const uint8_t refChId : mReferenceChIDs) { + // Amplitude histograms for reference channel peaks + mMapDebugHistAmp.insert({ refChId, std::make_unique(Form("AmpCh%i", refChId), Form("Amplitude, channel %i;Amp;", refChId), 4200, -100, 4100) }); + mMapDebugHistAmpADC0.insert({ refChId, std::make_unique(Form("AmpCh%iADC0", refChId), Form("Amplitude, channel %i, ADC0;Amp;", refChId), 4200, -100, 4100) }); + mMapDebugHistAmpADC1.insert({ refChId, std::make_unique(Form("AmpCh%iADC1", refChId), Form("Amplitude, channel %i, ADC1;Amp;", refChId), 4200, -100, 4100) }); + mMapDebugHistAmpPeak1.insert({ refChId, std::make_unique(Form("AmpCh%iPeak1", refChId), Form("Amplitude, channel %i, peak 1;Amp;", refChId), 4200, -100, 4100) }); + mMapDebugHistAmpPeak2.insert({ refChId, std::make_unique(Form("AmpCh%iPeak2", refChId), Form("Amplitude, channel %i, peak 2;Amp;", refChId), 4200, -100, 4100) }); + mMapDebugHistAmpPeak1ADC0.insert({ refChId, std::make_unique(Form("AmpCh%iPeak1ADC0", refChId), Form("Amplitude, channel %i, peak 1, ADC0;Amp;", refChId), 4200, -100, 4100) }); + mMapDebugHistAmpPeak1ADC1.insert({ refChId, std::make_unique(Form("AmpCh%iPeak1ADC1", refChId), Form("Amplitude, channel %i, peak 1, ADC1;Amp;", refChId), 4200, -100, 4100) }); + mMapDebugHistAmpPeak2ADC0.insert({ refChId, std::make_unique(Form("AmpCh%iPeak2ADC0", refChId), Form("Amplitude, channel %i, peak 2, ADC0;Amp;", refChId), 4200, -100, 4100) }); + mMapDebugHistAmpPeak2ADC1.insert({ refChId, std::make_unique(Form("AmpCh%iPeak2ADC1", refChId), Form("Amplitude, channel %i, peak 2, ADC1;Amp;", refChId), 4200, -100, 4100) }); + + // Time histograms for reference channel peaks + mMapDebugHistTimePeak1.insert({ refChId, std::make_unique(Form("TimeCh%iPeak1", refChId), Form("Time, channel %i, peak 1;Time;", refChId), 4100, -2050, 2050) }); + mMapDebugHistTimePeak2.insert({ refChId, std::make_unique(Form("TimeCh%iPeak2", refChId), Form("Time, channel %i, peak 2;Time;", refChId), 4100, -2050, 2050) }); + mMapDebugHistTimePeak1ADC0.insert({ refChId, std::make_unique(Form("TimeCh%iPeak1ADC0", refChId), Form("Time, channel %i, peak 1, ADC0;Time;", refChId), 4100, -2050, 2050) }); + mMapDebugHistTimePeak1ADC1.insert({ refChId, std::make_unique(Form("TimeCh%iPeak1ADC1", refChId), Form("Time, channel %i, peak 1, ADC1;Time;", refChId), 4100, -2050, 2050) }); + mMapDebugHistTimePeak2ADC0.insert({ refChId, std::make_unique(Form("TimeCh%iPeak2ADC0", refChId), Form("Time, channel %i, peak 2, ADC0;Time;", refChId), 4100, -2050, 2050) }); + mMapDebugHistTimePeak2ADC1.insert({ refChId, std::make_unique(Form("TimeCh%iPeak2ADC1", refChId), Form("Time, channel %i, peak 2, ADC1;Time;", refChId), 4100, -2050, 2050) }); + + // Amplitude per BC + mMapDebugHistAmpVsBC.insert({ refChId, std::make_unique(Form("AmpPerBC_ch%i", refChId), Form("Amplitude vs BC, channel %i;BC;Amp", refChId), sMaxBC, 0, sMaxBC, 4200, -100, 4200) }); + mMapDebugHistAmpVsBCADC0.insert({ refChId, std::make_unique(Form("AmpPerBC_ch%i_ADC0", refChId), Form("Amplitude vs BC, channel %i, ADC0;BC;Amp", refChId), sMaxBC, 0, sMaxBC, 4200, -100, 4200) }); + mMapDebugHistAmpVsBCADC1.insert({ refChId, std::make_unique(Form("AmpPerBC_ch%i_ADC1", refChId), Form("Amplitude vs BC, channel %i, ADC1;BC;Amp", refChId), sMaxBC, 0, sMaxBC, 4200, -100, 4200) }); + + // // Time per BC + // mMapDebugHistTimeVsBC.insert({ refChId, std::make_unique(Form("TimePerBC_ch%i", refChId), Form("Time vs BC, channel %i;BC;Time", refChId), sMaxBC, 0, sMaxBC, 4100, -2050, 2050) }); + // mMapDebugHistTimeVsBCADC0.insert({ refChId, std::make_unique(Form("TimePerBC_ch%i_ADC0", refChId), Form("Time vs BC, channel %i, ADC0;BC;Time", refChId), sMaxBC, 0, sMaxBC, 4100, -2050, 2050)}); + // mMapDebugHistTimeVsBCADC1.insert({ refChId, std::make_unique(Form("TimePerBC_ch%i_ADC1", refChId), Form("Time vs BC, channel %i, ADC1;BC;Time", refChId), sMaxBC, 0, sMaxBC, 4100, -2050, 2050)}); + } + + if (mDebug) { + // Amplitude per channel + getObjectsManager()->startPublishing(mDebugHistAmpVsCh.get()); + getObjectsManager()->setDefaultDrawOptions(mDebugHistAmpVsCh.get(), "COLZ"); + + // Time per channel + getObjectsManager()->startPublishing(mDebugHistTimeVsChADC0.get()); + getObjectsManager()->startPublishing(mDebugHistTimeVsChADC1.get()); + getObjectsManager()->startPublishing(mDebugHistTimeVsChPeak1ADC0.get()); + getObjectsManager()->startPublishing(mDebugHistTimeVsChPeak1ADC1.get()); + getObjectsManager()->startPublishing(mDebugHistTimeVsChPeak2ADC0.get()); + getObjectsManager()->startPublishing(mDebugHistTimeVsChPeak2ADC1.get()); + getObjectsManager()->setDefaultDrawOptions(mDebugHistTimeVsChADC0.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mDebugHistTimeVsChADC1.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mDebugHistTimeVsChPeak1ADC0.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mDebugHistTimeVsChPeak1ADC1.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mDebugHistTimeVsChPeak2ADC0.get(), "COLZ"); + getObjectsManager()->setDefaultDrawOptions(mDebugHistTimeVsChPeak2ADC1.get(), "COLZ"); + + // BC + getObjectsManager()->startPublishing(mDebugHistBC.get()); + getObjectsManager()->startPublishing(mDebugHistBCDetector.get()); + getObjectsManager()->startPublishing(mDebugHistBCReference.get()); + getObjectsManager()->startPublishing(mDebugHistBCAmpCut.get()); + getObjectsManager()->startPublishing(mDebugHistBCAmpCutADC0.get()); + getObjectsManager()->startPublishing(mDebugHistBCAmpCutADC1.get()); + getObjectsManager()->startPublishing(mDebugHistBCDetectorAmpCut.get()); + getObjectsManager()->startPublishing(mDebugHistBCDetectorAmpCutADC0.get()); + getObjectsManager()->startPublishing(mDebugHistBCDetectorAmpCutADC1.get()); + getObjectsManager()->startPublishing(mDebugHistBCReferenceAmpCut.get()); + getObjectsManager()->startPublishing(mDebugHistBCReferenceAmpCutADC0.get()); + getObjectsManager()->startPublishing(mDebugHistBCReferenceAmpCutADC1.get()); + + // Reference channel histograms + for (const uint8_t refChId : mReferenceChIDs) { + // Amplitude histograms for reference channel peaks + getObjectsManager()->startPublishing(mMapDebugHistAmp.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistAmpADC0.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistAmpADC1.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistAmpPeak1.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistAmpPeak2.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistAmpPeak1ADC0.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistAmpPeak1ADC1.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistAmpPeak2ADC0.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistAmpPeak2ADC1.at(refChId).get()); + + // Time histograms for reference channel peaks + getObjectsManager()->startPublishing(mMapDebugHistTimePeak1.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistTimePeak2.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistTimePeak1ADC0.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistTimePeak1ADC1.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistTimePeak2ADC0.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistTimePeak2ADC1.at(refChId).get()); + + // Amplitude per BC + getObjectsManager()->startPublishing(mMapDebugHistAmpVsBC.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistAmpVsBCADC0.at(refChId).get()); + getObjectsManager()->startPublishing(mMapDebugHistAmpVsBCADC1.at(refChId).get()); + + // // Time per BC + // getObjectsManager()->startPublishing(mMapDebugHistTimeVsBC.at(refChId).get()); + // getObjectsManager()->startPublishing(mMapDebugHistTimeVsBCADC0.at(refChId).get()); + // getObjectsManager()->startPublishing(mMapDebugHistTimeVsBCADC1.at(refChId).get()); + } + } +} + +void AgingLaserTask::startOfActivity(const Activity& activity) +{ + reset(); +} + +void AgingLaserTask::startOfCycle() +{ +} + +void AgingLaserTask::monitorData(o2::framework::ProcessingContext& ctx) +{ + auto channels = ctx.inputs().get>("channels"); + auto digits = ctx.inputs().get>("digits"); + + // Loop over digits + for (const auto& digit : digits) { + const int bc = digit.getIntRecord().bc; + const auto& digitChannelData = digit.getBunchChannelData(channels); + + // Conditions wether to fill BC histograms for this BC. For debug use only + // 'AmpCut' means there was at least one channel with chAmp > mReferenceAmpCut + // 'ADCX' means there was at least one channel data with ADCX + // 'Detector' means there was at least one detector channel + // 'Reference' means there was at least one reference channel + bool bcHasAmpCut = false; + bool bcHasAmpCutADC0 = false; + bool bcHasAmpCutADC1 = false; + bool bcHasDetectorCh = false; + bool bcHasDetectorChAmpCut = false; + bool bcHasDetectorChAmpCutADC0 = false; + bool bcHasDetectorChAmpCutADC1 = false; + bool bcHasReferenceCh = false; + bool bcHasReferenceChAmpCut = false; + bool bcHasReferenceChAmpCutADC0 = false; + bool bcHasReferenceChAmpCutADC1 = false; + + // Fill all BCs + mDebugHistBC->Fill(bc); + + // Loop over channels + for (const auto& chData : digitChannelData) { + const int chId = chData.ChId; + const int chAmp = chData.QTCAmpl; + const int chTime = chData.CFDTime; + const bool isRef = std::find(mReferenceChIDs.begin(), mReferenceChIDs.end(), chId) != mReferenceChIDs.end(); // TODO: optimize + const bool isDet = !isRef; + const bool isADC0 = !chData.getFlag(o2::ft0::ChannelData::kNumberADC); + const bool isADC1 = !isADC0; + const bool isAmpCutOk = chAmp > mReferenceAmpCut; + const bool isDetAmpCutOk = chAmp > mDetectorAmpCut; // TODO: use this + const bool isRefAmpCutOk = chAmp > mReferenceAmpCut; + + // Use var = condition || var, so that var is never set to back to false if once true + bcHasAmpCut = isAmpCutOk || bcHasAmpCut; + bcHasAmpCutADC0 = (isAmpCutOk && isADC0) || bcHasAmpCutADC0; + bcHasAmpCutADC1 = (isAmpCutOk && isADC1) || bcHasAmpCutADC1; + bcHasDetectorCh = isDet || bcHasDetectorCh; + bcHasDetectorChAmpCut = (isDet && isAmpCutOk) || bcHasDetectorChAmpCut; + bcHasDetectorChAmpCutADC0 = (isDet && isAmpCutOk && isADC0) || bcHasDetectorChAmpCutADC0; + bcHasDetectorChAmpCutADC1 = (isDet && isAmpCutOk && isADC1) || bcHasDetectorChAmpCutADC1; + bcHasReferenceCh = isRef || bcHasReferenceCh; + bcHasReferenceChAmpCut = (isRef && isAmpCutOk) || bcHasReferenceChAmpCut; + bcHasReferenceChAmpCutADC0 = (isRef && isAmpCutOk && isADC0) || bcHasReferenceChAmpCutADC0; + bcHasReferenceChAmpCutADC1 = (isRef && isAmpCutOk && isADC1) || bcHasReferenceChAmpCutADC1; + + // Fill amplitude and time per channel histograms + mDebugHistAmpVsCh->Fill(chId, chAmp); + mHistTimeVsCh->Fill(chId, chTime); + isADC0 ? mHistAmpVsChADC0->Fill(chId, chAmp) : mHistAmpVsChADC1->Fill(chId, chAmp); + isADC0 ? mDebugHistTimeVsChADC0->Fill(chId, chTime) : mDebugHistTimeVsChADC1->Fill(chId, chTime); + + // Fill amplitude per BC for reference channels + if (isRef && isRefAmpCutOk) { + mMapDebugHistAmpVsBC.at(chId)->Fill(bc, chAmp); + isADC0 ? mMapDebugHistAmpVsBCADC0.at(chId)->Fill(bc, chAmp) : mMapDebugHistAmpVsBCADC1.at(chId)->Fill(bc, chAmp); + // mMapDebugHistTimeVsBC.at(chId)->Fill(bc, chTime); + // isADC0 ? mMapDebugHistTimeVsBCADC0.at(chId)->Fill(bc, chTime) : mMapDebugHistTimeVsBCADC1.at(chId)->Fill(bc, chTime); + } + + // Fill reference channel ampltidude histograms + if (isRef) { + // Amplitude + mMapDebugHistAmp.at(chId)->Fill(chAmp); + isADC0 ? mMapDebugHistAmpADC0.at(chId)->Fill(chAmp) : mMapDebugHistAmpADC1.at(chId)->Fill(chAmp); + + // Ampltiude for the different peaks. The peaks are selected based on BC + if (isRefAmpCutOk) { + // Ampltiude and time for peak 1 + if (bcIsPeak1(bc, chId)) { + mHistTimeVsChPeak1->Fill(chId, chTime); + mMapDebugHistAmpPeak1.at(chId)->Fill(chAmp); + mMapDebugHistTimePeak1.at(chId)->Fill(chTime); + + if (isADC0) { + mHistAmpVsChPeak1ADC0->Fill(chId, chAmp); + mMapDebugHistAmpPeak1ADC0.at(chId)->Fill(chAmp); + mDebugHistTimeVsChPeak1ADC0->Fill(chId, chTime); + mMapDebugHistTimePeak1ADC0.at(chId)->Fill(chTime); + } else { + mHistAmpVsChPeak1ADC1->Fill(chId, chAmp); + mMapDebugHistAmpPeak1ADC1.at(chId)->Fill(chAmp); + mDebugHistTimeVsChPeak1ADC1->Fill(chId, chTime); + mMapDebugHistTimePeak1ADC1.at(chId)->Fill(chTime); + } + } // if bcIsPeak1 + + // Amplitude and time peak 2 + if (bcIsPeak2(bc, chId)) { + mHistTimeVsChPeak2->Fill(chId, chTime); + mMapDebugHistAmpPeak2.at(chId)->Fill(chAmp); + mMapDebugHistTimePeak2.at(chId)->Fill(chTime); + + if (isADC0) { + mHistAmpVsChPeak2ADC0->Fill(chId, chAmp); + mMapDebugHistAmpPeak2ADC0.at(chId)->Fill(chAmp); + mDebugHistTimeVsChPeak2ADC0->Fill(chId, chTime); + mMapDebugHistTimePeak2ADC0.at(chId)->Fill(chTime); + } else { + mHistAmpVsChPeak2ADC1->Fill(chId, chAmp); + mMapDebugHistAmpPeak2ADC1.at(chId)->Fill(chAmp); + mDebugHistTimeVsChPeak2ADC1->Fill(chId, chTime); + mMapDebugHistTimePeak2ADC1.at(chId)->Fill(chTime); + } + } // if bcIsPeak2 + } // if isRefAmpCutOK + } // if isRef + } // channel loop + + // Fill BCs + if (bcHasAmpCut) { + mDebugHistBCAmpCut->Fill(bc); + } + if (bcHasAmpCutADC0) { + mDebugHistBCAmpCutADC0->Fill(bc); + } + if (bcHasAmpCutADC1) { + mDebugHistBCAmpCutADC1->Fill(bc); + } + if (bcHasDetectorCh) { + mDebugHistBCDetector->Fill(bc); + } + if (bcHasDetectorChAmpCut) { + mDebugHistBCDetectorAmpCut->Fill(bc); + } + if (bcHasDetectorChAmpCutADC0) { + mDebugHistBCDetectorAmpCutADC0->Fill(bc); + } + if (bcHasDetectorChAmpCutADC1) { + mDebugHistBCDetectorAmpCutADC1->Fill(bc); + } + if (bcHasReferenceCh) { + mDebugHistBCReference->Fill(bc); + } + if (bcHasReferenceChAmpCut) { + mDebugHistBCReferenceAmpCut->Fill(bc); + } + if (bcHasReferenceChAmpCutADC0) { + mDebugHistBCReferenceAmpCutADC0->Fill(bc); + } + if (bcHasReferenceChAmpCutADC1) { + mDebugHistBCReferenceAmpCutADC1->Fill(bc); + } + } // digit loop +} // monitorData + +void AgingLaserTask::endOfCycle() +{ + ILOG(Debug, Devel) << "endOfCycle" << ENDM; +} + +void AgingLaserTask::endOfActivity(const Activity& /*activity*/) +{ + ILOG(Debug, Devel) << "endOfActivity" << ENDM; +} + +void AgingLaserTask::reset() +{ + // Reset histograms + ILOG(Debug, Devel) << "Resetting the histograms" << ENDM; + + // Amplitude per channel + mHistAmpVsChADC0->Reset(); + mHistAmpVsChADC1->Reset(); + mHistAmpVsChPeak1ADC0->Reset(); + mHistAmpVsChPeak1ADC1->Reset(); + mHistAmpVsChPeak2ADC0->Reset(); + mHistAmpVsChPeak2ADC1->Reset(); + + // Time per channel + mHistTimeVsCh->Reset(); + mHistTimeVsChPeak1->Reset(); + mHistTimeVsChPeak2->Reset(); + + // Amplitude per channel + mDebugHistAmpVsCh->Reset(); + + // Amplitude histograms for reference channel peaks + for (auto& entry : mMapDebugHistAmp) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistAmpADC0) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistAmpADC1) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistAmpPeak1) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistAmpPeak2) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistAmpPeak1ADC0) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistAmpPeak1ADC1) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistAmpPeak2ADC0) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistAmpPeak2ADC1) { + entry.second->Reset(); + } + + // Time per channel + mDebugHistTimeVsChADC0->Reset(); + mDebugHistTimeVsChADC1->Reset(); + mDebugHistTimeVsChPeak1ADC0->Reset(); + mDebugHistTimeVsChPeak1ADC1->Reset(); + mDebugHistTimeVsChPeak2ADC0->Reset(); + mDebugHistTimeVsChPeak2ADC1->Reset(); + + // Time histograms for reference channel peaks + for (auto& entry : mMapDebugHistTimePeak1) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistTimePeak2) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistTimePeak1ADC0) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistTimePeak1ADC1) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistTimePeak2ADC0) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistTimePeak2ADC1) { + entry.second->Reset(); + } + + // BC + mDebugHistBC->Reset(); + mDebugHistBCDetector->Reset(); + mDebugHistBCReference->Reset(); + mDebugHistBCAmpCut->Reset(); + mDebugHistBCAmpCutADC0->Reset(); + mDebugHistBCAmpCutADC1->Reset(); + mDebugHistBCDetectorAmpCut->Reset(); + mDebugHistBCDetectorAmpCutADC0->Reset(); + mDebugHistBCDetectorAmpCutADC1->Reset(); + mDebugHistBCReferenceAmpCut->Reset(); + mDebugHistBCReferenceAmpCutADC0->Reset(); + mDebugHistBCReferenceAmpCutADC1->Reset(); + + // Amplitude per BC for reference channels + for (auto& entry : mMapDebugHistAmpVsBC) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistAmpVsBCADC0) { + entry.second->Reset(); + } + for (auto& entry : mMapDebugHistAmpVsBCADC1) { + entry.second->Reset(); + } + + // // Time per BC for reference channels + // for (auto& entry : mMapDebugHistTimeVsBC) { + // entry.second->Reset(); + // } + // for (auto& entry : mMapDebugHistTimeVsBCADC0) { + // entry.second->Reset(); + // } + // for (auto& entry : mMapDebugHistTimeVsBCADC1) { + // entry.second->Reset(); + // } +} + +bool AgingLaserTask::bcIsTrigger(int bc, int bcDelay) const +{ + for (const int bcTrg : mLaserTriggerBCs) { + if (bc == bcTrg + bcDelay) { + return true; + } + } + return false; +} + +bool AgingLaserTask::bcIsDetector(int bc) const +{ + return bcIsTrigger(bc, mDetectorBCdelay); +} + +bool AgingLaserTask::bcIsPeak1(int bc, int refChId) const +{ + return bcIsTrigger(bc, mReferencePeak1BCdelays.at(refChId)); +} + +bool AgingLaserTask::bcIsPeak2(int bc, int refChId) const +{ + return bcIsTrigger(bc, mReferencePeak2BCdelays.at(refChId)); +} + +} // namespace o2::quality_control_modules::ft0 diff --git a/Modules/FIT/FT0/src/DigitQcTaskLaser.cxx b/Modules/FIT/FT0/src/DigitQcTaskLaser.cxx deleted file mode 100644 index 58c65f2c4b..0000000000 --- a/Modules/FIT/FT0/src/DigitQcTaskLaser.cxx +++ /dev/null @@ -1,592 +0,0 @@ -// 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 DigitQcTaskLaser.cxx -/// \brief Based on the existing DigitQcTask -/// \author Sandor Lokos sandor.lokos@cern.ch - -#include "FT0/DigitQcTaskLaser.h" - -#include "TCanvas.h" -#include "TROOT.h" - -#include "QualityControl/QcInfoLogger.h" -#include "DataFormatsFIT/Triggers.h" -#include "Framework/InputRecord.h" -#include "DataFormatsFT0/LookUpTable.h" - -namespace o2::quality_control_modules::ft0 -{ - -DigitQcTaskLaser::~DigitQcTaskLaser() -{ - delete mListHistGarbage; -} - -void DigitQcTaskLaser::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) { - if (!gROOT->FindObject(hName.data())) { - ILOG(Warning) << "config: histogram named \"" << hName << "\" not found" << ENDM; - return; - } - std::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 = "#"; - try { - for (auto& param : mCustomParameters.getAllDefaults()) { - 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 { - rebinHisto(hName, binning); - } - } - } catch (std::out_of_range& oor) { - ILOG(Error) << "Cannot access the default custom parameters : " << oor.what() << ENDM; - } -} - -unsigned int DigitQcTaskLaser::getModeParameter(std::string paramName, unsigned int defaultVal, std::map choices) -{ - if (auto param = mCustomParameters.find(paramName); param != mCustomParameters.end()) { - // if parameter was provided check which option was chosen - for (const auto& choice : choices) { - if (param->second == choice.second) { - ILOG(Debug, Support) << "setting \"" << paramName << "\" to: \"" << choice.second << "\"" << ENDM; - return choice.first; - } - } - // param value not allowed - use default but with warning - std::string allowedValues; - for (const auto& choice : choices) { - allowedValues += "\""; - allowedValues += choice.second; - allowedValues += "\", "; - } - ILOG(Warning, Support) << "Provided value (\"" << param->second << "\") for parameter \"" << paramName << "\" is not allowed. Allowed values are: " << allowedValues << " setting \"" << paramName << "\" to default value: \"" << choices[defaultVal] << "\"" << ENDM; - return defaultVal; - } else { - // param not provided - use default - ILOG(Debug, Support) << "Setting \"" << paramName << "\" to default value: \"" << choices[defaultVal] << "\"" << ENDM; - return defaultVal; - } -} - -int DigitQcTaskLaser::getNumericalParameter(std::string paramName, int defaultVal) -{ - if (auto param = mCustomParameters.find(paramName); param != mCustomParameters.end()) { - float val = stoi(param->second); - ILOG(Debug, Support) << "Setting \"" << paramName << "\" to: " << val << ENDM; - return val; - } else { - ILOG(Debug) << "Setting \"" << paramName << "\" to default value: " << defaultVal << ENDM; - return defaultVal; - } -} - -void DigitQcTaskLaser::initialize(o2::framework::InitContext& /*ctx*/) -{ - ILOG(Debug, Devel) << "initialize DigitQcTaskLaser" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. - mStateLastIR2Ch = {}; - mMapChTrgNames.insert({ o2::ft0::ChannelData::kNumberADC, "NumberADC" }); - mMapChTrgNames.insert({ o2::ft0::ChannelData::kIsDoubleEvent, "IsDoubleEvent" }); - mMapChTrgNames.insert({ o2::ft0::ChannelData::kIsTimeInfoNOTvalid, "IsTimeInfoNOTvalid" }); - mMapChTrgNames.insert({ o2::ft0::ChannelData::kIsCFDinADCgate, "IsCFDinADCgate" }); - mMapChTrgNames.insert({ o2::ft0::ChannelData::kIsTimeInfoLate, "IsTimeInfoLate" }); - mMapChTrgNames.insert({ o2::ft0::ChannelData::kIsAmpHigh, "IsAmpHigh" }); - mMapChTrgNames.insert({ o2::ft0::ChannelData::kIsEventInTVDC, "IsEventInTVDC" }); - mMapChTrgNames.insert({ o2::ft0::ChannelData::kIsTimeInfoLost, "IsTimeInfoLost" }); - - mMapDigitTrgNames.insert({ o2::fit::Triggers::bitA, "OrA" }); - mMapDigitTrgNames.insert({ o2::fit::Triggers::bitC, "OrC" }); - mMapDigitTrgNames.insert({ o2::fit::Triggers::bitVertex, "Vertex" }); - mMapDigitTrgNames.insert({ o2::fit::Triggers::bitCen, "Central" }); - mMapDigitTrgNames.insert({ o2::fit::Triggers::bitSCen, "SemiCentral" }); - mMapDigitTrgNames.insert({ o2::fit::Triggers::bitLaser, "Laser" }); - mMapDigitTrgNames.insert({ o2::fit::Triggers::bitOutputsAreBlocked, "OutputsAreBlocked" }); - mMapDigitTrgNames.insert({ o2::fit::Triggers::bitDataIsValid, "DataIsValid" }); - - mTrgModeThresholdVar = getModeParameter("trgModeThresholdVar", - TrgModeThresholdVar::kAmpl, - { { TrgModeThresholdVar::kAmpl, "Ampl" }, - { TrgModeThresholdVar::kNchannels, "Nchannels" } }); - mTrgModeSide = getModeParameter("trgModeSide", - TrgModeSide::kAplusC, - { { TrgModeSide::kAplusC, "A+C" }, - { TrgModeSide::kAandC, "A&C" }, - { TrgModeSide::kA, "A" }, - { TrgModeSide::kC, "C" } }); - mTrgThresholdTimeLow = getNumericalParameter("trgThresholdTimeLow", -192); - mTrgThresholdTimeHigh = getNumericalParameter("trgThresholdTimeHigh", 192); - if (mTrgModeSide == TrgModeSide::kAplusC) { - mTrgThresholdSCenSum = getNumericalParameter("trgThresholdSCenSum", 300); - mTrgThresholdCenSum = getNumericalParameter("trgThresholdCenSum", 600); - } else if (mTrgModeSide == TrgModeSide::kAandC) { - mTrgThresholdCenA = getNumericalParameter("trgThresholdCenA", 600); - mTrgThresholdCenC = getNumericalParameter("trgThresholdCenC", 600); - mTrgThresholdSCenA = getNumericalParameter("trgThresholdSCenA", 300); - mTrgThresholdSCenC = getNumericalParameter("trgThresholdSCenC", 300); - } else if (mTrgModeSide == TrgModeSide::kA) { - mTrgThresholdCenA = getNumericalParameter("trgThresholdCenA", 600); - mTrgThresholdSCenA = getNumericalParameter("trgThresholdSCenA", 300); - } else if (mTrgModeSide == TrgModeSide::kC) { - mTrgThresholdCenC = getNumericalParameter("trgThresholdCenC", 600); - mTrgThresholdSCenC = getNumericalParameter("trgThresholdSCenC", 300); - } - - 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;Channel;Amp", sNCHANNELS_PM, 0, sNCHANNELS_PM, 4200, -100, 4100); - mHistAmp2Ch->SetOption("colz"); - mHistBC = std::make_unique("BC", "BC;BC;counts;", sBCperOrbit, 0, sBCperOrbit); - mHistChDataBits = std::make_unique("ChannelDataBits", "ChannelData bits per ChannelID;Channel;Bit", sNCHANNELS_PM, 0, sNCHANNELS_PM, mMapChTrgNames.size(), 0, mMapChTrgNames.size()); - mHistChDataBits->SetOption("colz"); - for (const auto& entry : mMapChTrgNames) { - mHistChDataBits->GetYaxis()->SetBinLabel(entry.first + 1, entry.second.c_str()); - } - mHistOrbitVsTrg = std::make_unique("OrbitVsTriggers", "Orbit vs Triggers;Orbit;Trg", sOrbitsPerTF, 0, sOrbitsPerTF, mMapDigitTrgNames.size(), 0, mMapDigitTrgNames.size()); - mHistOrbitVsTrg->SetOption("colz"); - mHistTriggersSw = std::make_unique("TriggersSoftware", "Triggers from software", mMapDigitTrgNames.size(), 0, mMapDigitTrgNames.size()); - mHistTriggersSoftwareVsTCM = std::make_unique("TriggersSoftwareVsTCM", "Comparison of triggers from software and TCM;;Trigger name", mMapDigitTrgNames.size(), 0, mMapDigitTrgNames.size(), 4, 0, 4); - mHistTriggersSoftwareVsTCM->SetOption("colz"); - mHistTriggersSoftwareVsTCM->SetStats(0); - for (const auto& entry : mMapDigitTrgNames) { - mHistOrbitVsTrg->GetYaxis()->SetBinLabel(entry.first + 1, entry.second.c_str()); - mHistTriggersSw->GetXaxis()->SetBinLabel(entry.first + 1, entry.second.c_str()); - mHistTriggersSoftwareVsTCM->GetXaxis()->SetBinLabel(entry.first + 1, entry.second.c_str()); - } - mHistTriggersSw->GetXaxis()->SetRange(1, 5); - mHistTriggersSoftwareVsTCM->GetXaxis()->SetRange(1, 5); - mHistTriggersSoftwareVsTCM->GetYaxis()->SetBinLabel(TrgComparisonResult::kSWonly + 1, "Sw only"); - mHistTriggersSoftwareVsTCM->GetYaxis()->SetBinLabel(TrgComparisonResult::kTCMonly + 1, "TCM only"); - mHistTriggersSoftwareVsTCM->GetYaxis()->SetBinLabel(TrgComparisonResult::kNone + 1, "neither TCM nor Sw"); - mHistTriggersSoftwareVsTCM->GetYaxis()->SetBinLabel(TrgComparisonResult::kBoth + 1, "both TCM and Sw"); - - mListHistGarbage = new TList(); - mListHistGarbage->SetOwner(kTRUE); - - std::map mapFEE2hash; - const auto& lut = o2::ft0::SingleLUT::Instance().getVecMetadataFEE(); - auto lutSorted = lut; - std::sort(lutSorted.begin(), lutSorted.end(), [](const auto& first, const auto& second) { return first.mModuleName < second.mModuleName; }); - uint8_t binPos{ 0 }; - for (const auto& lutEntry : lutSorted) { - const auto& moduleName = lutEntry.mModuleName; - const auto& moduleType = lutEntry.mModuleType; - const auto& strChID = lutEntry.mChannelID; - const auto& pairIt = mapFEE2hash.insert({ moduleName, binPos }); - if (pairIt.second) { - binPos++; - } - if (std::regex_match(strChID, std::regex("[[\\d]{1,3}"))) { - int chID = std::stoi(strChID); - if (chID < sNCHANNELS_PM) { - mChID2PMhash[chID] = mapFEE2hash[moduleName]; - } else { - LOG(error) << "Incorrect LUT entry: chID " << strChID << " | " << moduleName; - } - } else if (moduleType != "TCM") { - LOG(error) << "Non-TCM module w/o numerical chID: chID " << strChID << " | " << moduleName; - } else if (moduleType == "TCM") { - mTCMhash = mapFEE2hash[moduleName]; - } - } - mHistBCvsFEEmodules = std::make_unique("BCvsFEEmodules", "BC vs FEE module;BC;FEE", sBCperOrbit, 0, sBCperOrbit, mapFEE2hash.size(), 0, mapFEE2hash.size()); - mHistOrbitVsFEEmodules = std::make_unique("OrbitVsFEEmodules", "Orbit vs FEE module;Orbit;FEE", sOrbitsPerTF, 0, sOrbitsPerTF, mapFEE2hash.size(), 0, mapFEE2hash.size()); - for (const auto& entry : mapFEE2hash) { - mHistBCvsFEEmodules->GetYaxis()->SetBinLabel(entry.second + 1, entry.first.c_str()); - mHistOrbitVsFEEmodules->GetYaxis()->SetBinLabel(entry.second + 1, entry.first.c_str()); - } - - mHistTimeSum2Diff = std::make_unique("timeSumVsDiff", "time A/C side: sum VS diff;(TOC-TOA)/2 [ns];(TOA+TOC)/2 [ns]", 2000, -52.08, 52.08, 2000, -52.08, 52.08); // range of 52.08 ns = 4000*13.02ps = 4000 channels - mHistTimeSum2Diff->GetXaxis()->SetRangeUser(-5, 5); - mHistTimeSum2Diff->GetYaxis()->SetRangeUser(-5, 5); - 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); - - std::vector vecChannelIDs; - if (auto param = mCustomParameters.find("ChannelIDs"); param != mCustomParameters.end()) { - const auto chIDs = param->second; - const std::string del = ","; - vecChannelIDs = parseParameters(chIDs, del); - } - for (const auto& entry : vecChannelIDs) { - mSetAllowedChIDs.insert(entry); - } - std::vector vecChannelIDsAmpVsTime; - if (auto param = mCustomParameters.find("ChannelIDsAmpVsTime"); param != mCustomParameters.end()) { - const auto chIDs = param->second; - const std::string del = ","; - vecChannelIDsAmpVsTime = parseParameters(chIDs, del); - } - for (const auto& entry : vecChannelIDsAmpVsTime) { - mSetAllowedChIDsAmpVsTime.insert(entry); - } - - for (const auto& chID : mSetAllowedChIDs) { - auto pairHistAmp = mMapHistAmp1D.insert({ chID, new TH1F(Form("Amp_channel%i", chID), Form("Amplitude, channel %i", chID), 4200, -100, 4100) }); - auto pairHistTime = mMapHistTime1D.insert({ chID, new TH1F(Form("Time_channel%i", chID), Form("Time, channel %i", chID), 4100, -2050, 2050) }); - auto pairHistBits = mMapHistPMbits.insert({ chID, new TH1F(Form("Bits_channel%i", chID), Form("Bits, channel %i", chID), mMapChTrgNames.size(), 0, mMapChTrgNames.size()) }); - for (const auto& entry : mMapChTrgNames) { - pairHistBits.first->second->GetXaxis()->SetBinLabel(entry.first + 1, entry.second.c_str()); - } - if (pairHistAmp.second) { - getObjectsManager()->startPublishing(pairHistAmp.first->second); - mListHistGarbage->Add(pairHistAmp.first->second); - } - if (pairHistTime.second) { - mListHistGarbage->Add(pairHistTime.first->second); - getObjectsManager()->startPublishing(pairHistTime.first->second); - } - if (pairHistBits.second) { - mListHistGarbage->Add(pairHistBits.first->second); - getObjectsManager()->startPublishing(pairHistBits.first->second); - } - } - for (const auto& chID : mSetAllowedChIDsAmpVsTime) { - auto pairHistAmpVsTime = mMapHistAmpVsTime.insert({ chID, new TH2F(Form("Amp_vs_time_channel%i", chID), Form("Amplitude vs time, channel %i;Amp;Time", chID), 420, -100, 4100, 410, -2050, 2050) }); - if (pairHistAmpVsTime.second) { - mListHistGarbage->Add(pairHistAmpVsTime.first->second); - getObjectsManager()->startPublishing(pairHistAmpVsTime.first->second); - } - } - - rebinFromConfig(); // after all histos are created - // 1-dim hists - getObjectsManager()->startPublishing(mHistCFDEff.get()); - getObjectsManager()->startPublishing(mHistBC.get()); - getObjectsManager()->startPublishing(mHistTriggersSw.get()); - // 2-dim hists - getObjectsManager()->startPublishing(mHistTime2Ch.get()); - getObjectsManager()->setDefaultDrawOptions(mHistTime2Ch.get(), "COLZ"); - getObjectsManager()->startPublishing(mHistAmp2Ch.get()); - getObjectsManager()->setDefaultDrawOptions(mHistAmp2Ch.get(), "COLZ"); - getObjectsManager()->startPublishing(mHistBCvsFEEmodules.get()); - getObjectsManager()->setDefaultDrawOptions(mHistBCvsFEEmodules.get(), "COLZ"); - getObjectsManager()->startPublishing(mHistOrbitVsTrg.get()); - getObjectsManager()->setDefaultDrawOptions(mHistOrbitVsTrg.get(), "COLZ"); - getObjectsManager()->startPublishing(mHistOrbitVsFEEmodules.get()); - getObjectsManager()->setDefaultDrawOptions(mHistOrbitVsFEEmodules.get(), "COLZ"); - getObjectsManager()->startPublishing(mHistChDataBits.get()); - getObjectsManager()->setDefaultDrawOptions(mHistChDataBits.get(), "COLZ"); - getObjectsManager()->startPublishing(mHistTimeSum2Diff.get()); - getObjectsManager()->setDefaultDrawOptions(mHistTimeSum2Diff.get(), "COLZ"); - getObjectsManager()->startPublishing(mHistTriggersSoftwareVsTCM.get()); - getObjectsManager()->setDefaultDrawOptions(mHistTriggersSoftwareVsTCM.get(), "COLZ"); - - for (int i = 0; i < getObjectsManager()->getNumberPublishedObjects(); i++) { - TH1* obj = dynamic_cast(getObjectsManager()->getMonitorObject(i)->getObject()); - obj->SetTitle((string("FT0 Laser ") + obj->GetTitle()).c_str()); - } -} - -void DigitQcTaskLaser::startOfActivity(const Activity& activity) -{ - ILOG(Debug, Devel) << "startOfActivity" << activity.mId << ENDM; - mHistTime2Ch->Reset(); - mHistAmp2Ch->Reset(); - mHistBC->Reset(); - mHistChDataBits->Reset(); - mHistCFDEff->Reset(); - mHistNumADC->Reset(); - mHistNumCFD->Reset(); - mHistTimeSum2Diff->Reset(); - mHistBCvsFEEmodules->Reset(); - mHistOrbitVsTrg->Reset(); - mHistOrbitVsFEEmodules->Reset(); - mHistTriggersSw->Reset(); - mHistTriggersSoftwareVsTCM->Reset(); - for (auto& entry : mMapHistAmp1D) { - entry.second->Reset(); - } - for (auto& entry : mMapHistTime1D) { - entry.second->Reset(); - } - for (auto& entry : mMapHistPMbits) { - entry.second->Reset(); - } - for (auto& entry : mMapHistAmpVsTime) { - entry.second->Reset(); - } -} - -void DigitQcTaskLaser::startOfCycle() -{ - ILOG(Debug, Devel) << "startOfCycle" << ENDM; -} - -void DigitQcTaskLaser::monitorData(o2::framework::ProcessingContext& ctx) -{ - auto channels = ctx.inputs().get>("channels"); - auto digits = ctx.inputs().get>("digits"); - for (auto& digit : digits) { - // Exclude all BCs, in which laser signals are NOT expected (and trigger outputs are NOT blocked) - if (!digit.mTriggers.getOutputsAreBlocked()) { - continue; - } - const auto& vecChData = digit.getBunchChannelData(channels); - bool isTCM = true; - if (digit.mTriggers.getTimeA() == o2::fit::Triggers::DEFAULT_TIME && digit.mTriggers.getTimeC() == o2::fit::Triggers::DEFAULT_TIME) { - isTCM = false; - } - mHistBC->Fill(digit.getBC()); - if (isTCM && digit.mTriggers.getDataIsValid() && digit.mTriggers.getOutputsAreBlocked()) { - mHistTimeSum2Diff->Fill((digit.mTriggers.getTimeC() - digit.mTriggers.getTimeA()) * sCFDChannel2NS / 2, (digit.mTriggers.getTimeC() + digit.mTriggers.getTimeA()) * sCFDChannel2NS / 2); - for (const auto& binPos : mHashedBitBinPos[digit.mTriggers.getTriggersignals()]) { - mHistOrbitVsTrg->Fill(digit.getIntRecord().orbit % sOrbitsPerTF, binPos); - } - } - std::set setFEEmodules{}; - - // reset triggers - for (auto& entry : mMapTrgSoftware) { - mMapTrgSoftware[entry.first] = false; - } - float sumAmplA = 0; - float sumAmplC = 0; - int sumTimeA = 0; - int sumTimeC = 0; - int nFiredChannelsA = 0; - int nFiredChannelsC = 0; - for (const auto& chData : vecChData) { - mHistTime2Ch->Fill(static_cast(chData.ChId), static_cast(chData.CFDTime)); - mHistAmp2Ch->Fill(static_cast(chData.ChId), static_cast(chData.QTCAmpl)); - mStateLastIR2Ch[chData.ChId] = digit.mIntRecord; - if (chData.QTCAmpl > 0) { - mHistNumADC->Fill(chData.ChId); - } - mHistNumCFD->Fill(chData.ChId); - if (mSetAllowedChIDs.size() != 0 && mSetAllowedChIDs.find(static_cast(chData.ChId)) != mSetAllowedChIDs.end()) { - mMapHistAmp1D[chData.ChId]->Fill(chData.QTCAmpl); - mMapHistTime1D[chData.ChId]->Fill(chData.CFDTime); - for (const auto& entry : mMapChTrgNames) { - if ((chData.ChainQTC & (1 << entry.first))) { - mMapHistPMbits[chData.ChId]->Fill(entry.first); - } - } - } - if (mSetAllowedChIDsAmpVsTime.size() != 0 && mSetAllowedChIDsAmpVsTime.find(static_cast(chData.ChId)) != mSetAllowedChIDsAmpVsTime.end()) { - mMapHistAmpVsTime[chData.ChId]->Fill(chData.QTCAmpl, chData.CFDTime); - } - for (const auto& binPos : mHashedBitBinPos[chData.ChainQTC]) { - mHistChDataBits->Fill(chData.ChId, binPos); - } - - setFEEmodules.insert(mChID2PMhash[chData.ChId]); - - if (chData.ChId < sNCHANNELS_A) { - sumAmplA += chData.QTCAmpl; - sumTimeA += chData.CFDTime; - nFiredChannelsA++; - } else if (chData.ChId < sNCHANNELS_A + sNCHANNELS_C) { - sumAmplC += chData.QTCAmpl; - sumTimeC += chData.CFDTime; - nFiredChannelsC++; - } - } - if (isTCM) { - setFEEmodules.insert(mTCMhash); - } - for (const auto& feeHash : setFEEmodules) { - mHistBCvsFEEmodules->Fill(static_cast(digit.getIntRecord().bc), static_cast(feeHash)); - mHistOrbitVsFEEmodules->Fill(static_cast(digit.getIntRecord().orbit % sOrbitsPerTF), static_cast(feeHash)); - } - - // triggers re-computation - mMapTrgSoftware[o2::ft0::Triggers::bitA] = nFiredChannelsA > 0; - mMapTrgSoftware[o2::ft0::Triggers::bitC] = nFiredChannelsC > 0; - - int avgTimeA = nFiredChannelsA ? int(sumTimeA / nFiredChannelsA) : 0; - int avgTimeC = nFiredChannelsC ? int(sumTimeC / nFiredChannelsC) : 0; - int vtxPos = (nFiredChannelsA && nFiredChannelsC) ? (avgTimeC - avgTimeA) / 2 : 0; - if (mTrgThresholdTimeLow < vtxPos && vtxPos < mTrgThresholdTimeHigh && nFiredChannelsA && nFiredChannelsC) - mMapTrgSoftware[o2::ft0::Triggers::bitVertex] = true; - - // Central/SemiCentral logic - switch (mTrgModeSide) { - case TrgModeSide::kAplusC: - if (mTrgModeThresholdVar == TrgModeThresholdVar::kAmpl) { - if (sumAmplA + sumAmplC >= mTrgThresholdCenSum) - mMapTrgSoftware[o2::ft0::Triggers::bitCen] = true; - if (sumAmplA + sumAmplC >= mTrgThresholdSCenSum) - mMapTrgSoftware[o2::ft0::Triggers::bitSCen] = true; - } else if (mTrgModeThresholdVar == TrgModeThresholdVar::kNchannels) { - if (nFiredChannelsA + nFiredChannelsC >= mTrgThresholdCenSum) - mMapTrgSoftware[o2::ft0::Triggers::bitCen] = true; - if (nFiredChannelsA + nFiredChannelsC >= mTrgThresholdSCenSum) - mMapTrgSoftware[o2::ft0::Triggers::bitSCen] = true; - } - break; - - case TrgModeSide::kAandC: - if (mTrgModeThresholdVar == TrgModeThresholdVar::kAmpl) { - if (sumAmplA >= mTrgThresholdCenA && sumAmplC >= mTrgThresholdCenC) - mMapTrgSoftware[o2::ft0::Triggers::bitCen] = true; - if (sumAmplA >= mTrgThresholdSCenA && sumAmplC >= mTrgThresholdSCenC) - mMapTrgSoftware[o2::ft0::Triggers::bitSCen] = true; - } else if (mTrgModeThresholdVar == TrgModeThresholdVar::kNchannels) { - if (nFiredChannelsA >= mTrgThresholdCenA && nFiredChannelsC >= mTrgThresholdCenC) - mMapTrgSoftware[o2::ft0::Triggers::bitCen] = true; - if (nFiredChannelsA >= mTrgThresholdSCenA && nFiredChannelsC >= mTrgThresholdSCenC) - mMapTrgSoftware[o2::ft0::Triggers::bitSCen] = true; - } - break; - - case TrgModeSide::kA: - if (mTrgModeThresholdVar == TrgModeThresholdVar::kAmpl) { - if (sumAmplA >= mTrgThresholdCenA) - mMapTrgSoftware[o2::ft0::Triggers::bitCen] = true; - if (sumAmplA >= mTrgThresholdSCenA) - mMapTrgSoftware[o2::ft0::Triggers::bitSCen] = true; - } else if (mTrgModeThresholdVar == TrgModeThresholdVar::kNchannels) { - if (nFiredChannelsA >= mTrgThresholdCenA) - mMapTrgSoftware[o2::ft0::Triggers::bitCen] = true; - if (nFiredChannelsA >= mTrgThresholdSCenA) - mMapTrgSoftware[o2::ft0::Triggers::bitSCen] = true; - } - break; - - case TrgModeSide::kC: - if (mTrgModeThresholdVar == TrgModeThresholdVar::kAmpl) { - if (sumAmplC >= mTrgThresholdCenC) - mMapTrgSoftware[o2::ft0::Triggers::bitCen] = true; - if (sumAmplC >= mTrgThresholdSCenC) - mMapTrgSoftware[o2::ft0::Triggers::bitSCen] = true; - } else if (mTrgModeThresholdVar == TrgModeThresholdVar::kNchannels) { - if (nFiredChannelsC >= mTrgThresholdCenC) - mMapTrgSoftware[o2::ft0::Triggers::bitCen] = true; - if (nFiredChannelsC >= mTrgThresholdSCenC) - mMapTrgSoftware[o2::ft0::Triggers::bitSCen] = true; - } - break; - } - - for (const auto& entry : mMapTrgSoftware) { - if (entry.second) - mHistTriggersSw->Fill(entry.first); - bool isTCMFired = digit.mTriggers.getTriggersignals() & (1 << entry.first); - bool isSwFired = entry.second; - if (!isTCMFired && isSwFired) - mHistTriggersSoftwareVsTCM->Fill(entry.first, TrgComparisonResult::kSWonly); - else if (isTCMFired && !isSwFired) - mHistTriggersSoftwareVsTCM->Fill(entry.first, TrgComparisonResult::kTCMonly); - else if (!isTCMFired && !isSwFired) - mHistTriggersSoftwareVsTCM->Fill(entry.first, TrgComparisonResult::kNone); - else if (isTCMFired && isSwFired) - mHistTriggersSoftwareVsTCM->Fill(entry.first, TrgComparisonResult::kBoth); - - if (isTCMFired != isSwFired) { - // (*) = triggers.amplA/C are sums of amplitudes **divided by 8** - auto msg = Form( - "Software does not reproduce TCM decision! \n \ - trigger name: %s\n \ - TCM / SW: \n \ - hasFired = %d / %d \n \ - nChannelsA = %d / %d \n \ - nChannelsC = %d / %d \n \ - sumAmplA = %d / %d (*) \n \ - sumAmplC = %d / %d (*) \n \ - timeA = %d / %d \n \ - timeC = %d / %d \n \ - vertexPos = -- / %d", - mMapDigitTrgNames[entry.first].c_str(), - isTCMFired, isSwFired, - digit.mTriggers.getNChanA(), nFiredChannelsA, - digit.mTriggers.getNChanC(), nFiredChannelsC, - digit.mTriggers.getAmplA(), int(sumAmplA / 8), - digit.mTriggers.getAmplC(), int(sumAmplC / 8), - digit.mTriggers.getTimeA(), avgTimeA, - digit.mTriggers.getTimeC(), avgTimeC, vtxPos); - ILOG(Debug, Support) << msg << ENDM; - } - } - // end of triggers re-computation - } -} - -void DigitQcTaskLaser::endOfCycle() -{ - ILOG(Debug, Devel) << "endOfCycle" << ENDM; - // one has to set num. of entries manually because - // default TH1Reductor gets only mean,stddev and entries (no integral) - mHistCFDEff->Divide(mHistNumADC.get(), mHistNumCFD.get()); -} - -void DigitQcTaskLaser::endOfActivity(const Activity& /*activity*/) -{ - ILOG(Debug, Devel) << "endOfActivity" << ENDM; -} - -void DigitQcTaskLaser::reset() -{ - // clean all the monitor objects here - mHistTime2Ch->Reset(); - mHistAmp2Ch->Reset(); - mHistBC->Reset(); - mHistChDataBits->Reset(); - mHistCFDEff->Reset(); - mHistNumADC->Reset(); - mHistNumCFD->Reset(); - mHistTimeSum2Diff->Reset(); - mHistBCvsFEEmodules->Reset(); - mHistOrbitVsTrg->Reset(); - mHistOrbitVsFEEmodules->Reset(); - mHistTriggersSw->Reset(); - mHistTriggersSoftwareVsTCM->Reset(); - for (auto& entry : mMapHistAmp1D) { - entry.second->Reset(); - } - for (auto& entry : mMapHistTime1D) { - entry.second->Reset(); - } - for (auto& entry : mMapHistPMbits) { - entry.second->Reset(); - } - for (auto& entry : mMapHistAmpVsTime) { - entry.second->Reset(); - } -} - -} // namespace o2::quality_control_modules::ft0 diff --git a/Modules/FIT/FT0/src/TH1ReductorLaser.cxx b/Modules/FIT/FT0/src/TH1ReductorLaser.cxx deleted file mode 100644 index 2af6fd3bd8..0000000000 --- a/Modules/FIT/FT0/src/TH1ReductorLaser.cxx +++ /dev/null @@ -1,93 +0,0 @@ -/// 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 TH1ReductorLaser.cxx -/// \author Piotr Konopka, developed to laser QC by Sandor Lokos -/// (sandor.lokos@cern.ch) -/// - -#include "FT0/TH1ReductorLaser.h" -#include "QualityControl/QcInfoLogger.h" -#include -#include -#include - -namespace o2::quality_control_modules::ft0 -{ -void* TH1ReductorLaser::getBranchAddress() { return &mStats; } -const char* TH1ReductorLaser::getBranchLeafList() -{ - return Form("validity1/D:validity2/D:mean1/D:mean2/D:mean[%i]/D:stddev1:stddev2:stddev[%i]", NChannel, NChannel); -} - -void TH1ReductorLaser::update(TObject* obj) -{ - if (auto histo = dynamic_cast(obj)) { - int channel = -1; - sscanf(histo->GetName(), "%*[^0-9]%d", &channel); - if (channel < NChannel) { - for (int ichannel = 1; ichannel < NChannel; ichannel++) { - TH1* bc_projection = histo->ProjectionY(Form("first peak in BC #%d", ichannel), ichannel, ichannel + 1); - mStats.mean[ichannel] = bc_projection->GetMean(); - } - } else { - TH1* bc_projection = histo->ProjectionY("bc_projection", 0, -1); - int ibc = 0; - int ibc_max = 0; - if (bc_projection->GetEntries() > 0) { - ibc = bc_projection->GetMean() - 2. * bc_projection->GetStdDev(); - ibc_max = bc_projection->GetMean() + 2. * bc_projection->GetStdDev(); - } - - TH1* slice_first_peak; - bool gotFirstPeak = false; - mStats.mean1 = 0.; - mStats.stddev1 = 0.; - mStats.validity1 = 0.; - while (!gotFirstPeak && ibc < ibc_max) { - slice_first_peak = histo->ProjectionX(Form("first peak in BC #%d", ibc), ibc, ibc + 1); - if (slice_first_peak->GetEntries() > 1000) { - mStats.mean1 = slice_first_peak->GetMean(); - mStats.stddev1 = slice_first_peak->GetStdDev(); - mStats.validity1 = 1.; - gotFirstPeak = true; - ibc += 2; - break; - } else - ibc++; - } - - TH1* slice_second_peak; - bool gotSecondPeak = false; - mStats.mean2 = 0.; - mStats.stddev2 = 0.; - mStats.validity2 = 0.; - while (!gotSecondPeak && gotFirstPeak && ibc < ibc_max) { - slice_second_peak = histo->ProjectionX(Form("second peak in BC #%d", ibc), ibc, ibc + 1); - if (slice_second_peak->GetEntries() > 1000) { - mStats.mean2 = slice_second_peak->GetMean(); - mStats.stddev2 = slice_second_peak->GetStdDev(); - mStats.validity2 = 1.; - gotSecondPeak = true; - break; - } else - ibc++; - } - - if (!gotSecondPeak) - ILOG(Warning) << "TH1ReductorLaser: one of the peaks of the reference PMT is missing!" << ENDM; - if (!gotFirstPeak && !gotSecondPeak) - ILOG(Warning) << "TH1ReductorLaser: cannot find peaks of the reference PMT distribution at all !" << ENDM; - } - } -} -} // namespace o2::quality_control_modules::ft0