diff --git a/DataQuality/dqm_algorithms/dqm_algorithms/LastBinThresholdAction.h b/DataQuality/dqm_algorithms/dqm_algorithms/LastBinThresholdAction.h new file mode 100644 index 0000000000000000000000000000000000000000..8e25fd315d9f7c97389090b7c29f05c92ad84db1 --- /dev/null +++ b/DataQuality/dqm_algorithms/dqm_algorithms/LastBinThresholdAction.h @@ -0,0 +1,62 @@ +/* +Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef DQM_ALGORITHMS_LASTBINTHRESHOLDACTION_H +#define DQM_ALGORITHMS_LASTBINTHRESHOLDACTION_H + +#include <dqm_core/Algorithm.h> + +namespace dqm_algorithms { + + class LessThan { + public: + bool operator() (double a, double b, double /*error = 0.*/) const { + return a < b; + } + }; + + class GreaterThan { + public: + bool operator() (double a, double b, double /*error = 0.*/) const { + return a > b; + } + }; + + class DifferentThan { + public: + bool operator() (double a, double b, double error = 0.) const { + return std::abs(a - b) > error; + } + }; + + class NoAction { + public: + void operator() (const std::string&, std::string&, double, double) const {} + }; + + class TileDQAction { + public: + void operator() (const std::string& histogramName, std::string action, + double averageBinContent, double lastBinContent) const; + }; + + template<class Exceed, class Action> + class LastBinThresholdAction : public dqm_core::Algorithm { + public: + LastBinThresholdAction(const std::string & name); + + // Overwrites virtual functions + virtual LastBinThresholdAction* clone( ) override; + virtual dqm_core::Result* execute( const std::string& , const TObject& , const dqm_core::AlgorithmConfig& ) override; + using dqm_core::Algorithm::printDescription; + virtual void printDescription(std::ostream& out) const; + + private: + std::string m_name; + Exceed m_exceeds; + Action m_doAction; + }; +} + +#endif // DQM_ALGORITHMS_LASTBINTHRESHOLDACTION_H diff --git a/DataQuality/dqm_algorithms/dqm_algorithms/dqm_algorithmsDict.h b/DataQuality/dqm_algorithms/dqm_algorithms/dqm_algorithmsDict.h index 11f524549c01043562ae1a5b8e38d780bddd236a..840bf73b5e8a8668ad84d16cb998ac6e20887f59 100644 --- a/DataQuality/dqm_algorithms/dqm_algorithms/dqm_algorithmsDict.h +++ b/DataQuality/dqm_algorithms/dqm_algorithms/dqm_algorithmsDict.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration */ #ifndef DQM_ALGORITHMS_DQM_ALGORITHMSDICT_H @@ -158,5 +158,5 @@ #include "dqm_algorithms/TRTCheckPeakSimple.h" #include "dqm_algorithms/TRTHistogramHasNonZeroEntries.h" #include "dqm_algorithms/TripleGaussCollFit.h" - +#include "dqm_algorithms/LastBinThresholdAction.h" #endif // DQM_ALGORITHMS_DQM_ALGORITHMSDICT_H diff --git a/DataQuality/dqm_algorithms/dqm_algorithms/selection.xml b/DataQuality/dqm_algorithms/dqm_algorithms/selection.xml index 81a54ea9f04b5cc65881c30d3863614628bbb5bc..36778865916ca4cdd1a3073aba87cf069c04bde0 100644 --- a/DataQuality/dqm_algorithms/dqm_algorithms/selection.xml +++ b/DataQuality/dqm_algorithms/dqm_algorithms/selection.xml @@ -104,6 +104,10 @@ <class name="dqm_algorithms::KurtosisTest_LessThan"/> <class name="dqm_algorithms::KurtosisTest_LessThanAbs"/> <class name="dqm_algorithms::LastBinThreshold"/> + <class name="dqm_algorithms::LastBinThresholdAction<dqm_algorithms::LessThan,dqm_algorithms::NoAction>"/> + <class name="dqm_algorithms::LastBinThresholdAction<dqm_algorithms::GreaterThan,dqm_algorithms::NoAction>"/> + <class name="dqm_algorithms::LastBinThresholdAction<dqm_algorithms::DifferentThan,dqm_algorithms::NoAction>"/> + <class name="dqm_algorithms::LastBinThresholdAction<dqm_algorithms::DifferentThan,dqm_algorithms::TileDQAction>"/> <class name="dqm_algorithms::L1Calo_OutlierAndFlatnessTest"/> <class name="dqm_algorithms::MDTADCSpectrum"/> <class name="dqm_algorithms::MDTChi2"/> @@ -149,6 +153,7 @@ <class name="dqm_algorithms::SkewnessTest_GreaterThanAbs"/> <class name="dqm_algorithms::SkewnessTest_LessThan"/> <class name="dqm_algorithms::SkewnessTest_LessThanAbs"/> + <class name="dqm_algorithms::TileDQAction"/> <class name="dqm_algorithms::TRTCheckPeakSimple"/> <class name="dqm_algorithms::TRTHistogramHasNonZeroEntries"/> <class name="dqm_algorithms::TripleGaussCollFit"/> diff --git a/DataQuality/dqm_algorithms/src/LastBinThresholdAction.cxx b/DataQuality/dqm_algorithms/src/LastBinThresholdAction.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a4a9e6e0fbd1983288d89ca507675a2a8cee2c0a --- /dev/null +++ b/DataQuality/dqm_algorithms/src/LastBinThresholdAction.cxx @@ -0,0 +1,203 @@ +/* +Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +#include <dqm_core/AlgorithmConfig.h> +#include <dqm_algorithms/LastBinThresholdAction.h> +#include <dqm_algorithms/tools/AlgorithmHelper.h> +#include <TH1.h> +#include <TF1.h> +#include <TProfile.h> +#include <TClass.h> +#include <ers/ers.h> + +#include <iostream> +#include <cstdlib> +#include <regex> + +#include <dqm_core/AlgorithmManager.h> + +namespace { + + + dqm_algorithms::LastBinThresholdAction<dqm_algorithms::GreaterThan, dqm_algorithms::NoAction> + LastBinGreaterThanThreshold("LastBinGreaterThanThreshold"); + + dqm_algorithms::LastBinThresholdAction<dqm_algorithms::LessThan, dqm_algorithms::NoAction> + LastBinLessThanThreshold("LastBinLessThanThreshold"); + + dqm_algorithms::LastBinThresholdAction<dqm_algorithms::DifferentThan, dqm_algorithms::NoAction> + LastBinDifferentThanThreshold("LastBinDifferentThanThreshold"); + + dqm_algorithms::LastBinThresholdAction<dqm_algorithms::GreaterThan, dqm_algorithms::TileDQAction> + TileDataCorruptionFractionGreaterThanThreshold("TileDataCorruptionGreaterThanThreshold"); +} + +void dqm_algorithms::TileDQAction::operator() (const std::string& histogramName, std::string action, + double averageBinContent, double lastBinContent) const { + + const char* actionPath = std::getenv("TILE_DQ_ACTION_PATH"); + if (actionPath != nullptr) action = std::string(actionPath) + "/" + action; + + std::smatch match; + std::regex expression (".*([LE]B[AC]\\d\\d).*"); + + std::string module("UNKNOWN"); + if (std::regex_search(histogramName, match, expression) && match.size() > 1) { + module = match.str(1); + } + + action += " "; + action += histogramName; + action += " "; + action += module; + action += " "; + action += std::to_string(lastBinContent); + action += " "; + action += std::to_string(averageBinContent); + action += " &"; + std::system(action.c_str()); +} + + +template<class Exceed, class Action> +dqm_algorithms::LastBinThresholdAction<Exceed, Action>::LastBinThresholdAction(const std::string& name) + : m_name( name ) +{ + dqm_core::AlgorithmManager::instance().registerAlgorithm(name, this); +} + +template<class Exceed, class Action> +dqm_algorithms::LastBinThresholdAction<Exceed, Action>* +dqm_algorithms::LastBinThresholdAction<Exceed, Action>::clone() { + return new LastBinThresholdAction(m_name); +} + + +template<class Exceed, class Action> dqm_core::Result* +dqm_algorithms::LastBinThresholdAction<Exceed, Action>::execute(const std::string& name, + const TObject& object, + const dqm_core::AlgorithmConfig& config ) +{ + const TProfile* histogram; + + if( object.IsA()->InheritsFrom( "TProfile" ) ) { + histogram = dynamic_cast<const TProfile*>(&object); + if (histogram->GetDimension() > 1){ + throw dqm_core::BadConfig( ERS_HERE, name, "dimension > 2 " ); + } + } else { + throw dqm_core::BadConfig( ERS_HERE, name, "does not inherit from TProfile" ); + } + + const double minStat = dqm_algorithms::tools::GetFirstFromMap( "MinStat", config.getParameters(), -1); + const double fixedError = dqm_algorithms::tools::GetFirstFromMap( "FixedError", config.getParameters(), -1); + const bool ignoreEmpty = static_cast<bool>( dqm_algorithms::tools::GetFirstFromMap( "IgnoreEmpty", config.getParameters(), 1) ); + const bool publish = static_cast<bool>( dqm_algorithms::tools::GetFirstFromMap( "PublishBins", config.getParameters(), 0) ); + const int maxPublish = static_cast<int>( dqm_algorithms::tools::GetFirstFromMap( "MaxPublish", config.getParameters(), 20) ); + const int nBinsToWatch = static_cast<int>( dqm_algorithms::tools::GetFirstFromMap( "NBinsToWatch", config.getParameters(), -1) ); + const int nBinsForAction = static_cast<int>( dqm_algorithms::tools::GetFirstFromMap( "NBinsForAction", config.getParameters(), 99999) ); + + std::string action(""); + std::map<std::string, std::string>::const_iterator itAction = config.getGenericParameters().find("Action"); + if (itAction != config.getGenericParameters().end()) { + action = itAction->second; + } + + if (histogram->GetEntries() < minStat ) { + dqm_core::Result *result = new dqm_core::Result(dqm_core::Result::Undefined); + result->tags_["InsufficientEntries"] = histogram->GetEntries(); + return result; + } + + double binThreshold; + double greenThreshold; + double redThreshold; + try { + binThreshold = dqm_algorithms::tools::GetFirstFromMap( "BinThreshold", config.getParameters() ); + redThreshold = dqm_algorithms::tools::GetFromMap( "NBins", config.getRedThresholds() ); + greenThreshold = dqm_algorithms::tools::GetFromMap( "NBins", config.getGreenThresholds() ); + } catch ( dqm_core::Exception & ex ) { + throw dqm_core::BadConfig( ERS_HERE, name, ex.what(), ex ); + } + + dqm_core::Result* result = new dqm_core::Result(); + + int nBinsOverThreshold = 0; + + int firstBin = 1; + int lastBin = histogram->GetNbinsX(); + + if (nBinsToWatch > 0) { + while ((histogram->GetBinEntries(lastBin) == 0) && (lastBin > 1)) --lastBin; + firstBin = (lastBin > nBinsToWatch) ? (lastBin - nBinsToWatch + 1) : 1; + + result->tags_["LastBinNumber"] = lastBin; // report where we began the checks (mostly for debugging) + result->tags_["LastBinCenter"] = histogram->GetBinCenter(lastBin); // report where that is on the x-axis + } + + double lastBinOverThresholdContent(0.0); + double binsOverThresholdContent(0.0); + + for (int bin = firstBin; bin <= lastBin; ++bin) { + if (ignoreEmpty && (histogram->GetBinEntries(bin) == 0)) { + continue; + } + double content = histogram->GetBinContent(bin); + if (m_exceeds(content, binThreshold, fixedError)) { + ++nBinsOverThreshold; + lastBinOverThresholdContent = content; + binsOverThresholdContent += content; + if (publish && nBinsOverThreshold < maxPublish){ + dqm_algorithms::tools::PublishBin(histogram, bin, 1, content, result); + } + } + } + + ERS_DEBUG(1,"Number of bins exceeded threshold of " << binThreshold << " is " << nBinsOverThreshold ); + ERS_DEBUG(1,"Green threshold: "<< greenThreshold << " bin(s); Red threshold : " << redThreshold << " bin(s) "); + + result->tags_["NBins"] = nBinsOverThreshold; + if (greenThreshold > redThreshold) { + if (nBinsOverThreshold >= greenThreshold) { + result->status_ = dqm_core::Result::Green; + } else if (nBinsOverThreshold > redThreshold) { + result->status_ = dqm_core::Result::Yellow; + } else { + result->status_ = dqm_core::Result::Red; + } + } else { + if (nBinsOverThreshold <= greenThreshold) { + result->status_ = dqm_core::Result::Green; + } else if (nBinsOverThreshold < redThreshold) { + result->status_ = dqm_core::Result::Yellow; + } else { + result->status_ = dqm_core::Result::Red; + } + } + + if (!action.empty() && nBinsOverThreshold >= nBinsForAction) { + double averageBinContent = binsOverThresholdContent / nBinsOverThreshold; + std::string histogramName(histogram->GetName()); + m_doAction(histogramName, action, lastBinOverThresholdContent, averageBinContent); + } + + return result; + +} + +template<class Exceed, class Action> +void dqm_algorithms::LastBinThresholdAction<Exceed, Action>::printDescription(std::ostream& out) const { + + out << m_name + ": Checks for number of bins exceded threshold value" << std::endl; + out << "Mandatory Parameter: BinThreshold: Look for bins exceeded BinTreshold; Count number of bins satifying requirement" << std::endl; + out << "Mandatory Green/Red Threshold: NBins: Number of bins satifying BinThreshold constraint to give Green/Red result" << std::endl; + + out << "Optional Parameter: FixedError: override the histogram errors with this value" << std::endl; + out << "Optional Parameter: IgnoreEmpty: Ignore bins which have zero entries in histogram" << std::endl; + out << "Optional Parameter: PublishBins: Save bins which are different from average in Result (set to 1)" << std::endl; + out << "Optional Parameter: MaxPublish: Max number of bins to save (default 20)" << std::endl; + out << "Optional Parameter: MinStat: Minimum histogram statistics needed to perform Algorithm" << std::endl; + out << "Optional parameter: NBinsToWatch - number of final bins that will be checked. (NBinsToWatch >= 1, default = -1)" << std::endl; +} + diff --git a/DataQuality/dqm_algorithms/workbench/TestLastBinThresholdAction.C b/DataQuality/dqm_algorithms/workbench/TestLastBinThresholdAction.C new file mode 100644 index 0000000000000000000000000000000000000000..c4f8963930caef99f0d1c7b90749401ad4761da6 --- /dev/null +++ b/DataQuality/dqm_algorithms/workbench/TestLastBinThresholdAction.C @@ -0,0 +1,143 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +void printHistogram(const TH1* histogam, std::string name) { + std::cout << "===========> BEGIN Histogram: " << name << " <============" << std::endl; + histogam->Print("All"); + std::cout << "------------> END Histogram: " << name << " <--------------" << std::endl; +} + +template<class Exceed> +bool testLastBinThresholdNoAction(std::string name, double value, std::array<double, 3> badValues, double error = -999.) { + using LastBinThresholdNoAction = dqm_algorithms::LastBinThresholdAction<Exceed,dqm_algorithms::NoAction>; + auto algorithm = new LastBinThresholdNoAction(name); + + std::unique_ptr<TProfile> histogram(new TProfile("histogram", "Simple Profile", 5, 0, 5)); + histogram->SetDirectory(0); + for (int i = 0; i < 3; ++i) { + histogram->Fill(i, value); + } + + std::unique_ptr<dqm_core::test::DummyAlgorithmConfig> config(new dqm_core::test::DummyAlgorithmConfig()); + + config->addParameter("NBinsToWatch", 3); + config->addParameter("BinThreshold", value); + if (error > 0.) { + config->addParameter("FixedError", error); + } + + // Threshold for number of bins aways from threshold + config->addGreenThreshold("NBins", 1); + config->addRedThreshold("NBins", 3); + + std::cout << "Config [" << name << "]: "; + config->print(std::cout); + + bool isTestOk = true; + + std::cout << std::endl << std::endl; + histogram->Fill(0., badValues[0]); + printHistogram(histogram.get(), "Green"); + std::unique_ptr<dqm_core::Result> greenResult(algorithm->execute( "test", *histogram, *config)); + std::cout << "Result: " << *(greenResult.get()) << std::endl; + isTestOk &= (greenResult->status_ == dqm_core::Result::Green); + + std::cout << std::endl; + histogram->Fill(1., badValues[1]); + printHistogram(histogram.get(), "Yellow"); + std::unique_ptr<dqm_core::Result> yellowResult(algorithm->execute( "test", *histogram, *config)); + std::cout << "Result: " << *(yellowResult.get()) << std::endl; + isTestOk &= (yellowResult->status_ == dqm_core::Result::Yellow); + + std::cout << std::endl; + histogram->Fill(2., badValues[2]); + printHistogram(histogram.get(), "Red"); + std::unique_ptr<dqm_core::Result> redResult(algorithm->execute( "test", *histogram, *config)); + std::cout << "Result: " << *(redResult.get()) << std::endl; + isTestOk &= (redResult->status_ == dqm_core::Result::Red); + + return isTestOk; +} + + + +bool testTileDataCorruption(std::string name, double value, std::array<double, 3> badValues) { + using TileDataCorruption = dqm_algorithms::LastBinThresholdAction<dqm_algorithms::GreaterThan,dqm_algorithms::TileDQAction>; + auto algorithm = new TileDataCorruption(name); + + std::unique_ptr<TProfile> histogram(new TProfile("TileDigiErrFracLBA56", "Simple Profile", 5, 0, 5)); + histogram->SetDirectory(0); + for (int i = 0; i < 4; ++i) { + histogram->Fill(i, value); + } + + std::unique_ptr<dqm_core::test::DummyAlgorithmConfig> config(new dqm_core::test::DummyAlgorithmConfig()); + + config->addParameter("NBinsToWatch", 3); + config->addParameter("BinThreshold", value); + config->addParameter("NBinsForAction", 3); + config->addGenericParameter("Action", "echo"); + + // Threshold for number of bins aways from threshold + config->addGreenThreshold("NBins", 1); + config->addRedThreshold("NBins", 4); // Given NBins > NBinsToWatch, do not give red status + + std::cout << "Config [" << name << "]: "; + config->print(std::cout); + + bool isTestOk = true; + + std::cout << std::endl << std::endl; + histogram->Fill(1., badValues[0]); + histogram->Fill(2., badValues[1]); + histogram->Fill(3., badValues[2]); + printHistogram(histogram.get(), "Yellow"); + std::unique_ptr<dqm_core::Result> yellowResult(algorithm->execute( "test", *histogram, *config)); + std::cout << "Result: " << *(yellowResult.get()) << std::endl; + isTestOk &= (yellowResult->status_ == dqm_core::Result::Yellow); + + return isTestOk; +} + + + + +void printTestStatus(std::string test, bool isTestOk) { + std::cout << "------------------------------------------------------------" << std::endl; + std::cout << "TEST [" << test << "]:\t" << (isTestOk ? "PASSED" : "FAILED") << std::endl; + std::cout << "------------------------------------------------------------" << std::endl; +} + +void TestLastBinThresholdAction(void) { + + bool isAllTestOk = true; + + std::string test = "LastBinLessThanThreshold"; + std::cout << std::endl << "=== >>> TEST: " << test << " <<< ===" << std::endl; + bool isTestOk = testLastBinThresholdNoAction<dqm_algorithms::LessThan>(test, 100., {10., 20., 30.}); + printTestStatus(test, isTestOk); + isAllTestOk &= isTestOk; + + test = "LastBinGreaterThanThreshold"; + std::cout << std::endl << "=== >>> TEST: " << test << " <<< ===" << std::endl; + isTestOk = testLastBinThresholdNoAction<dqm_algorithms::GreaterThan>(test, 100., {200., 300., 400.}); + printTestStatus(test, isTestOk); + isAllTestOk &= isTestOk; + + test = "LastBinDifferentThanThreshold"; + std::cout << std::endl << "=== >>> TEST: " << test << " <<< ===" << std::endl; + isTestOk = testLastBinThresholdNoAction<dqm_algorithms::DifferentThan>(test, 100., {10., 200., 50.}, 10); + printTestStatus(test, isTestOk); + isAllTestOk &= isTestOk; + + test = "TileDataCorruptionThanThreshold"; + std::cout << std::endl << "=== >>> TEST: " << test << " <<< ===" << std::endl; + isTestOk = testTileDataCorruption(test, 0., {10., 10., 10.}); + printTestStatus(test, isTestOk); + isAllTestOk &= isTestOk; + + std::cout << endl; + std::cout << "===================== >>> SUMMARY <<< =====================" << std::endl; + printTestStatus("ALL", isAllTestOk); +}