From 272bdd8bab36666caf26d18cf7b2a228c2a62b1b Mon Sep 17 00:00:00 2001 From: sevdokim Date: Fri, 26 Mar 2021 13:14:11 +0100 Subject: [PATCH 1/4] Add CPV Pedestal Task --- Modules/CMakeLists.txt | 1 + Modules/CPV/CMakeLists.txt | 42 ++ Modules/CPV/etc/read-raw-from-file/CPVraw.cfg | 10 + .../pedestal-task-no-sampling.json | 49 +++ Modules/CPV/etc/read-raw-from-file/readme | 10 + Modules/CPV/include/CPV/LinkDef.h | 7 + Modules/CPV/include/CPV/PedestalTask.h | 115 ++++++ Modules/CPV/src/PedestalTask.cxx | 386 ++++++++++++++++++ Modules/CPV/test/testQcCPV.cxx | 29 ++ 9 files changed, 649 insertions(+) create mode 100644 Modules/CPV/CMakeLists.txt create mode 100644 Modules/CPV/etc/read-raw-from-file/CPVraw.cfg create mode 100644 Modules/CPV/etc/read-raw-from-file/pedestal-task-no-sampling.json create mode 100644 Modules/CPV/etc/read-raw-from-file/readme create mode 100644 Modules/CPV/include/CPV/LinkDef.h create mode 100644 Modules/CPV/include/CPV/PedestalTask.h create mode 100644 Modules/CPV/src/PedestalTask.cxx create mode 100644 Modules/CPV/test/testQcCPV.cxx diff --git a/Modules/CMakeLists.txt b/Modules/CMakeLists.txt index ad81dc3df4..12013d76de 100644 --- a/Modules/CMakeLists.txt +++ b/Modules/CMakeLists.txt @@ -16,3 +16,4 @@ add_subdirectory(FT0) add_subdirectory(MID) add_subdirectory(TRD) add_subdirectory(HMPID) +add_subdirectory(CPV) diff --git a/Modules/CPV/CMakeLists.txt b/Modules/CPV/CMakeLists.txt new file mode 100644 index 0000000000..aab0a66e07 --- /dev/null +++ b/Modules/CPV/CMakeLists.txt @@ -0,0 +1,42 @@ +# ---- Library ---- + +add_library(QcCPV) + +target_sources(QcCPV PRIVATE src/PedestalTask.cxx ) + +target_include_directories( + QcCPV + PUBLIC $ + $ + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) + +target_link_libraries(QcCPV PUBLIC QualityControl O2::CPVBase) + +install(TARGETS QcCPV + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + +add_root_dictionary(QcCPV + HEADERS + include/CPV/PedestalTask.h + LINKDEF include/CPV/LinkDef.h + BASENAME QcCPV) + +# ---- Test(s) ---- + +set(TEST_SRCS test/testQcCPV.cxx) + +foreach(test ${TEST_SRCS}) + get_filename_component(test_name ${test} NAME) + string(REGEX REPLACE ".cxx" "" test_name ${test_name}) + + add_executable(${test_name} ${test}) + target_link_libraries(${test_name} + PRIVATE QcCPV Boost::unit_test_framework) + add_test(NAME ${test_name} COMMAND ${test_name}) + set_property(TARGET ${test_name} + PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests) + set_tests_properties(${test_name} PROPERTIES TIMEOUT 20) +endforeach() + diff --git a/Modules/CPV/etc/read-raw-from-file/CPVraw.cfg b/Modules/CPV/etc/read-raw-from-file/CPVraw.cfg new file mode 100644 index 0000000000..e4fc05678d --- /dev/null +++ b/Modules/CPV/etc/read-raw-from-file/CPVraw.cfg @@ -0,0 +1,10 @@ +#[defaults] +#dataOrigin = CPV +#dataDescription = RAWDATA +#readoutCard = RORC + +[input-CPV-0] +dataOrigin = CPV +dataDescription = RAWDATA +readoutCard = CRU +filePath = /data/cpv-raw-data/data_p2_21_012.raw diff --git a/Modules/CPV/etc/read-raw-from-file/pedestal-task-no-sampling.json b/Modules/CPV/etc/read-raw-from-file/pedestal-task-no-sampling.json new file mode 100644 index 0000000000..72b40e65fd --- /dev/null +++ b/Modules/CPV/etc/read-raw-from-file/pedestal-task-no-sampling.json @@ -0,0 +1,49 @@ +{ + "qc": { + "config": { + "database": { + "implementation": "CCDB", + "host": "ccdb-test.cern.ch:8080", + "username": "not_applicable", + "password": "not_applicable", + "name": "not_applicable" + }, + "Activity": { + "number": "42", + "type": "2" + }, + "monitoring": { + "url": "infologger:///debug?qc" + }, + "consul": { + "url": "http://consul-test.cern.ch:8500" + }, + "conditionDB": { + "url": "ccdb-test.cern.ch:8080" + } + }, + "tasks": { + "PedestalTask": { + "active": "true", + "className": "o2::quality_control_modules::cpv::PedestalTask", + "moduleName": "QcCPV", + "detectorName": "CPV", + "cycleDurationSeconds": "10", + "maxNumberCycles": "-1", + "": "The other type of dataSource is \"direct\", see basic-no-sampling.json.", + "dataSource": { + "type": "direct", + "query": "digits:CPV/DIGITS/0;dtrigrec:CPV/DIGITTRIGREC/0" + }, + "taskParameters": { + "cutOnMinAmplitude": "0" + }, + "location": "remote", + "saveObjectsToFile": "MOs.root", "": "For debugging, path to the file where to save. If empty or missing it won't save." + } + } + }, + "dataSamplingPolicies": [ + + ] +} diff --git a/Modules/CPV/etc/read-raw-from-file/readme b/Modules/CPV/etc/read-raw-from-file/readme new file mode 100644 index 0000000000..a01d78f219 --- /dev/null +++ b/Modules/CPV/etc/read-raw-from-file/readme @@ -0,0 +1,10 @@ +0) alienv enter qcg/latest + +1) start raw file reader with command + o2-raw-file-reader-workflow --input-conf CPVraw.cfg + +2) raw data stream is produced by previous command. Try to connect to it with raw to digit converter: + o2-raw-file-reader-workflow --input-conf CPVraw.cfg | o2-cpv-reco-workflow --input-type raw --output-type digits --disable-mc --pedestal=on --disable-root-output + +3) connect qc: + o2-raw-file-reader-workflow --input-conf CPVraw.cfg | o2-cpv-reco-workflow --input-type raw --output-type digits --disable-mc --pedestal=on --disable-root-output | o2-qc --config json://pedestal-task-no-sampling.json diff --git a/Modules/CPV/include/CPV/LinkDef.h b/Modules/CPV/include/CPV/LinkDef.h new file mode 100644 index 0000000000..8972927bab --- /dev/null +++ b/Modules/CPV/include/CPV/LinkDef.h @@ -0,0 +1,7 @@ +#ifdef __CLING__ +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::quality_control_modules::cpv::PedestalTask+; +#endif diff --git a/Modules/CPV/include/CPV/PedestalTask.h b/Modules/CPV/include/CPV/PedestalTask.h new file mode 100644 index 0000000000..c8eba50ab7 --- /dev/null +++ b/Modules/CPV/include/CPV/PedestalTask.h @@ -0,0 +1,115 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 PedestalTask.h +/// \author Sergey Evdokimov +/// + +#ifndef QC_MODULE_CPV_CPVPEDESTALTASK_H +#define QC_MODULE_CPV_CPVPEDESTALTASK_H + +#include "QualityControl/TaskInterface.h" +#include +#include +#include "DataFormatsCPV/Digit.h" +#include "DataFormatsCPV/TriggerRecord.h" +#include +#include "CPVBase/Geometry.h" + + +class TH1F; +class TH2F; + +using namespace o2::quality_control::core; + +namespace o2::quality_control_modules::cpv +{ + +/// \brief CPV Pedestal Task which processes uncalibrated digits from pedestal runs and produces pedestal monitor objects +/// \author Sergey Evdokimov +class PedestalTask final : public TaskInterface +{ + public: + /// \brief Constructor + PedestalTask() = default; + /// Destructor + ~PedestalTask() override; + + // Definition of the methods for the template method pattern + void initialize(o2::framework::InitContext& ctx) override; + void startOfActivity(Activity& activity) override; + void startOfCycle() override; + void monitorData(o2::framework::ProcessingContext& ctx) override; + void endOfCycle() override; + void endOfActivity(Activity& activity) override; + void reset() override; + + private: + + void initHistograms(); + // void fillHistograms(const gsl::span& digits, const gsl::span& triggerRecords); + void fillHistograms(); + void resetHistograms(); + + + static constexpr short kNHist1D = 14; + enum Histos1D { H1DInputPayloadSize, + H1DNInputs, + H1DNValidInputs, + H1DNDigitsPerInput, + H1DDigitIds, + H1DPedestalValueM2, + H1DPedestalValueM3, + H1DPedestalValueM4, + H1DPedestalSigmaM2, + H1DPedestalSigmaM3, + H1DPedestalSigmaM4, + H1DPedestalEfficiencyM2, + H1DPedestalEfficiencyM3, + H1DPedestalEfficiencyM4 + }; + + static constexpr short kNHist2D = 16; + enum Histos2D { H2DErrorType, + H2DDigitMapM2, + H2DDigitMapM3, + H2DDigitMapM4, + H2DPedestalValueMapM2, + H2DPedestalValueMapM3, + H2DPedestalValueMapM4, + H2DPedestalSigmaMapM2, + H2DPedestalSigmaMapM3, + H2DPedestalSigmaMapM4, + H2DPedestalEfficiencyMapM2, + H2DPedestalEfficiencyMapM3, + H2DPedestalEfficiencyMapM4, + H2DPedestalNPeaksMapM2, + H2DPedestalNPeaksMapM3, + H2DPedestalNPeaksMapM4 + + }; + + static constexpr short kNModules = 3; + static constexpr short kNChannels = 23040; + o2::cpv::Geometry mCPVGeometry; + + int mNEvents; + + std::array mHist1D = { nullptr }; ///< Array of 1D histograms + std::array mHist2D = { nullptr }; ///< Array of 2D histograms + + std::array mHistAmplitudes = { nullptr }; ///< Array of amplitude spectra + +}; + +} // namespace o2::quality_control_modules::cpv + +#endif // QC_MODULE_CPV_CPVPEDESTALTASK_H diff --git a/Modules/CPV/src/PedestalTask.cxx b/Modules/CPV/src/PedestalTask.cxx new file mode 100644 index 0000000000..58ed14a9c4 --- /dev/null +++ b/Modules/CPV/src/PedestalTask.cxx @@ -0,0 +1,386 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 PedestalTask.cxx +/// \author Sergey Evdokimov +/// + +#include +#include +#include +#include +#include + + +#include "QualityControl/QcInfoLogger.h" +#include "CPV/PedestalTask.h" +#include +#include "DataFormatsCPV/TriggerRecord.h" + +namespace o2::quality_control_modules::cpv +{ + +PedestalTask::~PedestalTask() +{ + for (int i = kNHist1D; i--;) { + if (mHist1D[i]) { + mHist1D[i]->Delete(); + mHist1D[i] = nullptr; + } + } + for (int i = kNHist2D; i--;) { + if (mHist2D[i]) { + mHist2D[i]->Delete(); + mHist2D[i] = nullptr; + } + } + for (int i = 0; iDelete(); + mHistAmplitudes[i] = nullptr; + } + } +} + +void PedestalTask::initialize(o2::framework::InitContext& /*ctx*/) +{ + ILOG(Info, Support) << "initialize PedestalTask" << ENDM; // QcInfoLogger is used. FairMQ logs will go to there as well. + + // this is how to get access to custom parameters defined in the config file at qc.tasks..taskParameters + if (auto param = mCustomParameters.find("myOwnKey"); param != mCustomParameters.end()) { + ILOG(Info, Devel) << "Custom parameter - myOwnKey: " << param->second << ENDM; + } + initHistograms(); + mNEvents = 0; +} + +void PedestalTask::startOfActivity(Activity& activity) +{ + ILOG(Info, Support) << "startOfActivity" << activity.mId << ENDM; + resetHistograms(); +} + +void PedestalTask::startOfCycle() +{ + ILOG(Info, Support) << "startOfCycle" << ENDM; +} + +void PedestalTask::monitorData(o2::framework::ProcessingContext& ctx) +{ + // In this function you can access data inputs specified in the JSON config file, for example: + // "query": "random:ITS/RAWDATA/0" + // which is correspondingly ://Fill(nInputs); + + int nValidInputs = ctx.inputs().countValidInputs(); + mHist1D[H1DNValidInputs]->Fill(nValidInputs); + + for (auto&& input : ctx.inputs()) { + // get message header + if (input.header != nullptr && input.payload != nullptr) { + const auto* header = header::get(input.header); + // get payload of a specific input, which is a char array. + // const char* payload = input.payload; + + // for the sake of an example, let's fill the histogram with payload sizes + mHist1D[H1DInputPayloadSize]->Fill(header->payloadSize); + } + } + + // 2. Using get("") + auto digits = ctx.inputs().get>("digits"); + mHist1D[H1DNDigitsPerInput]->Fill(digits.size()); + for (const auto& digit : digits){ + mHist1D[H1DDigitIds]->Fill(digit.getAbsId()); + short relId[3]; + mCPVGeometry.absToRelNumbering(digit.getAbsId(),relId); + //reminder: relId[3]={Module, phi col, z row} where Module=2..4, phi col=0..127, z row=0..59 + mHist2D[H2DDigitMapM2 + relId[0] - 2]->Fill(relId[1], relId[2]); + mHistAmplitudes[digit.getAbsId()]->Fill(digit.getAmplitude()); + } + + auto digitsTR = ctx.inputs().get>("dtrigrec"); + //mNEvents += digitsTR.size();//number of events in the current input + for (const auto& trigRecord : digitsTR) { + ILOG(Info, Devel) << " monitorData() : trigger record #" << mNEvents + << " contains "< 0) mNEvents++;//at least 1 digit in this trigger record + } + + // get the payload of a specific input, which is a char array. "random" is the binding specified in the config file. + // auto payload = ctx.inputs().get("random").payload; + + // get payload of a specific input, which is a structure array: + // const auto* header = header::get(ctx.inputs().get("random").header); + // struct s {int a; double b;}; + // auto array = ctx.inputs().get("random"); + // for (int j = 0; j < header->payloadSize / sizeof(s); ++j) { + // int i = array.get()[j].a; + // } + + // get payload of a specific input, which is a root object + // auto h = ctx.inputs().get("histos"); + // Double_t stats[4]; + // h->GetStats(stats); + // auto s = ctx.inputs().get("string"); + // LOG(INFO) << "String is " << s->GetString().Data(); + + // 3. Access CCDB. If it is enough to retrieve it once, do it in initialize(). + // Remember to delete the object when the pointer goes out of scope or it is no longer needed. + // TObject* condition = TaskInterface::retrieveCondition("QcTask/example"); // put a valid condition path here + // if (condition) { + // LOG(INFO) << "Retrieved " << condition->ClassName(); + // delete condition; + // } +} + +void PedestalTask::endOfCycle() +{ + ILOG(Info, Support) << "endOfCycle. I call fillHistograms()" << ENDM; + fillHistograms(); +} + +void PedestalTask::endOfActivity(Activity& /*activity*/) +{ + ILOG(Info, Support) << "endOfActivity" << ENDM; +} + +void PedestalTask::reset() +{ + // clean all the monitor objects here + ILOG(Info, Support) << "Resetting PedestalTask" << ENDM; + resetHistograms(); + mNEvents = 0; +} + +void PedestalTask::initHistograms() +{ + //create monitoring histograms (or reset, if they already exists) + for (int i = 0; i < kNChannels; i++){ + if (!mHistAmplitudes[i]) { + mHistAmplitudes[i] = new TH1F(Form("HistAmplitude%d", i), Form("HistAmplitude%d", i), 4096, 0., 4096.); + if(i % 1000 == 0) getObjectsManager()->startPublishing(mHistAmplitudes[i]); + + } else { + mHistAmplitudes[i]->Reset(); + } + } + + + //1D Histos + if (!mHist1D[H1DInputPayloadSize]){ + mHist1D[H1DInputPayloadSize] = new TH1F("InputPayloadSize", "Input Payload Size", 30000, 0, 30000000); + getObjectsManager()->startPublishing(mHist1D[H1DInputPayloadSize]); + } else { + mHist1D[H1DInputPayloadSize]->Reset(); + } + + if (!mHist1D[H1DNInputs]){ + mHist1D[H1DNInputs] = new TH1F("NInputs", "Number of inputs", 10, -0.5, 9.5); + getObjectsManager()->startPublishing(mHist1D[H1DNInputs]); + } else { + mHist1D[H1DNInputs]->Reset(); + } + + if (!mHist1D[H1DNValidInputs]){ + mHist1D[H1DNValidInputs] = new TH1F("NValidInputs", "Number of valid inputs", 10, -0.5, 9.5); + getObjectsManager()->startPublishing(mHist1D[H1DNValidInputs]); + } else { + mHist1D[H1DNValidInputs]->Reset(); + } + + if (!mHist1D[H1DNDigitsPerInput]){ + mHist1D[H1DNDigitsPerInput] = new TH1F("NDigitsPerInput", "Number of digits per input", 30000, 0, 300000); + getObjectsManager()->startPublishing(mHist1D[H1DNDigitsPerInput]); + } else { + mHist1D[H1DNDigitsPerInput]->Reset(); + } + + if (!mHist1D[H1DDigitIds]){ + mHist1D[H1DDigitIds] = new TH1F("DigitIds", "Digit Ids", 30000, -0.5, 29999.5); + getObjectsManager()->startPublishing(mHist1D[H1DDigitIds]); + } else { + mHist1D[H1DDigitIds]->Reset(); + } + + for (int mod = 0; mod < kNModules; mod++){ + if (!mHist1D[H1DPedestalValueM2 + mod]){ + mHist1D[H1DPedestalValueM2 + mod] = new TH1F(Form("PedestalValueM%d", mod + 2), Form("Pedestal value distribution M%d", mod + 2), 512, 0, 512); + getObjectsManager()->startPublishing(mHist1D[H1DPedestalValueM2 + mod]); + } else { + mHist1D[H1DPedestalValueM2 + mod]->Reset(); + } + + if (!mHist1D[H1DPedestalSigmaM2 + mod]){ + mHist1D[H1DPedestalSigmaM2 + mod] = new TH1F(Form("PedestalSigmaM%d", mod + 2), Form("Pedestal sigma distribution M%d", mod + 2), 512, 0, 512); + getObjectsManager()->startPublishing(mHist1D[H1DPedestalSigmaM2 + mod]); + } else { + mHist1D[H1DPedestalSigmaM2 + mod]->Reset(); + } + + if (!mHist1D[H1DPedestalEfficiencyM2 + mod]){ + mHist1D[H1DPedestalEfficiencyM2 + mod] = new TH1F(Form("PedestalEfficiencyM%d", mod + 2), Form("Pedestal efficiency distribution M%d", mod + 2), 1000, 0., 10.); + getObjectsManager()->startPublishing(mHist1D[H1DPedestalEfficiencyM2 + mod]); + } else { + mHist1D[H1DPedestalEfficiencyM2 + mod]->Reset(); + } + } + + + + //2D Histos + if (!mHist2D[H2DErrorType]){ + mHist2D[H2DErrorType] = new TH2F("ErrorType", "ErrorType", 50, 0, 50, 5, 0, 5); + getObjectsManager()->startPublishing(mHist2D[H2DErrorType]); + } else { + mHist2D[H2DErrorType]->Reset(); + } + + //per-module histos + int nPadsX = mCPVGeometry.kNumberOfCPVPadsPhi; + int nPadsZ = mCPVGeometry.kNumberOfCPVPadsZ; + + for (int mod = 0; mod < kNModules; mod++){ + if (!mHist2D[H2DDigitMapM2 + mod]){ + mHist2D[H2DDigitMapM2 + mod] = new TH2F(Form("DigitMapM%d", 2 + mod), Form("Digit Map in M%d", mod + 2), nPadsX, -0.5, nPadsX - 0.5, nPadsZ, -0.5, nPadsZ - 0.5); + getObjectsManager()->startPublishing(mHist2D[H2DDigitMapM2 + mod]); + } else { + mHist2D[H2DDigitMapM2 + mod]->Reset(); + } + + if (!mHist2D[H2DPedestalValueMapM2 + mod]){ + mHist2D[H2DPedestalValueMapM2 + mod] = new TH2F(Form("PedestalValueMapM%d", 2 + mod), Form("PedestalValue Map in M%d", mod + 2), nPadsX, -0.5, nPadsX - 0.5, nPadsZ, -0.5, nPadsZ - 0.5); + getObjectsManager()->startPublishing(mHist2D[H2DPedestalValueMapM2 + mod]); + } else { + mHist2D[H2DPedestalValueMapM2 + mod]->Reset(); + } + + if (!mHist2D[H2DPedestalSigmaMapM2 + mod]){ + mHist2D[H2DPedestalSigmaMapM2 + mod] = new TH2F(Form("PedestalSigmaMapM%d", 2 + mod), Form("PedestalSigma Map in M%d", mod + 2), nPadsX, -0.5, nPadsX - 0.5, nPadsZ, -0.5, nPadsZ - 0.5); + getObjectsManager()->startPublishing(mHist2D[H2DPedestalSigmaMapM2 + mod]); + } else { + mHist2D[H2DPedestalSigmaMapM2 + mod]->Reset(); + } + + if (!mHist2D[H2DPedestalEfficiencyMapM2 + mod]){ + mHist2D[H2DPedestalEfficiencyMapM2 + mod] = new TH2F(Form("PedestalEfficiencyMapM%d", 2 + mod), Form("Pedestal Efficiency Map in M%d", mod + 2), nPadsX, -0.5, nPadsX - 0.5, nPadsZ, -0.5, nPadsZ - 0.5); + getObjectsManager()->startPublishing(mHist2D[H2DPedestalEfficiencyMapM2 + mod]); + } else { + mHist2D[H2DPedestalEfficiencyMapM2 + mod]->Reset(); + } + if (!mHist2D[H2DPedestalNPeaksMapM2 + mod]){ + mHist2D[H2DPedestalNPeaksMapM2 + mod] = new TH2F(Form("PedestalNPeaksMapM%d", 2 + mod), Form("Number of pedestal peaks Map in M%d", mod + 2), nPadsX, -0.5, nPadsX - 0.5, nPadsZ, -0.5, nPadsZ - 0.5); + getObjectsManager()->startPublishing(mHist2D[H2DPedestalNPeaksMapM2 + mod]); + } else { + mHist2D[H2DPedestalNPeaksMapM2 + mod]->Reset(); + } + + + } + + + +} + +void PedestalTask::fillHistograms() +{ + // count pedestals and update MOs + static float pedestalValue, pedestalSigma, pedestalEfficiency; + static short relId[3]; + TF1* functionGaus = new TF1("functionGaus", "gaus", 0., 4095.); + TSpectrum *peakSearcher = new TSpectrum(5);//find up to 5 pedestal peaks + int numberOfPeaks; //number of pedestal peaks in channel. Normaly it's 1, otherwise channel is bad + double *xPeaks, yPeaks[5]; // arrays of x-position of the peaks and their heights + + for (int channel = 0; channel < kNChannels; channel++){ + if (mHistAmplitudes[channel]->GetEntries() < 1) continue; //no data in channel, skipping it + //first, make just estimation of pedestal value and sigma in whole histo range + //pedestalValue = mHistAmplitudes[channel]->GetMean(); + //pedestalSigma = mHistAmplitudes[channel]->GetStdDev(); + //then calc pedestal value and sigma in a zone of interest + //(i.e. exclude events which are far from pedestal value) + //mHistAmplitudes[channel]->GetXaxis()->SetRangeUser(pedestalValue - 5. * pedestalSigma, + // pedestalValue + 5. * pedestalSigma); + //pedestalValue = mHistAmplitudes[channel]->GetMean(); + //pedestalSigma = mHistAmplitudes[channel]->GetStdDev(); + //mHistAmplitudes[channel]->Fit(functionGaus, "WWQ", "", pedestalValue - 5. * pedestalSigma, + // pedestalValue + 5. * pedestalSigma); + //if(functionGaus->GetParameter(1) > 0){//in some cases it's not because of several peaks in the spectrum + // pedestalValue = functionGaus->GetParameter(1); + // pedestalSigma = functionGaus->GetParameter(2); + //} + + ILOG(Info, Support) << "fillHistograms(): Start to search peaks in channel " << channel << ENDM; + + numberOfPeaks = peakSearcher->Search(mHistAmplitudes[channel], 2, "nobackground", 0.05); + xPeaks = peakSearcher->GetPositionX(); + + if(numberOfPeaks == 1) {// only 1 peak, fit spectrum with gaus + yPeaks[0] = mHistAmplitudes[channel]->GetBinContent(mHistAmplitudes[channel]->GetXaxis()->FindBin(xPeaks[0])); + functionGaus->SetParameters(yPeaks[0], xPeaks[0], 2.); + mHistAmplitudes[channel]->Fit(functionGaus); + pedestalValue = functionGaus->GetParameter(1); + pedestalSigma = functionGaus->GetParameter(2); + } else + if (numberOfPeaks > 1){// >1 peaks, no fit. Just use mean and stddev as ped value & sigma + pedestalValue = mHistAmplitudes[channel]->GetMean(); + pedestalSigma = mHistAmplitudes[channel]->GetStdDev(); + //let's publish this bad amplitude + getObjectsManager()->startPublishing(mHistAmplitudes[channel]); + } + + pedestalEfficiency = mHistAmplitudes[channel]->GetEntries()/mNEvents; + mCPVGeometry.absToRelNumbering(channel,relId); + mHist2D[H2DPedestalValueMapM2 + relId[0] - 2]->SetBinContent(relId[1] + 1, relId[2] + 1, pedestalValue); + mHist2D[H2DPedestalSigmaMapM2 + relId[0] - 2]->SetBinContent(relId[1] + 1, relId[2] + 1, pedestalSigma); + mHist2D[H2DPedestalEfficiencyMapM2 + relId[0] - 2]->SetBinContent(relId[1] + 1, relId[2] + 1, pedestalEfficiency); + mHist2D[H2DPedestalNPeaksMapM2 + relId[0] - 2]->SetBinContent(relId[1] + 1, relId[2] + 1, numberOfPeaks); + + mHist1D[H1DPedestalValueM2 + relId[0] - 2]->Fill(pedestalValue); + mHist1D[H1DPedestalSigmaM2 + relId[0] - 2]->Fill(pedestalSigma); + mHist1D[H1DPedestalEfficiencyM2 + relId[0] - 2]->Fill(pedestalEfficiency); + + } + + //show some info to developer + ILOG(Info, Devel) << "fillHistograms() : N events = " << mNEvents << ENDM; +} + +void PedestalTask::resetHistograms() +{ + // clean all histograms + ILOG(Info, Support) << "Resetting amplitude histograms" << ENDM; + for (int i = 0; i < kNChannels; i++){ + mHistAmplitudes[i]->Reset(); + } + + ILOG(Info, Support) << "Resetting the 1D Histograms" << ENDM; + for (int itHist1D = H1DInputPayloadSize; itHist1D < kNHist1D; itHist1D++){ + mHist1D[itHist1D]->Reset(); + } + + ILOG(Info, Support) << "Resetting the 2D Histograms" << ENDM; + for (int itHist2D = H2DErrorType; itHist2D < kNHist2D; itHist2D++){ + mHist2D[itHist2D]->Reset(); + } +} + +} // namespace o2::quality_control_modules::cpv diff --git a/Modules/CPV/test/testQcCPV.cxx b/Modules/CPV/test/testQcCPV.cxx new file mode 100644 index 0000000000..e5eae3973b --- /dev/null +++ b/Modules/CPV/test/testQcCPV.cxx @@ -0,0 +1,29 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 testCPV.cxx +/// \author My Name +/// + +#include "QualityControl/TaskFactory.h" + +#define BOOST_TEST_MODULE Publisher test +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include + +namespace o2::quality_control_modules::cpv +{ + +BOOST_AUTO_TEST_CASE(instantiate_task) { BOOST_CHECK(true); } + +} // namespace o2::quality_control_modules::cpv From e86d245c631ba0a35f7ad0464e31f5e1f9c95144 Mon Sep 17 00:00:00 2001 From: sevdokim Date: Thu, 1 Apr 2021 17:19:53 +0200 Subject: [PATCH 2/4] CPV PedestalCheck added --- Modules/CPV/CMakeLists.txt | 5 +- .../pedestal-task-no-sampling.json | 59 ++- Modules/CPV/include/CPV/LinkDef.h | 1 + Modules/CPV/include/CPV/PedestalCheck.h | 58 +++ Modules/CPV/include/CPV/PedestalTask.h | 71 ++-- Modules/CPV/src/PedestalCheck.cxx | 253 +++++++++++++ Modules/CPV/src/PedestalTask.cxx | 340 +++++++++++------- 7 files changed, 626 insertions(+), 161 deletions(-) create mode 100644 Modules/CPV/include/CPV/PedestalCheck.h create mode 100644 Modules/CPV/src/PedestalCheck.cxx diff --git a/Modules/CPV/CMakeLists.txt b/Modules/CPV/CMakeLists.txt index aab0a66e07..61723d0274 100644 --- a/Modules/CPV/CMakeLists.txt +++ b/Modules/CPV/CMakeLists.txt @@ -2,7 +2,7 @@ add_library(QcCPV) -target_sources(QcCPV PRIVATE src/PedestalTask.cxx ) +target_sources(QcCPV PRIVATE src/PedestalCheck.cxx src/PedestalTask.cxx ) target_include_directories( QcCPV @@ -10,7 +10,7 @@ target_include_directories( $ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_link_libraries(QcCPV PUBLIC QualityControl O2::CPVBase) +target_link_libraries(QcCPV PUBLIC QualityControl O2::CPVBase ROOT::Spectrum) install(TARGETS QcCPV LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} @@ -19,6 +19,7 @@ install(TARGETS QcCPV add_root_dictionary(QcCPV HEADERS + include/CPV/PedestalCheck.h include/CPV/PedestalTask.h LINKDEF include/CPV/LinkDef.h BASENAME QcCPV) diff --git a/Modules/CPV/etc/read-raw-from-file/pedestal-task-no-sampling.json b/Modules/CPV/etc/read-raw-from-file/pedestal-task-no-sampling.json index 72b40e65fd..a95e7cc79b 100644 --- a/Modules/CPV/etc/read-raw-from-file/pedestal-task-no-sampling.json +++ b/Modules/CPV/etc/read-raw-from-file/pedestal-task-no-sampling.json @@ -23,7 +23,7 @@ } }, "tasks": { - "PedestalTask": { + "CPVPedestalTask": { "active": "true", "className": "o2::quality_control_modules::cpv::PedestalTask", "moduleName": "QcCPV", @@ -41,6 +41,63 @@ "location": "remote", "saveObjectsToFile": "MOs.root", "": "For debugging, path to the file where to save. If empty or missing it won't save." } + }, + "checks": { + "CPVPedestalCheck": { + "active": "true", + "className": "o2::quality_control_modules::cpv::PedestalCheck", + "moduleName": "QcCPV", + "policy": "OnAny", + "detectorName": "CPV", + "dataSource": [{ + "type": "Task", + "name": "CPVPedestalTask", + "MOs": [ + "PedestalValueM2", + "PedestalValueM3", + "PedestalValueM4", + "PedestalSigmaM2", + "PedestalSigmaM3", + "PedestalSigmaM4", + "PedestalEfficiencyM2", + "PedestalEfficiencyM3", + "PedestalEfficiencyM4" + ] + }], + "checkParameters": { + "mMinGoodPedestalValueM2": "1", + "mMinGoodPedestalValueM3": "1", + "mMinGoodPedestalValueM4": "1", + "": "", + "mMaxGoodPedestalSigmaM2": "2", + "mMaxGoodPedestalSigmaM3": "5", + "mMaxGoodPedestalSigmaM4": "2", + "": "", + "mMinGoodPedestalEfficiencyM2": "0.75", + "mMinGoodPedestalEfficiencyM3": "0.75", + "mMinGoodPedestalEfficiencyM4": "0.75", + "": "", + "mMaxGoodPedestalEfficiencyM2": "1.0", + "mMaxGoodPedestalEfficiencyM3": "1.0", + "mMaxGoodPedestalEfficiencyM4": "1.0", + "": "", + "mToleratedBadPedestalValueChannelsM2": "100", + "mToleratedBadPedestalValueChannelsM3": "200", + "mToleratedBadPedestalValueChannelsM4": "100", + "": "", + "mToleratedBadPedestalSigmaChannelsM2": "300", + "mToleratedBadPedestalSigmaChannelsM3": "400", + "mToleratedBadPedestalSigmaChannelsM4": "500", + "": "", + "mToleratedBadChannelsM2": "200", + "mToleratedBadChannelsM3": "200", + "mToleratedBadChannelsM4": "200", + "": "", + "mToleratedBadPedestalEfficiencyChannelsM2": "100", + "mToleratedBadPedestalEfficiencyChannelsM3": "100", + "mToleratedBadPedestalEfficiencyChannelsM4": "100" + } + } } }, "dataSamplingPolicies": [ diff --git a/Modules/CPV/include/CPV/LinkDef.h b/Modules/CPV/include/CPV/LinkDef.h index 8972927bab..88addf4590 100644 --- a/Modules/CPV/include/CPV/LinkDef.h +++ b/Modules/CPV/include/CPV/LinkDef.h @@ -4,4 +4,5 @@ #pragma link off all functions; #pragma link C++ class o2::quality_control_modules::cpv::PedestalTask+; +#pragma link C++ class o2::quality_control_modules::cpv::PedestalCheck+; #endif diff --git a/Modules/CPV/include/CPV/PedestalCheck.h b/Modules/CPV/include/CPV/PedestalCheck.h new file mode 100644 index 0000000000..3b8663a484 --- /dev/null +++ b/Modules/CPV/include/CPV/PedestalCheck.h @@ -0,0 +1,58 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 PedestalCheck.h +/// \author Sergey Evdokimov +/// + +#ifndef QC_MODULE_CPV_CPVPEDESTALCHECK_H +#define QC_MODULE_CPV_CPVPEDESTALCHECK_H + +#include "QualityControl/CheckInterface.h" + +namespace o2::quality_control_modules::cpv +{ + +/// \brief CPV PedestalCheck +/// \author Sergey Evdokimov +/// +class PedestalCheck : public o2::quality_control::checker::CheckInterface +{ + public: + /// Default constructor + PedestalCheck() = default; + /// Destructor + ~PedestalCheck() 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; + + private: + //configurable parameters and their default values + //see config example in Modules/CPV/etc/pedestal-task-no-sampling.json + int mMinGoodPedestalValueM[3] = { 1, 1, 1 }; + float mMaxGoodPedestalSigmaM[3] = { 2., 2., 2. }; + float mMinGoodPedestalEfficiencyM[3] = { 0.7, 0.7, 0.7 }; + float mMaxGoodPedestalEfficiencyM[3] = { 1., 1., 1. }; + int mToleratedBadPedestalValueChannelsM[3] = { 10, 10, 10 }; //pedestal value < mMinGoodPedestalValue or > 512 + int mToleratedBadChannelsM[3] = { 20, 20, 20 }; //double peaks or empty or channels + int mToleratedBadPedestalSigmaChannelsM[3] = { 20, 20, 20 }; //pedestal value < mMinGoodPedestalValue or > 512 + int mToleratedBadPedestalEfficiencyChannelsM[3] = { 20, 20, 20 }; //efficiency < min or > max + + ClassDefOverride(PedestalCheck, 1); +}; + +} // namespace o2::quality_control_modules::cpv + +#endif // QC_MODULE_CPV_CPVPEDESTALCHECK_H diff --git a/Modules/CPV/include/CPV/PedestalTask.h b/Modules/CPV/include/CPV/PedestalTask.h index c8eba50ab7..51061b38b1 100644 --- a/Modules/CPV/include/CPV/PedestalTask.h +++ b/Modules/CPV/include/CPV/PedestalTask.h @@ -24,7 +24,6 @@ #include #include "CPVBase/Geometry.h" - class TH1F; class TH2F; @@ -53,61 +52,59 @@ class PedestalTask final : public TaskInterface void reset() override; private: - void initHistograms(); // void fillHistograms(const gsl::span& digits, const gsl::span& triggerRecords); void fillHistograms(); void resetHistograms(); - - + static constexpr short kNHist1D = 14; enum Histos1D { H1DInputPayloadSize, - H1DNInputs, - H1DNValidInputs, - H1DNDigitsPerInput, - H1DDigitIds, - H1DPedestalValueM2, - H1DPedestalValueM3, - H1DPedestalValueM4, - H1DPedestalSigmaM2, - H1DPedestalSigmaM3, - H1DPedestalSigmaM4, - H1DPedestalEfficiencyM2, - H1DPedestalEfficiencyM3, - H1DPedestalEfficiencyM4 + H1DNInputs, + H1DNValidInputs, + H1DNDigitsPerInput, + H1DDigitIds, + H1DPedestalValueM2, + H1DPedestalValueM3, + H1DPedestalValueM4, + H1DPedestalSigmaM2, + H1DPedestalSigmaM3, + H1DPedestalSigmaM4, + H1DPedestalEfficiencyM2, + H1DPedestalEfficiencyM3, + H1DPedestalEfficiencyM4 }; static constexpr short kNHist2D = 16; enum Histos2D { H2DErrorType, - H2DDigitMapM2, - H2DDigitMapM3, - H2DDigitMapM4, - H2DPedestalValueMapM2, - H2DPedestalValueMapM3, - H2DPedestalValueMapM4, - H2DPedestalSigmaMapM2, - H2DPedestalSigmaMapM3, - H2DPedestalSigmaMapM4, - H2DPedestalEfficiencyMapM2, - H2DPedestalEfficiencyMapM3, - H2DPedestalEfficiencyMapM4, - H2DPedestalNPeaksMapM2, - H2DPedestalNPeaksMapM3, - H2DPedestalNPeaksMapM4 - + H2DDigitMapM2, + H2DDigitMapM3, + H2DDigitMapM4, + H2DPedestalValueMapM2, + H2DPedestalValueMapM3, + H2DPedestalValueMapM4, + H2DPedestalSigmaMapM2, + H2DPedestalSigmaMapM3, + H2DPedestalSigmaMapM4, + H2DPedestalEfficiencyMapM2, + H2DPedestalEfficiencyMapM3, + H2DPedestalEfficiencyMapM4, + H2DPedestalNPeaksMapM2, + H2DPedestalNPeaksMapM3, + H2DPedestalNPeaksMapM4 }; static constexpr short kNModules = 3; static constexpr short kNChannels = 23040; o2::cpv::Geometry mCPVGeometry; - int mNEvents; - + int mNEventsTotal; + int mNEventsFromLastFillHistogramsCall; + std::array mHist1D = { nullptr }; ///< Array of 1D histograms std::array mHist2D = { nullptr }; ///< Array of 2D histograms - std::array mHistAmplitudes = { nullptr }; ///< Array of amplitude spectra - + std::array mHistAmplitudes = { nullptr }; ///< Array of amplitude spectra + std::array mIsUpdatedAmplitude = { false }; ///< Array of isUpdatedAmplitude bools }; } // namespace o2::quality_control_modules::cpv diff --git a/Modules/CPV/src/PedestalCheck.cxx b/Modules/CPV/src/PedestalCheck.cxx new file mode 100644 index 0000000000..706fdfd77c --- /dev/null +++ b/Modules/CPV/src/PedestalCheck.cxx @@ -0,0 +1,253 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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 PedestalCheck.cxx +/// \author Sergey Evdokimov +/// + +#include "CPV/PedestalCheck.h" +#include "QualityControl/MonitorObject.h" +#include "QualityControl/Quality.h" +#include "QualityControl/QcInfoLogger.h" +// ROOT +#include +#include +#include +#include + +using namespace std; + +namespace o2::quality_control_modules::cpv +{ + +void PedestalCheck::configure(std::string) +{ + for (int mod = 0; mod < 3; mod++) { + //mMinGoodPedestalValueM + if (auto param = mCustomParameters.find(Form("mMinGoodPedestalValueM%d", mod + 2)); + param != mCustomParameters.end()) { + ILOG(Info, Devel) << "configure() : Custom parameter " + << Form("mMinGoodPedestalValueM%d", mod + 2) + << param->second << ENDM; + mMinGoodPedestalValueM[mod] = stoi(param->second); + } + ILOG(Info, Support) << "configure() : I use " + << Form("mMinGoodPedestalValueM%d", mod + 2) + << " = " + << mMinGoodPedestalValueM[mod] << ENDM; + //mMaxGoodPedestalSigmaM + if (auto param = mCustomParameters.find(Form("mMaxGoodPedestalSigmaM%d", mod + 2)); + param != mCustomParameters.end()) { + ILOG(Info, Devel) << "configure() : Custom parameter " + << Form("mMaxGoodPedestalSigmaM%d", mod + 2) + << param->second << ENDM; + mMaxGoodPedestalSigmaM[mod] = stof(param->second); + } + ILOG(Info, Support) << "configure() : I use " + << Form("mMaxGoodPedestalSigmaM%d", mod + 2) + << " = " + << mMaxGoodPedestalSigmaM[mod] << ENDM; + //mMinGoodPedestalEfficiencyM + if (auto param = mCustomParameters.find(Form("mMinGoodPedestalEfficiencyM%d", mod + 2)); + param != mCustomParameters.end()) { + ILOG(Info, Devel) << "configure() : Custom parameter " + << Form("mMinGoodPedestalEfficiencyM%d", mod + 2) + << param->second << ENDM; + mMinGoodPedestalEfficiencyM[mod] = stof(param->second); + } + ILOG(Info, Support) << "configure() : I use " + << Form("mMinGoodPedestalEfficiencyM%d", mod + 2) + << " = " + << mMinGoodPedestalEfficiencyM[mod] << ENDM; + //mMaxGoodPedestalEfficiencyM + if (auto param = mCustomParameters.find(Form("mMaxGoodPedestalEfficiencyM%d", mod + 2)); + param != mCustomParameters.end()) { + ILOG(Info, Devel) << "configure() : Custom parameter " + << Form("mMaxGoodPedestalEfficiencyM%d", mod + 2) + << param->second << ENDM; + mMaxGoodPedestalEfficiencyM[mod] = stof(param->second); + } + ILOG(Info, Support) << "configure() : I use " + << Form("mMaxGoodPedestalEfficiencyM%d", mod + 2) + << " = " + << mMaxGoodPedestalEfficiencyM[mod] << ENDM; + //mToleratedBadPedestalValueChannelsM + if (auto param = mCustomParameters.find(Form("mToleratedBadPedestalValueChannelsM%d", mod + 2)); + param != mCustomParameters.end()) { + ILOG(Info, Devel) << "configure() : Custom parameter " + << Form("mToleratedBadPedestalValueChannelsM%d", mod + 2) + << param->second << ENDM; + mToleratedBadPedestalValueChannelsM[mod] = stoi(param->second); + } + ILOG(Info, Support) << "configure() : I use " + << Form("mToleratedBadPedestalValueChannelsM%d", mod + 2) + << " = " + << mToleratedBadPedestalValueChannelsM[mod] << ENDM; + //mToleratedBadChannelsM + if (auto param = mCustomParameters.find(Form("mToleratedBadChannelsM%d", mod + 2)); + param != mCustomParameters.end()) { + ILOG(Info, Devel) << "configure() : Custom parameter " + << Form("mToleratedBadChannelsM%d", mod + 2) + << param->second << ENDM; + mToleratedBadChannelsM[mod] = stoi(param->second); + } + ILOG(Info, Support) << "configure() : I use " + << Form("mToleratedBadChannelsM%d", mod + 2) + << " = " + << mToleratedBadChannelsM[mod] << ENDM; + //mToleratedBadPedestalEfficiencyChannelsM + if (auto param = mCustomParameters.find(Form("mToleratedBadPedestalEfficiencyChannelsM%d", mod + 2)); + param != mCustomParameters.end()) { + ILOG(Info, Devel) << "configure() : Custom parameter " + << Form("mToleratedBadPedestalEfficiencyChannelsM%d", mod + 2) + << param->second << ENDM; + mToleratedBadPedestalEfficiencyChannelsM[mod] = stoi(param->second); + } + ILOG(Info, Support) << "configure() : I use " + << Form("mToleratedBadPedestalEfficiencyChannelsM%d", mod + 2) + << " = " + << mToleratedBadPedestalEfficiencyChannelsM[mod] << ENDM; + } +} + +Quality PedestalCheck::check(std::map>* moMap) +{ + Quality result = Quality::Good; + + for (auto& [moName, mo] : *moMap) { + + (void)moName; + for (int iMod = 0; iMod < 3; iMod++) { //loop modules + if (mo->getName() == Form("PedestalValueM%d", iMod + 2)) { + bool isGoodMO = true; + + auto* h = dynamic_cast(mo->getObject()); + result = Quality::Good; //default + TPaveText* msg = new TPaveText(0.5, 0.5, 0.9, 0.75, "NDC"); + h->GetListOfFunctions()->Add(msg); + msg->SetName(Form("%s_msg", mo->GetName())); + msg->Clear(); + //count number of too small pedestals + too big pedestals + int nOfBadPedestalValues = h->Integral(1, mMinGoodPedestalValueM[iMod]) + h->GetBinContent(h->GetNbinsX() + 1); //underflow + small pedestals + overflow + if (nOfBadPedestalValues > mToleratedBadPedestalValueChannelsM[iMod]) { + result = Quality::Bad; + msg->AddText(Form("Too many bad ped values: %d", nOfBadPedestalValues)); + msg->AddText(Form("Tolerated bad ped values: %d", mToleratedBadPedestalValueChannelsM[iMod])); + msg->SetFillColor(kRed); + h->SetFillColor(kRed); + isGoodMO = false; + } + //count number of bad pedestals (double peaked and so) + int nOfBadPedestals = 7680 - h->GetEntries(); + if (nOfBadPedestals > mToleratedBadChannelsM[iMod]) { + result = Quality::Bad; + msg->AddText(Form("Too many bad channels: %d", nOfBadPedestals)); + msg->AddText(Form("Tolerated bad channels: %d", mToleratedBadChannelsM[iMod])); + msg->SetFillColor(kRed); + h->SetFillColor(kRed); + isGoodMO = false; + } + if (isGoodMO) { + msg->AddText("OK"); + msg->SetFillColor(kGreen); + } + break; //exit modules loop for this particular object + } + + if (mo->getName() == Form("PedestalSigmaM%d", iMod + 2)) { + + auto* h = dynamic_cast(mo->getObject()); + result = Quality::Good; //default + TPaveText* msg = new TPaveText(0.5, 0.5, 0.9, 0.75, "NDC"); + h->GetListOfFunctions()->Add(msg); + msg->SetName(Form("%s_msg", mo->GetName())); + msg->Clear(); + //count number of too small pedestals + too big pedestals + float binWidth = h->GetBinWidth(1); + int nOfBadPedestalSigmas = h->Integral(mMaxGoodPedestalSigmaM[iMod] / binWidth + 1, + h->GetNbinsX() + 1); //big sigmas + overflow + + if (nOfBadPedestalSigmas > mToleratedBadPedestalSigmaChannelsM[iMod]) { + result = Quality::Bad; + msg->AddText(Form("Too many bad ped sigmas: %d", nOfBadPedestalSigmas)); + msg->AddText(Form("Tolerated bad ped sigmas: %d", mToleratedBadPedestalSigmaChannelsM[iMod])); + + msg->SetFillColor(kRed); + h->SetFillColor(kRed); + } else { + msg->AddText("OK"); + msg->SetFillColor(kGreen); + } + break; //exit modules loop for this particular object + } + + if (mo->getName() == Form("PedestalEfficiencyM%d", iMod + 2)) { + + auto* h = dynamic_cast(mo->getObject()); + result = Quality::Good; //default + TPaveText* msg = new TPaveText(0.5, 0.5, 0.9, 0.75, "NDC"); + h->GetListOfFunctions()->Add(msg); + msg->SetName(Form("%s_msg", mo->GetName())); + msg->Clear(); + //count number of too small pedestals + too big pedestals + float binWidth = h->GetBinWidth(1); + int nOfBadPedestalEfficiencies = 7680 - + h->Integral(mMinGoodPedestalEfficiencyM[iMod] / binWidth + 1, + mMaxGoodPedestalEfficiencyM[iMod] / binWidth); //big sigmas + overflow + + if (nOfBadPedestalEfficiencies > mToleratedBadPedestalEfficiencyChannelsM[iMod]) { + result = Quality::Bad; + msg->AddText(Form("Too many bad ped efficiencies: %d", nOfBadPedestalEfficiencies)); + msg->AddText(Form("Tolerated bad ped efficiencies: %d", + mToleratedBadPedestalEfficiencyChannelsM[iMod])); + msg->SetFillColor(kRed); + h->SetFillColor(kRed); + } else { + msg->AddText("OK"); + msg->SetFillColor(kGreen); + } + break; //exit modules loop for this particular object + } + + } //iMod cycle + } //moMap cycle + + return result; +} + +//std::string PedestalCheck::getAcceptedType() { return "TObject"; } +std::string PedestalCheck::getAcceptedType() { return "TH1"; } + +void PedestalCheck::beautify(std::shared_ptr mo, Quality checkResult) +{ + return; //do noting for the time being. Maybe in the future we will do something sofisticated + for (int iMod = 0; iMod < 3; iMod++) { //loop over modules + if (mo->getName() == Form("PedestalValueM%d", iMod + 2)) { + auto* h = dynamic_cast(mo->getObject()); + + if (checkResult == Quality::Good) { + h->SetFillColor(kGreen); + // + } else if (checkResult == Quality::Bad) { + ILOG(Info, Support) << "beautify() : Quality::Bad, setting to red for " + << mo->GetName() << ENDM; + h->SetFillColor(kRed); + // + } else if (checkResult == Quality::Medium) { + ILOG(Error, Support) << "beautify() : unexpected quality for " << mo->GetName() << ENDM; + h->SetFillColor(kOrange); + } + return; //exit when object is processed + } + } +} + +} // namespace o2::quality_control_modules::cpv diff --git a/Modules/CPV/src/PedestalTask.cxx b/Modules/CPV/src/PedestalTask.cxx index 58ed14a9c4..36a55027b6 100644 --- a/Modules/CPV/src/PedestalTask.cxx +++ b/Modules/CPV/src/PedestalTask.cxx @@ -19,7 +19,6 @@ #include #include - #include "QualityControl/QcInfoLogger.h" #include "CPV/PedestalTask.h" #include @@ -30,20 +29,20 @@ namespace o2::quality_control_modules::cpv PedestalTask::~PedestalTask() { - for (int i = kNHist1D; i--;) { + for (int i = 0; i < kNHist1D; i++) { if (mHist1D[i]) { mHist1D[i]->Delete(); mHist1D[i] = nullptr; } } - for (int i = kNHist2D; i--;) { + for (int i = 0; i < kNHist2D; i++) { if (mHist2D[i]) { mHist2D[i]->Delete(); mHist2D[i] = nullptr; } } - for (int i = 0; iDelete(); mHistAmplitudes[i] = nullptr; } @@ -59,18 +58,24 @@ void PedestalTask::initialize(o2::framework::InitContext& /*ctx*/) ILOG(Info, Devel) << "Custom parameter - myOwnKey: " << param->second << ENDM; } initHistograms(); - mNEvents = 0; + mNEventsTotal = 0; + mNEventsFromLastFillHistogramsCall = 0; } void PedestalTask::startOfActivity(Activity& activity) { ILOG(Info, Support) << "startOfActivity" << activity.mId << ENDM; - resetHistograms(); + resetHistograms(); + mNEventsTotal = 0; + mNEventsFromLastFillHistogramsCall = 0; } void PedestalTask::startOfCycle() { ILOG(Info, Support) << "startOfCycle" << ENDM; + //at at the startOfCycle all HistAmplitudes are not updated by definition + for (int i = 0; i < kNChannels; i++) + mIsUpdatedAmplitude[i] = false; } void PedestalTask::monitorData(o2::framework::ProcessingContext& ctx) @@ -92,7 +97,7 @@ void PedestalTask::monitorData(o2::framework::ProcessingContext& ctx) int nValidInputs = ctx.inputs().countValidInputs(); mHist1D[H1DNValidInputs]->Fill(nValidInputs); - + for (auto&& input : ctx.inputs()) { // get message header if (input.header != nullptr && input.payload != nullptr) { @@ -108,23 +113,26 @@ void PedestalTask::monitorData(o2::framework::ProcessingContext& ctx) // 2. Using get("") auto digits = ctx.inputs().get>("digits"); mHist1D[H1DNDigitsPerInput]->Fill(digits.size()); - for (const auto& digit : digits){ + for (const auto& digit : digits) { mHist1D[H1DDigitIds]->Fill(digit.getAbsId()); short relId[3]; - mCPVGeometry.absToRelNumbering(digit.getAbsId(),relId); + mCPVGeometry.absToRelNumbering(digit.getAbsId(), relId); //reminder: relId[3]={Module, phi col, z row} where Module=2..4, phi col=0..127, z row=0..59 mHist2D[H2DDigitMapM2 + relId[0] - 2]->Fill(relId[1], relId[2]); mHistAmplitudes[digit.getAbsId()]->Fill(digit.getAmplitude()); - } + mIsUpdatedAmplitude[digit.getAbsId()] = true; + } auto digitsTR = ctx.inputs().get>("dtrigrec"); - //mNEvents += digitsTR.size();//number of events in the current input + //mNEventsTotal += digitsTR.size();//number of events in the current input for (const auto& trigRecord : digitsTR) { - ILOG(Info, Devel) << " monitorData() : trigger record #" << mNEvents - << " contains "< 0) mNEvents++;//at least 1 digit in this trigger record - } - + ILOG(Info, Devel) << " monitorData() : trigger record #" << mNEventsTotal + << " contains " << trigRecord.getNumberOfObjects() << " objects." << ENDM; + if (trigRecord.getNumberOfObjects() > 0) { //at least 1 digit -> pedestal event + mNEventsTotal++; + mNEventsFromLastFillHistogramsCall++; + } + } // get the payload of a specific input, which is a char array. "random" is the binding specified in the config file. // auto payload = ctx.inputs().get("random").payload; @@ -155,12 +163,19 @@ void PedestalTask::monitorData(o2::framework::ProcessingContext& ctx) void PedestalTask::endOfCycle() { ILOG(Info, Support) << "endOfCycle. I call fillHistograms()" << ENDM; - fillHistograms(); + //fit histograms if have sufficient increment of event number + if (mNEventsFromLastFillHistogramsCall > 1000) + fillHistograms(); + mNEventsFromLastFillHistogramsCall = 0; } void PedestalTask::endOfActivity(Activity& /*activity*/) { ILOG(Info, Support) << "endOfActivity" << ENDM; + //do a final fill of histograms (if needed) + if (mNEventsFromLastFillHistogramsCall) + fillHistograms(); + mNEventsFromLastFillHistogramsCall = 0; } void PedestalTask::reset() @@ -168,87 +183,108 @@ void PedestalTask::reset() // clean all the monitor objects here ILOG(Info, Support) << "Resetting PedestalTask" << ENDM; resetHistograms(); - mNEvents = 0; + mNEventsTotal = 0; + mNEventsFromLastFillHistogramsCall = 0; } void PedestalTask::initHistograms() { - //create monitoring histograms (or reset, if they already exists) - for (int i = 0; i < kNChannels; i++){ + //create monitoring histograms (or reset, if they already exist) + for (int i = 0; i < kNChannels; i++) { if (!mHistAmplitudes[i]) { - mHistAmplitudes[i] = new TH1F(Form("HistAmplitude%d", i), Form("HistAmplitude%d", i), 4096, 0., 4096.); - if(i % 1000 == 0) getObjectsManager()->startPublishing(mHistAmplitudes[i]); - + mHistAmplitudes[i] = + new TH1F(Form("HistAmplitude%d", i), Form("HistAmplitude%d", i), 4096, 0., 4096.); + //publish some of them + if (i % 1000 == 0) + getObjectsManager()->startPublishing(mHistAmplitudes[i]); + } else { mHistAmplitudes[i]->Reset(); - } + } + mIsUpdatedAmplitude[i] = false; } - - + //1D Histos - if (!mHist1D[H1DInputPayloadSize]){ - mHist1D[H1DInputPayloadSize] = new TH1F("InputPayloadSize", "Input Payload Size", 30000, 0, 30000000); + if (!mHist1D[H1DInputPayloadSize]) { + mHist1D[H1DInputPayloadSize] = + new TH1F("InputPayloadSize", "Input Payload Size", 30000, 0, 30000000); getObjectsManager()->startPublishing(mHist1D[H1DInputPayloadSize]); } else { mHist1D[H1DInputPayloadSize]->Reset(); } - - if (!mHist1D[H1DNInputs]){ + + if (!mHist1D[H1DNInputs]) { mHist1D[H1DNInputs] = new TH1F("NInputs", "Number of inputs", 10, -0.5, 9.5); getObjectsManager()->startPublishing(mHist1D[H1DNInputs]); } else { mHist1D[H1DNInputs]->Reset(); } - - if (!mHist1D[H1DNValidInputs]){ - mHist1D[H1DNValidInputs] = new TH1F("NValidInputs", "Number of valid inputs", 10, -0.5, 9.5); + + if (!mHist1D[H1DNValidInputs]) { + mHist1D[H1DNValidInputs] = + new TH1F("NValidInputs", "Number of valid inputs", 10, -0.5, 9.5); getObjectsManager()->startPublishing(mHist1D[H1DNValidInputs]); } else { mHist1D[H1DNValidInputs]->Reset(); } - - if (!mHist1D[H1DNDigitsPerInput]){ - mHist1D[H1DNDigitsPerInput] = new TH1F("NDigitsPerInput", "Number of digits per input", 30000, 0, 300000); + + if (!mHist1D[H1DNDigitsPerInput]) { + mHist1D[H1DNDigitsPerInput] = + new TH1F("NDigitsPerInput", "Number of digits per input", 30000, 0, 300000); getObjectsManager()->startPublishing(mHist1D[H1DNDigitsPerInput]); } else { mHist1D[H1DNDigitsPerInput]->Reset(); } - - if (!mHist1D[H1DDigitIds]){ + + if (!mHist1D[H1DDigitIds]) { mHist1D[H1DDigitIds] = new TH1F("DigitIds", "Digit Ids", 30000, -0.5, 29999.5); getObjectsManager()->startPublishing(mHist1D[H1DDigitIds]); } else { mHist1D[H1DDigitIds]->Reset(); } - for (int mod = 0; mod < kNModules; mod++){ - if (!mHist1D[H1DPedestalValueM2 + mod]){ - mHist1D[H1DPedestalValueM2 + mod] = new TH1F(Form("PedestalValueM%d", mod + 2), Form("Pedestal value distribution M%d", mod + 2), 512, 0, 512); + for (int mod = 0; mod < kNModules; mod++) { + if (!mHist1D[H1DPedestalValueM2 + mod]) { + mHist1D[H1DPedestalValueM2 + mod] = + new TH1F( + Form("PedestalValueM%d", mod + 2), + Form("Pedestal value distribution M%d", mod + 2), + 512, 0, 512); + mHist1D[H1DPedestalValueM2 + mod]->GetXaxis()->SetTitle("Pedestal value"); getObjectsManager()->startPublishing(mHist1D[H1DPedestalValueM2 + mod]); } else { mHist1D[H1DPedestalValueM2 + mod]->Reset(); } - - if (!mHist1D[H1DPedestalSigmaM2 + mod]){ - mHist1D[H1DPedestalSigmaM2 + mod] = new TH1F(Form("PedestalSigmaM%d", mod + 2), Form("Pedestal sigma distribution M%d", mod + 2), 512, 0, 512); + + if (!mHist1D[H1DPedestalSigmaM2 + mod]) { + mHist1D[H1DPedestalSigmaM2 + mod] = + new TH1F( + Form("PedestalSigmaM%d", mod + 2), + Form("Pedestal sigma distribution M%d", mod + 2), + 200, 0, 20); + mHist1D[H1DPedestalSigmaM2 + mod]->GetXaxis()->SetTitle("Pedestal sigma"); getObjectsManager()->startPublishing(mHist1D[H1DPedestalSigmaM2 + mod]); } else { mHist1D[H1DPedestalSigmaM2 + mod]->Reset(); } - - if (!mHist1D[H1DPedestalEfficiencyM2 + mod]){ - mHist1D[H1DPedestalEfficiencyM2 + mod] = new TH1F(Form("PedestalEfficiencyM%d", mod + 2), Form("Pedestal efficiency distribution M%d", mod + 2), 1000, 0., 10.); + + if (!mHist1D[H1DPedestalEfficiencyM2 + mod]) { + mHist1D[H1DPedestalEfficiencyM2 + mod] = + new TH1F( + Form("PedestalEfficiencyM%d", mod + 2), + Form("Pedestal efficiency distribution M%d", mod + 2), + 500, 0., 5.); + mHist1D[H1DPedestalEfficiencyM2 + mod]->GetXaxis()->SetTitle("Pedestal efficiency"); getObjectsManager()->startPublishing(mHist1D[H1DPedestalEfficiencyM2 + mod]); } else { mHist1D[H1DPedestalEfficiencyM2 + mod]->Reset(); } } - - //2D Histos - if (!mHist2D[H2DErrorType]){ + if (!mHist2D[H2DErrorType]) { mHist2D[H2DErrorType] = new TH2F("ErrorType", "ErrorType", 50, 0, 50, 5, 0, 5); + mHist2D[H2DErrorType]->SetStats(0); getObjectsManager()->startPublishing(mHist2D[H2DErrorType]); } else { mHist2D[H2DErrorType]->Reset(); @@ -257,130 +293,192 @@ void PedestalTask::initHistograms() //per-module histos int nPadsX = mCPVGeometry.kNumberOfCPVPadsPhi; int nPadsZ = mCPVGeometry.kNumberOfCPVPadsZ; - - for (int mod = 0; mod < kNModules; mod++){ - if (!mHist2D[H2DDigitMapM2 + mod]){ - mHist2D[H2DDigitMapM2 + mod] = new TH2F(Form("DigitMapM%d", 2 + mod), Form("Digit Map in M%d", mod + 2), nPadsX, -0.5, nPadsX - 0.5, nPadsZ, -0.5, nPadsZ - 0.5); + + for (int mod = 0; mod < kNModules; mod++) { + if (!mHist2D[H2DDigitMapM2 + mod]) { + mHist2D[H2DDigitMapM2 + mod] = + new TH2F( + Form("DigitMapM%d", 2 + mod), + Form("Digit Map in M%d", mod + 2), + nPadsX, -0.5, nPadsX - 0.5, + nPadsZ, -0.5, nPadsZ - 0.5); + mHist2D[H2DDigitMapM2 + mod]->GetXaxis()->SetTitle("x, pad"); + mHist2D[H2DDigitMapM2 + mod]->GetYaxis()->SetTitle("z, pad"); + mHist2D[H2DDigitMapM2 + mod]->SetStats(0); getObjectsManager()->startPublishing(mHist2D[H2DDigitMapM2 + mod]); } else { mHist2D[H2DDigitMapM2 + mod]->Reset(); } - - if (!mHist2D[H2DPedestalValueMapM2 + mod]){ - mHist2D[H2DPedestalValueMapM2 + mod] = new TH2F(Form("PedestalValueMapM%d", 2 + mod), Form("PedestalValue Map in M%d", mod + 2), nPadsX, -0.5, nPadsX - 0.5, nPadsZ, -0.5, nPadsZ - 0.5); + + if (!mHist2D[H2DPedestalValueMapM2 + mod]) { + mHist2D[H2DPedestalValueMapM2 + mod] = + new TH2F( + Form("PedestalValueMapM%d", 2 + mod), + Form("PedestalValue Map in M%d", mod + 2), + nPadsX, -0.5, nPadsX - 0.5, + nPadsZ, -0.5, nPadsZ - 0.5); + mHist2D[H2DPedestalValueMapM2 + mod]->GetXaxis()->SetTitle("x, pad"); + mHist2D[H2DPedestalValueMapM2 + mod]->GetYaxis()->SetTitle("z, pad"); + mHist2D[H2DPedestalValueMapM2 + mod]->SetStats(0); getObjectsManager()->startPublishing(mHist2D[H2DPedestalValueMapM2 + mod]); } else { mHist2D[H2DPedestalValueMapM2 + mod]->Reset(); } - if (!mHist2D[H2DPedestalSigmaMapM2 + mod]){ - mHist2D[H2DPedestalSigmaMapM2 + mod] = new TH2F(Form("PedestalSigmaMapM%d", 2 + mod), Form("PedestalSigma Map in M%d", mod + 2), nPadsX, -0.5, nPadsX - 0.5, nPadsZ, -0.5, nPadsZ - 0.5); + if (!mHist2D[H2DPedestalSigmaMapM2 + mod]) { + mHist2D[H2DPedestalSigmaMapM2 + mod] = + new TH2F( + Form("PedestalSigmaMapM%d", 2 + mod), + Form("PedestalSigma Map in M%d", mod + 2), + nPadsX, -0.5, nPadsX - 0.5, + nPadsZ, -0.5, nPadsZ - 0.5); + mHist2D[H2DPedestalSigmaMapM2 + mod]->GetXaxis()->SetTitle("x, pad"); + mHist2D[H2DPedestalSigmaMapM2 + mod]->GetYaxis()->SetTitle("z, pad"); + mHist2D[H2DPedestalSigmaMapM2 + mod]->SetStats(0); getObjectsManager()->startPublishing(mHist2D[H2DPedestalSigmaMapM2 + mod]); } else { mHist2D[H2DPedestalSigmaMapM2 + mod]->Reset(); } - if (!mHist2D[H2DPedestalEfficiencyMapM2 + mod]){ - mHist2D[H2DPedestalEfficiencyMapM2 + mod] = new TH2F(Form("PedestalEfficiencyMapM%d", 2 + mod), Form("Pedestal Efficiency Map in M%d", mod + 2), nPadsX, -0.5, nPadsX - 0.5, nPadsZ, -0.5, nPadsZ - 0.5); + if (!mHist2D[H2DPedestalEfficiencyMapM2 + mod]) { + mHist2D[H2DPedestalEfficiencyMapM2 + mod] = + new TH2F( + Form("PedestalEfficiencyMapM%d", 2 + mod), + Form("Pedestal Efficiency Map in M%d", mod + 2), + nPadsX, -0.5, nPadsX - 0.5, + nPadsZ, -0.5, nPadsZ - 0.5); + mHist2D[H2DPedestalEfficiencyMapM2 + mod]->GetXaxis()->SetTitle("x, pad"); + mHist2D[H2DPedestalEfficiencyMapM2 + mod]->GetYaxis()->SetTitle("z, pad"); + mHist2D[H2DPedestalEfficiencyMapM2 + mod]->SetStats(0); getObjectsManager()->startPublishing(mHist2D[H2DPedestalEfficiencyMapM2 + mod]); } else { mHist2D[H2DPedestalEfficiencyMapM2 + mod]->Reset(); } - if (!mHist2D[H2DPedestalNPeaksMapM2 + mod]){ - mHist2D[H2DPedestalNPeaksMapM2 + mod] = new TH2F(Form("PedestalNPeaksMapM%d", 2 + mod), Form("Number of pedestal peaks Map in M%d", mod + 2), nPadsX, -0.5, nPadsX - 0.5, nPadsZ, -0.5, nPadsZ - 0.5); + if (!mHist2D[H2DPedestalNPeaksMapM2 + mod]) { + mHist2D[H2DPedestalNPeaksMapM2 + mod] = + new TH2F( + Form("PedestalNPeaksMapM%d", 2 + mod), + Form("Number of pedestal peaks Map in M%d", mod + 2), + nPadsX, -0.5, nPadsX - 0.5, nPadsZ, -0.5, nPadsZ - 0.5); + mHist2D[H2DPedestalNPeaksMapM2 + mod]->GetXaxis()->SetTitle("x, pad"); + mHist2D[H2DPedestalNPeaksMapM2 + mod]->GetYaxis()->SetTitle("z, pad"); + mHist2D[H2DPedestalNPeaksMapM2 + mod]->SetStats(0); getObjectsManager()->startPublishing(mHist2D[H2DPedestalNPeaksMapM2 + mod]); } else { mHist2D[H2DPedestalNPeaksMapM2 + mod]->Reset(); } - - } - - - } void PedestalTask::fillHistograms() { // count pedestals and update MOs - static float pedestalValue, pedestalSigma, pedestalEfficiency; - static short relId[3]; + float pedestalValue, pedestalSigma, pedestalEfficiency; + short relId[3]; TF1* functionGaus = new TF1("functionGaus", "gaus", 0., 4095.); - TSpectrum *peakSearcher = new TSpectrum(5);//find up to 5 pedestal peaks - int numberOfPeaks; //number of pedestal peaks in channel. Normaly it's 1, otherwise channel is bad - double *xPeaks, yPeaks[5]; // arrays of x-position of the peaks and their heights - - for (int channel = 0; channel < kNChannels; channel++){ - if (mHistAmplitudes[channel]->GetEntries() < 1) continue; //no data in channel, skipping it - //first, make just estimation of pedestal value and sigma in whole histo range - //pedestalValue = mHistAmplitudes[channel]->GetMean(); - //pedestalSigma = mHistAmplitudes[channel]->GetStdDev(); - //then calc pedestal value and sigma in a zone of interest - //(i.e. exclude events which are far from pedestal value) - //mHistAmplitudes[channel]->GetXaxis()->SetRangeUser(pedestalValue - 5. * pedestalSigma, - // pedestalValue + 5. * pedestalSigma); - //pedestalValue = mHistAmplitudes[channel]->GetMean(); - //pedestalSigma = mHistAmplitudes[channel]->GetStdDev(); - //mHistAmplitudes[channel]->Fit(functionGaus, "WWQ", "", pedestalValue - 5. * pedestalSigma, - // pedestalValue + 5. * pedestalSigma); - //if(functionGaus->GetParameter(1) > 0){//in some cases it's not because of several peaks in the spectrum - // pedestalValue = functionGaus->GetParameter(1); - // pedestalSigma = functionGaus->GetParameter(2); - //} - - ILOG(Info, Support) << "fillHistograms(): Start to search peaks in channel " << channel << ENDM; - - numberOfPeaks = peakSearcher->Search(mHistAmplitudes[channel], 2, "nobackground", 0.05); + TSpectrum* peakSearcher = new TSpectrum(5); //find up to 5 pedestal peaks + int numberOfPeaks; //number of pedestal peaks in channel. Normaly it's 1, otherwise channel is bad + double *xPeaks, yPeaks[5]; // arrays of x-position of the peaks and their heights + + //first, reset pedestal histograms + for (int mod = 0; mod < 3; mod++){ + mHist2D[H2DPedestalNPeaksMapM2 + mod]->Reset(); + mHist2D[H2DPedestalValueMapM2 + mod]->Reset(); + mHist2D[H2DPedestalSigmaMapM2 + mod]->Reset(); + mHist2D[H2DPedestalEfficiencyMapM2 + mod]->Reset(); + mHist1D[H1DPedestalValueM2 + mod]->Reset(); + mHist1D[H1DPedestalSigmaM2 + mod]->Reset(); + mHist1D[H1DPedestalEfficiencyM2 + mod]->Reset(); + + } + + //then fill them with actual values + for (int channel = 0; channel < kNChannels; channel++) { + if (!mHistAmplitudes[channel]) { + ILOG(Error, Devel) << "fillHistograms() : histo mHistAmplitudes[" << channel + << "] does not exist! Something is going wrong." << ENDM; + continue; + } + if (!mIsUpdatedAmplitude[channel]) + continue; //no data in channel, skipping it + + if (channel % 1000 == 0) { + ILOG(Info, Devel) << "fillHistograms(): Start to search peaks in channel " << channel << ENDM; + LOG(INFO) << "fillHistograms(): Start to search peaks in channel " << channel; + } + + numberOfPeaks = peakSearcher->Search(mHistAmplitudes[channel], 10., "nobackground", 0.2); xPeaks = peakSearcher->GetPositionX(); - - if(numberOfPeaks == 1) {// only 1 peak, fit spectrum with gaus - yPeaks[0] = mHistAmplitudes[channel]->GetBinContent(mHistAmplitudes[channel]->GetXaxis()->FindBin(xPeaks[0])); + + if (numberOfPeaks == 1) { // only 1 peak, fit spectrum with gaus + yPeaks[0] = mHistAmplitudes[channel] + ->GetBinContent(mHistAmplitudes[channel]->GetXaxis()->FindBin(xPeaks[0])); functionGaus->SetParameters(yPeaks[0], xPeaks[0], 2.); - mHistAmplitudes[channel]->Fit(functionGaus); + mHistAmplitudes[channel]->Fit(functionGaus, "WWQ", "", xPeaks[0] - 20., xPeaks[0] + 20.); pedestalValue = functionGaus->GetParameter(1); pedestalSigma = functionGaus->GetParameter(2); - } else - if (numberOfPeaks > 1){// >1 peaks, no fit. Just use mean and stddev as ped value & sigma - pedestalValue = mHistAmplitudes[channel]->GetMean(); - pedestalSigma = mHistAmplitudes[channel]->GetStdDev(); - //let's publish this bad amplitude - getObjectsManager()->startPublishing(mHistAmplitudes[channel]); + //stop publish this amplitude as it's OK (that fails due to some unclear reason) + //if (getObjectsManager()->isBeingPublished(mHistAmplitudes[channel]->GetName())){ + //getObjectsManager()->stopPublishing(mHistAmplitudes[channel]->GetName()); + //} + } else { + if (numberOfPeaks > 1) { // >1 peaks, no fit. Just use mean and stddev as ped value & sigma + pedestalValue = mHistAmplitudes[channel]->GetMean(); + if(pedestalValue > 0) + pedestalValue = -pedestalValue;//let it be negative so we can know it's bad later + pedestalSigma = mHistAmplitudes[channel]->GetStdDev(); + //let's publish this bad amplitude + if (!getObjectsManager()->isBeingPublished(mHistAmplitudes[channel]->GetName())) { + getObjectsManager()->startPublishing(mHistAmplitudes[channel]); + } + } else { //numberOfPeaks < 1 - what is it? + //no peaks found((( OK let's show the spectrum to the world... + if (!getObjectsManager()->isBeingPublished(mHistAmplitudes[channel]->GetName())) { + getObjectsManager()->startPublishing(mHistAmplitudes[channel]); + } + continue; + } } - - pedestalEfficiency = mHistAmplitudes[channel]->GetEntries()/mNEvents; - mCPVGeometry.absToRelNumbering(channel,relId); - mHist2D[H2DPedestalValueMapM2 + relId[0] - 2]->SetBinContent(relId[1] + 1, relId[2] + 1, pedestalValue); - mHist2D[H2DPedestalSigmaMapM2 + relId[0] - 2]->SetBinContent(relId[1] + 1, relId[2] + 1, pedestalSigma); - mHist2D[H2DPedestalEfficiencyMapM2 + relId[0] - 2]->SetBinContent(relId[1] + 1, relId[2] + 1, pedestalEfficiency); - mHist2D[H2DPedestalNPeaksMapM2 + relId[0] - 2]->SetBinContent(relId[1] + 1, relId[2] + 1, numberOfPeaks); + + pedestalEfficiency = mHistAmplitudes[channel]->GetEntries() / mNEventsTotal; + mCPVGeometry.absToRelNumbering(channel, relId); + mHist2D[H2DPedestalValueMapM2 + relId[0] - 2] + ->SetBinContent(relId[1] + 1, relId[2] + 1, pedestalValue); + mHist2D[H2DPedestalSigmaMapM2 + relId[0] - 2] + ->SetBinContent(relId[1] + 1, relId[2] + 1, pedestalSigma); + mHist2D[H2DPedestalEfficiencyMapM2 + relId[0] - 2] + ->SetBinContent(relId[1] + 1, relId[2] + 1, pedestalEfficiency); + mHist2D[H2DPedestalNPeaksMapM2 + relId[0] - 2] + ->SetBinContent(relId[1] + 1, relId[2] + 1, numberOfPeaks); mHist1D[H1DPedestalValueM2 + relId[0] - 2]->Fill(pedestalValue); mHist1D[H1DPedestalSigmaM2 + relId[0] - 2]->Fill(pedestalSigma); mHist1D[H1DPedestalEfficiencyM2 + relId[0] - 2]->Fill(pedestalEfficiency); - } //show some info to developer - ILOG(Info, Devel) << "fillHistograms() : N events = " << mNEvents << ENDM; + ILOG(Info, Devel) << "fillHistograms() : at this time, N events = " << mNEventsTotal << ENDM; + LOG(INFO) << "fillPedestals() : I finished filling of histograms"; } - + void PedestalTask::resetHistograms() { // clean all histograms ILOG(Info, Support) << "Resetting amplitude histograms" << ENDM; - for (int i = 0; i < kNChannels; i++){ + for (int i = 0; i < kNChannels; i++) { mHistAmplitudes[i]->Reset(); + mIsUpdatedAmplitude[i] = false; } ILOG(Info, Support) << "Resetting the 1D Histograms" << ENDM; - for (int itHist1D = H1DInputPayloadSize; itHist1D < kNHist1D; itHist1D++){ + for (int itHist1D = H1DInputPayloadSize; itHist1D < kNHist1D; itHist1D++) { mHist1D[itHist1D]->Reset(); } - + ILOG(Info, Support) << "Resetting the 2D Histograms" << ENDM; - for (int itHist2D = H2DErrorType; itHist2D < kNHist2D; itHist2D++){ + for (int itHist2D = H2DErrorType; itHist2D < kNHist2D; itHist2D++) { mHist2D[itHist2D]->Reset(); } } - + } // namespace o2::quality_control_modules::cpv From 0ff356ac721fe0669fd64664f8ad2bbfc5255c57 Mon Sep 17 00:00:00 2001 From: sevdokim Date: Thu, 1 Apr 2021 21:18:23 +0200 Subject: [PATCH 3/4] Applied clang-format to files. --- Modules/CPV/src/PedestalTask.cxx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Modules/CPV/src/PedestalTask.cxx b/Modules/CPV/src/PedestalTask.cxx index 36a55027b6..370a05f189 100644 --- a/Modules/CPV/src/PedestalTask.cxx +++ b/Modules/CPV/src/PedestalTask.cxx @@ -381,7 +381,7 @@ void PedestalTask::fillHistograms() double *xPeaks, yPeaks[5]; // arrays of x-position of the peaks and their heights //first, reset pedestal histograms - for (int mod = 0; mod < 3; mod++){ + for (int mod = 0; mod < 3; mod++) { mHist2D[H2DPedestalNPeaksMapM2 + mod]->Reset(); mHist2D[H2DPedestalValueMapM2 + mod]->Reset(); mHist2D[H2DPedestalSigmaMapM2 + mod]->Reset(); @@ -389,7 +389,6 @@ void PedestalTask::fillHistograms() mHist1D[H1DPedestalValueM2 + mod]->Reset(); mHist1D[H1DPedestalSigmaM2 + mod]->Reset(); mHist1D[H1DPedestalEfficiencyM2 + mod]->Reset(); - } //then fill them with actual values @@ -424,8 +423,8 @@ void PedestalTask::fillHistograms() } else { if (numberOfPeaks > 1) { // >1 peaks, no fit. Just use mean and stddev as ped value & sigma pedestalValue = mHistAmplitudes[channel]->GetMean(); - if(pedestalValue > 0) - pedestalValue = -pedestalValue;//let it be negative so we can know it's bad later + if (pedestalValue > 0) + pedestalValue = -pedestalValue; //let it be negative so we can know it's bad later pedestalSigma = mHistAmplitudes[channel]->GetStdDev(); //let's publish this bad amplitude if (!getObjectsManager()->isBeingPublished(mHistAmplitudes[channel]->GetName())) { @@ -436,7 +435,7 @@ void PedestalTask::fillHistograms() if (!getObjectsManager()->isBeingPublished(mHistAmplitudes[channel]->GetName())) { getObjectsManager()->startPublishing(mHistAmplitudes[channel]); } - continue; + continue; } } From 7fa8973e5547ee5368ae3b0b6db54504da6c15bd Mon Sep 17 00:00:00 2001 From: sevdokim Date: Sun, 4 Apr 2021 16:57:39 +0200 Subject: [PATCH 4/4] fix in Modules/CPV/CMakeLists.txt --- Modules/CPV/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CPV/CMakeLists.txt b/Modules/CPV/CMakeLists.txt index 61723d0274..bc2efb053e 100644 --- a/Modules/CPV/CMakeLists.txt +++ b/Modules/CPV/CMakeLists.txt @@ -10,7 +10,7 @@ target_include_directories( $ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) -target_link_libraries(QcCPV PUBLIC QualityControl O2::CPVBase ROOT::Spectrum) +target_link_libraries(QcCPV PUBLIC O2QualityControl O2::CPVBase ROOT::Spectrum) install(TARGETS QcCPV LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}