From f3ada0ee814957115e26b23ef656f79b41928c12 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Thu, 28 Jan 2016 13:56:42 +0100
Subject: [PATCH] Remove dead code (eigen2d matrix functions); sort functions
 in MathFunctions; rename 'value' -> 'x' or 'z'.

---
 Core/Tools/inc/MathFunctions.h                | 105 ++---
 Core/Tools/src/MathFunctions.cpp              | 383 ++++++++----------
 .../UnitTests/TestCore/MatrixFunctionsTest.h  |  77 ----
 .../UnitTests/TestCore/SpecialFunctionsTest.h |  42 +-
 Tests/UnitTests/TestCore/main.cpp             |   2 -
 5 files changed, 253 insertions(+), 356 deletions(-)
 delete mode 100644 Tests/UnitTests/TestCore/MatrixFunctionsTest.h

diff --git a/Core/Tools/inc/MathFunctions.h b/Core/Tools/inc/MathFunctions.h
index e60aeaea6c0..8048c90f721 100644
--- a/Core/Tools/inc/MathFunctions.h
+++ b/Core/Tools/inc/MathFunctions.h
@@ -3,8 +3,7 @@
 //  BornAgain: simulate and fit scattering at grazing incidence
 //
 //! @file      Tools/inc/MathFunctions.h
-//! @brief     Define many functions in namespace MathFunctions,
-//!              and provide inline implementation for most of them
+//! @brief     Defines functions in namespace MathFunctions.
 //!
 //! @homepage  http://www.bornagainproject.org
 //! @license   GNU General Public License v3 or higher (see COPYING)
@@ -25,81 +24,94 @@
 #include <vector>
 #include <cmath>
 
-#include "EigenCore.h"
-
 //! Various mathematical functions.
 
 namespace MathFunctions
 {
 
-    BA_CORE_API_ double Gaussian(double value, double average, double std_dev);
+// ************************************************************************** //
+//  Various functions
+// ************************************************************************** //
 
-    BA_CORE_API_ double IntegratedGaussian(double value, double average, double std_dev);
+    BA_CORE_API_ double StandardNormal(double x);
+    BA_CORE_API_ double Gaussian(double x, double average, double std_dev);
+    BA_CORE_API_ double IntegratedGaussian(double x, double average, double std_dev);
 
-    BA_CORE_API_ double GenerateNormalRandom(double average, double std_dev);
+//! Sine integral function: \f$Si(x)\equiv\int_0^x du \sin(u)/u\f$
+    BA_CORE_API_ double Si(double x);
 
-    BA_CORE_API_ double StandardNormal(double value);
+//! sinc function: \f$sinc(x)\equiv\sin(x)/x\f$
+    BA_CORE_API_ double sinc(double x);
 
-    BA_CORE_API_ double GenerateStandardNormalRandom();
+//! Complex sinc function: \f$sinc(x)\equiv\sin(x)/x\f$
+    BA_CORE_API_ complex_t sinc(const complex_t &z);
 
-    BA_CORE_API_ double GenerateUniformRandom();
+//! Complex tanhc function: \f$tanhc(x)\equiv\tanh(x)/x\f$
+    BA_CORE_API_ complex_t tanhc(const complex_t &z);
+
+    BA_CORE_API_ complex_t Laue(const complex_t &z, size_t N);
+
+//! Calculates the geometric series of z to order N
+    complex_t geometricSum(complex_t z, int exponent);
+
+
+// ************************************************************************** //
+//  Bessel functions
+// ************************************************************************** //
 
 //! Bessel function of the first kind and order 0
-    BA_CORE_API_ double Bessel_J0(double value);
+    BA_CORE_API_ double Bessel_J0(double x);
 
 //! Bessel function of the first kind and order 1
-    BA_CORE_API_ double Bessel_J1(double value);
+    BA_CORE_API_ double Bessel_J1(double x);
 
 //! Bessel function  Bessel_J1(x)/x
-    BA_CORE_API_ double Bessel_C1(double value);
+    BA_CORE_API_ double Bessel_C1(double x);
 
 //! Complex Bessel function of the first kind and order 0
-    BA_CORE_API_ complex_t Bessel_J0(const complex_t &value);
+    BA_CORE_API_ complex_t Bessel_J0(const complex_t &z);
 
 //! Complex Bessel function of the first kind and order 1
-    BA_CORE_API_ complex_t Bessel_J1(const complex_t &value);
+    BA_CORE_API_ complex_t Bessel_J1(const complex_t &z);
 
 //! Complex Bessel function  Bessel_J1(x)/x
-    BA_CORE_API_ complex_t Bessel_C1(const complex_t &value);
-
-//! Sine integral function: \f$Si(x)\equiv\int_0^x du \sin(u)/u\f$
-    BA_CORE_API_ double Si(double value);
+    BA_CORE_API_ complex_t Bessel_C1(const complex_t &z);
 
-//! sinc function: \f$sinc(x)\equiv\sin(x)/x\f$
-    BA_CORE_API_ double sinc(double value);
+//! Computes complex Bessel function J0(z), using power series and asymptotic expansion
+    BA_CORE_API_ complex_t Bessel_J0_PowSer(const complex_t &z);
 
-//! Complex sinc function: \f$sinc(x)\equiv\sin(x)/x\f$
-    BA_CORE_API_ complex_t sinc(const complex_t &value);
+//! Computes complex Bessel function J0(z), using power series and asymptotic expansion
+    BA_CORE_API_ complex_t Bessel_J1_PowSer(const complex_t &z);
 
-//! Complex tanhc function: \f$tanhc(x)\equiv\tanh(x)/x\f$
-    BA_CORE_API_ complex_t tanhc(const complex_t &value);
 
-    BA_CORE_API_ complex_t Laue(const complex_t &value, size_t N);
+// ************************************************************************** //
+//  Fourier transform and convolution
+// ************************************************************************** //
 
     enum EFFTDirection { FORWARD_FFT, BACKWARD_FFT };
-    BA_CORE_API_ std::vector<complex_t > FastFourierTransform(const std::vector<complex_t > &data, EFFTDirection tcase);
 
-    BA_CORE_API_ std::vector<complex_t > FastFourierTransform(const std::vector<double > &data, EFFTDirection tcase);
+    BA_CORE_API_ std::vector<complex_t >
+        FastFourierTransform(const std::vector<complex_t > &data, EFFTDirection tcase);
 
-    BA_CORE_API_ std::vector<complex_t> ConvolveFFT(const std::vector<double> &signal, const std::vector<double> &resfunc);
+    BA_CORE_API_ std::vector<complex_t >
+        FastFourierTransform(const std::vector<double > &data, EFFTDirection tcase);
 
-#ifndef GCCXML_SKIP_THIS
-//! computes the norm element-wise
-    BA_CORE_API_ Eigen::Matrix2d Norm(const Eigen::Matrix2cd &M);
+    BA_CORE_API_ std::vector<complex_t>
+        ConvolveFFT(const std::vector<double> &signal, const std::vector<double> &resfunc);
 
-//! computes the absolute value element-wise
-    BA_CORE_API_ Eigen::Matrix2d Abs(const Eigen::Matrix2cd &M);
 
-//! computes the complex conjugate element-wise
-    BA_CORE_API_ Eigen::Matrix2cd Conj(const Eigen::Matrix2cd &M);
+// ************************************************************************** //
+//  Random number generators
+// ************************************************************************** //
 
-//! element-wise product
-    BA_CORE_API_ Eigen::Matrix2cd ProductByElement(const Eigen::Matrix2cd &left,
-                                                   const Eigen::Matrix2cd &right);
+    BA_CORE_API_ double GenerateUniformRandom();
+    BA_CORE_API_ double GenerateStandardNormalRandom();
+    BA_CORE_API_ double GenerateNormalRandom(double average, double std_dev);
 
-//! take element-wise real value
-    BA_CORE_API_ Eigen::Matrix2d Real(const Eigen::Matrix2cd &M);
-#endif
+
+// ************************************************************************** //
+//  Workarounds for std functions
+// ************************************************************************** //
 
     BA_CORE_API_ inline bool isnan(double x)
     {
@@ -119,15 +131,6 @@ namespace MathFunctions
 #endif
     }
 
-//! Computes complex Bessel function J0(z), using power series and asymptotic expansion
-    BA_CORE_API_ complex_t Bessel_J0_PowSer(const complex_t &value);
-
-//! Computes complex Bessel function J0(z), using power series and asymptotic expansion
-    BA_CORE_API_ complex_t Bessel_J1_PowSer(const complex_t &value);
-
-//! Calculates the geometric series of z to order N
-    complex_t geometricSum(complex_t z, int exponent);
-
 } // Namespace MathFunctions
 
 
diff --git a/Core/Tools/src/MathFunctions.cpp b/Core/Tools/src/MathFunctions.cpp
index ee6049a4a9b..01ab34534d3 100644
--- a/Core/Tools/src/MathFunctions.cpp
+++ b/Core/Tools/src/MathFunctions.cpp
@@ -27,258 +27,126 @@
 #include "gsl/gsl_integration.h"
 
 
-double MathFunctions::GenerateNormalRandom(double average, double std_dev)
-{
-    return GenerateStandardNormalRandom()*std_dev + average;
-}
-
-double MathFunctions::GenerateUniformRandom()
-{
-    int random_int = std::rand();
-    return (double)random_int / RAND_MAX;
-}
-
-double MathFunctions::Bessel_J0(double value)
-{
-    return gsl_sf_bessel_J0(value);
-}
-
-double MathFunctions::Bessel_J1(double value)
-{
-    return gsl_sf_bessel_J1(value);
-}
-
-double MathFunctions::Bessel_C1(double value)
-{
-    return value > Numeric::double_epsilon ? gsl_sf_bessel_J1(value)/value : 0.5;
-}
+// ************************************************************************** //
+//  Various functions
+// ************************************************************************** //
 
-complex_t MathFunctions::Bessel_J0(const complex_t &value)
+double MathFunctions::StandardNormal(double x)
 {
-    if(std::imag(value) < Numeric::double_epsilon) {
-        return complex_t(Bessel_J0(std::real(value)), 0.0);
-    } else {
-        return Bessel_J0_PowSer(value);
-    }
+    return std::exp(-x * x / 2.0) / std::sqrt(Units::PI2);
 }
 
-complex_t MathFunctions::Bessel_J1(const complex_t &value)
+double MathFunctions::Gaussian(double x, double average, double std_dev)
 {
-    if(std::imag(value) < Numeric::double_epsilon) {
-        return complex_t(Bessel_J1(std::real(value)), 0.0);
-    } else {
-        return Bessel_J1_PowSer(value);
-    }
+    return StandardNormal((x - average) / std_dev) / std_dev;
 }
 
-complex_t MathFunctions::Bessel_C1(const complex_t &value)
+double MathFunctions::IntegratedGaussian(double x, double average, double std_dev)
 {
-    if(std::imag(value) < Numeric::double_epsilon) {
-        double xv = std::real(value);
-        return std::abs(xv) > Numeric::double_epsilon ? MathFunctions::Bessel_J1(xv)/xv : 0.5;
-    } else {
-        return std::abs(value) > Numeric::double_epsilon ? MathFunctions::Bessel_J1(value)/value : 0.5;
-    }
+    double normalized_x = (x - average) / std_dev;
+    double root2 = std::sqrt(2.0);
+    return (gsl_sf_erf(normalized_x / root2) + 1.0) / 2.0;
 }
 
-double MathFunctions::Si(double value)  // int_0^x du Sin(u)/u
+double MathFunctions::Si(double x)  // int_0^x du Sin(u)/u
 {
-    return gsl_sf_Si(value);
+    return gsl_sf_Si(x);
 }
 
-double MathFunctions::sinc(double value)  // Sin(x)/x
+double MathFunctions::sinc(double x)  // Sin(x)/x
 {
-    return gsl_sf_sinc(value/Units::PI);
+    return gsl_sf_sinc(x/Units::PI);
 }
 
-complex_t MathFunctions::sinc(const complex_t &value)  // Sin(x)/x
+complex_t MathFunctions::sinc(const complex_t &z)  // Sin(x)/x
 {
     // This is an exception from the rule that we must not test floating-point numbers for equality.
-    // For small non-zero values, sin(z) returns quite accurately z or z-z^3/6.
+    // For small non-zero arguments, sin(z) returns quite accurately z or z-z^3/6.
     // There is no loss of precision in computing sin(z)/z.
     // Therefore there is no need for an expensive test like abs(z)<eps.
-    if( value==complex_t(0.,0.) )
+    if( z==complex_t(0.,0.) )
         return complex_t(1.0, 0.0);
-    return std::sin(value)/value;
+    return std::sin(z)/z;
 }
 
-complex_t MathFunctions::tanhc(const complex_t &value)  // tanh(x)/x
+complex_t MathFunctions::tanhc(const complex_t &z)  // tanh(x)/x
 {
-    if(std::abs(value)<Numeric::double_epsilon)
+    if(std::abs(z)<Numeric::double_epsilon)
         return complex_t(1.0, 0.0);
-    return std::tanh(value)/value;
+    return std::tanh(z)/z;
 }
 
-complex_t MathFunctions::Laue(const complex_t &value, size_t N) // Exp(iNx/2)*Sin((N+1)x)/Sin(x)
+complex_t MathFunctions::Laue(const complex_t &z, size_t N) // Exp(iNx/2)*Sin((N+1)x)/Sin(x)
 {
     if (N==0)
         return complex_t(1.0, 0.0);
-    if(std::abs(value)<Numeric::double_epsilon)
+    if(std::abs(z)<Numeric::double_epsilon)
         return complex_t(N+1.0, 0.0);
-    return std::exp(complex_t(0.0, 1.0)*value*(double)N/2.0)*std::sin(value*(N+1.0)/2.0)/std::sin(value/2.0);
-}
-
-#ifndef GCCXML_SKIP_THIS
-Eigen::Matrix2d MathFunctions::Norm(const Eigen::Matrix2cd &M) {
-    Eigen::Matrix2d result;
-    result(0,0) = std::norm((complex_t)M(0,0));
-    result(0,1) = std::norm((complex_t)M(0,1));
-    result(1,0) = std::norm((complex_t)M(1,0));
-    result(1,1) = std::norm((complex_t)M(1,1));
-    return result;
+    return std::exp(complex_t(0.0, 1.0)*z*(double)N/2.0)*std::sin(z*(N+1.0)/2.0)/std::sin(z/2.0);
 }
 
-Eigen::Matrix2d MathFunctions::Abs(const Eigen::Matrix2cd &M) {
-    Eigen::Matrix2d result;
-    result(0,0) = std::abs((complex_t)M(0,0));
-    result(0,1) = std::abs((complex_t)M(0,1));
-    result(1,0) = std::abs((complex_t)M(1,0));
-    result(1,1) = std::abs((complex_t)M(1,1));
-    return result;
-}
-
-Eigen::Matrix2cd MathFunctions::Conj(const Eigen::Matrix2cd &M) {
-    Eigen::Matrix2cd result;
-    result(0,0) = std::conj((complex_t)M(0,0));
-    result(0,1) = std::conj((complex_t)M(0,1));
-    result(1,0) = std::conj((complex_t)M(1,0));
-    result(1,1) = std::conj((complex_t)M(1,1));
+complex_t MathFunctions::geometricSum(complex_t z, int exponent)
+{
+    if (exponent < 1) {
+        throw LogicErrorException("MathFunctions::geometricSeries:"
+                                  " exponent should be > 0");
+    }
+    complex_t result(0.0, 0.0);
+    double nd = (double)exponent;
+    --exponent;
+    while (exponent > 0) {
+        result += std::pow(z, exponent) * (nd - exponent);
+        --exponent;
+    }
     return result;
 }
 
-Eigen::Matrix2cd MathFunctions::ProductByElement(
-        const Eigen::Matrix2cd &left, const Eigen::Matrix2cd &right) {
-    Eigen::Matrix2cd result;
-    result(0,0) = left(0,0) * right(0,0);
-    result(0,1) = left(0,1) * right(0,1);
-    result(1,0) = left(1,0) * right(1,0);
-    result(1,1) = left(1,1) * right(1,1);
-    return result;
-}
 
-Eigen::Matrix2d MathFunctions::Real(const Eigen::Matrix2cd &M) {
-    Eigen::Matrix2d result;
-    result(0,0) = ((complex_t)M(0,0)).real();
-    result(0,1) = ((complex_t)M(0,1)).real();
-    result(1,0) = ((complex_t)M(1,0)).real();
-    result(1,1) = ((complex_t)M(1,1)).real();
-    return result;
-}
-#endif
+// ************************************************************************** //
+//  Bessel functions
+// ************************************************************************** //
 
-double MathFunctions::Gaussian(double value, double average, double std_dev)
+double MathFunctions::Bessel_J0(double x)
 {
-    return StandardNormal((value - average) / std_dev) / std_dev;
+    return gsl_sf_bessel_J0(x);
 }
 
-double MathFunctions::IntegratedGaussian(double value, double average, double std_dev)
+double MathFunctions::Bessel_J1(double x)
 {
-    double normalized_value = (value - average) / std_dev;
-    double root2 = std::sqrt(2.0);
-    return (gsl_sf_erf(normalized_value / root2) + 1.0) / 2.0;
+    return gsl_sf_bessel_J1(x);
 }
 
-double MathFunctions::StandardNormal(double value)
+double MathFunctions::Bessel_C1(double x)
 {
-    return std::exp(-value * value / 2.0) / std::sqrt(Units::PI2);
+    return x > Numeric::double_epsilon ? gsl_sf_bessel_J1(x)/x : 0.5;
 }
 
-double MathFunctions::GenerateStandardNormalRandom() // using GSL
+complex_t MathFunctions::Bessel_J0(const complex_t &z)
 {
-    gsl_rng *r;
-    r = gsl_rng_alloc(gsl_rng_ranlxs2);
-    double result = gsl_ran_ugaussian(r);
-    gsl_rng_free(r);
-    return result;
-}
-
-//! @brief simple (and unoptimized) wrapper function
-//!   for the discrete fast Fourier transformation library (fftw3)
-
-std::vector<complex_t> MathFunctions::FastFourierTransform(const std::vector<complex_t> &data,
-                                                           MathFunctions::EFFTDirection ftCase)
-{
-    double scale(1.);
-    size_t npx = data.size();
-
-    fftw_complex *ftData = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * npx);
-    fftw_complex *ftResult = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * npx);
-    memset(ftData, 0, sizeof(fftw_complex) * npx);
-    memset(ftResult, 0, sizeof(fftw_complex) * npx);
-
-    for (size_t i = 0; i < npx; i++) {
-        ftData[i][0] = data[i].real();
-        ftData[i][1] = data[i].imag();
-    }
-
-    fftw_plan plan;
-    switch (ftCase) {
-    case MathFunctions::FORWARD_FFT:
-        plan = fftw_plan_dft_1d((int)npx, ftData, ftResult, FFTW_FORWARD, FFTW_ESTIMATE);
-        break;
-    case MathFunctions::BACKWARD_FFT:
-        plan = fftw_plan_dft_1d((int)npx, ftData, ftResult, FFTW_BACKWARD, FFTW_ESTIMATE);
-        scale = 1. / double(npx);
-        break;
-    default:
-        throw std::runtime_error(
-            "MathFunctions::FastFourierTransform -> Panic! Unknown transform case.");
-    }
-
-    fftw_execute(plan);
-
-    // saving data for user
-    std::vector<complex_t> outData;
-    outData.resize(npx);
-    for (size_t i = 0; i < npx; i++) {
-        outData[i] = scale * complex_t(ftResult[i][0], ftResult[i][1]);
+    if(std::imag(z) < Numeric::double_epsilon) {
+        return complex_t(Bessel_J0(std::real(z)), 0.0);
+    } else {
+        return Bessel_J0_PowSer(z);
     }
-
-    fftw_destroy_plan(plan);
-    fftw_free(ftData);
-    fftw_free(ftResult);
-
-    return outData;
 }
 
-//! @brief simple (and unoptimized) wrapper function
-//!   for the discrete fast Fourier transformation library (fftw3);
-//!   transforms real to complex
-
-std::vector<complex_t> MathFunctions::FastFourierTransform(const std::vector<double> &data,
-                                                           MathFunctions::EFFTDirection ftCase)
+complex_t MathFunctions::Bessel_J1(const complex_t &z)
 {
-    std::vector<complex_t> cdata;
-    cdata.resize(data.size());
-    for (size_t i = 0; i < data.size(); i++) {
-        cdata[i] = complex_t(data[i], 0);
+    if(std::imag(z) < Numeric::double_epsilon) {
+        return complex_t(Bessel_J1(std::real(z)), 0.0);
+    } else {
+        return Bessel_J1_PowSer(z);
     }
-    return MathFunctions::FastFourierTransform(cdata, ftCase);
 }
 
-//! convolution of two real vectors of equal size
-
-std::vector<complex_t> MathFunctions::ConvolveFFT(const std::vector<double> &signal,
-                                                  const std::vector<double> &resfunc)
+complex_t MathFunctions::Bessel_C1(const complex_t &z)
 {
-    if (signal.size() != resfunc.size()) {
-        throw std::runtime_error("MathFunctions::ConvolveFFT() -> This convolution works only for "
-                                 "two vectors of equal size. Use Convolve class instead.");
-    }
-    std::vector<complex_t> fft_signal
-        = MathFunctions::FastFourierTransform(signal, MathFunctions::FORWARD_FFT);
-    std::vector<complex_t> fft_resfunc
-        = MathFunctions::FastFourierTransform(resfunc, MathFunctions::FORWARD_FFT);
-
-    std::vector<complex_t> fft_prod;
-    fft_prod.resize(fft_signal.size());
-    for (size_t i = 0; i < fft_signal.size(); i++) {
-        fft_prod[i] = fft_signal[i] * fft_resfunc[i];
+    if(std::imag(z) < Numeric::double_epsilon) {
+        double xv = std::real(z);
+        return std::abs(xv) > Numeric::double_epsilon ? MathFunctions::Bessel_J1(xv)/xv : 0.5;
+    } else {
+        return std::abs(z) > Numeric::double_epsilon ? MathFunctions::Bessel_J1(z)/z : 0.5;
     }
-
-    std::vector<complex_t> result
-        = MathFunctions::FastFourierTransform(fft_prod, MathFunctions::BACKWARD_FFT);
-    return result;
 }
 
 //! Computes the complex Bessel function J0(z), using standard power series and asymptotic expansion.
@@ -412,18 +280,123 @@ complex_t MathFunctions::Bessel_J1_PowSer(const complex_t &z)
     return cj1;
 }
 
-complex_t MathFunctions::geometricSum(complex_t z, int exponent)
+// ************************************************************************** //
+//  Fourier transform and convolution
+// ************************************************************************** //
+
+//! @brief simple (and unoptimized) wrapper function
+//!   for the discrete fast Fourier transformation library (fftw3)
+
+std::vector<complex_t>
+MathFunctions::FastFourierTransform(const std::vector<complex_t> &data,
+                                    MathFunctions::EFFTDirection ftCase)
 {
-    if (exponent < 1) {
-        throw LogicErrorException("MathFunctions::geometricSeries:"
-                                  " exponent should be > 0");
+    double scale(1.);
+    size_t npx = data.size();
+
+    fftw_complex *ftData = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * npx);
+    fftw_complex *ftResult = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * npx);
+    memset(ftData, 0, sizeof(fftw_complex) * npx);
+    memset(ftResult, 0, sizeof(fftw_complex) * npx);
+
+    for (size_t i = 0; i < npx; i++) {
+        ftData[i][0] = data[i].real();
+        ftData[i][1] = data[i].imag();
     }
-    complex_t result(0.0, 0.0);
-    double nd = (double)exponent;
-    --exponent;
-    while (exponent > 0) {
-        result += std::pow(z, exponent) * (nd - exponent);
-        --exponent;
+
+    fftw_plan plan;
+    switch (ftCase) {
+    case MathFunctions::FORWARD_FFT:
+        plan = fftw_plan_dft_1d((int)npx, ftData, ftResult, FFTW_FORWARD, FFTW_ESTIMATE);
+        break;
+    case MathFunctions::BACKWARD_FFT:
+        plan = fftw_plan_dft_1d((int)npx, ftData, ftResult, FFTW_BACKWARD, FFTW_ESTIMATE);
+        scale = 1. / double(npx);
+        break;
+    default:
+        throw std::runtime_error(
+            "MathFunctions::FastFourierTransform -> Panic! Unknown transform case.");
+    }
+
+    fftw_execute(plan);
+
+    // saving data for user
+    std::vector<complex_t> outData;
+    outData.resize(npx);
+    for (size_t i = 0; i < npx; i++) {
+        outData[i] = scale * complex_t(ftResult[i][0], ftResult[i][1]);
+    }
+
+    fftw_destroy_plan(plan);
+    fftw_free(ftData);
+    fftw_free(ftResult);
+
+    return outData;
+}
+
+//! @brief simple (and unoptimized) wrapper function
+//!   for the discrete fast Fourier transformation library (fftw3);
+//!   transforms real to complex
+
+std::vector<complex_t>
+MathFunctions::FastFourierTransform(const std::vector<double> &data,
+                                    MathFunctions::EFFTDirection ftCase)
+{
+    std::vector<complex_t> cdata;
+    cdata.resize(data.size());
+    for (size_t i = 0; i < data.size(); i++) {
+        cdata[i] = complex_t(data[i], 0);
     }
+    return MathFunctions::FastFourierTransform(cdata, ftCase);
+}
+
+//! convolution of two real vectors of equal size
+
+std::vector<complex_t>
+MathFunctions::ConvolveFFT(const std::vector<double> &signal,
+                           const std::vector<double> &resfunc)
+{
+    if (signal.size() != resfunc.size()) {
+        throw std::runtime_error("MathFunctions::ConvolveFFT() -> This convolution works only for "
+                                 "two vectors of equal size. Use Convolve class instead.");
+    }
+    std::vector<complex_t> fft_signal
+        = MathFunctions::FastFourierTransform(signal, MathFunctions::FORWARD_FFT);
+    std::vector<complex_t> fft_resfunc
+        = MathFunctions::FastFourierTransform(resfunc, MathFunctions::FORWARD_FFT);
+
+    std::vector<complex_t> fft_prod;
+    fft_prod.resize(fft_signal.size());
+    for (size_t i = 0; i < fft_signal.size(); i++) {
+        fft_prod[i] = fft_signal[i] * fft_resfunc[i];
+    }
+
+    std::vector<complex_t> result
+        = MathFunctions::FastFourierTransform(fft_prod, MathFunctions::BACKWARD_FFT);
+    return result;
+}
+
+
+// ************************************************************************** //
+//  Random number generators
+// ************************************************************************** //
+
+double MathFunctions::GenerateUniformRandom()
+{
+    int random_int = std::rand();
+    return (double)random_int / RAND_MAX;
+}
+
+double MathFunctions::GenerateNormalRandom(double average, double std_dev)
+{
+    return GenerateStandardNormalRandom()*std_dev + average;
+}
+
+double MathFunctions::GenerateStandardNormalRandom() // using GSL
+{
+    gsl_rng *r;
+    r = gsl_rng_alloc(gsl_rng_ranlxs2);
+    double result = gsl_ran_ugaussian(r);
+    gsl_rng_free(r);
     return result;
 }
diff --git a/Tests/UnitTests/TestCore/MatrixFunctionsTest.h b/Tests/UnitTests/TestCore/MatrixFunctionsTest.h
deleted file mode 100644
index 17c251235d3..00000000000
--- a/Tests/UnitTests/TestCore/MatrixFunctionsTest.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef MATRIXFUNCTIONSTEST_H
-#define MATRIXFUNCTIONSTEST_H
-
-#include "MathFunctions.h"
-#include "gtest/gtest.h"
-
-class MatrixFunctionsTest : public::testing::Test
-{
-protected:
-    MatrixFunctionsTest();
-    virtual ~MatrixFunctionsTest(){}
-
-    Eigen::Matrix2cd matrix_2cd;
-public:
-    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
-};
-
-MatrixFunctionsTest::MatrixFunctionsTest(){
-    matrix_2cd(0,0) = complex_t(2.0, 1.0);
-    matrix_2cd(0,1) = complex_t(3.0, 1.0);
-    matrix_2cd(1,0) = complex_t(4.0, 1.0);
-    matrix_2cd(1,1) = complex_t(5.0, 1.0);
-}
-
-TEST_F(MatrixFunctionsTest, Norm)
-{
-
-    Eigen::Matrix2d matrix_norm = MathFunctions::Norm(matrix_2cd);
-    EXPECT_EQ(std::norm((complex_t)matrix_2cd(0,0)), matrix_norm(0,0));
-    EXPECT_EQ(std::norm((complex_t)matrix_2cd(0,1)), matrix_norm(0,1));
-    EXPECT_EQ(std::norm((complex_t)matrix_2cd(1,0)), matrix_norm(1,0));
-    EXPECT_EQ(std::norm((complex_t)matrix_2cd(1,1)), matrix_norm(1,1));
-}
-
-TEST_F(MatrixFunctionsTest, Abs)
-{
-   Eigen::Matrix2d matrix_abs = MathFunctions::Abs(matrix_2cd);
-   EXPECT_EQ(std::abs((complex_t)matrix_2cd(0,0)), matrix_abs(0,0));
-   EXPECT_EQ(std::abs((complex_t)matrix_2cd(0,1)), matrix_abs(0,1));
-   EXPECT_EQ(std::abs((complex_t)matrix_2cd(1,0)), matrix_abs(1,0));
-   EXPECT_EQ(std::abs((complex_t)matrix_2cd(1,1)), matrix_abs(1,1));
-}
-
-TEST_F(MatrixFunctionsTest, ProductByElement)
-{
-    Eigen::Matrix2cd matrix_2cd2;
-    matrix_2cd2(0,0) = complex_t(2.0, 1.0);
-    matrix_2cd2(0,1) = complex_t(3.0, 1.0);
-    matrix_2cd2(1,0) = complex_t(4.0, 1.0);
-    matrix_2cd2(1,1) = complex_t(5.0, 1.0);
-
-   Eigen::Matrix2cd matrix_prod = MathFunctions::ProductByElement(matrix_2cd, matrix_2cd2);
-   EXPECT_EQ(complex_t(3.0, 4.0), matrix_prod(0,0));
-   EXPECT_EQ(complex_t(8.0, 6.0), matrix_prod(0,1));
-   EXPECT_EQ(complex_t(15.0, 8.0), matrix_prod(1,0));
-   EXPECT_EQ(complex_t(24.0, 10.0), matrix_prod(1,1));
-}
-
-TEST_F(MatrixFunctionsTest, Conj)
-{
-   Eigen::Matrix2cd matrix_conj = MathFunctions::Conj(matrix_2cd);
-   EXPECT_EQ(std::conj((complex_t)matrix_2cd(0,0)), matrix_conj(0,0));
-   EXPECT_EQ(std::conj((complex_t)matrix_2cd(0,1)), matrix_conj(0,1));
-   EXPECT_EQ(std::conj((complex_t)matrix_2cd(1,0)), matrix_conj(1,0));
-   EXPECT_EQ(std::conj((complex_t)matrix_2cd(1,1)), matrix_conj(1,1));
-}
-
-TEST_F(MatrixFunctionsTest, Real)
-{
-   Eigen::Matrix2d matrix_conj = MathFunctions::Real(matrix_2cd);
-   EXPECT_EQ(((complex_t)matrix_2cd(0,0)).real(), matrix_conj(0,0));
-   EXPECT_EQ(((complex_t)matrix_2cd(0,1)).real(), matrix_conj(0,1));
-   EXPECT_EQ(((complex_t)matrix_2cd(1,0)).real(), matrix_conj(1,0));
-   EXPECT_EQ(((complex_t)matrix_2cd(1,1)).real(), matrix_conj(1,1));
-}
-
-#endif //MATRIXFUNCTIONSTEST_H
diff --git a/Tests/UnitTests/TestCore/SpecialFunctionsTest.h b/Tests/UnitTests/TestCore/SpecialFunctionsTest.h
index 5df36be699f..178b084c53a 100644
--- a/Tests/UnitTests/TestCore/SpecialFunctionsTest.h
+++ b/Tests/UnitTests/TestCore/SpecialFunctionsTest.h
@@ -66,28 +66,28 @@ TEST_F(SpecialFunctionsTest, csinc)
         double ph = 2*M_PI*i/24;
         //std::cout << "---------------------------------------------------------------------\n";
         //std::cout << "phase = " << ph << "\n";
-        EXPECT_EQ( MathFunctions::Sinc(complex_t(0,0)),       complex_t(1.,0.) );
+        EXPECT_EQ( MathFunctions::sinc(complex_t(0,0)),       complex_t(1.,0.) );
         complex_t z;
-        z=std::polar(1e-17,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), complex_t(1.,0.), eps );
-        z=std::polar(2e-17,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), complex_t(1.,0.), eps );
-        z=std::polar(5e-17,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), complex_t(1.,0.), eps );
-        z=std::polar(1e-16,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), complex_t(1.,0.), eps );
-        z=std::polar(2e-16,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), complex_t(1.,0.), eps );
-        z=std::polar(5e-16,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), complex_t(1.,0.), eps );
-        z=std::polar(1e-15,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), complex_t(1.,0.), eps );
-        z=std::polar(1e-13,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), complex_t(1.,0.), eps );
-        z=std::polar(1e-11,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), complex_t(1.,0.), eps );
-        z=std::polar(1e-9, ph); EXPECT_CNEAR( MathFunctions::Sinc(z), complex_t(1.,0.), eps );
-        z=std::polar(5e-8,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), 1.-z*z/6., eps );
-        z=std::polar(2e-8,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), 1.-z*z/6., eps );
-        z=std::polar(1e-8,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), 1.-z*z/6., eps );
-        z=std::polar(5e-7,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), 1.-z*z/6., eps );
-        z=std::polar(2e-7,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), 1.-z*z/6., eps );
-        z=std::polar(1e-7,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), 1.-z*z/6., eps );
-        z=std::polar(1e-6,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), 1.-z*z/6., eps );
-        z=std::polar(1e-5,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), 1.-z*z/6., eps );
-        z=std::polar(1e-4,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), 1.-z*z/6.*(1.-z*z/20.), eps );
-        z=std::polar(1e-3,ph); EXPECT_CNEAR( MathFunctions::Sinc(z), 1.-z*z/6.*(1.-z*z/20.), eps );
+        z=std::polar(1e-17,ph); EXPECT_CNEAR( MathFunctions::sinc(z), complex_t(1.,0.), eps );
+        z=std::polar(2e-17,ph); EXPECT_CNEAR( MathFunctions::sinc(z), complex_t(1.,0.), eps );
+        z=std::polar(5e-17,ph); EXPECT_CNEAR( MathFunctions::sinc(z), complex_t(1.,0.), eps );
+        z=std::polar(1e-16,ph); EXPECT_CNEAR( MathFunctions::sinc(z), complex_t(1.,0.), eps );
+        z=std::polar(2e-16,ph); EXPECT_CNEAR( MathFunctions::sinc(z), complex_t(1.,0.), eps );
+        z=std::polar(5e-16,ph); EXPECT_CNEAR( MathFunctions::sinc(z), complex_t(1.,0.), eps );
+        z=std::polar(1e-15,ph); EXPECT_CNEAR( MathFunctions::sinc(z), complex_t(1.,0.), eps );
+        z=std::polar(1e-13,ph); EXPECT_CNEAR( MathFunctions::sinc(z), complex_t(1.,0.), eps );
+        z=std::polar(1e-11,ph); EXPECT_CNEAR( MathFunctions::sinc(z), complex_t(1.,0.), eps );
+        z=std::polar(1e-9, ph); EXPECT_CNEAR( MathFunctions::sinc(z), complex_t(1.,0.), eps );
+        z=std::polar(5e-8,ph); EXPECT_CNEAR( MathFunctions::sinc(z), 1.-z*z/6., eps );
+        z=std::polar(2e-8,ph); EXPECT_CNEAR( MathFunctions::sinc(z), 1.-z*z/6., eps );
+        z=std::polar(1e-8,ph); EXPECT_CNEAR( MathFunctions::sinc(z), 1.-z*z/6., eps );
+        z=std::polar(5e-7,ph); EXPECT_CNEAR( MathFunctions::sinc(z), 1.-z*z/6., eps );
+        z=std::polar(2e-7,ph); EXPECT_CNEAR( MathFunctions::sinc(z), 1.-z*z/6., eps );
+        z=std::polar(1e-7,ph); EXPECT_CNEAR( MathFunctions::sinc(z), 1.-z*z/6., eps );
+        z=std::polar(1e-6,ph); EXPECT_CNEAR( MathFunctions::sinc(z), 1.-z*z/6., eps );
+        z=std::polar(1e-5,ph); EXPECT_CNEAR( MathFunctions::sinc(z), 1.-z*z/6., eps );
+        z=std::polar(1e-4,ph); EXPECT_CNEAR( MathFunctions::sinc(z), 1.-z*z/6.*(1.-z*z/20.), eps );
+        z=std::polar(1e-3,ph); EXPECT_CNEAR( MathFunctions::sinc(z), 1.-z*z/6.*(1.-z*z/20.), eps );
     }
 }
 
diff --git a/Tests/UnitTests/TestCore/main.cpp b/Tests/UnitTests/TestCore/main.cpp
index 37bc2510515..c39b05f3a41 100644
--- a/Tests/UnitTests/TestCore/main.cpp
+++ b/Tests/UnitTests/TestCore/main.cpp
@@ -39,7 +39,6 @@
 #include "MatrixRTCoefficientsTest.h"
 #include "ScalarSpecularInfoMapTest.h"
 #include "MatrixSpecularInfoMapTest.h"
-#include "MatrixFunctionsTest.h"
 #include "FixedBinAxisTest.h"
 #include "VariableBinAxisTest.h"
 #include "ConstKBinAxisTest.h"
@@ -84,4 +83,3 @@ int main(int argc, char** argv)
     // run all google tests
     return RUN_ALL_TESTS();
 }
-
-- 
GitLab