From 47ac262adca648e849011b9fab3c1c09c6744b03 Mon Sep 17 00:00:00 2001 From: Matthew Andrew <matthew.andrew@tessella.com> Date: Wed, 27 Nov 2019 14:21:06 +0000 Subject: [PATCH] Updated handling of resolution in convFit Re #26881 This updates the handling of which resolution spectra to use for each spectra in the fit. This needed updating because for multiple files it was using the convolution for the first file for all files and because how QENSFitSequential and QENSFitSimultaneous handle convolutions is different. The sequential version requires a single workspace which contains all of the resolutions whereas the simultaneous version requires the resolutions to be encoded into the FitFunction. --- qt/scientific_interfaces/Indirect/ConvFit.cpp | 3 +- .../Indirect/ConvFitModel.cpp | 61 ++++++++++++++++++- .../Indirect/ConvFitModel.h | 7 ++- .../Indirect/FunctionTemplateBrowser.h | 2 + .../Indirect/IndirectFitPropertyBrowser.cpp | 8 +++ .../Indirect/IndirectFitPropertyBrowser.h | 2 + .../Indirect/IndirectFittingModel.h | 2 +- .../ConvFunctionModel.cpp | 11 +++- .../ConvFunctionModel.h | 3 + .../ConvTemplateBrowser.cpp | 5 ++ .../ConvTemplateBrowser.h | 2 + .../ConvTemplatePresenter.cpp | 5 ++ .../ConvTemplatePresenter.h | 2 + .../Indirect/test/ConvFitModelTest.h | 33 +++++++++- .../Common/ConvolutionFunctionModel.h | 8 +-- .../common/src/ConvolutionFunctionModel.cpp | 9 ++- .../test/ConvolutionFunctionModelTest.h | 8 ++- 17 files changed, 149 insertions(+), 22 deletions(-) diff --git a/qt/scientific_interfaces/Indirect/ConvFit.cpp b/qt/scientific_interfaces/Indirect/ConvFit.cpp index dec84539b97..71063362d11 100644 --- a/qt/scientific_interfaces/Indirect/ConvFit.cpp +++ b/qt/scientific_interfaces/Indirect/ConvFit.cpp @@ -152,7 +152,8 @@ void ConvFit::setModelResolution(const std::string &resolutionName, AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( resolutionName); m_convFittingModel->setResolution(resolution, index); - m_uiForm->fitPropertyBrowser->setModelResolution(resolutionName, index); + auto fitResolutions = m_convFittingModel->getResolutionsForFit(); + m_uiForm->fitPropertyBrowser->setModelResolution(fitResolutions); setModelFitFunction(); } diff --git a/qt/scientific_interfaces/Indirect/ConvFitModel.cpp b/qt/scientific_interfaces/Indirect/ConvFitModel.cpp index eb868db9a86..2c8633c5b5d 100644 --- a/qt/scientific_interfaces/Indirect/ConvFitModel.cpp +++ b/qt/scientific_interfaces/Indirect/ConvFitModel.cpp @@ -218,6 +218,20 @@ MatrixWorkspace_sptr appendWorkspace(MatrixWorkspace_sptr leftWS, return getADSMatrixWorkspace(outputName); } +MatrixWorkspace_sptr extractSingleSpectrum(const std::string &inputWS, + const std::string &outputWS, + int index) { + auto extractAlg = + AlgorithmManager::Instance().create("ExtractSingleSpectrum"); + extractAlg->setLogging(false); + extractAlg->initialize(); + extractAlg->setProperty("InputWorkspace", inputWS); + extractAlg->setProperty("WorkspaceIndex", index); + extractAlg->setProperty("OutputWorkspace", outputWS); + extractAlg->execute(); + return getADSMatrixWorkspace(outputWS); +} + void renameWorkspace(std::string const &name, std::string const &newName) { auto renamer = AlgorithmManager::Instance().create("RenameWorkspace"); renamer->setLogging(false); @@ -488,6 +502,34 @@ std::string ConvFitModel::singleFitOutputName(TableDatasetIndex index, index, spectrum); } +Mantid::API::IAlgorithm_sptr +ConvFitModel::createSequentialFit(Mantid::API::IFunction_sptr function) const { + auto resolutionWorkspaceName = constructSequentialResolutionWorkspace(); + auto functionCopy = function->clone(); + IFunction::Attribute attr(resolutionWorkspaceName); + setResolutionAttribute( + boost::dynamic_pointer_cast<CompositeFunction>(functionCopy), attr); + return IndirectFittingModel::createSequentialFit(functionCopy); +} + +std::string ConvFitModel::constructSequentialResolutionWorkspace() const { + auto resolutionWorkspaceName = "__ConvFitSequential"; + auto resolutionWorkspaces = getResolutionsForFit(); + auto resolutionWS = extractSingleSpectrum(resolutionWorkspaces[0].first, + resolutionWorkspaceName, + resolutionWorkspaces[0].second); + for (size_t index = 1; index < resolutionWorkspaces.size(); index++) { + auto extractedSpectra = extractSingleSpectrum( + resolutionWorkspaces[index].first, "__indirectResolutionCreationTemp", + resolutionWorkspaces[index].second); + resolutionWS = appendWorkspace(resolutionWS, extractedSpectra, 1, + resolutionWorkspaceName); + } + deleteWorkspace("__indirectResolutionCreationTemp"); + + return resolutionWorkspaceName; +} + Mantid::API::MultiDomainFunction_sptr ConvFitModel::getFittingFunction() const { // auto function = shallowCopy(IndirectFittingModel::getFittingFunction()); // auto composite = boost::dynamic_pointer_cast<CompositeFunction>(function); @@ -719,8 +761,23 @@ void ConvFitModel::setParameterNameChanges( model, backgroundIndex, m_temperature.is_initialized()); } -std::pair<std::string, int> ConvFitModel::getResolutionsForFit() const { - return std::pair<std::string, int>(); +std::vector<std::pair<std::string, int>> +ConvFitModel::getResolutionsForFit() const { + std::vector<std::pair<std::string, int>> resolutionVector; + resolutionVector.reserve(20); + for (TableDatasetIndex index = TableDatasetIndex{0}; + index < m_resolution.size(); index++) { + + auto spectra = getSpectra(index); + auto singleSpectraResolution = + getResolution(index)->getNumberHistograms() == 1; + for (auto &spectraIndex : spectra) { + auto resolutionIndex = singleSpectraResolution ? 0 : spectraIndex.value; + resolutionVector.emplace_back( + std::make_pair(getResolution(index)->getName(), resolutionIndex)); + } + } + return resolutionVector; } } // namespace IDA diff --git a/qt/scientific_interfaces/Indirect/ConvFitModel.h b/qt/scientific_interfaces/Indirect/ConvFitModel.h index 5fe27484083..e2407cef307 100644 --- a/qt/scientific_interfaces/Indirect/ConvFitModel.h +++ b/qt/scientific_interfaces/Indirect/ConvFitModel.h @@ -48,7 +48,7 @@ public: void addOutput(Mantid::API::IAlgorithm_sptr fitAlgorithm) override; - std::pair<std::string, int> getResolutionsForFit() const; + std::vector<std::pair<std::string, int>> getResolutionsForFit() const; private: Mantid::API::IAlgorithm_sptr sequentialFitAlgorithm() const override; @@ -62,7 +62,8 @@ private: createDefaultParameters(TableDatasetIndex index) const override; std::unordered_map<std::string, std::string> mapDefaultParameterNames() const override; - + Mantid::API::IAlgorithm_sptr + createSequentialFit(Mantid::API::IFunction_sptr function) const override; IndirectFitOutput createFitOutput(Mantid::API::WorkspaceGroup_sptr resultGroup, Mantid::API::ITableWorkspace_sptr parameterTable, @@ -94,6 +95,8 @@ private: void setParameterNameChanges(const Mantid::API::IFunction &model, boost::optional<std::size_t> backgroundIndex); + std::string constructSequentialResolutionWorkspace() const; + ResolutionCollectionType m_resolution; ExtendedResolutionType m_extendedResolution; std::unordered_map<std::string, std::string> m_parameterNameChanges; diff --git a/qt/scientific_interfaces/Indirect/FunctionTemplateBrowser.h b/qt/scientific_interfaces/Indirect/FunctionTemplateBrowser.h index 52bb4d70fd7..4a8ea817c00 100644 --- a/qt/scientific_interfaces/Indirect/FunctionTemplateBrowser.h +++ b/qt/scientific_interfaces/Indirect/FunctionTemplateBrowser.h @@ -67,6 +67,8 @@ public: virtual void setBackgroundA0(double value) = 0; virtual void setResolution(std::string const &name, TableDatasetIndex const &index) = 0; + virtual void + setResolution(const std::vector<std::pair<std::string, int>> &){}; signals: void functionStructureChanged(); diff --git a/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.cpp b/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.cpp index 2ca286848bb..20ff40b7bf2 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.cpp +++ b/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.cpp @@ -362,6 +362,14 @@ void IndirectFitPropertyBrowser::setModelResolution( m_templateBrowser->setResolution(name, index); } +void IndirectFitPropertyBrowser::setModelResolution( + const std::vector<std::pair<std::string, int>> &fitResolutions) { + if (isFullFunctionBrowserActive()) { + showFullFunctionBrowser(false); + } + m_templateBrowser->setResolution(fitResolutions); +} + /** * Called when the browser visibility has changed. * diff --git a/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.h b/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.h index 0537633f541..c816f05ffe9 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.h +++ b/qt/scientific_interfaces/Indirect/IndirectFitPropertyBrowser.h @@ -75,6 +75,8 @@ public slots: void sequentialFit(); void setModelResolution(std::string const &name, TableDatasetIndex const &index); + void setModelResolution( + const std::vector<std::pair<std::string, int>> &fitResolutions); protected slots: void clear(); diff --git a/qt/scientific_interfaces/Indirect/IndirectFittingModel.h b/qt/scientific_interfaces/Indirect/IndirectFittingModel.h index b6628284181..717591d1077 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFittingModel.h +++ b/qt/scientific_interfaces/Indirect/IndirectFittingModel.h @@ -143,7 +143,7 @@ public: protected: Mantid::API::IAlgorithm_sptr getFittingAlgorithm(FittingMode mode) const; - Mantid::API::IAlgorithm_sptr + virtual Mantid::API::IAlgorithm_sptr createSequentialFit(Mantid::API::IFunction_sptr function) const; Mantid::API::IAlgorithm_sptr createSimultaneousFit(Mantid::API::MultiDomainFunction_sptr function) const; diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.cpp b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.cpp index fe8290c2888..ff23f068cc8 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.cpp +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.cpp @@ -31,9 +31,8 @@ void ConvFunctionModel::clearData() { } void ConvFunctionModel::setModel() { - m_model.setModel(buildBackgroundFunctionString(), m_resolutionName, - m_resolutionIndex.value, buildPeaksFunctionString(), - m_hasDeltaFunction); + m_model.setModel(buildBackgroundFunctionString(), m_fitResolutions, + buildPeaksFunctionString(), m_hasDeltaFunction); m_model.setGlobalParameters(makeGlobalList()); } @@ -274,6 +273,12 @@ void ConvFunctionModel::setResolution(std::string const &name, setModel(); } +void ConvFunctionModel::setResolution( + const std::vector<std::pair<std::string, int>> &fitResolutions) { + m_fitResolutions = fitResolutions; + setModel(); +} + QString ConvFunctionModel::setBackgroundA0(double value) { if (hasBackground()) { auto const paramID = (m_backgroundType == BackgroundType::Flat) diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.h b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.h index e762616c033..c959f2fd3eb 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.h +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvFunctionModel.h @@ -88,6 +88,8 @@ public: void updateParameterEstimationData(DataForParameterEstimationCollection &&data); void setResolution(std::string const &name, TableDatasetIndex const &index); + void + setResolution(const std::vector<std::pair<std::string, int>> &fitResolutions); QMap<ParamID, double> getCurrentValues() const; QMap<ParamID, double> getCurrentErrors() const; @@ -131,6 +133,7 @@ private: BackgroundSubType m_backgroundSubtype; std::string m_resolutionName; TableDatasetIndex m_resolutionIndex; + std::vector<std::pair<std::string, int>> m_fitResolutions; }; } // namespace IDA diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.cpp b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.cpp index c083f448887..b1cf24ec9bd 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.cpp +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.cpp @@ -283,6 +283,11 @@ void ConvTemplateBrowser::setResolution(std::string const &name, m_presenter.setResolution(name, index); } +void ConvTemplateBrowser::setResolution( + const std::vector<std::pair<std::string, int>> &fitResolutions) { + m_presenter.setResolution(fitResolutions); +} + } // namespace IDA } // namespace CustomInterfaces } // namespace MantidQt diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.h b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.h index 0b5fb1d1b69..3ed796f24c1 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.h +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplateBrowser.h @@ -54,6 +54,8 @@ public: void setBackgroundA0(double value) override; void setResolution(std::string const &name, TableDatasetIndex const &index) override; + void + setResolution(const std::vector<std::pair<std::string, int>> &fitResolutions); protected slots: void intChanged(QtProperty *) override; diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.cpp b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.cpp index e64d5bd0593..91d01ae7109 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.cpp +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.cpp @@ -155,6 +155,11 @@ void ConvTemplatePresenter::setResolution(std::string const &name, m_model.setResolution(name, index); } +void ConvTemplatePresenter::setResolution( + const std::vector<std::pair<std::string, int>> &fitResolutions) { + m_model.setResolution(fitResolutions); +} + void ConvTemplatePresenter::updateViewParameters() { auto values = m_model.getCurrentValues(); auto errors = m_model.getCurrentErrors(); diff --git a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.h b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.h index 51cc137672c..9338c20b0fd 100644 --- a/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.h +++ b/qt/scientific_interfaces/Indirect/IndirectFunctionBrowser/ConvTemplatePresenter.h @@ -52,6 +52,8 @@ public: void setDatasetNames(const QStringList &names); void setErrorsEnabled(bool enabled); void setResolution(std::string const &name, TableDatasetIndex const &index); + void + setResolution(const std::vector<std::pair<std::string, int>> &fitResolutions); signals: void functionStructureChanged(); diff --git a/qt/scientific_interfaces/Indirect/test/ConvFitModelTest.h b/qt/scientific_interfaces/Indirect/test/ConvFitModelTest.h index 221a3f622c5..00dd30946af 100644 --- a/qt/scientific_interfaces/Indirect/test/ConvFitModelTest.h +++ b/qt/scientific_interfaces/Indirect/test/ConvFitModelTest.h @@ -207,12 +207,41 @@ public: void test_that_get_resolution_for_fit_returns_correctly_for_single_workspace() { + Spectra const spectra = Spectra("0,5"); addWorkspacesToModel(spectra, m_workspace); m_model->setResolution(m_workspace, TableDatasetIndex{0}); - auto fitResolutions = m_model->getResolutionFotFit(); + auto fitResolutions = m_model->getResolutionsForFit(); - TS_ASSERT_EQUALS(fitResolutions, std::pair<std::string, int>()); + TS_ASSERT_EQUALS(fitResolutions.size(), 2); + TS_ASSERT_EQUALS(fitResolutions[0].first, "Name"); + TS_ASSERT_EQUALS(fitResolutions[0].second, 0); + TS_ASSERT_EQUALS(fitResolutions[1].first, "Name"); + TS_ASSERT_EQUALS(fitResolutions[1].second, 5); + } + + void + test_that_get_resolution_for_fit_returns_correctly_for_multiple_workspaces() { + Spectra const spectra = Spectra("0,5"); + addWorkspacesToModel(spectra, m_workspace); + auto const workspace2 = createWorkspace(3, 3); + m_ads->addOrReplace("Workspace2", workspace2); + Spectra const spectra2 = Spectra("1-2"); + addWorkspacesToModel(spectra2, workspace2); + m_model->setResolution(m_workspace, TableDatasetIndex{0}); + m_model->setResolution(workspace2, TableDatasetIndex{1}); + + auto fitResolutions = m_model->getResolutionsForFit(); + + TS_ASSERT_EQUALS(fitResolutions.size(), 4); + TS_ASSERT_EQUALS(fitResolutions[0].first, "Name"); + TS_ASSERT_EQUALS(fitResolutions[0].second, 0); + TS_ASSERT_EQUALS(fitResolutions[1].first, "Name"); + TS_ASSERT_EQUALS(fitResolutions[1].second, 5); + TS_ASSERT_EQUALS(fitResolutions[2].first, "Workspace2"); + TS_ASSERT_EQUALS(fitResolutions[2].second, 1); + TS_ASSERT_EQUALS(fitResolutions[3].first, "Workspace2"); + TS_ASSERT_EQUALS(fitResolutions[3].second, 2); } private: diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h b/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h index 4f942b2b0e3..8098d25bf5f 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h @@ -25,10 +25,10 @@ public: void setModel(const std::string &background, const std::string &workspace, int workspaceIndex, const std::string &peaks, bool hasDeltaFunction); - void setModel(const std::string &background, - const std::vector<std::string> &resolutionWorkspaces, - std::vector<int> resolutionWorkspaceIndex, - const std::string &peaks, bool hasDeltaFunction); + void + setModel(const std::string &background, + const std::vector<std::pair<std::string, int>> &resolutionWorkspaces, + const std::string &peaks, bool hasDeltaFunction); boost::optional<QString> backgroundPrefix() const { return m_backgroundPrefix; } diff --git a/qt/widgets/common/src/ConvolutionFunctionModel.cpp b/qt/widgets/common/src/ConvolutionFunctionModel.cpp index 3fe1b1667d5..000a5fe496e 100644 --- a/qt/widgets/common/src/ConvolutionFunctionModel.cpp +++ b/qt/widgets/common/src/ConvolutionFunctionModel.cpp @@ -66,21 +66,20 @@ void ConvolutionFunctionModel::setModel(const std::string &background, void ConvolutionFunctionModel::setModel( const std::string &background, - const std::vector<std::string> &resolutionWorkspaces, - std::vector<int> resolutionWorkspaceIndex, const std::string &peaks, - bool hasDeltaFunction) { + const std::vector<std::pair<std::string, int>> &resolutionWorkspaces, + const std::string &peaks, bool hasDeltaFunction) { std::string resolution, convolution, function; auto const model = hasDeltaFunction ? "name=DeltaFunction;" + peaks : peaks; 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) { - auto workspace = resolutionWorkspaces[i]; + auto workspace = resolutionWorkspaces[i].first; resolution = workspace.empty() ? "name=Resolution" : "name=Resolution,Workspace=\"" + workspace + "\",WorkspaceIndex=" + - std::to_string(resolutionWorkspaceIndex[i]); + std::to_string(resolutionWorkspaces[i].second); convolution = "composite=Convolution;" + resolution + ";" + model; function = background.empty() ? convolution : background + ";(" + convolution + ")"; diff --git a/qt/widgets/common/test/ConvolutionFunctionModelTest.h b/qt/widgets/common/test/ConvolutionFunctionModelTest.h index cd962e10cf8..c85f6f16cce 100644 --- a/qt/widgets/common/test/ConvolutionFunctionModelTest.h +++ b/qt/widgets/common/test/ConvolutionFunctionModelTest.h @@ -256,9 +256,13 @@ public: 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("", std::vector<std::string>(2, "abc"), - std::vector<int>({1, 2}), "", false); + model.setModel("", fitResolutions, "", false); auto fitFunctionAsString = model.getFitFunction()->asString(); TS_ASSERT_EQUALS( -- GitLab