Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
HFitInterface.cxx
Go to the documentation of this file.
1// @(#)root/hist:$Id$
2// Author: L. Moneta Thu Aug 31 10:40:20 2006
3
4/**********************************************************************
5 * *
6 * Copyright (c) 2006 LCG ROOT Math Team, CERN/PH-SFT *
7 * *
8 * *
9 **********************************************************************/
10
11// Implementation file for class TH1Interface
12
13#include "HFitInterface.h"
14
15#include "Fit/BinData.h"
16#include "Fit/SparseData.h"
17#include "Fit/FitResult.h"
18#include "Math/IParamFunction.h"
19
20#include <cassert>
21#include <cmath>
22#include <utility>
23#include <vector>
24
25#include "TH1.h"
26#include "THnBase.h"
27#include "TF1.h"
28#include "TGraph2D.h"
29#include "TGraph.h"
30#include "TGraphErrors.h"
31#include "TMultiGraph.h"
32#include "TList.h"
33#include "TError.h"
34
35
36//#define DEBUG
37#ifdef DEBUG
38#include "TClass.h"
39#include <iostream>
40#endif
41
42
43namespace ROOT {
44
45namespace Fit {
46
47// add a namespace to distinguish from the Graph functions
48namespace HFitInterface {
49
50
51bool IsPointOutOfRange(const TF1 * func, const double * x) {
52 // function to check if a point is outside range
53 if (func ==nullptr) return false;
54 return !func->IsInside(x);
55}
56
57bool AdjustError(const DataOptions & option, double & error, double value = 1) {
58 // adjust the given error according to the option
59 // return false when point must be skipped.
60 // When point error = 0, the point is kept if the option UseEmpty is set or if
61 // fErrors1 is set and the point value is not zero.
62 // The value should be used only for points representing counts (histograms), not for the graph.
63 // In the graph points with zero errors are by default skipped indepentently of the value.
64 // If one wants to keep the points, the option fUseEmpty must be set
65
66 if (error <= 0) {
67 if (option.fUseEmpty || (option.fErrors1 && std::abs(value) > 0 ) )
68 error = 1.; // set error to 1
69 else
70 return false; // skip bins with zero errors or empty
71 } else if (option.fErrors1)
72 error = 1; // set all error to 1 for non-empty bins
73 return true;
74}
75
76void ExamineRange(const TAxis * axis, std::pair<double,double> range,int &hxfirst,int &hxlast) {
77 // examine the range given with the pair on the given histogram axis
78 // correct in case the bin values hxfirst hxlast
79 double xlow = range.first;
80 double xhigh = range.second;
81#ifdef DEBUG
82 std::cout << "xlow " << xlow << " xhigh = " << xhigh << std::endl;
83#endif
84 // ignore ranges specified outside histogram range
85 int ilow = axis->FindFixBin(xlow);
86 int ihigh = axis->FindFixBin(xhigh);
87 if (ilow > hxlast || ihigh < hxfirst) {
88 Warning("ROOT::Fit::FillData","fit range is outside histogram range, no fit data for %s",axis->GetName());
89 }
90 // consider only range defined with-in histogram not oustide. Always exclude underflow/overflow
91 hxfirst = std::min( std::max( ilow, hxfirst), hxlast+1) ;
92 hxlast = std::max( std::min( ihigh, hxlast), hxfirst-1) ;
93 // exclude bins where range coverage is less than half bin width
94 if (hxfirst < hxlast) {
95 if ( axis->GetBinCenter(hxfirst) < xlow) hxfirst++;
96 if ( axis->GetBinCenter(hxlast) > xhigh) hxlast--;
97 }
98}
99
100
101} // end namespace HFitInterface
102
103
104void FillData(BinData & dv, const TH1 * hfit, TF1 * func)
105{
106 // Function to fill the binned Fit data structure from a TH1
107 // The dimension of the data is the same of the histogram dimension
108 // The function pointer is need in case of integral is used and to reject points
109 // rejected in the function
110
111 // the TF1 pointer cannot be constant since EvalPar and InitArgs are not const methods
112
113 // get fit option
114 const DataOptions & fitOpt = dv.Opt();
115
116
117 // store instead of bin center the bin edges
118 bool useBinEdges = fitOpt.fIntegral || fitOpt.fBinVolume;
119
120 assert(hfit != nullptr);
121
122 //std::cout << "creating Fit Data from histogram " << hfit->GetName() << std::endl;
123
124 int hxfirst = hfit->GetXaxis()->GetFirst();
125 int hxlast = hfit->GetXaxis()->GetLast();
126
127 int hyfirst = hfit->GetYaxis()->GetFirst();
128 int hylast = hfit->GetYaxis()->GetLast();
129
130 int hzfirst = hfit->GetZaxis()->GetFirst();
131 int hzlast = hfit->GetZaxis()->GetLast();
132
133 // function by default has same range (use that one if requested otherwise use data one)
134
135
136 // get the range (add the function range ??)
137 // to check if inclusion/exclusion at end/point
138 const DataRange & range = dv.Range();
139 if (range.Size(0) != 0) {
141 if (range.Size(0) > 1 ) {
142 Warning("ROOT::Fit::FillData","support only one range interval for X coordinate");
143 }
144 }
145
146 if (hfit->GetDimension() > 1 && range.Size(1) != 0) {
148 if (range.Size(1) > 1 )
149 Warning("ROOT::Fit::FillData","support only one range interval for Y coordinate");
150 }
151
152 if (hfit->GetDimension() > 2 && range.Size(2) != 0) {
154 if (range.Size(2) > 1 )
155 Warning("ROOT::Fit::FillData","support only one range interval for Z coordinate");
156 }
157
158
159 int n = (hxlast-hxfirst+1)*(hylast-hyfirst+1)*(hzlast-hzfirst+1);
160
161#ifdef DEBUG
162 std::cout << "THFitInterface: ifirst = " << hxfirst << " ilast = " << hxlast
163 << " total bins " << n
164 << std::endl;
165#endif
166
167 // reserve n for more efficient usage
168 //dv.Data().reserve(n);
169
170 int hdim = hfit->GetDimension();
171 int ndim = hdim;
172 // case of function dimension less than histogram
173 if (func !=nullptr && func->GetNdim() == hdim-1) ndim = hdim-1;
174
175 assert( ndim > 0 );
176 //typedef BinPoint::CoordData CoordData;
177 //CoordData x = CoordData( hfit->GetDimension() );
179
180 double x[3];
181 double s[3];
182
183 int binx = 0;
184 int biny = 0;
185 int binz = 0;
186
187 const TAxis *xaxis = hfit->GetXaxis();
188 const TAxis *yaxis = hfit->GetYaxis();
189 const TAxis *zaxis = hfit->GetZaxis();
190
191 for ( binx = hxfirst; binx <= hxlast; ++binx) {
192 if (useBinEdges) {
193 x[0] = xaxis->GetBinLowEdge(binx);
194 s[0] = xaxis->GetBinUpEdge(binx);
195 }
196 else
197 x[0] = xaxis->GetBinCenter(binx);
198
199
200 for ( biny = hyfirst; biny <= hylast; ++biny) {
201 if (useBinEdges) {
202 x[1] = yaxis->GetBinLowEdge(biny);
203 s[1] = yaxis->GetBinUpEdge(biny);
204 }
205 else
206 x[1] = yaxis->GetBinCenter(biny);
207
208 for ( binz = hzfirst; binz <= hzlast; ++binz) {
209 if (useBinEdges) {
210 x[2] = zaxis->GetBinLowEdge(binz);
211 s[2] = zaxis->GetBinUpEdge(binz);
212 }
213 else
214 x[2] = zaxis->GetBinCenter(binz);
215
216 // need to evaluate function to know about rejected points
217 // hugly but no other solutions
218 if (func != nullptr) {
219 TF1::RejectPoint(false);
220 (*func)( &x[0] ); // evaluate using stored function parameters
221 if (TF1::RejectedPoint() ) continue;
222 }
223
224
225 double value = hfit->GetBinContent(binx, biny, binz);
226 double error = hfit->GetBinError(binx, biny, binz);
227 if (!HFitInterface::AdjustError(fitOpt,error,value) ) continue;
228
229 if (ndim == hdim -1) {
230 // case of fitting a function with dimension -1
231 // point error is bin width y / sqrt(N) where N is the number of entries in the bin
232 // normalization of error will be wrong - but they will be rescaled in the fit
233 if (hdim == 2) dv.Add( x, x[1], yaxis->GetBinWidth(biny) / error );
234 if (hdim == 3) dv.Add( x, x[2], zaxis->GetBinWidth(binz) / error );
235 } else {
236 if (fitOpt.fErrors1)
237 dv.Add( x, value );
238 else
239 dv.Add( x, value, error );
240 if (useBinEdges) {
241 dv.AddBinUpEdge( s );
242 }
243 }
244
245
246#ifdef DEBUG
247 std::cout << "bin " << binx << " add point " << x[0] << " " << hfit->GetBinContent(binx) << std::endl;
248#endif
249
250 } // end loop on z bins
251 } // end loop on y bins
252 } // end loop on x axis
253
254
255#ifdef DEBUG
256 std::cout << "THFitInterface::FillData: Hist FitData size is " << dv.Size() << std::endl;
257#endif
258
259}
260
261////////////////////////////////////////////////////////////////////////////////
262/// Compute rough values of parameters for an exponential
263
265{
266 unsigned int n = data.Size();
267 if (n == 0) return;
268
269 // find xmin and xmax of the data
270 double valxmin;
271 double xmin = *(data.GetPoint(0,valxmin));
272 double xmax = xmin;
273 double valxmax = valxmin;
274
275 for (unsigned int i = 1; i < n; ++ i) {
276 double val;
277 double x = *(data.GetPoint(i,val) );
278 if (x < xmin) {
279 xmin = x;
280 valxmin = val;
281 }
282 else if (x > xmax) {
283 xmax = x;
284 valxmax = val;
285 }
286 }
287
288 // avoid negative values of valxmin/valxmax
291 else if (valxmin <=0 && valxmax <= 0) { valxmin = 1; valxmax = 1; }
292
293 double slope = std::log( valxmax/valxmin) / (xmax - xmin);
294 double constant = std::log(valxmin) - slope * xmin;
296}
297
298////////////////////////////////////////////////////////////////////////////////
299/// Compute rough values of parameters for a first-degree polynomial
300///
301/// Compute starting values for the weighted fit by using an unweighted least-squares line.
302///
303/// Only the first-degree case is handled; a higher degree returns unchanged.
304
306{
307 if (f1->GetNpar() != 2)
308 return;
309
310 unsigned int n = data.Size();
311 if (n < 2)
312 return;
313
314 double sumX = 0, sumY = 0, sumXSq = 0, sumXY = 0;
315 for (unsigned int i = 0; i < n; ++i) {
316 double val;
317 double x = *(data.GetPoint(i, val));
318 sumX += x;
319 sumY += val;
320 sumXSq += x * x;
321 sumXY += x * val;
322 }
323
324 // Vanishes when every point shares one x: no line to estimate, leave as is.
325 double det = n * sumXSq - sumX * sumX;
326 if (det == 0)
327 return;
328
329 double slope = (n * sumXY - sumX * sumY) / det;
330 f1->SetParameters((sumY - slope * sumX) / n, slope);
331}
332
333////////////////////////////////////////////////////////////////////////////////
334/// Compute Initial values of parameters for a gaussian
335/// derived from function H1InitGaus defined in TH1.cxx
336
338{
339
340 static const double sqrtpi = 2.506628;
341
342 // - Compute mean value and RMS of the data
343 unsigned int n = data.Size();
344 if (n == 0) return;
345 double sumx = 0;
346 double sumx2 = 0;
347 double allcha = 0;
348 double valmax = 0;
349 double rangex = data.Coords(n-1)[0] - data.Coords(0)[0];
350 // to avoid binwidth = 0 set arbitrarly to 1
351 double binwidth = 1;
352 if ( rangex > 0) binwidth = rangex;
353 double x0 = 0;
354 for (unsigned int i = 0; i < n; ++ i) {
355 double val;
356 double x = *(data.GetPoint(i,val) );
357 sumx += val*x;
358 sumx2 += val*x*x;
359 allcha += val;
360 if (val > valmax) valmax = val;
361 if (i > 0) {
362 double dx = x - x0;
363 if (dx < binwidth) binwidth = dx;
364 }
365 x0 = x;
366 }
367
368 if (allcha <= 0) return;
369 double mean = sumx/allcha;
370 double rms = sumx2/allcha - mean*mean;
371
372
373 if (rms > 0)
374 rms = std::sqrt(rms);
375 else
376 rms = binwidth*n/4;
377
378
379 //if the distribution is really gaussian, the best approximation
380 //is binwidx*allcha/(sqrtpi*rms)
381 //However, in case of non-gaussian tails, this underestimates
382 //the normalisation constant. In this case the maximum value
383 //is a better approximation.
384 //We take the average of both quantities
385
386// printf("valmax %f other %f bw %f allcha %f rms %f \n",valmax, binwidth*allcha/(sqrtpi*rms),
387// binwidth, allcha,rms );
388
389 double constant = 0.5*(valmax+ binwidth*allcha/(sqrtpi*rms));
390
391
392 //In case the mean value is outside the histo limits and
393 //the RMS is bigger than the range, we take
394 // mean = center of bins
395 // rms = half range
396// Double_t xmin = curHist->GetXaxis()->GetXmin();
397// Double_t xmax = curHist->GetXaxis()->GetXmax();
398// if ((mean < xmin || mean > xmax) && rms > (xmax-xmin)) {
399// mean = 0.5*(xmax+xmin);
400// rms = 0.5*(xmax-xmin);
401// }
402
404 f1->SetParameter(1,mean);
405 f1->SetParameter(2,rms);
406 f1->SetParLimits(2,0,10*rms);
407
408
409#ifdef DEBUG
410 std::cout << "Gaussian initial par values" << constant << " " << mean << " " << rms << std::endl;
411#endif
412
413}
414
415////////////////////////////////////////////////////////////////////////////////
416/// Compute Initial values of parameters for a gaussian
417/// derived from function H1InitGaus defined in TH1.cxx
418
420{
421
422 static const double sqrtpi = 2.506628;
423
424 // - Compute mean value and RMS of the data
425 unsigned int n = data.Size();
426 if (n == 0) return;
427 double sumx = 0, sumy = 0;
428 double sumx2 = 0, sumy2 = 0;
429 double allcha = 0;
430 double valmax = 0;
431 double rangex = data.Coords(n-1)[0] - data.Coords(0)[0];
432 double rangey = data.Coords(n-1)[1] - data.Coords(0)[1];
433 // to avoid binwidthx = 0 set arbitrarly to 1
434 double binwidthx = 1, binwidthy = 1;
435 if ( rangex > 0) binwidthx = rangex;
436 if ( rangey > 0) binwidthy = rangey;
437 double x0 = 0, y0 = 0;
438 for (unsigned int i = 0; i < n; ++i) {
439 double val;
440 const double *coords = data.GetPoint(i,val);
441 double x = coords[0], y = coords[1];
442 sumx += val*x;
443 sumy += val*y;
444 sumx2 += val*x*x;
445 sumy2 += val*y*y;
446 allcha += val;
447 if (val > valmax) valmax = val;
448 if (i > 0) {
449 double dx = x - x0;
450 if (dx < binwidthx) binwidthx = dx;
451 double dy = y - y0;
452 if (dy < binwidthy) binwidthy = dy;
453 }
454 x0 = x;
455 y0 = y;
456 }
457
458 if (allcha <= 0) return;
459 double meanx = sumx/allcha, meany = sumy/allcha;
460 double rmsx = sumx2/allcha - meanx*meanx;
461 double rmsy = sumy2/allcha - meany*meany;
462
463
464 if (rmsx > 0)
465 rmsx = std::sqrt(rmsx);
466 else
467 rmsx = binwidthx*n/4;
468
469 if (rmsy > 0)
470 rmsy = std::sqrt(rmsy);
471 else
472 rmsy = binwidthy*n/4;
473
474
475 //if the distribution is really gaussian, the best approximation
476 //is binwidx*allcha/(sqrtpi*rmsx)
477 //However, in case of non-gaussian tails, this underestimates
478 //the normalisation constant. In this case the maximum value
479 //is a better approximation.
480 //We take the average of both quantities
481
482 double constant = 0.5 * (valmax+ binwidthx*allcha/(sqrtpi*rmsx))*
484
487 f1->SetParameter(2,rmsx);
488 f1->SetParLimits(2,0,10*rmsx);
490 f1->SetParameter(4,rmsy);
491 f1->SetParLimits(4,0,10*rmsy);
492
493#ifdef DEBUG
494 std::cout << "2D Gaussian initial par values"
495 << constant << " "
496 << meanx << " "
497 << rmsx
498 << meany << " "
499 << rmsy
500 << std::endl;
501#endif
502
503}
504
505// filling fit data from TGraph objects
506
508 // get type of data for TGraph objects
509 double *ex = gr->GetEX();
510 double *ey = gr->GetEY();
511 double * eyl = gr->GetEYlow();
512 double * eyh = gr->GetEYhigh();
513
514
515 // default case for graphs (when they have errors)
517 // if all errors are zero set option of using errors to 1
518 if (fitOpt.fErrors1 || ( ey == nullptr && ( eyl == nullptr || eyh == nullptr ) ) ) {
520 }
521 // need to treat case when all errors are zero
522 // note that by default fitOpt.fCoordError is true
523 else if ( ex != nullptr && fitOpt.fCoordErrors) {
524 // check that all errors are not zero
525 int i = 0;
526 while (i < gr->GetN() && type != BinData::kCoordError) {
527 if (ex[i] > 0) type = BinData::kCoordError;
528 ++i;
529 }
530 }
531 // case of asymmetric errors (by default fAsymErrors is true)
532 else if ( ( eyl != nullptr && eyh != nullptr) && fitOpt.fAsymErrors) {
533 // check also if that all errors are non zero's
534 int i = 0;
535 bool zeroErrorX = true;
536 bool zeroErrorY = true;
537 while (i < gr->GetN() && (zeroErrorX || zeroErrorY)) {
538 double e2X = ( gr->GetErrorXlow(i) + gr->GetErrorXhigh(i) );
539 double e2Y = eyl[i] + eyh[i];
540 zeroErrorX &= (e2X <= 0);
541 zeroErrorY &= (e2Y <= 0);
542 ++i;
543 }
544 if (zeroErrorX && zeroErrorY)
546 else if (!zeroErrorX && zeroErrorY)
548 else if (zeroErrorX && !zeroErrorY) {
550 fitOpt.fCoordErrors = false;
551 }
552 else {
554 }
555 }
556
557 // need to look also a case when all errors in y are zero
558 if ( ey != nullptr && type != BinData::kCoordError ) {
559 int i = 0;
560 bool zeroError = true;
561 while (i < gr->GetN() && zeroError) {
562 if (ey[i] > 0) zeroError = false;
563 ++i;
564 }
566 }
567
568
569#ifdef DEBUG
570 std::cout << "type is " << type << " graph type is " << gr->IsA()->GetName() << std::endl;
571#endif
572
573 return type;
574}
575
577 // get type of data for TGraph2D object
578 double *ex = gr->GetEX();
579 double *ey = gr->GetEY();
580 double *ez = gr->GetEZ();
581
582 // default case for graphs (when they have errors)
584 // if all errors are zero set option of using errors to 1
585 if (fitOpt.fErrors1 || ez == nullptr ) {
587 }
588 else if ( ex != nullptr && ey!=nullptr && fitOpt.fCoordErrors) {
589 // check that all errors are not zero
590 int i = 0;
591 while (i < gr->GetN() && type != BinData::kCoordError) {
592 if (ex[i] > 0 || ey[i] > 0) type = BinData::kCoordError;
593 ++i;
594 }
595 }
596
597
598#ifdef DEBUG
599 std::cout << "type is " << type << " graph2D type is " << gr->IsA()->GetName() << std::endl;
600#endif
601
602 return type;
603}
604
605
606
607void DoFillData ( BinData & dv, const TGraph * gr, BinData::ErrorType type, TF1 * func ) {
608 // internal method to do the actual filling of the data
609 // given a graph and a multigraph
610
611 // get fit option
612 DataOptions & fitOpt = dv.Opt();
613
614 int nPoints = gr->GetN();
615 double *gx = gr->GetX();
616 double *gy = gr->GetY();
617
618 const DataRange & range = dv.Range();
619 bool useRange = ( range.Size(0) > 0);
620 double xmin = 0;
621 double xmax = 0;
622 range.GetRange(xmin,xmax);
623
624 dv.Initialize(nPoints,1, type);
625
626#ifdef DEBUG
627 std::cout << "DoFillData: graph npoints = " << nPoints << " type " << type << std::endl;
628 if (func) {
629 double a1,a2; func->GetRange(a1,a2); std::cout << "func range " << a1 << " " << a2 << std::endl;
630 }
631#endif
632
633 // Unlike histograms, graphs may have array of points created in
634 // non-ascending order along the X axis. This breaks fitting algorithm. We
635 // create a "remap" for the TGraph point indexes that provides ascending
636 // order of X values for the BinData
637 std::vector<std::pair<double, int>> indexRemap;
638 for (int i = 0; i < nPoints; ++i) {
639 indexRemap.emplace_back(gx[i], i);
640 }
641 std::sort(indexRemap.begin(), indexRemap.end());
642
643 double x[1];
644 for (int j = 0; j < nPoints; ++j) {
645
646 int i = indexRemap[j].second;
647 x[0] = gx[i];
648
649
650 if (useRange && ( x[0] < xmin || x[0] > xmax) ) continue;
651
652 // need to evaluate function to know about rejected points
653 // hugly but no other solutions
654 if (func) {
655 TF1::RejectPoint(false);
656 (*func)( x ); // evaluate using stored function parameters
657 if (TF1::RejectedPoint() ) continue;
658 }
659
660
661 if (fitOpt.fErrors1)
662 dv.Add( gx[i], gy[i] );
663
664 // for the errors use the getters by index to avoid cases when the arrays are zero
665 // (like in a case of a graph)
666 else if (type == BinData::kValueError) {
667 double errorY = gr->GetErrorY(i);
668 // should consider error = 0 as 1 ? Decide to skip points with zero errors
669 // in case want to keep points with error = 0 as errrors=1 need to set the option UseEmpty
671 dv.Add( gx[i], gy[i], errorY );
672
673#ifdef DEBUG
674 std::cout << "Point " << i << " " << gx[i] << " " << gy[i] << " " << errorY << std::endl;
675#endif
676
677
678 }
679 else { // case use error in x or asym errors
680 double errorX = 0;
681 if (fitOpt.fCoordErrors)
682 // shoulkd take combined average (sqrt(0.5(e1^2+e2^2)) or math average ?
683 // gr->GetErrorX(i) returns combined average
684 // use math average for same behaviour as before
685 errorX = std::max( 0.5 * ( gr->GetErrorXlow(i) + gr->GetErrorXhigh(i) ) , 0. ) ;
686
687
688 // adjust error in y according to option
689 double errorY = std::max(gr->GetErrorY(i), 0.);
690 // we do not check the return value since we check later if error in X and Y is zero for skipping the point
692
693 // skip points with total error = 0
694 if ( errorX <=0 && errorY <= 0 ) continue;
695
696
697 if (type == BinData::kAsymError) {
698 // asymmetric errors
699 dv.Add( gx[i], gy[i], errorX, gr->GetErrorYlow(i), gr->GetErrorYhigh(i) );
700 }
701 else {
702 // case symmetric Y errors
703 dv.Add( gx[i], gy[i], errorX, errorY );
704 }
705 }
706
707 }
708
709#ifdef DEBUG
710 std::cout << "TGraphFitInterface::FillData Graph FitData size is " << dv.Size() << std::endl;
711#endif
712
713}
714
715void FillData(SparseData & dv, const TH1 * h1, TF1 * /*func*/)
716{
717 const int dim = h1->GetDimension();
718 std::vector<double> min(dim);
719 std::vector<double> max(dim);
720
721 int ncells = h1->GetNcells();
722 for ( int i = 0; i < ncells; ++i ) {
723// printf("i: %d; OF: %d; UF: %d; C: %f\n"
724// , i
725// , h1->IsBinOverflow(i) , h1->IsBinUnderflow(i)
726// , h1->GetBinContent(i));
727 if ( !( h1->IsBinOverflow(i) || h1->IsBinUnderflow(i) )
728 && h1->GetBinContent(i))
729 {
730 int x,y,z;
731 h1->GetBinXYZ(i, x, y, z);
732
733// std::cout << "FILLDATA: h1(" << i << ")"
734// << "[" << h1->GetXaxis()->GetBinLowEdge(x) << "-" << h1->GetXaxis()->GetBinUpEdge(x) << "]";
735// if ( dim >= 2 )
736// std::cout << "[" << h1->GetYaxis()->GetBinLowEdge(y) << "-" << h1->GetYaxis()->GetBinUpEdge(y) << "]";
737// if ( dim >= 3 )
738// std::cout << "[" << h1->GetZaxis()->GetBinLowEdge(z) << "-" << h1->GetZaxis()->GetBinUpEdge(z) << "]";
739
740// std::cout << h1->GetBinContent(i) << std::endl;
741
742 min[0] = h1->GetXaxis()->GetBinLowEdge(x);
743 max[0] = h1->GetXaxis()->GetBinUpEdge(x);
744 if ( dim >= 2 )
745 {
746 min[1] = h1->GetYaxis()->GetBinLowEdge(y);
747 max[1] = h1->GetYaxis()->GetBinUpEdge(y);
748 }
749 if ( dim >= 3 ) {
750 min[2] = h1->GetZaxis()->GetBinLowEdge(z);
751 max[2] = h1->GetZaxis()->GetBinUpEdge(z);
752 }
753
754 dv.Add(min, max, h1->GetBinContent(i), h1->GetBinError(i));
755 }
756 }
757}
758
759void FillData(SparseData & dv, const THnBase * h1, TF1 * /*func*/)
760{
761 const int dim = h1->GetNdimensions();
762 std::vector<double> min(dim);
763 std::vector<double> max(dim);
764 std::vector<Int_t> coord(dim);
765
766 ULong64_t nEntries = h1->GetNbins();
767 for ( ULong64_t i = 0; i < nEntries; i++ )
768 {
769 double value = h1->GetBinContent( i, &coord[0] );
770 if ( !value ) continue;
771
772// std::cout << "FILLDATA(SparseData): h1(" << i << ")";
773
774 // Exclude underflows and overflows! (defect behaviour with the TH1*)
775 bool insertBox = true;
776 for ( int j = 0; j < dim && insertBox; ++j )
777 {
778 TAxis* axis = h1->GetAxis(j);
779 if ( ( axis->GetBinLowEdge(coord[j]) < axis->GetXmin() ) ||
780 ( axis->GetBinUpEdge(coord[j]) > axis->GetXmax() ) ) {
781 insertBox = false;
782 }
783 min[j] = h1->GetAxis(j)->GetBinLowEdge(coord[j]);
784 max[j] = h1->GetAxis(j)->GetBinUpEdge(coord[j]);
785 }
786 if ( !insertBox ) {
787// std::cout << "NOT INSERTED!"<< std::endl;
788 continue;
789 }
790
791// for ( int j = 0; j < dim; ++j )
792// {
793// std::cout << "[" << h1->GetAxis(j)->GetBinLowEdge(coord[j])
794// << "-" << h1->GetAxis(j)->GetBinUpEdge(coord[j]) << "]";
795// }
796// std::cout << h1->GetBinContent(i) << std::endl;
797
798 dv.Add(min, max, value, h1->GetBinError(i));
799 }
800}
801
802void FillData(BinData & dv, const THnBase * s1, TF1 * func)
803{
804 // Fill the Range of the THnBase
805 unsigned int const ndim = s1->GetNdimensions();
806 std::vector<double> xmin(ndim);
807 std::vector<double> xmax(ndim);
808 for ( unsigned int i = 0; i < ndim; ++i ) {
809 TAxis* axis = s1->GetAxis(i);
810 xmin[i] = axis->GetXmin();
811 xmax[i] = axis->GetXmax();
812 }
813
814 // Put default options, needed for the likelihood fitting of sparse
815 // data.
817 //dopt.fUseEmpty = true;
818 // when using sparse data need to set option to use normalized bin volume, because sparse bins are merged together
819 //if (!dopt.fIntegral) dopt.fBinVolume = true;
820 dopt.fBinVolume = true;
821 dopt.fNormBinVolume = true;
822
823 // Get the sparse data
824 ROOT::Fit::SparseData d(ndim, &xmin[0], &xmax[0]);
825 ROOT::Fit::FillData(d, s1, func);
826
827// std::cout << "FillData(BinData & dv, const THnBase * s1, TF1 * func) (1)" << std::endl;
828
829 // Create the bin data from the sparse data
830 d.GetBinDataIntegral(dv);
831
832}
833
834void FillData ( BinData & dv, const TGraph * gr, TF1 * func ) {
835 // fill the data vector from a TGraph. Pass also the TF1 function which is
836 // needed in case to exclude points rejected by the function
837 assert(gr != nullptr);
838
839 // get fit option
840 DataOptions & fitOpt = dv.Opt();
841
843 // adjust option according to type
844 fitOpt.fErrors1 = (type == BinData::kNoError);
845 // set this if we want to have error=1 for points with zero errors (by default they are skipped)
846 // fitOpt.fUseEmpty = true;
847
848 // use coordinate or asym errors in case option is set and type is consistent
849 fitOpt.fCoordErrors &= (type == BinData::kCoordError) || (type == BinData::kAsymError) ;
850 fitOpt.fAsymErrors &= (type == BinData::kAsymError);
851
852
853 // if data are filled already check if there are consistent - otherwise do nothing
854 if (dv.Size() > 0 && dv.NDim() == 1 ) {
855 // check if size is correct otherwise flag an errors
856 if ( dv.GetErrorType() != type ) {
857 Error("FillData","Inconsistent TGraph with previous data set- skip all graph data");
858 return;
859 }
860 }
861
862 DoFillData(dv, gr, type, func);
863
864}
865
866void FillData ( BinData & dv, const TMultiGraph * mg, TF1 * func ) {
867 // fill the data vector from a TMultiGraph. Pass also the TF1 function which is
868 // needed in case to exclude points rejected by the function
869 assert(mg != nullptr);
870
871 TList * grList = mg->GetListOfGraphs();
872 assert(grList != nullptr);
873
874#ifdef DEBUG
875// grList->Print();
877 TObject *obj;
878 std::cout << "multi-graph list of graps: " << std::endl;
879 while ((obj = itr())) {
880 std::cout << obj->IsA()->GetName() << std::endl;
881 }
882
883#endif
884
885 // get fit option
886 DataOptions & fitOpt = dv.Opt();
887
888 // loop on the graphs to get the data type (use maximum)
889 TIter next(grList);
890
892 TGraph *gr = nullptr;
893 while ((gr = (TGraph*) next())) {
895 if (t > type ) type = t;
896 }
897 // adjust option according to type
898 fitOpt.fErrors1 = (type == BinData::kNoError);
899 // use coordinate or asym errors in case option is set and type is consistent
900 fitOpt.fCoordErrors &= (type == BinData::kCoordError) || (type == BinData::kAsymError);
901 fitOpt.fAsymErrors &= (type == BinData::kAsymError);
902
903
904#ifdef DEBUG
905 std::cout << "Fitting MultiGraph of type " << type << std::endl;
906#endif
907
908 // fill the data now
909 next = grList;
910 while ((gr = (TGraph*) next())) {
911 DoFillData( dv, gr, type, func);
912 }
913
914#ifdef DEBUG
915 std::cout << "TGraphFitInterface::FillData MultiGraph FitData size is " << dv.Size() << std::endl;
916#endif
917
918}
919
920void FillData ( BinData & dv, const TGraph2D * gr, TF1 * func ) {
921 // fill the data vector from a TGraph2D. Pass also the TF1 function which is
922 // needed in case to exclude points rejected by the function
923 // in case of a pure TGraph
924 assert(gr != nullptr);
925
926 // get fit option
927 DataOptions & fitOpt = dv.Opt();
929 // adjust option according to type
930 fitOpt.fErrors1 = (type == BinData::kNoError);
931 fitOpt.fCoordErrors = (type == BinData::kCoordError);
932 fitOpt.fAsymErrors = false; // a TGraph2D with asymmetric errors does not exist
933
934 int nPoints = gr->GetN();
935 double *gx = gr->GetX();
936 double *gy = gr->GetY();
937 double *gz = gr->GetZ();
938
939 // if all errors are zero set option of using errors to 1
940 if ( gr->GetEZ() == nullptr) fitOpt.fErrors1 = true;
941
942 double x[2];
943 double ex[2];
944
945 // look at data range
946 const DataRange & range = dv.Range();
947 bool useRangeX = ( range.Size(0) > 0);
948 bool useRangeY = ( range.Size(1) > 0);
949 double xmin = 0;
950 double xmax = 0;
951 double ymin = 0;
952 double ymax = 0;
953 range.GetRange(xmin,xmax,ymin,ymax);
954
955 dv.Initialize(nPoints,2, type);
956
957 for ( int i = 0; i < nPoints; ++i) {
958
959 x[0] = gx[i];
960 x[1] = gy[i];
961
962 //if (fitOpt.fUseRange && HFitInterface::IsPointOutOfRange(func, x) ) continue;
963 if (useRangeX && ( x[0] < xmin || x[0] > xmax) ) continue;
964 if (useRangeY && ( x[1] < ymin || x[1] > ymax) ) continue;
965
966 // need to evaluate function to know about rejected points
967 // hugly but no other solutions
968 if (func) {
969 TF1::RejectPoint(false);
970 (*func)( x ); // evaluate using stored function parameters
971 if (TF1::RejectedPoint() ) continue;
972 }
973
974 if (type == BinData::kNoError) {
975 dv.Add( x, gz[i] );
976 continue;
977 }
978
979 double errorZ = gr->GetErrorZ(i);
981
982 if (type == BinData::kValueError) {
983 dv.Add( x, gz[i], errorZ );
984 }
985 else if (type == BinData::kCoordError) { // case use error in coordinates (x and y)
986 ex[0] = std::max(gr->GetErrorX(i), 0.);
987 ex[1] = std::max(gr->GetErrorY(i), 0.);
988 dv.Add( x, gz[i], ex, errorZ );
989 }
990 else
991 assert(0); // should not go here
992
993#ifdef DEBUG
994 std::cout << "Point " << i << " " << gx[i] << " " << gy[i] << " " << errorZ << std::endl;
995#endif
996
997 }
998
999#ifdef DEBUG
1000 std::cout << "THFitInterface::FillData Graph2D FitData size is " << dv.Size() << std::endl;
1001#endif
1002
1003}
1004
1005
1006// confidence intervals
1008 if (h1->GetDimension() != 1) {
1009 Error("GetConfidenceIntervals","Invalid object used for storing confidence intervals");
1010 return false;
1011 }
1012 // fill fit data sets with points to estimate cl.
1013 BinData d;
1014 FillData(d,h1,nullptr);
1015 gr->Set(d.NPoints() );
1016 double * ci = gr->GetEY(); // make CL values error of the graph
1017 result.GetConfidenceIntervals(d,ci,cl);
1018 // put function value as abscissa of the graph
1019 for (unsigned int ipoint = 0; ipoint < d.NPoints(); ++ipoint) {
1020 const double * x = d.Coords(ipoint);
1021 const ROOT::Math::IParamMultiFunction * func = result.FittedFunction();
1022 gr->SetPoint(ipoint, x[0], (*func)(x) );
1023 }
1024 return true;
1025}
1026
1027} // end namespace Fit
1028
1029} // end namespace ROOT
#define d(i)
Definition RSha256.hxx:102
#define s1(x)
Definition RSha256.hxx:91
const Bool_t kIterBackward
Definition TCollection.h:43
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:208
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:252
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
float xmin
float ymin
float xmax
float ymax
Class describing the binned data sets : vectors of x coordinates, y values and optionally error on y ...
Definition BinData.h:52
class describing the range in the coordinates it supports multiple range in a coordinate.
Definition DataRange.h:35
class containing the result of the fit and all the related information (fitted parameter values,...
Definition FitResult.h:44
SparseData class representing the data of a THNSparse histogram The data needs to be converted to a B...
Definition SparseData.h:35
const_iterator begin() const
const_iterator end() const
Class to manage histogram axis.
Definition TAxis.h:32
virtual Double_t GetBinCenter(Int_t bin) const
Return center of bin.
Definition TAxis.cxx:482
Double_t GetXmax() const
Definition TAxis.h:142
virtual Double_t GetBinLowEdge(Int_t bin) const
Return low edge of bin.
Definition TAxis.cxx:522
virtual Int_t FindFixBin(Double_t x) const
Find bin number corresponding to abscissa x
Definition TAxis.cxx:422
Double_t GetXmin() const
Definition TAxis.h:141
virtual Double_t GetBinUpEdge(Int_t bin) const
Return up edge of bin.
Definition TAxis.cxx:532
1-Dim function class
Definition TF1.h:182
static void RejectPoint(Bool_t reject=kTRUE)
Static function to set the global flag to reject points the fgRejectPoint global flag is tested by al...
Definition TF1.cxx:3723
virtual Int_t GetNpar() const
Definition TF1.h:446
virtual void GetRange(Double_t *xmin, Double_t *xmax) const
Return range of a generic N-D function.
Definition TF1.cxx:2329
virtual void SetParLimits(Int_t ipar, Double_t parmin, Double_t parmax)
Set lower and upper limits for parameter ipar.
Definition TF1.cxx:3562
static Bool_t RejectedPoint()
See TF1::RejectPoint above.
Definition TF1.cxx:3732
virtual void SetParameters(const Double_t *params)
Definition TF1.h:618
virtual void SetParameter(Int_t param, Double_t value)
Definition TF1.h:608
virtual Bool_t IsInside(const Double_t *x) const
return kTRUE if the point is inside the function range
Definition TF1.h:567
virtual Int_t GetNdim() const
Definition TF1.h:450
Graphics object made of three arrays X, Y and Z with the same number of points each.
Definition TGraph2D.h:41
A TGraphErrors is a TGraph with error bars.
Double_t GetErrorY(Int_t bin) const override
It returns the error along Y at point i.
Double_t * GetEX() const override
Double_t GetErrorX(Int_t bin) const override
It returns the error along X at point i.
Double_t * GetEY() const override
Double_t GetErrorXhigh(Int_t bin) const override
It returns the error along X at point i.
Double_t GetErrorYlow(Int_t bin) const override
It returns the error along Y at point i.
Double_t GetErrorYhigh(Int_t bin) const override
It returns the error along Y at point i.
TClass * IsA() const override
Double_t GetErrorXlow(Int_t bin) const override
It returns the error along X at point i.
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
virtual void SetPoint(Int_t i, Double_t x, Double_t y)
Set x and y values for point number i.
Definition TGraph.cxx:2389
Double_t * GetY() const
Definition TGraph.h:139
virtual Double_t * GetEYlow() const
Definition TGraph.h:145
Int_t GetN() const
Definition TGraph.h:131
Double_t * GetX() const
Definition TGraph.h:138
virtual Double_t * GetEYhigh() const
Definition TGraph.h:144
virtual void Set(Int_t n)
Set number of points in the graph Existing coordinates are preserved New coordinates above fNpoints a...
Definition TGraph.cxx:2317
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:109
TAxis * GetZaxis()
Definition TH1.h:573
virtual Double_t GetBinError(Int_t bin) const
Return value of error associated to bin number bin.
Definition TH1.cxx:9293
virtual Int_t GetDimension() const
Definition TH1.h:527
TAxis * GetXaxis()
Definition TH1.h:571
virtual void GetBinXYZ(Int_t binglobal, Int_t &binx, Int_t &biny, Int_t &binz) const
Return binx, biny, binz corresponding to the global bin number globalbin see TH1::GetBin function abo...
Definition TH1.cxx:5150
virtual Int_t GetNcells() const
Definition TH1.h:544
TAxis * GetYaxis()
Definition TH1.h:572
Bool_t IsBinUnderflow(Int_t bin, Int_t axis=0) const
Return true if the bin is underflow.
Definition TH1.cxx:5392
Bool_t IsBinOverflow(Int_t bin, Int_t axis=0) const
Return true if the bin is overflow.
Definition TH1.cxx:5360
virtual Double_t GetBinLowEdge(Int_t bin) const
Return bin lower edge for 1D histogram.
Definition TH1.cxx:9382
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition TH1.cxx:5239
Multidimensional histogram base.
Definition THnBase.h:45
A doubly linked list.
Definition TList.h:38
A TMultiGraph is a collection of TGraph (or derived) objects.
Definition TMultiGraph.h:34
TList * GetListOfGraphs() const
Definition TMultiGraph.h:67
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
Mother of all ROOT objects.
Definition TObject.h:42
virtual TClass * IsA() const
Definition TObject.h:248
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
Double_t ey[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
TGraphErrors * gr
Definition legend1.C:25
Double_t ex[n]
Definition legend1.C:17
TH1F * h1
Definition legend1.C:5
TF1 * f1
Definition legend1.C:11
TFitResultPtr Fit(FitObject *h1, TF1 *f1, Foption_t &option, const ROOT::Math::MinimizerOptions &moption, const char *goption, ROOT::Fit::DataRange &range)
Definition HFitImpl.cxx:133
void ExamineRange(const TAxis *axis, std::pair< double, double > range, int &hxfirst, int &hxlast)
bool AdjustError(const DataOptions &option, double &error, double value=1)
bool IsPointOutOfRange(const TF1 *func, const double *x)
void InitPolynom(const ROOT::Fit::BinData &data, TF1 *f1)
compute initial parameter for a polynomial function given the fit data Set the parameters to an unwei...
void Init2DGaus(const ROOT::Fit::BinData &data, TF1 *f1)
compute initial parameter for 2D gaussian function given the fit data Set the sigma limits for zero t...
void FillData(BinData &dv, const TH1 *hist, TF1 *func=nullptr)
fill the data vector from a TH1.
void InitExpo(const ROOT::Fit::BinData &data, TF1 *f1)
compute initial parameter for an exponential function given the fit data Set the constant and slope a...
void InitGaus(const ROOT::Fit::BinData &data, TF1 *f1)
compute initial parameter for gaussian function given the fit data Set the sigma limits for zero top ...
void DoFillData(BinData &dv, const TGraph *gr, BinData::ErrorType type, TF1 *func)
BinData::ErrorType GetDataType(const TGraph *gr, DataOptions &fitOpt)
bool GetConfidenceIntervals(const TH1 *h1, const ROOT::Fit::FitResult &r, TGraphErrors *gr, double cl=0.95)
compute confidence intervals at level cl for a fitted histogram h1 in a TGraphErrors gr
DataOptions : simple structure holding the options on how the data are filled.
Definition DataOptions.h:28