From feb171c696fde6174d3627d669bfcfed5bd13f94 Mon Sep 17 00:00:00 2001
From: pospelov <pospelov@fz-juelich.de>
Date: Mon, 11 Jun 2012 13:21:17 +0200
Subject: [PATCH] Functional test for Convolve class, code cleanup.

---
 App/App.pro                                   |   4 +-
 .../{TestInstrument.h => TestConvolution.h}   |  19 +-
 ...TestInstrument.cpp => TestConvolution.cpp} | 276 ++++-----
 App/src/TestFactory.cpp                       |  14 +-
 Core/inc/Convolve.h                           |  52 +-
 Core/src/Convolve.cpp                         | 556 ++++--------------
 6 files changed, 262 insertions(+), 659 deletions(-)
 rename App/inc/{TestInstrument.h => TestConvolution.h} (75%)
 rename App/src/{TestInstrument.cpp => TestConvolution.cpp} (57%)

diff --git a/App/App.pro b/App/App.pro
index 5e1188a8c84..b3af846a5cd 100644
--- a/App/App.pro
+++ b/App/App.pro
@@ -17,7 +17,7 @@ SOURCES += \
     src/CommandLine.cpp \
     src/TestFactory.cpp \
     src/TestDiffuseReflection.cpp \
-    src/TestInstrument.cpp
+    src/TestConvolution.cpp
 
 HEADERS += \
     inc/DrawHelper.h \
@@ -32,7 +32,7 @@ HEADERS += \
     inc/CommandLine.h \
     inc/TestFactory.h \
     inc/TestDiffuseReflection.h \
-    inc/TestInstrument.h
+    inc/TestConvolution.h
 
 INCLUDEPATH += ./inc
 DEPENDPATH += ./inc
diff --git a/App/inc/TestInstrument.h b/App/inc/TestConvolution.h
similarity index 75%
rename from App/inc/TestInstrument.h
rename to App/inc/TestConvolution.h
index 79073497c70..b3b375894c3 100644
--- a/App/inc/TestInstrument.h
+++ b/App/inc/TestConvolution.h
@@ -1,5 +1,5 @@
-#ifndef TESTINSTRUMENT_H
-#define TESTINSTRUMENT_H
+#ifndef TESTCONVOLUTION_H
+#define TESTCONVOLUTION_H
 // ********************************************************************
 // * The BornAgain project                                            *
 // * Simulation of neutron and x-ray scattering at grazing incidence  *
@@ -24,10 +24,10 @@
 //! @class TestConvolution
 //! @brief Testing Convolve class for instrumental effects studies
 //- -------------------------------------------------------------------
-class TestInstrument : public IFunctionalTest
+class TestConvolution : public IFunctionalTest
 {
 public:
-    TestInstrument();
+    TestConvolution();
 
     void execute();
 
@@ -38,8 +38,17 @@ public:
     void test_convolve2d();
 
 private:
+    //! test function with many gaus'es on top of flat background for convolution studies
+    double fpeaks(double *x, double *par);
+
+    //! typedef of pair for the description of convolution mode
     typedef std::pair<std::string, MathFunctions::Convolve::Mode> mode_pair_t;
+
+    //! vector of pairs defined above
     std::vector<mode_pair_t> m_modes;
+
+    //! number of peaks for convolution test function
+    int m_npeaks;
 };
 
-#endif // TESTINSTRUMENT_H
+#endif // TESTCONVOLUTION_H
diff --git a/App/src/TestInstrument.cpp b/App/src/TestConvolution.cpp
similarity index 57%
rename from App/src/TestInstrument.cpp
rename to App/src/TestConvolution.cpp
index 98923c866ad..c48eebadf31 100644
--- a/App/src/TestInstrument.cpp
+++ b/App/src/TestConvolution.cpp
@@ -1,4 +1,4 @@
-#include "TestInstrument.h"
+#include "TestConvolution.h"
 #include "MathFunctions.h"
 #include "Convolve.h"
 #include "DrawHelper.h"
@@ -16,29 +16,14 @@
 #include "TGraph.h"
 #include "TBenchmark.h"
 #include "TStyle.h"
+#include "TText.h"
 
-std::vector<double > Convolve_MyFFT1D_B(int mode, const std::vector<double> &data1, const std::vector<double> &data2);
 
 
-int npeaks(30);
 
-Double_t fpeaks(Double_t *x, Double_t *par) {
-   Double_t result = par[0] + par[1]*x[0];
-   for (Int_t p=0;p<npeaks;p++) {
-      Double_t norm  = par[3*p+2];
-      Double_t mean  = par[3*p+3];
-      Double_t sigma = par[3*p+4];
-      result += norm*TMath::Gaus(x[0],mean,sigma);
-   }
-   return result;
-}
-
-
-
-
-TestInstrument::TestInstrument()
+TestConvolution::TestConvolution()
 {
-    std::cout << "TestInstrument::TestInstrument() -> Info." << std::endl;
+    std::cout << "TestConvolution::TestConvolution() -> Info." << std::endl;
 
     m_modes.push_back( mode_pair_t("LINEAR_FULL", MathFunctions::Convolve::FFTW_LINEAR_FULL));
     m_modes.push_back( mode_pair_t("LINEAR_SAME_UNPADDED", MathFunctions::Convolve::FFTW_LINEAR_SAME_UNPADDED));
@@ -48,107 +33,120 @@ TestInstrument::TestInstrument()
 }
 
 
-void TestInstrument::execute()
+void TestConvolution::execute()
 {
 
     test_convolve1d();
-    // results are about
-    // LINEAR_FULL: Real Time =   0.37 seconds Cpu Time =   0.36 seconds
-    // LINEAR_SAME_UNPADDED: Real Time =   1.03 seconds Cpu Time =   1.03 seconds
-    // LINEAR_SAME: Real Time =   0.23 seconds Cpu Time =   0.23 seconds
-    // CIRCULAR_SAME: Real Time =   0.50 seconds Cpu Time =   0.50 seconds
-    // CIRCULAR_SAME_SHIFTED: Real Time =   0.51 seconds Cpu Time =   0.51 seconds
-
-    //test_convolve2d();
-    // LINEAR_FULL: Real Time =   1.19 seconds Cpu Time =   1.18 seconds
-    // LINEAR_SAME_UNPADDED: Real Time =   0.72 seconds Cpu Time =   0.72 seconds
-    // LINEAR_SAME: Real Time =   0.72 seconds Cpu Time =   0.73 seconds
-    // CIRCULAR_SAME: Real Time =   0.53 seconds Cpu Time =   0.54 seconds
-    // CIRCULAR_SAME_SHIFTED: Real Time =   0.61 seconds Cpu Time =   0.61 seconds
 
-}
+    test_convolve2d();
+
+    /*
+    --- TestConvolution::test_convolve_1d() -> Peformance.
+    LINEAR_FULL: Real Time =   0.37 seconds Cpu Time =   0.37 seconds
+    LINEAR_SAME_UNPADDED: Real Time =   0.98 seconds Cpu Time =   0.98 seconds
+    LINEAR_SAME: Real Time =   0.22 seconds Cpu Time =   0.22 seconds
+    CIRCULAR_SAME: Real Time =   0.51 seconds Cpu Time =   0.50 seconds
+    CIRCULAR_SAME_SHIFTED: Real Time =   0.51 seconds Cpu Time =   0.51 seconds
 
+    --- TestConvolution::test_convolve_2d() -> Peformance.
+    LINEAR_FULL: Real Time =   1.26 seconds Cpu Time =   1.26 seconds
+    LINEAR_SAME_UNPADDED: Real Time =   0.76 seconds Cpu Time =   0.76 seconds
+    LINEAR_SAME: Real Time =   0.73 seconds Cpu Time =   0.73 seconds
+    CIRCULAR_SAME: Real Time =   0.57 seconds Cpu Time =   0.57 seconds
+    CIRCULAR_SAME_SHIFTED: Real Time =   0.62 seconds Cpu Time =   0.63 seconds
+    */
+
+}
 
 
-void TestInstrument::test_convolve1d()
+/* ************************************************************************* */
+// test of convolution of two arrays in 1d
+/* ************************************************************************* */
+void TestConvolution::test_convolve1d()
 {
-    npeaks = TMath::Abs(10);
     double xmin(0.0);
     double xmax(1000.);
     size_t npoints = 501;
-    double dx = (xmax-xmin)/(npoints-1);
-
-    double sigma0=(xmax-xmin)*0.001;
+    double dx = (xmax-xmin)/double(npoints-1);
+    double sigmax=(xmax-xmin)*0.01; // precision of the measurement of x-value
 
-    TH1F *href = new TH1F("h","test", npoints-1, xmin, xmax);
-    href->SetMinimum(0.0);
-    href->SetMaximum(2.0);
-
-    //generate n peaks at random
-    Double_t par[3000];
+    // generate signal (n gaus peaks at random on top of flat background)
+    std::vector<double > signal;
+    m_npeaks = 10;
+    double *par = new double[m_npeaks*3+2];
     par[0] = 1.0;
     par[1] = -0.6/(xmax-xmin);
-    Int_t p;
-    for (p=0;p<npeaks;p++) {
-       par[3*p+2] = 1;
-       par[3*p+3] = (xmax-xmin)*0.01+gRandom->Rndm()*(xmax-xmin);
-       par[3*p+4] = sigma0+sigma0*5*gRandom->Rndm();
+    for (int i_par=0; i_par<m_npeaks;i_par++) {
+       par[3*i_par+2] = 1;
+       par[3*i_par+3] = (xmax-xmin)*0.01+gRandom->Rndm()*(xmax-xmin);
+       par[3*i_par+4] = sigmax/5.+sigmax*gRandom->Rndm();
     }
-    TF1 *fspect = new TF1("f",fpeaks,0,1000,2+3*npeaks);
-    fspect->SetNpx(10000);
-    fspect->SetParameters(par);
-    TCanvas *c1 = new TCanvas("c1_test_convolve1d","c1_test_convolve1d",1024, 768);
-    c1->Divide(3,3);
-    c1->cd(1);
-    //href->FillRandom("f",20000);
-    href->DrawCopy();
-    fspect->Draw("pl same");
-
-    c1->cd(2);
-    double sigma_measure = sigma0*5;
-    TH1F *hmeasured = new TH1F("hp","hp",500, xmin, xmax);
-//    double sigma_measure=sigma0*3;
-    for(int i=0; i<1000000; i++) {
-        hmeasured->Fill(fspect->GetRandom(xmin, xmax) + gRandom->Gaus(0.0,sigma_measure));
-    }
-    hmeasured->Scale(1./hmeasured->GetEntries());
-    hmeasured->SetLineColor(kRed);
-    hmeasured->Draw();
-
-    std::vector<double> xspect;
-    xspect.resize(npoints);
+    TF1 *fsignal = new TF1("f",this, &TestConvolution::fpeaks, xmin, xmax,2+3*m_npeaks, "TestConvolution","fpeaks");
+    fsignal->SetNpx(10000);
+    fsignal->SetParameters(par);
+    signal.resize(npoints);
     for(size_t i=0; i<npoints; i++) {
         double x = xmin + i*dx;
-        xspect[i] = fspect->Eval(x);
-        std::cout << i << " " << x << " " << xspect[i] << std::endl;
+        signal[i] = fsignal->Eval(x);
     }
 
-    // building responce function
-    std::vector<double> xresp;
-    xresp.resize(npoints);
+    // building kernel
+    std::vector<double> kernel;
+    kernel.resize(npoints);
+    TGraph *gr_kernel = new TGraph(npoints);
 //    for(size_t i=0; i<npoints/2; i++) {
 //        double x = i*dx;
 //        double y = std::exp(-x*x/sigma_measure/sigma_measure);
-//        xresp[i] = y;
-//        xresp[npoints-1-i] = xresp[i];
+//        kernel[i] = y;
+//        kernel[npoints-1-i] = kernel[i];
 //    }
-
     for(size_t i=0; i<npoints; i++) {
         double x = -(xmax-xmin)/2.+i*dx;
-        double y = std::exp(-x*x/sigma_measure/sigma_measure);
-        xresp[i] = y;
+        double y = std::exp(-x*x/sigmax/sigmax);
+        kernel[i] = y;
+        gr_kernel->SetPoint(i,x,kernel[i]);
     }
 
-    TGraph *gr_resp = new TGraph(npoints);
-    for(size_t i=0; i<xresp.size(); i++){
-        double x = xmin + i*dx;
-        gr_resp->SetPoint(i,x,xresp[i]);
-    }
-    c1->cd(3);
+
+    // --------------
+    // drawing
+    // --------------
+    TCanvas *c1 = new TCanvas("c1_test_convolve1d","c1_test_convolve1d",1024, 768);
+    DrawHelper::instance().SetMagnifier(c1);
+    c1->Divide(3,3);
+
+    // drawing signal
+    c1->cd(1);
+    gPad->SetTopMargin(0.1);
+    TH1F *href = new TH1F("h","test", npoints-1, xmin, xmax);
+    href->SetMinimum(0.0);
+    href->SetMaximum(2.0);
+    href->SetStats(0);
     href->DrawCopy();
-    gr_resp->Draw("pl same");
+    href->SetBit(TH1::kNoTitle, false);
+    fsignal->SetTitle("signal");
+    fsignal->Draw("pl same");
+
+    // drawing measured signal
+    c1->cd(2);
+    gPad->SetTopMargin(0.1);
+    TH1F *hmeasured = new TH1F("hmeasured","hmeasured",500, xmin, xmax);
+    for(int i=0; i<1000000; i++) {
+        hmeasured->Fill(fsignal->GetRandom(xmin, xmax) + gRandom->Gaus(0.0,sigmax));
+    }
+    hmeasured->Scale(1./hmeasured->GetEntries());
+    hmeasured->SetLineColor(kRed);
+    hmeasured->SetStats(0);
+    hmeasured->SetBit(TH1::kNoTitle, false);
+    hmeasured->Draw();
 
+    // drawing kernel
+    c1->cd(3);
+    gPad->SetTopMargin(0.1);
+    gr_kernel->SetTitle("kernel");
+    gr_kernel->Draw("apl");
 
+    // calculation of convolution
     TBenchmark benchmark;
     for(size_t i_mode=0; i_mode<m_modes.size(); i_mode++) {
         std::string sname = m_modes[i_mode].first;
@@ -160,34 +158,34 @@ void TestInstrument::test_convolve1d()
 
         MathFunctions::Convolve cv;
         cv.setMode(mode);
-        std::vector<double> xresult;
+        std::vector<double> result;
         for(int i=0; i<1000; i++) {
-            //int mm = (int)modes[i_mode];
-     //       xresult = Convolve_MyFFT1D_B(mm, xspect, xresp);
-            cv.fftconvolve(xspect, xresp, xresult);
+            cv.fftconvolve(signal, kernel, result);
         }
         benchmark.Stop(sname.c_str());
-        benchmark.Show(sname.c_str());
-        for(size_t i=0; i<xresult.size(); i++) {
+        //benchmark.Show(sname.c_str());
+        for(size_t i=0; i<result.size(); i++) {
             double x = xmin + i*dx;
-            gr_result->SetPoint(i,x,xresult[i]);
+            gr_result->SetPoint(i,x,result[i]);
         }
         c1->cd(4+i_mode);
+        gPad->SetTopMargin(0.1);
         href->SetMaximum(20.0);
+        href->SetTitle(sname.c_str());
         href->DrawCopy();
         gr_result->Draw("pl same");
     }
     float_t rp, cp;
-    std::cout << "--------------" << std::endl;
+    std::cout << "--- TestConvolution::test_convolve_1d() -> Peformance." << std::endl;
     benchmark.Summary(rp, cp);
 
 }
 
 
 /* ************************************************************************* */
-//
+// test of convolution of two arrays in 2d
 /* ************************************************************************* */
-void TestInstrument::test_convolve2d()
+void TestConvolution::test_convolve2d()
 {
     double xmin(0.0), xmax(100.);
     size_t npx = 100;
@@ -211,13 +209,12 @@ void TestInstrument::test_convolve2d()
             // spikes
             if(ix>1 && iy!=0) {
                 if( (ix%20==0 || (ix-1)%20==0) && iy%8==0) {
-                    std::cout << ix << " " << iy << std::endl;
                     source[ix][iy]+=5;
                 }
             }
         } // iy
     } // ix
-    // signal histogram
+    // filling signal histogram with values from signal array
     TH2F *h2_signal = new TH2F("h2_signal","h2_signal", npx, xmin, xmax, npy, ymin, ymax);
     h2_signal->SetStats(0);
     h2_signal->SetMinimum(0);
@@ -236,6 +233,7 @@ void TestInstrument::test_convolve2d()
     // preparing resolution kernel and histogram
     std::vector<std::vector<double> > kernel;
     TH2F *h2_kernel = new TH2F("h2_kernel","h2_kernel", npx, xmin, xmax, npy, ymin, ymax);
+    h2_kernel->SetStats(0);
     kernel.resize(npx);
     for(size_t ix=0; ix<npx; ix++) {
         kernel[ix].resize(npy);
@@ -249,6 +247,7 @@ void TestInstrument::test_convolve2d()
 
     // simulation of measurements with smearing measurement with resolution function
     TH2F *h2_measured = new TH2F("h2_measured","h2_measured", npx, xmin, xmax, npy, ymin, ymax);
+    h2_measured->SetStats(0);
     TRandom mr;
     for(int i_meas=0; i_meas<1000000; i_meas++) {
         // generating distribution according to our signal
@@ -264,16 +263,24 @@ void TestInstrument::test_convolve2d()
     gStyle->SetPalette(1);
 
     c1->Divide(3,3);
-    c1->cd(1); gPad->SetRightMargin(0.15);
+    c1->cd(1);
+    gPad->SetRightMargin(0.12);
+    gPad->SetTopMargin(0.1);
     h2_signal->Draw("colz");
 
-    c1->cd(2); gPad->SetRightMargin(0.15);
+    c1->cd(2);
+    gPad->SetRightMargin(0.12);
+    gPad->SetTopMargin(0.1);
     h2_signal->Draw("lego");
 
-    c1->cd(3); gPad->SetRightMargin(0.15);
+    c1->cd(3);
+    gPad->SetRightMargin(0.12);
+    gPad->SetTopMargin(0.1);
     h2_kernel->Draw("lego");
 
-    c1->cd(4); gPad->SetRightMargin(0.15);
+    c1->cd(4);
+    gPad->SetRightMargin(0.12);
+    gPad->SetTopMargin(0.1);
     h2_measured->Draw("colz");
 
     // calculation of convolution
@@ -294,6 +301,8 @@ void TestInstrument::test_convolve2d()
 
         // drawing results of last convolution
         c1->cd(5+i_mode);
+        gPad->SetRightMargin(0.12);
+        gPad->SetTopMargin(0.1);
         TH2F h2_result("h2_result","h2_result", npx, xmin, xmax, npy, ymin, ymax);
         h2_result.SetStats(0);
         for(size_t ix=0; ix<npx; ix++) {
@@ -304,61 +313,32 @@ void TestInstrument::test_convolve2d()
             }
         }
         h2_result.SetTitle(sname.c_str());
+        h2_result.SetBit(TH1::kNoTitle, false);
         h2_result.DrawCopy("colz");
     }
 
     // benchmark summary
     float_t rp, cp;
-    std::cout << "--------------" << std::endl;
+    std::cout << "--- TestConvolution::test_convolve_2d() -> Peformance." << std::endl;
     benchmark.Summary(rp, cp);
 
 }
 
 
-
-
-std::vector<double> Convolve_MyFFT1D_B(int mode, const std::vector<double> &data1, const std::vector<double> &data2)
+/* ************************************************************************* */
+// test function for convolution
+/* ************************************************************************* */
+double TestConvolution::fpeaks(double *x, double *par)
 {
-    size_t Ns = data1.size();
-    double * src = new double[Ns];
-    for(size_t i=0; i<Ns; i++) {
-        src[i] = data1[i];
+    Double_t result = par[0] + par[1]*x[0];
+    for (Int_t p=0;p<m_npeaks;p++) {
+       Double_t norm  = par[3*p+2];
+       Double_t mean  = par[3*p+3];
+       Double_t sigma = par[3*p+4];
+       result += norm*TMath::Gaus(x[0],mean,sigma);
     }
-
-    size_t Nk = data2.size();
-    double * kernel = new double[Nk];
-    for(size_t i=0; i<Nk; i++) {
-        kernel[i] = data2[i];
-    }
-
-    FFTW_Workspace ws;
-//    init_workspace_fftw(ws, FFTW_LINEAR_FULL, 1,Ns,1,Nk);
-//    init_workspace_fftw(ws, FFTW_LINEAR_SAME_UNPADDED, 1,Ns,1,Nk);
-//    init_workspace_fftw(ws, FFTW_LINEAR_SAME, 1,Ns,1,Nk);
-//    init_workspace_fftw(ws, FFTW_LINEAR_VALID, 1,Ns,1,Nk);
-//    init_workspace_fftw(ws, FFTW_CIRCULAR_SAME, 1,Ns,1,Nk);
-//    init_workspace_fftw(ws, FFTW_CIRCULAR_SAME_SHIFTED, 1,Ns,1,Nk);
-
-    FFTW_Convolution_Mode xm = (FFTW_Convolution_Mode)mode;
-    init_workspace_fftw(ws, xm, 1,Ns,1,Nk);
-
-
-    fftw_convolve(ws, src, kernel);
-
-//    std::cout << "!!! " << ws.w_dst << std::endl;
-//    for(int j = 0 ; j < ws.w_dst ; ++j) std::cout << ws.dst[j] << " ";
-
-    std::vector<double > fft_result;
-    fft_result.resize(ws.w_dst);
-    for(size_t i=0; i<data1.size(); i++){
-        fft_result[i] = ws.dst[i];
-    }
-
-    clear_workspace_fftw(ws);
-    return fft_result;
+    return result;
 }
 
 
 
-
-
diff --git a/App/src/TestFactory.cpp b/App/src/TestFactory.cpp
index 97b6cf7705f..c60096d74f6 100644
--- a/App/src/TestFactory.cpp
+++ b/App/src/TestFactory.cpp
@@ -4,7 +4,7 @@
 #include "TestFormFactor.h"
 #include "TestDWBAFormFactor.h"
 #include "TestDiffuseReflection.h"
-#include "TestInstrument.h"
+#include "TestConvolution.h"
 
 #include "TBenchmark.h"
 
@@ -15,12 +15,12 @@ TestFactory::TestFactory() : m_benchmark(0)
     setStoreObjects(true);
     setDeleteObjects(true);
 
-    registerItem("roughness",  IFactoryCreateFunction<TestRoughness, IFunctionalTest> );
-    registerItem("fresnel",    IFactoryCreateFunction<TestFresnelCoeff, IFunctionalTest> );
-    registerItem("formfactor", IFactoryCreateFunction<TestFormFactor, IFunctionalTest> );
-    registerItem("dwba",       IFactoryCreateFunction<TestDWBAFormFactor, IFunctionalTest> );
-    registerItem("diffuse",    IFactoryCreateFunction<TestDiffuseReflection, IFunctionalTest> );
-    registerItem("instrument", IFactoryCreateFunction<TestInstrument, IFunctionalTest> );
+    registerItem("roughness",   IFactoryCreateFunction<TestRoughness, IFunctionalTest> );
+    registerItem("fresnel",     IFactoryCreateFunction<TestFresnelCoeff, IFunctionalTest> );
+    registerItem("formfactor",  IFactoryCreateFunction<TestFormFactor, IFunctionalTest> );
+    registerItem("dwba",        IFactoryCreateFunction<TestDWBAFormFactor, IFunctionalTest> );
+    registerItem("diffuse",     IFactoryCreateFunction<TestDiffuseReflection, IFunctionalTest> );
+    registerItem("convolution", IFactoryCreateFunction<TestConvolution, IFunctionalTest> );
 
     m_benchmark = new TBenchmark();
 }
diff --git a/Core/inc/Convolve.h b/Core/inc/Convolve.h
index 2ba520f64b6..7b0671a8cf8 100644
--- a/Core/inc/Convolve.h
+++ b/Core/inc/Convolve.h
@@ -52,6 +52,7 @@ public:
     typedef std::vector<double1d_t> double2d_t;
 
     //! convolution  modes
+    //! use LINEAR_SAME or CIRCULAR_SAME_SHIFTED for maximum performance
     enum Mode { FFTW_LINEAR_FULL, FFTW_LINEAR_SAME_UNPADDED, FFTW_LINEAR_SAME, FFTW_LINEAR_VALID, FFTW_CIRCULAR_SAME, FFTW_CIRCULAR_SAME_SHIFTED, FFTW_UNDEFINED };
 
     //! convolution in 1D
@@ -67,12 +68,7 @@ public:
     void setMode(Mode mode) { m_mode = mode; }
 
 private:
-    //! compute convolution of source and kernel using fast fourier transformation
-    void fftw_convolve(const double2d_t &source, const double2d_t &kernel);
-    //void fftw_convolve(double * src,double * kernel);
-
     //! compute circual convolution of source and kernel using fast fourier transformation
-    //void fftw_circular_convolution(double * src, double * kernel);
     void fftw_circular_convolution(const double2d_t &source, const double2d_t &kernel);
 
     //! find closest number X>n,  which  can be factorised according to fftw3 favorite factorisation
@@ -82,7 +78,7 @@ private:
     bool is_optimal(int n);
 
     //! Workspace contains input (source and kernel), intermediate and output arrays to run convolution via fft
-    //! 'source' it is our signal, 'kernel' it is our resolution (or delta-responce) function
+    //! 'source' it is our signal, 'kernel' it is our resolution (also known as delta-responce) function
     //! Sizes of input arrays are adjusted; output arrays are alocated via fftw3 allocation for maximum performance
     class Workspace
     {
@@ -102,6 +98,7 @@ private:
         double *dst_fft;                  // result of production of FFT(source) and FFT(kernel)
         int h_dst, w_dst;                 // size of resulting array
         double *dst;                      // The array containing the result
+        int h_offset, w_offset;           // offsets to copy result into output arrays
         fftw_plan p_forw_src;
         fftw_plan p_forw_kernel;
         fftw_plan p_back;
@@ -116,47 +113,4 @@ private:
 } // namespace MathFunctions
 
 
-typedef enum
-{
-    FFTW_LINEAR_FULL,
-    FFTW_LINEAR_SAME_UNPADDED,
-    FFTW_LINEAR_SAME,
-    FFTW_LINEAR_VALID,
-    FFTW_CIRCULAR_SAME,
-    FFTW_CIRCULAR_SAME_SHIFTED,
-    FFTW_CIRCULAR_CUSTOM
-} FFTW_Convolution_Mode;
-
-typedef struct FFTW_Workspace
-{
-    //fftw_complex * in_src, *out_src;
-    double * in_src, *out_src, *in_kernel, *out_kernel;
-    int h_src, w_src, h_kernel, w_kernel;
-    int w_fftw, h_fftw;
-    FFTW_Convolution_Mode mode;
-    double * dst_fft;
-    double * dst; // The array containing the result
-    int h_dst, w_dst; // its size ; This is automatically set by init_workspace, despite you use FFTW_CIRCULAR_CUSTOM
-    fftw_plan p_forw_src;
-    fftw_plan p_forw_kernel;
-    fftw_plan p_back;
-
-} FFTW_Workspace;
-
-extern void factorize (const int n,
-                int *n_factors,
-                int factors[],
-                int * implemented_factors);
-
-extern bool is_optimal(int n, int * implemented_factors);
-extern int find_closest_factor(int n, int * implemented_factor);
-extern void init_workspace_fftw(FFTW_Workspace & ws, FFTW_Convolution_Mode mode, int h_src, int w_src, int h_kernel, int w_kernel);
-extern void clear_workspace_fftw(FFTW_Workspace & ws);
-extern void fftw_convolve(FFTW_Workspace &ws, double * src,double * kernel);
-extern void fftw_circular_convolution(FFTW_Workspace &ws, double * src, double * kernel);
-
-
-
-
-
 #endif // CONVOLVE_H
diff --git a/Core/src/Convolve.cpp b/Core/src/Convolve.cpp
index fa2e7c70bc7..86a37ec4958 100644
--- a/Core/src/Convolve.cpp
+++ b/Core/src/Convolve.cpp
@@ -1,6 +1,7 @@
 #include "Convolve.h"
 #include <iostream>
 #include <stdexcept>
+#include <sstream>
 #include "Exceptions.h"
 
 MathFunctions::Convolve::Convolve() : m_mode(FFTW_UNDEFINED)
@@ -21,6 +22,7 @@ MathFunctions::Convolve::~Convolve()
 MathFunctions::Convolve::Workspace::Workspace() :
     h_src(0), w_src(0), h_kernel(0), w_kernel(0),
     w_fftw(0), h_fftw(0), in_src(0), out_src(0), in_kernel(0), out_kernel(0), dst_fft(0), h_dst(0), w_dst(0), dst(0),
+    h_offset(0), w_offset(0),
     p_forw_src(NULL), p_forw_kernel(NULL), p_back(NULL)
 {
 
@@ -57,6 +59,9 @@ void MathFunctions::Convolve::Workspace::clear()
     if(dst) delete[] dst;
     dst=0;
 
+    h_offset = 0;
+    w_offset = 0;
+
     if(p_forw_src != NULL) fftw_destroy_plan(p_forw_src);
     if(p_forw_kernel != NULL) fftw_destroy_plan(p_forw_kernel);
     if(p_back != NULL)  fftw_destroy_plan(p_back);
@@ -67,13 +72,13 @@ void MathFunctions::Convolve::Workspace::clear()
 
 
 /* ************************************************************************* */
-// convolution in dd
+// convolution in 2d
 /* ************************************************************************* */
 void MathFunctions::Convolve::fftconvolve(const double2d_t &source, const double2d_t &kernel, double2d_t &result)
 {
     // set default convolution mode, if not defined
     if(m_mode == FFTW_UNDEFINED) {
-        std::cout << "setting FFTW_LINEAR_SAME" << std::endl;
+        std::cout << "MathFunctions::Convolve::fftconvolve() -> Info. Setting FFTW_LINEAR_SAME convolution mode." << std::endl;
         setMode(FFTW_LINEAR_SAME);
     }
 
@@ -82,32 +87,10 @@ void MathFunctions::Convolve::fftconvolve(const double2d_t &source, const double
     size_t h_kernel = kernel.size();
     size_t w_kernel = (kernel.size() ? kernel[0].size() : 0);
 
-    if(!h_src || !w_src || !h_kernel || !w_kernel) {
-        std::cout << "MathFunctions::Convolve::fftconvolve() -> Panic! Wrong dimensions " << h_src << " " << w_src << " " << h_kernel << " " << w_kernel << std::endl;
-        throw std::runtime_error("XXX");
-    }
-
+    // initialisation
     init(h_src, w_src, h_kernel, w_kernel);
-
-//    double *src = new double[h_src*w_src];
-//    for(size_t i=0; i<h_src; i++) {
-//        for(size_t j=0; j<w_src; j++) {
-//            src[i*w_src + j] = source[i][j];
-//        }
-//    }
-
-//    double *krn = new double[h_kernel*w_kernel];
-//    for(size_t i=0; i<h_kernel; i++) {
-//        for(size_t j=0; j<w_kernel; j++) {
-//            krn[i*w_kernel + j] = kernel[i][j];
-//        }
-//    }
-
-//    fftw_convolve(src, krn);
-    fftw_convolve(source, kernel);
-
-//    delete [] src;
-//    delete [] krn;
+    // Compute the circular convolution
+    fftw_circular_convolution(source, kernel);
 
     // results
     result.clear();
@@ -115,7 +98,12 @@ void MathFunctions::Convolve::fftconvolve(const double2d_t &source, const double
     for(int i=0; i<ws.h_dst; i++) {
         result[i].resize(ws.w_dst,0);
         for(int j=0; j<ws.w_dst; j++) {
-            result[i][j]=ws.dst[i*ws.w_dst+j];
+            //result[i][j]=ws.dst[i*ws.w_dst+j];
+            if(m_mode == FFTW_CIRCULAR_SAME_SHIFTED) {
+                result[i][j] = ws.dst_fft[((i+int(ws.h_kernel/2.0))%ws.h_fftw)*ws.w_fftw+(j+int(ws.w_kernel/2.0))%ws.w_fftw];
+            } else {
+                result[i][j] = ws.dst_fft[(i+ws.h_offset)*ws.w_fftw+j+ws.w_offset];
+            }
         }
     }
 
@@ -147,6 +135,12 @@ void MathFunctions::Convolve::fftconvolve(const double1d_t &source, const double
 /* ************************************************************************* */
 void MathFunctions::Convolve::init(int h_src, int w_src, int h_kernel, int w_kernel)
 {
+    if(!h_src || !w_src || !h_kernel || !w_kernel) {
+        std::ostringstream os;
+        os << "MathFunctions::Convolve::init() -> Panic! Wrong dimensions " << h_src << " " << w_src << " " << h_kernel << " " << w_kernel << std::endl;
+        throw RuntimeErrorException(os.str());
+    }
+
     ws.clear();
     ws.h_src = h_src;
     ws.w_src = w_src;
@@ -160,6 +154,9 @@ void MathFunctions::Convolve::init(int h_src, int w_src, int h_kernel, int w_ker
         ws.w_fftw = find_closest_factor(w_src + w_kernel - 1);
         ws.h_dst = h_src + h_kernel-1;
         ws.w_dst = w_src + w_kernel-1;
+        // Here we just keep the first [0:h_dst-1 ; 0:w_dst-1] real part elements of out_src
+        ws.h_offset = 0;
+        ws.w_offset = 0;
         break;
     case FFTW_LINEAR_SAME_UNPADDED:
         // Same Linear convolution
@@ -167,6 +164,9 @@ void MathFunctions::Convolve::init(int h_src, int w_src, int h_kernel, int w_ker
         ws.w_fftw = w_src + int(w_kernel/2.0);
         ws.h_dst = h_src;
         ws.w_dst = w_src;
+        // Here we just keep the first [h_filt/2:h_filt/2+h_dst-1 ; w_filt/2:w_filt/2+w_dst-1] real part elements of out_src
+        ws.h_offset = int(ws.h_kernel/2.0);
+        ws.w_offset = int(ws.w_kernel/2.0);
         break;
     case FFTW_LINEAR_SAME:
         // Same Linear convolution
@@ -174,6 +174,9 @@ void MathFunctions::Convolve::init(int h_src, int w_src, int h_kernel, int w_ker
         ws.w_fftw = find_closest_factor(w_src + int(w_kernel/2.0));
         ws.h_dst = h_src;
         ws.w_dst = w_src;
+        // Here we just keep the first [h_filt/2:h_filt/2+h_dst-1 ; w_filt/2:w_filt/2+w_dst-1] real part elements of out_src
+        ws.h_offset = int(ws.h_kernel/2.0);
+        ws.w_offset = int(ws.w_kernel/2.0);
         break;
     case FFTW_LINEAR_VALID:
         // Valid Linear convolution
@@ -191,6 +194,9 @@ void MathFunctions::Convolve::init(int h_src, int w_src, int h_kernel, int w_ker
             ws.h_dst = h_src - h_kernel+1;
             ws.w_dst = w_src - w_kernel+1;
         }
+        // Here we just take [h_dst x w_dst] elements starting at [h_kernel-1;w_kernel-1]
+        ws.h_offset = ws.h_kernel - 1;
+        ws.w_offset = ws.w_kernel - 1;
         break;
     case FFTW_CIRCULAR_SAME:
         // Circular convolution, modulo N
@@ -201,6 +207,9 @@ void MathFunctions::Convolve::init(int h_src, int w_src, int h_kernel, int w_ker
         ws.w_fftw = w_src;
         ws.h_dst = h_src;
         ws.w_dst = w_src;
+        // We copy the first [0:h_dst-1 ; 0:w_dst-1] real part elements of out_src
+        ws.h_offset = 0;
+        ws.w_offset = 0;
         break;
     case FFTW_CIRCULAR_SAME_SHIFTED:
         // Circular convolution, modulo N, shifted by M/2
@@ -211,6 +220,9 @@ void MathFunctions::Convolve::init(int h_src, int w_src, int h_kernel, int w_ker
         ws.w_fftw = w_src;
         ws.h_dst = h_src;
         ws.w_dst = w_src;
+        // We copy the [h_kernel/2:h_kernel/2+h_dst-1 ; w_kernel/2:w_kernel/2+w_dst-1] real part elements of out_src
+        ws.h_offset = 0;
+        ws.w_offset = 0;
         break;
     default:
         std::cout << "Unrecognized convolution mode, possible modes are FFTW_LINEAR_FULL, FFTW_LINEAR_SAME, FFTW_LINEAR_SAME_UNPADDED, FFTW_LINEAR_VALID, FFTW_CIRCULAR_SAME, FFTW_CIRCULAR_SHIFTED " << std::endl;
@@ -242,9 +254,13 @@ void MathFunctions::Convolve::init(int h_src, int w_src, int h_kernel, int w_ker
 /* ************************************************************************* */
 // initialise input and output arrays for fast fourier transformation
 /* ************************************************************************* */
-//void MathFunctions::Convolve::fftw_circular_convolution(double * src, double * kernel)
 void MathFunctions::Convolve::fftw_circular_convolution(const double2d_t &src, const double2d_t &kernel)
 {
+    if(ws.h_fftw <= 0 || ws.w_fftw <= 0)
+    {
+        throw RuntimeErrorException("MathFunctions::Convolve::fftw_convolve() -> Panic! Initialisation is missed.");
+    }
+
     double * ptr, *ptr_end, *ptr2;
 
     // Reset the content of ws.in_src
@@ -294,74 +310,69 @@ void MathFunctions::Convolve::fftw_circular_convolution(const double2d_t &src, c
 
 
 
-/* ************************************************************************* */
-// initialise input and output arrays for fast fourier transformation
-/* ************************************************************************* */
-//void MathFunctions::Convolve::fftw_convolve(double * src,double * kernel)
-void MathFunctions::Convolve::fftw_convolve(const double2d_t &src, const double2d_t &kernel)
-{
-    if(ws.h_fftw <= 0 || ws.w_fftw <= 0)
-    {
-        std::cout << "MathFunctions::Convolve::fftw_convolve() -> Panic! Initialisation is missed." << std::endl;
-        throw std::runtime_error("MathFunctions::Convolve::fftw_convolve() -> Panic! Initialisation is missed.");
-    }
-
-    // Compute the circular convolution
-    fftw_circular_convolution(src, kernel);
-
-    // Depending on the type of convolution one is looking for, we extract the appropriate part of the result from out_src
-    int h_offset(0), w_offset(0);
-
-    switch(m_mode)
-    {
-    case FFTW_LINEAR_FULL:
-        // Full Linear convolution
-        // Here we just keep the first [0:h_dst-1 ; 0:w_dst-1] real part elements of out_src
-        for(int i = 0 ; i < ws.h_dst  ; ++i)
-            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[i*ws.w_fftw], ws.w_dst*sizeof(double));
-        break;
-    case FFTW_LINEAR_SAME_UNPADDED:
-        // Same linear convolution
-        // Here we just keep the first [h_filt/2:h_filt/2+h_dst-1 ; w_filt/2:w_filt/2+w_dst-1] real part elements of out_src
-        h_offset = int(ws.h_kernel/2.0);
-        w_offset = int(ws.w_kernel/2.0);
-        for(int i = 0 ; i < ws.h_dst ; ++i)
-            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[(i+h_offset)*ws.w_fftw+w_offset], ws.w_dst*sizeof(double));
-        break;
-    case FFTW_LINEAR_SAME:
-        // Same linear convolution
-        // Here we just keep the first [h_filt/2:h_filt/2+h_dst-1 ; w_filt/2:w_filt/2+w_dst-1] real part elements of out_src
-        h_offset = int(ws.h_kernel/2.0);
-        w_offset = int(ws.w_kernel/2.0);
-        for(int i = 0 ; i < ws.h_dst ; ++i)
-            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[(i+h_offset)*ws.w_fftw+w_offset], ws.w_dst*sizeof(double));
-        break;
-    case FFTW_LINEAR_VALID:
-        // Valid linear convolution
-        // Here we just take [h_dst x w_dst] elements starting at [h_kernel-1;w_kernel-1]
-        h_offset = ws.h_kernel - 1;
-        w_offset = ws.w_kernel - 1;
-        for(int i = 0 ; i < ws.h_dst ; ++i)
-            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[(i+h_offset)*ws.w_fftw+w_offset], ws.w_dst*sizeof(double));
-        break;
-    case FFTW_CIRCULAR_SAME:
-        // Circular convolution
-        // We copy the first [0:h_dst-1 ; 0:w_dst-1] real part elements of out_src
-        for(int i = 0 ; i < ws.h_dst ; ++i)
-            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[i*ws.w_fftw], ws.w_dst*sizeof(double) );
-        break;
-    case FFTW_CIRCULAR_SAME_SHIFTED:
-        // Shifted Circular convolution
-        // We copy the [h_kernel/2:h_kernel/2+h_dst-1 ; w_kernel/2:w_kernel/2+w_dst-1] real part elements of out_src
-        for(int i = 0 ; i < ws.h_dst ; ++i)
-            for(int j = 0 ; j < ws.w_dst ; ++j)
-                ws.dst[i*ws.w_dst + j] = ws.dst_fft[((i+int(ws.h_kernel/2.0))%ws.h_fftw)*ws.w_fftw+(j+int(ws.w_kernel/2.0))%ws.w_fftw];
-        break;
-    default:
-        std::cout << "Unrecognized convolution mode, possible modes are FFTW_LINEAR_FULL, FFTW_LINEAR_SAME, FFTW_LINEAR_SAME_UNPADDED, FFTW_LINEAR_VALID, FFTW_CIRCULAR_SAME, FFTW_CIRCULAR_SHIFTED " << std::endl;
-    }
-}
-
+//void MathFunctions::Convolve::fftw_convolve(const double2d_t &src, const double2d_t &kernel)
+//{
+//    if(ws.h_fftw <= 0 || ws.w_fftw <= 0)
+//    {
+//        std::cout << "MathFunctions::Convolve::fftw_convolve() -> Panic! Initialisation is missed." << std::endl;
+//        throw std::runtime_error("MathFunctions::Convolve::fftw_convolve() -> Panic! Initialisation is missed.");
+//    }
+//
+//    // Compute the circular convolution
+//    fftw_circular_convolution(src, kernel);
+//
+//    // Depending on the type of convolution one is looking for, we extract the appropriate part of the result from out_src
+//    int h_offset(0), w_offset(0);
+//
+//    switch(m_mode)
+//    {
+//    case FFTW_LINEAR_FULL:
+//        // Full Linear convolution
+//        // Here we just keep the first [0:h_dst-1 ; 0:w_dst-1] real part elements of out_src
+//        for(int i = 0 ; i < ws.h_dst  ; ++i)
+//            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[i*ws.w_fftw], ws.w_dst*sizeof(double));
+//        break;
+//    case FFTW_LINEAR_SAME_UNPADDED:
+//        // Same linear convolution
+//        // Here we just keep the first [h_filt/2:h_filt/2+h_dst-1 ; w_filt/2:w_filt/2+w_dst-1] real part elements of out_src
+//        h_offset = int(ws.h_kernel/2.0);
+//        w_offset = int(ws.w_kernel/2.0);
+//        for(int i = 0 ; i < ws.h_dst ; ++i)
+//            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[(i+h_offset)*ws.w_fftw+w_offset], ws.w_dst*sizeof(double));
+//        break;
+//    case FFTW_LINEAR_SAME:
+//        // Same linear convolution
+//        // Here we just keep the first [h_filt/2:h_filt/2+h_dst-1 ; w_filt/2:w_filt/2+w_dst-1] real part elements of out_src
+//        h_offset = int(ws.h_kernel/2.0);
+//        w_offset = int(ws.w_kernel/2.0);
+//        for(int i = 0 ; i < ws.h_dst ; ++i)
+//            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[(i+h_offset)*ws.w_fftw+w_offset], ws.w_dst*sizeof(double));
+//        break;
+//    case FFTW_LINEAR_VALID:
+//        // Valid linear convolution
+//        // Here we just take [h_dst x w_dst] elements starting at [h_kernel-1;w_kernel-1]
+//        h_offset = ws.h_kernel - 1;
+//        w_offset = ws.w_kernel - 1;
+//        for(int i = 0 ; i < ws.h_dst ; ++i)
+//            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[(i+h_offset)*ws.w_fftw+w_offset], ws.w_dst*sizeof(double));
+//        break;
+//    case FFTW_CIRCULAR_SAME:
+//        // Circular convolution
+//        // We copy the first [0:h_dst-1 ; 0:w_dst-1] real part elements of out_src
+//        for(int i = 0 ; i < ws.h_dst ; ++i)
+//            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[i*ws.w_fftw], ws.w_dst*sizeof(double) );
+//        break;
+//    case FFTW_CIRCULAR_SAME_SHIFTED:
+//        // Shifted Circular convolution
+//        // We copy the [h_kernel/2:h_kernel/2+h_dst-1 ; w_kernel/2:w_kernel/2+w_dst-1] real part elements of out_src
+//        for(int i = 0 ; i < ws.h_dst ; ++i)
+//            for(int j = 0 ; j < ws.w_dst ; ++j)
+//                ws.dst[i*ws.w_dst + j] = ws.dst_fft[((i+int(ws.h_kernel/2.0))%ws.h_fftw)*ws.w_fftw+(j+int(ws.w_kernel/2.0))%ws.w_fftw];
+//        break;
+//    default:
+//        std::cout << "Unrecognized convolution mode, possible modes are FFTW_LINEAR_FULL, FFTW_LINEAR_SAME, FFTW_LINEAR_SAME_UNPADDED, FFTW_LINEAR_VALID, FFTW_CIRCULAR_SAME, FFTW_CIRCULAR_SHIFTED " << std::endl;
+//    }
+//}
 
 
 /* ************************************************************************* */
@@ -397,354 +408,3 @@ bool MathFunctions::Convolve::is_optimal(int n)
 }
 
 
-
-
-
-/////////////////
-///
-///
-
-
-// ******************** Begin of factorization code ***********************//
-// A piece of code to determine if a number "n" can be written as products of only the integers given in implemented_factors
-void factorize (const int n,
-                int *n_factors,
-                int factors[],
-                int * implemented_factors)
-{
-    int nf = 0;
-    int ntest = n;
-    int factor;
-    int i = 0;
-
-    if (n == 0)
-    {
-        printf("Length n must be positive integer\n");
-        return ;
-    }
-
-    if (n == 1)
-    {
-        factors[0] = 1;
-        *n_factors = 1;
-        return ;
-    }
-
-    /* deal with the implemented factors */
-
-    while (implemented_factors[i] && ntest != 1)
-    {
-        factor = implemented_factors[i];
-        while ((ntest % factor) == 0)
-        {
-            ntest = ntest / factor;
-            factors[nf] = factor;
-            nf++;
-        }
-        i++;
-    }
-
-    // Ok that's it
-    if(ntest != 1)
-    {
-        factors[nf] = ntest;
-        nf++;
-    }
-
-    /* check that the factorization is correct */
-    {
-        int product = 1;
-
-        for (i = 0; i < nf; i++)
-        {
-            product *= factors[i];
-        }
-
-        if (product != n)
-        {
-            printf("factorization failed");
-        }
-    }
-
-    *n_factors = nf;
-}
-
-bool is_optimal(int n, int * implemented_factors)
-{
-    int nf;
-    int factors[64];
-    int i = 0;
-    factorize(n, &nf, factors,implemented_factors);
-
-    // We just have to check if the last factor belongs to GSL_FACTORS
-    while(implemented_factors[i])
-    {
-        if(factors[nf-1] == implemented_factors[i])
-            return true;
-        ++i;
-    }
-    return false;
-}
-
-int find_closest_factor(int n, int * implemented_factor)
-{
-    int j;
-    if(is_optimal(n,implemented_factor))
-        return n;
-    else
-    {
-        j = n+1;
-        while(!is_optimal(j,implemented_factor))
-            ++j;
-        return j;
-    }
-}
-// ******************** End of factorization code ***********************//
-
-int FFTW_FACTORS[7] = {13,11,7,5,3,2,0}; // end with zero to detect the end of the array
-
-
-void init_workspace_fftw(FFTW_Workspace & ws, FFTW_Convolution_Mode mode, int h_src, int w_src, int h_kernel, int w_kernel)
-{
-    ws.h_src = h_src;
-    ws.w_src = w_src;
-    ws.h_kernel = h_kernel;
-    ws.w_kernel = w_kernel;
-    ws.mode = mode;
-
-    switch(mode)
-    {
-    case FFTW_LINEAR_FULL:
-        // Full Linear convolution
-        ws.h_fftw = find_closest_factor(h_src + h_kernel - 1,FFTW_FACTORS);
-        ws.w_fftw = find_closest_factor(w_src + w_kernel - 1,FFTW_FACTORS);
-        ws.h_dst = h_src + h_kernel-1;
-        ws.w_dst = w_src + w_kernel-1;
-        break;
-    case FFTW_LINEAR_SAME_UNPADDED:
-        // Same Linear convolution
-        ws.h_fftw = h_src + int(h_kernel/2.0);
-        ws.w_fftw = w_src + int(w_kernel/2.0);
-        ws.h_dst = h_src;
-        ws.w_dst = w_src;
-        break;
-    case FFTW_LINEAR_SAME:
-        // Same Linear convolution
-        ws.h_fftw = find_closest_factor(h_src + int(h_kernel/2.0),FFTW_FACTORS);
-        ws.w_fftw = find_closest_factor(w_src + int(w_kernel/2.0),FFTW_FACTORS);
-        ws.h_dst = h_src;
-        ws.w_dst = w_src;
-        break;
-    case FFTW_LINEAR_VALID:
-        // Valid Linear convolution
-        if(ws.h_kernel > ws.h_src || ws.w_kernel > ws.w_src)
-        {
-            printf("Warning : The 'valid' convolution results in an empty matrix\n");
-            ws.h_fftw = 0;
-            ws.w_fftw = 0;
-            ws.h_dst = 0;
-            ws.w_dst = 0;
-        }
-        else
-        {
-            ws.h_fftw = find_closest_factor(h_src, FFTW_FACTORS);
-            ws.w_fftw = find_closest_factor(w_src, FFTW_FACTORS);
-            ws.h_dst = h_src - h_kernel+1;
-            ws.w_dst = w_src - w_kernel+1;
-        }
-        break;
-    case FFTW_CIRCULAR_SAME:
-        // Circular convolution, modulo N
-        // We don't padd with zeros because if we do, we need to padd with at least h_kernel/2; w_kernel/2 elements
-        // plus the wrapp around
-        // which in facts leads to too much computations compared to the gain obtained with the optimal size
-        ws.h_fftw = h_src;
-        ws.w_fftw = w_src;
-        ws.h_dst = h_src;
-        ws.w_dst = w_src;
-        break;
-    case FFTW_CIRCULAR_SAME_SHIFTED:
-        // Circular convolution, modulo N, shifted by M/2
-        // We don't padd with zeros because if we do, we need to padd with at least h_kernel/2; w_kernel/2 elements
-        // plus the wrapp around
-        // which in facts leads to too much computations compared to the gain obtained with the optimal size
-        ws.h_fftw = h_src;
-        ws.w_fftw = w_src;
-        ws.h_dst = h_src;
-        ws.w_dst = w_src;
-        break;
-    case FFTW_CIRCULAR_CUSTOM:
-        // We here want to compute a circular convolution modulo h_dst, w_dst
-        // These two variables must have been set before calling init_workscape !!
-        ws.h_fftw = ws.h_dst;
-        ws.w_fftw = ws.w_dst;
-        break;
-    default:
-        printf("Unrecognized convolution mode, possible modes are :\n");
-        printf("   - FFTW_LINEAR_FULL \n");
-        printf("   - FFTW_LINEAR_SAME \n");
-        printf("   - FFTW_LINEAR_SAME_UNPADDED\n");
-        printf("   - FFTW_LINEAR_VALID \n");
-        printf("   - FFTW_CIRCULAR_SAME \n");
-        printf("   - FFTW_CIRCULAR_SHIFTED\n");
-        printf("   - FFTW_CIRCULAR_CUSTOM\n");
-    }
-
-    ws.in_src = new double[ws.h_fftw * ws.w_fftw];
-    ws.out_src = (double*) fftw_malloc(sizeof(fftw_complex) * ws.h_fftw * (ws.w_fftw/2+1));
-    ws.in_kernel = new double[ws.h_fftw * ws.w_fftw];
-    ws.out_kernel = (double*) fftw_malloc(sizeof(fftw_complex) * ws.h_fftw * (ws.w_fftw/2+1));
-
-    ws.dst_fft = new double[ws.h_fftw * ws.w_fftw];
-    ws.dst = new double[ws.h_dst * ws.w_dst];
-
-    // Initialization of the plans
-    ws.p_forw_src = fftw_plan_dft_r2c_2d(ws.h_fftw, ws.w_fftw, ws.in_src, (fftw_complex*)ws.out_src, FFTW_ESTIMATE);
-    ws.p_forw_kernel = fftw_plan_dft_r2c_2d(ws.h_fftw, ws.w_fftw, ws.in_kernel, (fftw_complex*)ws.out_kernel, FFTW_ESTIMATE);
-
-    // The backward FFT takes ws.out_kernel as input !!
-    ws.p_back = fftw_plan_dft_c2r_2d(ws.h_fftw, ws.w_fftw, (fftw_complex*)ws.out_kernel, ws.dst_fft, FFTW_ESTIMATE);
-}
-
-void clear_workspace_fftw(FFTW_Workspace & ws)
-{
-    delete[] ws.in_src;
-    fftw_free((fftw_complex*)ws.out_src);
-    delete[] ws.in_kernel;
-    fftw_free((fftw_complex*)ws.out_kernel);
-
-    delete[] ws.dst_fft;
-    delete[] ws.dst;
-
-    // Destroy the plans
-    fftw_destroy_plan(ws.p_forw_src);
-    fftw_destroy_plan(ws.p_forw_kernel);
-    fftw_destroy_plan(ws.p_back);
-}
-
-// Compute the circular convolution of src and kernel modulo ws.h_fftw, ws.w_fftw
-// using the Fast Fourier Transform
-// The result is in ws.dst
-void fftw_circular_convolution(FFTW_Workspace &ws, double * src, double * kernel)
-{
-    double * ptr, *ptr_end, *ptr2;
-
-    // Reset the content of ws.in_src
-    for(ptr = ws.in_src, ptr_end = ws.in_src + ws.h_fftw*ws.w_fftw ; ptr != ptr_end ; ++ptr)
-        *ptr = 0.0;
-    for(ptr = ws.in_kernel, ptr_end = ws.in_kernel + ws.h_fftw*ws.w_fftw ; ptr != ptr_end ; ++ptr)
-        *ptr = 0.0;
-
-    // Then we build our periodic signals
-    //ptr = src;
-    for(int i = 0 ; i < ws.h_src ; ++i)
-        for(int j = 0 ; j < ws.w_src ; ++j, ++ptr)
-            ws.in_src[(i%ws.h_fftw)*ws.w_fftw+(j%ws.w_fftw)] += src[i*ws.w_src + j];
-    //ptr = kernel;
-    for(int i = 0 ; i < ws.h_kernel ; ++i)
-        for(int j = 0 ; j < ws.w_kernel ; ++j, ++ptr)
-            ws.in_kernel[(i%ws.h_fftw)*ws.w_fftw+(j%ws.w_fftw)] += kernel[i*ws.w_kernel + j];
-
-    // And we compute their packed FFT
-    fftw_execute(ws.p_forw_src);
-    fftw_execute(ws.p_forw_kernel);
-
-    // Compute the element-wise product on the packed terms
-    // Let's put the element wise products in ws.in_kernel
-    double re_s, im_s, re_k, im_k;
-    for(ptr = ws.out_src, ptr2 = ws.out_kernel, ptr_end = ws.out_src+2*ws.h_fftw * (ws.w_fftw/2+1); ptr != ptr_end ; ++ptr, ++ptr2)
-    {
-        re_s = *ptr;
-        im_s = *(++ptr);
-        re_k = *ptr2;
-        im_k = *(++ptr2);
-        *(ptr2-1) = re_s * re_k - im_s * im_k;
-        *ptr2 = re_s * im_k + im_s * re_k;
-    }
-
-    // Compute the backward FFT
-    // Carefull, The backward FFT does not preserve the output
-    fftw_execute(ws.p_back);
-    // Scale the transform
-    for(ptr = ws.dst_fft, ptr_end = ws.dst_fft + ws.w_fftw*ws.h_fftw ; ptr != ptr_end ; ++ptr)
-        *ptr /= double(ws.h_fftw*ws.w_fftw);
-
-    // That's it !
-}
-
-void fftw_convolve(FFTW_Workspace &ws, double * src,double * kernel)
-{
-    if(ws.h_fftw <= 0 || ws.w_fftw <= 0)
-        return;
-
-    // Compute the circular convolution
-    fftw_circular_convolution(ws, src, kernel);
-
-    // Depending on the type of convolution one is looking for, we extract the appropriate part of the result from out_src
-    int h_offset, w_offset;
-
-//    double * dst_ptr;
-//    double * src_ptr;
-    switch(ws.mode)
-    {
-    case FFTW_LINEAR_FULL:
-        // Full Linear convolution
-        // Here we just keep the first [0:h_dst-1 ; 0:w_dst-1] real part elements of out_src
-        for(int i = 0 ; i < ws.h_dst  ; ++i)
-            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[i*ws.w_fftw], ws.w_dst*sizeof(double));
-        break;
-    case FFTW_LINEAR_SAME_UNPADDED:
-        // Same linear convolution
-        // Here we just keep the first [h_filt/2:h_filt/2+h_dst-1 ; w_filt/2:w_filt/2+w_dst-1] real part elements of out_src
-        h_offset = int(ws.h_kernel/2.0);
-        w_offset = int(ws.w_kernel/2.0);
-        for(int i = 0 ; i < ws.h_dst ; ++i)
-            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[(i+h_offset)*ws.w_fftw+w_offset], ws.w_dst*sizeof(double));
-            //for(int j = 0 ; j < ws.w_dst ; ++j)
-             //   ws.dst[i*ws.w_dst + j] = ws.out_src[2*((i+h_offset)*ws.w_fftw+j+w_offset)+0]/double(ws.w_fftw * ws.h_fftw);
-        break;
-    case FFTW_LINEAR_SAME:
-        // Same linear convolution
-        // Here we just keep the first [h_filt/2:h_filt/2+h_dst-1 ; w_filt/2:w_filt/2+w_dst-1] real part elements of out_src
-        h_offset = int(ws.h_kernel/2.0);
-        w_offset = int(ws.w_kernel/2.0);
-        for(int i = 0 ; i < ws.h_dst ; ++i)
-            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[(i+h_offset)*ws.w_fftw+w_offset], ws.w_dst*sizeof(double));
-        break;
-    case FFTW_LINEAR_VALID:
-        // Valid linear convolution
-        // Here we just take [h_dst x w_dst] elements starting at [h_kernel-1;w_kernel-1]
-        h_offset = ws.h_kernel - 1;
-        w_offset = ws.w_kernel - 1;
-        for(int i = 0 ; i < ws.h_dst ; ++i)
-            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[(i+h_offset)*ws.w_fftw+w_offset], ws.w_dst*sizeof(double));
-        break;
-    case FFTW_CIRCULAR_SAME:
-        // Circular convolution
-        // We copy the first [0:h_dst-1 ; 0:w_dst-1] real part elements of out_src
-        for(int i = 0 ; i < ws.h_dst ; ++i)
-            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[i*ws.w_fftw], ws.w_dst*sizeof(double) );
-        break;
-    case FFTW_CIRCULAR_SAME_SHIFTED:
-        // Shifted Circular convolution
-        // We copy the [h_kernel/2:h_kernel/2+h_dst-1 ; w_kernel/2:w_kernel/2+w_dst-1] real part elements of out_src
-        for(int i = 0 ; i < ws.h_dst ; ++i)
-            for(int j = 0 ; j < ws.w_dst ; ++j)
-                ws.dst[i*ws.w_dst + j] = ws.dst_fft[((i+int(ws.h_kernel/2.0))%ws.h_fftw)*ws.w_fftw+(j+int(ws.w_kernel/2.0))%ws.w_fftw];
-        break;
-    case FFTW_CIRCULAR_CUSTOM:
-        for(int i = 0 ; i < ws.h_dst ; ++i)
-            memcpy(&ws.dst[i*ws.w_dst], &ws.dst_fft[i*ws.w_fftw], ws.w_dst*sizeof(double) );
-        break;
-    default:
-        printf("Unrecognized convolution mode, possible modes are :\n");
-        printf("   - FFTW_LINEAR_FULL \n");
-        printf("   - FFTW_LINEAR_SAME \n");
-        printf("   - FFTW_LINEAR_SAME_UNPADDED\n");
-        printf("   - FFTW_LINEAR_VALID \n");
-        printf("   - FFTW_CIRCULAR_SAME \n");
-        printf("   - FFTW_CIRCULAR_SHIFTED\n");
-        printf("   - FFTW_CIRCULAR_CUSTOM\n");
-    }
-}
-
-- 
GitLab