Mantid
Loading...
Searching...
No Matches
Fit1D.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//----------------------------------------------------------------------
11#include "MantidAPI/Axis.h"
13#include "MantidAPI/TableRow.h"
20
21#include <gsl/gsl_blas.h>
22#include <gsl/gsl_multifit_nlin.h>
23#include <gsl/gsl_multimin.h>
24#include <gsl/gsl_statistics.h>
25#include <gsl/gsl_version.h>
26
27#include <cmath>
28#include <numeric>
29#include <sstream>
30
32
33using namespace Kernel;
34using API::Jacobian;
35using API::MatrixWorkspace;
37using API::Progress;
38using API::WorkspaceProperty;
39
41class JacobianImpl : public Jacobian {
42public:
44 JacobianImpl() : Jacobian(), m_J(nullptr) {};
45
47 std::map<int, int> m_map;
54 void set(size_t iY, size_t iP, double value) override {
55 int j = m_map[static_cast<int>(iP)];
56 if (j >= 0)
57 gsl_matrix_set(m_J, iY, j, value);
58 }
64 double get(size_t iY, size_t iP) override {
65 int j = m_map[static_cast<int>(iP)];
66 if (j >= 0)
67 return gsl_matrix_get(m_J, iY, j);
68 return 0.0;
69 }
72 void zero() override { gsl_matrix_set_zero(m_J); }
74 void setJ(gsl_matrix *J) { m_J = J; }
75
76private:
78 gsl_matrix *m_J;
79};
80
82struct FitData {
84 FitData(Fit1D *fit, const std::string &fixed);
86 size_t n;
88 size_t p;
90 double *X;
92 const double *Y;
94 double *sigmaData;
102 double *parameters;
105 std::vector<bool> active;
108};
109
116static int gsl_f(const gsl_vector *x, void *params, gsl_vector *f) {
117 auto fitParams = static_cast<FitData *>(params);
118 for (size_t i = 0, j = 0; i < fitParams->active.size(); i++)
119 if (fitParams->active[i])
120 fitParams->parameters[i] = x->data[j++];
121
122 fitParams->fit1D->function(fitParams->parameters, f->data, fitParams->X, fitParams->n);
123
124 // function() return calculated data values. Need to convert this values into
125 // calculated-observed devided by error values used by GSL
126
127 for (size_t i = 0; i < fitParams->n; i++)
128 f->data[i] = (f->data[i] - fitParams->Y[i]) / fitParams->sigmaData[i];
129
130 return GSL_SUCCESS;
131}
132
139static int gsl_df(const gsl_vector *x, void *params, gsl_matrix *J) {
140 auto fitParams = static_cast<FitData *>(params);
141 for (size_t i = 0, j = 0; i < fitParams->active.size(); i++) {
142 if (fitParams->active[i])
143 fitParams->parameters[i] = x->data[j++];
144 }
145
146 fitParams->J.setJ(J);
147
148 fitParams->fit1D->functionDeriv(fitParams->parameters, &fitParams->J, fitParams->X, fitParams->n);
149
150 // functionDeriv() return derivatives of calculated data values. Need to
151 // convert this values into derivatives of calculated-observed devided
152 // by error values used by GSL
153
154 for (size_t iY = 0; iY < fitParams->n; iY++)
155 for (size_t iP = 0; iP < fitParams->p; iP++)
156 J->data[iY * fitParams->p + iP] /= fitParams->sigmaData[iY];
157
158 return GSL_SUCCESS;
159}
160
168static int gsl_fdf(const gsl_vector *x, void *params, gsl_vector *f, gsl_matrix *J) {
169 gsl_f(x, params, f);
170 gsl_df(x, params, J);
171 return GSL_SUCCESS;
172}
173
181static double gsl_costFunction(const gsl_vector *x, void *params) {
182 auto fitParams = static_cast<FitData *>(params);
183 double *l_forSimplexLSwrap = fitParams->forSimplexLSwrap;
184
185 for (size_t i = 0, j = 0; i < fitParams->active.size(); i++)
186 if (fitParams->active[i])
187 fitParams->parameters[i] = x->data[j++];
188
189 fitParams->fit1D->function(fitParams->parameters, l_forSimplexLSwrap, fitParams->X, fitParams->n);
190
191 // function() return calculated data values. Need to convert this values into
192 // calculated-observed devided by error values used by GSL
193 for (size_t i = 0; i < fitParams->n; i++)
194 l_forSimplexLSwrap[i] = (l_forSimplexLSwrap[i] - fitParams->Y[i]) / fitParams->sigmaData[i];
195
196 double retVal = 0.0;
197
198 for (unsigned int i = 0; i < fitParams->n; i++)
199 retVal += l_forSimplexLSwrap[i] * l_forSimplexLSwrap[i];
200
201 return retVal;
202}
203
218void Fit1D::functionDeriv(const double *in, Jacobian *out, const double *xValues, const size_t nData) {
219 UNUSED_ARG(in);
220 UNUSED_ARG(out);
221 UNUSED_ARG(xValues);
222 UNUSED_ARG(nData);
223 throw Exception::NotImplementedError("No derivative function provided");
224}
225
235void Fit1D::modifyInitialFittedParameters(std::vector<double> &fittedParameter) {
236 (void)fittedParameter; // Avoid compiler warning
237}
238
246void Fit1D::modifyFinalFittedParameters(std::vector<double> &fittedParameter) {
247 (void)fittedParameter; // Avoid compiler warning
248}
249
252void Fit1D::init() {
253 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
254 "Name of the input Workspace");
255
256 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
257 mustBePositive->setLower(0);
258 declareProperty("WorkspaceIndex", 0, mustBePositive,
259 "The Workspace to fit, uses the workspace numbering of the "
260 "spectra (default 0)");
261 declareProperty("StartX", EMPTY_DBL(),
262 "A value of x in, or on the low x "
263 "boundary of, the first bin to "
264 "include in\n"
265 "the fit (default lowest value of x)");
266 declareProperty("EndX", EMPTY_DBL(),
267 "A value in, or on the high x boundary "
268 "of, the last bin the fitting range\n"
269 "(default the highest value of x)");
270
271 size_t i0 = getProperties().size();
272
273 // declare parameters specific to a given fitting function
275
276 // load the name of these specific parameter into a vector for later use
277 const std::vector<Property *> props = getProperties();
278 for (size_t i = i0; i < props.size(); i++) {
279 m_parameterNames.emplace_back(props[i]->name());
280 }
281
282 declareProperty("Fix", "",
283 "A list of comma separated parameter names which "
284 "should be fixed in the fit");
285 declareProperty("MaxIterations", 500, mustBePositive,
286 "Stop after this number of iterations if a good fit is not found");
287 declareProperty("OutputStatus", "", Direction::Output);
288 declareProperty("OutputChi2overDoF", 0.0, Direction::Output);
289
290 // Disable default gsl error handler (which is to call abort!)
291 gsl_set_error_handler_off();
292
294
295 declareProperty("Output", "",
296 "If not empty OutputParameters TableWorksace "
297 "and OutputWorkspace will be created.");
298}
299
304void Fit1D::exec() {
305
306 // Custom initialization
307 prepare();
308
309 if (nParams() == 0) {
310 throw std::runtime_error("The fitting function has no parameters to fit. "
311 "Add at least one fitting parameter to the function, or use the "
312 "EvaluateFunction algorithm to calculate the function values.");
313 }
314
315 // check if derivative defined in derived class
316 bool isDerivDefined = true;
317 gsl_matrix *M = nullptr;
318 try {
319 const std::vector<double> inTest(m_parameterNames.size(), 1.0);
320 std::vector<double> outTest(m_parameterNames.size());
321 const double xValuesTest = 0;
322 JacobianImpl J;
323 M = gsl_matrix_alloc(m_parameterNames.size(), 1);
324 J.setJ(M);
325 // note nData set to zero (last argument) hence this should avoid further
326 // memory problems
327 functionDeriv(&(inTest.front()), &J, &xValuesTest, 0);
329 isDerivDefined = false;
330 }
331 gsl_matrix_free(M);
332
333 // Try to retrieve optional properties
334 int histNumber = getProperty("WorkspaceIndex");
335 const int maxInterations = getProperty("MaxIterations");
336
337 // Get the input workspace
338 MatrixWorkspace_const_sptr localworkspace = getProperty("InputWorkspace");
339
340 // number of histogram is equal to the number of spectra
341 const size_t numberOfSpectra = localworkspace->getNumberHistograms();
342 // Check that the index given is valid
343 if (histNumber >= static_cast<int>(numberOfSpectra)) {
344 g_log.warning("Invalid Workspace index given, using first Workspace");
345 histNumber = 0;
346 }
347
348 // Retrieve the spectrum into a vector
349 Mantid::HistogramData::HistogramX const &XValues = localworkspace->x(histNumber);
350 Mantid::HistogramData::HistogramY const &YValues = localworkspace->y(histNumber);
351 Mantid::HistogramData::HistogramE const &YErrors = localworkspace->e(histNumber);
352
353 // Read in the fitting range data that we were sent
354 double startX = getProperty("StartX");
355 double endX = getProperty("EndX");
356 // check if the values had been set, otherwise use defaults
357 if (isEmpty(startX)) {
358 startX = XValues.front();
359 modifyStartOfRange(startX); // does nothing by default but derived class may
360 // provide a more intelligent value
361 }
362 if (isEmpty(endX)) {
363 endX = XValues.back();
364 modifyEndOfRange(endX); // does nothing by default but derived class may
365 // previde a more intelligent value
366 }
367
368 int m_minX;
369 int m_maxX;
370
371 // Check the validity of startX
372 if (startX < XValues.front()) {
373 g_log.warning("StartX out of range! Set to start of frame.");
374 startX = XValues.front();
375 }
376 // Get the corresponding bin boundary that comes before (or coincides with)
377 // this value
378 for (m_minX = 0; XValues[m_minX + 1] < startX; ++m_minX) {
379 }
380
381 // Check the validity of endX and get the bin boundary that come after (or
382 // coincides with) it
383 if (endX >= XValues.back() || endX < startX) {
384 g_log.warning("EndX out of range! Set to end of frame");
385 endX = XValues.back();
386 m_maxX = static_cast<int>(YValues.size());
387 } else {
388 for (m_maxX = m_minX; XValues[m_maxX] < endX; ++m_maxX) {
389 }
390 }
391
392 afterDataRangedDetermined(m_minX, m_maxX);
393
394 // create and populate GSL data container warn user if l_data.n < l_data.p
395 // since as a rule of thumb this is required as a minimum to obtained
396 // 'accurate'
397 // fitting parameter values.
398
399 FitData l_data(this, getProperty("Fix"));
400
401 // The GSL solvers cannot be created for zero free parameters
402 if (l_data.p == 0) {
403 throw std::runtime_error("All parameters of the fitting function are fixed, there is nothing to fit. "
404 "Unfix at least one parameter, or use the EvaluateFunction algorithm to "
405 "calculate the function values.");
406 }
407
408 l_data.n = m_maxX - m_minX; // m_minX and m_maxX are array index markers. I.e. e.g. 0 & 19.
409 if (l_data.n == 0) {
410 g_log.error("The data set is empty.");
411 throw std::runtime_error("The data set is empty.");
412 }
413 if (l_data.n < l_data.p) {
414 g_log.error("Number of data points less than number of parameters to be fitted.");
415 throw std::runtime_error("Number of data points less than number of parameters to be fitted.");
416 }
417 l_data.X = new double[l_data.n];
418 l_data.sigmaData = new double[l_data.n];
419 l_data.forSimplexLSwrap = new double[l_data.n];
420 l_data.parameters = new double[nParams()];
421
422 // check if histogram data in which case use mid points of histogram bins
423
424 const bool isHistogram = localworkspace->isHistogramData();
425 for (unsigned int i = 0; i < l_data.n; ++i) {
426 if (isHistogram)
427 l_data.X[i] = 0.5 * (XValues[m_minX + i] + XValues[m_minX + i + 1]); // take mid-point if histogram bin
428 else
429 l_data.X[i] = XValues[m_minX + i];
430 }
431
432 l_data.Y = &YValues[m_minX];
433
434 // check that no error is negative or zero
435 for (unsigned int i = 0; i < l_data.n; ++i) {
436 if (YErrors[m_minX + i] <= 0.0) {
437 l_data.sigmaData[i] = 1.0;
438 } else
439 l_data.sigmaData[i] = YErrors[m_minX + i];
440 }
441
442 // create array of fitted parameter. Take these to those input by the user.
443 // However, for doing the
444 // underlying fitting it might be more efficient to actually perform the
445 // fitting on some of other
446 // form of the fitted parameters. For instance, take the Gaussian sigma
447 // parameter. In practice it
448 // in fact more efficient to perform the fitting not on sigma but 1/sigma^2.
449 // The methods
450 // modifyInitialFittedParameters() and modifyFinalFittedParameters() are used
451 // to allow for this;
452 // by default these function do nothing.
453
454 m_fittedParameter.clear();
455 for (size_t i = 0; i < nParams(); i++) {
457 }
458 modifyInitialFittedParameters(m_fittedParameter); // does nothing except if overwritten by derived class
459 for (size_t i = 0; i < nParams(); i++) {
460 l_data.parameters[i] = m_fittedParameter[i];
461 }
462
463 // set-up initial guess for fit parameters
464
465 gsl_vector *initFuncArg;
466 initFuncArg = gsl_vector_alloc(l_data.p);
467
468 for (size_t i = 0, j = 0; i < nParams(); i++) {
469 if (l_data.active[i])
470 gsl_vector_set(initFuncArg, j++, m_fittedParameter[i]);
471 }
472
473 // set-up GSL container to be used with GSL simplex algorithm
474
475 gsl_multimin_function gslSimplexContainer;
476 gslSimplexContainer.n = l_data.p; // n here refers to number of parameters
477 gslSimplexContainer.f = &gsl_costFunction;
478 gslSimplexContainer.params = &l_data;
479
480 // set-up GSL least squares container
481
482 gsl_multifit_function_fdf f;
483 f.f = &gsl_f;
484 f.df = &gsl_df;
485 f.fdf = &gsl_fdf;
486 f.n = l_data.n;
487 f.p = l_data.p;
488 f.params = &l_data;
489
490 // set-up remaining GSL machinery for least squared
491
492 const gsl_multifit_fdfsolver_type *T = gsl_multifit_fdfsolver_lmsder;
493 gsl_multifit_fdfsolver *s = nullptr;
494 if (isDerivDefined) {
495 s = gsl_multifit_fdfsolver_alloc(T, l_data.n, l_data.p);
496 gsl_multifit_fdfsolver_set(s, &f, initFuncArg);
497 }
498
499 // set-up remaining GSL machinery to use simplex algorithm
500
501 const gsl_multimin_fminimizer_type *simplexType = gsl_multimin_fminimizer_nmsimplex;
502 gsl_multimin_fminimizer *simplexMinimizer = nullptr;
503 gsl_vector *simplexStepSize = nullptr;
504 if (!isDerivDefined) {
505 simplexMinimizer = gsl_multimin_fminimizer_alloc(simplexType, l_data.p);
506 simplexStepSize = gsl_vector_alloc(l_data.p);
507 gsl_vector_set_all(simplexStepSize,
508 1.0); // is this always a sensible starting step size?
509 gsl_multimin_fminimizer_set(simplexMinimizer, &gslSimplexContainer, initFuncArg, simplexStepSize);
510 }
511
512 // finally do the fitting
513
514 int iter = 0;
515 int status;
516 double finalCostFuncVal;
517 auto dof = static_cast<double>(l_data.n - l_data.p); // dof stands for degrees of freedom
518
519 // Standard least-squares used if derivative function defined otherwise
520 // simplex
521 Progress prog(this, 0.0, 1.0, maxInterations);
522 if (isDerivDefined) {
523
524 do {
525 iter++;
526 status = gsl_multifit_fdfsolver_iterate(s);
527
528 if (status) // break if error
529 break;
530
531 status = gsl_multifit_test_delta(s->dx, s->x, 1e-4, 1e-4);
532 prog.report();
533 } while (status == GSL_CONTINUE && iter < maxInterations);
534
535 double chi = gsl_blas_dnrm2(s->f);
536 finalCostFuncVal = chi * chi / dof;
537
538 // put final converged fitting values back into m_fittedParameter
539 for (size_t i = 0, j = 0; i < nParams(); i++)
540 if (l_data.active[i])
541 m_fittedParameter[i] = gsl_vector_get(s->x, j++);
542 } else {
543 do {
544 iter++;
545 status = gsl_multimin_fminimizer_iterate(simplexMinimizer);
546
547 if (status) // break if error
548 break;
549
550 double size = gsl_multimin_fminimizer_size(simplexMinimizer);
551 status = gsl_multimin_test_size(size, 1e-2);
552 prog.report();
553 } while (status == GSL_CONTINUE && iter < maxInterations);
554
555 finalCostFuncVal = simplexMinimizer->fval / dof;
556
557 // put final converged fitting values back into m_fittedParameter
558 for (unsigned int i = 0, j = 0; i < m_fittedParameter.size(); i++)
559 if (l_data.active[i])
560 m_fittedParameter[i] = gsl_vector_get(simplexMinimizer->x, j++);
561 }
562
563 modifyFinalFittedParameters(m_fittedParameter); // do nothing except if overwritten by derived class
564
565 // Output summary to log file
566
567 std::string reportOfFit = gsl_strerror(status);
568
569 g_log.information() << "Iteration = " << iter << "\n"
570 << "Status = " << reportOfFit << "\n"
571 << "Chi^2/DoF = " << finalCostFuncVal << "\n";
572 for (size_t i = 0; i < m_fittedParameter.size(); i++)
573 g_log.information() << m_parameterNames[i] << " = " << m_fittedParameter[i] << " \n";
574
575 // also output summary to properties
576
577 setProperty("OutputStatus", reportOfFit);
578 setProperty("OutputChi2overDoF", finalCostFuncVal);
579 for (size_t i = 0; i < m_fittedParameter.size(); i++)
581
582 std::string output = getProperty("Output");
583 if (!output.empty()) {
584 // calculate covariance matrix if derivatives available
585
586 gsl_matrix *covar(nullptr);
587 std::vector<double> standardDeviations;
588 std::vector<double> sdExtended;
589 if (isDerivDefined) {
590 covar = gsl_matrix_alloc(l_data.p, l_data.p);
591#if GSL_MAJOR_VERSION < 2
592 gsl_multifit_covar(s->J, 0.0, covar);
593#else
594 gsl_matrix *J = gsl_matrix_alloc(l_data.n, l_data.p);
595 gsl_multifit_fdfsolver_jac(s, J);
596 gsl_multifit_covar(J, 0.0, covar);
597 gsl_matrix_free(J);
598#endif
599
600 int iPNotFixed = 0;
601 for (size_t i = 0; i < nParams(); i++) {
602 sdExtended.emplace_back(1.0);
603 if (l_data.active[i]) {
604 sdExtended[i] = sqrt(gsl_matrix_get(covar, iPNotFixed, iPNotFixed));
605 iPNotFixed++;
606 }
607 }
608 modifyFinalFittedParameters(sdExtended);
609 for (size_t i = 0; i < nParams(); i++)
610 if (l_data.active[i])
611 standardDeviations.emplace_back(sdExtended[i]);
612
613 declareProperty(std::make_unique<WorkspaceProperty<API::ITableWorkspace>>("OutputNormalisedCovarianceMatrix", "",
615 "The name of the TableWorkspace in which to store the final "
616 "covariance matrix");
617 setPropertyValue("OutputNormalisedCovarianceMatrix", output + "_NormalisedCovarianceMatrix");
618
620 Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace");
621 m_covariance->addColumn("str", "Name");
622 std::vector<std::string> paramThatAreFitted; // used for populating 1st "name" column
623 for (size_t i = 0; i < nParams(); i++) {
624 if (l_data.active[i]) {
625 m_covariance->addColumn("double", m_parameterNames[i]);
626 paramThatAreFitted.emplace_back(m_parameterNames[i]);
627 }
628 }
629
630 for (size_t i = 0; i < l_data.p; i++) {
631
632 Mantid::API::TableRow row = m_covariance->appendRow();
633 row << paramThatAreFitted[i];
634 for (size_t j = 0; j < l_data.p; j++) {
635 if (j == i)
636 row << 1.0;
637 else {
638 row << 100.0 * gsl_matrix_get(covar, i, j) /
639 sqrt(gsl_matrix_get(covar, i, i) * gsl_matrix_get(covar, j, j));
640 }
641 }
642 }
643
644 setProperty("OutputNormalisedCovarianceMatrix", m_covariance);
645 }
646
648 std::make_unique<WorkspaceProperty<API::ITableWorkspace>>("OutputParameters", "", Direction::Output),
649 "The name of the TableWorkspace in which to store the "
650 "final fit parameters");
651 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
652 "Name of the output Workspace holding resulting simlated spectrum");
653
654 setPropertyValue("OutputParameters", output + "_Parameters");
655 setPropertyValue("OutputWorkspace", output + "_Workspace");
656
657 // Save the final fit parameters in the output table workspace
659 Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace");
660 m_result->addColumn("str", "Name");
661 m_result->addColumn("double", "Value");
662 if (isDerivDefined)
663 m_result->addColumn("double", "Error");
664 Mantid::API::TableRow firstRow = m_result->appendRow();
665 firstRow << "Chi^2/DoF" << finalCostFuncVal;
666
667 for (size_t i = 0; i < nParams(); i++) {
668 Mantid::API::TableRow row = m_result->appendRow();
669 row << m_parameterNames[i] << m_fittedParameter[i];
670 if (isDerivDefined && l_data.active[i]) {
671 // perhaps want to scale standard deviations with sqrt(finalCostFuncVal)
672 row << sdExtended[i];
673 }
674 }
675 setProperty("OutputParameters", m_result);
676
677 // Save the fitted and simulated spectra in the output workspace
678 MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace");
679 int iSpec = getProperty("WorkspaceIndex");
680 Mantid::HistogramData::HistogramX const &inputX = inputWorkspace->x(iSpec);
681 Mantid::HistogramData::HistogramY const &inputY = inputWorkspace->y(iSpec);
682
683 int histN = isHistogram ? 1 : 0;
684 Mantid::DataObjects::Workspace2D_sptr ws = std::dynamic_pointer_cast<Mantid::DataObjects::Workspace2D>(
685 Mantid::API::WorkspaceFactory::Instance().create("Workspace2D", 3, l_data.n + histN, l_data.n));
686 ws->setTitle("");
687 ws->getAxis(0)->unit() = inputWorkspace->getAxis(0)->unit(); // UnitFactory::Instance().create("TOF");
688
689 for (int i = 0; i < 3; i++)
690 ws->mutableX(i).assign(inputX.begin() + m_minX, inputX.begin() + m_maxX + histN);
691
692 ws->mutableY(0).assign(inputY.begin() + m_minX, inputY.begin() + m_maxX);
693
694 auto &Y = ws->mutableY(1);
695 auto &E = ws->mutableY(2);
696
697 auto lOut = new double[l_data.n]; // to capture output from call to function()
698 modifyInitialFittedParameters(m_fittedParameter); // does nothing except if
699 // overwritten by derived
700 // class
701 function(&m_fittedParameter[0], lOut, l_data.X, l_data.n);
702 modifyInitialFittedParameters(m_fittedParameter); // reverse the effect of
703 // modifyInitialFittedParameters - if any
704
705 for (unsigned int i = 0; i < l_data.n; i++) {
706 Y[i] = lOut[i];
707 E[i] = l_data.Y[i] - Y[i];
708 }
709
710 delete[] lOut;
711
712 setProperty("OutputWorkspace", std::dynamic_pointer_cast<MatrixWorkspace>(ws));
713
714 if (isDerivDefined)
715 gsl_matrix_free(covar);
716 }
717
718 // clean up dynamically allocated gsl stuff
719
720 if (isDerivDefined)
721 gsl_multifit_fdfsolver_free(s);
722 else {
723 gsl_vector_free(simplexStepSize);
724 gsl_multimin_fminimizer_free(simplexMinimizer);
725 }
726
727 delete[] l_data.X;
728 delete[] l_data.sigmaData;
729 delete[] l_data.forSimplexLSwrap;
730 delete[] l_data.parameters;
731 gsl_vector_free(initFuncArg);
732}
733
738FitData::FitData(Fit1D *fit, const std::string &fixed)
739 : n(0), X(nullptr), Y(nullptr), sigmaData(nullptr), fit1D(fit), forSimplexLSwrap(nullptr), parameters(nullptr) {
741 active.insert(active.begin(), fit1D->m_parameterNames.size(), true);
742 for (const auto &name : namesStrTok) {
743 std::vector<std::string>::const_iterator i =
744 std::find(fit1D->m_parameterNames.begin(), fit1D->m_parameterNames.end(), name);
745 if (i != fit1D->m_parameterNames.end()) {
746 active[i - fit1D->m_parameterNames.begin()] = false;
747 } else
748 throw std::invalid_argument("Attempt to fix non-existing parameter " + name);
749 }
750 p = 0;
751 for (int i = 0; i < int(active.size()); i++)
752 if (active[i])
753 J.m_map[i] = static_cast<int>(p++);
754 else
755 J.m_map[i] = -1;
756}
757
758} // namespace Mantid::CurveFitting::Algorithms
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:44
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:426
void setPropertyValue(const std::string &name, const std::string &value) override
Set the value of a property by string N.B.
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
const std::vector< Kernel::Property * > & getProperties() const override
Get the list of managed properties.
Represents the Jacobian in IFitFunction::functionDeriv.
Definition Jacobian.h:22
Helper class for reporting progress from algorithms.
Definition Progress.h:25
TableRow represents a row in a TableWorkspace.
Definition TableRow.h:39
A property class for workspaces.
Deprecation notice: instead of using this algorithm please use the Fit algorithm instead.
Definition Fit1D.h:46
virtual void declareAdditionalProperties()
Declare additional properties other than fitting parameters.
Definition Fit1D.h:78
std::vector< std::string > m_parameterNames
Holds a copy of the names of the fitting parameters.
Definition Fit1D.h:114
std::vector< double > m_fittedParameter
Holds a copy of the value of the parameters that are actually least-squared fitted.
Definition Fit1D.h:111
virtual void afterDataRangedDetermined(const int &m_minX, const int &m_maxX)
Called after the data ranged has been determined but before the fitting starts.
Definition Fit1D.h:91
virtual void function(const double *in, double *out, const double *xValues, const size_t nData)=0
Function you want to fit to.
virtual void functionDeriv(const double *in, API::Jacobian *out, const double *xValues, const size_t nData)
Derivatives of function with respect to parameters you are trying to fit.
Definition Fit1D.cpp:218
size_t nParams() const
Number of parameters (incuding fixed).
Definition Fit1D.h:117
virtual void prepare()
Called in the beginning of exec(). Custom initialization.
Definition Fit1D.h:80
virtual void modifyInitialFittedParameters(std::vector< double > &fittedParameter)
Overload this function if the actual fitted parameters are different from those the user specifies.
Definition Fit1D.cpp:235
virtual void modifyStartOfRange(double &startX)
Option for providing intelligent range starting value based e.g.
Definition Fit1D.h:68
virtual void modifyFinalFittedParameters(std::vector< double > &fittedParameter)
If modifyInitialFittedParameters is overloaded this method must also be overloaded to reverse the eff...
Definition Fit1D.cpp:246
const std::string name() const override
Algorithm's name for identification overriding a virtual method.
Definition Fit1D.h:49
virtual void modifyEndOfRange(double &endX)
Option for providing intelligent range finishing value based e.g.
Definition Fit1D.h:73
virtual void declareParameters()=0
Declare parameters specific to fitting function.
The implementation of Jacobian.
Definition Fit1D.cpp:41
std::map< int, int > m_map
The index map.
Definition Fit1D.cpp:47
void setJ(gsl_matrix *J)
Set the pointer to the GSL's jacobian.
Definition Fit1D.cpp:74
void set(size_t iY, size_t iP, double value) override
Set a value to a Jacobian matrix element.
Definition Fit1D.cpp:54
void zero() override
Zero all matrix elements.
Definition Fit1D.cpp:72
double get(size_t iY, size_t iP) override
Get a value to a Jacobian matrix element.
Definition Fit1D.cpp:64
gsl_matrix * m_J
The pointer to the GSL's internal jacobian matrix.
Definition Fit1D.cpp:78
Marks code as not implemented yet.
Definition Exception.h:138
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
@ TOK_TRIM
remove leading and trailing whitespace from tokens
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
static double gsl_costFunction(const gsl_vector *v, void *params)
The gsl_costFunction is optimized by GSL simplex.
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.
std::shared_ptr< Workspace2D > Workspace2D_sptr
shared pointer to Mantid::DataObjects::Workspace2D
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
double gsl_costFunction(const gsl_vector *x, void *params)
Structure to contain least squares data and used by GSL.
Definition Fit1D.cpp:82
JacobianImpl J
Jacobi matrix interface.
Definition Fit1D.cpp:107
std::vector< bool > active
Holds a boolean for each parameter, true if it's active or false if it's fixed.
Definition Fit1D.cpp:105
Fit1D * fit1D
pointer to instance of Fit1D
Definition Fit1D.cpp:96
size_t n
number of points to be fitted (size of X, Y and sigmaData arrays)
Definition Fit1D.cpp:86
double * X
the data to be fitted (abscissae)
Definition Fit1D.cpp:90
size_t p
number of (active) fit parameters
Definition Fit1D.cpp:88
double * forSimplexLSwrap
Needed to use the simplex algorithm within the gsl least-squared framework.
Definition Fit1D.cpp:100
const double * Y
the data to be fitted (ordinates)
Definition Fit1D.cpp:92
double * parameters
A copy of the parameters.
Definition Fit1D.cpp:102
double * sigmaData
the standard deviations of the Y data points
Definition Fit1D.cpp:94
@ Input
An input workspace.
Definition Property.h:54
@ Output
An output workspace.
Definition Property.h:55