ATLAS Offline Software
BinHeightThreshold.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
9 #include <dqm_core/AlgorithmConfig.h>
12 #include <TH1.h>
13 #include <TF1.h>
14 #include <TClass.h>
15 #include <ers/ers.h>
16 
17 #include <iostream>
18 #include <cmath>
19 
20 #include <dqm_core/AlgorithmManager.h>
21 
22 
23 //static dqm_algorithms::BinHeightThreshold myInstance;
24 namespace
25 {
26  dqm_algorithms::BinHeightThreshold HeightGreaterThan( "GreaterThan" );
27  dqm_algorithms::BinHeightThreshold HeightGreaterThanEqual( "GreaterThanEqual" );
28  dqm_algorithms::BinHeightThreshold HeightLessThan( "LessThan" );
29  dqm_algorithms::BinHeightThreshold HeightLessThanEqual( "LessThanEqual" );
30  dqm_algorithms::BinHeightThreshold HeightRedEqYellowGT( "redEqual_yellowGreaterThan" );
31  dqm_algorithms::BinHeightThreshold HeightRedEqYellowLT( "redEqual_yellowLessThan" );
32  dqm_algorithms::BinHeightThreshold HeightEqual( "Equal" );
33 }
34 
36  : m_name( name )
37 {
38  m_precision=1e-4;
39  dqm_core::AlgorithmManager::instance().registerAlgorithm("BinHeight_"+name+"_Threshold", this);
40 }
41 
44 {
45  return new BinHeightThreshold(m_name);
46 }
47 
48 
51  const TObject & object,
52  const dqm_core::AlgorithmConfig & config )
53 {
54  const TH1 * histogram;
55  if( object.IsA()->InheritsFrom( "TH1" ) ) {
56  histogram = static_cast<const TH1*>(&object);
57  if (histogram->GetDimension() > 2 ){
58  throw dqm_core::BadConfig( ERS_HERE, name, "dimension > 2 " );
59  }
60  } else {
61  throw dqm_core::BadConfig( ERS_HERE, name, "does not inherit from TH1" );
62  }
63  const double minstat = 1;
64  if (histogram->GetEntries() < minstat ) {
65  ERS_INFO( "Too few entries: " << histogram->GetEntries() );
67  result->tags_["InsufficientEntries"] = histogram->GetEntries();
68  return result;
69  }
70 
71  int start_from_last;
72  int n_bins;
73  int window_size;
74  double gthreshold;
75  double rthreshold;
76  std::pair<bool,double> grayValue;
77  try {
78  n_bins = dqm_algorithms::tools::GetFirstFromMap( "NBins", config.getParameters() ,1);
79  window_size = dqm_algorithms::tools::GetFirstFromMap( "WindowSize", config.getParameters() ,1);
80  start_from_last = dqm_algorithms::tools::GetFirstFromMap( "StartFromLast", config.getParameters() ,-1);
81  gthreshold = dqm_algorithms::tools::GetFromMap( "HeightThreshold", config.getGreenThresholds() );
82  rthreshold = dqm_algorithms::tools::GetFromMap( "HeightThreshold", config.getRedThresholds() );
83  }
84  catch ( dqm_core::Exception & ex ) {
85  throw dqm_core::BadConfig( ERS_HERE, name, ex.what(), ex );
86  }
87  grayValue.first=true;
88  try {
89  grayValue.second = dqm_algorithms::tools::GetFirstFromMap( "UndefinedStatus", config.getParameters() );
90  }
91  catch ( dqm_core::Exception & ex ) {
92  grayValue.first=false;
93  grayValue.second=-1;
94  }
95  try {
96  m_precision = dqm_algorithms::tools::GetFirstFromMap( "EqualityPrecision", config.getParameters(),1e-4);
97  }
98  catch ( dqm_core::Exception & ex ) {
99  m_precision=1e-4;
100  }
101 
102 
103  //check if the provided parameter values make sense
104  if(m_precision<0) {
105  ERS_INFO("'EqualityPrecision cannot be negative: it will be re-set to its absolute value.");
106  m_precision=std::abs(m_precision);
107  }
108  if(window_size<=0) {
109  ERS_INFO("You set search window size (WindowSize) <= 0: I will search the whole histogram.");
110  }
111  else {
112  if(n_bins>window_size) {
113  ERS_INFO("You set the minimum number of bins for throwing error/warning (NBins) larger than the window size (WindowSize): in this way the algorithm can never return error/warning. Setting NBins=WindowSize.");
114  n_bins=window_size;
115  }
116  }
117  if(n_bins<=0) {
118  ERS_INFO("You set the minimum number of bins for throwing error/warning (NBins) <= 0: in this way the algorithm would always return error. Setting NBins=1 (default value).");
119  n_bins=1;
120  }
121  CheckThresholds(m_name,gthreshold,rthreshold);
122  grayValue.first=checkUndefinedStatusValue(m_name,gthreshold,rthreshold,grayValue);
123 
125  TH1* resulthisto;
126  if (histogram->InheritsFrom("TH2")) {
127  throw dqm_core::BadConfig( ERS_HERE, name, "TH2 received. This algorithm only works with TH1" );
128  } else if (histogram->InheritsFrom("TH1")) {
129  resulthisto=(TH1*)(histogram->Clone());
130  } else {
131  throw dqm_core::BadConfig( ERS_HERE, name, "does not inherit from TH1" );
132  }
133 
134  resulthisto->Reset();
135 
136 
137  //first, look for the last filled LB, i.e. the bin with nonzero content of largest x if start_from_last<0, if start_from_last>=0, then starts from last but N-th bin, where N=start_from_last
138  int i_currentLB=histogram->GetNbinsX();
139  if(start_from_last>=0)
140  i_currentLB-=start_from_last;
141  else
142  {
143  while(i_currentLB>=1)
144  {
145  if(histogram->GetBinContent(i_currentLB)!=0) break;
146  i_currentLB--;
147  }
148  }
149  //if the histogram is just empty, or still has too few bins, do nothing
150  if(i_currentLB<=0 || i_currentLB<n_bins)
151  {
152  ERS_DEBUG(1,"start_from_last parameter >= total number of bins, I just cannot do the check. Do nothing.");
153  return result;
154  }
155 
156  //now loop over an x window of size 'window_size'
157  int iLB=i_currentLB;
158  int countYellow=0;
159  int countRed=0;
160  int countGray=0;
161  while(iLB>=1 && (window_size<0 || (i_currentLB-iLB)<window_size))
162  {
163  double content=histogram->GetBinContent(iLB);
164  dqm_algorithms::BinHeightThreshold::binStatus LBstatus=CompareBinHeightThreshold(m_name,content, gthreshold , rthreshold,grayValue);
165  if(LBstatus==dqm_algorithms::BinHeightThreshold::binStatus::aYellowBin)
166  {
167  countYellow++;
168  }
169  if(LBstatus==dqm_algorithms::BinHeightThreshold::binStatus::aRedBin)
170  {
171  countRed++;
172  }
173  if(LBstatus==dqm_algorithms::BinHeightThreshold::binStatus::anUndefBin)
174  {
175  countGray++;
176  }
177  //fill result histogram
178  resulthisto->SetBinContent(iLB,content);
179  iLB--;
180  }
181 
182 
183  ERS_DEBUG(1,"Found " << countRed << " red bins and " << countYellow << " red bins. In a window of size " << window_size << " bins, starting at bin " << i_currentLB);
184  ERS_DEBUG(1,"To be compared with: " << n_bins);
185  ERS_DEBUG(1,"Green treshold=" << gthreshold << " Red threshold=" << rthreshold );
186 
187  result->tags_["NRedBins"] = countRed;
188  result->tags_["NYellowBins"] = countYellow;
189  result->object_ = (boost::shared_ptr<TObject>)(TObject*)(resulthisto);
190  if(countRed>=n_bins)
191  {
192  result->status_ = dqm_core::Result::Red;
193  }
194  else if(countRed+countYellow>=n_bins)
195  {
196  result->status_ = dqm_core::Result::Yellow;
197  }
198  else if(countGray>=n_bins)
199  {
201  }
202  else
203  {
204  result->status_ = dqm_core::Result::Green;
205  }
206 
207  return result;
208 
209 }
210 
211 
212 void dqm_algorithms::BinHeightThreshold::CheckThresholds(const std::string & type, double thresholdGr, double thresholdRed) {
213  if(type=="GreaterThan" || type=="GreaterThanEqual")
214  {
215  if(thresholdGr>=thresholdRed)
216  ERS_INFO("'BinHeight_" << type << "_Threshold' algorithm expects red > yellow > green. You set the warning threshold (" << thresholdGr << ") >= error threshold (" << thresholdRed << "): it will never return 'yellow/warning'.");
217  }
218  if(type=="LessThan" || type=="LessThanEqual")
219  {
220  if(thresholdGr<=thresholdRed)
221  ERS_INFO("'BinHeight_" << type << "_Threshold' algorithm expects red < yellow < green. You set the warning threshold (" << thresholdGr << ") <= error threshold (" << thresholdRed << "): it will never return 'yellow/warning'. Are you sure this is what you want?");
222  }
223  if(type=="redEqual_yellowGreaterThan")
224  {
225  if(thresholdRed>0 && thresholdRed<thresholdGr)
226  ERS_INFO("You set the error threshold (" << thresholdRed << ") between zero and the warning threshold (" << thresholdGr << ") in 'BinHeight_redEqual_yellowGreaterThan_Threshgold' algorithm. Are you sure this is what you want?");
227  }
228  if(type=="redEqual_yellowLessThan")
229  {
230  if(thresholdRed>thresholdGr)
231  ERS_INFO("You set the error threshold (" << thresholdRed << ") larger than the warning threshold (" << thresholdGr << ") in 'BinHeight_redEqual_yellowLessThan_Threshold' algorithm. Are you sure this is what you want?");
232  }
233 }
234 
235 bool
236 dqm_algorithms::BinHeightThreshold::checkUndefinedStatusValue(const std::string & type,double thresholdGr, double thresholdRed,std::pair<bool,double> valueGray) {
237  if(!valueGray.first)
238  return valueGray.first;
239 
240  if(type=="LessThan" || type=="GreaterThan")
241  return valueGray.first;
242 
243  if(equalWithinPrecision(valueGray.second,thresholdRed))
244  {
245  ERS_INFO("You have set 'UndefinedStatus' equal to the error threshold in 'BinHeight_" << type << "_Threshold' algorithm. Error has the precedence here: the bin content WILL NOT be checked against 'UndefinedStatus'");
246  return false;
247  }
248 
249  if(type!="redEqual_yellowLessThan" && type!="redEqual_yellowGreaterThan" && equalWithinPrecision(valueGray.second,thresholdGr))
250  {
251  ERS_INFO("You have set 'UndefinedStatus' equal to the warning threshold in 'BinHeight_" << type << "_Threshold' algorithm. Warning has the precedence here: the bin content WILL NOT be checked against 'UndefinedStatus'");
252  return false;
253  }
254 
255  return valueGray.first;
256 }
257 
258 
259 
261 dqm_algorithms::BinHeightThreshold::CompareBinHeightThreshold(const std::string & type,double bincontent, double thresholdGr, double thresholdRed,std::pair<bool,double> valueGray) {
262  if(valueGray.first)
263  {
264  if(equalWithinPrecision(bincontent,valueGray.second))
265  {
266  return dqm_algorithms::BinHeightThreshold::binStatus::anUndefBin;
267  }
268  }
269 
270  if(type=="GreaterThan")
271  {
272  if(bincontent>thresholdRed)
273  return dqm_algorithms::BinHeightThreshold::binStatus::aRedBin;
274  if(bincontent>thresholdGr)
275  return dqm_algorithms::BinHeightThreshold::binStatus::aYellowBin;
276  return dqm_algorithms::BinHeightThreshold::binStatus::aGreenBin;
277  }
278  if(type=="LessThan")
279  {
280  if(bincontent<thresholdRed)
281  return dqm_algorithms::BinHeightThreshold::binStatus::aRedBin;
282  if(bincontent<thresholdGr)
283  return dqm_algorithms::BinHeightThreshold::binStatus::aYellowBin;
284  return dqm_algorithms::BinHeightThreshold::binStatus::aGreenBin;
285  }
286  if(type=="GreaterThanEqual")
287  {
288  if(bincontent>thresholdRed || equalWithinPrecision(bincontent,thresholdRed))
289  return dqm_algorithms::BinHeightThreshold::binStatus::aRedBin;
290  if(bincontent>thresholdGr || equalWithinPrecision(bincontent,thresholdGr))
291  return dqm_algorithms::BinHeightThreshold::binStatus::aYellowBin;
292  return dqm_algorithms::BinHeightThreshold::binStatus::aGreenBin;
293  }
294  if(type=="LessThanEqual")
295  {
296  if(bincontent<thresholdRed || equalWithinPrecision(bincontent,thresholdRed))
297  return dqm_algorithms::BinHeightThreshold::binStatus::aRedBin;
298  if(bincontent<thresholdGr || equalWithinPrecision(bincontent,thresholdGr))
299  return dqm_algorithms::BinHeightThreshold::binStatus::aYellowBin;
300  return dqm_algorithms::BinHeightThreshold::binStatus::aGreenBin;
301  }
302  if(type=="redEqual_yellowGreaterThan")
303  {
304  if(equalWithinPrecision(bincontent,thresholdRed))
305  return dqm_algorithms::BinHeightThreshold::binStatus::aRedBin;
306  if(bincontent>thresholdGr)
307  return dqm_algorithms::BinHeightThreshold::binStatus::aYellowBin;
308  return dqm_algorithms::BinHeightThreshold::binStatus::aGreenBin;
309  }
310  if(type=="redEqual_yellowLessThan")
311  {
312  if(equalWithinPrecision(bincontent,thresholdRed))
313  return dqm_algorithms::BinHeightThreshold::binStatus::aRedBin;
314  if(bincontent<thresholdGr)
315  return dqm_algorithms::BinHeightThreshold::binStatus::aYellowBin;
316  return dqm_algorithms::BinHeightThreshold::binStatus::aGreenBin;
317  }
318  if(type=="Equal")
319  {
320  if(equalWithinPrecision(bincontent,thresholdRed))
321  return dqm_algorithms::BinHeightThreshold::binStatus::aRedBin;
322  if(equalWithinPrecision(bincontent,thresholdGr))
323  return dqm_algorithms::BinHeightThreshold::binStatus::aYellowBin;
324  return dqm_algorithms::BinHeightThreshold::binStatus::aGreenBin;
325  }
326  return dqm_algorithms::BinHeightThreshold::binStatus::anUndefBin;
327 }
328 
329 
330 bool
332 {
333  //relative difference method (following what suggested in (non-ATLAS) web page http://floating-point-gui.de/errors/comparison/)
334  double absA = std::abs(a);
335  double absB = std::abs(b);
336  double diff = std::abs(a - b);
337 
338  if (a == b) { // shortcut, handles infinities
339  return true;
340  }
341  else if (a == 0 || b == 0 || diff < DBL_MIN) {
342  // a or b is zero or both are extremely close to it
343  // relative error is less meaningful here
344  return diff < (m_precision * DBL_MIN);
345  }
346  else { // use relative error
347  return (diff / std::min((absA + absB), DBL_MAX)) < m_precision;
348  }
349 }
350 
351 void
353 {
354  TString redCond,yellowCond;
355  if(m_name=="redEqual_yellowGreaterThan" || m_name=="redEqual_yellowLessThan" || m_name=="Equal")
356  {
357  redCond="bin_content==redThreshold";
358  if(m_name=="Equal")
359  yellowCond="bin_content==yellowThreshold && bin_content!=redThreshold";
360  else if(m_name=="redEqual_yellowGreaterThan")
361  yellowCond="bin_content>yellowThreshold && bin_content!=redThreshold";
362  else
363  yellowCond="bin_content<yellowThreshold && bin_content!=redThreshold";
364  }
365  else
366  {
367  if(m_name=="GreaterThan")
368  {
369  redCond="bin_content>redThreshold";
370  yellowCond="redThreshold>=bin_content>yellowThreshold";
371  }
372  else if(m_name=="LessThan")
373  {
374  redCond="bin_content<redThreshold";
375  yellowCond="redThreshold<=bin_content<yellowThreshold";
376  }
377  else if(m_name=="GreaterThanEqual")
378  {
379  redCond="bin_content>=redThreshold";
380  yellowCond="redThreshold>bin_content>=yellowThreshold";
381  }
382  else //LessThenEqual is the only remaining
383  {
384  redCond="bin_content<=redThreshold";
385  yellowCond="redThreshold<bin_content<=yellowThreshold";
386  }
387  }
388  out << "BinHeight_" << m_name << "_Threshold checks the bin height of a TH1. Ideally, a quantity as a function of LB. LB is expected to be on x axis, the quantity of interest is the bin content." << std::endl;
389  out << "BinHeight_" << m_name << "_Threshold defines 'red' and 'yellow' bins depending on the value of the bin content:\n \t-if " << redCond << ": the bin is 'red'.\n \t-if " << yellowCond << ": the bin is 'yellow'.\n \t-if (OPTIONAL) an 'UndefinedStatus' value is set and bin_content==UndefinedStatus, the bin is 'gray'.";
390  if(m_name!="GreaterThan" && m_name!="LessThan")
391  out << " Note that if 'UndefinedStatus' is equal to 'redThreshold' or 'yellowThreshold', the bin will be 'red'/'yellow' rather than 'gray'.";
392  out << "\n \t-otherwise the bin is 'green'" << std::endl;
393  out << "The algorithm checks all the bins in a window of size 'WindowSize', starting from:\n \t a) the last but X bin.\n \t b) the last non-zero bin.\n Oprion a) or b) is chosen by the parameter 'StartFromLast': if('StartFromLast'>=0), (a) holds and X is equal to 'StartFromLast', while (b) holds if 'StartFromLast'<0." << std::endl;
394  out << "In the window of interest, the number of red/yellow/gray bins is counted, respectively Nred/Nyellow/Ngray. The output is then defined comparing these numbers against the parameter 'NBins':\n \t- if Nred>=NBins: returns 'RED'.\n \t- else, if (Nred+Nyellow)>=NBins: returns 'YELLOW'.\n \t- else, if Ngray>=NBins: returns 'GREY'.\n \t- else returns 'GREEN'." << std::endl;
395  out << "NOTE: to avoid issues due to rounding in double precision, the equality between the bin content and any parameter is defined asking for the relative difference between the two to be smaller than a given parameter. I.e. content==Y is implemented as (abs(content-Y)/(content+Y))<epsilon. epsilon is equal to the parameter 'EqualityPrecision' which is tunable and set to 10^-4 by default\n"<<std::endl;
396 
397  out<<"Mandatory Parameter: HeightThreshold: sets the warning (yellowThreshold) and error (redThreshold) thresholds."<<std::endl;
398  out<<"Optional Parameter: NBins: minimum number of red/(yellow+red)/gray bins in the window of interest for the algorithm to return Red/Yellow/Grey. Default is 1."<<std::endl;
399  out<<"Optional Parameter: WindowSize: size of the x-axis range (in number of bins) in which red/yellow/gray bins are searched for. If WindowSize<=0, the whole istogram is searched for. Default is 1."<<std::endl;
400  out<<"Optional Parameter: StartFromLast: if StartFromLast=X with X>=0, the algorithm will check the bins starting from the last but X bin. If StartFromLast<0, it will start from the first bin of nonzero content. Default is -1."<<std::endl;
401  out<<"Optional Parameter: UndefinedStatus: a bin is defined to be 'gray' if its content is equal to UndefinedStatus. If not set, bins are not check against it."<<std::endl;
402  out<<"Optional Parameter: EqualityPrecision: sets the precision with which the bin content is defined to be 'equal' to a parameter, as described above. Default is 10^-4."<<std::endl;
403 }
404 
dqm_algorithms::BinHeightThreshold::CompareBinHeightThreshold
BinHeightThreshold::binStatus CompareBinHeightThreshold(const std::string &type, double bincontent, double thresholdGr, double thresholdRed, std::pair< bool, double > valueGray)
Definition: BinHeightThreshold.cxx:261
dqm_algorithms::BinHeightThreshold::printDescription
void printDescription(std::ostream &out)
Definition: BinHeightThreshold.cxx:352
Undefined
@ Undefined
Definition: MaterialTypes.h:8
get_generator_info.result
result
Definition: get_generator_info.py:21
IsA
#define IsA
Declare the TObject style functions.
Definition: xAODTEventBranch.h:59
dqm_algorithms::BinHeightThreshold
Definition: BinHeightThreshold.h:20
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:71
mc.diff
diff
Definition: mc.SFGenPy8_MuMu_DD.py:14
dqm_algorithms::BinHeightThreshold::m_precision
double m_precision
Definition: BinHeightThreshold.h:36
config
Definition: PhysicsAnalysis/AnalysisCommon/AssociationUtils/python/config.py:1
instance
std::map< std::string, double > instance
Definition: Run_To_Get_Tags.h:8
grepfile.content
string content
Definition: grepfile.py:56
dqm_algorithms::BinHeightThreshold::equalWithinPrecision
bool equalWithinPrecision(double a, double b)
Definition: BinHeightThreshold.cxx:331
TH1::SetBinContent
void SetBinContent(int, double)
Definition: rootspy.cxx:301
Result
ICscStripFitter::Result Result
Definition: CalibCscStripFitter.cxx:13
python.handimod.Green
int Green
Definition: handimod.py:524
dqm_algorithms::BinHeightThreshold::BinHeightThreshold
BinHeightThreshold(const std::string &name)
Definition: BinHeightThreshold.cxx:35
min
#define min(a, b)
Definition: cfImp.cxx:40
python.handimod.Red
Red
Definition: handimod.py:551
dqm_algorithms::BinHeightThreshold::binStatus
binStatus
Definition: BinHeightThreshold.h:21
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
a
TList * a
Definition: liststreamerinfos.cxx:10
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
TH1
Definition: rootspy.cxx:268
CheckValues.CheckThresholds
def CheckThresholds(calib)
Definition: CheckValues.py:16
AlgorithmHelper.h
dqm_algorithms::tools::GetFromMap
const T & GetFromMap(const std::string &pname, const std::map< std::string, T > &params)
Definition: AlgorithmHelper.h:114
pickleTool.object
object
Definition: pickleTool.py:30
dqm_algorithms::BinHeightThreshold::clone
BinHeightThreshold * clone()
Definition: BinHeightThreshold.cxx:43
dqm_algorithms::BinHeightThreshold::checkUndefinedStatusValue
bool checkUndefinedStatusValue(const std::string &type, double thresholdGr, double thresholdRed, std::pair< bool, double > valueGray)
Definition: BinHeightThreshold.cxx:236
dqm_algorithms::tools::GetFirstFromMap
double GetFirstFromMap(const std::string &paramName, const std::map< std::string, double > &params)
Definition: AlgorithmHelper.cxx:339
dqm_algorithms::BinHeightThreshold::CheckThresholds
void CheckThresholds(const std::string &type, double thresholdGr, double thresholdRed)
Definition: BinHeightThreshold.cxx:212
histogram
std::string histogram
Definition: chains.cxx:52
BinHeightThreshold.h
dqm_algorithms::BinHeightThreshold::execute
dqm_core::Result * execute(const std::string &, const TObject &, const dqm_core::AlgorithmConfig &)
Definition: BinHeightThreshold.cxx:50