Mantid
Loading...
Searching...
No Matches
FitDomain.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2020 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 +
9
13#include "MantidKernel/Logger.h"
14
15#include <boost/algorithm/string.hpp>
16
17#include <algorithm>
18#include <stdexcept>
19#include <utility>
20
21using namespace Mantid::API;
22using namespace MantidQt::MantidWidgets;
23
24namespace {
25Mantid::Kernel::Logger g_log("FitDomain");
26
27IFunction_sptr createIFunction(std::string const &functionString) {
28 return FunctionFactory::Instance().createInitialized(functionString);
29}
30
31CompositeFunction_sptr toComposite(const IFunction_sptr &function) {
32 return std::dynamic_pointer_cast<CompositeFunction>(function);
33}
34
35CompositeFunction_sptr createEmptyComposite() { return toComposite(createIFunction("name=CompositeFunction")); }
36
37std::vector<std::string> getFunctionNamesInString(std::string const &functionString) {
38 std::vector<std::string> functionNames;
39 for (auto const &str : splitStringBy(functionString, ",();"))
40 if (str.substr(0, 5) == "name=")
41 functionNames.emplace_back(str.substr(5));
42 return functionNames;
43}
44
45bool isValueWithinConstraint(std::string const &constraint, double value) {
46 auto const limits = splitConstraintString(constraint).second;
47 return limits.first.toDouble() <= value && value <= limits.second.toDouble();
48}
49
50} // namespace
51
53
54FitDomain::FitDomain(std::string workspaceName, WorkspaceIndex workspaceIndex, double startX, double endX)
55 : m_workspaceName(std::move(workspaceName)), m_workspaceIndex(workspaceIndex), m_startX(startX), m_endX(endX),
56 m_function(nullptr) {}
57
58void FitDomain::setWorkspaceName(std::string const &workspaceName) { m_workspaceName = workspaceName; }
59
60std::string FitDomain::domainName() const {
62}
63
64bool FitDomain::setStartX(double startX) {
65 auto const validStartX = isValidStartX(startX);
66 if (validStartX)
68 return validStartX;
69}
70
71bool FitDomain::setEndX(double endX) {
72 auto const validEndX = isValidEndX(endX);
73 if (validEndX)
74 m_endX = endX;
75 return validEndX;
76}
77
79
81 if (m_function)
82 return m_function->clone();
83 return nullptr;
84}
85
86void FitDomain::removeFunction(std::string const &function) {
87 if (m_function) {
88 if (auto composite = toComposite(m_function))
89 removeFunctionFromComposite(function, composite);
90 else
92 }
93}
94
95void FitDomain::removeFunctionFromIFunction(std::string const &function, IFunction_sptr &iFunction) {
96 auto const functionNames = getFunctionNamesInString(function);
97 const std::string iFunctionName = iFunction->name();
98 const auto it = std::find_if(functionNames.cbegin(), functionNames.cend(),
99 [&iFunctionName](const auto &name) { return iFunctionName == name; });
100 if (it != functionNames.cend())
101 iFunction = nullptr;
102}
103
104void FitDomain::removeFunctionFromComposite(std::string const &function, CompositeFunction_sptr &composite) {
105 for (auto const &functionName : getFunctionNamesInString(function)) {
106 if (composite->hasFunction(functionName))
107 composite->removeFunction(composite->functionIndex(functionName));
108 }
109
110 if (composite->nFunctions() == 0)
111 m_function = nullptr;
112 else if (composite->nFunctions() == 1)
113 m_function = composite->getFunction(0);
114}
115
117 if (m_function) {
118 addFunctionToExisting(function);
119 } else {
120 m_function = function;
121 }
122}
123
125 if (toComposite(function)) {
126 g_log.error("Add function failed: Nested composite functions are not supported.");
127 return;
128 }
129
130 if (auto composite = toComposite(m_function)) {
131 composite->addFunction(function);
132 } else {
133 auto newComposite = createEmptyComposite();
134 newComposite->addFunction(m_function->clone());
135 newComposite->addFunction(function);
136 m_function = newComposite;
137 }
138}
139
140void FitDomain::setParameterValue(std::string const &parameter, double newValue) {
141 if (hasParameter(parameter) && isParameterValueWithinConstraints(parameter, newValue)) {
142 m_function->setParameter(parameter, newValue);
144 }
145}
146
148 for (auto paramIndex = 0u; paramIndex < m_function->nParams(); ++paramIndex) {
149 if (auto const tie = m_function->getTie(paramIndex)) {
150 auto const parameterName = m_function->parameterName(paramIndex);
151 if (!isParameterValueWithinConstraints(parameterName, tie->eval(false)))
152 clearParameterTie(parameterName);
153 }
154 }
155}
156
157double FitDomain::getParameterValue(std::string const &parameter) const {
158 if (hasParameter(parameter))
159 return m_function->getParameter(parameter);
160 throw std::runtime_error("The function does not contain the parameter " + parameter + ".");
161}
162
163double FitDomain::getTieValue(std::string const &tie) const {
164 if (tie.empty())
165 throw std::runtime_error("This tie does not have a value.");
166 else if (isNumber(tie))
167 return std::stod(tie);
168 return getParameterValue(tie);
169}
170
171void FitDomain::setAttributeValue(std::string const &attribute, const IFunction::Attribute &newValue) {
172 if (m_function && m_function->hasAttribute(attribute))
173 m_function->setAttribute(attribute, newValue);
174}
175
177 if (m_function && m_function->hasAttribute(attribute))
178 return m_function->getAttribute(attribute);
179 throw std::runtime_error("The function does not contain this attribute.");
180}
181
182bool FitDomain::hasParameter(std::string const &parameter) const {
183 if (m_function)
184 return m_function->hasParameter(parameter);
185 return false;
186}
187
188bool FitDomain::isParameterActive(std::string const &parameter) const {
189 if (hasParameter(parameter))
190 return m_function->getParameterStatus(m_function->parameterIndex(parameter)) == IFunction::ParameterStatus::Active;
191 return false;
192}
193
194void FitDomain::setParameterFixed(std::string const &parameter, bool fix) const {
195 if (!hasParameter(parameter))
196 throw std::runtime_error("The parameter does not exist in this domain.");
197
198 if (fix) {
199 m_function->tie(parameter, std::to_string(getParameterValue(parameter)));
200 } else {
201 m_function->removeTie(m_function->parameterIndex(parameter));
202 }
203}
204
205bool FitDomain::isParameterFixed(std::string const &parameter) const {
206 if (hasParameter(parameter)) {
207 return m_function->getParameterStatus(m_function->parameterIndex(parameter)) == IFunction::ParameterStatus::Fixed;
208 }
209 throw std::runtime_error("The parameter does not exist in this domain.");
210}
211
212std::string FitDomain::getParameterTie(std::string const &parameter) const {
213 if (hasParameter(parameter)) {
214 auto const parameterIndex = m_function->parameterIndex(parameter);
215 if (auto const tie = m_function->getTie(parameterIndex)) {
216 auto const tieStr = tie->asString();
217 auto const equalsIndex = tieStr.find("=");
218 if (equalsIndex != std::string::npos)
219 return tieStr.substr(equalsIndex + 1);
220 }
221 return "";
222 }
223 throw std::runtime_error("The parameter does not exist in this domain.");
224}
225
226std::string FitDomain::getParameterConstraint(std::string const &parameter) const {
227 if (hasParameter(parameter)) {
228 auto const parameterIndex = m_function->parameterIndex(parameter);
229 auto const constraint = m_function->getConstraint(parameterIndex);
230 return constraint ? constraint->asString() : "";
231 }
232 throw std::runtime_error("The parameter does not exist in this domain.");
233}
234
235void FitDomain::clearParameterTie(std::string const &parameter) {
236 if (hasParameter(parameter))
237 m_function->removeTie(m_function->parameterIndex(parameter));
238}
239
240bool FitDomain::updateParameterTie(std::string const &parameter, std::string const &tie) {
241 if (hasParameter(parameter)) {
242 if (tie.empty())
243 m_function->removeTie(m_function->parameterIndex(parameter));
244 else
245 return setParameterTie(parameter, tie);
246 }
247 // We want to silently ignore if the function doesn't have the parameter
248 return true;
249}
250
251bool FitDomain::setParameterTie(std::string const &parameter, std::string const &tie) {
252 try {
253 if (isValidParameterTie(parameter, tie)) {
254 m_function->tie(parameter, tie);
255 setParameterValue(parameter, getTieValue(tie));
256 }
257 } catch (std::invalid_argument const &ex) {
258 g_log.warning(ex.what());
259 return false;
260 } catch (std::runtime_error const &ex) {
261 g_log.warning(ex.what());
262 return false;
263 }
264 return true;
265}
266
267void FitDomain::removeParameterConstraint(std::string const &parameter) {
268 if (hasParameter(parameter))
269 m_function->removeConstraint(parameter);
270}
271
272void FitDomain::updateParameterConstraint(std::string const &functionIndex, std::string const &parameter,
273 std::string const &constraint) {
274 if (isValidParameterConstraint(functionIndex + parameter, constraint)) {
275 if (functionIndex.empty())
276 m_function->addConstraints(constraint);
277 else if (auto composite = toComposite(m_function))
278 updateParameterConstraint(composite, functionIndex, parameter, constraint);
279 }
280}
281
282void FitDomain::updateParameterConstraint(CompositeFunction_sptr &composite, std::string const &functionIndex,
283 std::string const &parameter, std::string const &constraint) {
284 auto const index = getFunctionIndexAt(functionIndex, 0);
285 if (index < composite->nFunctions()) {
286 auto function = composite->getFunction(index);
287 if (function->hasParameter(parameter))
288 function->addConstraints(constraint);
289 }
290}
291
292std::vector<std::string> FitDomain::getParametersTiedTo(std::string const &parameter) const {
293 std::vector<std::string> tiedParameters;
294 if (m_function) {
295 for (auto paramIndex = 0u; paramIndex < m_function->nParams(); ++paramIndex)
296 appendParametersTiedTo(tiedParameters, parameter, paramIndex);
297 }
298 return tiedParameters;
299}
300
301void FitDomain::appendParametersTiedTo(std::vector<std::string> &tiedParameters, std::string const &parameter,
302 std::size_t const &parameterIndex) const {
303 if (auto const tie = m_function->getTie(parameterIndex)) {
304 for (auto rhsParameter : tie->getRHSParameters()) {
305 if (parameter == rhsParameter.parameterName())
306 tiedParameters.emplace_back(m_function->parameterName(parameterIndex));
307 }
308 }
309}
310
311bool FitDomain::isParameterValueWithinConstraints(std::string const &parameter, double value) const {
312 if (!hasParameter(parameter))
313 return false;
314
315 auto isValid = true;
316
317 auto const parameterIndex = m_function->parameterIndex(parameter);
318 if (auto const constraint = m_function->getConstraint(parameterIndex))
319 isValid = isValueWithinConstraint(constraint->asString(), value);
320
321 if (!isValid)
322 g_log.warning("The provided value for '" + parameter + "' is not within its constraints.");
323 return isValid;
324}
325
326bool FitDomain::isValidParameterTie(std::string const &parameter, std::string const &tie) const {
327 if (tie.empty())
328 return true;
329 else if (isNumber(tie))
330 return isParameterValueWithinConstraints(parameter, std::stod(tie));
332}
333
334bool FitDomain::isValidParameterConstraint(std::string const &parameter, std::string const &constraint) const {
335 auto isValid = false;
336 if (hasParameter(parameter)) {
337 auto const parameterValue = m_function->getParameter(parameter);
338 isValid = isValueWithinConstraint(constraint, parameterValue);
339 if (!isValid)
340 g_log.warning("The provided constraint for '" + parameter + "' does not encompass its current value.");
341 }
342 return isValid;
343}
344
345bool FitDomain::isValidStartX(double startX) const {
346 auto const limits = xLimits();
347 return limits.first <= startX && startX <= limits.second && startX < m_endX;
348}
349
350bool FitDomain::isValidEndX(double endX) const {
351 auto const limits = xLimits();
352 return limits.first <= endX && endX <= limits.second && endX > m_startX;
353}
354
355std::pair<double, double> FitDomain::xLimits() const {
356 auto &ads = AnalysisDataService::Instance();
357 if (ads.doesExist(m_workspaceName))
359
360 throw std::invalid_argument("The domain '" + m_workspaceName + " (" + std::to_string(m_workspaceIndex.value) +
361 ")' could not be found.");
362}
363
365 WorkspaceIndex workspaceIndex) const {
366 if (workspace) {
367 auto const xData = workspace->x(workspaceIndex.value);
368 return std::pair<double, double>(xData.front(), xData.back());
369 }
370
371 throw std::invalid_argument("The workspace '" + m_workspaceName + "' is not a matrix workspace.");
372}
373
374} // namespace MantidQt::MantidWidgets
double value
The value of the point.
Definition: FitMW.cpp:51
IPeaksWorkspace_sptr workspace
Definition: IndexPeaks.cpp:114
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
void setParameterValue(std::string const &parameter, double newValue)
Definition: FitDomain.cpp:140
std::string domainName() const
Definition: FitDomain.cpp:60
void updateParameterConstraint(std::string const &functionIndex, std::string const &parameter, std::string const &constraint)
Definition: FitDomain.cpp:272
void removeFunctionFromIFunction(std::string const &function, Mantid::API::IFunction_sptr &iFunction)
Definition: FitDomain.cpp:95
std::string getParameterTie(std::string const &parameter) const
Definition: FitDomain.cpp:212
FitDomain(std::string workspaceName, WorkspaceIndex workspaceIndex, double startX, double endX)
Definition: FitDomain.cpp:54
double getParameterValue(std::string const &parameter) const
Definition: FitDomain.cpp:157
bool isParameterValueWithinConstraints(std::string const &parameter, double value) const
Definition: FitDomain.cpp:311
std::string workspaceName() const noexcept
Definition: FitDomain.h:35
void setParameterFixed(std::string const &parameter, bool fix) const
Definition: FitDomain.cpp:194
void addFunctionToExisting(Mantid::API::IFunction_sptr const &function)
Definition: FitDomain.cpp:124
bool isValidParameterConstraint(std::string const &parameter, std::string const &constraint) const
Definition: FitDomain.cpp:334
bool isParameterActive(std::string const &parameter) const
Definition: FitDomain.cpp:188
bool hasParameter(std::string const &parameter) const
Definition: FitDomain.cpp:182
void removeFunctionFromComposite(std::string const &function, Mantid::API::CompositeFunction_sptr &composite)
Definition: FitDomain.cpp:104
void setAttributeValue(std::string const &attribute, const Mantid::API::IFunction::Attribute &newValue)
Definition: FitDomain.cpp:171
Mantid::API::IFunction_sptr getFunctionCopy() const
Definition: FitDomain.cpp:80
void setFunction(Mantid::API::IFunction_sptr const &function)
Definition: FitDomain.cpp:78
void removeFunction(std::string const &function)
Definition: FitDomain.cpp:86
bool updateParameterTie(std::string const &parameter, std::string const &tie)
Definition: FitDomain.cpp:240
Mantid::API::IFunction::Attribute getAttributeValue(std::string const &attribute) const
Definition: FitDomain.cpp:176
bool isValidStartX(double startX) const
Definition: FitDomain.cpp:345
bool setParameterTie(std::string const &parameter, std::string const &tie)
Definition: FitDomain.cpp:251
std::string getParameterConstraint(std::string const &parameter) const
Definition: FitDomain.cpp:226
double endX() const noexcept
Definition: FitDomain.h:42
double getTieValue(std::string const &tie) const
Definition: FitDomain.cpp:163
void removeParameterConstraint(std::string const &parameter)
Definition: FitDomain.cpp:267
bool isParameterFixed(std::string const &parameter) const
Definition: FitDomain.cpp:205
void clearParameterTie(std::string const &parameter)
Definition: FitDomain.cpp:235
void appendParametersTiedTo(std::vector< std::string > &tiedParameters, std::string const &parameter, std::size_t const &parameterIndex) const
Definition: FitDomain.cpp:301
Mantid::API::IFunction_sptr m_function
Definition: FitDomain.h:104
void setWorkspaceName(std::string const &workspaceName)
Definition: FitDomain.cpp:58
void addFunction(Mantid::API::IFunction_sptr const &function)
Definition: FitDomain.cpp:116
bool isValidEndX(double endX) const
Definition: FitDomain.cpp:350
bool isValidParameterTie(std::string const &parameter, std::string const &tie) const
Definition: FitDomain.cpp:326
bool setStartX(double startX)
Definition: FitDomain.cpp:64
std::vector< std::string > getParametersTiedTo(std::string const &parameter) const
Definition: FitDomain.cpp:292
WorkspaceIndex workspaceIndex() const noexcept
Definition: FitDomain.h:36
double startX() const noexcept
Definition: FitDomain.h:41
std::pair< double, double > xLimits() const
Definition: FitDomain.cpp:355
Attribute is a non-fitting parameter.
Definition: IFunction.h:282
Base MatrixWorkspace Abstract Class.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
EXPORT_OPT_MANTIDQT_COMMON bool isNumber(std::string const &str)
Checks if a string contains a number, or whether it contains characters.
EXPORT_OPT_MANTIDQT_COMMON std::pair< QString, std::pair< QString, QString > > splitConstraintString(const std::string &constraint)
Split a constraint definition into a parameter name and a pair of bounds, for example -1 < f0....
EXPORT_OPT_MANTIDQT_COMMON std::size_t getFunctionIndexAt(std::string const &parameter, std::size_t const &index)
Returns the function index found at index of a parameter.
EXPORT_OPT_MANTIDQT_COMMON std::vector< std::string > splitStringBy(std::string const &str, std::string const &delimiter)
Splits the string by the given delimiters.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
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
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)
IntImplementationType value
Definition: IndexTypes.h:26