23 const double kEps = 1.0E-9;
28 ResidualFunctionAdapter::ResidualFunctionAdapter(fcn_residual_t func,
30 : m_datasize(0), m_fcn(func), m_parameters(parameters)
33 auto residuals = m_fcn(parameters);
34 m_datasize = residuals.size();
39 gradient_function_t gradient_fun = [&](
const std::vector<double>& pars,
unsigned int index,
40 std::vector<double>& gradients) {
41 return element_residual(pars, index, gradients);
44 scalar_function_t objective_fun = [&](
const std::vector<double>& pars) {
return chi2(pars); };
46 m_root_objective.reset(
49 return m_root_objective.get();
52 void ResidualFunctionAdapter::calculate_gradients(
const std::vector<double>& pars)
55 m_gradients.resize(pars.size());
56 for (
size_t i_par = 0; i_par < pars.size(); ++i_par)
57 m_gradients[i_par].resize(m_datasize, 0.0);
59 auto residuals = get_residuals(pars);
60 m_number_of_gradient_calls++;
62 for (
size_t i_par = 0; i_par < pars.size(); ++i_par) {
63 std::vector<double> pars_deriv = pars;
64 pars_deriv[i_par] += kEps;
66 auto residuals2 = get_residuals(pars_deriv);
68 for (
size_t i_data = 0; i_data < m_datasize; ++i_data)
69 m_gradients[i_par][i_data] = (residuals2[i_data] - residuals[i_data]) / kEps;
73 std::vector<double> ResidualFunctionAdapter::get_residuals(
const std::vector<double>& pars)
75 if (pars.size() != m_parameters.size()) {
76 std::ostringstream ostr;
77 ostr <<
"ResidualFunctionAdapter::residuals() -> Error. Number of fit parameters "
78 <<
"has changed in the course of minimization. Initially was " << m_parameters.size()
79 <<
" become " << pars.size() <<
"\n";
80 throw std::runtime_error(ostr.str());
83 m_parameters.setValues(pars);
84 auto result = m_fcn(m_parameters);
86 if (result.size() != m_datasize) {
87 std::ostringstream ostr;
88 ostr <<
"ResidualFunctionAdapter::residuals() -> Error. Size of data "
89 <<
"has changed in the course of minimization. Initial length " << m_datasize
90 <<
" new length " << result.size() <<
"\n";
91 throw std::runtime_error(ostr.str());
100 double ResidualFunctionAdapter::element_residual(
const std::vector<double>& pars,
101 unsigned int index, std::vector<double>& gradients)
104 m_residuals = get_residuals(pars);
107 if (!gradients.empty()) {
109 if (pars.size() != gradients.size())
110 throw std::runtime_error(
"ResidualFunctionAdapter::element_residual() -> Error. "
111 "Number of gradients doesn't match number of fit parameters.");
113 calculate_gradients(pars);
114 for (
size_t i_par = 0; i_par < pars.size(); ++i_par)
115 gradients[i_par] = m_gradients[i_par][index];
118 return m_residuals[index];
121 double ResidualFunctionAdapter::chi2(
const std::vector<double>& pars)
126 for (
auto x : get_residuals(pars))
129 int fnorm =
static_cast<int>(m_datasize) -
static_cast<int>(m_parameters.
freeParameterCount());
131 throw std::runtime_error(
"ResidualFunctionAdapter::chi2() -> Error. Normalization is 0");
133 return result / fnorm;
Defines class ResidualFunctionAdapter.
Declares class RootResidualFunction.
A collection of fit parameters.
size_t freeParameterCount() const
Returns number of free parameters.
Minimizer function with access to single data element residuals, required by Fumili2 and GSLMultiMin ...
Objective function types.