From b45b6db17aa3ccf58b7fc741f64213c1eac24e0a Mon Sep 17 00:00:00 2001
From: Matthew Andrew <matthew.andrew@tessella.com>
Date: Mon, 20 Jan 2020 16:44:40 +0000
Subject: [PATCH] Updated temperature function model Re #26881

---
 .../Common/ConvolutionFunctionModel.h         |   5 +-
 .../common/src/ConvolutionFunctionModel.cpp   | 165 ++++++++----------
 .../test/ConvolutionFunctionModelTest.h       |  54 ++++--
 3 files changed, 121 insertions(+), 103 deletions(-)

diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h b/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h
index 21f7788b9ae..3ffd339a488 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/ConvolutionFunctionModel.h
@@ -49,7 +49,10 @@ public:
 
 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,
diff --git a/qt/widgets/common/src/ConvolutionFunctionModel.cpp b/qt/widgets/common/src/ConvolutionFunctionModel.cpp
index f5a0d1f378d..1754c2841f1 100644
--- a/qt/widgets/common/src/ConvolutionFunctionModel.cpp
+++ b/qt/widgets/common/src/ConvolutionFunctionModel.cpp
@@ -24,25 +24,28 @@ using namespace Mantid::API;
 
 namespace {
 
-bool isConvolution(const IFunction_sptr &fun) {
-  return fun->name() == "Convolution";
-}
+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 isProductFunction(const IFunction_sptr &fun) {
-  return fun->name() == "ProductFunction";
+bool isTempFunction(const IFunction *fun) {
+  return fun->name() == "UserFunction";
 }
 
-bool isBackground(const IFunction_sptr &fun) {
+bool isBackground(const IFunction *fun) {
   return static_cast<bool>(
-      boost::dynamic_pointer_cast<const IBackgroundFunction>(fun));
+      dynamic_cast<const IBackgroundFunction*>(fun));
+}
+
+bool isPeakFunction(const IFunction *fun) {
+  if(dynamic_cast<const CompositeFunction*>(fun)){
+    return false;
+  }
+  return true;
 }
 
 } // namespace
@@ -81,17 +84,17 @@ void ConvolutionFunctionModel::setModel(
   for (int i = 0; i < nf; ++i) {
     CompositeFunction_sptr domainFunction;
     auto qValue = qValues.empty() ? 0.0 : qValues[i];
-    domainFunction = createInnerFunction(peaks, hasDeltaFunction, isQDependent,
-                                         qValue, hasTempCorrection);
+    auto innerFunction = createInnerFunction(
+        peaks, hasDeltaFunction, isQDependent, qValue, hasTempCorrection);
     auto workspace =
         resolutionWorkspaces.empty() ? "" : resolutionWorkspaces[i].first;
     auto workspaceIndex =
         resolutionWorkspaces.empty() ? 0 : resolutionWorkspaces[i].second;
     auto resolutionFunction =
         createResolutionFunction(workspace, workspaceIndex);
-    domainFunction =
-        createConvolutionFunction(resolutionFunction, domainFunction);
-    domainFunction = addBackground(domainFunction, background);
+    auto convolutionFunction =
+        createConvolutionFunction(resolutionFunction, innerFunction);
+    domainFunction = addBackground(convolutionFunction, background);
 
     fitFunction->addFunction(domainFunction);
     fitFunction->setDomainIndex(i, i);
@@ -142,13 +145,23 @@ CompositeFunction_sptr ConvolutionFunctionModel::createInnerFunction(
       innerFunction->setAttribute("Q", attr);
     }
   }
+
+  if (hasTempCorrection) {
+    innerFunction = addTempCorrection(innerFunction);
+  }
+
   if (hasDeltaFunction) {
     auto deltaFunction =
         FunctionFactory::Instance().createFunction("DeltaFunction");
-    innerFunction->addFunction(deltaFunction);
-  }
-  if (hasTempCorrection) {
-    innerFunction = addTempCorrection(innerFunction);
+    if (!hasTempCorrection) {
+      innerFunction->addFunction(deltaFunction);
+    } else {
+      CompositeFunction_sptr innerFunctionNew =
+          boost::make_shared<CompositeFunction>();
+      innerFunctionNew->addFunction(deltaFunction);
+      innerFunctionNew->addFunction(innerFunction);
+      return innerFunctionNew;
+    }
   }
 
   return innerFunction;
@@ -208,92 +221,62 @@ void ConvolutionFunctionModel::findComponentPrefixes() {
   m_convolutionPrefix.reset();
   m_deltaFunctionPrefix.reset();
   m_tempFunctionPrefix.reset();
-  m_peakPrefixes.reset();
+  m_peakPrefixes = QStringList();
   m_resolutionWorkspace.clear();
   m_resolutionWorkspaceIndex = 0;
+
   auto function = getCurrentFunction();
-  if (!function)
+  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 model = fun->getFunction(1);
-  QString convolutionPrefix = "f1.";
-  if (isProductFunction(model)) {
-    model = model->getFunction(1);
-    convolutionPrefix = "f1.f1.";
-    m_tempFunctionPrefix = *m_convolutionPrefix + "f1.f0.";
+  for (size_t k = 0; k < numberOfSubFunction; ++k) {
+    iterateThroughFunction(func->getFunction(k).get(),
+                           prefix + QString("f%1.").arg(k));
   }
-  auto const nm = model->nFunctions();
-  if (nm == 0) {
-    auto const prefix = *m_convolutionPrefix + convolutionPrefix;
-    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 + convolutionPrefix + QString("f%1.").arg(j);
-      if (isDeltaFunction(model->getFunction(j))) {
-        m_deltaFunctionPrefix = prefix;
-      } else {
-        m_peakPrefixes->append(prefix);
-      }
+}
+
+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 5022c152da5..73558d05631 100644
--- a/qt/widgets/common/test/ConvolutionFunctionModelTest.h
+++ b/qt/widgets/common/test/ConvolutionFunctionModelTest.h
@@ -31,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(
@@ -92,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(), "");
@@ -399,21 +404,21 @@ public:
         "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=();(composite="
-        "ProductFunction,NumDeriv=false;name=UserFunction,Formula=x*11.606/"
-        "Temp/(1-exp( "
+        "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;"
-        "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=();(composite=ProductFunction,"
+        "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;"
-        "name=DeltaFunction,Height=1,Centre=0))))");
+        "PeakCentre=0,FWHM=0;name=Lorentzian,Amplitude=1,PeakCentre=0,FWHM=0)))"
+        "))");
   }
 
   void test_component_prefixes_set_correctly_without_temp_correction() {
@@ -521,6 +526,33 @@ public:
     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);
+    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_
-- 
GitLab