diff --git a/Framework/PythonInterface/mantid/api/src/FitFunctions/IFunctionAdapter.cpp b/Framework/PythonInterface/mantid/api/src/FitFunctions/IFunctionAdapter.cpp index 94d69465072d..37457ea0db94 100644 --- a/Framework/PythonInterface/mantid/api/src/FitFunctions/IFunctionAdapter.cpp +++ b/Framework/PythonInterface/mantid/api/src/FitFunctions/IFunctionAdapter.cpp @@ -203,11 +203,12 @@ void IFunctionAdapter::setAttributePythonValue(IFunction &self, const std::strin * @param attr An attribute object */ void IFunctionAdapter::setAttribute(const std::string &attName, const Attribute &attr) { - try { + auto self = getSelf(); + if (typeHasAttribute(self, "setAttributeValue")) { object value = object(handle<>(getAttributeValue(*this, attr))); - callMethod(getSelf(), "setAttributeValue", attName, value); + callMethod(self, "setAttributeValue", attName, value); storeAttributeValue(attName, attr); - } catch (UndefinedAttributeError &) { + } else { IFunction::setAttribute(attName, attr); } } diff --git a/Framework/PythonInterface/plugins/functions/TeixeiraWaterIqt.py b/Framework/PythonInterface/plugins/functions/TeixeiraWaterIqt.py index 535a10a8dbf3..83ab6f0ae69b 100644 --- a/Framework/PythonInterface/plugins/functions/TeixeiraWaterIqt.py +++ b/Framework/PythonInterface/plugins/functions/TeixeiraWaterIqt.py @@ -5,16 +5,10 @@ # & Institut Laue - Langevin # SPDX - License - Identifier: GPL - 3.0 + # pylint: disable=no-init,invalid-name - -""" -@author Spencer Howells, ISIS -@date December 05, 2013 -""" - import numpy as np from mantid.api import IFunction1D, FunctionFactory -from scipy.special import spherical_jn # bessel +from scipy.special import spherical_jn class TeixeiraWaterIqt(IFunction1D): @@ -32,46 +26,25 @@ def init(self): self.declareAttribute("Q", 0.4) self.declareAttribute("a", 0.98) - def setAttributeValue(self, name, value): - if name == "Q": - self.Q = value - if name == "a": - self.radius = value - def function1D(self, xvals): amp = self.getParameterValue("Amp") tau1 = self.getParameterValue("Tau1") gamma = self.getParameterValue("Gamma") + + q_value = self.getAttributeValue("Q") + radius = self.getAttributeValue("a") + xvals = np.array(xvals) - qr = np.array(self.Q * self.radius) + qr = np.array(q_value * radius) j0 = spherical_jn(0, qr) j1 = spherical_jn(1, qr) j2 = spherical_jn(2, qr) with np.errstate(divide="ignore"): - rotational = j0 * j0 + 3 * j1 * j1 * np.exp(-xvals / (3 * tau1)) + 5 * j2 * j2 * np.exp(-xvals / tau1) + rotational = np.square(j0) + 3 * np.square(j1) * np.exp(-xvals / (3 * tau1)) + 5 * np.square(j2) * np.exp(-xvals / tau1) translational = np.exp(-gamma * xvals) iqt = amp * rotational * translational return iqt - def functionDeriv1D(self, xvals, jacobian): - amp = self.getParameterValue("Amp") - tau1 = self.getParameterValue("Tau1") - gamma = self.getParameterValue("Gamma") - - qr = np.array(self.Q * self.radius) - j0 = spherical_jn(0, qr) - j1 = spherical_jn(1, qr) - j2 = spherical_jn(2, qr) - with np.errstate(divide="ignore"): - for i, x in enumerate(xvals, start=0): - rotational = j0 * j0 + 3 * j1 * j1 * np.exp(-x / (3 * tau1)) + 5 * j2 * j2 * np.exp(-x / tau1) - translational = np.exp(-gamma * x) - partial_tau = (x / np.square(tau1)) * (j1 * j1 * np.exp(-x / (3 * tau1)) + 5 * j2 * j2 * np.exp(-x / tau1)) - jacobian.set(i, 0, rotational * translational) - jacobian.set(i, 1, amp * rotational * partial_tau) - jacobian.set(i, 2, -x * amp * rotational * translational) - -# Required to have Mantid recognise the new function FunctionFactory.subscribe(TeixeiraWaterIqt) diff --git a/docs/source/release/v6.10.0/Inelastic/New_features/36502.rst b/docs/source/release/v6.10.0/Inelastic/New_features/36502.rst index 307d11ce3025..ee7b8841219d 100644 --- a/docs/source/release/v6.10.0/Inelastic/New_features/36502.rst +++ b/docs/source/release/v6.10.0/Inelastic/New_features/36502.rst @@ -1 +1 @@ -- Added new `TeixeiraWaterIqt` fitting function, to fit linewidth and molecular residence time in intermediate scattering functions with Teixeira's model for water. \ No newline at end of file +- Added new `TeixeiraWaterIqt` fitting function, to fit linewidth and molecular residence time in intermediate scattering functions with Teixeira's model for water. This is now available in the IqtFit tab of the :ref:`QENS Fitting ` interface. diff --git a/qt/python/mantidqt/mantidqt/_common.sip b/qt/python/mantidqt/mantidqt/_common.sip index 24583c80184b..57fb824407ff 100644 --- a/qt/python/mantidqt/mantidqt/_common.sip +++ b/qt/python/mantidqt/mantidqt/_common.sip @@ -351,7 +351,7 @@ public: UserSubWindow *createSubWindow( const QString &interface_name, - QWidget *parent = nullptr); + QWidget *parent = nullptr) throw(std::exception); QStringList getUserSubWindowKeys() const; void showHelpPage(const QString &url=QString()); diff --git a/qt/scientific_interfaces/Inelastic/QENSFitting/FitTabConstants.h b/qt/scientific_interfaces/Inelastic/QENSFitting/FitTabConstants.h index 65869f518047..6eea73c572cb 100644 --- a/qt/scientific_interfaces/Inelastic/QENSFitting/FitTabConstants.h +++ b/qt/scientific_interfaces/Inelastic/QENSFitting/FitTabConstants.h @@ -23,6 +23,7 @@ static const auto FUNCTION_STRINGS = {"Lorentzian", "L"}, {"StretchedExpFT", "SFT"}, {"TeixeiraWater", "TxWater"}, + {"TeixeiraWaterIqt", "TxWater"}, {"TeixeiraWaterSQE", "TxWater"}, {"FickDiffusionSQE", "FickDiff"}, {"ChudleyElliotSQE", "ChudElliot"}, diff --git a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ConvFunctionTemplateModel.cpp b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ConvFunctionTemplateModel.cpp index 116222dc0f72..ae3f44cb81c0 100644 --- a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ConvFunctionTemplateModel.cpp +++ b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ConvFunctionTemplateModel.cpp @@ -159,8 +159,6 @@ void ConvFunctionTemplateModel::checkSingleFunction(const IFunction_sptr &fun, b } } -void ConvFunctionTemplateModel::setQValues(const std::vector &qValues) { m_qValues = qValues; } - void ConvFunctionTemplateModel::addFunction(std::string const &prefix, std::string const &funStr) { if (!prefix.empty()) throw std::runtime_error("Function doesn't have member function with prefix " + prefix); diff --git a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ConvFunctionTemplateModel.h b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ConvFunctionTemplateModel.h index 2fbf58840864..26bfd126845a 100644 --- a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ConvFunctionTemplateModel.h +++ b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ConvFunctionTemplateModel.h @@ -41,7 +41,6 @@ class MANTIDQT_INELASTIC_DLL ConvFunctionTemplateModel : public MultiFunctionTem std::map getSubTypes() const override; std::string setBackgroundA0(double value) override; void setResolution(const std::vector> &fitResolutions) override; - void setQValues(const std::vector &qValues) override; bool hasDeltaFunction() const; bool hasTempCorrection() const; @@ -55,7 +54,7 @@ class MANTIDQT_INELASTIC_DLL ConvFunctionTemplateModel : public MultiFunctionTem void applyParameterFunction(const std::function ¶mFun) const override; void clearData(); - void setModel(); + void setModel() override; std::optional getLor1Prefix() const; std::optional getLor2Prefix() const; @@ -63,6 +62,7 @@ class MANTIDQT_INELASTIC_DLL ConvFunctionTemplateModel : public MultiFunctionTem std::optional getDeltaPrefix() const; std::optional getBackgroundPrefix() const; + std::string buildFunctionString(int const domainIndex) const override { return ""; } std::string buildLorentzianFunctionString() const; std::string buildTeixeiraFunctionString() const; std::string buildFickFunctionString() const; @@ -96,7 +96,6 @@ class MANTIDQT_INELASTIC_DLL ConvFunctionTemplateModel : public MultiFunctionTem BackgroundSubType m_backgroundSubtype; std::vector> m_fitResolutions; - std::vector m_qValues; bool m_isQDependentFunction = false; }; diff --git a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/FitTypes.cpp b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/FitTypes.cpp index 8d5116cf1037..8cf8e319c8f7 100644 --- a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/FitTypes.cpp +++ b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/FitTypes.cpp @@ -25,6 +25,8 @@ std::map TemplateSubTypeImpl diff --git a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/FitTypes.h b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/FitTypes.h index 60747ff8c64c..c7ad097ac663 100644 --- a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/FitTypes.h +++ b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/FitTypes.h @@ -23,7 +23,7 @@ enum class ExponentialType { TwoExponentials, }; -enum class FitType { None, StretchExponential }; +enum class FitType { None, StretchExponential, TeixeiraWaterIqt }; enum class BackgroundType { None, Flat }; diff --git a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/IqtFunctionTemplateModel.cpp b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/IqtFunctionTemplateModel.cpp index b332b5d96c1e..7de3706b7477 100644 --- a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/IqtFunctionTemplateModel.cpp +++ b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/IqtFunctionTemplateModel.cpp @@ -64,11 +64,8 @@ void IqtFunctionTemplateModel::clearData() { } void IqtFunctionTemplateModel::setModel() { - m_model->setFunctionString(buildFunctionString()); - m_model->setGlobalParameters(makeGlobalList()); - + MultiFunctionTemplateModel::setModel(); tieIntensities(); - estimateFunctionParameters(); } @@ -82,6 +79,8 @@ void IqtFunctionTemplateModel::setFunction(IFunction_sptr fun) { m_exponentialType = ExponentialType::OneExponential; } else if (name == "StretchExp") { m_fitType = FitType::StretchExponential; + } else if (name == "TeixeiraWaterIqt") { + m_fitType = FitType::TeixeiraWaterIqt; } else if (name == "FlatBackground") { m_backgroundType = BackgroundType::Flat; } else { @@ -91,7 +90,7 @@ void IqtFunctionTemplateModel::setFunction(IFunction_sptr fun) { return; } bool areExponentialsSet = false; - bool isStretchSet = false; + bool isFitTypeSet = false; bool isBackgroundSet = false; for (size_t i = 0; i < fun->nFunctions(); ++i) { auto f = fun->getFunction(i); @@ -107,19 +106,23 @@ void IqtFunctionTemplateModel::setFunction(IFunction_sptr fun) { areExponentialsSet = true; } } else if (name == "StretchExp") { - if (isStretchSet) { + if (isFitTypeSet) { throw std::runtime_error("Function has wrong structure."); } m_fitType = FitType::StretchExponential; areExponentialsSet = true; - isStretchSet = true; + isFitTypeSet = true; + } else if (name == "TeixeiraWaterIqt") { + m_fitType = FitType::TeixeiraWaterIqt; + areExponentialsSet = true; + isFitTypeSet = true; } else if (name == "FlatBackground") { if (isBackgroundSet) { throw std::runtime_error("Function has wrong structure."); } m_backgroundType = BackgroundType::Flat; areExponentialsSet = true; - isStretchSet = true; + isFitTypeSet = true; isBackgroundSet = true; } else { clear(); @@ -146,10 +149,15 @@ void IqtFunctionTemplateModel::addFunction(std::string const &prefix, std::strin newPrefix = *getExp1Prefix(); } } else if (name == "StretchExp") { - if (hasStretchExponential()) + if (hasFitType(FitType::StretchExponential)) throw std::runtime_error("Cannot add more stretched exponentials."); m_fitType = FitType::StretchExponential; - newPrefix = *getStretchPrefix(); + newPrefix = *getFitTypePrefix(m_fitType); + } else if (name == "TeixeiraWaterIqt") { + if (hasFitType(FitType::TeixeiraWaterIqt)) + throw std::runtime_error("Cannot add another TeixeiraWaterIqt function."); + m_fitType = FitType::TeixeiraWaterIqt; + newPrefix = *getFitTypePrefix(m_fitType); } else if (name == "FlatBackground") { if (hasBackground()) throw std::runtime_error("Cannot add more backgrounds."); @@ -213,7 +221,7 @@ void IqtFunctionTemplateModel::removeFunction(std::string const &prefix) { m_exponentialType = ExponentialType::OneExponential; return; } - prefix1 = getStretchPrefix(); + prefix1 = getFitTypePrefix(m_fitType); if (prefix1 && *prefix1 == prefix) { m_fitType = FitType::None; return; @@ -230,13 +238,14 @@ int IqtFunctionTemplateModel::numberOfExponentials() const { return static_cast< bool IqtFunctionTemplateModel::hasExponential() const { return m_exponentialType != ExponentialType::None; } -bool IqtFunctionTemplateModel::hasStretchExponential() const { return m_fitType == FitType::StretchExponential; } +bool IqtFunctionTemplateModel::hasFitType() const { return m_fitType != FitType::None; } + +bool IqtFunctionTemplateModel::hasFitType(FitType fitType) const { return m_fitType == fitType; } void IqtFunctionTemplateModel::removeBackground() { auto oldValues = getCurrentValues(); m_backgroundType = BackgroundType::None; - m_model->setFunctionString(buildFunctionString()); - m_model->setGlobalParameters(makeGlobalList()); + setModel(); setCurrentValues(oldValues); } @@ -278,8 +287,6 @@ void IqtFunctionTemplateModel::setResolution(const std::vector &qValues) { (void)qValues; } - void IqtFunctionTemplateModel::tieIntensities() { auto heightName = getParameterName(ParamID::STRETCH_HEIGHT); if (!heightName) @@ -299,7 +306,9 @@ std::optional IqtFunctionTemplateModel::getPrefix(ParamID name) con } else if (name <= ParamID::EXP2_LIFETIME) { return getExp2Prefix(); } else if (name <= ParamID::STRETCH_STRETCHING) { - return getStretchPrefix(); + return getFitTypePrefix(FitType::StretchExponential); + } else if (name <= ParamID::TWI_GAMMA) { + return getFitTypePrefix(FitType::TeixeiraWaterIqt); } else { return getBackgroundPrefix(); } @@ -314,11 +323,16 @@ void IqtFunctionTemplateModel::applyParameterFunction(const std::function0,0(m_qValues.size()) ? m_qValues[domainIndex] : 0.4; + return "name=TeixeiraWaterIqt,Q=" + std::to_string(qValue) + + ",Amp=1,Tau1=0.05,Gamma=1.2,constraints=(Amp>" + "0,Tau1>0,Gamma>0)"; +} + std::string IqtFunctionTemplateModel::buildBackgroundFunctionString() const { return "name=FlatBackground,A0=0,constraints=(A0>0)"; } -std::string IqtFunctionTemplateModel::buildFunctionString() const { +std::string IqtFunctionTemplateModel::buildFunctionString(int const domainIndex) const { QStringList functions; if (hasExponential()) { functions << QString::fromStdString(buildExpDecayFunctionString()); @@ -345,9 +366,12 @@ std::string IqtFunctionTemplateModel::buildFunctionString() const { if (numberOfExponentials() > 1) { functions << QString::fromStdString(buildExpDecayFunctionString()); } - if (hasStretchExponential()) { + if (hasFitType(FitType::StretchExponential)) { functions << QString::fromStdString(buildStretchExpFunctionString()); } + if (hasFitType(FitType::TeixeiraWaterIqt)) { + functions << QString::fromStdString(buildTeixeiraWaterIqtFunctionString(domainIndex)); + } if (hasBackground()) { functions << QString::fromStdString(buildBackgroundFunctionString()); } @@ -357,7 +381,7 @@ std::string IqtFunctionTemplateModel::buildFunctionString() const { std::optional IqtFunctionTemplateModel::getExp1Prefix() const { if (!hasExponential()) return std::optional(); - if (numberOfExponentials() == 1 && !hasStretchExponential() && !hasBackground()) + if (numberOfExponentials() == 1 && !hasFitType() && !hasBackground()) return std::string(""); return std::string("f0."); } @@ -368,8 +392,8 @@ std::optional IqtFunctionTemplateModel::getExp2Prefix() const { return std::string("f1."); } -std::optional IqtFunctionTemplateModel::getStretchPrefix() const { - if (!hasStretchExponential()) +std::optional IqtFunctionTemplateModel::getFitTypePrefix(FitType fitType) const { + if (!hasFitType(fitType)) return std::optional(); if (!hasExponential() && !hasBackground()) return std::string(""); @@ -379,9 +403,9 @@ std::optional IqtFunctionTemplateModel::getStretchPrefix() const { std::optional IqtFunctionTemplateModel::getBackgroundPrefix() const { if (!hasBackground()) return std::optional(); - if (!hasExponential() && !hasStretchExponential()) + if (!hasExponential() && !hasFitType()) return std::string(""); - return "f" + std::to_string(numberOfExponentials() + (hasStretchExponential() ? 1 : 0)) + "."; + return "f" + std::to_string(numberOfExponentials() + (hasFitType() ? 1 : 0)) + "."; } } // namespace MantidQt::CustomInterfaces::Inelastic diff --git a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/IqtFunctionTemplateModel.h b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/IqtFunctionTemplateModel.h index b0990fd1c31f..9acb8a214522 100644 --- a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/IqtFunctionTemplateModel.h +++ b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/IqtFunctionTemplateModel.h @@ -36,11 +36,11 @@ class MANTIDQT_INELASTIC_DLL IqtFunctionTemplateModel : public MultiFunctionTemp std::map getSubTypes() const override; std::string setBackgroundA0(double value) override; void setResolution(const std::vector> &fitResolutions) override; - void setQValues(const std::vector &qValues) override; int numberOfExponentials() const; bool hasExponential() const; - bool hasStretchExponential() const; + bool hasFitType() const; + bool hasFitType(IqtTypes::FitType fitType) const; void removeBackground(); bool hasBackground() const; void tieIntensities(bool on); @@ -52,18 +52,19 @@ class MANTIDQT_INELASTIC_DLL IqtFunctionTemplateModel : public MultiFunctionTemp void applyParameterFunction(const std::function ¶mFun) const override; void clearData(); - void setModel(); + void setModel() override; void tieIntensities(); std::optional getExp1Prefix() const; std::optional getExp2Prefix() const; - std::optional getStretchPrefix() const; + std::optional getFitTypePrefix(IqtTypes::FitType fitType) const; std::optional getBackgroundPrefix() const; - std::string buildFunctionString() const; + std::string buildFunctionString(int const domainIndex) const override; std::string buildExpDecayFunctionString() const; std::string buildStretchExpFunctionString() const; + std::string buildTeixeiraWaterIqtFunctionString(int const domainIndex) const; std::string buildBackgroundFunctionString() const; IqtTypes::ExponentialType m_exponentialType = IqtTypes::ExponentialType::None; diff --git a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/MultiFunctionTemplateModel.cpp b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/MultiFunctionTemplateModel.cpp index 5d985ccffaed..ea5eba5eb293 100644 --- a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/MultiFunctionTemplateModel.cpp +++ b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/MultiFunctionTemplateModel.cpp @@ -6,8 +6,10 @@ // SPDX - License - Identifier: GPL - 3.0 + #include "MultiFunctionTemplateModel.h" +#include "MantidAPI/FunctionFactory.h" #include "MantidAPI/IFunction.h" #include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/MultiDomainFunction.h" namespace MantidQt::CustomInterfaces::Inelastic { @@ -51,7 +53,10 @@ std::string MultiFunctionTemplateModel::getParameterDescription(std::string cons std::vector MultiFunctionTemplateModel::getParameterNames() const { return m_model->getParameterNames(); } -void MultiFunctionTemplateModel::setNumberDomains(int n) { m_model->setNumberDomains(n); } +void MultiFunctionTemplateModel::setNumberDomains(int n) { + m_model->setNumberDomains(n); + setModel(); +} int MultiFunctionTemplateModel::getNumberDomains() const { return m_model->getNumberDomains(); } @@ -175,6 +180,8 @@ void MultiFunctionTemplateModel::setGlobalParameterValue(std::string const ¶ m_model->setGlobalParameterValue(parameterName, value); } +void MultiFunctionTemplateModel::setQValues(const std::vector &qValues) { m_qValues = qValues; } + void MultiFunctionTemplateModel::updateParameterEstimationData(DataForParameterEstimationCollection &&data) { m_estimationData = std::move(data); } @@ -204,6 +211,24 @@ std::map MultiFunctionTemplateModel::getParameterNameMap() con return out; } +void MultiFunctionTemplateModel::setModel() { + auto multiDomainFunction = std::make_shared(); + + for (int i = 0; i < m_model->getNumberDomains(); ++i) { + auto domainFunctionString = buildFunctionString(i); + if (domainFunctionString.empty()) { + break; + } + auto singleDomainFunction = FunctionFactory::Instance().createInitialized(domainFunctionString); + multiDomainFunction->addFunction(std::move(singleDomainFunction)); + multiDomainFunction->setDomainIndex(i, i); + } + + m_model->setFunction(std::move(multiDomainFunction)); + + m_model->setGlobalParameters(makeGlobalList()); +} + std::vector MultiFunctionTemplateModel::makeGlobalList() const { std::vector globals; for (auto const id : m_globals) { diff --git a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/MultiFunctionTemplateModel.h b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/MultiFunctionTemplateModel.h index 80f9f7e3de72..129b241a8b43 100644 --- a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/MultiFunctionTemplateModel.h +++ b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/MultiFunctionTemplateModel.h @@ -76,6 +76,8 @@ class MANTIDQT_INELASTIC_DLL MultiFunctionTemplateModel : public IFunctionModel virtual void setSubType(std::size_t subTypeIndex, int typeIndex) = 0; virtual std::map getSubTypes() const = 0; + void setQValues(const std::vector &qValues) override; + virtual EstimationDataSelector getEstimationDataSelector() const = 0; void updateParameterEstimationData(DataForParameterEstimationCollection &&data); void estimateFunctionParameters(); @@ -85,6 +87,9 @@ class MANTIDQT_INELASTIC_DLL MultiFunctionTemplateModel : public IFunctionModel std::map getParameterNameMap() const; protected: + virtual void setModel(); + virtual std::string buildFunctionString(int const domainIndex) const = 0; + void setParameter(ParamID name, double value); std::optional getParameterName(ParamID name) const; void setCurrentValues(const std::map &); @@ -93,6 +98,8 @@ class MANTIDQT_INELASTIC_DLL MultiFunctionTemplateModel : public IFunctionModel std::unique_ptr m_model; QList m_globals; + std::vector m_qValues; + private: double getParameter(ParamID name) const; double getParameterError(ParamID name) const; diff --git a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ParamID.h b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ParamID.h index bf2f1d87b90e..0bd9a2260e26 100644 --- a/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ParamID.h +++ b/qt/scientific_interfaces/Inelastic/QENSFitting/FunctionBrowser/ParamID.h @@ -23,6 +23,9 @@ enum class ParamID { STRETCH_HEIGHT, STRETCH_LIFETIME, STRETCH_STRETCHING, + TWI_AMPLITUDE, + TWI_TAU, + TWI_GAMMA, LOR1_AMPLITUDE, LOR1_PEAKCENTRE, LOR1_FWHM, @@ -96,6 +99,9 @@ static std::map g_paramName{ {ParamID::STRETCH_HEIGHT, "Height"}, {ParamID::STRETCH_LIFETIME, "Lifetime"}, {ParamID::STRETCH_STRETCHING, "Stretching"}, + {ParamID::TWI_AMPLITUDE, "Amp"}, + {ParamID::TWI_TAU, "Tau1"}, + {ParamID::TWI_GAMMA, "Gamma"}, {ParamID::LOR1_AMPLITUDE, "Amplitude"}, {ParamID::LOR1_PEAKCENTRE, "PeakCentre"}, {ParamID::LOR1_FWHM, "FWHM"}, diff --git a/qt/widgets/common/src/FunctionModel.cpp b/qt/widgets/common/src/FunctionModel.cpp index f6e2fd703959..c2abdb4711d5 100644 --- a/qt/widgets/common/src/FunctionModel.cpp +++ b/qt/widgets/common/src/FunctionModel.cpp @@ -174,23 +174,23 @@ void FunctionModel::setParameterError(std::string const ¶meterName, double v } double FunctionModel::getParameter(std::string const ¶meterName) const { - return getCurrentFunction()->getParameter(parameterName); + auto const fun = getCurrentFunction(); + return fun && fun->hasParameter(parameterName) ? fun->getParameter(parameterName) : 0.0; } IFunction::Attribute FunctionModel::getAttribute(std::string const &attrName) const { - return getCurrentFunction()->getAttribute(attrName); + auto const fun = getCurrentFunction(); + return fun && fun->hasAttribute(attrName) ? fun->getAttribute(attrName) : IFunction::Attribute(); } double FunctionModel::getParameterError(std::string const ¶meterName) const { auto fun = getCurrentFunction(); - auto const index = fun->parameterIndex(parameterName); - return fun->getError(index); + return fun && fun->hasParameter(parameterName) ? fun->getError(fun->parameterIndex(parameterName)) : 0.0; } std::string FunctionModel::getParameterDescription(std::string const ¶meterName) const { auto fun = getCurrentFunction(); - auto const index = fun->parameterIndex(parameterName); - return fun->parameterDescription(index); + return fun && fun->hasParameter(parameterName) ? fun->parameterDescription(fun->parameterIndex(parameterName)) : ""; } bool FunctionModel::isParameterFixed(std::string const ¶meterName) const {