19using namespace CurveFitting;
20using namespace Kernel;
28double calculateWidth(
double x,
const std::vector<double> &xVec,
const std::vector<double> &yVec) {
29 assert(xVec.size() == yVec.size());
30 auto upperIt = std::lower_bound(xVec.begin(), xVec.end(),
x);
31 if (upperIt == xVec.end() ||
x < xVec.front()) {
34 if (upperIt == xVec.begin()) {
37 double lowerX = *(upperIt - 1);
38 double upperX = *upperIt;
39 auto i = std::distance(xVec.begin(), upperIt) - 1;
40 return yVec[i] + (yVec[i + 1] - yVec[i]) / (upperX - lowerX) * (
x - lowerX);
48 double upperBound = fwhm + fwhmVariation;
49 double lowerBound = fwhm - fwhmVariation;
50 bool fix = lowerBound == upperBound;
52 if (lowerBound < 0.0) {
55 if (lowerBound >= upperBound) {
56 lowerBound = upperBound / 2;
59 if (peak.
name() ==
"Lorentzian") {
65 auto constraint = std::make_unique<Constraints::BoundaryConstraint>(&peak,
"FWHM", lowerBound, upperBound);
67 }
else if (peak.
name() ==
"Gaussian") {
72 const double WIDTH_TO_SIGMA = 2.0 * sqrt(2.0 * M_LN2);
73 lowerBound /= WIDTH_TO_SIGMA;
74 upperBound /= WIDTH_TO_SIGMA;
76 auto constraint = std::make_unique<Constraints::BoundaryConstraint>(&peak,
"Sigma", lowerBound, upperBound);
79 throw std::runtime_error(
"Cannot set constraint on width of " + peak.
name());
108 const std::vector<double> &yVec,
double fwhmVariation,
double defaultFWHM,
bool useDefaultFWHM) {
109 if (useDefaultFWHM) {
135 const std::vector<double> &xVec,
const std::vector<double> &yVec,
136 double fwhmVariation,
double defaultFWHM,
bool isGood,
bool fixAllPeaks) {
138 auto peak = std::dynamic_pointer_cast<API::IPeakFunction>(fun);
140 throw std::runtime_error(
"A peak function is expected.");
142 bool useDefaultFWHM = xVec.empty();
143 const bool fixByDefault =
true;
145 peak->setCentre(centre);
146 peak->setIntensity(intensity);
147 setPeakWidth(*peak, centre, xVec, yVec, fwhmVariation, defaultFWHM, useDefaultFWHM);
148 peak->fixCentre(fixByDefault);
149 peak->fixIntensity(fixByDefault);
154 peak->fixAll(fixByDefault);
175 const std::vector<double> &yVec,
double fwhmVariation,
double defaultFWHM,
176 size_t nRequiredPeaks,
bool fixAllPeaks) {
177 if (xVec.size() != yVec.size()) {
178 throw std::runtime_error(
"WidthX and WidthY must have the same size.");
183 if (nRequiredPeaks > maxNPeaks) {
184 maxNPeaks = nRequiredPeaks;
186 for (
size_t i = 0; i < maxNPeaks; ++i) {
187 const bool isGood = i < nPeaks;
188 const auto centre = isGood ? centresAndIntensities.
getCalculated(i) : 0.0;
189 const auto intensity = isGood ? centresAndIntensities.
getCalculated(i + nPeaks) : 0.0;
190 auto peak =
createPeak(peakShape, centre, intensity, xVec, yVec, fwhmVariation, defaultFWHM, isGood, fixAllPeaks);
203 const std::vector<double> &yVec,
double fwhmVariation) {
204 bool mustUpdateWidth = !xVec.empty();
205 if (mustUpdateWidth) {
206 auto fwhm = peak.
fwhm();
208 if (expectedFwhm <= 0.0) {
210 }
else if (
fabs(fwhm - expectedFwhm) > fwhmVariation) {
227 const std::vector<double> &yVec,
double fwhmVariation,
bool isGood,
bool fixAllPeaks) {
228 const bool fixByDefault =
true;
238 peak.
fixAll(fixByDefault);
266 const std::vector<double> &xVec,
const std::vector<double> &yVec,
double fwhmVariation,
267 double defaultFWHM,
bool fixAllPeaks) {
272 for (
size_t i = 0; i < maxNPeaks; ++i) {
273 const bool isGood = i < nGoodPeaks;
274 auto centre = isGood ? centresAndIntensities.
getCalculated(i) : 0.0;
275 auto intensity = isGood ? centresAndIntensities.
getCalculated(i + nGoodPeaks) : 0.0;
277 if (i < nFunctions - iFirst) {
280 updatePeak(peak, centre, intensity, xVec, yVec, fwhmVariation, isGood, fixAllPeaks);
283 createPeak(peakShape, centre, intensity, xVec, yVec, fwhmVariation, defaultFWHM, isGood, fixAllPeaks);
289 const bool fixByDefault =
true;
290 for (
size_t i = maxNPeaks; i < nFunctions - iFirst; ++i) {
293 const auto fwhm = peak.
fwhm();
296 peak.fixIntensity(fixByDefault);
297 peak.fixCentre(fixByDefault);
A composite function is a function containing other functions.
virtual size_t addFunction(IFunction_sptr f)
Add a function at the back of the internal function list.
std::size_t nFunctions() const override
Number of functions.
IFunction_sptr getFunction(std::size_t i) const override
Returns the pointer to i-th function.
A class to store values calculated by a function.
size_t size() const
Return the number of values.
double getCalculated(size_t i) const
Get i-th calculated value.
virtual void setHeight(const double h)=0
Sets the parameters such that height == h.
virtual void setCentre(const double c)=0
Sets the parameters such that centre == c.
virtual void fixCentre(bool isDefault=false)
Fix a parameter or set up a tie such that value returned by centre() is constant during fitting.
virtual void removeConstraint(const std::string &parName)
Remove a constraint.
void unfixAllDefault()
Free all parameters fixed by default.
void fixParameter(const std::string &name, bool isDefault=false)
Fix a parameter.
virtual std::string name() const =0
Returns the function's name.
void fixAll(bool isDefault=false)
Fix all parameters.
virtual void addConstraint(std::unique_ptr< IConstraint > ic)
Add a constraint to function.
An interface to a peak function, which extend the interface of IFunctionWithLocation by adding method...
virtual void setIntensity(const double newIntensity)
Sets the integral intensity of the peak.
virtual double fwhm() const =0
Returns the peak FWHM.
virtual void setFwhm(const double w)=0
Sets the parameters such that FWHM = w.
virtual void fixIntensity(bool isDefault=false)
Fix a parameter or set up a tie such that value returned by intensity() is constant during fitting.
virtual void unfixIntensity()
Free the intensity parameter.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< IPeakFunction > IPeakFunction_sptr
size_t calculateMaxNPeaks(size_t nPeaks)
Calculate the maximum number of peaks a spectrum can have.
size_t updateSpectrumFunction(API::CompositeFunction &spectrum, const std::string &peakShape, const API::FunctionValues ¢resAndIntensities, size_t iFirst, const std::vector< double > &xVec, const std::vector< double > &yVec, double fwhmVariation, double defaultFWHM, bool fixAllPeaks)
Update the peaks parameters after recalculationof the crystal field.
void ignorePeak(API::IPeakFunction &peak, double fwhm)
Set peak's properties such that it was invisible in the spectrum.
void setPeakWidth(API::IPeakFunction &peak, double centre, const std::vector< double > &xVec, const std::vector< double > &yVec, double fwhmVariation, double defaultFWHM, bool useDefaultFWHM)
Set the width of a peak.
size_t calculateNPeaks(const API::FunctionValues ¢resAndIntensities)
Calculate the number of visible peaks.
API::IPeakFunction_sptr createPeak(const std::string &peakShape, double centre, double intensity, const std::vector< double > &xVec, const std::vector< double > &yVec, double fwhmVariation, double defaultFWHM, bool isGood, bool fixAllPeaks)
Create a single peak.
size_t buildSpectrumFunction(API::CompositeFunction &spectrum, const std::string &peakShape, const API::FunctionValues ¢resAndIntensities, const std::vector< double > &xVec, const std::vector< double > &yVec, double fwhmVariation, double defaultFWHM, size_t nRequiredPeaks, bool fixAllPeaks)
Utility functions to help set up peak functions in a Crystal Field spectrum.
double calculateWidth(double x, const std::vector< double > &xVec, const std::vector< double > &yVec)
Calculate the width of a peak cenrted at x using an interpolated value of a function tabulated at xVe...
void setWidthConstraint(API::IPeakFunction &peak, double fwhm, double fwhmVariation)
Set a boundary constraint on the appropriate parameter of the peak.
void updatePeakWidth(API::IPeakFunction &peak, double centre, const std::vector< double > &xVec, const std::vector< double > &yVec, double fwhmVariation)
Update width of a peak.
void updatePeak(API::IPeakFunction &peak, double centre, double intensity, const std::vector< double > &xVec, const std::vector< double > &yVec, double fwhmVariation, bool isGood, bool fixAllPeaks)
Update a single peak.