Logo ROOT  
Reference Guide
RooAbsRealLValue.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 RooAbsRealLValue.cxx
19\class RooAbsRealLValue
20\ingroup Roofitcore
21
22RooAbsRealLValue is the common abstract base class for objects that represent a
23real value that may appear on the left hand side of an equation ('lvalue').
24Each implementation must provide a setVal() member to allow direct modification
25of the value. RooAbsRealLValue may be derived, but its functional relation
26to other RooAbsArg must be invertible
27
28This class has methods that export the defined range of the lvalue,
29but doesn't hold its values because these limits may be derived
30from limits of client object. The range serve as integration
31range when interpreted as a observable and a boundaries when
32interpreted as a parameter.
33**/
34
35#include "RooAbsRealLValue.h"
36
37#include "RooFit.h"
38#include "RooStreamParser.h"
39#include "RooRandom.h"
40#include "RooPlot.h"
41#include "RooArgList.h"
42#include "RooAbsBinning.h"
43#include "RooBinning.h"
44#include "RooUniformBinning.h"
45#include "RooCmdConfig.h"
46#include "RooAbsData.h"
47#include "RooRealVar.h"
50#include "ROOT/StringUtils.hxx"
51
52#include "TH1.h"
53#include "TH2.h"
54#include "TH3.h"
55
56#include <cmath>
57
58using namespace std;
59
61
62////////////////////////////////////////////////////////////////////////////////
63/// Constructor
64
65RooAbsRealLValue::RooAbsRealLValue(const char *name, const char *title, const char *unit) :
66 RooAbsReal(name, title, 0, 0, unit)
67{
68}
69
70
71
72////////////////////////////////////////////////////////////////////////////////
73/// Copy constructor
74
76 RooAbsReal(other,name), RooAbsLValue(other)
77{
78}
79
80
81////////////////////////////////////////////////////////////////////////////////
82/// Destructor
83
85{
86}
87
88
89
90////////////////////////////////////////////////////////////////////////////////
91/// Return kTRUE if the input value is within our fit range. Otherwise, return
92/// kFALSE and write a clipped value into clippedValPtr if it is non-zero.
93
94Bool_t RooAbsRealLValue::inRange(Double_t value, const char* rangeName, Double_t* clippedValPtr) const
95{
96 // Double_t range = getMax() - getMin() ; // ok for +/-INIFINITY
97 Double_t clippedValue(value);
98 Bool_t isInRange(kTRUE) ;
99
100 const RooAbsBinning& binning = getBinning(rangeName) ;
101 Double_t min = binning.lowBound() ;
102 Double_t max = binning.highBound() ;
103
104 // test this value against our upper fit limit
105 if(!RooNumber::isInfinite(max) && value > (max+1e-6)) {
106 clippedValue = max;
107 isInRange = kFALSE ;
108 }
109 // test this value against our lower fit limit
110 if(!RooNumber::isInfinite(min) && value < min-1e-6) {
111 clippedValue = min ;
112 isInRange = kFALSE ;
113 }
114
115 if (clippedValPtr) *clippedValPtr=clippedValue ;
116
117 return isInRange ;
118}
119
120
121
122////////////////////////////////////////////////////////////////////////////////
123/// Check if given value is valid
124
126{
127 if (!inRange(value,0)) {
128 if (verbose)
129 coutI(InputArguments) << "RooRealVar::isValid(" << GetName() << "): value " << value
130 << " out of range (" << getMin() << " - " << getMax() << ")" << endl ;
131 return kFALSE ;
132 }
133 return kTRUE ;
134}
135
136
137
138////////////////////////////////////////////////////////////////////////////////
139/// Read object contents from given stream
140
141Bool_t RooAbsRealLValue::readFromStream(istream& /*is*/, Bool_t /*compact*/, Bool_t /*verbose*/)
142{
143 return kTRUE ;
144}
145
146
147
148////////////////////////////////////////////////////////////////////////////////
149/// Write object contents to given stream
150
151void RooAbsRealLValue::writeToStream(ostream& /*os*/, Bool_t /*compact*/) const
152{
153}
154
155
156
157////////////////////////////////////////////////////////////////////////////////
158/// Assignment operator from a Double_t
159
161{
162 Double_t clipValue ;
163 // Clip
164 inRange(newValue,0,&clipValue) ;
165 setVal(clipValue) ;
166
167 return *this ;
168}
169
170
171////////////////////////////////////////////////////////////////////////////////
172/// Assignment operator from other RooAbsReal
173
175{
176 return operator=(arg.getVal()) ;
177}
178
179
180
181////////////////////////////////////////////////////////////////////////////////
182/// Create a new RooPlot on the heap with a drawing frame initialized for this
183/// object, but no plot contents. Use x.frame() as the first argument to a
184/// y.plotOn(...) method, for example. The caller is responsible for deleting
185/// the returned object.
186///
187/// <table>
188/// <tr><th> Optional arguments <th>
189/// <tr><td> Range(double lo, double hi) <td> Make plot frame for the specified range
190/// <tr><td> Range(const char* name) <td> Make plot frame for range with the specified name
191/// <tr><td> Bins(Int_t nbins) <td> Set default binning for datasets to specified number of bins
192/// <tr><td> AutoRange(const RooAbsData& data, double margin) <td> Specifies range so that all points in given data set fit
193/// inside the range with given margin.
194/// <tr><td> AutoSymRange(const RooAbsData& data, double margin) <td> Specifies range so that all points in given data set fit
195/// inside the range and center of range coincides with mean of distribution in given dataset.
196/// <tr><td> Name(const char* name) <td> Give specified name to RooPlot object
197/// <tr><td> Title(const char* title) <td> Give specified title to RooPlot object
198/// </table>
199///
200RooPlot* RooAbsRealLValue::frame(const RooCmdArg& arg1, const RooCmdArg& arg2, const RooCmdArg& arg3, const RooCmdArg& arg4,
201 const RooCmdArg& arg5, const RooCmdArg& arg6, const RooCmdArg& arg7, const RooCmdArg& arg8) const
202{
203 RooLinkedList cmdList ;
204 cmdList.Add(const_cast<RooCmdArg*>(&arg1)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg2)) ;
205 cmdList.Add(const_cast<RooCmdArg*>(&arg3)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg4)) ;
206 cmdList.Add(const_cast<RooCmdArg*>(&arg5)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg6)) ;
207 cmdList.Add(const_cast<RooCmdArg*>(&arg7)) ; cmdList.Add(const_cast<RooCmdArg*>(&arg8)) ;
208
209 return frame(cmdList) ;
210}
211
212
213
214////////////////////////////////////////////////////////////////////////////////
215/// Back-end function for named argument frame() method
216
218{
219 // Define configuration for this method
220 RooCmdConfig pc(Form("RooAbsRealLValue::frame(%s)",GetName())) ;
221 pc.defineDouble("min","Range",0,getMin()) ;
222 pc.defineDouble("max","Range",1,getMax()) ;
223 pc.defineInt("nbins","Bins",0,getBins()) ;
224 pc.defineString("rangeName","RangeWithName",0,"") ;
225 pc.defineString("name","Name",0,"") ;
226 pc.defineString("title","Title",0,"") ;
227 pc.defineMutex("Range","RangeWithName","AutoRange") ;
228 pc.defineObject("rangeData","AutoRange",0,0) ;
229 pc.defineDouble("rangeMargin","AutoRange",0,0.1) ;
230 pc.defineInt("rangeSym","AutoRange",0,0) ;
231
232 // Process & check varargs
233 pc.process(cmdList) ;
234 if (!pc.ok(kTRUE)) {
235 return 0 ;
236 }
237
238 // Extract values from named arguments
240 if (pc.hasProcessed("Range")) {
241 xmin = pc.getDouble("min") ;
242 xmax = pc.getDouble("max") ;
243 if (xmin==xmax) {
244 xmin = getMin() ;
245 xmax = getMax() ;
246 }
247 } else if (pc.hasProcessed("RangeWithName")) {
248 const char* rangeName=pc.getString("rangeName",0,kTRUE) ;
249 xmin = getMin(rangeName) ;
250 xmax = getMax(rangeName) ;
251 } else if (pc.hasProcessed("AutoRange")) {
252 auto rangeData = static_cast<RooAbsData*>(pc.getObject("rangeData")) ;
253 const bool error = rangeData->getRange(*this,xmin,xmax);
254 if (error) {
255 xmin = getMin();
256 xmax = getMax();
257 }
258 if (pc.getInt("rangeSym")==0) {
259 // Regular mode: range is from xmin to xmax with given extra margin
260 Double_t margin = pc.getDouble("rangeMargin")*(xmax-xmin) ;
261 xmin -= margin ;
262 xmax += margin ;
263 if (xmin<getMin()) xmin = getMin() ;
264 if (xmin>getMax()) xmax = getMax() ;
265 } else {
266 // Symmetric mode: range is centered at mean of distribution with enough width to include
267 // both lowest and highest point with margin
268 Double_t dmean = rangeData->moment((RooRealVar&)*this,1) ;
269 Double_t ddelta = ((xmax-dmean)>(dmean-xmin)?(xmax-dmean):(dmean-xmin))*(1+pc.getDouble("rangeMargin")) ;
270 xmin = dmean-ddelta ;
271 xmax = dmean+ddelta ;
272 if (xmin<getMin()) xmin = getMin() ;
273 if (xmin>getMax()) xmax = getMax() ;
274 }
275 } else {
276 xmin = getMin() ;
277 xmax = getMax() ;
278 }
279
280 Int_t nbins = pc.getInt("nbins") ;
281 const char* name = pc.getString("name",0,kTRUE) ;
282 const char* title = pc.getString("title",0,kTRUE) ;
283
284 RooPlot* theFrame = new RooPlot(*this,xmin,xmax,nbins) ;
285
286 if (name) {
287 theFrame->SetName(name) ;
288 }
289 if (title) {
290 theFrame->SetTitle(title) ;
291 }
292
293 return theFrame ;
294}
295
296
297
298////////////////////////////////////////////////////////////////////////////////
299/// Create a new RooPlot on the heap with a drawing frame initialized for this
300/// object, but no plot contents. Use x.frame() as the first argument to a
301/// y.plotOn(...) method, for example. The caller is responsible for deleting
302/// the returned object.
303
305{
306 return new RooPlot(*this,xlo,xhi,nbins);
307}
308
309
310
311////////////////////////////////////////////////////////////////////////////////
312/// Create a new RooPlot on the heap with a drawing frame initialized for this
313/// object, but no plot contents. Use x.frame() as the first argument to a
314/// y.plotOn(...) method, for example. The caller is responsible for deleting
315/// the returned object.
316
318{
319 return new RooPlot(*this,xlo,xhi,getBins());
320}
321
322
323
324////////////////////////////////////////////////////////////////////////////////
325/// Create a new RooPlot on the heap with a drawing frame initialized for this
326/// object, but no plot contents. Use x.frame() as the first argument to a
327/// y.plotOn(...) method, for example. The caller is responsible for deleting
328/// the returned object.
329///
330/// The current fit range may not be open ended or empty.
331
333{
334 // Plot range of variable may not be infinite or empty
335 if (getMin()==getMax()) {
336 coutE(InputArguments) << "RooAbsRealLValue::frame(" << GetName() << ") ERROR: empty fit range, must specify plot range" << endl ;
337 return 0 ;
338 }
340 coutE(InputArguments) << "RooAbsRealLValue::frame(" << GetName() << ") ERROR: open ended fit range, must specify plot range" << endl ;
341 return 0 ;
342 }
343
344 return new RooPlot(*this,getMin(),getMax(),nbins);
345}
346
347
348
349////////////////////////////////////////////////////////////////////////////////
350/// Create a new RooPlot on the heap with a drawing frame initialized for this
351/// object, but no plot contents. Use x.frame() as the first argument to a
352/// y.plotOn(...) method, for example. The caller is responsible for deleting
353/// the returned object.
354///
355/// The current fit range may not be open ended or empty.
356
358{
359 // Plot range of variable may not be infinite or empty
360 if (getMin()==getMax()) {
361 coutE(InputArguments) << "RooAbsRealLValue::frame(" << GetName() << ") ERROR: empty fit range, must specify plot range" << endl ;
362 return 0 ;
363 }
365 coutE(InputArguments) << "RooAbsRealLValue::frame(" << GetName() << ") ERROR: open ended fit range, must specify plot range" << endl ;
366 return 0 ;
367 }
368
369 return new RooPlot(*this,getMin(),getMax(),getBins());
370}
371
372
373
374////////////////////////////////////////////////////////////////////////////////
375/// Copy cache of another RooAbsArg to our cache
376
377void RooAbsRealLValue::copyCache(const RooAbsArg* source, Bool_t valueOnly, Bool_t setValDirty)
378{
379 RooAbsReal::copyCache(source,valueOnly,setValDirty) ;
380 setVal(_value) ; // force back-propagation
381}
382
383
384////////////////////////////////////////////////////////////////////////////////
385/// Structure printing
386
388{
390 os << indent << "--- RooAbsRealLValue ---" << endl;
391 TString unit(_unit);
392 if(!unit.IsNull()) unit.Prepend(' ');
393 os << indent << " Fit range is [ ";
394 if(hasMin()) {
395 os << getMin() << unit << " , ";
396 }
397 else {
398 os << "-INF , ";
399 }
400 if(hasMax()) {
401 os << getMax() << unit << " ]" << endl;
402 }
403 else {
404 os << "+INF ]" << endl;
405 }
406}
407
408
409
410////////////////////////////////////////////////////////////////////////////////
411/// Set a new value sampled from a uniform distribution over the fit range.
412/// Prints a warning and does nothing if the fit range is not finite.
413
414void RooAbsRealLValue::randomize(const char* rangeName)
415{
416 RooAbsBinning& binning = getBinning(rangeName) ;
417 Double_t min = binning.lowBound() ;
418 Double_t max = binning.highBound() ;
419
421 setValFast(min + RooRandom::uniform()*(max-min));
422 }
423 else {
424 coutE(Generation) << fName << "::" << ClassName() << ":randomize: fails with unbounded fit range" << endl;
425 }
426}
427
428
429
430////////////////////////////////////////////////////////////////////////////////
431/// Set value to center of bin 'ibin' of binning 'rangeName' (or of
432/// default binning if no range is specified)
433
434void RooAbsRealLValue::setBin(Int_t ibin, const char* rangeName)
435{
436 // Check range of plot bin index
437 if (ibin<0 || ibin>=numBins(rangeName)) {
438 coutE(InputArguments) << "RooAbsRealLValue::setBin(" << GetName() << ") ERROR: bin index " << ibin
439 << " is out of range (0," << getBins(rangeName)-1 << ")" << endl ;
440 return ;
441 }
442
443 // Set value to center of requested bin
444 setVal(getBinning(rangeName).binCenter(ibin)) ;
445}
446
447
448
449
450
451////////////////////////////////////////////////////////////////////////////////
452/// Set value to center of bin 'ibin' of binning 'binning'
453
455{
456 // Set value to center of requested bin
457 setVal(binning.binCenter(ibin)) ;
458}
459
460
461
462
463
464////////////////////////////////////////////////////////////////////////////////
465/// Set a new value sampled from a uniform distribution over the fit range.
466/// Prints a warning and does nothing if the fit range is not finite.
467
469{
470 Double_t range= binning.highBound() - binning.lowBound() ;
471 setVal(binning.lowBound() + RooRandom::uniform()*range);
472}
473
474
475
476
477
478////////////////////////////////////////////////////////////////////////////////
479/// Set value to center of bin 'ibin' of binning 'rangeName' (or of
480/// default binning if no range is specified)
481
483{
484 // Set value to center of requested bin
485 setValFast(binning.binCenter(ibin)) ;
486}
487
488
489
490////////////////////////////////////////////////////////////////////////////////
491/// Check if fit range is usable as plot range, i.e. it is neither
492/// open ended, nor empty
493
495{
496 return (hasMin() && hasMax() && (getMin()!=getMax())) ;
497}
498
499
500
501////////////////////////////////////////////////////////////////////////////////
502/// Check if current value is inside range with given name. Multiple comma-separated
503/// ranges can be passed. In this case, it will be checked if the value is in any of
504/// these ranges.
506{
507 const double val = getVal() ;
508 const double epsilon = 1e-8 * fabs(val) ;
509 if (!name || name[0] == '\0') {
510 const auto minMax = getRange(nullptr);
511 return minMax.first - epsilon <= val && val <= minMax.second + epsilon;
512 }
513
514 const auto& ranges = ROOT::Split(name, ",");
515 return std::any_of(ranges.begin(), ranges.end(), [val,epsilon,this](const std::string& range){
516 const auto minMax = this->getRange(range.c_str());
517 return minMax.first - epsilon <= val && val <= minMax.second + epsilon;
518 });
519}
520
521
522
523////////////////////////////////////////////////////////////////////////////////
524
525TH1* RooAbsRealLValue::createHistogram(const char *name, const RooCmdArg& arg1, const RooCmdArg& arg2,
526 const RooCmdArg& arg3, const RooCmdArg& arg4, const RooCmdArg& arg5,
527 const RooCmdArg& arg6, const RooCmdArg& arg7, const RooCmdArg& arg8) const
528
529 // Create an empty ROOT histogram TH1,TH2 or TH3 suitabe to store information represent by the RooAbsRealLValue
530 //
531 // This function accepts the following arguments
532 //
533 // name -- Name of the ROOT histogram
534 //
535 // Binning(const char* name) -- Apply binning with given name to x axis of histogram
536 // Binning(RooAbsBinning& binning) -- Apply specified binning to x axis of histogram
537 // Binning(int_t nbins) -- Apply specified binning to x axis of histogram
538 // Binning(int_t nbins, double lo, double hi) -- Apply specified binning to x axis of histogram
539 // ConditionalObservables(const RooArgSet& set) -- Do not normalized PDF over following observables when projecting PDF into histogram
540 //
541 // YVar(const RooAbsRealLValue& var,...) -- Observable to be mapped on y axis of ROOT histogram
542 // ZVar(const RooAbsRealLValue& var,...) -- Observable to be mapped on z axis of ROOT histogram
543 //
544 // The YVar() and ZVar() arguments can be supplied with optional Binning() arguments to control the binning of the Y and Z axes, e.g.
545 // createHistogram("histo",x,Binning(-1,1,20), YVar(y,Binning(-1,1,30)), ZVar(z,Binning("zbinning")))
546 //
547 // The caller takes ownership of the returned histogram
548{
550 l.Add((TObject*)&arg1) ; l.Add((TObject*)&arg2) ;
551 l.Add((TObject*)&arg3) ; l.Add((TObject*)&arg4) ;
552 l.Add((TObject*)&arg5) ; l.Add((TObject*)&arg6) ;
553 l.Add((TObject*)&arg7) ; l.Add((TObject*)&arg8) ;
554
555 return createHistogram(name,l) ;
556}
557
558
559
560////////////////////////////////////////////////////////////////////////////////
561/// Create empty 1,2 or 3D histogram
562/// Arguments recognized
563///
564/// YVar() -- RooRealVar defining Y dimension with optional range/binning
565/// ZVar() -- RooRealVar defining Z dimension with optional range/binning
566/// AxisLabel() -- Vertical axis label
567/// Binning() -- Range/Binning specification of X axis
568
569TH1* RooAbsRealLValue::createHistogram(const char *name, const RooLinkedList& cmdList) const
570{
571 // Define configuration for this method
572 RooCmdConfig pc(Form("RooAbsRealLValue::createHistogram(%s)",GetName())) ;
573
574 pc.defineObject("xbinning","Binning",0,0) ;
575 pc.defineString("xbinningName","BinningName",0,"") ;
576 pc.defineInt("nxbins","BinningSpec",0) ;
577 pc.defineDouble("xlo","BinningSpec",0,0) ;
578 pc.defineDouble("xhi","BinningSpec",1,0) ;
579
580 pc.defineObject("yvar","YVar",0,0) ;
581 pc.defineObject("ybinning","YVar::Binning",0,0) ;
582 pc.defineString("ybinningName","YVar::BinningName",0,"") ;
583 pc.defineInt("nybins","YVar::BinningSpec",0) ;
584 pc.defineDouble("ylo","YVar::BinningSpec",0,0) ;
585 pc.defineDouble("yhi","YVar::BinningSpec",1,0) ;
586
587 pc.defineObject("zvar","ZVar",0,0) ;
588 pc.defineObject("zbinning","ZVar::Binning",0,0) ;
589 pc.defineString("zbinningName","ZVar::BinningName",0,"") ;
590 pc.defineInt("nzbins","ZVar::BinningSpec",0) ;
591 pc.defineDouble("zlo","ZVar::BinningSpec",0,0) ;
592 pc.defineDouble("zhi","ZVar::BinningSpec",1,0) ;
593
594 pc.defineString("axisLabel","AxisLabel",0,"Events") ;
595
596 pc.defineDependency("ZVar","YVar") ;
597
598 // Process & check varargs
599 pc.process(cmdList) ;
600 if (!pc.ok(kTRUE)) {
601 return 0 ;
602 }
603
604 // Initialize arrays for call to implementation version of createHistogram
605 const char* axisLabel = pc.getString("axisLabel") ;
606 const RooAbsBinning* binning[3] ;
607 Bool_t ownBinning[3] = { kFALSE, kFALSE, kFALSE } ;
608 RooArgList vars ;
609
610 // Prepare X dimension
611 vars.add(*this) ;
612 if (pc.hasProcessed("Binning")) {
613 binning[0] = static_cast<RooAbsBinning*>(pc.getObject("xbinning")) ;
614 } else if (pc.hasProcessed("BinningName")) {
615 binning[0] = &getBinning(pc.getString("xbinningName",0,kTRUE)) ;
616 } else if (pc.hasProcessed("BinningSpec")) {
617 Double_t xlo = pc.getDouble("xlo") ;
618 Double_t xhi = pc.getDouble("xhi") ;
619 binning[0] = new RooUniformBinning((xlo==xhi)?getMin():xlo,(xlo==xhi)?getMax():xhi,pc.getInt("nxbins")) ;
620 ownBinning[0] = kTRUE ;
621 } else {
622 binning[0] = &getBinning() ;
623 }
624
625 if (pc.hasProcessed("YVar")) {
626 RooAbsRealLValue& yvar = *static_cast<RooAbsRealLValue*>(pc.getObject("yvar")) ;
627 vars.add(yvar) ;
628 if (pc.hasProcessed("YVar::Binning")) {
629 binning[1] = static_cast<RooAbsBinning*>(pc.getObject("ybinning")) ;
630 } else if (pc.hasProcessed("YVar::BinningName")) {
631 binning[1] = &yvar.getBinning(pc.getString("ybinningName",0,kTRUE)) ;
632 } else if (pc.hasProcessed("YVar::BinningSpec")) {
633 Double_t ylo = pc.getDouble("ylo") ;
634 Double_t yhi = pc.getDouble("yhi") ;
635 binning[1] = new RooUniformBinning((ylo==yhi)?yvar.getMin():ylo,(ylo==yhi)?yvar.getMax():yhi,pc.getInt("nybins")) ;
636 ownBinning[1] = kTRUE ;
637 } else {
638 binning[1] = &yvar.getBinning() ;
639 }
640 }
641
642 if (pc.hasProcessed("ZVar")) {
643 RooAbsRealLValue& zvar = *static_cast<RooAbsRealLValue*>(pc.getObject("zvar")) ;
644 vars.add(zvar) ;
645 if (pc.hasProcessed("ZVar::Binning")) {
646 binning[2] = static_cast<RooAbsBinning*>(pc.getObject("zbinning")) ;
647 } else if (pc.hasProcessed("ZVar::BinningName")) {
648 binning[2] = &zvar.getBinning(pc.getString("zbinningName",0,kTRUE)) ;
649 } else if (pc.hasProcessed("ZVar::BinningSpec")) {
650 Double_t zlo = pc.getDouble("zlo") ;
651 Double_t zhi = pc.getDouble("zhi") ;
652 binning[2] = new RooUniformBinning((zlo==zhi)?zvar.getMin():zlo,(zlo==zhi)?zvar.getMax():zhi,pc.getInt("nzbins")) ;
653 ownBinning[2] = kTRUE ;
654 } else {
655 binning[2] = &zvar.getBinning() ;
656 }
657 }
658
659
660 TH1* ret = createHistogram(name, vars, axisLabel, binning) ;
661
662 if (ownBinning[0]) delete binning[0] ;
663 if (ownBinning[1]) delete binning[1] ;
664 if (ownBinning[2]) delete binning[2] ;
665
666 return ret ;
667}
668
669
670
671////////////////////////////////////////////////////////////////////////////////
672/// Create an empty 1D-histogram with appropriate scale and labels for this variable.
673/// This method uses the default plot range which can be changed using the
674/// setPlotMin(),setPlotMax() methods, and the default binning which can be
675/// changed with setPlotBins(). The caller takes ownership of the returned
676/// object and is responsible for deleting it.
677
678TH1F *RooAbsRealLValue::createHistogram(const char *name, const char *yAxisLabel) const
679{
680 // Check if the fit range is usable as plot range
681 if (!fitRangeOKForPlotting()) {
682 coutE(InputArguments) << "RooAbsRealLValue::createHistogram(" << GetName()
683 << ") ERROR: fit range empty or open ended, must explicitly specify range" << endl ;
684 return 0 ;
685 }
686
687 RooArgList list(*this) ;
688 Double_t xlo = getMin() ;
689 Double_t xhi = getMax() ;
690 Int_t nbins = getBins() ;
691
692 // coverity[ARRAY_VS_SINGLETON]
693 return (TH1F*)createHistogram(name, list, yAxisLabel, &xlo, &xhi, &nbins);
694}
695
696
697
698////////////////////////////////////////////////////////////////////////////////
699/// Create an empty 1D-histogram with appropriate scale and labels for this variable.
700/// This method uses the default plot range which can be changed using the
701/// setPlotMin(),setPlotMax() methods, and the default binning which can be
702/// changed with setPlotBins(). The caller takes ownership of the returned
703/// object and is responsible for deleting it.
704
705TH1F *RooAbsRealLValue::createHistogram(const char *name, const char *yAxisLabel, Double_t xlo, Double_t xhi, Int_t nBins) const
706{
707 RooArgList list(*this) ;
708
709 // coverity[ARRAY_VS_SINGLETON]
710 return (TH1F*)createHistogram(name, list, yAxisLabel, &xlo, &xhi, &nBins);
711}
712
713
714
715////////////////////////////////////////////////////////////////////////////////
716/// Create an empty 1D-histogram with appropriate scale and labels for this variable.
717
718TH1F *RooAbsRealLValue::createHistogram(const char *name, const char *yAxisLabel, const RooAbsBinning& bins) const
719{
720 RooArgList list(*this) ;
721 const RooAbsBinning* pbins = &bins ;
722
723 // coverity[ARRAY_VS_SINGLETON]
724 return (TH1F*)createHistogram(name, list, yAxisLabel, &pbins);
725}
726
727
728
729////////////////////////////////////////////////////////////////////////////////
730/// Create an empty 2D-histogram with appropriate scale and labels for this variable (x)
731/// and the specified y variable. This method uses the default plot ranges for x and y which
732/// can be changed using the setPlotMin(),setPlotMax() methods, and the default binning which
733/// can be changed with setPlotBins(). The caller takes ownership of the returned object
734/// and is responsible for deleting it.
735
736TH2F *RooAbsRealLValue::createHistogram(const char *name, const RooAbsRealLValue &yvar, const char *zAxisLabel,
737 Double_t* xlo, Double_t* xhi, Int_t* nBins) const
738{
739 if ((!xlo && xhi) || (xlo && !xhi)) {
740 coutE(InputArguments) << "RooAbsRealLValue::createHistogram(" << GetName()
741 << ") ERROR must specify either no range, or both limits" << endl ;
742 return 0 ;
743 }
744
745 Double_t xlo_fit[2] ;
746 Double_t xhi_fit[2] ;
747 Int_t nbins_fit[2] ;
748
749 Double_t *xlo2 = xlo;
750 Double_t *xhi2 = xhi;
751 Int_t *nBins2 = nBins;
752
753 if (!xlo2) {
754
755 if (!fitRangeOKForPlotting()) {
756 coutE(InputArguments) << "RooAbsRealLValue::createHistogram(" << GetName()
757 << ") ERROR: fit range empty or open ended, must explicitly specify range" << endl ;
758 return 0 ;
759 }
760 if (!yvar.fitRangeOKForPlotting()) {
761 coutE(InputArguments) << "RooAbsRealLValue::createHistogram(" << GetName()
762 << ") ERROR: fit range of " << yvar.GetName() << " empty or open ended, must explicitly specify range" << endl ;
763 return 0 ;
764 }
765
766 xlo_fit[0] = getMin() ;
767 xhi_fit[0] = getMax() ;
768
769 xlo_fit[1] = yvar.getMin() ;
770 xhi_fit[1] = yvar.getMax() ;
771
772 xlo2 = xlo_fit ;
773 xhi2 = xhi_fit ;
774 }
775
776 if (!nBins2) {
777 nbins_fit[0] = getBins() ;
778 nbins_fit[1] = yvar.getBins() ;
779 nBins2 = nbins_fit ;
780 }
781
782
783 RooArgList list(*this,yvar) ;
784 // coverity[OVERRUN_STATIC]
785 return (TH2F*)createHistogram(name, list, zAxisLabel, xlo2, xhi2, nBins2);
786}
787
788
789
790////////////////////////////////////////////////////////////////////////////////
791/// Create an empty 2D-histogram with appropriate scale and labels for this variable (x)
792/// and the specified y variable.
793
795 const char *zAxisLabel, const RooAbsBinning** bins) const
796{
797 RooArgList list(*this,yvar) ;
798 return (TH2F*)createHistogram(name, list, zAxisLabel, bins);
799}
800
801
802
803////////////////////////////////////////////////////////////////////////////////
804/// Create an empty 3D-histogram with appropriate scale and labels for this variable (x)
805/// and the specified y,z variables. This method uses the default plot ranges for x,y,z which
806/// can be changed using the setPlotMin(),setPlotMax() methods, and the default binning which
807/// can be changed with setPlotBins(). The caller takes ownership of the returned object
808/// and is responsible for deleting it.
809
811 const char *tAxisLabel, Double_t* xlo, Double_t* xhi, Int_t* nBins) const
812{
813 if ((!xlo && xhi) || (xlo && !xhi)) {
814 coutE(InputArguments) << "RooAbsRealLValue::createHistogram(" << GetName()
815 << ") ERROR must specify either no range, or both limits" << endl ;
816 return 0 ;
817 }
818
819 Double_t xlo_fit[3] ;
820 Double_t xhi_fit[3] ;
821 Int_t nbins_fit[3] ;
822
823 Double_t *xlo2 = xlo;
824 Double_t *xhi2 = xhi;
825 Int_t* nBins2 = nBins;
826 if (!xlo2) {
827
828 if (!fitRangeOKForPlotting()) {
829 coutE(InputArguments) << "RooAbsRealLValue::createHistogram(" << GetName()
830 << ") ERROR: fit range empty or open ended, must explicitly specify range" << endl ;
831 return 0 ;
832 }
833 if (!yvar.fitRangeOKForPlotting()) {
834 coutE(InputArguments) << "RooAbsRealLValue::createHistogram(" << GetName()
835 << ") ERROR: fit range of " << yvar.GetName() << " empty or open ended, must explicitly specify range" << endl ;
836 return 0 ;
837 }
838 if (!zvar.fitRangeOKForPlotting()) {
839 coutE(InputArguments) << "RooAbsRealLValue::createHistogram(" << GetName()
840 << ") ERROR: fit range of " << zvar.GetName() << " empty or open ended, must explicitly specify range" << endl ;
841 return 0 ;
842 }
843
844 xlo_fit[0] = getMin() ;
845 xhi_fit[0] = getMax() ;
846
847 xlo_fit[1] = yvar.getMin() ;
848 xhi_fit[1] = yvar.getMax() ;
849
850 xlo_fit[2] = zvar.getMin() ;
851 xhi_fit[2] = zvar.getMax() ;
852
853 xlo2 = xlo_fit ;
854 xhi2 = xhi_fit ;
855 }
856
857 if (!nBins2) {
858 nbins_fit[0] = getBins() ;
859 nbins_fit[1] = yvar.getBins() ;
860 nbins_fit[2] = zvar.getBins() ;
861 nBins2 = nbins_fit ;
862 }
863
864 RooArgList list(*this,yvar,zvar) ;
865 return (TH3F*)createHistogram(name, list, tAxisLabel, xlo2, xhi2, nBins2);
866}
867
868
870 const char* tAxisLabel, const RooAbsBinning** bins) const
871{
872 // Create an empty 3D-histogram with appropriate scale and labels for this variable (x)
873 // and the specified y,z variables.
874
875 RooArgList list(*this,yvar,zvar) ;
876 return (TH3F*)createHistogram(name, list, tAxisLabel, bins);
877}
878
879
880
881
882////////////////////////////////////////////////////////////////////////////////
883/// Create 1-, 2- or 3-d ROOT histogram with labels taken
884/// from the variables in 'vars' and the with range and binning
885/// specified in xlo,xhi and nBins. The dimensions of the arrays xlo,xhi,
886/// nBins should match the number of objects in vars.
887
888TH1 *RooAbsRealLValue::createHistogram(const char *name, RooArgList &vars, const char *tAxisLabel,
889 Double_t* xlo, Double_t* xhi, Int_t* nBins)
890{
891 const RooAbsBinning* bin[3] ;
892 Int_t ndim = vars.getSize() ;
893 bin[0] = new RooUniformBinning(xlo[0],xhi[0],nBins[0]) ;
894 bin[1] = (ndim>1) ? new RooUniformBinning(xlo[1],xhi[1],nBins[1]) : 0 ;
895 bin[2] = (ndim>2) ? new RooUniformBinning(xlo[2],xhi[2],nBins[2]) : 0 ;
896
897 TH1* ret = createHistogram(name,vars,tAxisLabel,bin) ;
898
899 if (bin[0]) delete bin[0] ;
900 if (bin[1]) delete bin[1] ;
901 if (bin[2]) delete bin[2] ;
902 return ret ;
903}
904
905
906
907////////////////////////////////////////////////////////////////////////////////
908/// Create a 1,2, or 3D-histogram with appropriate scale and labels.
909/// Binning and ranges are taken from the variables themselves and can be changed by
910/// calling their setPlotMin/Max() and setPlotBins() methods. A histogram can be filled
911/// using RooAbsReal::fillHistogram() or RooTreeData::fillHistogram().
912/// The caller takes ownership of the returned object and is responsible for deleting it.
913
914TH1 *RooAbsRealLValue::createHistogram(const char *name, RooArgList &vars, const char *tAxisLabel, const RooAbsBinning** bins)
915{
916 // Check that we have 1-3 vars
917 Int_t dim= vars.getSize();
918 if(dim < 1 || dim > 3) {
919 oocoutE((TObject*)0,InputArguments) << "RooAbsReal::createHistogram: dimension not supported: " << dim << endl;
920 return 0;
921 }
922
923 // Check that all variables are AbsReals and prepare a name of the form <name>_<var1>_...
924 TString histName(name);
925 histName.Append("_");
926 const RooAbsRealLValue *xyz[3];
927
928 Int_t index;
929 for(index= 0; index < dim; index++) {
930 const RooAbsArg *arg= vars.at(index);
931 xyz[index]= dynamic_cast<const RooAbsRealLValue*>(arg);
932 if(!xyz[index]) {
933 oocoutE((TObject*)0,InputArguments) << "RooAbsRealLValue::createHistogram: variable is not real lvalue: " << arg->GetName() << endl;
934 return 0;
935 }
936 histName.Append("_");
937 histName.Append(arg->GetName());
938 }
939 TString histTitle(histName);
940 histTitle.Prepend("Histogram of ");
941
942 // Create the histogram
943 TH1 *histogram = 0;
944 switch(dim) {
945 case 1:
946 if (bins[0]->isUniform()) {
947 histogram= new TH1F(histName.Data(), histTitle.Data(),
948 bins[0]->numBins(),bins[0]->lowBound(),bins[0]->highBound());
949 } else {
950 histogram= new TH1F(histName.Data(), histTitle.Data(),
951 bins[0]->numBins(),bins[0]->array());
952 }
953 break;
954 case 2:
955 if (bins[0]->isUniform() && bins[1]->isUniform()) {
956 histogram= new TH2F(histName.Data(), histTitle.Data(),
957 bins[0]->numBins(),bins[0]->lowBound(),bins[0]->highBound(),
958 bins[1]->numBins(),bins[1]->lowBound(),bins[1]->highBound());
959 } else {
960 histogram= new TH2F(histName.Data(), histTitle.Data(),
961 bins[0]->numBins(),bins[0]->array(),
962 bins[1]->numBins(),bins[1]->array());
963 }
964 break;
965 case 3:
966 if (bins[0]->isUniform() && bins[1]->isUniform() && bins[2]->isUniform()) {
967 histogram= new TH3F(histName.Data(), histTitle.Data(),
968 bins[0]->numBins(),bins[0]->lowBound(),bins[0]->highBound(),
969 bins[1]->numBins(),bins[1]->lowBound(),bins[1]->highBound(),
970 bins[2]->numBins(),bins[2]->lowBound(),bins[2]->highBound()) ;
971 } else {
972 histogram= new TH3F(histName.Data(), histTitle.Data(),
973 bins[0]->numBins(),bins[0]->array(),
974 bins[1]->numBins(),bins[1]->array(),
975 bins[2]->numBins(),bins[2]->array()) ;
976 }
977 break;
978 }
979 if(!histogram) {
980 oocoutE((TObject*)0,InputArguments) << "RooAbsReal::createHistogram: unable to create a new histogram" << endl;
981 return 0;
982 }
983
984 // Set the histogram coordinate axis labels from the titles of each variable, adding units if necessary.
985 for(index= 0; index < dim; index++) {
986 TString axisTitle(xyz[index]->getTitle(kTRUE));
987 switch(index) {
988 case 0:
989 histogram->SetXTitle(axisTitle.Data());
990 break;
991 case 1:
992 histogram->SetYTitle(axisTitle.Data());
993 break;
994 case 2:
995 histogram->SetZTitle(axisTitle.Data());
996 break;
997 default:
998 assert(0);
999 break;
1000 }
1001 }
1002
1003 // Set the t-axis title if given one
1004 if((0 != tAxisLabel) && (0 != strlen(tAxisLabel))) {
1005 TString axisTitle(tAxisLabel);
1006 axisTitle.Append(" / ( ");
1007 for(Int_t index2= 0; index2 < dim; index2++) {
1008 Double_t delta= bins[index2]->averageBinWidth() ; // xyz[index2]->getBins();
1009 if(index2 > 0) axisTitle.Append(" x ");
1010 axisTitle.Append(Form("%g",delta));
1011 if(strlen(xyz[index2]->getUnit())) {
1012 axisTitle.Append(" ");
1013 axisTitle.Append(xyz[index2]->getUnit());
1014 }
1015 }
1016 axisTitle.Append(" )");
1017 switch(dim) {
1018 case 1:
1019 histogram->SetYTitle(axisTitle.Data());
1020 break;
1021 case 2:
1022 histogram->SetZTitle(axisTitle.Data());
1023 break;
1024 case 3:
1025 // not supported in TH1
1026 break;
1027 default:
1028 assert(0);
1029 break;
1030 }
1031 }
1032
1033 return histogram;
1034}
1035
1036
1038{
1039 // Interface function to indicate that this lvalue
1040 // has a unit or constant jacobian terms with respect to
1041 // the observable passed as argument. This default implementation
1042 // always returns true (i.e. jacobian is constant)
1043 return kTRUE ;
1044}
#define e(i)
Definition: RSha256.hxx:103
#define coutI(a)
Definition: RooMsgService.h:30
#define oocoutE(o, a)
Definition: RooMsgService.h:48
#define coutE(a)
Definition: RooMsgService.h:33
int Int_t
Definition: RtypesCore.h:45
const Bool_t kFALSE
Definition: RtypesCore.h:101
bool Bool_t
Definition: RtypesCore.h:63
double Double_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:100
#define ClassImp(name)
Definition: Rtypes.h:364
static void indent(ostringstream &buf, int indent_level)
char name[80]
Definition: TGX11.cxx:110
float xmin
Definition: THbookFile.cxx:95
float xmax
Definition: THbookFile.cxx:95
char * Form(const char *fmt,...)
RooAbsArg is the common abstract base class for objects that represent a value and a "shape" in RooFi...
Definition: RooAbsArg.h:72
RooAbsBinning is the abstract base class for RooRealVar binning definitions.
Definition: RooAbsBinning.h:26
virtual Double_t * array() const =0
Int_t numBins() const
Return number of bins.
Definition: RooAbsBinning.h:38
virtual Double_t highBound() const =0
virtual Double_t binCenter(Int_t bin) const =0
virtual Double_t lowBound() const =0
virtual Double_t averageBinWidth() const =0
Int_t getSize() const
virtual Bool_t add(const RooAbsArg &var, Bool_t silent=kFALSE)
Add the specified argument to list.
RooAbsData is the common abstract base class for binned and unbinned datasets.
Definition: RooAbsData.h:79
Bool_t getRange(const RooAbsRealLValue &var, Double_t &lowest, Double_t &highest, Double_t marginFrac=0, Bool_t symMode=kFALSE) const
Fill Doubles 'lowest' and 'highest' with the lowest and highest value of observable 'var' in this dat...
Abstract base class for objects that are lvalues, i.e.
Definition: RooAbsLValue.h:26
RooAbsRealLValue is the common abstract base class for objects that represent a real value that may a...
virtual Double_t getMax(const char *name=0) const
Get maximum of currently defined range.
Bool_t hasMax(const char *name=0) const
Check if variable has an upper bound.
void copyCache(const RooAbsArg *source, Bool_t valueOnly=kFALSE, Bool_t setValDirty=kTRUE)
Copy cache of another RooAbsArg to our cache.
virtual const RooAbsBinning & getBinning(const char *name=0, Bool_t verbose=kTRUE, Bool_t createOnTheFly=kFALSE) const =0
Retrive binning configuration with given name or default binning.
std::pair< double, double > getRange(const char *name=0) const
Get low and high bound of the variable.
virtual Bool_t isValidReal(Double_t value, Bool_t printError=kFALSE) const
Check if given value is valid.
virtual void printMultiline(std::ostream &os, Int_t contents, Bool_t verbose=kFALSE, TString indent="") const
Structure printing.
virtual void setBin(Int_t ibin, const char *rangeName=0)
Set value to center of bin 'ibin' of binning 'rangeName' (or of default binning if no range is specif...
virtual void setVal(Double_t value)=0
Set the current value of the object. Needs to be overridden by implementations.
virtual Int_t numBins(const char *rangeName=0) const
virtual Bool_t readFromStream(std::istream &is, Bool_t compact, Bool_t verbose=kFALSE)
Read object contents from given stream.
virtual void randomize(const char *rangeName=0)
Set a new value sampled from a uniform distribution over the fit range.
RooPlot * frame() const
Create a new RooPlot on the heap with a drawing frame initialized for this object,...
virtual void writeToStream(std::ostream &os, Bool_t compact) const
Write object contents to given stream.
virtual Bool_t inRange(const char *name) const
Check if current value is inside range with given name.
virtual Bool_t isJacobianOK(const RooArgSet &depList) const
virtual Int_t getBins(const char *name=0) const
Get number of bins of currently defined range.
virtual void setValFast(Double_t value)
RooAbsRealLValue & operator=(const RooAbsRealLValue &)=default
Bool_t hasMin(const char *name=0) const
Check if variable has a lower bound.
virtual ~RooAbsRealLValue()
Destructor.
virtual Double_t getMin(const char *name=0) const
Get miniminum of currently defined range.
TH1 * createHistogram(const char *name, const RooCmdArg &arg1=RooCmdArg::none(), const RooCmdArg &arg2=RooCmdArg::none(), const RooCmdArg &arg3=RooCmdArg::none(), const RooCmdArg &arg4=RooCmdArg::none(), const RooCmdArg &arg5=RooCmdArg::none(), const RooCmdArg &arg6=RooCmdArg::none(), const RooCmdArg &arg7=RooCmdArg::none(), const RooCmdArg &arg8=RooCmdArg::none()) const
Bool_t fitRangeOKForPlotting() const
Check if fit range is usable as plot range, i.e.
virtual void setBinFast(Int_t ibin, const RooAbsBinning &binning)
Set value to center of bin 'ibin' of binning 'rangeName' (or of default binning if no range is specif...
RooAbsReal is the common abstract base class for objects that represent a real value and implements f...
Definition: RooAbsReal.h:61
TString getTitle(Bool_t appendUnit=kFALSE) const
Return this variable's title string.
Definition: RooAbsReal.cxx:257
virtual void copyCache(const RooAbsArg *source, Bool_t valueOnly=kFALSE, Bool_t setValDirty=kTRUE)
Copy the cached value of another RooAbsArg to our cache.
TString _unit
Definition: RooAbsReal.h:478
Double_t _value
Definition: RooAbsReal.h:477
virtual void printMultiline(std::ostream &os, Int_t contents, Bool_t verbose=kFALSE, TString indent="") const
Structure printing.
Definition: RooAbsReal.cxx:489
Double_t getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition: RooAbsReal.h:91
const Text_t * getUnit() const
Definition: RooAbsReal.h:146
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition: RooArgList.h:22
RooAbsArg * at(Int_t idx) const
Return object at given index, or nullptr if index is out of range.
Definition: RooArgList.h:110
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition: RooArgSet.h:35
RooCmdArg is a named container for two doubles, two integers two object points and three string point...
Definition: RooCmdArg.h:27
Class RooCmdConfig is a configurable parser for RooCmdArg named arguments.
Definition: RooCmdConfig.h:27
RooLinkedList is an collection class for internal use, storing a collection of RooAbsArg pointers in ...
Definition: RooLinkedList.h:38
virtual void Add(TObject *arg)
Definition: RooLinkedList.h:67
static Int_t isInfinite(Double_t x)
Return true if x is infinite by RooNumBer internal specification.
Definition: RooNumber.cxx:58
A RooPlot is a plot frame and a container for graphics objects within that frame.
Definition: RooPlot.h:44
void SetTitle(const char *name)
Set the title of the RooPlot to 'title'.
Definition: RooPlot.cxx:1251
void SetName(const char *name)
Set the name of the RooPlot to 'name'.
Definition: RooPlot.cxx:1229
static Double_t uniform(TRandom *generator=randomGenerator())
Return a number uniformly distributed from (0,1)
Definition: RooRandom.cxx:83
RooRealVar represents a variable that can be changed from the outside.
Definition: RooRealVar.h:39
RooUniformBinning is an implementation of RooAbsBinning that provides a uniform binning in 'n' bins b...
1-D histogram with a float per channel (see TH1 documentation)}
Definition: TH1.h:575
TH1 is the base class of all histogram classes in ROOT.
Definition: TH1.h:58
virtual void SetXTitle(const char *title)
Definition: TH1.h:413
virtual void SetZTitle(const char *title)
Definition: TH1.h:415
virtual void SetYTitle(const char *title)
Definition: TH1.h:414
2-D histogram with a float per channel (see TH1 documentation)}
Definition: TH2.h:251
3-D histogram with a float per channel (see TH1 documentation)}
Definition: TH3.h:268
TString fName
Definition: TNamed.h:32
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Mother of all ROOT objects.
Definition: TObject.h:37
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:130
Basic string class.
Definition: TString.h:136
const char * Data() const
Definition: TString.h:369
TString & Prepend(const char *cs)
Definition: TString.h:661
Bool_t IsNull() const
Definition: TString.h:407
TString & Append(const char *cs)
Definition: TString.h:564
VecExpr< UnaryOp< Fabs< T >, VecExpr< A, T, D >, T >, T, D > fabs(const VecExpr< A, T, D > &rhs)
std::vector< std::string > Split(std::string_view str, std::string_view delims, bool skipEmpty=false)
Splits a string at each character in delims.
Definition: StringUtils.cxx:23
@ Generation
Definition: RooGlobalFunc.h:60
@ InputArguments
Definition: RooGlobalFunc.h:61
static constexpr double pc
auto * l
Definition: textangle.C:4
REAL epsilon
Definition: triangle.c:618