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