Mantid
Loading...
Searching...
No Matches
GSLFunctions.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
13
15
16namespace Mantid::CurveFitting {
17
18namespace {
19double leastSquaresLoss(const std::shared_ptr<API::FunctionValues> &values, const size_t index) {
20 return (values->getCalculated(index) - values->getFitData(index)) * values->getFitWeight(index);
21}
22
23double poissonLoss(const std::shared_ptr<API::FunctionValues> &values, const size_t index) {
24 return CostFunctions::PoissonLossLM::calculatePoissonLossLM(values->getFitData(index), values->getCalculated(index));
25}
26
27double leastSquaresWeight(const std::shared_ptr<API::FunctionValues> &values, const size_t index) {
28 return values->getFitWeight(index);
29}
30
31double poissonWeight(const std::shared_ptr<API::FunctionValues> &values, const size_t index) {
33 values->getCalculated(index));
34}
35} // namespace
36
43int gsl_f(const gsl_vector *x, void *params, gsl_vector *f) {
44 assert(x->data);
45 auto *p = reinterpret_cast<struct GSL_FitData *>(params);
46
47 // update function parameters
48 size_t ia = 0;
49 for (size_t i = 0; i < p->function->nParams(); ++i) {
50 if (p->function->isActive(i)) {
51 if (ia < x->size) {
52 p->function->setActiveParameter(i, x->data[ia]);
53 ++ia;
54 } else {
55 // The number of active parameters now exceeds the space
56 // originally allocated
58 }
59 }
60 }
61 p->function->applyTies();
62
63 auto values = std::dynamic_pointer_cast<API::FunctionValues>(p->costFunction->getValues());
64 if (!values) {
65 throw std::invalid_argument("FunctionValues expected");
66 }
67 p->function->function(*p->costFunction->getDomain(), *values);
68
69 // Add penalty
70 double penalty = 0.;
71 for (size_t i = 0; i < p->function->nParams(); ++i) {
72 API::IConstraint *c = p->function->getConstraint(i);
73 if (c) {
74 penalty += c->checkDeriv();
75 }
76 }
77
78 size_t n = values->size() - 1;
79 // add penalty to first and last point and every 10th point in between
80 if (penalty != 0.0) {
81 values->addToCalculated(0, penalty);
82 values->addToCalculated(n, penalty);
83
84 for (size_t i = 9; i < n; i += 10) {
85 values->addToCalculated(i, penalty);
86 }
87 }
88
89 // function() return calculated data values. Need to convert this values into
90 // calculated-observed divided by error values used by GSL
91
92 for (size_t i = 0; i < p->n; i++) {
93 f->data[i] = p->m_loss(values, i);
94 }
95 return GSL_SUCCESS;
96}
97
105int gsl_df(const gsl_vector *x, void *params, gsl_matrix *J) {
106
107 auto *p = reinterpret_cast<struct GSL_FitData *>(params);
108 std::unique_ptr<gsl_matrix, decltype(&gsl_matrix_free)> J_tr(gsl_matrix_calloc(J->size2, J->size1), gsl_matrix_free);
109 gsl_matrix_transpose_memcpy(J_tr.get(), J);
110 EigenMatrix m(J_tr->size2, J_tr->size1);
111 p->J.setJ(&m);
112
113 // update function parameters
114 if (x->data) {
115 size_t ia = 0;
116 for (size_t i = 0; i < p->function->nParams(); ++i) {
117 if (p->function->isActive(i)) {
118 p->function->setActiveParameter(i, x->data[ia]);
119 ++ia;
120 }
121 }
122 }
123 p->function->applyTies();
124
125 // calculate the Jacobian
126 p->function->functionDeriv(*p->costFunction->getDomain(), p->J);
127
128 // p->function->addPenaltyDeriv(&p->J);
129 // add penalty
130 size_t n = p->costFunction->getValues()->size() - 1;
131 size_t ia = 0;
132 for (size_t i = 0; i < p->function->nParams(); ++i) {
133 if (!p->function->isActive(i))
134 continue;
135 API::IConstraint *c = p->function->getConstraint(i);
136 if (c) {
137 double penalty = c->checkDeriv2();
138 if (penalty != 0.0) {
139 double deriv = p->J.get(0, ia);
140 p->J.set(0, ia, deriv + penalty);
141 deriv = p->J.get(n, ia);
142 p->J.set(n, ia, deriv + penalty);
143
144 for (size_t j = 9; j < n; j += 10) {
145 deriv = p->J.get(j, ia);
146 p->J.set(j, ia, deriv + penalty);
147 }
148 }
149 } // if (c)
150 ++ia;
151 }
152
153 // functionDeriv() return derivatives of calculated data values. Need to
154 // convert this values into
155 // derivatives of calculated-observed divided by error values used by GSL
156 auto values = std::dynamic_pointer_cast<API::FunctionValues>(p->costFunction->getValues());
157 if (!values) {
158 throw std::invalid_argument("FunctionValues expected");
159 }
160
161 EigenMatrix m_tr = m.tr();
162 std::copy(&m_tr.mutator().data()[0], &m_tr.mutator().data()[J_tr->size1 * J_tr->size2], &J->data[0]);
163 for (size_t iY = 0; iY < p->n; iY++) {
164 const double weight = p->m_scaleFactor(values, iY);
165 for (size_t iP = 0; iP < p->p; iP++) {
166 J->data[iY * p->p + iP] *= weight;
167 }
168 }
169
170 return GSL_SUCCESS;
171}
172
180int gsl_fdf(const gsl_vector *x, void *params, gsl_vector *f, gsl_matrix *J) {
181 gsl_f(x, params, f);
182 gsl_df(x, params, J);
183 return GSL_SUCCESS;
184}
185
190GSL_FitData::GSL_FitData(const std::shared_ptr<CostFunctions::CostFuncFitting> &cf)
191 : function(cf->getFittingFunction()), costFunction(cf) {
192 gsl_set_error_handler_off();
193
194 if (std::dynamic_pointer_cast<CostFunctions::CostFuncPoisson>(cf)) {
195 this->m_loss = &poissonLoss;
196 this->m_scaleFactor = &poissonWeight;
197 } else {
198 this->m_loss = &leastSquaresLoss;
199 this->m_scaleFactor = &leastSquaresWeight;
200 }
201
202 // number of active parameters
203 p = 0;
204 for (size_t i = 0; i < function->nParams(); ++i) {
205 if (function->isActive(i))
206 ++p;
207 }
208
209 // number of fitting data
210 n = cf->getValues()->size();
211
212 bool functionFixed = false;
213 if (p == 0) {
214 p = 1;
215 functionFixed = true;
216 }
217
218 // holdCalculatedJacobian = gsl_matrix_alloc (n, p);
219
220 initFuncParams = gsl_vector_alloc(p);
221
222 if (functionFixed) {
223 gsl_vector_set(initFuncParams, 0, 0.0);
224 } else {
225 size_t ia = 0;
226 for (size_t i = 0; i < function->nParams(); ++i) {
227 if (function->isActive(i)) {
228 gsl_vector_set(initFuncParams, ia, function->activeParameter(i));
229 ++ia;
230 }
231 }
232 }
233
234 int j = 0;
235 for (size_t i = 0; i < function->nParams(); ++i) {
236 if (function->isActive(i)) {
237 J.m_index.emplace_back(j);
238 j++;
239 } else
240 J.m_index.emplace_back(-1);
241 }
242}
243
245 // gsl_matrix_free(holdCalculatedJacobian);
246 gsl_vector_free(initFuncParams);
247}
248
249} // namespace Mantid::CurveFitting
std::map< DeltaEMode::Type, std::string > index
An interface to a constraint.
Definition IConstraint.h:26
virtual double checkDeriv()=0
Returns the derivative of the penalty for each active parameter.
virtual double checkDeriv2()=0
Returns the derivative of the penalty for each active parameter.
A wrapper around Eigen::Matrix.
Definition EigenMatrix.h:33
EigenMatrix tr() const
Calculate the eigensystem of a symmetric matrix.
map_type & mutator()
Get the map to Eigen matrix.
Definition EigenMatrix.h:56
Exception thrown when a fitting function changes number of parameters during fit.
Definition Exception.h:336
double MANTID_CURVEFITTING_DLL calculateJacobianScaleFactor(double observedCounts, double predicted)
double MANTID_CURVEFITTING_DLL calculatePoissonLossLM(double observedCounts, double predicted)
int gsl_fdf(const gsl_vector *x, void *params, gsl_vector *f, gsl_matrix *J)
Fit derivatives and function GSL wrapper.
int gsl_f(const gsl_vector *x, void *params, gsl_vector *f)
Fit GSL function wrapper.
int gsl_df(const gsl_vector *x, void *params, gsl_matrix *J)
Fit GSL derivative function wrapper.
Various GSL specific functions used GSL specific minimizers.
size_t n
number of points to be fitted (size of X, Y and sqrtWeightData arrays)
double(* m_loss)(const std::shared_ptr< API::FunctionValues > &values, size_t index)
GSL_FitData(const std::shared_ptr< CostFunctions::CostFuncFitting > &cf)
Constructor.
double(* m_scaleFactor)(const std::shared_ptr< API::FunctionValues > &values, size_t index)
API::IFunction_sptr function
Pointer to the function.
size_t p
number of (active) fit parameters
JacobianImpl1< EigenMatrix > J
Jacobi matrix interface.
gsl_vector * initFuncParams
Initial function parameters.