Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RooCurve.cxx
Go to the documentation of this file.
1/*****************************************************************************
2 * Project: RooFit *
3 * Package: RooFitCore *
4 * @(#)root/roofitcore:$Id$
5 * Authors: *
6 * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7 * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8 * *
9 * Copyright (c) 2000-2005, Regents of the University of California *
10 * and Stanford University. All rights reserved. *
11 * *
12 * Redistribution and use in source and binary forms, *
13 * with or without modification, are permitted according to the terms *
14 * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15 *****************************************************************************/
16
17/**
18\file RooCurve.cxx
19\class RooCurve
20\ingroup Roofitcore
21
22One-dimensional graphical representation of a real-valued function.
23A curve is approximated by straight line segments with end points chosen to give
24a "good" approximation to the true curve. The goodness of the approximation is
25controlled by a precision and a resolution parameter.
26
27A RooCurve derives from TGraph, so it can either be drawn as a line (default) or
28as points:
29```
30RooPlot *p = y.plotOn(x.frame());
31p->getAttMarker("curve_y")->SetMarkerStyle(20);
32p->setDrawOptions("curve_y","PL");
33p->Draw();
34```
35
36To retrieve a RooCurve from a RooPlot, use RooPlot::getCurve().
37**/
38
39#include "RooCurve.h"
40#include "RooHist.h"
41#include "RooAbsReal.h"
42#include "RooArgSet.h"
43#include "RooRealVar.h"
44#include "RooRealBinding.h"
45#include "RooMsgService.h"
46#include "RooProduct.h"
47#include "RooConstVar.h"
48
49#include "TMath.h"
50#include "TAxis.h"
51#include "TMatrixD.h"
52#include "TVectorD.h"
53#include "Math/Util.h"
54
55#include <iomanip>
56#include <deque>
57#include <algorithm>
58#include <ostream>
59#include <list>
60#include <vector>
61#include <cmath>
62
63using std::ostream, std::list, std::vector, std::min;
64
65
66namespace {
67
68// Helpers to manage points
69struct Point {
70 double x;
71 double y;
72};
73
74inline Point getPoint(TGraph const &gr, int i)
75{
76 Point p;
77 gr.GetPoint(i, p.x, p.y);
78 return p;
79}
80
81} // namespace
82
83
84////////////////////////////////////////////////////////////////////////////////
85/// Default constructor.
86
91
92
93////////////////////////////////////////////////////////////////////////////////
94/// Create a 1-dim curve of the value of the specified real-valued expression
95/// as a function of x. Use the optional precision parameter to control
96/// how precisely the smooth curve is rasterized. Use the optional argument set
97/// to specify how the expression should be normalized. Use the optional scale
98/// factor to rescale the expression after normalization.
99/// If shiftToZero is set, the entire curve is shifted down to make the lowest
100/// point of the curve go through zero.
101RooCurve::RooCurve(const RooAbsReal &f, RooAbsRealLValue &x, double xlo, double xhi, Int_t xbins, double scaleFactor,
102 const RooArgSet *normVars, double prec, double resolution, bool shiftToZero, WingMode wmode,
104 : _showProgress(showProg)
105{
106 // grab the function's name and title
107 TString name(f.GetName());
108 SetName(name.Data());
109 TString title(f.GetTitle());
110 SetTitle(title.Data());
111 // append " ( [<funit> ][/ <xunit> ])" to our y-axis label if necessary
112 if(0 != strlen(f.getUnit()) || 0 != strlen(x.getUnit())) {
113 title.Append(" ( ");
114 if(0 != strlen(f.getUnit())) {
115 title.Append(f.getUnit());
116 title.Append(" ");
117 }
118 if(0 != strlen(x.getUnit())) {
119 title.Append("/ ");
120 title.Append(x.getUnit());
121 title.Append(" ");
122 }
123 title.Append(")");
124 }
125 setYAxisLabel(title.Data());
126
127 RooProduct scaledFunc{"scaled_func", "scaled_func", {f, RooFit::RooConst(scaleFactor)}};
128 std::unique_ptr<RooAbsFunc> funcPtr{scaledFunc.bindVars(x, normVars, true)};
129
130 // calculate the points to add to our curve
131 if(xbins > 0){
132 // regular mode - use the sampling hint to decide where to evaluate the pdf
133 std::unique_ptr<std::list<double>> hint{f.plotSamplingHint(x,xlo,xhi)};
135 if (_showProgress) {
136 ccoutP(Plotting) << std::endl ;
137 }
138 } else {
139 // if number of bins is set to <= 0, skip any interpolation and just evaluate the pdf at the bin centers
140 // this is useful when plotting a pdf like a histogram
141 int nBinsX = x.numBins();
142 for(int i=0; i<nBinsX; ++i){
143 double xval = x.getBinning().binCenter(i);
144 addPoint(xval,(*funcPtr)(&xval)) ;
145 }
146 }
147 initialize();
148
149 if (shiftToZero) shiftCurveToZero() ;
150
151 // Adjust limits
152 for (int i=0 ; i<GetN() ; i++) {
154 }
155 this->Sort();
156}
157
158
159
160////////////////////////////////////////////////////////////////////////////////
161/// Create a 1-dim curve of the value of the specified real-valued
162/// expression as a function of x. Use the optional precision
163/// parameter to control how precisely the smooth curve is
164/// rasterized. If shiftToZero is set, the entire curve is shifted
165/// down to make the lowest point in of the curve go through zero.
166
167RooCurve::RooCurve(const char *name, const char *title, const RooAbsFunc &func,
168 double xlo, double xhi, UInt_t minPoints, double prec, double resolution,
169 bool shiftToZero, WingMode wmode, Int_t nEvalError, Int_t doEEVal, double eeVal)
170{
171 SetName(name);
172 SetTitle(title);
174 initialize();
175 if (shiftToZero) shiftCurveToZero() ;
176
177 // Adjust limits
178 for (int i=0 ; i<GetN() ; i++) {
180 }
181 this->Sort();
182}
183
184
185
186////////////////////////////////////////////////////////////////////////////////
187/// Constructor of a curve as sum of two other curves.
188/// \f[
189/// C_\mathrm{sum} = \mathrm{scale1}*c1 + \mathrm{scale2}*c2
190/// \f]
191///
192/// \param[in] name Name of the curve (to retrieve it from a plot)
193/// \param[in] title Title (for plotting).
194/// \param[in] c1 First curve.
195/// \param[in] c2 Second curve.
196/// \param[in] scale1 Scale y values for c1 by this factor.
197/// \param[in] scale2 Scale y values for c2 by this factor.
198
199RooCurve::RooCurve(const char* name, const char* title, const RooCurve& c1, const RooCurve& c2, double scale1, double scale2)
200{
201 initialize() ;
202 SetName(name) ;
203 SetTitle(title) ;
204
205 // Make deque of points in X
206 std::deque<double> pointList ;
207
208 // Add X points of C1
209 Int_t n1 = c1.GetN();
210 for (int i1=0 ; i1<n1 ; i1++) {
211 pointList.push_back(c1.GetPointX(i1));
212 }
213
214 // Add X points of C2
215 Int_t n2 = c2.GetN();
216 for (int i2=0 ; i2<n2 ; i2++) {
217 pointList.push_back(c2.GetPointX(i2));
218 }
219
220 // Sort X points
221 std::sort(pointList.begin(),pointList.end()) ;
222
223 // Loop over X points
224 double last(-RooNumber::infinity()) ;
225 for (auto point : pointList) {
226
227 if ((point-last)>1e-10) {
228 // Add OR of points to new curve, skipping duplicate points within tolerance
229 addPoint(point,scale1*c1.interpolate(point)+scale2*c2.interpolate(point)) ;
230 }
231 last = point ;
232 }
233
234 this->Sort();
235}
236
237
238RooCurve::~RooCurve() = default;
239
240
241////////////////////////////////////////////////////////////////////////////////
242/// Perform initialization that is common to all curves
243
245{
246 // set default line width in pixels
247 SetLineWidth(3);
248 // set default line color
250}
251
252
253
254////////////////////////////////////////////////////////////////////////////////
255/// Find lowest point in curve and move all points in curve so that
256/// lowest point will go exactly through zero
257
259{
260 double minVal = std::numeric_limits<double>::infinity();
261 double maxVal = -std::numeric_limits<double>::infinity();
262
263 // First iteration, find current lowest point
264 for (int i = 1; i < GetN() - 1; i++) {
265 double y = GetPointY(i);
266 minVal = std::min(y, minVal);
267 maxVal = std::max(y, maxVal);
268 }
269
270 // Second iteration, lower all points by minVal
271 for (int i = 1; i < GetN() - 1; i++) {
272 Point point = getPoint(*this, i);
273 SetPoint(i, point.x, point.y - minVal);
274 }
275
276 setYAxisLimits(0, maxVal - minVal);
277}
278
279
280
281////////////////////////////////////////////////////////////////////////////////
282/// Add points calculated with the specified function, over the range (xlo,xhi).
283/// Add at least minPoints equally spaced points, and add sufficient points so that
284/// the maximum deviation from the final straight-line segments is prec*(ymax-ymin),
285/// down to a minimum horizontal spacing of resolution*(xhi-xlo).
286
287void RooCurve::addPoints(const RooAbsFunc &func, double xlo, double xhi,
288 Int_t minPoints, double prec, double resolution, WingMode wmode,
289 Int_t numee, bool doEEVal, double eeVal, list<double>* samplingHint)
290{
291 // check the inputs
292 if(!func.isValid()) {
293 coutE(InputArguments) << fName << "::addPoints: input function is not valid" << std::endl;
294 return;
295 }
296 if(minPoints <= 0 || xhi <= xlo) {
297 coutE(InputArguments) << fName << "::addPoints: bad input (nothing added)" << std::endl;
298 return;
299 }
300
301 // Perform a coarse scan of the function to estimate its y range.
302 // Save the results so we do not have to re-evaluate at the scan points.
303
304 // Adjust minimum number of points to external sampling hint if used
305 if (samplingHint) {
306 minPoints = samplingHint->size() ;
307 }
308
309 double dx= (xhi-xlo)/(minPoints-1.);
310 const double epsilon = (xhi - xlo) * relativeXEpsilon();
311 std::vector<double> yval(minPoints);
312
313 // Get list of initial x values. If function provides sampling hint use that,
314 // otherwise use default binning of frame
315 std::vector<double> xval;
316 if (!samplingHint) {
317 for(int step= 0; step < minPoints; step++) {
318 xval.push_back(xlo + step*dx) ;
319 }
320 } else {
321 std::copy(samplingHint->begin(), samplingHint->end(), std::back_inserter(xval));
322 }
323
324 for (unsigned int step=0; step < xval.size(); ++step) {
325 double xx = xval[step];
326 if (step == static_cast<unsigned int>(minPoints-1))
327 xx -= 1e-9 * dx;
328
329 yval[step]= func(&xx);
330 if (_showProgress) {
331 ccoutP(Plotting) << "." ;
332 std::cout.flush() ;
333 }
334
336 if (numee>=0) {
337 coutW(Plotting) << "At observable [x]=" << xx << " " ;
338 RooAbsReal::printEvalErrors(ccoutW(Plotting),numee) ;
339 }
340 if (doEEVal) {
341 yval[step]=eeVal ;
342 }
343 }
345 }
346
347 const double ymax = *std::max_element(yval.begin(), yval.end());
348 const double ymin = *std::min_element(yval.begin(), yval.end());
349 double yrangeEst=(ymax-ymin) ;
350
351 // store points of the coarse scan and calculate any refinements necessary
352 double minDx= resolution*(xhi-xlo);
353 double x1;
354 double x2 = xlo;
355
356 if (wmode==Extended) {
357 // Add two points to make curve jump from 0 to yval at the left end of the plotting range.
358 // This ensures that filled polygons are drawn properly. The first point needs to be to the
359 // left of the second, so it's shifted by 1/1000 more than the second.
360 addPoint(xlo-dx*1.001, 0);
361 addPoint(xlo-dx,yval[0]) ;
362 } else if (wmode==Straight) {
363 addPoint(xlo-dx*0.001,0) ;
364 }
365
366 addPoint(xlo,yval[0]);
367
368 auto iter2 = xval.begin() ;
369 x1 = *iter2 ;
370 int step=1 ;
371 while(true) {
372 x1= x2;
373 ++iter2 ;
374 if (iter2==xval.end()) {
375 break ;
376 }
377 x2= *iter2 ;
378 if (prec<0) {
379 // If precision is <0, no attempt at recursive interpolation is made
380 addPoint(x2,yval[step]) ;
381 } else {
382 addRange(func,x1,x2,yval[step-1],yval[step],prec*yrangeEst,minDx,numee,doEEVal,eeVal,epsilon);
383 }
384 step++ ;
385 }
386 addPoint(xhi,yval[minPoints-1]) ;
387
388 if (wmode==Extended) {
389 // Add two points to close polygon. The order matters. Since they are sorted in x later, the second
390 // point is shifted by 1/1000 more than the second-to-last point.
391 addPoint(xhi+dx,yval[minPoints-1]) ;
392 addPoint(xhi+dx*1.001, 0);
393 } else if (wmode==Straight) {
394 addPoint(xhi+dx*0.001,0) ;
395 }
396}
397
398
399////////////////////////////////////////////////////////////////////////////////
400/// Fill the range (x1,x2) with points calculated using func(&x). No point will
401/// be added at x1, and a point will always be added at x2. The density of points
402/// will be calculated so that the maximum deviation from a straight line
403/// approximation is prec*(ymax-ymin) down to the specified minimum horizontal spacing.
404
405void RooCurve::addRange(const RooAbsFunc& func, double x1, double x2,
406 double y1, double y2, double minDy, double minDx,
407 int numee, bool doEEVal, double eeVal, double epsilon)
408{
409 // Explicitly skip empty ranges to eliminate point duplication
410 if (std::abs(x2-x1) <= epsilon) {
411 return ;
412 }
413
414 // calculate our value at the midpoint of this range
415 double xmid= 0.5*(x1+x2);
416 double ymid= func(&xmid);
417 if (_showProgress) {
418 ccoutP(Plotting) << "." ;
419 std::cout.flush() ;
420 }
421
423 if (numee>=0) {
424 coutW(Plotting) << "At observable [x]=" << xmid << " " ;
425 RooAbsReal::printEvalErrors(ccoutW(Plotting),numee) ;
426 }
427 if (doEEVal) {
428 ymid=eeVal ;
429 }
430 }
432
433 // test if the midpoint is sufficiently close to a straight line across this interval
434 double dy= ymid - 0.5*(y1+y2);
435 if((xmid - x1 >= minDx) && std::abs(dy)>0 && std::abs(dy) >= minDy) {
436 // fill in each subrange
437 addRange(func,x1,xmid,y1,ymid,minDy,minDx,numee,doEEVal,eeVal,epsilon);
438 addRange(func,xmid,x2,ymid,y2,minDy,minDx,numee,doEEVal,eeVal,epsilon);
439 }
440 else {
441 // add the endpoint
442 addPoint(x2,y2);
443 }
444}
445
446
447////////////////////////////////////////////////////////////////////////////////
448/// Add a point with the specified coordinates. Update our y-axis limits.
449
450void RooCurve::addPoint(double x, double y)
451{
452// std::cout << "RooCurve("<< GetName() << ") adding point at (" << x << "," << y << ")" << std::endl ;
453 Int_t next= GetN();
454 SetPoint(next, x, y);
456}
457
458
459////////////////////////////////////////////////////////////////////////////////
460/// Return the number of events associated with the plotable object,
461/// it is always 1 for curves
462
464 return 1;
465}
466
467
468////////////////////////////////////////////////////////////////////////////////
469/// Return the number of events associated with the plotable object,
470/// in the given range. It is always 1 for curves
471
472double RooCurve::getFitRangeNEvt(double, double) const
473{
474 return 1 ;
475}
476
477
478////////////////////////////////////////////////////////////////////////////////
479/// Get the bin width associated with this plotable object.
480/// It is alwats zero for curves
481
483 return 0 ;
484}
485
486
487
488////////////////////////////////////////////////////////////////////////////////
489
490void RooCurve::printName(ostream& os) const
491//
492{
493 // Print the name of this curve
494 os << GetName() ;
495}
496
497
498////////////////////////////////////////////////////////////////////////////////
499/// Print the title of this curve
500
501void RooCurve::printTitle(ostream& os) const
502{
503 os << GetTitle() ;
504}
505
506
507////////////////////////////////////////////////////////////////////////////////
508/// Print the class name of this curve
509
510void RooCurve::printClassName(ostream& os) const
511{
512 os << ClassName() ;
513}
514
515
516
517////////////////////////////////////////////////////////////////////////////////
518/// Print the details of this curve
519
520void RooCurve::printMultiline(ostream& os, Int_t /*contents*/, bool /*verbose*/, TString indent) const
521{
522 os << indent << "--- RooCurve ---" << std::endl ;
523 Int_t n= GetN();
524 os << indent << " Contains " << n << " points" << std::endl;
525 os << indent << " Graph points:" << std::endl;
526 for(Int_t i= 0; i < n; i++) {
527 os << indent << std::setw(3) << i << ") x = " << fX[i] << " , y = " << fY[i] << std::endl;
528 }
529}
530
531
532
533////////////////////////////////////////////////////////////////////////////////
534/// Calculate the chi^2/NDOF of this curve with respect to the histogram
535/// 'hist' accounting nFitParam floating parameters in case the curve
536/// was the result of a fit
537
538double RooCurve::chiSquare(const RooHist& hist, Int_t nFitParam) const
539{
540 Int_t np = hist.GetN();
541
542 // Find starting and ending bin of histogram based on range of RooCurve
543 double xstart = GetPointX(0);
544 double xstop = GetPointX(GetN()-1);
545
546 Int_t nbin(0) ;
547
549 for (int i=0 ; i<np ; i++) {
550
551 // Retrieve histogram contents
552 Point point = getPoint(hist, i);
553
554 // Check if point is in range of curve
555 if (point.x<xstart || point.x>xstop) continue ;
556
557 double eyl = hist.GetEYlow()[i] ;
558 double eyh = hist.GetEYhigh()[i] ;
559 double exl = hist.GetEXlow()[i] ;
560 double exh = hist.GetEXhigh()[i] ;
561
562 // Integrate function over this bin
563 double avg = average(point.x-exl,point.x+exh) ;
564
565 // Add pull^2 to chisq
566 if (point.y!=0) {
567 double pull = (point.y>avg) ? ((point.y-avg)/eyl) : ((point.y-avg)/eyh) ;
568 chisq += pull*pull ;
569 nbin++ ;
570 }
571 }
572
573 // Return chisq/nDOF
574 return chisq.Sum() / (nbin-nFitParam) ;
575}
576
577
578
579////////////////////////////////////////////////////////////////////////////////
580/// Return average curve value in [xFirst,xLast] by integrating curve between points
581/// and dividing by xLast-xFirst
582/// If xFirst > xLast, it prints an error and returns 0.
583/// If xFirst == xLast, it returns the y interpolated value at xFirst.
584
585double RooCurve::average(double xFirst, double xLast) const
586{
587 if (xFirst>xLast) {
588 coutE(InputArguments) << "RooCurve::average(" << GetName()
589 << ") invalid range (" << xFirst << "," << xLast << ")" << std::endl ;
590 return 0 ;
591 }
592 else if (xFirst == xLast) {
593 return interpolate(xFirst,1e-10);
594 }
595
596 // Find Y values and begin and end points
597 double yFirst = interpolate(xFirst,1e-10) ;
598 double yLast = interpolate(xLast,1e-10) ;
599
600 // Find first and last mid points
601 Int_t ifirst = findPoint(xFirst, std::numeric_limits<double>::infinity());
602 Int_t ilast = findPoint(xLast, std::numeric_limits<double>::infinity());
603
604 // Make sure the midpoints are actually in the interval
605 while (GetPointX(ifirst) < xFirst) {
606 ++ifirst;
607 }
608 while (GetPointX(ilast) > xLast) {
609 --ilast;
610 }
611
612 // Handle trivial scenario -- no midway points, point only at or outside given range
613 if (ilast < ifirst) {
614 return 0.5*(yFirst+yLast) ;
615 }
616
617 Point firstPt = getPoint(*this, ifirst);
618 Point lastPt = getPoint(*this, ilast);
619
620 // Trapezoid integration from lower edge to first midpoint
621 double sum = 0.5 * (firstPt.x-xFirst)*(yFirst+firstPt.y);
622
623 // Trapezoid integration between midpoints
624 for (int i=ifirst ; i<ilast ; i++) {
625 Point p1 = getPoint(*this, i) ;
626 Point p2 = getPoint(*this, i+1) ;
627 sum += 0.5 * (p2.x-p1.x)*(p1.y+p2.y);
628 }
629
630 // Trapezoid integration from last midpoint to upper edge
631 sum += 0.5 * (xLast-lastPt.x)*(lastPt.y+yLast);
632 return sum/(xLast-xFirst) ;
633}
634
635
636
637////////////////////////////////////////////////////////////////////////////////
638/// Find the nearest point to xvalue. Return -1 if distance
639/// exceeds tolerance
640
642{
643 double delta(std::numeric_limits<double>::max());
644 Int_t n = GetN();
645 Int_t ibest(-1) ;
646 for (int i=0 ; i<n ; i++) {
647 double x = GetPointX(i);
648 if (std::abs(xvalue-x)<delta) {
649 delta = std::abs(xvalue-x) ;
650 ibest = i ;
651 }
652 }
653
654 return (delta<tolerance)?ibest:-1 ;
655}
656
657
658////////////////////////////////////////////////////////////////////////////////
659/// Return linearly interpolated value of curve at xvalue. If distance
660/// to nearest point is less than tolerance, return nearest point value
661/// instead
662
663double RooCurve::interpolate(double xvalue, double tolerance) const
664{
665 // Find best point
666 int n = GetN() ;
667 int ibest = findPoint(xvalue,1e10) ;
668
669 // Get position of best point
670 Point pbest = getPoint(*this, ibest);
671
672 // Handle trivial case of being dead on
673 if (std::abs(pbest.x-xvalue)<tolerance) {
674 return pbest.y;
675 }
676
677 // Get nearest point on other side w.r.t. xvalue
678 double retVal(0);
679 if (pbest.x<xvalue) {
680 if (ibest==n-1) {
681 // Value beyond end requested -- return value of last point
682 return pbest.y ;
683 }
684 Point pother = getPoint(*this, ibest+1);
685 if (pother.x==pbest.x) return pbest.y ;
686 retVal = pbest.y + (pother.y-pbest.y)*(xvalue-pbest.x)/(pother.x-pbest.x) ;
687
688 } else {
689 if (ibest==0) {
690 // Value before 1st point requested -- return value of 1st point
691 return pbest.y ;
692 }
693 Point pother = getPoint(*this, ibest-1);
694 if (pother.x==pbest.x) return pbest.y ;
695 retVal = pother.y + (pbest.y-pother.y)*(xvalue-pother.x)/(pbest.x-pother.x) ;
696 }
697
698 return retVal ;
699}
700
701
702
703
704////////////////////////////////////////////////////////////////////////////////
705/// Construct filled RooCurve represented error band that captures alpha% of the variations
706/// of the curves passed through argument variations, where the percentage alpha corresponds to
707/// the central interval fraction of a significance Z
708
709RooCurve* RooCurve::makeErrorBand(const vector<RooCurve*>& variations, double Z) const
710{
711 RooCurve* band = new RooCurve ;
712 band->SetName((std::string(GetName()) + "_errorband").c_str());
713 band->SetLineWidth(1) ;
714 band->SetFillColor(kCyan) ;
715 band->SetLineColor(kCyan) ;
716
719 for (int i=0 ; i<GetN() ; i++) {
720 calcBandInterval(variations,i,Z,bandLo[i],bandHi[i],false) ;
721 }
722
723 for (int i=0 ; i<GetN() ; i++) {
724 band->addPoint(GetX()[i],bandLo[i]) ;
725 }
726 for (int i=GetN()-1 ; i>=0 ; i--) {
727 band->addPoint(GetX()[i],bandHi[i]) ;
728 }
729 // if the axis of the old graph is alphanumeric, copy the labels to the new one as well
730 if(this->GetXaxis() && this->GetXaxis()->IsAlphanumeric()){
731 band->GetXaxis()->Set(this->GetXaxis()->GetNbins(),this->GetXaxis()->GetXmin(),this->GetXaxis()->GetXmax());
732 for(int i=0; i<this->GetXaxis()->GetNbins(); ++i){
733 band->GetXaxis()->SetBinLabel(i+1,this->GetXaxis()->GetBinLabel(i+1));
734 }
735 }
736
737 return band ;
738}
739
740
741
742
743////////////////////////////////////////////////////////////////////////////////
744/// Construct filled RooCurve represented error band represent the error added in quadrature defined by the curves arguments
745/// plusVar and minusVar corresponding to one-sigma variations of each parameter. The resulting error band, combined used the correlation matrix C
746/// is multiplied with the significance parameter Z to construct the equivalent of a Z sigma error band (in Gaussian approximation)
747
749{
750
751 RooCurve* band = new RooCurve ;
752 band->SetName((std::string(GetName()) + "_errorband").c_str());
753 band->SetLineWidth(1) ;
754 band->SetFillColor(kCyan) ;
755 band->SetLineColor(kCyan) ;
756
759 for (int i=0 ; i<GetN() ; i++) {
761 }
762
763 for (int i=0 ; i<GetN() ; i++) {
764 band->addPoint(GetX()[i],bandLo[i]) ;
765 }
766 for (int i=GetN()-1 ; i>=0 ; i--) {
767 band->addPoint(GetX()[i],bandHi[i]) ;
768 }
769
770 // if the axis of the old graph is alphanumeric, copy the labels to the new one as well
771 if(this->GetXaxis() && this->GetXaxis()->IsAlphanumeric()){
772 band->GetXaxis()->Set(this->GetXaxis()->GetNbins(),this->GetXaxis()->GetXmin(),this->GetXaxis()->GetXmax());
773 for(int i=0; i<this->GetXaxis()->GetNbins(); ++i){
774 band->GetXaxis()->SetBinLabel(i+1,this->GetXaxis()->GetBinLabel(i+1));
775 }
776 }
777
778 return band ;
779}
780
781
782
783
784
785////////////////////////////////////////////////////////////////////////////////
786/// Retrieve variation points from curves
787
788void RooCurve::calcBandInterval(const vector<RooCurve*>& plusVar, const vector<RooCurve*>& minusVar,Int_t i, const TMatrixD& C, double /*Z*/, double& lo, double& hi) const
789{
792 Int_t j(0) ;
793 for (vector<RooCurve*>::const_iterator iter=plusVar.begin() ; iter!=plusVar.end() ; ++iter) {
794 y_plus[j++] = (*iter)->interpolate(GetX()[i]) ;
795 }
796 j=0 ;
797 for (vector<RooCurve*>::const_iterator iter=minusVar.begin() ; iter!=minusVar.end() ; ++iter) {
798 y_minus[j++] = (*iter)->interpolate(GetX()[i]) ;
799 }
800 double y_cen = GetY()[i] ;
801 Int_t n = j ;
802
803 // Make vector of variations
804 TVectorD F(plusVar.size()) ;
805 for (j=0 ; j<n ; j++) {
806 F[j] = (y_plus[j]-y_minus[j])/2 ;
807 }
808
809 // Calculate error in linear approximation from variations and correlation coefficient
810 double sum = F*(C*F) ;
811
812 lo= y_cen + sqrt(sum) ;
813 hi= y_cen - sqrt(sum) ;
814}
815
816
817
818////////////////////////////////////////////////////////////////////////////////
819
820void RooCurve::calcBandInterval(const vector<RooCurve*>& variations,Int_t i,double Z, double& lo, double& hi, bool approxGauss) const
821{
822 vector<double> y(variations.size()) ;
823 Int_t j(0) ;
824 for (vector<RooCurve*>::const_iterator iter=variations.begin() ; iter!=variations.end() ; ++iter) {
825 y[j++] = (*iter)->interpolate(GetX()[i]) ;
826}
827
828 if (!approxGauss) {
829 // Construct central 68% interval from variations collected at each point
830 double pvalue = TMath::Erfc(Z/sqrt(2.)) ;
831 Int_t delta = Int_t( y.size()*(pvalue)/2 + 0.5) ;
832 sort(y.begin(),y.end()) ;
833 lo = y[delta] ;
834 hi = y[y.size()-delta] ;
835 } else {
836 // Estimate R.M.S of variations at each point and use that as Gaussian sigma
837 double sum_y(0);
838 double sum_ysq(0);
839 for (unsigned int k=0 ; k<y.size() ; k++) {
840 sum_y += y[k] ;
841 sum_ysq += y[k]*y[k] ;
842 }
843 sum_y /= y.size() ;
844 sum_ysq /= y.size() ;
845
846 double rms = sqrt(sum_ysq - (sum_y*sum_y)) ;
847 lo = GetY()[i] - Z*rms ;
848 hi = GetY()[i] + Z*rms ;
849 }
850}
851
852
853
854
855////////////////////////////////////////////////////////////////////////////////
856/// Return true if curve is identical to other curve allowing for given
857/// absolute tolerance on each point compared point.
858
859bool RooCurve::isIdentical(const RooCurve& other, double tol, bool verbose) const
860{
861 // Determine X range and Y range
862 Int_t n= min(GetN(),other.GetN());
863 double xmin(1e30);
864 double xmax(-1e30);
865 double ymin(1e30);
866 double ymax(-1e30);
867 for(Int_t i= 0; i < n; i++) {
868 if (fX[i]<xmin) xmin=fX[i] ;
869 if (fX[i]>xmax) xmax=fX[i] ;
870 if (fY[i]<ymin) ymin=fY[i] ;
871 if (fY[i]>ymax) ymax=fY[i] ;
872 }
873 const double Yrange=ymax-ymin ;
874
875 bool ret(true) ;
876 for(Int_t i= 2; i < n-2; i++) {
877 double yTest = interpolate(other.fX[i],1e-10) ;
878 double rdy = std::abs(yTest-other.fY[i])/Yrange ;
879 if (rdy>tol) {
880 ret = false;
881 if(!verbose) continue;
882 std::cout << "RooCurve::isIdentical[" << std::setw(3) << i << "] Y tolerance exceeded (" << std::setprecision(5) << std::setw(10) << rdy << ">" << tol << "),";
883 std::cout << " x,y=(" << std::right << std::setw(10) << fX[i] << "," << std::setw(10) << fY[i] << ")\tref: y="
884 << std::setw(10) << other.interpolate(fX[i], 1.E-15) << ". [Nearest point from ref: ";
885 auto j = other.findPoint(fX[i], 1.E10);
886 std::cout << "j=" << j << "\tx,y=(" << std::setw(10) << other.fX[j] << "," << std::setw(10) << other.fY[j] << ") ]" << "\trange=" << Yrange << std::endl;
887 }
888 }
889
890 return ret ;
891}
892
893
894
895////////////////////////////////////////////////////////////////////////////////
896/// Returns sampling hints for a histogram with given boundaries. This helper
897/// function is meant to be used by binned RooAbsReals to produce sampling
898/// hints that are working well with RooFits plotting.
899
900std::list<double> *
901RooCurve::plotSamplingHintForBinBoundaries(std::span<const double> boundaries, double xlo, double xhi)
902{
903 auto hint = new std::list<double>;
904
905 // Make sure the difference between two points around a bin boundary is
906 // larger than the relative epsilon for which the RooCurve considers two
907 // points as the same. Otherwise, the points right of the bin boundary would
908 // be skipped.
909 const double delta = (xhi - xlo) * RooCurve::relativeXEpsilon();
910
911 // Sample points right next to the plot limits
912 hint->push_back(xlo + delta);
913 hint->push_back(xhi - delta);
914
915 // Sample points very close to the left and right of the bin boundaries that
916 // are strictly in between the plot limits.
917 for (const double x : boundaries) {
918 if (x - xlo > delta && xhi - x > delta) {
919 hint->push_back(x - delta);
920 hint->push_back(x + delta);
921 }
922 }
923
924 hint->sort();
925
926 return hint;
927}
#define f(i)
Definition RSha256.hxx:104
#define e(i)
Definition RSha256.hxx:103
#define coutW(a)
#define ccoutP(a)
#define coutE(a)
#define ccoutW(a)
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
@ kCyan
Definition Rtypes.h:66
@ kBlue
Definition Rtypes.h:66
static void indent(ostringstream &buf, int indent_level)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t SetLineWidth
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 np
Option_t Option_t SetLineColor
Option_t Option_t TPoint TPoint const char x2
Option_t Option_t TPoint TPoint const char x1
Option_t Option_t TPoint TPoint const char y2
Option_t Option_t TPoint TPoint const char y1
char name[80]
Definition TGX11.cxx:142
float xmin
#define hi
float ymin
float xmax
float ymax
The Kahan summation is a compensated summation algorithm, which significantly reduces numerical error...
Definition Util.h:141
const_iterator begin() const
const_iterator end() const
Abstract interface for evaluating a real-valued function of one real variable and performing numerica...
Definition RooAbsFunc.h:27
bool isValid() const
Definition RooAbsFunc.h:37
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
static Int_t numEvalErrors()
Return the number of logged evaluation errors since the last clearing.
static void printEvalErrors(std::ostream &os=std::cout, Int_t maxPerNode=10000000)
Print all outstanding logged evaluation error on the given ostream.
static void clearEvalErrorLog()
Clear the stack of evaluation error messages.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
One-dimensional graphical representation of a real-valued function.
Definition RooCurve.h:36
void addPoints(const RooAbsFunc &func, double xlo, double xhi, Int_t minPoints, double prec, double resolution, WingMode wmode, Int_t numee=0, bool doEEVal=false, double eeVal=0.0, std::list< double > *samplingHint=nullptr)
Add points calculated with the specified function, over the range (xlo,xhi).
Definition RooCurve.cxx:287
void printTitle(std::ostream &os) const override
Print the title of this curve.
Definition RooCurve.cxx:501
void initialize()
Perform initialization that is common to all curves.
Definition RooCurve.cxx:244
~RooCurve() override
double getFitRangeBinW() const override
Get the bin width associated with this plotable object.
Definition RooCurve.cxx:482
static constexpr double relativeXEpsilon()
The distance between two points x1 and x2 relative to the full plot range below which two points are ...
Definition RooCurve.h:104
void addRange(const RooAbsFunc &func, double x1, double x2, double y1, double y2, double minDy, double minDx, int numee, bool doEEVal, double eeVal, double epsilon)
Fill the range (x1,x2) with points calculated using func(&x).
Definition RooCurve.cxx:405
void printName(std::ostream &os) const override
Print name of object.
Definition RooCurve.cxx:490
void printMultiline(std::ostream &os, Int_t contents, bool verbose=false, TString indent="") const override
Print the details of this curve.
Definition RooCurve.cxx:520
double interpolate(double x, double tolerance=1e-10) const
Return linearly interpolated value of curve at xvalue.
Definition RooCurve.cxx:663
static std::list< double > * plotSamplingHintForBinBoundaries(std::span< const double > boundaries, double xlo, double xhi)
Returns sampling hints for a histogram with given boundaries.
Definition RooCurve.cxx:901
void printClassName(std::ostream &os) const override
Print the class name of this curve.
Definition RooCurve.cxx:510
@ Straight
Definition RooCurve.h:39
RooCurve()
Default constructor.
Definition RooCurve.cxx:87
bool _showProgress
! Show progress indication when adding points
Definition RooCurve.h:97
RooCurve * makeErrorBand(const std::vector< RooCurve * > &variations, double Z=1) const
Construct filled RooCurve represented error band that captures alpha% of the variations of the curves...
Definition RooCurve.cxx:709
double chiSquare(const RooHist &hist, int nFitParam) const
Calculate the chi^2/NDOF of this curve with respect to the histogram 'hist' accounting nFitParam floa...
Definition RooCurve.cxx:538
void calcBandInterval(const std::vector< RooCurve * > &variations, Int_t i, double Z, double &lo, double &hi, bool approxGauss) const
Definition RooCurve.cxx:820
double getFitRangeNEvt() const override
Return the number of events associated with the plotable object, it is always 1 for curves.
Definition RooCurve.cxx:463
void shiftCurveToZero()
Find lowest point in curve and move all points in curve so that lowest point will go exactly through ...
Definition RooCurve.cxx:258
void addPoint(double x, double y)
Add a point with the specified coordinates. Update our y-axis limits.
Definition RooCurve.cxx:450
bool isIdentical(const RooCurve &other, double tol=1e-6, bool verbose=true) const
Return true if curve is identical to other curve allowing for given absolute tolerance on each point ...
Definition RooCurve.cxx:859
Int_t findPoint(double value, double tolerance=1e-10) const
Find the nearest point to xvalue.
Definition RooCurve.cxx:641
double average(double lo, double hi) const
Return average curve value in [xFirst,xLast] by integrating curve between points and dividing by xLas...
Definition RooCurve.cxx:585
Graphical representation of binned data based on the TGraphAsymmErrors class.
Definition RooHist.h:29
static constexpr double infinity()
Return internal infinity representation.
Definition RooNumber.h:25
void updateYAxisLimits(double y)
Definition RooPlotable.h:30
void setYAxisLimits(double ymin, double ymax)
Definition RooPlotable.h:34
void setYAxisLabel(const char *label)
Definition RooPlotable.h:29
Represents the product of a given set of RooAbsReal objects.
Definition RooProduct.h:29
Bool_t IsAlphanumeric() const
Definition TAxis.h:90
Double_t GetXmax() const
Definition TAxis.h:142
const char * GetBinLabel(Int_t bin) const
Return label for bin.
Definition TAxis.cxx:444
virtual void Set(Int_t nbins, Double_t xmin, Double_t xmax)
Initialize axis with fix bins.
Definition TAxis.cxx:790
Double_t GetXmin() const
Definition TAxis.h:141
Int_t GetNbins() const
Definition TAxis.h:127
Double_t * GetEXlow() const override
Double_t * GetEYhigh() const override
Double_t * GetEXhigh() const override
Double_t * GetEYlow() const override
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
virtual Double_t GetPointX(Int_t i) const
Get x value for point i.
Definition TGraph.cxx:1573
virtual void SetPoint(Int_t i, Double_t x, Double_t y)
Set x and y values for point number i.
Definition TGraph.cxx:2386
Double_t * GetY() const
Definition TGraph.h:139
Int_t GetN() const
Definition TGraph.h:131
Double_t * fY
[fNpoints] array of Y points
Definition TGraph.h:48
virtual void Sort(Bool_t(*greater)(const TGraph *, Int_t, Int_t)=&TGraph::CompareX, Bool_t ascending=kTRUE, Int_t low=0, Int_t high=-1111)
Sorts the points of this TGraph using in-place quicksort (see e.g.
Definition TGraph.cxx:2530
Double_t * GetX() const
Definition TGraph.h:138
void SetName(const char *name="") override
Set graph name.
Definition TGraph.cxx:2425
TAxis * GetXaxis() const
Get x axis of the graph.
Definition TGraph.cxx:1595
Double_t * fX
[fNpoints] array of X points
Definition TGraph.h:47
virtual Double_t GetPointY(Int_t i) const
Get y value for point i.
Definition TGraph.cxx:1584
void SetTitle(const char *title="") override
Change (i.e.
Definition TGraph.cxx:2441
virtual Int_t GetPoint(Int_t i, Double_t &x, Double_t &y) const
Get x and y values for point number i.
Definition TGraph.cxx:1562
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
TString fName
Definition TNamed.h:32
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:226
Basic string class.
Definition TString.h:137
const char * Data() const
Definition TString.h:385
TString & Append(const char *cs)
Definition TString.h:582
RooConstVar & RooConst(double val)
Double_t y[n]
Definition legend1.C:17
return c1
Definition legend1.C:41
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
TGraphErrors * gr
Definition legend1.C:25
return c2
Definition legend2.C:14
Double_t Erfc(Double_t x)
Computes the complementary error function erfc(x).
Definition TMath.cxx:199
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2335