Logo ROOT   6.12/07
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"
15 #include "Math/WrappedFunction.h"
16 #include "Math/WrappedTF1.h"
17 
19 
20 /** \class TF1NormSum
21  \ingroup Hist
22 Class adding two functions: c1*f1+c2*f2
23 */
24 
25 ////////////////////////////////////////////////////////////////////////////////
26 /// Function to find and rename duplicate parameters with the same name
27 
28 template<class Iterator>
29 void 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 
54 void 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 
76  fFunctions[n]->SetBit(TF1::kNotGlobal, kTRUE);
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 
123  FixDuplicateNames(fParNames.begin() + fNOfFunctions, fParNames.end());
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 
141 TF1NormSum::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 
149 TF1NormSum::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 
163 TF1NormSum::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 
271 double TF1NormSum::operator()(const Double_t *x, const Double_t *p)
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 
288 std::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 
312 void 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 
408 void 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 }
void InitializeDataMembers(const std::vector< TF1 *> &functions, const std::vector< Double_t > &coeffs, Double_t scale)
Definition: TF1NormSum.cxx:54
static long int sum(long int i)
Definition: Factory.cxx:2173
An array of TObjects.
Definition: TObjArray.h:37
Int_t GetNpar() const
Return the number of (non constant) parameters including the coefficients: for 2 functions: c1...
Definition: TF1NormSum.cxx:360
float xmin
Definition: THbookFile.cxx:93
std::vector< TString > fParNames
Parameter names.
Definition: TF1NormSum.h:29
static double p3(double t, double a, double b, double c, double d)
Collectable string class.
Definition: TObjString.h:28
const char * GetParName(Int_t ipar) const
Definition: TF1NormSum.h:66
#define gROOT
Definition: TROOT.h:402
Basic string class.
Definition: TString.h:125
int Int_t
Definition: RtypesCore.h:41
unsigned int fNOfFunctions
Number of functions to add.
Definition: TF1NormSum.h:22
Double_t x[n]
Definition: legend1.C:17
std::vector< Int_t > fCstIndexes
Vector with size of fNOfFunctions containing the index of the constant parameter/ function (the remov...
Definition: TF1NormSum.h:28
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:2365
static double p2(double t, double a, double b, double c)
void SetRange(Double_t a, Double_t b)
Definition: TF1NormSum.cxx:373
void FixDuplicateNames(Iterator begin, Iterator end)
Function to find and rename duplicate parameters with the same name.
Definition: TF1NormSum.cxx:29
auto * a
Definition: textangle.C:12
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
Double_t fXmin
Definition: TF1NormSum.h:24
double operator()(const Double_t *x, const Double_t *p)
Overload the parenthesis to add the functions.
Definition: TF1NormSum.cxx:271
Class adding two functions: c1*f1+c2*f2.
Definition: TF1NormSum.h:19
static void InitStandardFunctions()
Create the basic function objects.
Definition: TF1.cxx:2369
static double p1(double t, double a, double b)
float xmax
Definition: THbookFile.cxx:93
void Update()
Update the component functions of the normalized sum.
Definition: TF1NormSum.cxx:400
std::vector< Double_t > fCoeffs
Vector of size afNOfFunctions containing coefficients in front of each function.
Definition: TF1NormSum.h:27
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2251
void GetRange(Double_t &a, Double_t &b) const
Definition: TF1NormSum.cxx:391
#define ClassImp(name)
Definition: Rtypes.h:359
double Double_t
Definition: RtypesCore.h:55
Double_t fScale
Fixed Scale parameter to normalize function (e.g. bin width)
Definition: TF1NormSum.h:23
std::vector< double > GetParameters() const
Return array of parameters.
Definition: TF1NormSum.cxx:288
TF1NormSum & operator=(const TF1NormSum &rhs)
Operator =.
Definition: TF1NormSum.cxx:261
void Copy(TObject &obj) const
Copy this to obj.
Definition: TF1NormSum.cxx:408
void SetParameters(const Double_t *params)
Initialize array of all parameters.
Definition: TF1NormSum.cxx:312
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
std::vector< std::unique_ptr< TF1 > > fFunctions
Maximal bound of range of NormSum.
Definition: TF1NormSum.h:26
1-Dim function class
Definition: TF1.h:211
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
Definition: TRolke.cxx:630
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:908
Double_t fXmax
Minimal bound of range of NormSum.
Definition: TF1NormSum.h:25
const Bool_t kTRUE
Definition: RtypesCore.h:87
const Int_t n
Definition: legend1.C:16
char name[80]
Definition: TGX11.cxx:109
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
const char * Data() const
Definition: TString.h:345