Skip to content
Snippets Groups Projects
Convolve.h 4.23 KiB
// ************************************************************************** //
//
//  BornAgain: simulate and fit scattering at grazing incidence
//
//! @file      Tools/inc/Convolve.h
//! @brief     Defines class MathFunctions::Convolve.
//!
//! @homepage  http://apps.jcns.fz-juelich.de/BornAgain
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2013
//! @authors   Scientific Computing Group at MLZ Garching
//! @authors   C. Durniak, G. Pospelov, W. Van Herck, J. Wuttke
//
// ************************************************************************** //

#ifndef CONVOLVE_H
#define CONVOLVE_H

#include <fftw3.h>
#include <vector>

namespace MathFunctions
{

//! Convolution of two real vectors (in 1D or 2D) using Fast Fourier Transform.

//! Usage:
//! std::vector<double> signal, kernel, result;
//! Convolve cv;
//! cv.fftconvolve(signal, kernel, result)
//!
//! Given code rely on code from Jeremy Fix page
//! http://jeremy.fix.free.fr/spip.php?article15
//! see also
//! "Efficient convolution using the Fast Fourier Transform, Application in C++"
//! by Jeremy Fix, May 30, 2011
//!
class Convolve
{
 public:
    //! definition of 1d vector of double
    typedef std::vector<double > double1d_t;

    //! definition of 2d vector of double
    typedef std::vector<double1d_t > double2d_t;

    Convolve();
    ~Convolve();

    //! 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
    void fftconvolve(const double1d_t& source, const double1d_t& kernel, double1d_t& result);

    //! convolution in 2D
    void fftconvolve(const double2d_t& source, const double2d_t& kernel, double2d_t& result);

    //! prepare arrays for 2D convolution of given vectors
    void init(int h_src, int w_src, int h_kernel, int w_kernel);

    //! Sets convolution mode
    void setMode(Mode mode) { m_mode = mode; }

 private:
    //! compute circual convolution of source and kernel using fast Fourier transformation
    void fftw_circular_convolution(const double2d_t& source, const double2d_t& kernel);

    //! find closest number X>n that can be factorised according to fftw3 favorite factorisation
    int find_closest_factor(int n);

    //! if a number can be factorised using only favorite fftw3 factors
    bool is_optimal(int n);

    //! Workspace for Fourier convolution.

    //! 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 function.
    //! Sizes of input arrays are adjusted; output arrays are alocated via
    //! fftw3 allocation for maximum performance.
    class Workspace
    {
    public:
        Workspace();
        ~Workspace();
        void clear();
        friend class Convolve;
    private:
        int h_src, w_src;                 // size of original 'source' array in 2 dimensions
        int h_kernel, w_kernel;           // size of original 'kernel' array in 2 dimensions
        int w_fftw, h_fftw;               // size of adjusted source and kernel arrays (in_src, out_src, in_kernel, out_kernel)
        //! adjusted input 'source' array
        double *in_src;
        //! result of Fourier transformation of source
        double *out_src;
        //! adjusted input 'kernel' array
        double *in_kernel;
        //! result of Fourier transformation of kernel
        double *out_kernel;
        //! result of production of FFT(source) and FFT(kernel)
        double *dst_fft;
        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;
    };

    //! input and output data for fftw3
    Workspace ws;
    //! convolution mode
    Mode m_mode;
    std::vector<size_t > m_implemented_factors; // favorite factorization terms of fftw3
};

}  // namespace MathFunctions

#endif // CONVOLVE_H