diff --git a/Modules/FIT/FV0/CMakeLists.txt b/Modules/FIT/FV0/CMakeLists.txt index 23355145e7..d31b9d5d88 100644 --- a/Modules/FIT/FV0/CMakeLists.txt +++ b/Modules/FIT/FV0/CMakeLists.txt @@ -9,7 +9,8 @@ target_sources(O2QcFV0 PRIVATE src/TH1ReductorLaser.cxx src/CFDEffCheck.cxx src/PostProcTask.cxx src/OutOfBunchCollCheck.cxx - src/TriggersSwVsTcmCheck.cxx) + src/TriggersSwVsTcmCheck.cxx + src/OutOfBunchCollFeeModulesCheck.cxx) target_include_directories( O2QcFV0 @@ -37,6 +38,7 @@ add_root_dictionary(O2QcFV0 include/FV0/OutOfBunchCollCheck.h include/FV0/GenericCheck.h include/FV0/TriggersSwVsTcmCheck.h + include/FV0/OutOfBunchCollFeeModulesCheck.h LINKDEF include/FV0/LinkDef.h) install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/FV0 diff --git a/Modules/FIT/FV0/include/FV0/LinkDef.h b/Modules/FIT/FV0/include/FV0/LinkDef.h index c070f5164f..69751a9930 100644 --- a/Modules/FIT/FV0/include/FV0/LinkDef.h +++ b/Modules/FIT/FV0/include/FV0/LinkDef.h @@ -9,6 +9,7 @@ #pragma link C++ class o2::quality_control_modules::fv0::OutOfBunchCollCheck + ; #pragma link C++ class o2::quality_control_modules::fv0::GenericCheck + ; #pragma link C++ class o2::quality_control_modules::fv0::TriggersSwVsTcmCheck + ; +#pragma link C++ class o2::quality_control_modules::fv0::OutOfBunchCollFeeModulesCheck + ; //#pragma link C++ class o2::quality_control_modules::fv0::CalibrationTask + ; //#pragma link C++ class o2::quality_control_modules::fv0::ChannelTimeCalibrationCheck + ; diff --git a/Modules/FIT/FV0/include/FV0/OutOfBunchCollFeeModulesCheck.h b/Modules/FIT/FV0/include/FV0/OutOfBunchCollFeeModulesCheck.h new file mode 100644 index 0000000000..3d35dd3150 --- /dev/null +++ b/Modules/FIT/FV0/include/FV0/OutOfBunchCollFeeModulesCheck.h @@ -0,0 +1,52 @@ +// Copyright 2023 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 OutOfBunchCollFeeModulesCheck.h +/// \author Dawid Skora dawid.mateusz.skora@cern.ch +/// + +#ifndef QC_MODULE_FV0_OUTOFBUNCHCOLLFEEMODULESCHECK_H +#define QC_MODULE_FV0_OUTOFBUNCHCOLLFEEMODULESCHECK_H + +#include "QualityControl/CheckInterface.h" + +#include "FV0Base/Constants.h" +#include "CommonConstants/LHCConstants.h" + +#include + +namespace o2::quality_control_modules::fv0 +{ + +class OutOfBunchCollFeeModulesCheck : public o2::quality_control::checker::CheckInterface +{ + public: + OutOfBunchCollFeeModulesCheck() = default; + ~OutOfBunchCollFeeModulesCheck() override = default; + + void configure() override; + Quality check(std::map>* moMap) override; + void beautify(std::shared_ptr mo, Quality checkResult = Quality::Null) override; + std::string getAcceptedType() override; + + ClassDefOverride(OutOfBunchCollFeeModulesCheck, 2); + + private: + float mThreshWarning; + float mThreshError; + float mFractionOutOfBunchColl = 0; + constexpr static std::size_t sBCperOrbit = o2::constants::lhc::LHCMaxBunches; +}; + +} // namespace o2::quality_control_modules::fv0 + +#endif // QC_MODULE_FV0_OUTOFBUNCHCOLLFEEMODULESCHECK_H diff --git a/Modules/FIT/FV0/include/FV0/PostProcTask.h b/Modules/FIT/FV0/include/FV0/PostProcTask.h index d4d1c3b3fd..998f713976 100644 --- a/Modules/FIT/FV0/include/FV0/PostProcTask.h +++ b/Modules/FIT/FV0/include/FV0/PostProcTask.h @@ -29,6 +29,8 @@ #include #include #include +#include +#include class TH1F; class TCanvas; @@ -87,9 +89,15 @@ class PostProcTask final : public quality_control::postprocessing::PostProcessin // if storage size matters it can be replaced with TH1 // and TH2 can be created based on it on the fly, but only TH1 would be stored std::unique_ptr mHistBcPattern; + std::unique_ptr mHistBcPatternFee; std::unique_ptr mHistBcTrgOutOfBunchColl; + std::unique_ptr mHistBcFeeOutOfBunchColl; + uint8_t mTCMhash; + std::array mChID2PMhash; // map chID->hashed PM value + std::map mMapPMhash2isInner; std::map mMapTrgHistBC; + std::map mMapFEE2hash; }; } // namespace o2::quality_control_modules::fv0 diff --git a/Modules/FIT/FV0/src/OutOfBunchCollFeeModulesCheck.cxx b/Modules/FIT/FV0/src/OutOfBunchCollFeeModulesCheck.cxx new file mode 100644 index 0000000000..6da41c79cb --- /dev/null +++ b/Modules/FIT/FV0/src/OutOfBunchCollFeeModulesCheck.cxx @@ -0,0 +1,160 @@ +// Copyright 2023 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 OutOfBunchCollFeeModulesCheck.cxx +/// \author Dawid Skora dawid.mateusz.skora@cern.ch +/// + +#include "FV0/OutOfBunchCollFeeModulesCheck.h" +#include "QualityControl/MonitorObject.h" +#include "QualityControl/Quality.h" +#include "QualityControl/QcInfoLogger.h" +#include "DataFormatsParameters/GRPLHCIFData.h" + +// ROOT +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace o2::quality_control; + +namespace o2::quality_control_modules::fv0 +{ + +void OutOfBunchCollFeeModulesCheck::configure() +{ + if (auto param = mCustomParameters.find("thresholdWarning"); param != mCustomParameters.end()) { + mThreshWarning = stof(param->second); + ILOG(Debug, Support) << "configure() : using thresholdWarning = " << mThreshWarning << ENDM; + } else { + mThreshWarning = 1e-3; + ILOG(Debug, Support) << "configure() : using default thresholdWarning = " << mThreshWarning << ENDM; + } + + if (auto param = mCustomParameters.find("thresholdError"); param != mCustomParameters.end()) { + mThreshError = stof(param->second); + ILOG(Debug, Support) << "configure() : using thresholdError = " << mThreshError << ENDM; + } else { + mThreshError = 0.1; + ILOG(Debug, Support) << "configure() : using default thresholdError = " << mThreshError << ENDM; + } + + if (mThreshError < mThreshWarning) { + ILOG(Debug, Support) << "thresholdError lower than thresholdWarning. Swaping values." << ENDM; + std::swap(mThreshError, mThreshWarning); + } +} + +Quality OutOfBunchCollFeeModulesCheck::check(std::map>* moMap) +{ + Quality result = Quality::Null; + + for (auto& [moName, mo] : *moMap) { + (void)moName; + if (mo->getName() == "OutOfBunchColl_BCvsFeeModules") { + auto* histogram = dynamic_cast(mo->getObject()); + + if (!histogram) { + ILOG(Error, Support) << "check(): MO " << mo->getName() << " not found" << ENDM; + result.addReason(FlagReasonFactory::Unknown(), "MO " + mo->getName() + " not found"); + result.set(Quality::Null); + return result; + } + + std::vector allCollPerFeeModule(mo->getMetadataMap().size() + 1, 0); + for (auto metainfo : mo->getMetadataMap()) { + int bin = 0; + float value = 0; + try { + bin = std::stoi(metainfo.first); + value = std::stof(metainfo.second); + allCollPerFeeModule[bin] = value; + } catch (const std::invalid_argument& e) { + ILOG(Warning, Support) << "Could not get value for key " << metainfo.first << ENDM; + continue; + } + } + + // Calculate out-of-bunch-coll fraction for Fee Modules + for (int binY = 1; binY <= histogram->GetNbinsY(); binY++) { + auto outOfBcCollisions = histogram->Integral(1, sBCperOrbit, binY, binY); + float fraction = 0; + if (allCollPerFeeModule[binY]) { + fraction = outOfBcCollisions / allCollPerFeeModule[binY]; + } + + if (fraction > mFractionOutOfBunchColl) { + mFractionOutOfBunchColl = fraction; + } + } + + // Check the biggest fraction of out-of-bunch-coll + if (mFractionOutOfBunchColl > mThreshError) { + result.set(Quality::Bad); + result.addReason(FlagReasonFactory::Unknown(), + Form("Fraction of out of bunch collisions (%.2e) is above \"Error\" threshold (%.2e)", + mFractionOutOfBunchColl, mThreshError)); + } else if (mFractionOutOfBunchColl > mThreshWarning) { + result.set(Quality::Medium); + result.addReason(FlagReasonFactory::Unknown(), + Form("Fraction of out of bunch collisions (%.2e) is above \"Warning\" threshold (%.2e)", + mFractionOutOfBunchColl, mThreshWarning)); + } else { + result.set(Quality::Good); + } + } + } + + return result; +} + +std::string OutOfBunchCollFeeModulesCheck::getAcceptedType() { return "TH2"; } + +void OutOfBunchCollFeeModulesCheck::beautify(std::shared_ptr mo, Quality checkResult) +{ + if (mo->getName() == "OutOfBunchColl_BCvsFeeModules") { + auto* histogram = dynamic_cast(mo->getObject()); + + if (!histogram) { + ILOG(Error, Support) << "beautify(): MO " << mo->getName() << " not found" << ENDM; + return; + } + + TPaveText* msg = new TPaveText(0.1, 0.85, 0.9, 0.9, "NDC"); + histogram->GetListOfFunctions()->Add(msg); + msg->SetName(Form("%s_msg", mo->GetName())); + msg->Clear(); + if (checkResult.isWorseThan(Quality::Good)) { + msg->AddText(checkResult.getReasons()[0].second.c_str()); + } + int color = kWhite; + if (checkResult == Quality::Good) { + color = kGreen + 1; + msg->AddText(">> Quality::Good <<"); + } else if (checkResult == Quality::Medium) { + color = kOrange - 1; + msg->AddText(">> Quality::Medium <<"); + } else if (checkResult == Quality::Bad) { + color = kRed; + msg->AddText(">> Quality::Bad <<"); + } + msg->SetFillColor(color); + } +} + +} // namespace o2::quality_control_modules::fv0 diff --git a/Modules/FIT/FV0/src/PostProcTask.cxx b/Modules/FIT/FV0/src/PostProcTask.cxx index 48bf05ddce..4cac9759a0 100644 --- a/Modules/FIT/FV0/src/PostProcTask.cxx +++ b/Modules/FIT/FV0/src/PostProcTask.cxx @@ -18,6 +18,7 @@ #include "QualityControl/QcInfoLogger.h" #include "CommonConstants/LHCConstants.h" #include "DataFormatsParameters/GRPLHCIFData.h" +#include "DataFormatsFV0/LookUpTable.h" #include #include @@ -25,6 +26,8 @@ #include #include #include +#include +#include using namespace o2::quality_control::postprocessing; @@ -175,11 +178,52 @@ void PostProcTask::initialize(Trigger, framework::ServiceRegistryRef services) getObjectsManager()->startPublishing(pairHistBC.first->second); } } + + const auto& lut = o2::fv0::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 = mMapFEE2hash.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_FV0_PLUSREF) { + mChID2PMhash[chID] = mMapFEE2hash[moduleName]; + } else { + ILOG(Error, Support) << "Incorrect LUT entry: chID " << strChID << " | " << moduleName << ENDM; + } + } else if (moduleType != "TCM") { + ILOG(Error, Support) << "Non-TCM module w/o numerical chID: chID " << strChID << " | " << moduleName << ENDM; + } else if (moduleType == "TCM") { + uint8_t mTCMhash = mMapFEE2hash[moduleName]; + } + } + + mHistBcPatternFee = std::make_unique("bcPatternForFeeModules", "BC pattern", sBCperOrbit, 0, sBCperOrbit, 13, 0, 13); + mHistBcFeeOutOfBunchColl = std::make_unique("OutOfBunchColl_BCvsFeeModules", "BC vs FEE Modules for out-of-bunch collisions;BC;FEE Modules", sBCperOrbit, 0, sBCperOrbit, mMapFEE2hash.size(), 0, mMapFEE2hash.size()); + + for (const auto& entry : mMapFEE2hash) { + // ILOG(Warning, Support) << "============= mMapFEE2hash.second + 1: " << entry.second + 1 + // << " mMapFEE2hash.first.c_str(): " << entry.first.c_str() << ENDM; + + mHistBcPatternFee->GetYaxis()->SetBinLabel(entry.second + 1, entry.first.c_str()); + mHistBcFeeOutOfBunchColl->GetYaxis()->SetBinLabel(entry.second + 1, entry.first.c_str()); + } getObjectsManager()->startPublishing(mHistTriggers.get()); getObjectsManager()->startPublishing(mHistBcPattern.get()); getObjectsManager()->setDefaultDrawOptions(mHistBcPattern.get(), "COLZ"); getObjectsManager()->startPublishing(mHistBcTrgOutOfBunchColl.get()); getObjectsManager()->setDefaultDrawOptions(mHistBcTrgOutOfBunchColl.get(), "COLZ"); + getObjectsManager()->startPublishing(mHistBcPatternFee.get()); + getObjectsManager()->setDefaultDrawOptions(mHistBcPatternFee.get(), "COLZ"); + getObjectsManager()->startPublishing(mHistBcFeeOutOfBunchColl.get()); + getObjectsManager()->setDefaultDrawOptions(mHistBcFeeOutOfBunchColl.get(), "COLZ"); mHistTimeUpperFraction = std::make_unique("TimeUpperFraction", "Fraction of events under time window(-+190 channels);ChID;Fraction", sNCHANNELS_FV0_PLUSREF, 0, sNCHANNELS_FV0_PLUSREF); getObjectsManager()->startPublishing(mHistTimeUpperFraction.get()); @@ -348,13 +392,13 @@ void PostProcTask::update(Trigger t, framework::ServiceRegistryRef) mTime->GetYaxis()->SetTitleOffset(1); } + // Download BCvsTriggers auto moBCvsTriggers = mDatabase->retrieveMO(mPathDigitQcTask, "BCvsTriggers", t.timestamp, t.activity); auto hBcVsTrg = moBCvsTriggers ? dynamic_cast(moBCvsTriggers->getObject()) : nullptr; if (!hBcVsTrg) { ILOG(Error, Support) << "MO \"BCvsTriggers\" NOT retrieved!!!" << ENDM; return; } - for (const auto& entry : mMapTrgHistBC) { hBcVsTrg->ProjectionX(entry.second->GetName(), entry.first + 1, entry.first + 1); } @@ -380,6 +424,7 @@ void PostProcTask::update(Trigger t, framework::ServiceRegistryRef) } } + // Download bcPattern std::map metadata; std::map headers; auto* lhcIf = mCcdbApi.retrieveFromTFileAny(mPathGrpLhcIf, metadata, ts, &headers); @@ -397,6 +442,45 @@ void PostProcTask::update(Trigger t, framework::ServiceRegistryRef) } auto bcPattern = lhcIf->getBunchFilling(); + // Download histogram BCvsFEEmodules from database + auto moBcVsFeeModules = mDatabase->retrieveMO(mPathDigitQcTask, "BCvsFEEmodules", t.timestamp, t.activity); + auto hBcVsFeeModules = moBcVsFeeModules ? dynamic_cast(moBcVsFeeModules->getObject()) : nullptr; + + if (!hBcVsFeeModules) { + ILOG(Error, Support) << "MO \"BCvsFEEmodules\" NOT retrieved!!!" << ENDM; + return; + } else { + + // Create histogram with bc pattern for FEE modules + mHistBcPatternFee->Reset(); + for (int i = 0; i < sBCperOrbit + 1; i++) { + for (int j = 0; j < mMapFEE2hash.size() + 1; j++) { + mHistBcPatternFee->SetBinContent(i + 1, j + 1, bcPattern.testBC(i)); + } + } + ILOG(Warning, Support) << " mHistBcPatternFee->Integral: " << mHistBcPatternFee->Integral(1, sBCperOrbit, 1, mMapFEE2hash.size()) << ENDM; + + mHistBcFeeOutOfBunchColl->Reset(); + float vmax = hBcVsFeeModules->GetBinContent(hBcVsFeeModules->GetMaximumBin()); + mHistBcFeeOutOfBunchColl->Add(hBcVsFeeModules, mHistBcPatternFee.get(), 1, -1 * vmax); + + for (int i = 0; i < sBCperOrbit + 1; i++) { + for (int j = 0; j < mMapFEE2hash.size() + 1; j++) { + if (mHistBcFeeOutOfBunchColl->GetBinContent(i + 1, j + 1) < 0) { + mHistBcFeeOutOfBunchColl->SetBinContent(i + 1, j + 1, 0); + } + } + } + + // Add metadata to histogram OutOfBunchColl_BCvsFeeModules + mHistBcFeeOutOfBunchColl->SetEntries(mHistBcFeeOutOfBunchColl->Integral(1, sBCperOrbit, 1, mMapFEE2hash.size())); + for (int iBin = 1; iBin <= mMapFEE2hash.size(); iBin++) { + const std::string metadataKey = std::to_string(iBin); + const std::string metadataValue = std::to_string(hBcVsFeeModules->Integral(1, sBCperOrbit, iBin, iBin)); + getObjectsManager()->getMonitorObject(mHistBcFeeOutOfBunchColl->GetName())->addOrUpdateMetadata(metadataKey, metadataValue); + } + } + mHistBcPattern->Reset(); for (int i = 0; i < sBCperOrbit + 1; i++) { for (int j = 0; j < mMapDigitTrgNames.size() + 1; j++) { @@ -410,10 +494,11 @@ void PostProcTask::update(Trigger t, framework::ServiceRegistryRef) for (int i = 0; i < sBCperOrbit + 1; i++) { for (int j = 0; j < mMapDigitTrgNames.size() + 1; j++) { if (mHistBcTrgOutOfBunchColl->GetBinContent(i + 1, j + 1) < 0) { - mHistBcTrgOutOfBunchColl->SetBinContent(i + 1, j + 1, 0); // is it too slow? + mHistBcTrgOutOfBunchColl->SetBinContent(i + 1, j + 1, 0); } } } + mHistBcTrgOutOfBunchColl->SetEntries(mHistBcTrgOutOfBunchColl->Integral(1, sBCperOrbit, 1, mMapDigitTrgNames.size())); for (int iBin = 1; iBin < mMapDigitTrgNames.size() + 1; iBin++) { const std::string metadataKey = "BcVsTrgIntegralBin" + std::to_string(iBin);