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