From d3bec142f13552d4362d1fd5266f3e8d4021174b Mon Sep 17 00:00:00 2001
From: Roman Tolchenov <roman.tolchenov@stfc.ac.uk>
Date: Mon, 21 Feb 2011 15:28:24 +0000
Subject: [PATCH] Added algorithm FFTDerivative. re #2517

---
 .../Framework/Algorithms/CMakeLists.txt       |   7 +-
 .../inc/MantidAlgorithms/FFTDerivative.h      |  61 ++++++++
 .../Algorithms/src/FFTDerivative.cpp          | 132 ++++++++++++++++++
 .../Algorithms/test/FFTDerivativeTest.h       |  89 ++++++++++++
 4 files changed, 287 insertions(+), 2 deletions(-)
 create mode 100644 Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FFTDerivative.h
 create mode 100644 Code/Mantid/Framework/Algorithms/src/FFTDerivative.cpp
 create mode 100644 Code/Mantid/Framework/Algorithms/test/FFTDerivativeTest.h

diff --git a/Code/Mantid/Framework/Algorithms/CMakeLists.txt b/Code/Mantid/Framework/Algorithms/CMakeLists.txt
index ba00fe0db53..5344bd916a6 100644
--- a/Code/Mantid/Framework/Algorithms/CMakeLists.txt
+++ b/Code/Mantid/Framework/Algorithms/CMakeLists.txt
@@ -49,6 +49,7 @@ set ( SRC_FILES src/AbsorptionCorrection.cpp
 		src/ExtractMasking.cpp
 		src/ExtractSingleSpectrum.cpp
 		src/FFT.cpp
+		src/FFTDerivative.cpp
 		src/FFTSmooth2.cpp
 		src/FFTSmooth.cpp
 		src/FilterBadPulses.cpp
@@ -184,6 +185,7 @@ set ( INC_FILES inc/MantidAlgorithms/AbsorptionCorrection.h
 		inc/MantidAlgorithms/ExtractMasking.h
 		inc/MantidAlgorithms/ExtractSingleSpectrum.h
 		inc/MantidAlgorithms/FFT.h
+		inc/MantidAlgorithms/FFTDerivative.h
 		inc/MantidAlgorithms/FFTSmooth2.h
 		inc/MantidAlgorithms/FFTSmooth.h
 		inc/MantidAlgorithms/FilterBadPulses.h
@@ -317,6 +319,7 @@ set ( TEST_FILES test/AddSampleLogTest.h
 		 test/ExtractSingleSpectrumTest.h
 		 test/FFTSmooth2Test.h
 		 test/FFTTest.h
+		 test/FFTDerivativeTest.h
 		 test/FilterByLogValueTest.h
 		 test/FilterByTimeTest.h
 		 test/FindCenterOfMassPositionTest.h
@@ -335,7 +338,7 @@ set ( TEST_FILES test/AddSampleLogTest.h
 		 test/IdentifyNoisyDetectorsTest.h
 		 test/IntegrationTest.h
 		 test/InterpolatingRebinTest.h
-                 test/IQTransformTest.h
+		 test/IQTransformTest.h
 		 test/LogarithmTest.h
 		 test/MaskBinsTest.h
 		 test/MedianDetectorTestTest.h
@@ -389,7 +392,7 @@ set ( TEST_FILES test/AddSampleLogTest.h
 		 test/UnaryOperationTest.h
 		 test/UnGroupWorkspacesTest.h
 		 test/UnwrapTest.h
-         test/WeightedMeanTest.h
+		 test/WeightedMeanTest.h
 		 test/WorkspaceGroupTest.h
 		 )
 
diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FFTDerivative.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FFTDerivative.h
new file mode 100644
index 00000000000..fb9c5c23952
--- /dev/null
+++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/FFTDerivative.h
@@ -0,0 +1,61 @@
+#ifndef FFTDERIVATIVE_H_
+#define FFTDERIVATIVE_H_
+
+#include "MantidAPI/Algorithm.h"
+
+namespace Mantid
+{
+namespace Algorithms
+{
+
+/** Calculates derivatives of the spectra in a MatrixWorkspace using a Fast Fourier Transform.
+
+    @author Roman Tolchenov
+    @date 21/02/2011
+
+    Copyright &copy; 2008 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
+
+    This file is part of Mantid.
+
+    Mantid is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    Mantid is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+    File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>
+    Code Documentation is available at: <http://doxygen.mantidproject.org>
+ */
+class FFTDerivative : public Mantid::API::Algorithm
+{
+public:
+  /// (Empty) Constructor
+  FFTDerivative() : Mantid::API::Algorithm() {}
+  /// Virtual destructor
+  virtual ~FFTDerivative() {}
+  /// Algorithm's name
+  virtual const std::string name() const { return "FFTDerivative"; }
+  /// Algorithm's version
+  virtual int version() const { return (1); }
+  /// Algorithm's category for identification
+  virtual const std::string category() const { return "General"; }
+
+private:
+  /// Initialisation code
+  void init();
+  ///Execution code
+  void exec();
+
+};
+
+} // FFT
+} // Mandid
+
+#endif /*DERIVATIVE_H_*/
diff --git a/Code/Mantid/Framework/Algorithms/src/FFTDerivative.cpp b/Code/Mantid/Framework/Algorithms/src/FFTDerivative.cpp
new file mode 100644
index 00000000000..61d2070ebb0
--- /dev/null
+++ b/Code/Mantid/Framework/Algorithms/src/FFTDerivative.cpp
@@ -0,0 +1,132 @@
+#include "MantidAlgorithms/FFTDerivative.h"
+
+#include <algorithm>
+#include <functional>
+
+namespace Mantid
+{
+namespace Algorithms
+{
+
+// Register the algorithm into the AlgorithmFactory
+DECLARE_ALGORITHM(FFTDerivative)
+
+using namespace Mantid::Kernel;
+using namespace Mantid::API;
+
+void FFTDerivative::init()
+{
+  declareProperty(new WorkspaceProperty<>("InputWorkspace","",Direction::Input,"Input workspace for differentiation"));
+  declareProperty(new WorkspaceProperty<>("OutputWorkspace","",Direction::Output,"Workspace with result derivatives"));
+}
+
+void FFTDerivative::exec()
+{
+
+  MatrixWorkspace_sptr inWS = getProperty("InputWorkspace");
+  MatrixWorkspace_sptr outWS;
+
+  int n = inWS->getNumberHistograms();
+  API::Progress progress(this,0,1,n);
+
+  int ny = inWS->readY(0).size();
+  int nx = inWS->readX(0).size();
+
+  // Workspace for holding a copy of a spectrum. Each spectrum is symmetrized to minimize
+  // possible edge effects.
+  MatrixWorkspace_sptr copyWS = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>
+    (Mantid::API::WorkspaceFactory::Instance().create(inWS,1,nx+ny,ny+ny));
+
+  bool isHist = (nx != ny);
+
+  for(int spec = 0; spec < n; ++spec)
+  {
+
+    const Mantid::MantidVec& x0 = inWS->readX(spec);
+    const Mantid::MantidVec& y0 = inWS->readY(spec);
+
+    Mantid::MantidVec& x1 = copyWS->dataX(0);
+    Mantid::MantidVec& y1 = copyWS->dataY(0);
+
+    double xx = 2*x0[0];
+
+    x1[ny] = x0[0];
+    y1[ny] = y0[0];
+
+    for(int i = 1; i < ny; ++i)
+    {
+      int j1 = ny - i;
+      int j2 = ny + i;
+      x1[j1] = xx - x0[i];
+      x1[j2] = x0[i];
+      y1[j1] = y1[j2] = y0[i];
+    }
+
+    x1[0] = 2*x1[1] - x1[2];
+    y1[0] = y0.back();
+
+    if (isHist)
+    {
+      x1[y1.size()] = x0[ny];
+    }
+
+    // Transform symmetrized spectrum
+    IAlgorithm_sptr fft = createSubAlgorithm("RealFFT");
+    fft->setProperty("InputWorkspace",copyWS);
+    fft->setProperty("WorkspaceIndex",0);
+    fft->setProperty("Transform","Forward");
+    fft->execute();
+
+    MatrixWorkspace_sptr transWS = fft->getProperty("OutputWorkspace");
+
+    Mantid::MantidVec& nu = transWS->dataX(0);
+    Mantid::MantidVec& re = transWS->dataY(0);
+    Mantid::MantidVec& im = transWS->dataY(1);
+
+    // Multiply the transform by 2*pi*i*w
+    for(int j=0; j < re.size(); ++j)
+    {
+      double w = 2 * M_PI * nu[j];
+      double a =  re[j]*w;
+      double b = -im[j]*w;
+      re[j] = b;
+      im[j] = a;
+    }
+
+    // Inverse transform
+    fft = createSubAlgorithm("RealFFT");
+    fft->setProperty("InputWorkspace",transWS);
+    fft->setProperty("Transform","Backward");
+    fft->execute();
+
+    transWS = fft->getProperty("OutputWorkspace");
+
+    int m2 = transWS->readY(0).size() / 2;
+    int my = m2 + (transWS->readY(0).size() % 2 ? 1 : 0);
+    int mx = my + (transWS->isHistogramData() ? 1 : 0);
+
+    if (!outWS)
+    {
+      outWS = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>
+        (Mantid::API::WorkspaceFactory::Instance().create(inWS,n,mx,my));
+    }
+
+    // Save the upper half of the inverse transform for output
+    Mantid::MantidVec& x = outWS->dataX(spec);
+    Mantid::MantidVec& y = outWS->dataY(spec);
+    double dx = x1[0];
+    std::copy(transWS->dataX(0).begin() + m2,transWS->dataX(0).end(),x.begin());
+    std::transform(x.begin(),x.end(),x.begin(),std::bind2nd(std::plus<double>(),dx));
+    std::copy(transWS->dataY(0).begin() + m2,transWS->dataY(0).end(),y.begin());
+
+    progress.report();
+
+  }
+
+  setProperty("OutputWorkspace",outWS);
+
+}
+
+} // Algorithms
+} // Mandid
+
diff --git a/Code/Mantid/Framework/Algorithms/test/FFTDerivativeTest.h b/Code/Mantid/Framework/Algorithms/test/FFTDerivativeTest.h
new file mode 100644
index 00000000000..540f044faea
--- /dev/null
+++ b/Code/Mantid/Framework/Algorithms/test/FFTDerivativeTest.h
@@ -0,0 +1,89 @@
+#ifndef FFT_DERIVATIVE_TEST_H_
+#define FFT_DERIVATIVE_TEST_H_
+
+#include <cxxtest/TestSuite.h>
+
+#include "MantidAlgorithms/FFTDerivative.h"
+#include "MantidAPI/AnalysisDataService.h"
+#include "MantidAPI/FrameworkManager.h"
+#include "MantidAPI/MatrixWorkspace.h"
+#include "MantidDataObjects/Workspace2D.h"
+
+using namespace Mantid;
+using namespace Mantid::API;
+
+class FFTDerivativeTest : public CxxTest::TestSuite
+{
+public:
+  FFTDerivativeTest()
+  {
+  }
+  ~FFTDerivativeTest()
+  {
+  }
+
+  void testGaussianDerivative()
+  {
+    const int N = 100;
+
+    createWS(N,0,"exp");
+
+    IAlgorithm* fft = Mantid::API::FrameworkManager::Instance().createAlgorithm("FFTDerivative");
+    fft->initialize();
+    fft->setPropertyValue("InputWorkspace","FFTDerivative_WS_exp");
+    fft->setPropertyValue("OutputWorkspace","FFTDerivative_out");
+    fft->execute();
+
+    MatrixWorkspace_sptr fWS = boost::dynamic_pointer_cast<MatrixWorkspace>
+      (AnalysisDataService::Instance().retrieve("FFTDerivative_out"));
+
+    const MantidVec& X = fWS->readX(0);
+    const MantidVec& Y = fWS->readY(0);
+
+    TS_ASSERT_EQUALS(Y.size(),101);
+
+    for(int i=0; i < Y.size(); ++i)
+    {
+      double xx = X[i] - 5.1;
+      TS_ASSERT_DELTA( Y[i],(-2 * xx * exp(-(xx*xx)*2)*2),0.000001);
+    }
+
+    FrameworkManager::Instance().deleteWorkspace("FFTDerivative_WS_exp");
+    FrameworkManager::Instance().deleteWorkspace("FFTDerivative_out");
+  }
+
+
+private:
+
+  MatrixWorkspace_sptr createWS(int n,int dn,const std::string& name)
+  {
+    FrameworkManager::Instance();
+    Mantid::DataObjects::Workspace2D_sptr ws = boost::dynamic_pointer_cast<Mantid::DataObjects::Workspace2D>
+      (WorkspaceFactory::Instance().create("Workspace2D",1,n+dn,n));
+
+    const double dX = 10.0 / (n-1);
+    const double x0 = 0.;
+    const double c = 5.1;
+    Mantid::MantidVec& X = ws->dataX(0);
+    Mantid::MantidVec& Y = ws->dataY(0);
+    Mantid::MantidVec& E = ws->dataE(0);
+
+    for(int i=0;i<n;i++)
+    {
+      double x = x0 + dX*(i);
+      X[i] = x;
+      Y[i] = exp(-(x-c)*(x-c)*2);
+      E[i] = 1.;
+    }
+
+    if (dn > 0)
+      X[n] = X[n-1] + dX;
+
+    AnalysisDataService::Instance().add("FFTDerivative_WS_"+name,ws);
+
+    return ws;
+  }
+
+};
+
+#endif /*FFT_DERIVATIVE_TEST_H_*/
-- 
GitLab