ATLAS Offline Software
Loading...
Searching...
No Matches
AlgorithmHelper.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
8#ifndef DQM_ALGORITHMS_TOOLS_ALGORITHMHELPER_CXX
9#define DQM_ALGORITHMS_TOOLS_ALGORITHMHELPER_CXX
10
11#include <TF1.h>
12#include <TH1.h>
13#include <TH3F.h>
14#include <TH2F.h>
15#include <TH1F.h>
16
17#include <Math/ProbFuncMathCore.h>
18#include <Math/DistFunc.h>
19#include <TClass.h>
20#include <iostream>
22#include <ers/ers.h>
23
24#include <dqm_core/Result.h>
25
26#include <dqm_core/AlgorithmManager.h>
27#include <dqm_core/LibraryManager.h>
28
29std::map<std::string, double >
31{
32 std::map<std::string,double> fitparams;
33
34 const int nPar =(int) func->GetNpar();
35
36 for ( int i = 0; i< nPar; ++i ) {
37 std::string name = func->GetParName( i );
38 fitparams[name] = func->GetParameter( i );
39 }
40 return fitparams;
41}
42
43std::map<std::string, double >
45{
46 std::map<std::string,double> fitParamErrors;
47
48 const int nPar =(int) func->GetNpar();
49
50 for ( int i = 0; i< nPar; ++i ) {
51 std::string name = func->GetParName( i );
52 fitParamErrors[name] = func->GetParError( i );
53 }
54 return fitParamErrors;
55}
56
57
58
59dqm_core::Result *
60dqm_algorithms::tools::MakeComparisons( const std::map<std::string,double> & algparams,
61 const std::map<std::string,double> & gthreshold,
62 const std::map<std::string,double> & rthreshold )
63{
64
65 int red=0;
66 int yellow=0;
67 int green=0;
68
69
70 if (gthreshold.size() != rthreshold.size()) {
71 throw dqm_core::BadConfig( ERS_HERE, "MakeComparisons", "Need same number of Red and Green Threshold" );
72 }
73
74 if (gthreshold.size() == 0 ) {
75 throw dqm_core::BadConfig( ERS_HERE, "MakeComparisons", "No Threshold specified" );
76 }
77
78 std::map<std::string,double>::const_iterator g_iter;
79
80 for (g_iter=gthreshold.begin();g_iter!=gthreshold.end();++g_iter){
81
82 std::string name=(std::string) g_iter->first;
83 std::string findname=name;
84 double gtvalue=g_iter->second;
85
86 if (name == "AbsMean" )
87 findname="Mean";
88 if (name == "AbsXMean" )
89 findname="XMean";
90 if (name == "AbsYMean" )
91 findname="YMean";
92
93
94 std::map<std::string,double>::const_iterator ait = algparams.find(findname);
95 std::map<std::string,double>::const_iterator rit = rthreshold.find(name);
96 double rtvalue=-999;
97 double avalue=-999;
98
99 if ( ait != algparams.end() ) {
100 avalue=ait->second;
101 }
102 else {
103 throw dqm_core::BadConfig( ERS_HERE, "None",std::move(name) );
104 }
105
106 if ( rit != rthreshold.end() ) {
107 rtvalue=rit->second;
108 }
109 else {
110 throw dqm_core::BadConfig( ERS_HERE, "None",std::move(name) );
111 }
112
113 //cppcheck-suppress accessMoved
114 if (name == "AbsMean" || name == "AbsXMean" || name== "AbsYMean") {
115 avalue = fabs(avalue);
116 if (gtvalue < 0 || rtvalue <0 ) {
117 throw dqm_core::BadConfig( ERS_HERE, "None",std::move(name) );
118 }
119 }
120
121 ERS_DEBUG(1, name<<" :red value "<<rtvalue<<" :green value "<<gtvalue<<" :param value "<<avalue);
122
123 if (gtvalue < rtvalue) {
124
125 if (avalue <= gtvalue ){
126 ++green;
127 }else if(avalue < rtvalue){
128 ++yellow;
129 }else {
130 ++red;
131 }
132 }
133 else if (gtvalue > rtvalue) {
134 if (avalue >= gtvalue ){
135 ++green;
136 }else if(avalue > rtvalue){
137 ++yellow;
138 }else {
139 ++red;
140 }
141 }
142 else {
143 ERS_DEBUG(0, "red threshold (" << rtvalue << ") same as green threshold "<< gtvalue <<") for parameter " << name << ": can't evaluate result");
144 throw dqm_core::BadConfig( ERS_HERE, "None", std::move(name) );
145 }
146
147 }
148 ERS_DEBUG(1, "red: "<<red<<" yellow: "<<yellow<<" green: "<<green);
149
150
151 dqm_core::Result* result = new dqm_core::Result();
152
153 result->tags_ = algparams;
154
155
156 if (red>0) {
157 result->status_= dqm_core::Result::Red;
158 }else if (yellow>0) {
159 result->status_= dqm_core::Result::Yellow;
160 }else if (green>0) {
161 result->status_= dqm_core::Result::Green;
162 }
163
164 return result;
165}
166
167dqm_core::Result *
168dqm_algorithms::tools::CompareWithErrors( const std::map<std::string,double> & algparams,
169 const std::map<std::string,double> & paramErrors,
170 const std::map<std::string,double> & gthreshold,
171 const std::map<std::string,double> & rthreshold, double minSig )
172{
173
174 int red = 0;
175 int yellow = 0;
176 int green = 0;
177 int undefined = 0;
178
179
180 if (gthreshold.size() != rthreshold.size()) {
181 throw dqm_core::BadConfig( ERS_HERE, "MakeComparisons", "Need same number of Red and Green Threshold" );
182 }
183
184 if (gthreshold.size() == 0 ) {
185 throw dqm_core::BadConfig( ERS_HERE, "MakeComparisons", "No Threshold specified" );
186 }
187
188 std::map<std::string,double>::const_iterator g_iter;
189
190 for (g_iter=gthreshold.begin();g_iter!=gthreshold.end();++g_iter){
191
192 std::string name=(std::string) g_iter->first;
193 std::string findname=name;
194 double gtvalue=g_iter->second;
195
196 if (name == "AbsMean" )
197 findname="Mean";
198 if (name == "AbsXMean" )
199 findname="XMean";
200 if (name == "AbsYMean" )
201 findname="YMean";
202
203
204 std::map<std::string,double>::const_iterator ait = algparams.find(findname);
205 std::map<std::string,double>::const_iterator errItr = paramErrors.find(findname);
206 std::map<std::string,double>::const_iterator rit = rthreshold.find(name);
207
208 double rtvalue = -999;
209 double avalue = -999;
210 double error = 0;
211
212 if ( ait != algparams.end() ) {
213 avalue=ait->second;
214 }
215 else {
216 throw dqm_core::BadConfig( ERS_HERE, "None", std::move(name) );
217 }
218
219 if ( errItr != paramErrors.end() ) {
220 error = errItr->second;
221 }
222 else {
223 throw dqm_core::BadConfig( ERS_HERE, "Problem retrieving fit param error", std::move(name) );
224 }
225 if ( error < 0 ) error = 0;
226
227 if ( rit != rthreshold.end() ) {
228 rtvalue=rit->second;
229 }
230 else {
231 throw dqm_core::BadConfig( ERS_HERE, "None", std::move(name) );
232 }
233
234 //cppcheck-suppress accessMoved
235 if (name == "AbsMean" || name == "AbsXMean" || name== "AbsYMean") {
236 avalue = fabs(avalue);
237 if (gtvalue < 0 || rtvalue <0 ) {
238 throw dqm_core::BadConfig( ERS_HERE, "None", std::move(name) );
239 }
240 }
241
242 ERS_DEBUG(1, name<<" :red value "<<rtvalue<<" :green value "<<gtvalue<<" :param value "<<avalue <<" :param error "<<error);
243
244 double significanceBound = error * minSig;
245
246
247 if (gtvalue < rtvalue) {
248
249 if ( avalue <= (gtvalue - significanceBound) ){
250 ++green;
251 }
252 else if( avalue > (rtvalue + significanceBound) ){
253 ++red;
254 }
255 else if( avalue > (gtvalue + significanceBound) ) {
256 ++yellow;
257 }
258 else {
259 ++undefined;
260 }
261 }
262 else if (gtvalue > rtvalue) {
263 if ( avalue >= (gtvalue + significanceBound) ){
264 ++green;
265 }
266 else if( avalue < (rtvalue - significanceBound) ){
267 ++red;
268 }
269 else if( avalue < (gtvalue - significanceBound) ){
270 ++yellow;
271 }
272 else {
273 ++undefined;
274 }
275 }
276 else {
277 ERS_DEBUG(0, "red threshold same as green threshold: can't evaluate result");
278 throw dqm_core::BadConfig( ERS_HERE, "None", std::move(name) );
279 }
280
281 }
282 ERS_DEBUG(1, "red: "<<red<<" yellow: "<<yellow<<" green: "<<green << " undefined: " <<undefined);
283
284
285 dqm_core::Result* result = new dqm_core::Result();
286
287 result->tags_ = algparams;
288
289 // We use a strung undefined here: if one of the test parameters was in the undefined region about gth,
290 // then the overall result will be undefined.
291 if (red>0) {
292 result->status_= dqm_core::Result::Red;
293 }
294 else if (yellow>0) {
295 result->status_= dqm_core::Result::Yellow;
296 }
297 else if (undefined>0) {
298 result->status_= dqm_core::Result::Undefined;
299 }
300 else if (green>0) {
301 result->status_= dqm_core::Result::Green;
302 }
303
304 return result;
305}
306
307dqm_core::Result *
308dqm_algorithms::tools::GetFitResult (const TF1 * func, const dqm_core::AlgorithmConfig & config, double minSig )
309{
310 std::map<std::string, double > params = GetFitParams(func);
311 std::map<std::string, double > greenthresh=config.getGreenThresholds();
312 std::map<std::string,double>::const_iterator ait = greenthresh.find("Chi2_per_NDF");
313 if ( ait != greenthresh.end() ) {
314 params["Chi2_per_NDF"]=func->GetChisquare()/ func->GetNDF();
315 }
316 double subtractfrommean = GetFirstFromMap( "SubtractFromMean", config.getParameters(), 0 );
317
318 params["Mean"] = params["Mean"] - subtractfrommean;
319 dqm_core::Result * result;
320 std::map<std::string, double > paramErrors = GetFitParamErrors(func);
321 if( minSig == 0) {
322 result = MakeComparisons( params, config.getGreenThresholds(), config.getRedThresholds() );
323 //result->tags_ = params;
324 }
325 else {
326 result = CompareWithErrors( params, paramErrors, config.getGreenThresholds(), config.getRedThresholds(), minSig );
327 }
328
329 result->tags_ = std::move(params);
330 for ( std::map<std::string,double>::const_iterator peItr = paramErrors.begin(); peItr != paramErrors.end(); ++peItr ) {
331 std::string errorName = peItr->first;
332 errorName += " Error";
333 result->tags_[errorName] = peItr->second;
334 }
335
336 return result;
337}
338
339double dqm_algorithms::tools::GetFirstFromMap(const std::string &paramName, const std::map<std::string, double > &params)
340{
341 std::map<std::string, double >::const_iterator it = params.find(paramName);
342 if (it == params.end()) {
343 throw dqm_core::BadConfig(ERS_HERE, "None", paramName); // this is the only difference between the two overloaded versions
344 } else {
345 return it->second;
346 }
347}
348
349double dqm_algorithms::tools::GetFirstFromMap(const std::string &paramName, const std::map<std::string, double > &params, double defaultValue)
350{
351 std::map<std::string, double >::const_iterator it = params.find(paramName);
352 if (it == params.end()) {
353 return defaultValue; // this is the only difference between the two overloaded versions
354 } else {
355 return it->second;
356 }
357}
358
359//string overloads
360const std::string& dqm_algorithms::tools::GetFirstFromMap(const std::string &paramName, const std::map<std::string, std::string > &params)
361{
362 std::map<std::string, std::string >::const_iterator it = params.find(paramName);
363 if (it == params.end()) {
364 throw dqm_core::BadConfig(ERS_HERE, "None", paramName); // this is the only difference between the two overloaded versions
365 } else {
366 return it->second;
367 }
368}
369
370const std::string& dqm_algorithms::tools::GetFirstFromMap(const std::string &paramName, const std::map<std::string, std::string > &params, const std::string& defaultValue)
371{
372 std::map<std::string, std::string >::const_iterator it = params.find(paramName);
373 if (it == params.end()) {
374 return defaultValue; // this is the only difference between the two overloaded versions
375 } else {
376 return it->second;
377 }
378}
379
380std::vector<int> dqm_algorithms::tools::GetBinRange(const TH1 *h, const std::map<std::string, double > &params)
381{
382 std::vector<int> range;
383 const TAxis *xAxis = h->GetXaxis();
384 const TAxis *yAxis = h->GetYaxis();
385
386 if (h->GetDimension() > 2) {
387 throw dqm_core::BadConfig(ERS_HERE, h->GetName(), "histogram has more than 2 dimensions");
388 }
389
390 const double notFound = -99999;
391 const double xmin = dqm_algorithms::tools::GetFirstFromMap("xmin", params, notFound);
392 const double xmax = dqm_algorithms::tools::GetFirstFromMap("xmax", params, notFound);
393 const double ymin = dqm_algorithms::tools::GetFirstFromMap("ymin", params, notFound);
394 const double ymax = dqm_algorithms::tools::GetFirstFromMap("ymax", params, notFound);
395
401 const int xlow = (xmin == notFound) ? 1 : xAxis->FindBin(xmin);
402 const int xhigh = (xmax == notFound) ? xAxis->GetNbins() : (xAxis->GetBinLowEdge(xAxis->FindBin(xmax))== xmax) ? (xAxis->FindBin(xmax)-1) : xAxis->FindBin(xmax);
403 const int ylow = (ymin == notFound) ? 1 : yAxis->FindBin(ymin);
404 const int yhigh = (ymax == notFound) ? yAxis->GetNbins() : (yAxis->GetBinLowEdge(yAxis->FindBin(ymax))== ymax) ? (yAxis->FindBin(ymax)-1) : yAxis->FindBin(ymax);
405
406
407 if (xlow>xhigh) {
408 char temp[128];
409 sprintf(temp,"Bin Range Error: xmin = %.3g, xmax = %.3g",xmin,xmax);
410 throw dqm_core::BadConfig( ERS_HERE, h->GetName(), temp );
411 }
412 if (ylow>yhigh) {
413 char temp[128];
414 sprintf(temp,"Bin Range Error: xmin = %.3g, xmax = %.3g",xmin,xmax);
415 throw dqm_core::BadConfig( ERS_HERE, h->GetName(), temp );
416 }
417
418 range.push_back(xlow);
419 range.push_back(xhigh);
420 range.push_back(ylow);
421 range.push_back(yhigh);
422 return range;
423}
424
425void
426dqm_algorithms::tools::PublishBin(const TH1 * histogram, int x, int y, double inputcont, dqm_core::Result *result) {
427
428 std::string name = histogram->GetName();
429 double xbin = histogram->GetXaxis()->GetBinCenter(x);
430 std::string xbinlabel = (std::string)(histogram->GetXaxis()->GetBinLabel(x));
431 if (histogram->GetDimension() == 2){
432 double ybin = histogram->GetYaxis()->GetBinCenter(y);
433 std::string ybinlabel = (std::string)(histogram->GetYaxis()->GetBinLabel(y));
434 std::string badbin = Form("x-axis %s(%f) y-axis %s(%f))",xbinlabel.c_str(),xbin,ybinlabel.c_str(),ybin);
435 result->tags_[badbin.c_str()] = inputcont;
436 ERS_DEBUG(1,"x bin "<<xbin<<" y bin "<<ybin <<" value "<<inputcont);
437 } else {
438 std::string badbin = Form("%s(%f)",xbinlabel.c_str(),xbin);
439 result->tags_[badbin.c_str()] = inputcont;
440 ERS_DEBUG(1,"x bin "<<xbin<<" value "<<inputcont);
441 }
442}
443
444
445TH1*
446dqm_algorithms::tools::DivideByHistogram(const TH1* hNumerator, const TH1* hDenominator)
447{
448
449 TH1 * hResult = 0;
450
451 int hNdimension = hNumerator->GetDimension();
452 int hDdimension = hDenominator->GetDimension();
453
454 if( hDdimension == hNdimension ) {
455 if( (hNumerator->GetNbinsX() != hDenominator->GetNbinsX()) || (hNumerator->GetNbinsY() != hDenominator->GetNbinsY()) ||
456 (hNumerator->GetNbinsZ() != hNumerator->GetNbinsZ()) ) {
457 throw dqm_core::BadConfig( ERS_HERE, "DivideByHistogram", "number of bins do not match");
458 }
459 //since the dimensions match, use the root TH1 division method
460 //as recommended in root documentation, we call Sumw2 first to keep the errors well behaved:
461
462 if( hNdimension == 1) {
463 hResult = BookHistogramByExample(hNumerator,"hQuotient","Result of Division of One Histogram By Another",XAxis);
464 }
465 else if ( hNdimension == 2 ) {
466 hResult = BookHistogramByExample(hNumerator,"hQuotient","Result of Division of One Histogram By Another",XYAxes);
467 }
468 else if ( hNdimension == 3 ) {
469 hResult = BookHistogramByExample(hNumerator,"hQuotient","Result of Division of One Histogram By Another",XYZAxes);
470 }
471 else {
472 throw dqm_core::BadConfig( ERS_HERE, "DivideByHistogram", "Histograms with dimension greater than 3 are not supported");
473 }
474 hResult->Sumw2();
475
476 hResult->Divide(hNumerator,hDenominator);
477 }
478 else if ( hNdimension > hDdimension ) {
479 //Handle division for case where denominator has lower dimension than numerator:
480 //There are only a few possibilities, hNdimension = 2 or 3, hDdimension = 1 or 2.
481
482 const TAxis* xax = hNumerator->GetXaxis();
483 int nbinsx = xax->GetNbins();
484 const TAxis* yax = hNumerator->GetYaxis();
485 int nbinsy = yax->GetNbins();
486 const TAxis* zax = hNumerator->GetZaxis();
487 int nbinsz = zax->GetNbins();
488
489 if( nbinsx != hDenominator->GetNbinsX() ) {
490 throw dqm_core::BadConfig( ERS_HERE, "DivideByHistogram", "number of bins in x-axis do not match");
491 }
492 if( (hDdimension == 2) && (nbinsy != hDenominator->GetNbinsY()) ) {
493 throw dqm_core::BadConfig( ERS_HERE, "DivideByHistogram", "number of bins in y-axis do not match");
494 }
495
496 double numeratorCont = 0;
497 double denominatorCont = 0;
498 double numeratorError = 0;
499 double denominatorError = 0;
500
501 if(hNdimension == 2) {
502 hResult = BookHistogramByExample(hNumerator,"hQuotient","Result of Division of One Histogram By Another",XYAxes);
503 }
504 else if(hNdimension == 3) {
505 hResult = BookHistogramByExample(hNumerator,"hQuotient","Result of Division of One Histogram By Another",XYZAxes);
506 }
507 else {
508 throw dqm_core::BadConfig( ERS_HERE, "DivideByHistogram", "Histograms with dimension greater than 3 are not supported");
509 }
510
511 for (int i=1; i <= nbinsx; i++) {
512 if( hDdimension == 1){
513 denominatorCont = hDenominator->GetBinContent(i);
514 denominatorError = hDenominator->GetBinError(i);
515 }
516 for (int j=1; j <= nbinsy; j++) {
517 if( hDdimension == 2){
518 denominatorCont = hDenominator->GetBinContent(i,j);
519 denominatorError = hDenominator->GetBinError(i,j);
520 }
521 if( hNdimension == 2){
522 numeratorCont = hNumerator->GetBinContent(i,j);
523 numeratorError = hNumerator->GetBinError(i,j);
524 if(denominatorCont != 0){
525 hResult->SetBinContent(i,j,numeratorCont/denominatorCont);
526 hResult->SetBinError(i,j,sqrt( ( pow(numeratorError,2)/pow(denominatorCont,2) )
527 + ( pow(denominatorError,2) * pow(numeratorCont,2) / pow(denominatorCont,4) ) ) );
528 }
529 }
530 else {
531 for (int k=1; k <= nbinsz; k++) {
532 numeratorCont = hNumerator->GetBinContent(i,j,k);
533 numeratorError = hNumerator->GetBinError(i,j,k);
534 if(denominatorCont != 0){
535 hResult->SetBinContent(i,j,k,numeratorCont/denominatorCont);
536 hResult->SetBinError(i,j,k,sqrt( ( pow(numeratorError,2)/pow(denominatorCont,2) )
537 + ( pow(denominatorError,2) * pow(numeratorCont,2) / pow(denominatorCont,4) ) ) );
538 }
539 }
540 }
541 }
542 }
543 }
544 else {
545 //Handle division for case where the numerator has lower dimension than the denominator
546 //There are only a few possibilities, hNdimension = 1 or 2, hDdimension = 2 or 3.
547
548 const TAxis* xax = hDenominator->GetXaxis();
549 int nbinsx = xax->GetNbins();
550 const TAxis* yax = hDenominator->GetYaxis();
551 int nbinsy = yax->GetNbins();
552 const TAxis* zax = hDenominator->GetZaxis();
553 int nbinsz = zax->GetNbins();
554
555 if( nbinsx != hNumerator->GetNbinsX() ) {
556 throw dqm_core::BadConfig( ERS_HERE, "number of bins in x-axis", "do not match");
557 }
558 if( (hNdimension == 2) && (nbinsy != hNumerator->GetNbinsY()) ) {
559 throw dqm_core::BadConfig( ERS_HERE, "number of bins in y-axis", "do not match");
560 }
561
562 double denominatorCont = 0;
563 double numeratorCont = 0;
564 double denominatorError = 0;
565 double numeratorError = 0;
566
567 if(hDdimension == 2) {
568 hResult = BookHistogramByExample(hDenominator,"hQuotient","Result of Division of One Histogram By Another",XYAxes);
569 }
570 else if(hDdimension == 3) {
571 hResult = BookHistogramByExample(hDenominator,"hQuotient","Result of Division of One Histogram By Another",XYZAxes);
572 }
573 else {
574 throw dqm_core::BadConfig( ERS_HERE, "DivideByHistogram", "Histograms with dimension greater than 3 are not supported");
575 }
576
577 // Always loop so at to handle over/underflows too
578 for (int i=1; i <= nbinsx; i++) {
579 if( hNdimension == 1){
580 numeratorCont = hNumerator->GetBinContent(i);
581 numeratorError = hNumerator->GetBinError(i);
582 }
583 for (int j=1; j <= nbinsy; j++) {
584 if( hNdimension == 2){
585 numeratorCont = hNumerator->GetBinContent(i,j);
586 numeratorError = hNumerator->GetBinError(i,j);
587 }
588 if( hDdimension == 2){
589 denominatorCont = hDenominator->GetBinContent(i,j);
590 denominatorError = hDenominator->GetBinError(i,j);
591 if(denominatorCont != 0){
592 hResult->SetBinContent(i,j,numeratorCont/denominatorCont);
593 hResult->SetBinError(i,j,sqrt( ( pow(numeratorError,2)/pow(denominatorCont,2) )
594 + ( pow(denominatorError,2) * pow(numeratorCont,2) / pow(denominatorCont,4) ) ) );
595 }
596 }
597 else {
598 for (int k=1; k <= nbinsz; k++) {
599 denominatorCont = hDenominator->GetBinContent(i,j,k);
600 denominatorError = hDenominator->GetBinError(i,j,k);
601 if(denominatorCont != 0){
602 hResult->SetBinContent(i,j,k,numeratorCont/denominatorCont);
603 hResult->SetBinError(i,j,sqrt( ( pow(numeratorError,2)/pow(denominatorCont,2) )
604 + ( pow(denominatorError,2) * pow(numeratorCont,2) / pow(denominatorCont,4) ) ) );
605 }
606 }
607 }
608 }
609 }
610 }
611 return hResult;
612}
613
614std::string
615dqm_algorithms::tools::ExtractAlgorithmName(const dqm_core::AlgorithmConfig& config)
616{
617 // Function to extract the name of an auxiliary algorithm specified through an algorithm configuration parameter
618 // Uses syntax AuxAlgName::[Algorithm Name] = [value], where value is ignored.
619
620 std::string algNameTag = "AuxAlgName--";
621 std::string algName = "None";
622
623 if (config.getParameters().empty()){
624 throw dqm_core::BadConfig( ERS_HERE, "ExtractAlgorithmName","called with an empty config file");
625 }
626
627 std::map<std::string,double > confParams = config.getParameters();//Copy is necessary as AlgorithmConfig does not return map by reference (bug?)
628 for ( std::map<std::string,double >::const_iterator itr = confParams.begin();itr != confParams.end();++itr ) {
629 size_t stringPos;
630 if ( (stringPos = itr->first.find(algNameTag)) != std::string::npos ){
631 stringPos += algNameTag.length();
632 algName = itr->first.substr(stringPos);
633 }
634 }
635
636 return algName;
637}
638
639dqm_core::Result *
640dqm_algorithms::tools::ExecuteNamedAlgorithm(const std::string & name, const TObject & object, const dqm_core::AlgorithmConfig & config)
641{
642 // Function to find and execute the named algorithm
643 dqm_core::Algorithm* algorithm = 0;
644
645 if (name.compare("None") == 0 ) {
646 throw dqm_core::BadConfig( ERS_HERE,"no auxiliary algorithm specified", name);
647 }
648
649 try {
650 algorithm = dqm_core::AlgorithmManager::instance().getAlgorithm(name);
651 }
652 catch( dqm_core::Exception& ex ) {
653 throw dqm_core::BadConfig( ERS_HERE,"unable to get algorithm of this name", name);
654 }
655
656 return algorithm->execute(name,object,config);
657}
658
659
660void
661dqm_algorithms::tools::ModifyHistogram(TH1 * histogram, const dqm_core::AlgorithmConfig & config)
662{
663 if (config.getParameters().empty()){
664 //Nothing to do
665 return;
666 }
667 std::map<std::string,double > confParams = config.getParameters();//Copy is necessary as AlgorithmConfig does not return map by reference (bug?)
668 for ( std::map<std::string,double >::const_iterator itr = confParams.begin();itr != confParams.end();++itr ) {
669 if ( itr->first.find("MultiplyHistogramByValue") != std::string::npos ){
670 histogram->Scale(itr->second);
671 continue;
672 }
673 if ( itr->first.find("DivideHistogramByValue") != std::string::npos ){
674 histogram->Scale( (1./itr->second) );
675 continue;
676 }
677 size_t stringPos;
678 std::string configTag = "SetHistogramTitle";
679 if ( (stringPos = itr->first.find(configTag)) != std::string::npos ){
680 stringPos += configTag.length();
681 histogram->SetTitle( (itr->first.substr(stringPos)).c_str() );
682 continue;
683 }
684 }
685}
686
687TH1*
688dqm_algorithms::tools::BookHistogramByExample(const TH1* histogram, const std::string& name, const std::string& title, AxisType axisType){
689
690 switch (axisType) {
691 case XYAxes:
692
693 if (histogram->GetDimension() == 1){
694 throw dqm_core::BadConfig( ERS_HERE, name,"can't make a 2D histogram from a 1D histogram");
695 }
696 TH2F * resultXY;
697 if(histogram->GetXaxis()->IsVariableBinSize()) {
698 resultXY = new TH2F(name.c_str(),title.c_str(),
699 histogram->GetNbinsX(),histogram->GetXaxis()->GetXbins()->GetArray(),
700 histogram->GetNbinsY(),histogram->GetYaxis()->GetXbins()->GetArray());
701 }
702 else {
703 resultXY = new TH2F(name.c_str(),title.c_str(),
704 histogram->GetNbinsX(),histogram->GetXaxis()->GetXmin(),histogram->GetXaxis()->GetXmax(),
705 histogram->GetNbinsY(),histogram->GetYaxis()->GetXmin(),histogram->GetYaxis()->GetXmax());
706 }
707
708 resultXY->SetXTitle(histogram->GetXaxis()->GetTitle());
709 resultXY->SetYTitle(histogram->GetYaxis()->GetTitle());
710 return static_cast<TH1*> (resultXY);
711
712 case YAxis:
713
714 if (histogram->GetDimension() == 1){
715 throw dqm_core::BadConfig( ERS_HERE, name, "can't extract a Y-Axis from a 1D histogram");
716 }
717 TH1F *resultY;
718 if(histogram->GetYaxis()->IsVariableBinSize()) {
719 resultY = new TH1F(name.c_str(),title.c_str(),
720 histogram->GetNbinsY(),histogram->GetYaxis()->GetXbins()->GetArray());
721 }
722 else {
723 resultY = new TH1F(name.c_str(),title.c_str(),
724 histogram->GetNbinsY(),histogram->GetYaxis()->GetXmin(),histogram->GetYaxis()->GetXmax());
725 }
726 resultY->SetXTitle(histogram->GetYaxis()->GetTitle());
727 return static_cast<TH1*> (resultY);
728
729 case XYZAxes:
730
731 if (histogram->GetDimension() < 3){
732 throw dqm_core::BadConfig( ERS_HERE, name, "can't make a 3D histrogram without at least a 3D histogram");
733 }
734 TH3F *resultXYZ;
735 if(histogram->GetXaxis()->IsVariableBinSize()) {
736 resultXYZ = new TH3F(name.c_str(),title.c_str(),
737 histogram->GetNbinsX(),histogram->GetXaxis()->GetXbins()->GetArray(),
738 histogram->GetNbinsY(),histogram->GetYaxis()->GetXbins()->GetArray(),
739 histogram->GetNbinsZ(),histogram->GetZaxis()->GetXbins()->GetArray());
740 }
741 else {
742 resultXYZ = new TH3F(name.c_str(),title.c_str(),
743 histogram->GetNbinsX(),histogram->GetXaxis()->GetXmin(),histogram->GetXaxis()->GetXmax(),
744 histogram->GetNbinsY(),histogram->GetYaxis()->GetXmin(),histogram->GetYaxis()->GetXmax(),
745 histogram->GetNbinsZ(),histogram->GetZaxis()->GetXmin(),histogram->GetZaxis()->GetXmax());
746 }
747 resultXYZ->SetXTitle(histogram->GetXaxis()->GetTitle());
748 resultXYZ->SetYTitle(histogram->GetYaxis()->GetTitle());
749 resultXYZ->SetZTitle(histogram->GetZaxis()->GetTitle());
750 return resultXYZ;
751
752 case XZAxes:
753
754 if (histogram->GetDimension() < 3){
755 throw dqm_core::BadConfig( ERS_HERE, name,"can't extract a Z-Axis from a dimension < 3 histogram");
756 }
757 TH2F * resultXZ;
758 if(histogram->GetXaxis()->IsVariableBinSize()) {
759 resultXZ = new TH2F(name.c_str(),title.c_str(),
760 histogram->GetNbinsX(),histogram->GetXaxis()->GetXbins()->GetArray(),
761 histogram->GetNbinsZ(),histogram->GetZaxis()->GetXbins()->GetArray());
762 }
763 else {
764 resultXZ = new TH2F(name.c_str(),title.c_str(),
765 histogram->GetNbinsX(),histogram->GetXaxis()->GetXmin(),histogram->GetXaxis()->GetXmax(),
766 histogram->GetNbinsZ(),histogram->GetZaxis()->GetXmin(),histogram->GetZaxis()->GetXmax());
767 }
768 resultXZ->SetXTitle(histogram->GetXaxis()->GetTitle());
769 resultXZ->SetYTitle(histogram->GetZaxis()->GetTitle());
770 return static_cast<TH1*> (resultXZ);
771
772 case YZAxes:
773
774 if (histogram->GetDimension() < 3){
775 throw dqm_core::BadConfig( ERS_HERE, name,"can't extract a Z-Axis from a dimension < 3 histogram");
776 }
777 TH2F * resultYZ;
778 if(histogram->GetYaxis()->IsVariableBinSize()) {
779 resultYZ = new TH2F(name.c_str(),title.c_str(),
780 histogram->GetNbinsY(),histogram->GetYaxis()->GetXbins()->GetArray(),
781 histogram->GetNbinsZ(),histogram->GetZaxis()->GetXbins()->GetArray());
782 }
783 else {
784 resultYZ = new TH2F(name.c_str(),title.c_str(),
785 histogram->GetNbinsY(),histogram->GetYaxis()->GetXmin(),histogram->GetYaxis()->GetXmax(),
786 histogram->GetNbinsZ(),histogram->GetZaxis()->GetXmin(),histogram->GetZaxis()->GetXmax());
787 }
788 resultYZ->SetXTitle(histogram->GetYaxis()->GetTitle());
789 resultYZ->SetYTitle(histogram->GetZaxis()->GetTitle());
790 return static_cast<TH1*> (resultYZ);
791
792 case ZAxis:
793
794 if (histogram->GetDimension() < 3){
795 throw dqm_core::BadConfig( ERS_HERE, name, "can't extract a Z-Axis from a dimension < 3 histogram");
796 }
797 TH1F *resultZ;
798 if(histogram->GetZaxis()->IsVariableBinSize()) {
799 resultZ = new TH1F(name.c_str(),title.c_str(),
800 histogram->GetNbinsZ(),histogram->GetZaxis()->GetXbins()->GetArray());
801 }
802 else {
803 resultZ = new TH1F(name.c_str(),title.c_str(),
804 histogram->GetNbinsZ(),histogram->GetZaxis()->GetXmin(),histogram->GetZaxis()->GetXmax());
805 }
806 resultZ->SetXTitle(histogram->GetZaxis()->GetTitle());
807 return static_cast<TH1*> (resultZ);
808
809 case XAxis:
810 default:
811
812 TH1F *resultX;
813 if(histogram->GetXaxis()->IsVariableBinSize()) {
814 resultX = new TH1F(name.c_str(),title.c_str(),
815 histogram->GetNbinsX(),histogram->GetXaxis()->GetXbins()->GetArray());
816 }
817 else {
818 resultX = new TH1F(name.c_str(),title.c_str(),
819 histogram->GetNbinsX(),histogram->GetXaxis()->GetXmin(),histogram->GetXaxis()->GetXmax());
820 }
821 resultX->SetXTitle(histogram->GetXaxis()->GetTitle());
822 return static_cast<TH1*> (resultX );
823 }
824
825}
826
827void
829 const TObject*& firstReference ,
830 TObject*& secondReference )
831{
832 if ( ro.InheritsFrom("TH1") )
833 {
834 //Simple reference
835 firstReference = &ro;
836 secondReference = 0;
837 return;
838 }
839 else if ( ro.InheritsFrom("TCollection") )
840 {
841 //The reference is a collection of TObjects
842 const TCollection* coll = static_cast<const TCollection*>(&ro);
843 TIterator* it = coll->MakeIterator();
844 TObject* content = it->Next();
845 if ( content == 0 || content->InheritsFrom("TH1") == kFALSE )
846 {
847 throw dqm_core::BadRefHist(ERS_HERE,"handleReference"," Could not retreive reference");
848 }
849 firstReference = static_cast<TH1 *>(content);
850 Int_t csize = coll->GetEntries();
851 if ( csize == 1 )
852 {
853 //Only one element, no secondReference is available.
854 secondReference = 0;
855 return;
856 }
857 else if ( coll->GetEntries() == 2 )
858 {
859 //The collection is a pair, the second reference will be used directly
860 secondReference = it->Next();
861 return;
862 }
863 else
864 {
865 //This case is more complex, we basically want to create a new collection without the first element
866 secondReference = static_cast<TObject*>( (coll->IsA())->New() );//Create a new container of the same class as the original one
867 if ( secondReference == 0 || secondReference->InheritsFrom("TCollection") == kFALSE )
868 {
869 throw dqm_core::BadRefHist(ERS_HERE,"handleReference"," Could not retreive reference");
870 }
871 while ( (content = it->Next()) )//start from second element, since we already called Next()
872 {
873 static_cast<TCollection*>(secondReference)->Add(content);
874 }
875 return;
876 }
877 }
878 else
879 {
880 //This kind of reference is not supported
881 throw dqm_core::BadRefHist(ERS_HERE,"handleReference"," Could not retreive reference");
882 }
883}
884
885
886
887void
888dqm_algorithms::tools::findOutliers( std::vector<binContainer>& input, double& mean, double& scale, int& nIn,
889 int nIterations, double exponent, double threshold, double SBCF, double nStop) {
890
891 int size = input.size();
892 if(size < 2) {
893 return;
894 }
895
896 if (nStop < 0) nStop = 0;
897 if (SBCF < 0) SBCF = 0;
898
899 std::vector<binContainer>::const_iterator cbegin = input.begin();
900 std::vector<binContainer>::const_iterator cend = input.end();
901
902 std::vector<binContainer>::iterator begin = input.begin();
903 std::vector<binContainer>::iterator end = input.end();
904
905 nIn = 0;
906 mean = 0;
907 scale = 0;
908
909 double newMean = 0;
910 double newScale = 0;
911 for ( int j = 0; j < nIterations ; j++ ) {
912 mean = newMean;
913 scale = newScale;
914
915 int newNin = 0;
916 double sum = 0;
917 //Loop to test, counting and summing elements that pass:
918 for ( std::vector<binContainer>::iterator it = begin; it != end; ++it ) {
919 //The Test:
920 it->test = ( (fabs(it->value - mean) < (threshold * scale) ) || (j==0) );
921 if ( it->test ) {
922 sum += it->value;
923 newNin++;
924 }
925 }
926 int nOut = size - newNin;
927 // Check if the iteration process is complete (or failed):
928 if (newNin < (2 + nStop + SBCF * nOut) ) {
929 return;
930 }
931 newMean = newNin ? (sum / newNin) : 0; // avoid to divide by zero (should never happen)
932 // Check if the iteration process has stabilized:
933 if ( (newNin == nIn) && (newMean == mean) ) {
934 return;
935 }
936 nIn = newNin;
937
938 // Calculate the scale parameter:
939 double scaleSum = 0;
940 for ( std::vector<binContainer>::const_iterator it = cbegin; it != cend; ++it ) {
941 if(it->test) {
942 scaleSum += pow( fabs(it->value - newMean) , exponent );
943 }
944 }
945 newScale = pow( scaleSum / (nIn - 1 - (SBCF * nOut) ), 1/exponent);
946 }
947 return;
948}
949
950void
951dqm_algorithms::tools::findOutliersUsingErrors( std::vector<binContainer>& input, double& mean, double& meanError, int& nIn, double minDiff, int minNin ) {
952
953
954 //Perform outlier determination using the bin errors and the relative pull on the mean,
955 // Taken from algorithm by Michele Petteni
956
957 if( minDiff < 0 ) minDiff = 0;
958 if( minNin < 2) minNin = 3;
959
960 nIn = input.size();
961 if(nIn < minNin) {
962 return;
963 }
964 meanError = 0;
965
966
967 std::vector<binContainer>::iterator begin = input.begin();
968 std::vector<binContainer>::iterator end = input.end();
969
970 //First pass: calucalate the mean:
971 double sum = 0;
972 double sumError2 = 0;
973 for( std::vector<binContainer>::iterator it = begin; it != end; ++it ) {
974 sum += it->value;
975 sumError2 += pow(it->error,2);
976 it->test = true;
977 }
978 mean = sum / nIn;
979 meanError = sqrt( sumError2/ nIn );
980 //Loop to tag and remove outliers:
981 while( nIn > 2 ) {
982
983 //Use map for ordering by distance from mean:
984 std::map<double,binContainer*> absDiffMap;
985 for( std::vector<binContainer>::iterator it = begin; it != end; ++it ) {
986 if( it->test ) {
987 absDiffMap[ fabs( it->value - mean ) ] = &(*it);
988 }
989 }
990
991 //If max(absDiff) < minDiff, this is not considered an outlier: we are done.
992 std::map<double,binContainer*>::iterator outlierCandidate = absDiffMap.end();
993 --outlierCandidate;//<- the last element in a map is the largest.
994 if( outlierCandidate->first < minDiff ) {
995 return;
996 }
997
998 //Find the mean and its error if we exclude the outlier candidate:
999 double newMean = 0;
1000 double newMeanError = 0;
1001 sum = 0;
1002 for( std::map<double,binContainer*>::iterator it = absDiffMap.begin(); it != outlierCandidate; ++it) {
1003 sum += it->second->value;
1004 sumError2 += pow(it->second->error,2);
1005 }
1006 newMean = sum/(nIn - 1);
1007 newMeanError = sqrt( sumError2/(nIn - 2) );
1008
1009 double meanShift = fabs( mean - newMean );
1010
1011 //If the shift is bigger than the new error the candidate is an outlier: mark it and move on to the next one.
1012 if( meanShift > newMeanError ) {
1013 outlierCandidate->second->test = false;
1014 mean = newMean;
1015 meanError = newMeanError;
1016 nIn--;
1017 }
1018 else {
1019 return;
1020 }
1021 }
1022}
1023
1025dqm_algorithms::tools::buildCluster( binContainer& seed, const std::vector<std::vector<binContainer*> >& binMap,
1026 const std::vector<double>& xValues, const std::vector<double>& yValues, double threshold, int topology ) {
1027
1028 binCluster cluster = {0.,0.,xValues[seed.ix],yValues[seed.iy],-1.,0,seed.ix,seed.ix,seed.iy,seed.iy};
1029 std::list<binContainer*> binsToCheck;
1030 std::vector<binContainer*> binsInCluster;
1031 binsToCheck.push_back(&seed);
1032 double pvpX = 0;
1033 double pvpY = 0;
1034 double error2 = 0;
1035
1036 double maxDistanceX = -1;
1037 double maxDistanceY = -1;
1038 int ixRangeMax = (int)xValues.size() - 2;
1039 int iyRangeMax = (int)yValues.size() - 2;
1040
1041 switch(topology) {
1042 case CylinderX:
1043 maxDistanceY = (yValues.back() - yValues.front()) / 2;
1044 break;
1045 case CylinderY:
1046 maxDistanceX = (xValues.back() - xValues.front()) / 2;
1047 break;
1048 case Torus:
1049 maxDistanceX = (xValues.back() - xValues.front()) / 2;
1050 maxDistanceY = (yValues.back() - yValues.front()) / 2;
1051 break;
1052 }
1053
1054 while( binsToCheck.size() != 0) {
1055
1056 std::list<binContainer*> newNeighbors;
1057 for( std::list<binContainer*>::const_iterator bin = binsToCheck.begin(); bin != binsToCheck.end(); ++bin ) {
1058
1059 //If bin is a null pointer, continue to the next bin:
1060 if( *bin == 0) {
1061 continue;
1062 }
1063
1064 //If the bin passes the threshold, add its values to the clusters and its neighbors to the list of bins to look at:
1065 //(As long as it hasn't already been added to another cluster or otherwise excluded)
1066 if( ( fabs((*bin)->value) > (threshold + 5*(*bin)->error ) ) && ( (*bin)->test == 0 ) && ((*bin)->error >= 0) ) {
1067 //Add bin to cluster:
1068 binsInCluster.push_back(*bin);
1069 (*bin)->test = 10;
1070
1071 cluster.value += (*bin)->value;
1072 error2 += pow( (*bin)->error, 2);
1073 cluster.n++;
1074
1075 int ix = (*bin)->ix;
1076 int iy = (*bin)->iy;
1077 double xPosition = xValues[ix];
1078 double yPosition = yValues[iy];
1079
1080 //Adjust position information if it looks like we may have jumped a discontinuity
1081 // and such discontinuities are expected. Also check for max, min ix, iy:
1082 if( (maxDistanceX > 0) && (fabs(xPosition - cluster.x) > maxDistanceX) ) {
1083 //Correct for topological mapping difficulties:
1084 if( xPosition < maxDistanceX ) {
1085 xPosition += 2 * maxDistanceX;
1086 if( (ix + ixRangeMax) > cluster.ixmax ) {
1087 cluster.ixmax = ix + ixRangeMax;
1088 }
1089 }
1090 else {
1091 xPosition -= 2 * maxDistanceX;
1092 if( (ix - ixRangeMax) < cluster.ixmin ) {
1093 cluster.ixmin = ix - ixRangeMax;
1094 }
1095 }
1096 }
1097 else {
1098 //No topological difficulties:
1099 if( ix < cluster.ixmin ) {
1100 cluster.ixmin = ix;
1101 }
1102 if( ix > cluster.ixmax ) {
1103 cluster.ixmax = ix;
1104 }
1105 }
1106
1107 if( (maxDistanceY > 0) && (fabs(yPosition - cluster.y) > maxDistanceY) ) {
1108 //Correct for topological mapping difficulties:
1109 if( yPosition < maxDistanceY ) {
1110 yPosition += 2 * maxDistanceY;
1111 if( (iy + iyRangeMax) > cluster.iymax ) {
1112 cluster.iymax = iy + iyRangeMax;
1113 }
1114 }
1115 else {
1116 yPosition -= 2 * maxDistanceY;
1117 if( (iy - iyRangeMax) < cluster.iymin ) {
1118 cluster.iymin = iy - iyRangeMax;
1119 }
1120 }
1121 }
1122 else {
1123 //No topological difficulties:
1124 if( iy < cluster.iymin ) {
1125 cluster.iymin = iy;
1126 }
1127 if( iy > cluster.iymax ) {
1128 cluster.iymax = iy;
1129 }
1130 }
1131
1132 pvpX += xPosition * (*bin)->value;
1133 pvpY += yPosition * (*bin)->value;
1134
1135
1136 //Find neighbors
1137 newNeighbors.push_back( binMap[ix+1][iy+1] );
1138 newNeighbors.push_back( binMap[ix+1][iy] );
1139 newNeighbors.push_back( binMap[ix+1][iy-1] );
1140
1141 newNeighbors.push_back( binMap[ix][iy+1] );
1142 newNeighbors.push_back( binMap[ix][iy-1] );
1143
1144 newNeighbors.push_back( binMap[ix-1][iy+1] );
1145 newNeighbors.push_back( binMap[ix-1][iy] );
1146 newNeighbors.push_back( binMap[ix-1][iy-1] );
1147
1148
1149 }
1150 }//End looping over binsToCheck (last set of neighbors)
1151
1152 //Remove repeated references to the same bin:
1153 newNeighbors.unique();
1154 //Perpare to check the cluster's new neighbors:
1155 binsToCheck = std::move(newNeighbors);
1156
1157 if (cluster.value != 0) {
1158 cluster.x = pvpX / cluster.value;
1159 cluster.y = pvpY / cluster.value;
1160 }
1161 else {
1162 cluster.x = cluster.y = 0;
1163 }
1164 }//Finished finding bins in cluster
1165
1166 //Assume that the input errors are uncorrelated (or that the caller will deal with this)
1167 cluster.error = sqrt( error2 );
1168
1169 //loop to calculate the radius of the cluster (the value weighted average distance from its center)
1170 double dvpSum = 0;
1171 for(std::vector<binContainer*>::const_iterator bin = binsInCluster.begin(); bin != binsInCluster.end(); ++bin) {
1172 double xDistance = fabs( xValues[(*bin)->ix] - cluster.x );
1173 double yDistance = fabs( yValues[(*bin)->iy] - cluster.y );
1174 if (maxDistanceX > 0 && (xDistance > maxDistanceX) ) {
1175 xDistance = 2 * maxDistanceX - xDistance;
1176 }
1177 if (maxDistanceY > 0 && (yDistance > maxDistanceY) ) {
1178 yDistance = 2 * maxDistanceY - yDistance;
1179 }
1180
1181 dvpSum += (*bin)->value * sqrt( pow( xValues[(*bin)->ix] - cluster.x,2) + pow(yValues[(*bin)->iy] - cluster.y,2) );
1182 }
1183 cluster.radius = dvpSum / cluster.value;
1184
1185 //Check that positions are within the bounds of the histogram and correct
1186 while( cluster.ixmin < 1 ){
1187 cluster.ixmin += ixRangeMax;
1188 }
1189 while( cluster.ixmax > ixRangeMax ){
1190 cluster.ixmax -= ixRangeMax;
1191 }
1192 while( cluster.iymin < 1 ){
1193 cluster.iymin += iyRangeMax;
1194 }
1195 while( cluster.iymax > iyRangeMax ){
1196 cluster.iymax -= iyRangeMax;
1197 }
1198
1199 if( cluster.x < xValues.front() ) {
1200 cluster.x += 2 * maxDistanceX;
1201 }
1202 if( cluster.x > xValues.back() ) {
1203 cluster.x -= 2 * maxDistanceX;
1204 }
1205 if( cluster.y < yValues.front() ) {
1206 cluster.y += 2 * maxDistanceY;
1207 }
1208 if( cluster.y > yValues.back() ) {
1209 cluster.y -= 2 * maxDistanceY;
1210 }
1211
1212
1213 return cluster;
1214}
1215
1216
1217//Method to map bins in binContainer based on binContainer::ix, binContainer::iy, and chosen topology
1218std::vector<std::vector<dqm_algorithms::tools::binContainer*> >
1219dqm_algorithms::tools::makeBinMap(std::vector<dqm_algorithms::tools::binContainer>& bins, int ixmax, int iymax, int topology) {
1220
1221 std::vector<binContainer*> emptyVector;
1222 for(int iy = 0; iy <= iymax + 1; ++iy) {
1223 binContainer* emptyPointer = 0;
1224 emptyVector.push_back(emptyPointer);
1225 }
1226 std::vector<std::vector<binContainer*> > binMap;
1227 for(int ix = 0; ix <= ixmax + 1; ++ix) {
1228 binMap.push_back(emptyVector);
1229 }
1230 switch(topology) {
1231 //The mapping depends on the topology of the histogram.
1232 case CylinderX:
1233 //Cylinder About X-Axis (default topology), wraps max Y to min Y.
1234 //Connect iy == 1 with iy == iymax while leaving hard (null pointer) walls at ix = 0 and ix = imax+1:
1235 for (std::vector<binContainer>::iterator it = bins.begin(); it != bins.end(); ++it) {
1236 binMap[it->ix][it->iy] = &(*it);
1237 if(it->iy == 1){
1238 binMap[it->ix][iymax+1] = &(*it);
1239 }
1240 else if(it->iy == iymax){
1241 binMap[it->ix][0] = &(*it);
1242 }
1243 }
1244 break;
1245
1246 case CylinderY:
1247 //Cylinder About Y-Axis
1248 //Connect ix == 1 with ix == ixmax while leaving hard (null pointer) walls at iy = 0 and iy = imax+1:
1249 for (std::vector<binContainer>::iterator it = bins.begin(); it != bins.end(); ++it) {
1250 binMap[it->ix][it->iy] = &(*it);
1251 if(it->ix == 1){
1252 binMap[ixmax+1][it->iy] = &(*it);
1253 }
1254 else if(it->ix == ixmax){
1255 binMap[0][it->iy] = &(*it);
1256 }
1257 }
1258 break;
1259
1260 case Torus:
1261 //Torus:
1262 //Connect iy == 1 with iy == iymax and ix == 1 with ix == ixmax
1263 for (std::vector<binContainer>::iterator it = bins.begin(); it != bins.end(); ++it) {
1264 binMap[it->ix][it->iy] = &(*it);
1265 if(it->ix == 1){
1266 binMap[ixmax+1][it->iy] = &(*it);
1267 if(it->iy == 1){
1268 binMap[ixmax+1][iymax+1] = &(*it);
1269 }
1270 if(it->iy == iymax){
1271 binMap[ixmax+1][0] = &(*it);
1272 }
1273 }
1274 else if(it->ix == ixmax){
1275 binMap[0][it->iy] = &(*it);
1276 if(it->iy == 1){
1277 binMap[0][iymax+1] = &(*it);
1278 }
1279 if(it->iy == iymax){
1280 binMap[0][0] = &(*it);
1281 }
1282 }
1283 if(it->iy == 1){
1284 binMap[it->ix][iymax+1] = &(*it);
1285 }
1286 else if(it->iy == iymax){
1287 binMap[it->ix][0] = &(*it);
1288 }
1289 }
1290 break;
1291
1292 default:
1293 //Rectangle:
1294 //Treat the histogram as a simple rectangle, leaving null pointers at its boundaries:
1295 for (std::vector<binContainer>::iterator it = bins.begin(); it != bins.end(); ++it) {
1296 binMap[it->ix][it->iy] = &(*it);
1297 }
1298 }
1299 return binMap;
1300}
1301
1302//An attempt to generalize the status combination process with the use of weights:
1303//Worst Case:
1304dqm_core::Result::Status
1305dqm_algorithms::tools::WorstCaseAddStatus(dqm_core::Result::Status baseStatus, dqm_core::Result::Status addedStatus, float weight) {
1306 //-- Acts analogously to a logical OR -- (Red <-> True, etc.)
1307
1308 if(baseStatus == dqm_core::Result::Red) {
1309 return dqm_core::Result::Red;
1310 }
1311 //apply the "weight" to addedstatus only:
1312 if( weight <= 0 ) {
1313 return baseStatus;
1314 }
1315
1316 if( weight <= 0.25 ) {
1317 if( addedStatus == dqm_core::Result::Yellow ) {
1318 addedStatus = dqm_core::Result::Green;
1319 }
1320 }
1321 if( weight <= 0.5 ) {
1322 if( addedStatus == dqm_core::Result::Red) {
1323 addedStatus = dqm_core::Result::Yellow;
1324 }
1325 }
1326
1327 if(addedStatus == dqm_core::Result::Red) {
1328 return dqm_core::Result::Red;
1329 }
1330
1331 if(baseStatus == dqm_core::Result::Disabled) {
1332 return addedStatus;
1333 }
1334 if(addedStatus == dqm_core::Result::Disabled) {
1335 return baseStatus;
1336 }
1337 if(baseStatus == dqm_core::Result::Undefined) {
1338 return addedStatus;
1339 }
1340 if(addedStatus == dqm_core::Result::Undefined) {
1341 return baseStatus;
1342 }
1343
1344 if( (baseStatus == dqm_core::Result::Green) && (addedStatus == dqm_core::Result::Green) ) {
1345 return dqm_core::Result::Green;
1346 }
1347
1348 return dqm_core::Result::Yellow;
1349}
1350//Best Case:
1351dqm_core::Result::Status
1352dqm_algorithms::tools::BestCaseAddStatus(dqm_core::Result::Status baseStatus, dqm_core::Result::Status addedStatus, float weight) {
1353 //-- Acts analogously to a logical AND -- (Red <-> True, etc.)
1354
1355 //apply the "weight" to addedstatus only: (same scheme as in WorstCaseAddStatus)
1356 if( weight <= 0 ) {
1357 return baseStatus;
1358 }
1359 if( weight <= 0.25 ) {
1360 if( addedStatus == dqm_core::Result::Yellow ) {
1361 addedStatus = dqm_core::Result::Green;
1362 }
1363 }
1364 if( weight <= 0.5 ) {
1365 if( addedStatus == dqm_core::Result::Red) {
1366 addedStatus = dqm_core::Result::Yellow;
1367 }
1368 }
1369
1370 if( (baseStatus == dqm_core::Result::Disabled) || (addedStatus == dqm_core::Result::Disabled) ) {
1371 return dqm_core::Result::Disabled;
1372 }
1373
1374 if( (baseStatus == dqm_core::Result::Undefined) || (addedStatus == dqm_core::Result::Undefined) ) {
1375 return dqm_core::Result::Undefined;
1376 }
1377
1378 if( (baseStatus == dqm_core::Result::Green) || (addedStatus == dqm_core::Result::Green) ) {
1379 return dqm_core::Result::Green;
1380 }
1381
1382 if( (baseStatus == dqm_core::Result::Red) && (addedStatus == dqm_core::Result::Red) ) {
1383 return dqm_core::Result::Red;
1384 }
1385
1386 return dqm_core::Result::Yellow;
1387
1388}
1389
1390
1391std::pair<double,double>
1392dqm_algorithms::tools::CalcBinsProbChisq(const std::vector<double>& inputval,const std::vector<double>& inputerr,const std::vector<double>& x0,const std::vector<double>& x0err){
1393
1394 double chisq = 0.;
1395 std::vector<double>::const_iterator iter_vals = inputval.begin();
1396 std::vector<double>::const_iterator iter_err = inputerr.begin();
1397
1398 std::vector<double>::const_iterator iter_x0 = x0.begin();
1399 std::vector<double>::const_iterator iter_x0err = x0err.begin();
1400
1401 int ndf = 0;
1402 for ( ; iter_vals != inputval.end(); ++iter_vals,++iter_err,++iter_x0,++iter_x0err){
1403 if (fabs(*iter_err) > 1.0e-5 || fabs(*iter_x0err) > 1.0e-5){
1404 double chisq_cont = pow(((*iter_vals)-(*iter_x0)),2.)/(pow(*iter_err,2.0)+pow(*iter_x0err,2.0));
1405 ++ndf;
1406 chisq += chisq_cont;
1407 }
1408 }
1409
1410 double prob = ROOT::Math::chisquared_cdf_c(chisq,ndf);
1411 double sigma_chisq = ROOT::Math::normal_quantile_c(prob,1.);
1412 return std::make_pair(prob,sigma_chisq);
1413}
1414
1415std::pair<double,double>
1416dqm_algorithms::tools::CalcBinsProbChisq(const std::vector<double>& inputval,const std::vector<double>& inputerr,double x0,double x0_err){
1417
1418 double chisq = 0.;
1419 std::vector<double>::const_iterator iter_vals = inputval.begin();
1420 std::vector<double>::const_iterator iter_err = inputerr.begin();
1421 int ndf = 0;
1422 for ( ; iter_vals != inputval.end(); ++iter_vals,++iter_err){
1423 if (fabs(*iter_err) > 1.0e-5){
1424 double chisq_cont = pow(((*iter_vals)-x0),2.)/(pow(*iter_err,2.0)+pow(x0_err,2.0));
1425 ++ndf;
1426 chisq += chisq_cont;
1427 }
1428 }
1429
1430 double prob = ROOT::Math::chisquared_cdf_c(chisq,ndf);
1431 double sigma_chisq = ROOT::Math::normal_quantile_c(prob,1.);
1432 return std::make_pair(prob,sigma_chisq);
1433}
1434
1435void
1436dqm_algorithms::tools::MergePastMinStat(std::vector<std::vector<tools::binContainer> >& strips, int minStat) {
1437 //Method to merge neighboring vectors so that all non-empty vectors have a size of at least minStat
1438 //If two vectors are equally close to the vector with size < minstat, it will be merged with the one
1439 //with the smallest size.
1440
1441 if(strips.size() < 2) {
1442 return;
1443 }
1444
1445 std::vector<std::vector<tools::binContainer> >::iterator begining = strips.begin();
1446 std::vector<std::vector<tools::binContainer> >::iterator ending = strips.end();
1447 --ending;
1448
1449 while ( begining != ending ) {
1450 std::vector<std::vector<tools::binContainer> >::iterator minBinsItr = begining;
1451 for( std::vector<std::vector<tools::binContainer> >::iterator itr = begining; itr != (ending+1); ++itr ) {
1452 if( (!itr->empty()) && ((itr->size() < minBinsItr->size()) || minBinsItr->empty()) ) {
1453 minBinsItr = itr;
1454 }
1455 }
1456
1457 if( ((int)minBinsItr->size()) < minStat ) {
1458 if( minBinsItr == begining ) {
1459 //Merge right
1460 std::vector<std::vector<tools::binContainer> >::iterator mergeStripItr = minBinsItr;
1461 ++mergeStripItr;
1462 while( mergeStripItr->empty() ) {
1463 ++mergeStripItr;
1464 if( mergeStripItr == ending ) break;
1465 }
1466 mergeStripItr->insert( mergeStripItr->end(), minBinsItr->begin(), minBinsItr->end() );
1467 minBinsItr->clear();
1468 begining = mergeStripItr;
1469 }
1470 else if( minBinsItr == ending ) {
1471 //Merge left
1472 std::vector<std::vector<tools::binContainer> >::iterator mergeStripItr = minBinsItr;
1473 --mergeStripItr;
1474 while( mergeStripItr->empty() ) {
1475 --mergeStripItr;
1476 if( mergeStripItr == begining ) break;
1477 }
1478 mergeStripItr->insert( mergeStripItr->end(), minBinsItr->begin(), minBinsItr->end() );
1479 minBinsItr->clear();
1480 ending = mergeStripItr;
1481 }
1482 else {
1483 //Merge with the smallest of nearest neighbors:
1484 std::vector<std::vector<tools::binContainer> >::iterator mergeLeftItr = minBinsItr;
1485 std::vector<std::vector<tools::binContainer> >::iterator mergeRightItr = minBinsItr;
1486 --mergeLeftItr;
1487 ++mergeRightItr;
1488 while( mergeLeftItr->empty() && mergeRightItr->empty() ) {
1489 --mergeLeftItr;
1490 ++mergeRightItr;
1491 }
1492 if( mergeLeftItr->empty() ) {
1493 mergeRightItr->insert( mergeRightItr->end(), minBinsItr->begin(), minBinsItr->end() );
1494 minBinsItr->clear();
1495 }
1496 else if( mergeRightItr->empty() ) {
1497 mergeLeftItr->insert( mergeLeftItr->end(), minBinsItr->begin(), minBinsItr->end() );
1498 minBinsItr->clear();
1499 }
1500 else {
1501 if( mergeLeftItr->size() < mergeRightItr->size() ) {
1502 mergeLeftItr->insert( mergeLeftItr->end(), minBinsItr->begin(), minBinsItr->end() );
1503 minBinsItr->clear();
1504 }
1505 else {
1506 mergeRightItr->insert( mergeRightItr->end(), minBinsItr->begin(), minBinsItr->end() );
1507 minBinsItr->clear();
1508 }
1509 }
1510 }
1511 }
1512 else {
1513 break;
1514 }
1515 }
1516}
1517
1518void
1520 if(bin.error < 0) {
1521 return;
1522 }
1523 tag += "(eta,phi)[err]= (";
1524 FormatToSize(bin.x,6,tag,true);
1525 tag += ",";
1526 FormatToSize(bin.y,6,tag,true);
1527 tag += ")[";
1528 FormatToSize(bin.error,5,tag,false);
1529 tag += "]";
1530}
1531
1532void
1533dqm_algorithms::tools::FormatToSize( double value, int size, std::string & str, bool showSign) {
1534 //Method to append size characters representing value to string str
1535
1536 char temp[35];
1537
1538 if( value == 0 ) {
1539 int prec = size - 2;
1540 if(prec < 0) prec = 0;
1541 sprintf(temp,"%.*f",prec,value);
1542 str += temp;
1543 return;
1544 }
1545
1546 std::string format;
1547 if(showSign) {
1548 format = "%+0*.*";
1549 }
1550 else {
1551 format = "%0*.*";
1552 }
1553
1554 int order = (int) floor( log10(fabs(value)) );
1555
1556 if( (size > 34) || (size < 1) || ((size < 5) && (order > size)) ) {
1557 size = 5;
1558 }
1559
1560 int prec = 0;
1561 if( (value > 0) && !showSign ) {
1562 if( ( (abs(order) > (size-3)) || (order < -2) ) && (size > 4) ) {
1563 prec = size-6;
1564 if(prec < 0) prec = 0;
1565 format += "e";
1566 }
1567 else if( order == -1 ) {
1568 prec = size - 2;
1569 if(prec < 0) prec = 0;
1570 format += "f";
1571 }
1572 else {
1573 prec = size - order -2;
1574 if(prec > (size - 2) ) prec = size - 2;
1575 if(prec < 0) prec = 0;
1576 format += "f";
1577 }
1578 }
1579 else {
1580 if( ( (abs(order) > (size-3)) || (order < -2) ) && (size > 4) ) {
1581 prec = size-7;
1582 if(prec < 0) prec = 0;
1583 format += "e";
1584 }
1585 else if( order == -1 ) {
1586 prec = size - 3;
1587 if(prec < 0) prec = 0;
1588 format += "f";
1589 }
1590 else {
1591 prec = size - order -3;
1592 if(prec > (size - 3) ) prec = size - 3;
1593 if(prec < 0) prec = 0;
1594 format += "f";
1595 }
1596 }
1597
1598 sprintf(temp,format.c_str(),size,prec,value);
1599
1600 str += temp;
1601}
1602
1603#endif // #ifndef DQM_ALGORITHMS_TOOLS_ALGORITHMHELPER_CXX
static const std::vector< std::string > bins
#define y
#define x
constexpr int pow(int base, int exp) noexcept
std::string histogram
Definition chains.cxx:52
Header file for AthHistogramAlgorithm.
const_iterator begin() const
const_iterator end() const
void mean(std::vector< double > &bins, std::vector< double > &values, const std::vector< std::string > &files, const std::string &histname, const std::string &tplotname, const std::string &label="")
std::string algorithm
Definition hcg.cxx:85
double xmax
Definition listroot.cxx:61
double ymin
Definition listroot.cxx:63
double xmin
Definition listroot.cxx:60
double ymax
Definition listroot.cxx:64
void FormatToSize(double value, int size, std::string &str, bool showSign=true)
std::vector< int > GetBinRange(const TH1 *histogram, const std::map< std::string, double > &params)
dqm_core::Result::Status WorstCaseAddStatus(dqm_core::Result::Status baseStatus, dqm_core::Result::Status addedStatus, float weight=1.0)
void findOutliersUsingErrors(std::vector< binContainer > &input, double &mean, double &meanError, int &nIn, double mindiff=0, int minNin=4)
std::pair< double, double > CalcBinsProbChisq(const std::vector< double > &inputval, const std::vector< double > &inputerr, double x0, double x0_err)
double GetFirstFromMap(const std::string &paramName, const std::map< std::string, double > &params)
TH1 * DivideByHistogram(const TH1 *hNumerator, const TH1 *hDenominator)
std::vector< std::vector< binContainer * > > makeBinMap(std::vector< dqm_algorithms::tools::binContainer > &bins, int ixmax, int iymax, int topology=CylinderX)
dqm_core::Result * CompareWithErrors(const std::map< std::string, double > &algparams, const std::map< std::string, double > &paramErrors, const std::map< std::string, double > &gthreshold, const std::map< std::string, double > &rthreshold, double minSig)
TH1 * BookHistogramByExample(const TH1 *histogram, const std::string &name, const std::string &title, AxisType axisType)
void MakeBinTag(const binContainer &bin, std::string &tag)
void MergePastMinStat(std::vector< std::vector< tools::binContainer > > &strips, int minStat)
dqm_core::Result * GetFitResult(const TF1 *func, const dqm_core::AlgorithmConfig &config, double minSig=0)
std::string ExtractAlgorithmName(const dqm_core::AlgorithmConfig &config)
void findOutliers(std::vector< binContainer > &input, double &mean, double &scale, int &nIn, int nIterations, double exponent, double threshold, double SBCF=1., double nStop=8.)
std::map< std::string, double > GetFitParamErrors(const TF1 *func)
dqm_core::Result * MakeComparisons(const std::map< std::string, double > &algparams, const std::map< std::string, double > &gthreshold, const std::map< std::string, double > &rthreshold)
dqm_core::Result::Status BestCaseAddStatus(dqm_core::Result::Status baseStatus, dqm_core::Result::Status addedStatus, float weight=1.0)
dqm_core::Result * ExecuteNamedAlgorithm(const std::string &name, const TObject &object, const dqm_core::AlgorithmConfig &config)
void ModifyHistogram(TH1 *histogram, const dqm_core::AlgorithmConfig &config)
std::map< std::string, double > GetFitParams(const TF1 *func)
binCluster buildCluster(binContainer &seed, const std::vector< std::vector< binContainer * > > &binMap, const std::vector< double > &xValues, const std::vector< double > &yValues, double threhold, int topology=CylinderX)
void handleReference(const TObject &inputReference, const TObject *&firstReference, TObject *&secondReference)
Helper function used to handle complex reference histograms This function gets as input a reference o...
void PublishBin(const TH1 *histogram, int xbin, int ybin, double content, dqm_core::Result *result)