Mantid
Loading...
Searching...
No Matches
IPeakFunction.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#include "MantidAPI/IFunction1D.tcc"
14#include "MantidAPI/Jacobian.h"
17#include "boost/make_shared.hpp"
18
19#include <cmath>
20#include <limits>
21#include <memory>
22
23namespace Mantid::API {
24
25namespace {
26
29class PartialJacobian1 : public Jacobian {
30 Jacobian *m_J;
31 int m_iY0;
32public:
37 PartialJacobian1(Jacobian *J, int iY0) : m_J(J), m_iY0(iY0) {}
44 void set(size_t iY, size_t iP, double value) override { m_J->set(m_iY0 + iY, iP, value); }
50 double get(size_t iY, size_t iP) override { return m_J->get(m_iY0 + iY, iP); }
53 void zero() override {
54 throw Kernel::Exception::NotImplementedError("zero() is not implemented for PartialJacobian1");
55 }
56};
57
59const double PEAK_TOLERANCE = 1e-14;
61const int MAX_PEAK_RADIUS = std::numeric_limits<int>::max();
62
63} // namespace
64
68IPeakFunction::IPeakFunction() : m_peakRadius(MAX_PEAK_RADIUS) {}
69
70void IPeakFunction::function(const FunctionDomain &domain, FunctionValues &values) const {
71 auto peakRadius = dynamic_cast<const FunctionDomain1D &>(domain).getPeakRadius();
72 setPeakRadius(peakRadius);
73 IFunction1D::function(domain, values);
74}
75
86void IPeakFunction::function1D(double *out, const double *xValues, const size_t nData) const {
87 double c = this->centre();
88 double dx = fabs(m_peakRadius * this->fwhm());
89 int i0 = -1;
90 int n = 0;
91 for (size_t i = 0; i < nData; ++i) {
92 if (fabs(xValues[i] - c) < dx) {
93 if (i0 < 0)
94 i0 = static_cast<int>(i);
95 ++n;
96 } else {
97 out[i] = 0.0;
98 }
99 }
100 if (i0 < 0 || n == 0)
101 return;
102 this->functionLocal(out + i0, xValues + i0, n);
103}
104
116void IPeakFunction::functionDeriv1D(Jacobian *out, const double *xValues, const size_t nData) {
117 double c = this->centre();
118 double dx = fabs(m_peakRadius * this->fwhm());
119 int i0 = -1;
120 int n = 0;
121 for (size_t i = 0; i < nData; ++i) {
122 if (fabs(xValues[i] - c) < dx) {
123 if (i0 < 0)
124 i0 = static_cast<int>(i);
125 ++n;
126 } else {
127 for (size_t ip = 0; ip < this->nParams(); ++ip) {
128 out->set(i, ip, 0.0);
129 }
130 }
131 }
132 if (i0 < 0 || n == 0)
133 return;
134 PartialJacobian1 J(out, i0);
135 this->functionDerivLocal(&J, xValues + i0, n);
136}
137
139 if (r > 0) {
140 m_peakRadius = r;
141 } else if (r == 0) {
142 m_peakRadius = MAX_PEAK_RADIUS;
143 }
144}
145
146void IPeakFunction::setParameter(size_t i, const double &value, bool explicitlySet) {
148 ParamFunction::setParameter(i, value, explicitlySet);
149}
150
151void IPeakFunction::setParameter(const std::string &name, const double &value, bool explicitlySet) {
153 ParamFunction::setParameter(name, value, explicitlySet);
154}
155
156/*
157 * @brief Integrate based on dirty parameters then cache the result
158 * @details Returns the integrated intensity of the peak function, using the peak radius
159 * to determine integration borders.
160 */
163 auto const interval = getDomainInterval();
164
165 PeakFunctionIntegrator integrator;
166
167 auto const result = integrator.integrate(*this, interval.first, interval.second);
168 if (result.success)
169 integrationResult = boost::make_shared<IntegrationResultCache>(result.result, result.error);
170 else
171 integrationResult = boost::make_shared<IntegrationResultCache>(std::nan(""), std::nan(""));
173 }
174 return *integrationResult;
175}
176
179double IPeakFunction::intensity() const { return integrate().first; }
180
182 auto const interval = getDomainInterval();
183 PeakFunctionIntegrator integrator;
184 return integrator.integrateError(*this, interval.first, interval.second);
185}
186
188void IPeakFunction::setIntensity(const double newIntensity) {
189 double currentHeight = height();
190 double currentIntensity = intensity();
191
192 if (currentIntensity == 0.0) {
193 // Try to set a different height first.
194 setHeight(2.0);
195
196 currentHeight = height();
197 currentIntensity = intensity();
198
199 // If the current intensity is still 0, there's nothing left to do.
200 if (currentIntensity == 0.0) {
201 throw std::invalid_argument("Cannot set new intensity, not enough information available.");
202 }
203 }
204
205 setHeight(newIntensity / currentIntensity * currentHeight);
206}
207
209 FunctionParameterDecorator_sptr fn = std::dynamic_pointer_cast<FunctionParameterDecorator>(
210 FunctionFactory::Instance().createFunction("PeakParameterFunction"));
211
212 if (!fn) {
213 throw std::runtime_error("PeakParameterFunction could not be created successfully.");
214 }
215
216 fn->setDecoratedFunction(this->name());
217
218 FunctionDomain1DVector domain(std::vector<double>(4, 0.0));
219 TempJacobian jacobian(4, fn->nParams());
220
221 fn->functionDeriv(domain, jacobian);
222
223 return parameterName(jacobian.maxParam(0));
224}
225
230std::pair<double, double> IPeakFunction::getDomainInterval(double level) const {
231 if (level < PEAK_TOLERANCE) {
232 level = PEAK_TOLERANCE;
233 }
234 double left = 0.0;
235 double right = 0.0;
236 auto h = height();
237 auto w = fwhm();
238
239 auto c = centre();
240 if (h == 0.0 || w == 0.0 || level >= 1.0) {
241 return std::make_pair(c, c);
242 }
243
244 auto findBound = [this, c, h, level](double dx) {
245 for (size_t i = 0; i < 100; ++i) {
246 double x = c + dx;
247 double y = 0.0;
248 this->functionLocal(&y, &x, 1);
249 if (fabs(y / h) < level) {
250 return x;
251 }
252 dx *= 2;
253 }
254 return c + dx;
255 };
256
257 left = findBound(-w);
258 right = findBound(w);
259 return std::make_pair(left, right);
260}
261
268void IPeakFunction::functionDerivLocal(Jacobian *jacobian, const double *xValues, const size_t nData) {
269 auto evalMethod = [this](double *out, const double *xValues, const size_t nData) {
270 this->functionLocal(out, xValues, nData);
271 };
272 this->calcNumericalDerivative1D(jacobian, std::move(evalMethod), xValues, nData);
273}
274
275} // namespace Mantid::API
Jacobian * m_J
pointer to the overall Jacobian
int m_iY0
offset in the overall Jacobian for a particular function
double value
The value of the point.
Definition: FitMW.cpp:51
double left
Definition: LineProfile.cpp:80
double right
Definition: LineProfile.cpp:81
#define fabs(x)
Definition: Matrix.cpp:22
Implements FunctionDomain1D with its own storage in form of a std::vector.
Represent a domain for functions of one real argument.
Base class that represents the domain of a function.
A class to store values calculated by a function.
void calcNumericalDerivative1D(Jacobian *jacobian, EvaluationMethod func1D, const double *xValues, const size_t nData)
Calculate a numerical derivative for the 1D data.
void function(const FunctionDomain &domain, FunctionValues &values) const override
Evaluates the function for all arguments in the domain.
Definition: IFunction1D.cpp:38
virtual void setHeight(const double h)=0
Sets the parameters such that height == h.
virtual double height() const =0
Returns the height of the function.
virtual double centre() const =0
Returns the centre of the function, which may be something as simple as the centre of the fitting ran...
virtual std::string name() const =0
Returns the function's name.
virtual void setIntensity(const double newIntensity)
Sets the integral intensity of the peak.
virtual void functionLocal(double *out, const double *xValues, const size_t nData) const =0
Function evaluation method to be implemented in the inherited classes.
virtual void functionDerivLocal(Jacobian *jacobian, const double *xValues, const size_t nData)
Derivative evaluation method. Default is to calculate numerically.
void functionDeriv1D(Jacobian *out, const double *xValues, const size_t nData) override
General implementation of the method for all peaks.
std::string getCentreParameterName() const
Get name of parameter that is associated to centre.
virtual double fwhm() const =0
Returns the peak FWHM.
void function1D(double *out, const double *xValues, const size_t nData) const override
General implementation of the method for all peaks.
void function(const FunctionDomain &domain, FunctionValues &values) const override
Evaluates the function for all arguments in the domain.
virtual IntegrationResultCache integrate() const
boost::shared_ptr< IntegrationResultCache > integrationResult
virtual double intensity() const
Returns the integral intensity of the peak.
void setPeakRadius(int r) const
Set new peak radius.
virtual double intensityError() const
Error in the integrated intensity of the peak due to uncertainties in the values of the fit parameter...
int m_peakRadius
Defines the area around the centre where the peak values are to be calculated (in FWHM).
void setParameter(const std::string &name, const double &value, bool explicitlySet=true) override
Override parent so that we may bust the cache when a parameter is set.
virtual std::pair< double, double > getDomainInterval(double level=DEFAULT_SEARCH_LEVEL) const
Get the interval on which the peak has all its values above a certain level.
Represents the Jacobian in IFitFunction::functionDeriv.
Definition: Jacobian.h:22
virtual void set(size_t iY, size_t iP, double value)=0
Set a value to a Jacobian matrix element.
void setParameter(size_t, const double &value, bool explicitlySet=true) override
Set i-th parameter.
std::string parameterName(size_t i) const override
Returns the name of parameter i.
size_t nParams() const override
Total number of parameters.
Definition: ParamFunction.h:53
double integrateError(const IPeakFunction &peakFunction, double lowerLimit, double upperLimit) const
Error in the integrated intensity within an continuous interval due to uncertainties in the values of...
IntegrationResult integrate(const IPeakFunction &peakFunction, double lowerLimit, double upperLimit) const
Integration of peak function on the interval [a, b].
size_t maxParam(size_t iY)
Definition: IPeakFunction.h:23
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::pair< double, double > IntegrationResultCache
Definition: IPeakFunction.h:44
std::shared_ptr< FunctionParameterDecorator > FunctionParameterDecorator_sptr