Mantid
Loading...
Searching...
No Matches
ConvolutionFunctionModel.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 +
15#include "MantidKernel/Logger.h"
17
18#include <utility>
19
20namespace {
21Mantid::Kernel::Logger g_log("ConvolutionFunctionModel");
22}
23
25
26using namespace Mantid::API;
27
28namespace {
29
30bool isConvolution(const IFunction *fun) { return fun->name() == "Convolution"; }
31
32bool isResolution(const IFunction *fun) { return fun->name() == "Resolution"; }
33
34bool isDeltaFunction(const IFunction *fun) { return fun->name() == "DeltaFunction"; }
35
36bool isTempFunction(const IFunction *fun) { return fun->name() == "ConvTempCorrection"; }
37
38bool isBackground(const IFunction *fun) { return static_cast<bool>(dynamic_cast<const IBackgroundFunction *>(fun)); }
39
40bool isLorentzianFunction(const IFunction *fun) { return fun->name() == "Lorentzian"; }
41bool isfitTypeFunction(const IFunction *fun) {
42 if (dynamic_cast<const CompositeFunction *>(fun) && !dynamic_cast<const ImmutableCompositeFunction *>(fun)) {
43 return false;
44 }
45 return true;
46}
47} // namespace
48
52}
53
54void ConvolutionFunctionModel::setModel(const std::string &background, const std::string &workspace, int workspaceIndex,
55 const std::string &peaks, bool hasDeltaFunction) {
56 auto const resolution = workspace.empty() ? "name=Resolution"
57 : "name=Resolution,Workspace=\"" + workspace +
58 "\",WorkspaceIndex=" + std::to_string(workspaceIndex);
59 auto const model = hasDeltaFunction ? "name=DeltaFunction;" + peaks : peaks;
60 auto const convolution = "composite=Convolution;" + resolution + ";" + model;
61 auto const function = background.empty() ? convolution : background + ";(" + convolution + ")";
62 setFunction(FunctionFactory::Instance().createInitialized(function));
63}
64
65void ConvolutionFunctionModel::setModel(const std::string &background,
66 const std::vector<std::pair<std::string, size_t>> &resolutionWorkspaces,
67 const std::string &lorentzianPeaks, const std::string &fitType,
68 bool hasDeltaFunction, const std::vector<double> &qValues,
69 const bool isQDependent, bool hasTempCorrection, double tempValue) {
70 auto fitFunction = std::make_shared<MultiDomainFunction>();
71 auto const nf = m_numberDomains > 0 ? static_cast<int>(m_numberDomains) : 1;
72 for (int i = 0; i < nf; ++i) {
73 CompositeFunction_sptr domainFunction;
74 auto qValue = qValues.empty() ? 0.0 : qValues[i];
75 auto innerFunction = createInnerFunction(lorentzianPeaks, fitType, hasDeltaFunction, isQDependent, qValue,
76 hasTempCorrection, tempValue);
77 auto workspace = resolutionWorkspaces.empty() ? "" : resolutionWorkspaces[i].first;
78 auto workspaceIndex = resolutionWorkspaces.empty() ? 0 : resolutionWorkspaces[i].second;
79 auto resolutionFunction = createResolutionFunction(workspace, workspaceIndex);
80 auto convolutionFunction = createConvolutionFunction(resolutionFunction, innerFunction);
81 domainFunction = addBackground(convolutionFunction, background);
82
83 fitFunction->addFunction(domainFunction);
84 fitFunction->setDomainIndex(i, i);
85 }
86 // The two clones here are needed as the clone value of IFunction goes through
87 // a string serialisation and deserialisation. This can lead to the function
88 // structure subtly changing. For example composite functions of only one
89 // member are removed and unneeded brackets are removed from user defined
90 // functions. As function cloning is used later on in the workflow it seems
91 // safer to clone twice here to get the function in it's final state early on
92 // rather than have it change during the workflow.
93 setFunction(fitFunction->clone()->clone());
94}
95
97 const std::string &background) {
98 if (background.empty())
99 return domainFunction;
100
101 auto backgroundFunction = FunctionFactory::Instance().createInitialized(background);
102 auto functionWithBackground = std::make_shared<CompositeFunction>();
103 functionWithBackground->addFunction(backgroundFunction);
104 functionWithBackground->addFunction(domainFunction);
105
106 return functionWithBackground;
107}
108
110 const std::string &fitType, bool hasDeltaFunction,
111 bool isQDependent, double qValue,
112 bool hasTempCorrection, double tempValue) {
113 CompositeFunction_sptr innerFunction = std::make_shared<CompositeFunction>();
114 if (!lorentzianPeaks.empty()) {
115 auto lorentzianPeakFunction = FunctionFactory::Instance().createInitialized(lorentzianPeaks);
116 auto peakFunctionComposite = std::dynamic_pointer_cast<CompositeFunction>(lorentzianPeakFunction);
117 if (peakFunctionComposite) {
118 innerFunction = peakFunctionComposite;
119 } else {
120 innerFunction->addFunction(lorentzianPeakFunction);
121 }
122 }
123
124 if (!fitType.empty()) {
125 auto fitTypeFunction = FunctionFactory::Instance().createInitialized(fitType);
126 innerFunction->addFunction(fitTypeFunction);
127 if (isQDependent) {
128 IFunction::Attribute attr(qValue);
129 fitTypeFunction->setAttribute("Q", attr);
130 }
131 }
132
133 if (hasTempCorrection) {
134 innerFunction = addTempCorrection(innerFunction, tempValue);
135 }
136
137 if (hasDeltaFunction) {
138 auto deltaFunction = FunctionFactory::Instance().createFunction("DeltaFunction");
139 auto lowerBound = std::unique_ptr<IConstraint>(
140 ConstraintFactory::Instance().createInitialized(deltaFunction.get(), "0.0 < Height", false));
141 deltaFunction->addConstraint(std::move(lowerBound));
142
143 if (!hasTempCorrection) {
144 innerFunction->addFunction(deltaFunction);
145 } else {
146 CompositeFunction_sptr innerFunctionNew = std::make_shared<CompositeFunction>();
147 innerFunctionNew->addFunction(deltaFunction);
148 innerFunctionNew->addFunction(innerFunction);
149 return innerFunctionNew;
150 }
151 }
152
153 return innerFunction;
154}
155
157 double tempValue) {
158 CompositeFunction_sptr productFunction =
159 std::dynamic_pointer_cast<CompositeFunction>(FunctionFactory::Instance().createFunction("ProductFunction"));
160 auto tempFunction = createTemperatureCorrection(tempValue);
161 productFunction->addFunction(tempFunction);
162 productFunction->addFunction(peaksFunction);
163 return productFunction;
164}
165
167 auto tempFunc = FunctionFactory::Instance().createInitialized("name=ConvTempCorrection");
168 tempFunc->setParameter("Temperature", correction);
169 tempFunc->fixParameter("Temperature", false);
170 return tempFunc;
171}
172
174 const IFunction_sptr &innerFunction) {
175 CompositeFunction_sptr convolution =
176 std::dynamic_pointer_cast<CompositeFunction>(FunctionFactory::Instance().createFunction("Convolution"));
177 convolution->addFunction(std::move(resolutionFunction));
178
179 if (innerFunction->nFunctions() > 0)
180 convolution->addFunction(innerFunction);
181
182 return convolution;
183}
184
186 size_t workspaceIndex) {
187 std::string resolution = workspaceName.empty() ? "name=Resolution"
188 : "name=Resolution,Workspace=\"" + workspaceName +
189 "\",WorkspaceIndex=" + std::to_string(workspaceIndex);
190 return FunctionFactory::Instance().createInitialized(resolution);
191}
192
194 m_backgroundPrefix.reset();
195 m_convolutionPrefix.reset();
196 m_deltaFunctionPrefix.reset();
197 m_tempFunctionPrefix.reset();
198 m_fitTypePrefix.reset();
199 m_peakPrefixes = QStringList();
200 m_resolutionWorkspace.clear();
202
203 auto function = getCurrentFunction();
204 if (!function)
205 return;
206 iterateThroughFunction(function.get(), QString());
207
208 if (m_peakPrefixes->isEmpty()) {
209 m_peakPrefixes.reset();
210 }
211 if (!m_convolutionPrefix) {
212 throw std::runtime_error("Model doesn't contain a convolution.");
213 }
214}
215
217 auto numberOfSubFunction = func->nFunctions();
218
219 setPrefix(func, prefix);
220 if (numberOfSubFunction == 0) {
221 return;
222 }
223 if (!isfitTypeFunction(func)) {
224 for (size_t k = 0; k < numberOfSubFunction; ++k) {
225 iterateThroughFunction(func->getFunction(k).get(), prefix + QString("f%1.").arg(k));
226 }
227 }
228}
229
230void ConvolutionFunctionModel::setPrefix(IFunction *func, const QString &prefix) {
231 if (isBackground(func)) {
232 if (m_backgroundPrefix) {
233 throw std::runtime_error("Model cannot have more than one background.");
234 }
235 m_backgroundPrefix = prefix;
236 } else if (isConvolution(func)) {
237 if (func->nFunctions() != 0 && func->getFunction(0)->name() != "Resolution") {
238 throw std::runtime_error("Model's resolution function must have type Resolution.");
239 } else if (func->nFunctions() == 0) {
242 }
243 m_convolutionPrefix = prefix;
244 } else if (isDeltaFunction(func)) {
245 m_deltaFunctionPrefix = prefix;
246 } else if (isTempFunction(func)) {
247 m_tempFunctionPrefix = prefix;
248 } else if (isResolution(func)) {
249 m_resolutionWorkspace = func->getAttribute("Workspace").asString();
250 m_resolutionWorkspaceIndex = func->getAttribute("WorkspaceIndex").asInt();
251 } else if (isLorentzianFunction(func)) {
252 m_peakPrefixes->append(prefix);
253 } else if (isfitTypeFunction(func)) {
254 m_fitTypePrefix = prefix;
255 }
256}
257
258} // namespace MantidQt::MantidWidgets
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
void iterateThroughFunction(IFunction *func, const QString &prefix)
CompositeFunction_sptr addTempCorrection(const CompositeFunction_sptr &peaksFunction, double tempValue)
void setModel(const std::string &background, const std::string &workspace, int workspaceIndex, const std::string &peaks, bool hasDeltaFunction)
void setPrefix(IFunction *func, const QString &prefix)
IFunction_sptr createResolutionFunction(const std::string &workspaceName, size_t workspaceIndex)
CompositeFunction_sptr createConvolutionFunction(IFunction_sptr resolutionFunction, const IFunction_sptr &innerFunction)
CompositeFunction_sptr createInnerFunction(const std::string &lorentzianPeaks, const std::string &fitType, bool hasDeltaFunction, bool isQDependent, double q, bool hasTempCorrection, double tempValue)
CompositeFunction_sptr addBackground(CompositeFunction_sptr domainFunction, const std::string &background)
IFunction_sptr getCurrentFunction() const override
void setFunction(IFunction_sptr) override
A composite function is a function containing other functions.
An interface to a background function.
Attribute is a non-fitting parameter.
Definition: IFunction.h:282
int asInt() const
Returns int value if attribute is a int, throws exception otherwise.
Definition: IFunction.cpp:726
std::string asString() const
Returns string value if attribute is a string, throws exception otherwise.
Definition: IFunction.cpp:660
This is an interface to a fitting function - a semi-abstarct class.
Definition: IFunction.h:163
virtual Attribute getAttribute(const std::string &name) const
Return a value of attribute attName.
Definition: IFunction.cpp:1394
virtual std::string name() const =0
Returns the function's name.
virtual std::shared_ptr< IFunction > getFunction(size_t i) const
Returns the pointer to i-th child function.
Definition: IFunction.cpp:1363
virtual std::size_t nFunctions() const
Number of child functions.
Definition: IFunction.h:611
Immutable composite function is a composite function which members cannot be added or removed after c...
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition: IFunction.h:732
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
std::string to_string(const wide_integer< Bits, Signed > &n)