diff --git a/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.cpp b/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.cpp index d20eee0ee84f8f6822f522dc1563de4ab41f1fef..b573838327b69c7653d225aa2b789e497cdbe602 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.cpp +++ b/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.cpp @@ -138,8 +138,8 @@ QStringList IndirectFitPropertyBrowser::getLocalParameters() const { void IndirectFitPropertyBrowser::syncFullBrowserWithTemplate() { auto const fun = m_templateBrowser->getFunction(); - m_functionBrowser->setFunction(fun); if (fun) { + m_functionBrowser->setFunction(fun); m_functionBrowser->updateMultiDatasetParameters( *m_templateBrowser->getGlobalFunction()); m_functionBrowser->setGlobalParameters( @@ -151,8 +151,8 @@ void IndirectFitPropertyBrowser::syncFullBrowserWithTemplate() { void IndirectFitPropertyBrowser::syncTemplateBrowserWithFull() { auto const funStr = m_functionBrowser->getFunctionString(); - m_templateBrowser->setFunction(funStr); if (auto const fun = m_functionBrowser->getGlobalFunction()) { + m_templateBrowser->setFunction(funStr); m_templateBrowser->updateMultiDatasetParameters(*fun); m_templateBrowser->setGlobalParameters( m_functionBrowser->getGlobalParameters()); diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.cpp b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.cpp index 66f3f218bd3172d23e08b0d17dabe7cbead00da8..47d2d9b49528c6efedeafde3807fa5c5f616c1a8 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.cpp +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.cpp @@ -23,6 +23,7 @@ ConvFunctionModel::ConvFunctionModel() {} void ConvFunctionModel::clearData() { m_fitType = FitType::None; m_hasDeltaFunction = false; + m_hasTempCorrection = false; m_backgroundType = BackgroundType::None; m_model.clear(); } @@ -30,7 +31,10 @@ void ConvFunctionModel::clearData() { void ConvFunctionModel::setModel() { m_model.setModel(buildBackgroundFunctionString(), m_fitResolutions, buildPeaksFunctionString(), m_hasDeltaFunction, m_qValues, - m_isQDependentFunction); + m_isQDependentFunction, m_hasTempCorrection, m_tempValue); + if (m_hasTempCorrection && !m_globals.contains(ParamID::TEMPERATURE)) { + m_globals.push_back(ParamID::TEMPERATURE); + } m_model.setGlobalParameters(makeGlobalList()); } @@ -38,7 +42,6 @@ void ConvFunctionModel::setFunction(IFunction_sptr fun) { clearData(); if (!fun) return; - bool isBackgroundSet = false; if (fun->name() == "Convolution") { checkConvolution(fun); @@ -77,53 +80,57 @@ void ConvFunctionModel::checkConvolution(IFunction_sptr fun) { throw std::runtime_error("Function has wrong structure."); } isResolutionSet = true; - } else if (name == "CompositeFunction") { - checkComposite(innerFunction); - } else if (FitTypeStringToEnum.count(name) == 1) { - if (isFitTypeSet) { + } else if (name == "ProductFunction") { + if (innerFunction->getFunction(0)->name() != "UserFunction" || + innerFunction->getFunction(0)->nParams() != 1 || + !innerFunction->getFunction(0)->hasParameter("Temp")) { throw std::runtime_error("Function has wrong structure."); } - m_fitType = FitTypeStringToEnum[name]; - m_isQDependentFunction = FitTypeQDepends[m_fitType]; - isFitTypeSet = true; - } else if (name == "DeltaFunction") { - m_hasDeltaFunction = true; + m_hasTempCorrection = true; + if (boost::dynamic_pointer_cast<CompositeFunction>( + innerFunction->getFunction(1))) + checkConvolution(innerFunction->getFunction(1)); + else + checkSingleFunction(innerFunction->getFunction(1), isFitTypeSet); + } + + else if (name == "CompositeFunction") { + checkConvolution(innerFunction); } else { - clear(); - throw std::runtime_error("Function has wrong structure."); + checkSingleFunction(innerFunction, isFitTypeSet); } } } -void ConvFunctionModel::checkComposite(IFunction_sptr fun) { - bool isFitTypeSet = false; - for (size_t i = 0; i < fun->nFunctions(); ++i) { - auto innerFunction = fun->getFunction(i); - auto const name = innerFunction->name(); - if (name == "Lorentzian") { - if (isFitTypeSet && m_fitType != FitType::OneLorentzian) { - throw std::runtime_error("Function has wrong structure."); - } - if (isFitTypeSet) - m_fitType = FitType::TwoLorentzians; - else - m_fitType = FitType::OneLorentzian; - m_isQDependentFunction = false; - isFitTypeSet = true; - - } else if (FitTypeStringToEnum.count(name) == 1) { - if (isFitTypeSet) { - throw std::runtime_error("Function has wrong structure."); - } - m_fitType = FitTypeStringToEnum[name]; - m_isQDependentFunction = FitTypeQDepends[m_fitType]; - isFitTypeSet = true; - } else if (name == "DeltaFunction") { - m_hasDeltaFunction = true; - } else { - clear(); +void ConvFunctionModel::checkSingleFunction(IFunction_sptr fun, + bool &isFitTypeSet) { + assert(fun->nFunctions() == 0); + auto const name = fun->name(); + if (name == "Lorentzian") { + if (isFitTypeSet && m_fitType != FitType::OneLorentzian) { throw std::runtime_error("Function has wrong structure."); } + if (isFitTypeSet) + m_fitType = FitType::TwoLorentzians; + else + m_fitType = FitType::OneLorentzian; + m_isQDependentFunction = false; + isFitTypeSet = true; + + } else if (FitTypeStringToEnum.count(name) == 1) { + if (isFitTypeSet) { + throw std::runtime_error( + "Function has wrong structure. More than one fit type set"); + } + m_fitType = FitTypeStringToEnum[name]; + m_isQDependentFunction = FitTypeQDepends[m_fitType]; + isFitTypeSet = true; + } else if (name == "DeltaFunction") { + m_hasDeltaFunction = true; + } else { + clear(); + throw std::runtime_error( + "Function has wrong structure. Function not recognized"); } } @@ -225,6 +232,20 @@ void ConvFunctionModel::setDeltaFunction(bool on) { setCurrentValues(oldValues); } +void ConvFunctionModel::setTempCorrection(bool on, double value) { + auto oldValues = getCurrentValues(); + m_hasTempCorrection = on; + m_tempValue = value; + setModel(); + setCurrentValues(oldValues); +} + +bool ConvFunctionModel::hasTempCorrection() const { + return m_hasTempCorrection; +} + +double ConvFunctionModel::getTempValue() const { return m_tempValue; } + bool ConvFunctionModel::hasDeltaFunction() const { return m_hasDeltaFunction; } void ConvFunctionModel::setBackground(BackgroundType bgType) { @@ -542,6 +563,8 @@ boost::optional<QString> ConvFunctionModel::getPrefix(ParamID name) const { return m_model.backgroundPrefix(); } else if (name == ParamID::DELTA_HEIGHT) { return m_model.deltaFunctionPrefix(); + } else if (name == ParamID::TEMPERATURE) { + return m_model.tempFunctionPrefix(); } else { auto const prefixes = m_model.peakPrefixes(); if (!prefixes) @@ -590,6 +613,9 @@ void ConvFunctionModel::applyParameterFunction( applyToFitType(m_fitType, paramFun); applyToBackground(m_backgroundType, paramFun); applyToDelta(m_hasDeltaFunction, paramFun); + auto tempType = m_hasTempCorrection ? TempCorrectionType::Exponential + : TempCorrectionType::None; + applyToTemp(tempType, paramFun); } boost::optional<ParamID> diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.h b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.h index 1de886dbe3d2ad6af4e1d34e4cd5be51d9020088..f59e00c287896cfc6a57769e0f20c2e8032801d2 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.h +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.h @@ -84,6 +84,9 @@ public: void setFitType(FitType fitType); void setDeltaFunction(bool); bool hasDeltaFunction() const; + void setTempCorrection(bool, double value); + bool hasTempCorrection() const; + double getTempValue() const; void setBackground(BackgroundType bgType); void removeBackground(); bool hasBackground() const; @@ -129,12 +132,14 @@ private: QStringList makeGlobalList() const; int getNumberOfPeaks() const; void checkConvolution(IFunction_sptr fun); - void checkComposite(IFunction_sptr fun); + void checkSingleFunction(IFunction_sptr fun, bool &isFitTypeSet); ConvolutionFunctionModel m_model; FitType m_fitType = FitType::None; BackgroundType m_backgroundType = BackgroundType::None; bool m_hasDeltaFunction = false; + bool m_hasTempCorrection = false; + double m_tempValue = 100.0; DataForParameterEstimationCollection m_estimationData; QList<ParamID> m_globals; FitSubType m_fitSubType; diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.cpp b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.cpp index d8848097995675411882be2b7226df15b4170cf1..189d9768a6ec5bcdc61a72d9eb53fc3c5ae9df47 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.cpp +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.cpp @@ -57,9 +57,11 @@ void ConvTemplateBrowser::createProperties() { createFunctionParameterProperties(); createDeltaFunctionProperties(); + createTempCorrectionProperties(); m_browser->addProperty(m_subTypeProperties[0]); m_browser->addProperty(m_deltaFunctionOn); + m_browser->addProperty(m_tempCorrectionOn); m_browser->addProperty(m_subTypeProperties[1]); m_parameterManager->blockSignals(false); @@ -111,8 +113,12 @@ void ConvTemplateBrowser::setGlobalParameters(const QStringList &globals) { void ConvTemplateBrowser::intChanged(QtProperty *) {} void ConvTemplateBrowser::boolChanged(QtProperty *prop) { + if (!m_emitBoolChange) + return; if (prop == m_deltaFunctionOn) { m_presenter.setDeltaFunction(m_boolManager->value(prop)); + } else if (prop == m_tempCorrectionOn) { + m_presenter.setTempCorrection(m_boolManager->value(prop)); } } @@ -121,8 +127,8 @@ void ConvTemplateBrowser::setQValues(const std::vector<double> &qValues) { } void ConvTemplateBrowser::addDeltaFunction() { + ScopedFalse _boolBlock(m_emitBoolChange); m_deltaFunctionOn->addSubProperty(m_deltaFunctionHeight); - ScopedFalse _false(m_emitBoolChange); m_boolManager->setValue(m_deltaFunctionOn, true); } @@ -132,7 +138,40 @@ void ConvTemplateBrowser::removeDeltaFunction() { m_boolManager->setValue(m_deltaFunctionOn, false); } +void ConvTemplateBrowser::addTempCorrection(double value) { + ScopedFalse _boolBlock(m_emitBoolChange); + + m_tempCorrectionOn->addSubProperty(m_temperature); + m_boolManager->setValue(m_tempCorrectionOn, true); + m_parameterManager->setValue(m_temperature, value); + m_parameterManager->setGlobal(m_temperature, true); +} + +void ConvTemplateBrowser::updateTemperatureCorrectionAndDelta( + bool tempCorrection, bool deltaFunction) { + ScopedFalse _boolBlock(m_emitBoolChange); + ScopedFalse _paramBlock(m_emitParameterValueChange); + + if (tempCorrection) + addTempCorrection(100.0); + else + removeTempCorrection(); + + if (deltaFunction) + addDeltaFunction(); + else + removeDeltaFunction(); +} + +void ConvTemplateBrowser::removeTempCorrection() { + m_tempCorrectionOn->removeSubProperty(m_temperature); + ScopedFalse _false(m_emitBoolChange); + m_boolManager->setValue(m_tempCorrectionOn, false); +} + void ConvTemplateBrowser::enumChanged(QtProperty *prop) { + if (!m_emitEnumChange) + return; auto const index = m_enumManager->value(prop); auto propIt = std::find(m_subTypeProperties.begin(), m_subTypeProperties.end(), prop); @@ -143,10 +182,7 @@ void ConvTemplateBrowser::enumChanged(QtProperty *prop) { } } -void ConvTemplateBrowser::globalChanged(QtProperty *, const QString &name, - bool on) { - std::cerr << "Global " << name.toStdString() << ' ' << on << std::endl; -} +void ConvTemplateBrowser::globalChanged(QtProperty *, const QString &, bool) {} void ConvTemplateBrowser::parameterChanged(QtProperty *prop) { auto isGlobal = m_parameterManager->isGlobal(prop); @@ -199,9 +235,7 @@ void ConvTemplateBrowser::setErrorsEnabled(bool enabled) { void ConvTemplateBrowser::clear() {} -void ConvTemplateBrowser::popupMenu(const QPoint &) { - std::cerr << "Popup" << std::endl; -} +void ConvTemplateBrowser::popupMenu(const QPoint &) {} void ConvTemplateBrowser::setParameterPropertyValue(QtProperty *prop, double value, @@ -260,6 +294,11 @@ void ConvTemplateBrowser::createFunctionParameterProperties() { } } +void ConvTemplateBrowser::setEnum(size_t subTypeIndex, int enumIndex) { + ScopedFalse _false(m_emitEnumChange); + m_enumManager->setValue(m_subTypeProperties[subTypeIndex], enumIndex); +} + void ConvTemplateBrowser::createDeltaFunctionProperties() { m_deltaFunctionOn = m_boolManager->addProperty("Delta Function"); m_deltaFunctionHeight = @@ -271,6 +310,14 @@ void ConvTemplateBrowser::createDeltaFunctionProperties() { m_parameterReverseMap[ParamID::DELTA_HEIGHT] = m_deltaFunctionHeight; } +void ConvTemplateBrowser::createTempCorrectionProperties() { + m_tempCorrectionOn = m_boolManager->addProperty("Temp Correction"); + m_temperature = m_parameterManager->addProperty("Temperature"); + m_parameterManager->setDescription(m_temperature, "Temperature"); + m_parameterMap[m_temperature] = ParamID::TEMPERATURE; + m_parameterReverseMap[ParamID::TEMPERATURE] = m_temperature; +} + void ConvTemplateBrowser::setSubType(size_t subTypeIndex, int typeIndex) { auto subTypeProp = m_subTypeProperties[subTypeIndex]; auto ¤tParameters = m_currentSubTypeParameters[subTypeIndex]; diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.h b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.h index ac0ac891c0a47ef31f793d83ed422753f7b1dde6..e4a8b8655dec4e037e04c755399d0fed1a78f085 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.h +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.h @@ -58,7 +58,12 @@ public: const std::vector<std::pair<std::string, int>> &fitResolutions) override; void addDeltaFunction(); void removeDeltaFunction(); + void addTempCorrection(double value); + void removeTempCorrection(); void setQValues(const std::vector<double> &qValues) override; + void setEnum(size_t subTypeIndex, int fitType); + void updateTemperatureCorrectionAndDelta(bool tempCorrection, + bool deltaFunction); protected slots: void intChanged(QtProperty *) override; @@ -75,6 +80,7 @@ private: void setGlobalParametersQuiet(const QStringList &globals); void createFunctionParameterProperties(); void createDeltaFunctionProperties(); + void createTempCorrectionProperties(); void setSubType(size_t subTypeIndex, int typeIndex); void setParameterValueQuiet(ParamID id, double value, double error); @@ -88,6 +94,9 @@ private: QtProperty *m_deltaFunctionOn; QtProperty *m_deltaFunctionHeight; + QtProperty *m_tempCorrectionOn; + QtProperty *m_temperature; + QMap<QtProperty *, ParamID> m_parameterMap; QMap<ParamID, QtProperty *> m_parameterReverseMap; QMap<QtProperty *, QString> m_actualParameterNames; @@ -97,6 +106,7 @@ private: ConvTemplatePresenter m_presenter; bool m_emitParameterValueChange = true; bool m_emitBoolChange = true; + bool m_emitEnumChange = true; friend class ConvTemplatePresenter; }; diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.cpp b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.cpp index 5780b5f58a59171558113bb2e6971faf3405292f..febb6ed1976a9747466f6d1aab7168b85ff12333 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.cpp +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.cpp @@ -7,8 +7,9 @@ #include "ConvTemplatePresenter.h" #include "ConvTemplateBrowser.h" #include "MantidQtWidgets/Common/EditLocalParameterDialog.h" - +#include <QInputDialog> #include <cmath> +#include <float.h> namespace MantidQt { namespace CustomInterfaces { @@ -29,7 +30,7 @@ ConvTemplatePresenter::ConvTemplatePresenter(ConvTemplateBrowser *view) } void ConvTemplatePresenter::setSubType(size_t subTypeIndex, int typeIndex) { - if (subTypeIndex == 0) { + if (subTypeIndex == SubTypeIndex::Fit) { m_model.setFitType(static_cast<FitType>(typeIndex)); } else { m_model.setBackground(static_cast<BackgroundType>(typeIndex)); @@ -56,6 +57,30 @@ void ConvTemplatePresenter::setDeltaFunction(bool on) { emit functionStructureChanged(); } +void ConvTemplatePresenter::setTempCorrection(bool on) { + if (on == m_model.hasTempCorrection()) + return; + double temp = m_model.getTempValue(); + if (on) { + bool ok; + temp = QInputDialog::getDouble(m_view, "Temperature", "Set Temperature", + temp, 0.0, + std::numeric_limits<double>::max(), 3, &ok); + if (!ok) + return; + } + m_model.setTempCorrection(on, temp); + if (on) + m_view->addTempCorrection(temp); + else + m_view->removeTempCorrection(); + + setErrorsEnabled(false); + updateViewParameterNames(); + updateViewParameters(); + emit functionStructureChanged(); +} + void ConvTemplatePresenter::setNumberOfDatasets(int n) { m_model.setNumberDomains(n); } @@ -66,8 +91,17 @@ int ConvTemplatePresenter::getNumberOfDatasets() const { void ConvTemplatePresenter::setFunction(const QString &funStr) { m_model.setFunctionString(funStr); - m_view->setSubType(0, static_cast<int>(m_model.getFitType())); - m_view->setSubType(1, static_cast<int>(m_model.getBackgroundType())); + + m_view->updateTemperatureCorrectionAndDelta(m_model.hasTempCorrection(), + m_model.hasDeltaFunction()); + + m_view->setSubType(SubTypeIndex::Fit, static_cast<int>(m_model.getFitType())); + m_view->setSubType(SubTypeIndex::Background, + static_cast<int>(m_model.getBackgroundType())); + m_view->setEnum(SubTypeIndex::Fit, static_cast<int>(m_model.getFitType())); + m_view->setEnum(SubTypeIndex::Background, + static_cast<int>(m_model.getBackgroundType())); + setErrorsEnabled(false); updateViewParameterNames(); updateViewParameters(); @@ -96,9 +130,6 @@ QStringList ConvTemplatePresenter::getLocalParameters() const { void ConvTemplatePresenter::setGlobalParameters(const QStringList &globals) { m_model.setGlobalParameters(globals); - // if (m_model.hasStretchExponential()) { - // m_view->setGlobalParametersQuiet(globals); - //} } void ConvTemplatePresenter::setGlobal(const QString &parName, bool on) { diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.h b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.h index 1f9497dc4bece657b0cc5ac5b4c0b230cbc8aab3..43244ff21d8b3bafd3845b87e30a37accba2b3bc 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.h +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.h @@ -35,6 +35,7 @@ public: explicit ConvTemplatePresenter(ConvTemplateBrowser *view); void setSubType(size_t subTypeIndex, int typeIndex); void setDeltaFunction(bool); + void setTempCorrection(bool); void setNumberOfDatasets(int); int getNumberOfDatasets() const; int getCurrentDataset(); diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.cpp b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.cpp index d8ba2c649a8f4c8378f2c2cca6f61a9c18d97b94..b0450895a46ca4d6293e53bdb38350e930995ab9 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.cpp +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.cpp @@ -56,6 +56,7 @@ std::map<ParamID, QString> g_paramName{ {ParamID::TW_TAU, "Tau"}, {ParamID::TW_CENTRE, "Centre"}, {ParamID::DELTA_HEIGHT, "Height"}, + {ParamID::TEMPERATURE, "Temp"}, {ParamID::SE_HEIGHT, "Height"}, {ParamID::SE_TAU, "Tau"}, {ParamID::SE_BETA, "Beta"}, @@ -141,6 +142,17 @@ std::map<bool, TemplateSubTypeDescriptor> TemplateSubTypeImpl<bool>::g_typeMap{ {ParamID::DELTA_HEIGHT, ParamID::DELTA_HEIGHT}}}, }; +template <> +std::map<TempCorrectionType, TemplateSubTypeDescriptor> + TemplateSubTypeImpl<TempCorrectionType>::g_typeMap{ + {TempCorrectionType::None, + {"None", "", {ParamID::NONE, ParamID::NONE}}}, + {TempCorrectionType::Exponential, + {"Temp Correction", + "UserFunction", + {ParamID::TEMPERATURE, ParamID::TEMPERATURE}}}, + }; + QString paramName(ParamID id) { return g_paramName.at(id); } void applyToFitType(FitType fitType, @@ -163,6 +175,13 @@ void applyToDelta(bool hasDeltaFunction, paramFun); } +void applyToTemp(TempCorrectionType tempCorrectionType, + const std::function<void(ParamID)> ¶mFun) { + applyToParamIDRange(TempSubType::g_typeMap[tempCorrectionType].blocks.front(), + TempSubType::g_typeMap[tempCorrectionType].blocks.back(), + paramFun); +} + } // namespace ConvTypes } // namespace IDA } // namespace CustomInterfaces diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.h b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.h index 0479fbb1985c133343fc75fc4bcb7d7fa4a6b42c..e17ce6ae3e415b1b793c09733e2cc83860c4280c 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.h +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTypes.h @@ -42,6 +42,8 @@ extern std::unordered_map<std::string, FitType> FitTypeStringToEnum; enum class BackgroundType { None, Flat, Linear }; +enum class TempCorrectionType { None, Exponential }; + enum class ParamID { NONE, LOR1_AMPLITUDE, @@ -58,6 +60,7 @@ enum class ParamID { TW_TAU, TW_CENTRE, DELTA_HEIGHT, + TEMPERATURE, SE_HEIGHT, SE_TAU, SE_BETA, @@ -96,6 +99,11 @@ inline void applyToParamIDRange(ParamID from, ParamID to, fun(i); } +enum SubTypeIndex { + Fit = 0, + Background = 1, +}; + struct TemplateSubType { virtual QString name() const = 0; virtual QStringList getTypeNames() const = 0; @@ -188,12 +196,19 @@ struct DeltaSubType : public TemplateSubTypeImpl<bool> { QString name() const override { return "Delta"; } }; +struct TempSubType : public TemplateSubTypeImpl<TempCorrectionType> { + QString name() const override { return "TempCorrection"; } +}; + void applyToFitType(FitType fitType, const std::function<void(ParamID)> ¶mFun); void applyToBackground(BackgroundType bgType, const std::function<void(ParamID)> ¶mFun); void applyToDelta(bool deltaType, const std::function<void(ParamID)> ¶mFun); +void applyToTemp(TempCorrectionType tempCorrectionType, + const std::function<void(ParamID)> ¶mFun); + } // namespace ConvTypes } // namespace IDA } // namespace CustomInterfaces diff --git a/qt/scientific_interfaces/Indirect/test/ConvFunctionModelTest.h b/qt/scientific_interfaces/Indirect/test/ConvFunctionModelTest.h index f1902fe0041ac82493ff3723e35480c6f05892cf..67de1704411e0afe4f27b4a7f82a70c033e1b3d6 100644 --- a/qt/scientific_interfaces/Indirect/test/ConvFunctionModelTest.h +++ b/qt/scientific_interfaces/Indirect/test/ConvFunctionModelTest.h @@ -114,6 +114,63 @@ public: TS_ASSERT_THROWS(m_model->setFunction(fun), std::runtime_error &) } + void test_setFunction_does_not_throw_for_valid_temperature_function() { + m_model->setFitType(FitType::OneLorentzian); + m_model->setTempCorrection(true, 100.0); + auto func = m_model->getFitFunction(); + + m_model->setFunction(func); + + TS_ASSERT_EQUALS(m_model->getCurrentFunction()->asString(), + func->asString()) + TS_ASSERT_EQUALS(m_model->getBackgroundType(), BackgroundType::None); + TS_ASSERT_EQUALS(m_model->getFitType(), FitType::OneLorentzian); + } + + void + test_setFunction_does_not_throw_for_valid_temperature_function_with_delta() { + m_model->setFitType(FitType::OneLorentzian); + m_model->setTempCorrection(true, 100.0); + m_model->setDeltaFunction(true); + auto func = m_model->getFitFunction(); + + m_model->setFunction(func); + + TS_ASSERT_EQUALS(m_model->getCurrentFunction()->asString(), + func->asString()) + TS_ASSERT_EQUALS(m_model->getBackgroundType(), BackgroundType::None); + TS_ASSERT_EQUALS(m_model->getFitType(), FitType::OneLorentzian); + } + + void + test_setFunction_does_not_throw_for_valid_two_lorenztian_temperature_function() { + m_model->setFitType(FitType::TwoLorentzians); + m_model->setTempCorrection(true, 100.0); + auto func = m_model->getFitFunction(); + + m_model->setFunction(func); + + TS_ASSERT_EQUALS(m_model->getCurrentFunction()->asString(), + func->asString()) + TS_ASSERT_EQUALS(m_model->getBackgroundType(), BackgroundType::None); + TS_ASSERT_EQUALS(m_model->getFitType(), FitType::TwoLorentzians); + } + + void + test_setFunction_does_not_throw_for_valid_two_lorenztian_temperature_function_with_delta() { + m_model->setFitType(FitType::TwoLorentzians); + m_model->setTempCorrection(true, 100.0); + m_model->setDeltaFunction(true); + auto func = m_model->getFitFunction(); + + m_model->setFunction(func); + + TS_ASSERT_EQUALS(m_model->getCurrentFunction()->asString(), + func->asString()); + TS_ASSERT_EQUALS(m_model->getBackgroundType(), BackgroundType::None); + TS_ASSERT_EQUALS(m_model->getFitType(), FitType::TwoLorentzians); + } + private: std::unique_ptr<MantidQt::CustomInterfaces::IDA::ConvFunctionModel> m_model; }; diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h b/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h index c083fe01a12a9e4c0054ad26b4ec8692d750b655..0785824b87ec74fa1b14df0d09977fdd05c54e14 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h @@ -29,7 +29,8 @@ public: setModel(const std::string &background, const std::vector<std::pair<std::string, int>> &resolutionWorkspaces, const std::string &peaks, bool hasDeltaFunction, - const std::vector<double> &qValues, const bool isQDependent); + const std::vector<double> &qValues, const bool isQDependent, + bool hasTempCorrection, double tempValue); boost::optional<QString> backgroundPrefix() const { return m_backgroundPrefix; } @@ -39,16 +40,37 @@ public: boost::optional<QString> deltaFunctionPrefix() const { return m_deltaFunctionPrefix; } + boost::optional<QString> tempFunctionPrefix() const { + return m_tempFunctionPrefix; + } boost::optional<QStringList> peakPrefixes() const { return m_peakPrefixes; } std::string resolutionWorkspace() const { return m_resolutionWorkspace; } int resolutionWorkspaceIndex() const { return m_resolutionWorkspaceIndex; } private: void findComponentPrefixes(); - void findConvolutionPrefixes(const IFunction_sptr &fun); + // void findConvolutionPrefixes(const IFunction_sptr &fun); + void iterateThroughFunction(IFunction *func, const QString &prefix); + void setPrefix(IFunction *func, const QString &prefix); + CompositeFunction_sptr createInnerFunction(std::string peaksFunction, + bool hasDeltaFunction, + bool isQDependent, double q, + bool hasTempCorrection, + double tempValue); + CompositeFunction_sptr addTempCorrection(CompositeFunction_sptr peaksFunction, + double tempValue); + IFunction_sptr createTemperatureCorrection(double correction); + CompositeFunction_sptr + createConvolutionFunction(IFunction_sptr resolutionFunction, + IFunction_sptr innerFunction); + IFunction_sptr createResolutionFunction(std::string workspaceName, + int workspaceIndex); + CompositeFunction_sptr addBackground(CompositeFunction_sptr domainFunction, + std::string background); boost::optional<QString> m_backgroundPrefix; boost::optional<QString> m_convolutionPrefix; boost::optional<QString> m_deltaFunctionPrefix; + boost::optional<QString> m_tempFunctionPrefix; boost::optional<QStringList> m_peakPrefixes; std::string m_resolutionWorkspace; int m_resolutionWorkspaceIndex; diff --git a/qt/widgets/common/src/ConvolutionFunctionModel.cpp b/qt/widgets/common/src/ConvolutionFunctionModel.cpp index 346caa8139ea4d837c4ac0c3eda52889a6ec3d09..5f7d48597d85dbdd623518ee29e8eb7bde07c3a7 100644 --- a/qt/widgets/common/src/ConvolutionFunctionModel.cpp +++ b/qt/widgets/common/src/ConvolutionFunctionModel.cpp @@ -11,6 +11,7 @@ #include "MantidAPI/MultiDomainFunction.h" #include "MantidKernel/Logger.h" #include "MantidQtWidgets/Common/FunctionBrowser/FunctionBrowserUtils.h" +#include <iostream> namespace { Mantid::Kernel::Logger g_log("ConvolutionFunctionModel"); @@ -23,21 +24,29 @@ using namespace Mantid::API; namespace { -bool isConvolution(const IFunction_sptr &fun) { +bool isConvolution(const IFunction *fun) { return fun->name() == "Convolution"; } -bool isResolution(const IFunction_sptr &fun) { - return fun->name() == "Resolution"; -} +bool isResolution(const IFunction *fun) { return fun->name() == "Resolution"; } -bool isDeltaFunction(const IFunction_sptr &fun) { +bool isDeltaFunction(const IFunction *fun) { return fun->name() == "DeltaFunction"; } -bool isBackground(const IFunction_sptr &fun) { - return static_cast<bool>( - boost::dynamic_pointer_cast<const IBackgroundFunction>(fun)); +bool isTempFunction(const IFunction *fun) { + return fun->name() == "UserFunction"; +} + +bool isBackground(const IFunction *fun) { + return static_cast<bool>(dynamic_cast<const IBackgroundFunction *>(fun)); +} + +bool isPeakFunction(const IFunction *fun) { + if (dynamic_cast<const CompositeFunction *>(fun)) { + return false; + } + return true; } } // namespace @@ -68,126 +77,208 @@ void ConvolutionFunctionModel::setModel( const std::string &background, const std::vector<std::pair<std::string, int>> &resolutionWorkspaces, const std::string &peaks, bool hasDeltaFunction, - const std::vector<double> &qValues, const bool isQDependent) { - std::string resolution, convolution, function, modifiedPeaks; + const std::vector<double> &qValues, const bool isQDependent, + bool hasTempCorrection, double tempValue) { auto fitFunction = boost::make_shared<MultiDomainFunction>(); - auto const nf = m_numberDomains > 0 ? static_cast<int>(m_numberDomains) : 1; for (int i = 0; i < nf; ++i) { - if (isQDependent) { - auto qValue = qValues.empty() ? 0.0 : qValues[i]; - IFunction::Attribute attr(qValue); - auto peaksFunction = FunctionFactory::Instance().createInitialized(peaks); - peaksFunction->setAttribute("Q", attr); - modifiedPeaks = peaksFunction->asString(); - } else { - modifiedPeaks = peaks; - } - auto const model = hasDeltaFunction ? "name=DeltaFunction;" + modifiedPeaks - : modifiedPeaks; + CompositeFunction_sptr domainFunction; + auto qValue = qValues.empty() ? 0.0 : qValues[i]; + auto innerFunction = + createInnerFunction(peaks, hasDeltaFunction, isQDependent, qValue, + hasTempCorrection, tempValue); auto workspace = resolutionWorkspaces.empty() ? "" : resolutionWorkspaces[i].first; - resolution = workspace.empty() - ? "name=Resolution" - : "name=Resolution,Workspace=\"" + workspace + - "\",WorkspaceIndex=" + - std::to_string(resolutionWorkspaces[i].second); - convolution = "composite=Convolution;" + resolution + ";" + model; - function = background.empty() ? convolution - : background + ";(" + convolution + ")"; - auto domainFunction = - FunctionFactory::Instance().createInitialized(function); + auto workspaceIndex = + resolutionWorkspaces.empty() ? 0 : resolutionWorkspaces[i].second; + auto resolutionFunction = + createResolutionFunction(workspace, workspaceIndex); + auto convolutionFunction = + createConvolutionFunction(resolutionFunction, innerFunction); + domainFunction = addBackground(convolutionFunction, background); fitFunction->addFunction(domainFunction); fitFunction->setDomainIndex(i, i); } + // The two clones here are needed as the clone value of IFunction goes through + // a string serialisation and deserialisation. This can lead to the function + // structure subtly changeing. For exmaple composite functions of only one + // member are removed and uneeded brackets are removed from user defined + // functions. As function cloning is used later on in the workflow it seems + // safer to clone twice here to get the function in it's final state early on + // rather than have it change during the workflow. + setFunction(fitFunction->clone()->clone()); +} + +CompositeFunction_sptr +ConvolutionFunctionModel::addBackground(CompositeFunction_sptr domainFunction, + std::string background) { + if (background.empty()) + return domainFunction; + + auto backgroundFunction = + FunctionFactory::Instance().createInitialized(background); + auto functionWithBackground = boost::make_shared<CompositeFunction>(); + functionWithBackground->addFunction(backgroundFunction); + functionWithBackground->addFunction(domainFunction); + + return functionWithBackground; +} + +CompositeFunction_sptr ConvolutionFunctionModel::createInnerFunction( + std::string peaksFunction, bool hasDeltaFunction, bool isQDependent, + double qValue, bool hasTempCorrection, double tempValue) { + auto functionSpecified = !peaksFunction.empty(); + CompositeFunction_sptr innerFunction = + boost::make_shared<CompositeFunction>(); + if (functionSpecified) { + auto peakFunction = + FunctionFactory::Instance().createInitialized(peaksFunction); + auto peakFunctionComposite = + boost::dynamic_pointer_cast<CompositeFunction>(peakFunction); + if (peakFunctionComposite) { + innerFunction = peakFunctionComposite; + } else { + innerFunction->addFunction(peakFunction); + } + if (isQDependent) { + IFunction::Attribute attr(qValue); + peakFunction->setAttribute("Q", attr); + } + } - setFunction(fitFunction); + if (hasTempCorrection) { + innerFunction = addTempCorrection(innerFunction, tempValue); + } + + if (hasDeltaFunction) { + auto deltaFunction = + FunctionFactory::Instance().createFunction("DeltaFunction"); + if (!hasTempCorrection) { + innerFunction->addFunction(deltaFunction); + } else { + CompositeFunction_sptr innerFunctionNew = + boost::make_shared<CompositeFunction>(); + innerFunctionNew->addFunction(deltaFunction); + innerFunctionNew->addFunction(innerFunction); + return innerFunctionNew; + } + } + + return innerFunction; +} + +CompositeFunction_sptr ConvolutionFunctionModel::addTempCorrection( + CompositeFunction_sptr peaksFunction, double tempValue) { + CompositeFunction_sptr productFunction = + boost::dynamic_pointer_cast<CompositeFunction>( + FunctionFactory::Instance().createFunction("ProductFunction")); + auto tempFunction = createTemperatureCorrection(tempValue); + productFunction->addFunction(tempFunction); + productFunction->addFunction(peaksFunction); + return productFunction; +} + +IFunction_sptr +ConvolutionFunctionModel::createTemperatureCorrection(double correction) { + // create user function for the exponential correction + // (x/temp) / (1-exp(-(x/temp))) + auto tempFunc = FunctionFactory::Instance().createFunction("UserFunction"); + // 11.606 is the conversion factor from meV to K + std::string formula = "((x*11.606)/Temp) / (1 - exp(-((x*11.606)/Temp)))"; + IFunction::Attribute att(formula); + tempFunc->setAttribute("Formula", att); + tempFunc->setParameter("Temp", correction); + tempFunc->fixParameter("Temp", false); + return tempFunc; +} + +CompositeFunction_sptr ConvolutionFunctionModel::createConvolutionFunction( + IFunction_sptr resolutionFunction, IFunction_sptr innerFunction) { + CompositeFunction_sptr convolution = + boost::dynamic_pointer_cast<CompositeFunction>( + FunctionFactory::Instance().createFunction("Convolution")); + convolution->addFunction(resolutionFunction); + + if (innerFunction->nFunctions() > 0) + convolution->addFunction(innerFunction); + + return convolution; +} + +IFunction_sptr +ConvolutionFunctionModel::createResolutionFunction(std::string workspaceName, + int workspaceIndex) { + std::string resolution = + workspaceName.empty() + ? "name=Resolution" + : "name=Resolution,Workspace=\"" + workspaceName + + "\",WorkspaceIndex=" + std::to_string(workspaceIndex); + return FunctionFactory::Instance().createInitialized(resolution); } void ConvolutionFunctionModel::findComponentPrefixes() { m_backgroundPrefix.reset(); m_convolutionPrefix.reset(); m_deltaFunctionPrefix.reset(); - m_peakPrefixes.reset(); + m_tempFunctionPrefix.reset(); + m_peakPrefixes = QStringList(); m_resolutionWorkspace.clear(); m_resolutionWorkspaceIndex = 0; + auto function = getCurrentFunction(); if (!function) return; - if (function->nFunctions() == 0) { - if (!isConvolution(function)) { - throw std::runtime_error("Model doesn't contain a convolution."); - } - m_convolutionPrefix = ""; - return; - } - if (isConvolution(function)) { - m_convolutionPrefix = ""; - findConvolutionPrefixes(function); - return; - } - for (size_t i = 0; i < function->nFunctions(); ++i) { - auto const fun = function->getFunction(i); - if (isBackground(fun)) { - if (m_backgroundPrefix) { - throw std::runtime_error("Model cannot have more than one background."); - } - m_backgroundPrefix = QString("f%1.").arg(i); - } else if (isConvolution(fun)) { - if (m_convolutionPrefix) { - throw std::runtime_error( - "Model cannot have more than one convolution."); - } - m_convolutionPrefix = QString("f%1.").arg(i); - findConvolutionPrefixes(fun); - } + iterateThroughFunction(function.get(), QString()); + + if (m_peakPrefixes->isEmpty()) { + m_peakPrefixes.reset(); } if (!m_convolutionPrefix) { throw std::runtime_error("Model doesn't contain a convolution."); } } -void ConvolutionFunctionModel::findConvolutionPrefixes( - const IFunction_sptr &fun) { - auto const nf = fun->nFunctions(); - if (nf == 0) +void ConvolutionFunctionModel::iterateThroughFunction(IFunction *func, + const QString &prefix) { + auto numberOfSubFunction = func->nFunctions(); + + setPrefix(func, prefix); + if (numberOfSubFunction == 0) { return; - auto const resolution = fun->getFunction(0); - if (!isResolution(resolution)) { - throw std::runtime_error( - "Model's resolution function must have type Resolution."); } - m_resolutionWorkspace = resolution->getAttribute("Workspace").asString(); - m_resolutionWorkspaceIndex = - resolution->getAttribute("WorkspaceIndex").asInt(); - if (nf == 1) - return; - auto const model = fun->getFunction(1); - auto const nm = model->nFunctions(); - if (nm == 0) { - auto const prefix = *m_convolutionPrefix + "f1."; - if (isDeltaFunction(model)) { - m_deltaFunctionPrefix = prefix; - } else { - m_peakPrefixes = QStringList(prefix); - } - } else { - m_peakPrefixes = QStringList(); - for (size_t j = 0; j < model->nFunctions(); ++j) { - auto const prefix = *m_convolutionPrefix + QString("f1.f%1.").arg(j); - if (isDeltaFunction(model->getFunction(j))) { - m_deltaFunctionPrefix = prefix; - } else { - m_peakPrefixes->append(prefix); - } + for (size_t k = 0; k < numberOfSubFunction; ++k) { + iterateThroughFunction(func->getFunction(k).get(), + prefix + QString("f%1.").arg(k)); + } +} + +void ConvolutionFunctionModel::setPrefix(IFunction *func, + const QString &prefix) { + if (isBackground(func)) { + if (m_backgroundPrefix) { + throw std::runtime_error("Model cannot have more than one background."); } - if (m_peakPrefixes->isEmpty()) { - m_peakPrefixes.reset(); + m_backgroundPrefix = prefix; + } else if (isConvolution(func)) { + if (func->nFunctions() != 0 && + func->getFunction(0)->name() != "Resolution") { + throw std::runtime_error( + "Model's resolution function must have type Resolution."); + } else if (func->nFunctions() == 0) { + m_resolutionWorkspace = ""; + m_resolutionWorkspaceIndex = 0; } - } - if (!m_convolutionPrefix) { - throw std::runtime_error("Model doesn't contain a convolution."); + m_convolutionPrefix = prefix; + } else if (isDeltaFunction(func)) { + m_deltaFunctionPrefix = prefix; + } else if (isTempFunction(func)) { + m_tempFunctionPrefix = prefix; + } else if (isResolution(func)) { + m_resolutionWorkspace = func->getAttribute("Workspace").asString(); + m_resolutionWorkspaceIndex = func->getAttribute("WorkspaceIndex").asInt(); + } else if (isPeakFunction(func)) { + m_peakPrefixes->append(prefix); } } diff --git a/qt/widgets/common/test/ConvolutionFunctionModelTest.h b/qt/widgets/common/test/ConvolutionFunctionModelTest.h index 29504a6d14ace64496bec54b0b498713a6f9b855..cf0b3759b1be1a93bc998d9bafc206efe2868384 100644 --- a/qt/widgets/common/test/ConvolutionFunctionModelTest.h +++ b/qt/widgets/common/test/ConvolutionFunctionModelTest.h @@ -13,6 +13,7 @@ #include "MantidAPI/IFunction.h" #include "MantidQtWidgets/Common/ConvolutionFunctionModel.h" #include <cxxtest/TestSuite.h> +#include <iostream> using namespace MantidQt::MantidWidgets; using namespace Mantid::API; @@ -30,6 +31,11 @@ public: TS_ASSERT(!model.getFitFunction()); } + void test_clear() { + ConvolutionFunctionModel model; + model.clear(); + } + void test_no_convolution() { ConvolutionFunctionModel model; TS_ASSERT_THROWS_EQUALS( @@ -91,7 +97,7 @@ public: ConvolutionFunctionModel model; TS_ASSERT_THROWS_NOTHING( model.setFunctionString("name=LinearBackground;(composite=Convolution;" - "name=Resolution;name=Gaussian)")); + "name=Resolution;name=Lorentzian)")); TS_ASSERT_EQUALS(model.backgroundPrefix()->toStdString(), "f0."); TS_ASSERT_EQUALS(model.convolutionPrefix()->toStdString(), "f1."); TS_ASSERT_EQUALS(model.resolutionWorkspace(), ""); @@ -255,7 +261,8 @@ public: fitResolutions.emplace_back(pair1); fitResolutions.emplace_back(pair2); - model.setModel("", fitResolutions, "", false, std::vector<double>(), false); + model.setModel("", fitResolutions, "", false, std::vector<double>(), false, + false, 100.0); auto fitFunctionAsString = model.getFitFunction()->asString(); TS_ASSERT_EQUALS( @@ -266,6 +273,284 @@ public: "true,NumDeriv=true,$domains=i;name=Resolution,Workspace=abc," "WorkspaceIndex=2,X=(),Y=())"); } + + void test_setModel_with_delta_function_correct() { + auto algo = FrameworkManager::Instance().createAlgorithm("CreateWorkspace"); + algo->initialize(); + algo->setPropertyValue("DataX", "1,2,3"); + algo->setPropertyValue("DataY", "1,2,3"); + algo->setPropertyValue("OutputWorkspace", "abc"); + algo->execute(); + ConvolutionFunctionModel model; + model.setNumberDomains(2); + auto pair1 = std::make_pair<std::string, int>("abc", 1); + auto pair2 = std::make_pair<std::string, int>("abc", 2); + auto fitResolutions = std::vector<std::pair<std::string, int>>(); + fitResolutions.emplace_back(pair1); + fitResolutions.emplace_back(pair2); + + model.setModel("", fitResolutions, "", true, std::vector<double>(), false, + false, 100.0); + + auto fitFunctionAsString = model.getFitFunction()->asString(); + std::cout << fitFunctionAsString << std::endl; + TS_ASSERT_EQUALS( + fitFunctionAsString, + "composite=MultiDomainFunction,NumDeriv=true;(composite=Convolution," + "FixResolution=true,NumDeriv=true,$domains=i;name=Resolution,Workspace=" + "abc,WorkspaceIndex=1,X=(),Y=();name=DeltaFunction,Height=1,Centre=0);(" + "composite=Convolution,FixResolution=" + "true,NumDeriv=true,$domains=i;name=Resolution,Workspace=abc," + "WorkspaceIndex=2,X=(),Y=();name=DeltaFunction,Height=1,Centre=0)"); + } + + void test_setModel_with_delta_function_TeixeiraWaterSQE_correct() { + auto algo = FrameworkManager::Instance().createAlgorithm("CreateWorkspace"); + algo->initialize(); + algo->setPropertyValue("DataX", "1,2,3"); + algo->setPropertyValue("DataY", "1,2,3"); + algo->setPropertyValue("OutputWorkspace", "abc"); + algo->execute(); + ConvolutionFunctionModel model; + model.setNumberDomains(2); + auto pair1 = std::make_pair<std::string, int>("abc", 1); + auto pair2 = std::make_pair<std::string, int>("abc", 2); + auto fitResolutions = std::vector<std::pair<std::string, int>>(); + fitResolutions.emplace_back(pair1); + fitResolutions.emplace_back(pair2); + + model.setModel("name=FlatBackground", fitResolutions, + "name=TeixeiraWaterSQE", true, std::vector<double>(), false, + false, 100.0); + + auto fitFunctionAsString = model.getFitFunction()->asString(); + std::cout << fitFunctionAsString << std::endl; + TS_ASSERT_EQUALS( + fitFunctionAsString, + "composite=MultiDomainFunction,NumDeriv=true;(composite=" + "CompositeFunction,NumDeriv=false,$domains=i;name=FlatBackground,A0=0;(" + "composite=Convolution,FixResolution=true,NumDeriv=true;name=" + "Resolution,Workspace=abc,WorkspaceIndex=1,X=(),Y=();(name=" + "TeixeiraWaterSQE,Q=8.9884656743115785e+307,WorkspaceIndex=2147483647," + "Height=1,DiffCoeff=2.3,Tau=1.25,Centre=0;name=DeltaFunction,Height=1," + "Centre=0)));(composite=CompositeFunction,NumDeriv=false,$domains=i;" + "name=FlatBackground,A0=0;(composite=Convolution,FixResolution=true," + "NumDeriv=true;name=Resolution,Workspace=abc,WorkspaceIndex=2,X=(),Y=()" + ";(name=TeixeiraWaterSQE,Q=8.9884656743115785e+307,WorkspaceIndex=" + "2147483647,Height=1,DiffCoeff=2.3,Tau=1.25,Centre=0;name=" + "DeltaFunction,Height=1,Centre=0)))"); + } + + void test_setModel_with_delta_function_TwoLorenztian_correct() { + auto algo = FrameworkManager::Instance().createAlgorithm("CreateWorkspace"); + algo->initialize(); + algo->setPropertyValue("DataX", "1,2,3"); + algo->setPropertyValue("DataY", "1,2,3"); + algo->setPropertyValue("OutputWorkspace", "abc"); + algo->execute(); + ConvolutionFunctionModel model; + model.setNumberDomains(2); + auto pair1 = std::make_pair<std::string, int>("abc", 1); + auto pair2 = std::make_pair<std::string, int>("abc", 2); + auto fitResolutions = std::vector<std::pair<std::string, int>>(); + fitResolutions.emplace_back(pair1); + fitResolutions.emplace_back(pair2); + + model.setModel("name=FlatBackground", fitResolutions, + "(name=Lorentzian;name=Lorentzian)", true, + std::vector<double>(), false, false, 100.0); + + auto fitFunctionAsString = model.getFitFunction()->asString(); + TS_ASSERT_EQUALS( + fitFunctionAsString, + "composite=MultiDomainFunction,NumDeriv=true;(composite=" + "CompositeFunction,NumDeriv=false,$domains=i;name=FlatBackground,A0=0;(" + "composite=Convolution,FixResolution=true,NumDeriv=true;name=" + "Resolution,Workspace=abc,WorkspaceIndex=1,X=(),Y=();(name=Lorentzian," + "Amplitude=1,PeakCentre=0,FWHM=0;name=Lorentzian,Amplitude=1," + "PeakCentre=0,FWHM=0;name=DeltaFunction,Height=1,Centre=0)));(" + "composite=CompositeFunction,NumDeriv=false,$domains=i;name=" + "FlatBackground,A0=0;(composite=Convolution,FixResolution=true," + "NumDeriv=true;name=Resolution,Workspace=abc,WorkspaceIndex=2,X=(),Y=()" + ";(name=Lorentzian,Amplitude=1,PeakCentre=0,FWHM=0;name=Lorentzian," + "Amplitude=1,PeakCentre=0,FWHM=0;name=DeltaFunction,Height=1,Centre=0))" + ")"); + } + + void test_setModel_with_delta_function_TwoLorenztian_correctWithTemp() { + auto algo = FrameworkManager::Instance().createAlgorithm("CreateWorkspace"); + algo->initialize(); + algo->setPropertyValue("DataX", "1,2,3"); + algo->setPropertyValue("DataY", "1,2,3"); + algo->setPropertyValue("OutputWorkspace", "abc"); + algo->execute(); + ConvolutionFunctionModel model; + model.setNumberDomains(2); + auto pair1 = std::make_pair<std::string, int>("abc", 1); + auto pair2 = std::make_pair<std::string, int>("abc", 2); + auto fitResolutions = std::vector<std::pair<std::string, int>>(); + fitResolutions.emplace_back(pair1); + fitResolutions.emplace_back(pair2); + + model.setModel("name=FlatBackground", fitResolutions, + "(name=Lorentzian;name=Lorentzian)", true, + std::vector<double>(), false, true, 100.0); + + auto fitFunctionAsString = model.getFitFunction()->asString(); + TS_ASSERT_EQUALS( + fitFunctionAsString, + "composite=MultiDomainFunction,NumDeriv=true;(composite=" + "CompositeFunction,NumDeriv=false,$domains=i;name=FlatBackground,A0=0;(" + "composite=Convolution,FixResolution=true,NumDeriv=true;name=" + "Resolution,Workspace=abc,WorkspaceIndex=1,X=(),Y=();(name=" + "DeltaFunction,Height=1,Centre=0;(composite=ProductFunction,NumDeriv=" + "false;name=UserFunction,Formula=x*11.606/Temp/(1-exp( " + "-(x*11.606/" + "Temp))),Temp=100,ties=(Temp=100);(name=Lorentzian,Amplitude=1," + "PeakCentre=0,FWHM=0;name=Lorentzian,Amplitude=1,PeakCentre=0,FWHM=0)))" + "));(composite=CompositeFunction,NumDeriv=false,$domains=i;name=" + "FlatBackground,A0=0;(composite=Convolution,FixResolution=true," + "NumDeriv=true;name=Resolution,Workspace=abc,WorkspaceIndex=2,X=(),Y=()" + ";(name=DeltaFunction,Height=1,Centre=0;(composite=ProductFunction," + "NumDeriv=false;name=UserFunction,Formula=x*11.606/Temp/(1-exp( " + "-(x*11.606/" + "Temp))),Temp=100,ties=(Temp=100);(name=Lorentzian,Amplitude=1," + "PeakCentre=0,FWHM=0;name=Lorentzian,Amplitude=1,PeakCentre=0,FWHM=0)))" + "))"); + } + + void test_component_prefixes_set_correctly_without_temp_correction() { + auto algo = FrameworkManager::Instance().createAlgorithm("CreateWorkspace"); + algo->initialize(); + algo->setPropertyValue("DataX", "1,2,3"); + algo->setPropertyValue("DataY", "1,2,3"); + algo->setPropertyValue("OutputWorkspace", "abc"); + algo->execute(); + ConvolutionFunctionModel model; + model.setNumberDomains(2); + auto pair1 = std::make_pair<std::string, int>("abc", 1); + auto pair2 = std::make_pair<std::string, int>("abc", 2); + auto fitResolutions = std::vector<std::pair<std::string, int>>(); + fitResolutions.emplace_back(pair1); + fitResolutions.emplace_back(pair2); + + model.setModel("name=FlatBackground", fitResolutions, + "(name=Lorentzian;name=Lorentzian)", true, + std::vector<double>(), false, false, 100.0); + + TS_ASSERT_EQUALS(model.backgroundPrefix().value().toStdString(), "f0."); + TS_ASSERT_EQUALS(model.convolutionPrefix().value().toStdString(), "f1."); + TS_ASSERT_EQUALS(model.deltaFunctionPrefix().value().toStdString(), + "f1.f1.f2."); + TS_ASSERT_EQUALS(model.peakPrefixes().value()[0].toStdString(), + "f1.f1.f0."); + TS_ASSERT_EQUALS(model.peakPrefixes().value()[1].toStdString(), + "f1.f1.f1."); + } + + void test_component_prefixes_set_correctly_with_temp_correction() { + auto algo = FrameworkManager::Instance().createAlgorithm("CreateWorkspace"); + algo->initialize(); + algo->setPropertyValue("DataX", "1,2,3"); + algo->setPropertyValue("DataY", "1,2,3"); + algo->setPropertyValue("OutputWorkspace", "abc"); + algo->execute(); + ConvolutionFunctionModel model; + model.setNumberDomains(2); + auto pair1 = std::make_pair<std::string, int>("abc", 1); + auto pair2 = std::make_pair<std::string, int>("abc", 2); + auto fitResolutions = std::vector<std::pair<std::string, int>>(); + fitResolutions.emplace_back(pair1); + fitResolutions.emplace_back(pair2); + + model.setModel("name=FlatBackground", fitResolutions, + "(name=Lorentzian;name=Lorentzian)", false, + std::vector<double>(), false, true, 100.0); + + TS_ASSERT_EQUALS(model.backgroundPrefix().value().toStdString(), "f0."); + TS_ASSERT_EQUALS(model.convolutionPrefix().value().toStdString(), "f1."); + TS_ASSERT_EQUALS(model.peakPrefixes().value()[0].toStdString(), + "f1.f1.f1.f0."); + TS_ASSERT_EQUALS(model.peakPrefixes().value()[1].toStdString(), + "f1.f1.f1.f1."); + TS_ASSERT_EQUALS(model.tempFunctionPrefix().value().toStdString(), + "f1.f1.f0."); + } + + void test_component_prefixes_if_only_temp_set() { + auto algo = FrameworkManager::Instance().createAlgorithm("CreateWorkspace"); + algo->initialize(); + algo->setPropertyValue("DataX", "1,2,3"); + algo->setPropertyValue("DataY", "1,2,3"); + algo->setPropertyValue("OutputWorkspace", "abc"); + algo->execute(); + ConvolutionFunctionModel model; + model.setNumberDomains(2); + auto pair1 = std::make_pair<std::string, int>("abc", 1); + auto pair2 = std::make_pair<std::string, int>("abc", 2); + auto fitResolutions = std::vector<std::pair<std::string, int>>(); + fitResolutions.emplace_back(pair1); + fitResolutions.emplace_back(pair2); + + model.setModel("", fitResolutions, "", false, std::vector<double>(), false, + true, 100.0); + + TS_ASSERT_EQUALS(model.convolutionPrefix().value().toStdString(), ""); + TS_ASSERT_EQUALS(model.tempFunctionPrefix().value().toStdString(), + "f1.f0."); + } + + void test_component_prefixes_one_lorenzian_temp_set() { + auto algo = FrameworkManager::Instance().createAlgorithm("CreateWorkspace"); + algo->initialize(); + algo->setPropertyValue("DataX", "1,2,3"); + algo->setPropertyValue("DataY", "1,2,3"); + algo->setPropertyValue("OutputWorkspace", "abc"); + algo->execute(); + ConvolutionFunctionModel model; + model.setNumberDomains(2); + auto pair1 = std::make_pair<std::string, int>("abc", 1); + auto pair2 = std::make_pair<std::string, int>("abc", 2); + auto fitResolutions = std::vector<std::pair<std::string, int>>(); + fitResolutions.emplace_back(pair1); + fitResolutions.emplace_back(pair2); + + model.setModel("name=FlatBackground", fitResolutions, "name=Lorentzian", + false, std::vector<double>(), false, true, 100.0); + TS_ASSERT_EQUALS(model.backgroundPrefix().value().toStdString(), "f0."); + TS_ASSERT_EQUALS(model.convolutionPrefix().value().toStdString(), "f1."); + TS_ASSERT_EQUALS(model.peakPrefixes().value()[0].toStdString(), + "f1.f1.f1."); + TS_ASSERT_EQUALS(model.tempFunctionPrefix().value().toStdString(), + "f1.f1.f0."); + } + + void test_component_prefixes_if_temp_and_delta_set() { + auto algo = FrameworkManager::Instance().createAlgorithm("CreateWorkspace"); + algo->initialize(); + algo->setPropertyValue("DataX", "1,2,3"); + algo->setPropertyValue("DataY", "1,2,3"); + algo->setPropertyValue("OutputWorkspace", "abc"); + algo->execute(); + ConvolutionFunctionModel model; + model.setNumberDomains(2); + auto pair1 = std::make_pair<std::string, int>("abc", 1); + auto pair2 = std::make_pair<std::string, int>("abc", 2); + auto fitResolutions = std::vector<std::pair<std::string, int>>(); + fitResolutions.emplace_back(pair1); + fitResolutions.emplace_back(pair2); + + model.setModel("name=FlatBackground", fitResolutions, "name=Lorentzian", + true, std::vector<double>(), false, true, 100.0); + TS_ASSERT_EQUALS(model.backgroundPrefix().value().toStdString(), "f0."); + TS_ASSERT_EQUALS(model.convolutionPrefix().value().toStdString(), "f1."); + TS_ASSERT_EQUALS(model.peakPrefixes().value()[0].toStdString(), + "f1.f1.f1.f1."); + TS_ASSERT_EQUALS(model.tempFunctionPrefix().value().toStdString(), + "f1.f1.f1.f0."); + TS_ASSERT_EQUALS(model.deltaFunctionPrefix().value().toStdString(), + "f1.f1.f0."); + } }; #endif // MANTIDWIDGETS_CONVOLUTIONFUNCTIONMODELTEST_H_