Logo ROOT   6.16/01
Reference Guide
TF1NormSum.cxx
Go to the documentation of this file.
1// @(#)root/hist:$Id$
2// Authors: Lorenzo Moneta, Aurélie Flandi 27/08/14
3//
4/**********************************************************************
5 * *
6 * Copyright (c) 2015 ROOT Team, CERN/PH-SFT *
7 * *
8 * *
9 **********************************************************************/
10
11#include "TROOT.h"
12#include "TClass.h"
13#include "TMath.h"
14#include "TF1NormSum.h"
16#include "Math/WrappedTF1.h"
17
19
20/** \class TF1NormSum
21 \ingroup Hist
22Class adding two functions: c1*f1+c2*f2
23*/
24
25////////////////////////////////////////////////////////////////////////////////
26/// Function to find and rename duplicate parameters with the same name
27
28template<class Iterator>
29void FixDuplicateNames(Iterator begin, Iterator end) {
30
31 // make a map of values
32
33 std::multimap<TString, int > parMap;
34 for (Iterator it = begin; it != end; ++it) {
35 parMap.insert( std::make_pair( *it, std::distance(begin,it) ) );
36 }
37 for ( auto & elem : parMap) {
38 TString name = elem.first;
39 int n = parMap.count( name);
40 if (n > 1 ) {
41 std::pair <std::multimap<TString,int>::iterator, std::multimap<TString,int>::iterator> ret;
42 ret = parMap.equal_range(name);
43 int i = 0;
44 for (std::multimap<TString,int>::iterator it=ret.first; it!=ret.second; ++it) {
45 *(begin+it->second) = TString::Format("%s%d",name.Data(),++i);
46 }
47 }
48 }
49
50}
51
52////////////////////////////////////////////////////////////////////////////////
53
54void TF1NormSum::InitializeDataMembers(const std::vector<TF1 *> &functions, const std::vector<Double_t> &coeffs,
55 Double_t scale)
56{
57
58 fScale = scale;
59 fCoeffs = coeffs;
60 fNOfFunctions = functions.size();
61 fCstIndexes = std::vector < Int_t > (fNOfFunctions);
62 fParNames = std::vector<TString> (fNOfFunctions);
63 fParNames.reserve(3*fNOfFunctions); // enlarge capacity for function parameters
64
65 // fill fFunctions with unique_ptr's
66 fFunctions = std::vector<std::unique_ptr<TF1>>(functions.size());
67 for (unsigned int n = 0; n < fNOfFunctions; n++) {
68 TF1 *f = new TF1();
69 functions[n]->Copy(*f);
70 fFunctions[n] = std::unique_ptr<TF1>(f);
71 // Use Copy, not Clone
72
73 if (!fFunctions[n])
74 Fatal("InitializeDataMembers", "Invalid input function -- abort");
75
77 }
78
79 for (unsigned int n=0; n < fNOfFunctions; n++)
80 {
81 int npar = fFunctions[n] -> GetNpar();
82 fCstIndexes[n] = fFunctions[n] -> GetParNumber("Constant");//return -1 if there is no constant parameter
83 fParNames[n] = TString::Format("Coeff%d",n);
84 if (fCstIndexes[n]!= -1) //if there exists a constant parameter
85 {
86 fFunctions[n] -> FixParameter(fCstIndexes[n], 1.); // fixes the parameters called "Constant" to 1
87 int k = 0; // index for the temp array, k wil go form 0 until fNofNonCstParameter
88 for (int i=0; i<npar; i++) // go through all the parameter to
89 {
90 if (i==fCstIndexes[n]) continue; // go to next step if this is the constant parameter
91 fParNames.push_back( fFunctions[n] -> GetParName(i) );
92 k++;
93 }
94 }
95 else {
96 for (int i=0; i < npar; i++) //go through all the parameter to
97 {
98 fParNames.push_back( fFunctions[n] -> GetParName(i) );
99 }
100 }
101 //normalize the functions if it is not already done (do at the end so constant parameter is not zero)
102 if (!fFunctions[n] -> IsEvalNormalized()) fFunctions[n] -> SetNormalized(true);
103 }
104
105 // Set range
106 if (fNOfFunctions == 0) {
107 fXmin = 0.;
108 fXmax = 1.;
109 // Info("InitializeDataMembers", "Initializing empty TF1NormSum with default [0,1] range");
110 } else {
111 fFunctions[0]->GetRange(fXmin, fXmax);
112 if (fXmin >= fXmax) {
113 fXmin = 0.;
114 fXmax = 1.;
115 // Info("InitializeDataMembers", "Initializing empty TF1NormSum with default [0,1] range");
116 }
117 for (unsigned int n = 1; n < fNOfFunctions; n++) {
118 fFunctions[n]->SetRange(fXmin, fXmax);
119 fFunctions[n]->Update();
120 }
121 }
122
124}
125
126////////////////////////////////////////////////////////////////////////////////
127
129{
130 fNOfFunctions = 0;
131 fScale = 1.;
132 fFunctions = std::vector<std::unique_ptr<TF1>>(0); // Vector of size fNOfFunctions containing TF1 functions
133 fCoeffs = std::vector < Double_t >(0) ; // Vector of size fNOfFunctions containing coefficients in front of each function
134 fCstIndexes = std::vector < Int_t > (0);
135 fXmin = 0; // Dummy values of xmin and xmax
136 fXmax = 1;
137}
138
139////////////////////////////////////////////////////////////////////////////////
140
141TF1NormSum::TF1NormSum(const std::vector <TF1*> &functions, const std::vector <Double_t> &coeffs, Double_t scale)
142{
143 InitializeDataMembers(functions, coeffs, scale);
144}
145
146////////////////////////////////////////////////////////////////////////////////
147/// TF1NormSum constructor taking 2 functions, and 2 coefficients (if not equal to 1)
148
149TF1NormSum::TF1NormSum(TF1* function1, TF1* function2, Double_t coeff1, Double_t coeff2, Double_t scale)
150{
151 std::vector<TF1 *> functions(2);
152 std::vector < Double_t > coeffs(2);
153
154 functions = {function1, function2};
155 coeffs = {coeff1, coeff2};
156
157 InitializeDataMembers(functions, coeffs,scale);
158}
159
160////////////////////////////////////////////////////////////////////////////////
161/// TF1NormSum constructor taking 3 functions, and 3 coefficients (if not equal to 1)
162
163TF1NormSum::TF1NormSum(TF1* function1, TF1* function2, TF1* function3, Double_t coeff1, Double_t coeff2, Double_t coeff3, Double_t scale)
164{
165 std::vector<TF1 *> functions(3);
166 std::vector < Double_t > coeffs(3);
167
168 functions = {function1, function2, function3};
169 coeffs = {coeff1, coeff2, coeff3};
170
171 InitializeDataMembers(functions, coeffs,scale);
172}
173
174////////////////////////////////////////////////////////////////////////////////
175/// TF1NormSum constructor taking any addition of formulas with coefficient or not
176///
177/// - example 1 : 2.*expo + gauss + 0.5* gauss
178/// - example 2 : expo + 0.3*f1 if f1 is defined in the list of functions
179
181{
183
184 TObjArray *arrayall = formula.Tokenize("*+");
185 TObjArray *arraytimes = formula.Tokenize("*") ;
186 Int_t noffunctions = (formula.Tokenize("+")) -> GetEntries();
187 Int_t nofobj = arrayall -> GetEntries();
188 Int_t nofcoeffs = nofobj - noffunctions;
189
190 std::vector<TF1 *> functions(noffunctions);
191 std::vector < Double_t > coeffs(noffunctions);
192 std::vector < TString > funcstringall(nofobj);
193 std::vector < Int_t > indexsizetimes(nofcoeffs+1);
194 std::vector < Bool_t > isacoeff(nofobj);//1 is it is a coeff, 0 if it is a functions
195
196 for (int i=0; i<nofobj; i++)
197 {
198 funcstringall[i] = ((TObjString*)((*arrayall)[i])) -> GetString();
199 funcstringall[i].ReplaceAll(" ","");
200 }
201 //algorithm to determine which object is a coefficient and which is a function
202 //uses the fact that the last item of funcstringtimes[i].Tokenize("+") is always a coeff.
203 Int_t j = 0;
204 Int_t k = 1;
205 for (int i=0; i<nofcoeffs+1; i++)
206 {
207 indexsizetimes[i] = ( ( ( (TObjString*)(*arraytimes)[i] ) -> GetString() ).Tokenize("+") ) -> GetEntries();
208 while (k < indexsizetimes[i])
209 {
210 isacoeff[k+j-1] = 0;
211 k++;
212 }
213 j = j+indexsizetimes[i];
214 if (j==nofobj) isacoeff[j-1] = 0; //the last one is never a coeff
215 else isacoeff[j-1] = 1;
216 k = 1;
217 }
218
219 Double_t old_xmin = 0.0, old_xmax = 0.0;
220 k = 0; // index of term in funcstringall
221 for (int i=0; i<noffunctions; i++)
222 {
223 // first, handle coefficient
224 if (isacoeff[k]) {
225 coeffs[i] = funcstringall[k].Atof();
226 k++;
227 } else {
228 coeffs[i] = 1.;
229 }
230
231 // then, handle function
232 functions[i] = (TF1 *)(gROOT->GetListOfFunctions()->FindObject(funcstringall[k]));
233 if (!functions[i])
234 Error("TF1NormSum", "Function %s does not exist", funcstringall[k].Data());
235 // (set range for first function, which determines range of whole TF1NormSum)
236 if (i == 0) {
237 functions[i]->GetRange(old_xmin, old_xmax);
238 functions[i]->SetRange(xmin, xmax);
239 }
240
241 k++;
242 }
243 InitializeDataMembers(functions, coeffs,1.);
244
245 // Set range of first function back to original state
246 if (noffunctions > 0 && functions[0])
247 functions[0]->SetRange(old_xmin, old_xmax);
248}
249
250////////////////////////////////////////////////////////////////////////////////
251/// Copy constructor (necessary to hold unique_ptr as member variable)
252
254{
255 nsum.Copy((TObject &)*this);
256}
257
258////////////////////////////////////////////////////////////////////////////////
259/// Operator =
260
262{
263 if (this != &rhs)
264 rhs.Copy(*this);
265 return *this;
266}
267
268////////////////////////////////////////////////////////////////////////////////
269/// Overload the parenthesis to add the functions
270
272{
273 // first refresh the parameters
274 if (p != 0)
275 SetParameters(p);
276
277 Double_t sum = 0.;
278 for (unsigned int n=0; n<fNOfFunctions; n++)
279 sum += fCoeffs[n]*(fFunctions[n] -> EvalPar(x,0));
280
281 // normalize by a scale parameter (typically the bin width)
282 return fScale * sum;
283}
284
285////////////////////////////////////////////////////////////////////////////////
286/// Return array of parameters
287
288std::vector<double> TF1NormSum::GetParameters() const {
289 std::vector<double> params(GetNpar() );
290 int offset = 0;
291 int nOfNonCstParams = 0;
292 for (unsigned int n=0; n<fNOfFunctions; n++)
293 {
294 params[n] = fCoeffs[n]; // copy the coefficients
295 offset += nOfNonCstParams; // offset to go along the list of parameters
296 int k = 0;
297 for (int j = 0; j < fFunctions[n]->GetNpar(); ++j) {
298 if (j != fCstIndexes[n]) {
299 params[k+fNOfFunctions+offset] = fFunctions[n]->GetParameter(j);
300 k++;
301 }
302 }
303 nOfNonCstParams = k;
304 }
305 return params;
306}
307////////////////////////////////////////////////////////////////////////////////
308/// Initialize array of all parameters.
309///
310/// double *params must contains first an array of the coefficients, then an array of the parameters.
311
312void TF1NormSum::SetParameters(const Double_t *params) // params should have the size [fNOfFunctions][fNOfNonCstParams]
313{
314 for (unsigned int n=0; n<fNOfFunctions; n++) //initialization of the coefficients
315 {
316 fCoeffs[n] = params[n];
317 }
318 Int_t offset = 0;
319 int k = 0; // k indicates the number of non-constant parameter per function
320 for (unsigned int n=0; n<fNOfFunctions; n++)
321 {
322 bool equalParams = true;
323 Double_t * funcParams = fFunctions[n]->GetParameters();
324 int npar = fFunctions[n]->GetNpar();
325 offset += k; // offset to go along the list of parameters
326 k = 0; // reset k value for next function
327 for (int i = 0; i < npar; ++i) {
328 // constant parameters can be only one
329 if (i != fCstIndexes[n])
330 {
331 // check if they are equal
332 equalParams &= (funcParams[i] == params[k+fNOfFunctions+offset] );
333 funcParams[i] = params[k+fNOfFunctions+offset];
334 k++;
335 }
336 }
337 // update function integral if not equal
338 if (!equalParams) fFunctions[n]->Update();
339
340 }
341}
342
343////////////////////////////////////////////////////////////////////////////////
344/// Initialize array of all parameters.
345///
346/// Overload the TF1::SetParameters() method.
347/// A maximum of 10 parameters must be used, with first the coefficients, then the parameters
348
350 Double_t p5, Double_t p6, Double_t p7, Double_t p8, Double_t p9, Double_t p10)
351{
352 const double params[] = {p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10};
354
355}
356
357////////////////////////////////////////////////////////////////////////////////
358/// Return the number of (non constant) parameters including the coefficients: for 2 functions: c1,c2,p0,p1,p2,p3...
359
361{
362 Int_t nofparams = 0;
363 for (unsigned int n=0; n<fNOfFunctions; ++n)
364 {
365 nofparams += fFunctions[n]->GetNpar();
366 if (fCstIndexes[n] >= 0) nofparams -= 1;
367 }
368 return nofparams + fNOfFunctions; //fNOfFunctions for the coefficients
369}
370
371////////////////////////////////////////////////////////////////////////////////
372
374{
375 if (a >= b) {
376 Warning("SetRange", "Invalid range: %f >= %f", a, b);
377 return;
378 }
379
380 fXmin = a;
381 fXmax = b;
382
383 for (unsigned int n = 0; n < fNOfFunctions; n++) {
384 fFunctions[n]->SetRange(a, b);
385 fFunctions[n]->Update();
386 }
387}
388
389////////////////////////////////////////////////////////////////////////////////
390
392{
393 a = fXmin;
394 b = fXmax;
395}
396
397////////////////////////////////////////////////////////////////////////////////
398/// Update the component functions of the normalized sum
399
401{
402 for (unsigned int n = 0; n < fNOfFunctions; n++)
403 fFunctions[n]->Update();
404}
405
406////////////////////////////////////////////////////////////////////////////////
407
408void TF1NormSum::Copy(TObject &obj) const
409{
410 ((TF1NormSum &)obj).fNOfFunctions = fNOfFunctions;
411 ((TF1NormSum &)obj).fScale = fScale;
412 ((TF1NormSum &)obj).fXmin = fXmin;
413 ((TF1NormSum &)obj).fXmax = fXmax;
414 ((TF1NormSum &)obj).fCoeffs = fCoeffs;
415 ((TF1NormSum &)obj).fCstIndexes = fCstIndexes;
416 ((TF1NormSum &)obj).fParNames = fParNames;
417
418 // Clone objects in unique_ptr's
419 ((TF1NormSum &)obj).fFunctions = std::vector<std::unique_ptr<TF1>>(fNOfFunctions);
420 for (unsigned int n = 0; n < fNOfFunctions; n++) {
421 ((TF1NormSum &)obj).fFunctions[n] = std::unique_ptr<TF1>((TF1 *)fFunctions[n]->Clone());
422 }
423}
#define b(i)
Definition: RSha256.hxx:100
#define f(i)
Definition: RSha256.hxx:104
static double p3(double t, double a, double b, double c, double d)
static double p1(double t, double a, double b)
static double p2(double t, double a, double b, double c)
int Int_t
Definition: RtypesCore.h:41
double Double_t
Definition: RtypesCore.h:55
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define ClassImp(name)
Definition: Rtypes.h:363
void FixDuplicateNames(Iterator begin, Iterator end)
Function to find and rename duplicate parameters with the same name.
Definition: TF1NormSum.cxx:29
float xmin
Definition: THbookFile.cxx:93
float xmax
Definition: THbookFile.cxx:93
#define gROOT
Definition: TROOT.h:410
Class adding two functions: c1*f1+c2*f2.
Definition: TF1NormSum.h:19
Double_t fScale
Fixed Scale parameter to normalize function (e.g. bin width)
Definition: TF1NormSum.h:23
const char * GetParName(Int_t ipar) const
Definition: TF1NormSum.h:66
void GetRange(Double_t &a, Double_t &b) const
Definition: TF1NormSum.cxx:391
TF1NormSum & operator=(const TF1NormSum &rhs)
Operator =.
Definition: TF1NormSum.cxx:261
Double_t fXmax
Minimal bound of range of NormSum.
Definition: TF1NormSum.h:25
std::vector< TString > fParNames
Parameter names.
Definition: TF1NormSum.h:29
void SetParameters(const Double_t *params)
Initialize array of all parameters.
Definition: TF1NormSum.cxx:312
Double_t fXmin
Definition: TF1NormSum.h:24
std::vector< double > GetParameters() const
Return array of parameters.
Definition: TF1NormSum.cxx:288
std::vector< std::unique_ptr< TF1 > > fFunctions
Maximal bound of range of NormSum.
Definition: TF1NormSum.h:26
void InitializeDataMembers(const std::vector< TF1 * > &functions, const std::vector< Double_t > &coeffs, Double_t scale)
Definition: TF1NormSum.cxx:54
void Copy(TObject &obj) const
Copy this to obj.
Definition: TF1NormSum.cxx:408
std::vector< Double_t > fCoeffs
Vector of size afNOfFunctions containing coefficients in front of each function.
Definition: TF1NormSum.h:27
Int_t GetNpar() const
Return the number of (non constant) parameters including the coefficients: for 2 functions: c1,...
Definition: TF1NormSum.cxx:360
void Update()
Update the component functions of the normalized sum.
Definition: TF1NormSum.cxx:400
unsigned int fNOfFunctions
Number of functions to add.
Definition: TF1NormSum.h:22
double operator()(const Double_t *x, const Double_t *p)
Overload the parenthesis to add the functions.
Definition: TF1NormSum.cxx:271
void SetRange(Double_t a, Double_t b)
Definition: TF1NormSum.cxx:373
std::vector< Int_t > fCstIndexes
Vector with size of fNOfFunctions containing the index of the constant parameter/ function (the remov...
Definition: TF1NormSum.h:28
1-Dim function class
Definition: TF1.h:211
static void InitStandardFunctions()
Create the basic function objects.
Definition: TF1.cxx:2463
@ kNotGlobal
Definition: TF1.h:310
An array of TObjects.
Definition: TObjArray.h:37
Collectable string class.
Definition: TObjString.h:28
Mother of all ROOT objects.
Definition: TObject.h:37
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition: TObject.cxx:144
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:908
Basic string class.
Definition: TString.h:131
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2172
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition: TString.cxx:2286
Double_t x[n]
Definition: legend1.C:17
const Int_t n
Definition: legend1.C:16
auto * a
Definition: textangle.C:12
static long int sum(long int i)
Definition: Factory.cxx:2258