Belle II Software development
ChebFitter.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9
10#include <cmath>
11#include <iostream>
12#include <sstream>
13
14#include <Math/Minimizer.h>
15#include <Math/Factory.h>
16#include <Math/Functor.h>
17
18#include <Eigen/Core>
19
20//If compiled within BASF2
21#ifdef _PACKAGE_
22#include <reconstruction/calibration/BeamSpotBoostInvMass/ChebFitter.h>
23#include <reconstruction/calibration/BeamSpotBoostInvMass/nodes.h>
24#include <framework/logging/Logger.h>
25#else
26#include <ChebFitter.h>
27#include <nodes.h>
28#define B2INFO(arg) { std::cout << arg << std::endl;}
29#endif
30
31
32namespace Belle2 {
37
38 using Eigen::VectorXd;
39 using Eigen::MatrixXd;
40
41
42//return values of -2*log(p(x)), where p(x) is normalized to 1 over the fitted range
43 VectorXd ChebFitter::getLogFunction(Pars pars) const
44 {
45 VectorXd fVals(m_nodes.size());
46
47 //calc function values
48 fVals = m_nodes.unaryExpr([&](double x) { return m_myFun(x, pars); });
49
50 //normalize the function
51 double I = fVals.dot(m_weights);
52
53 fVals = -2 * log(fVals.array() / I); //normalize by integral
54
55 return fVals;
56
57 }
58
59 void ChebFitter::init(int Size, double xMin, double xMax)
60 {
61 // loading the Cheb nodes
62 m_nodes = (xMax - xMin) * getNodes(Size).array() + xMin;
63
64 // loading the weights for integration
65 m_weights = (xMax - xMin) * getWeights(Size);
66
67
68 // calculate the transformation matrix from pol coefs to grid points
69 m_coefsMat = getCoefsCheb(Size).transpose();
70
72
73 }
74
75//function assumed to be normalized !!!
76 double ChebFitter::getLogLikelihoodSlow(const Pars& pars) const
77 {
78
79 double L = 0;
80 for (double d : m_data) {
81 double v = m_myFun(d, pars);
82 L += -2 * log(v);
83 }
84
85 return L;
86 }
87
88//evaluation using cheb pols
89 double ChebFitter::getLogLikelihoodFast(const Pars& pars) const
90 {
91 VectorXd funVals = getLogFunction(pars);
92 double LL = funVals.dot(m_dataGrid);
93
94 return LL;
95 }
96
97 double ChebFitter::operator()(const double* par) const
98 {
99 Pars pars;
100 for (unsigned i = 0; i < m_parNames.size(); ++i)
101 pars[m_parNames[i]] = par[i];
102
103 double LL = m_useCheb ? getLogLikelihoodFast(pars) : getLogLikelihoodSlow(pars);
104
105 return LL;
106 }
107
108// get data transformed into the grid such that (chebFunVals dot m_dataGrid) == logL
109 VectorXd ChebFitter::getDataGrid() const
110 {
111 double a = m_nodes[0];
112 double b = m_nodes[m_nodes.size() - 1];
113
114
115 VectorXd polSum = VectorXd::Zero(m_nodes.size());
116 for (double x : m_data) {
117 double xx = (x - a) / (b - a); //normalize between 0 and 1
118 polSum += getPols(m_nodes.size(), xx);
119 }
120
121
122 //transform to the basis of the cheb m_nodes
123 VectorXd gridVals = m_coefsMat * polSum;
124
125 return gridVals;
126 }
127
128
129//Minimize using ROOT minimizer
130 std::pair<Pars, MatrixXd> ChebFitter::fitData(const Pars& pars, Limits limits, bool UseCheb)
131 {
132 m_useCheb = UseCheb;
133
134 ROOT::Math::Minimizer* minimum =
135 ROOT::Math::Factory::CreateMinimizer("Minuit2", "");
136
137 // set tolerance , etc...
138 minimum->SetMaxFunctionCalls(10000000); // for Minuit/Minuit2
139 minimum->SetMaxIterations(100000); // for GSL
140 minimum->SetTolerance(10.0);
141 //minimum->SetPrecision(1e-5);
142
143 //minimum->SetPrintLevel(3); //many outputs
144 minimum->SetPrintLevel(0); //few outputs
145 minimum->SetStrategy(2);
146 minimum->SetErrorDef(1);
147
148
149 // Set the free variables to be minimized !
150 m_parNames.clear();
151 int k = 0;
152 for (auto p : pars) {
153 std::string n = p.first;
154 double vCnt = p.second;
155 if (limits.count(n) == 1) {
156 double vMin = limits.at(n).first;
157 double vMax = limits.at(n).second;
158 double step = (vMax - vMin) / 100;
159 minimum->SetLimitedVariable(k, n, vCnt, step, vMin, vMax);
160 } else {
161 double step = 1;
162 minimum->SetVariable(k, n, vCnt, step);
163 }
164 m_parNames.push_back(n);
165 ++k;
166 }
167
168 // create function wrapper for minimizer
169 // a IMultiGenFunction type
170 ROOT::Math::Functor f(*this, pars.size());
171 minimum->SetFunction(f);
172
173
174 // do the minimization
175 minimum->Minimize();
176
177
178 Pars parsF;
179 for (unsigned i = 0; i < m_parNames.size(); ++i)
180 parsF[m_parNames[i]] = minimum->X()[i];
181
182 MatrixXd covMat(parsF.size(), parsF.size());
183 for (unsigned i = 0; i < parsF.size(); ++i)
184 for (unsigned j = 0; j < parsF.size(); ++j)
185 covMat(i, j) = minimum->CovMatrix(i, j);
186
187 // print pars
188 std::stringstream log;
189 log << "Minuit status : " << minimum->Status() << ", ";
190 for (auto p : parsF)
191 log << "\"" << p.first << "\" : " << p.second << ", ";
192
193 B2INFO(log.str());
194
195 delete minimum;
196
197 return std::make_pair(parsF, covMat);
198 }
199
201}
std::vector< double > m_data
vector with the data points to be fitted
Definition ChebFitter.h:71
bool m_useCheb
flag to use approximation based on Chebyshev polynomials
Definition ChebFitter.h:79
Eigen::VectorXd m_weights
vector with cheb weights for integration
Definition ChebFitter.h:76
std::vector< std::string > m_parNames
vector with names of the parameters
Definition ChebFitter.h:78
std::function< double(double, Pars)> m_myFun
function to fit
Definition ChebFitter.h:81
Eigen::VectorXd m_dataGrid
vector with the data points related to the cheb nodes (m_dataGrid.size = nodes.size)
Definition ChebFitter.h:72
Eigen::VectorXd m_nodes
vector with cheb nodes
Definition ChebFitter.h:75
Eigen::MatrixXd m_coefsMat
transformation matrix from chebPol to gridPoints
Definition ChebFitter.h:73
double operator()(const double *par) const
Evaluate the log likelihood.
Definition ChebFitter.cc:97
double getLogLikelihoodSlow(const Pars &pars) const
Calculate log likelihood using exact formula.
Definition ChebFitter.cc:76
Eigen::VectorXd getWeights(int Size)
Get the vector of weights to calculate the integral over the Chebyshev nodes The nodes are by definit...
Definition nodes.cc:29
void init(int Size, double xMin, double xMax)
Initialize the fitter (the Chebyshev coefficients)
Definition ChebFitter.cc:59
Eigen::VectorXd getPols(int Size, double x)
Evaluate Chebyshev polynomials up to Size at point x It returns a vector of the P_i(x) for i=0....
Definition nodes.cc:77
std::map< std::string, double > Pars
values of parameters in ML fit
Definition ChebFitter.h:25
Eigen::VectorXd getDataGrid() const
Calculate Chebyshev coefficients for the data set.
Eigen::VectorXd getLogFunction(Pars pars) const
Get the -2*log(p(x)) on the Cheb nodes.
Definition ChebFitter.cc:43
Eigen::MatrixXd getCoefsCheb(int oldSize)
Transformation matrix between Cheb nodes and Cheb coefficients with better normalization of the borde...
Definition nodes.cc:162
double getLogLikelihoodFast(const Pars &pars) const
Calculate log likelihood using approximation based on Chebyshev polynomials (typically faster)
Definition ChebFitter.cc:89
std::map< std::string, std::pair< double, double > > Limits
limits of parameters in ML fit
Definition ChebFitter.h:28
std::pair< Pars, Eigen::MatrixXd > fitData(const Pars &pars, Limits limits, bool UseCheb=true)
Fit the data with specified initial values of parameters and limits on them.
Eigen::VectorXd getNodes(int Size)
Get the vector of positions of the Chebyshev nodes The nodes are by definition between 0 and 1,...
Definition nodes.cc:65
Abstract base class for different kinds of events.