From 492aff6d156bc1f4a38c8bffef85609c2996ad29 Mon Sep 17 00:00:00 2001
From: Michael Wedel <michael.wedel@psi.ch>
Date: Wed, 11 Mar 2015 16:54:27 +0100
Subject: [PATCH] Refs #11043. Correcting parameter behavior, adding peaks.

---
 .../inc/MantidCurveFitting/PawleyFunction.h   | 22 +++++-
 .../CurveFitting/src/PawleyFunction.cpp       | 78 ++++++++++++++++---
 .../CurveFitting/test/PawleyFunctionTest.h    | 36 +++++++--
 3 files changed, 118 insertions(+), 18 deletions(-)

diff --git a/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/PawleyFunction.h b/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/PawleyFunction.h
index 948dd31ac10..f7b795c8209 100644
--- a/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/PawleyFunction.h
+++ b/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/PawleyFunction.h
@@ -5,6 +5,7 @@
 #include "MantidAPI/CompositeFunction.h"
 #include "MantidAPI/FunctionParameterDecorator.h"
 #include "MantidAPI/IFunction1D.h"
+#include "MantidAPI/IPeakFunction.h"
 #include "MantidAPI/ParamFunction.h"
 
 #include "MantidGeometry/Crystal/PointGroup.h"
@@ -26,6 +27,14 @@ public:
   Geometry::PointGroup::CrystalSystem getCrystalSystem() const;
   Geometry::UnitCell getUnitCellFromParameters() const;
 
+  std::string getProfileFunctionName() const {
+    return getAttribute("ProfileFunction").asString();
+  }
+
+  std::string getProfileFunctionCenterParameterName() const {
+    return m_profileFunctionCenterParameterName;
+  }
+
   void function(const API::FunctionDomain &domain,
                 API::FunctionValues &values) const;
   void functionDeriv(const API::FunctionDomain &domain,
@@ -34,12 +43,16 @@ public:
 protected:
   void init();
 
+  void setProfileFunction(const std::string &profileFunction);
   void setCrystalSystem(const std::string &crystalSystem);
 
   void createCrystalSystemParameters(
       Geometry::PointGroup::CrystalSystem crystalSystem);
+  void setCenterParameterNameFromFunction(
+      const API::IPeakFunction_sptr &profileFunction);
 
   Geometry::PointGroup::CrystalSystem m_crystalSystem;
+  std::string m_profileFunctionCenterParameterName;
 };
 
 typedef boost::shared_ptr<PawleyParameterFunction> PawleyParameterFunction_sptr;
@@ -82,6 +95,7 @@ typedef boost::shared_ptr<PawleyParameterFunction> PawleyParameterFunction_sptr;
 class PawleyFunction : public API::IFunction1D,
                        public API::FunctionParameterDecorator {
 public:
+  PawleyFunction();
   virtual ~PawleyFunction() {}
 
   std::string name() const { return "PawleyFunction"; }
@@ -94,10 +108,12 @@ public:
                        const size_t nData);
   void functionDeriv(const API::FunctionDomain &domain,
                      API::Jacobian &jacobian) {
-      calNumericalDeriv(domain, jacobian);
+    calNumericalDeriv(domain, jacobian);
   }
 
-  void addPeak();
+  void addPeak(const Kernel::V3D &hkl, double centre, double fwhm,
+               double height);
+  API::IPeakFunction_sptr getPeak(size_t i) const;
 
 protected:
   void init();
@@ -106,6 +122,8 @@ protected:
   API::CompositeFunction_sptr m_compositeFunction;
   PawleyParameterFunction_sptr m_pawleyParameterFunction;
   API::CompositeFunction_sptr m_peakProfileComposite;
+
+  std::vector<Kernel::V3D> m_hkls;
 };
 } // namespace CurveFitting
 } // namespace Mantid
diff --git a/Code/Mantid/Framework/CurveFitting/src/PawleyFunction.cpp b/Code/Mantid/Framework/CurveFitting/src/PawleyFunction.cpp
index d729affefce..6fbed58fa98 100644
--- a/Code/Mantid/Framework/CurveFitting/src/PawleyFunction.cpp
+++ b/Code/Mantid/Framework/CurveFitting/src/PawleyFunction.cpp
@@ -14,12 +14,15 @@ using namespace API;
 using namespace Geometry;
 
 PawleyParameterFunction::PawleyParameterFunction()
-    : ParamFunction(), m_crystalSystem(PointGroup::Triclinic) {}
+    : ParamFunction(), m_crystalSystem(PointGroup::Triclinic),
+      m_profileFunctionCenterParameterName() {}
 
 void PawleyParameterFunction::setAttribute(const std::string &attName,
                                            const Attribute &attValue) {
   if (attName == "CrystalSystem") {
     setCrystalSystem(attValue.asString());
+  } else if (attName == "ProfileFunction") {
+    setProfileFunction(attValue.asString());
   }
 
   ParamFunction::setAttribute(attName, attValue);
@@ -81,15 +84,21 @@ void PawleyParameterFunction::init() {
   declareAttribute("CrystalSystem", IFunction::Attribute("Triclinic"));
   declareAttribute("ProfileFunction", IFunction::Attribute("Gaussian"));
 
-  declareParameter("a", 1.0);
-  declareParameter("b", 1.0);
-  declareParameter("c", 1.0);
+  setCrystalSystem("Triclinic");
+  setProfileFunction("Gaussian");
+}
 
-  declareParameter("Alpha", 90.0);
-  declareParameter("Beta", 90.0);
-  declareParameter("Gamma", 90.0);
+void PawleyParameterFunction::setProfileFunction(
+    const std::string &profileFunction) {
+  IPeakFunction_sptr peakFunction = boost::dynamic_pointer_cast<IPeakFunction>(
+      FunctionFactory::Instance().createFunction(profileFunction));
 
-  declareParameter("ZeroShift", 0.0);
+  if (!peakFunction) {
+    throw std::invalid_argument("PawleyFunction can only use IPeakFunctions to "
+                                "calculate peak profiles.");
+  }
+
+  setCenterParameterNameFromFunction(peakFunction);
 }
 
 void
@@ -166,6 +175,19 @@ void PawleyParameterFunction::createCrystalSystemParameters(
   declareParameter("ZeroShift", 0.0);
 }
 
+void PawleyParameterFunction::setCenterParameterNameFromFunction(
+    const IPeakFunction_sptr &profileFunction) {
+  m_profileFunctionCenterParameterName.clear();
+  if (profileFunction) {
+    m_profileFunctionCenterParameterName =
+        profileFunction->getCentreParameterName();
+  }
+}
+
+PawleyFunction::PawleyFunction()
+    : FunctionParameterDecorator(), m_compositeFunction(),
+      m_pawleyParameterFunction(), m_peakProfileComposite(), m_hkls() {}
+
 void PawleyFunction::setCrystalSystem(const std::string &crystalSystem) {
   m_pawleyParameterFunction->setAttributeValue("CrystalSystem", crystalSystem);
   m_compositeFunction->checkFunction();
@@ -174,6 +196,23 @@ void PawleyFunction::setCrystalSystem(const std::string &crystalSystem) {
 void PawleyFunction::setProfileFunction(const std::string &profileFunction) {
   m_pawleyParameterFunction->setAttributeValue("ProfileFunction",
                                                profileFunction);
+
+  // At this point PawleyParameterFunction guarantees that it's an IPeakFunction
+  for (size_t i = 0; i < m_peakProfileComposite->nFunctions(); ++i) {
+    IPeakFunction_sptr oldFunction = boost::dynamic_pointer_cast<IPeakFunction>(
+        m_peakProfileComposite->getFunction(i));
+
+    IPeakFunction_sptr newFunction = boost::dynamic_pointer_cast<IPeakFunction>(
+        FunctionFactory::Instance().createFunction(
+            m_pawleyParameterFunction->getProfileFunctionName()));
+
+    newFunction->setCentre(oldFunction->centre());
+    newFunction->setFwhm(oldFunction->fwhm());
+    newFunction->setHeight(oldFunction->height());
+
+    m_peakProfileComposite->replaceFunction(i, newFunction);
+  }
+
   m_compositeFunction->checkFunction();
 }
 
@@ -191,9 +230,26 @@ void PawleyFunction::functionDeriv1D(API::Jacobian *out, const double *xValues,
   UNUSED_ARG(nData);
 }
 
-void PawleyFunction::addPeak() {
-  m_peakProfileComposite->addFunction(
-      FunctionFactory::Instance().createFunction("Gaussian"));
+void PawleyFunction::addPeak(const Kernel::V3D &hkl, double centre, double fwhm,
+                             double height) {
+  m_hkls.push_back(hkl);
+
+  IPeakFunction_sptr peak = boost::dynamic_pointer_cast<IPeakFunction>(
+      FunctionFactory::Instance().createFunction(
+          m_pawleyParameterFunction->getProfileFunctionName()));
+
+  peak->setCentre(centre);
+  peak->setFwhm(fwhm);
+  peak->setHeight(height);
+
+  m_peakProfileComposite->addFunction(peak);
+
+  m_compositeFunction->checkFunction();
+}
+
+IPeakFunction_sptr PawleyFunction::getPeak(size_t i) const {
+  return boost::dynamic_pointer_cast<IPeakFunction>(
+      m_peakProfileComposite->getFunction(i));
 }
 
 void PawleyFunction::init() {
diff --git a/Code/Mantid/Framework/CurveFitting/test/PawleyFunctionTest.h b/Code/Mantid/Framework/CurveFitting/test/PawleyFunctionTest.h
index 0086d7a9c69..7942404e49e 100644
--- a/Code/Mantid/Framework/CurveFitting/test/PawleyFunctionTest.h
+++ b/Code/Mantid/Framework/CurveFitting/test/PawleyFunctionTest.h
@@ -263,14 +263,40 @@ public:
   }
 
   void testPawleyFunctionSetCrystalSystem() {
-      PawleyFunction fn;
-      fn.initialize();
+    PawleyFunction fn;
+    fn.initialize();
+
+    TS_ASSERT_EQUALS(fn.nParams(), 7);
+
+    fn.setCrystalSystem("Cubic");
+
+    TS_ASSERT_EQUALS(fn.nParams(), 2);
+  }
+
+  void testPawleyFunctionAddPeak() {
+    PawleyFunction fn;
+    fn.initialize();
+
+    TS_ASSERT_EQUALS(fn.nParams(), 7);
+
+    fn.addPeak(V3D(), 2.0, 3.0, 4.0);
+
+    TS_ASSERT_EQUALS(fn.nParams(), 10);
+  }
+
+  void testPawleyFunctionSetProfileFunction() {
+    PawleyFunction fn;
+    fn.initialize();
+
+    TS_ASSERT_EQUALS(fn.nParams(), 7);
+
+    fn.addPeak(V3D(), 2.0, 3.0, 4.0);
 
-      TS_ASSERT_EQUALS(fn.nParams(), 7);
+    TS_ASSERT_EQUALS(fn.nParams(), 10);
 
-      fn.setCrystalSystem("Cubic");
+    fn.setProfileFunction("PseudoVoigt");
 
-      TS_ASSERT_EQUALS(fn.nParams(), 2);
+    TS_ASSERT_EQUALS(fn.nParams(), 11);
   }
 
 private:
-- 
GitLab