From b7679ed67fb8593ebd0479acd96382f8cfbd46e2 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste Keck <Jean-Baptiste.Keck@imag.fr>
Date: Fri, 26 Feb 2016 20:11:18 +0100
Subject: [PATCH] Added missing main source (planner.cpp), added rpath and
 macro define parsing in setup.py.in, extended swig coverage

---
 .gitignore                                    |   2 +-
 HySoP/.gitignore                              |   5 +
 HySoP/CMakeLists.txt                          |   4 +-
 HySoP/setup.py.in                             |   7 +-
 HySoP/src/hysop++/main/diffSolver.cpp         |   4 +-
 HySoP/src/hysop++/main/planner.cpp            | 197 ++++
 HySoP/src/hysop++/main/poissonSolver.cpp      |  16 +-
 .../data/multi_array/multi_array_defines.h    |   6 +-
 .../src/data/multi_array/multi_array_impl.h   |  12 +-
 HySoP/src/hysop++/src/domain/boundary.cpp     |   2 +-
 HySoP/src/hysop++/src/domain/boundary.h       |   8 +-
 HySoP/src/hysop++/src/domain/domain.h         |  14 +-
 .../hysop++/src/domain/domainConfiguration.h  |  28 +-
 HySoP/src/hysop++/src/fft/extension.cpp       |   2 +-
 HySoP/src/hysop++/src/fft/extension.h         |   2 +-
 .../hysop++/src/fft/fftDomainConfiguration.h  |   8 +-
 HySoP/src/hysop++/src/fft/fftw3.cpp           |  40 +
 HySoP/src/hysop++/src/fft/fftw3.h             | 839 ++++++++++--------
 HySoP/src/hysop++/src/fft/planner.h           |  22 +-
 HySoP/src/hysop++/src/maths/quad_maths.h      |   8 +-
 HySoP/src/hysop++/src/utils/types.h           |  18 +-
 .../tests/testDiffSolver/testDiffSolver.cpp   |   4 +-
 .../hysop++/tests/testPlanner/testPlanner.cpp |   4 +-
 .../testPoissonSolver/testPoissonSolver.cpp   |   4 +-
 .../tests/testPolynoms/testPolynoms.cpp       |   4 +-
 HySoP/swig/constants.i                        |   7 -
 HySoP/swig/cpp2hysop.i                        |   5 +-
 HySoP/swig/{ => fftw}/fftw.i                  |   3 +-
 HySoP/swig/hysop++/domain.i                   |  38 +
 HySoP/swig/hysop++/fft.i                      |  91 ++
 HySoP/swig/hysop++/hysop++.i                  |   5 +
 HySoP/swig/hysop++/utils.i                    |  29 +
 HySoP/swig/start.i                            |   4 +
 HySoP/swig/types.i                            |   7 -
 34 files changed, 970 insertions(+), 479 deletions(-)
 create mode 100644 HySoP/.gitignore
 create mode 100644 HySoP/src/hysop++/main/planner.cpp
 create mode 100644 HySoP/src/hysop++/src/fft/fftw3.cpp
 delete mode 100644 HySoP/swig/constants.i
 rename HySoP/swig/{ => fftw}/fftw.i (62%)
 create mode 100644 HySoP/swig/hysop++/domain.i
 create mode 100644 HySoP/swig/hysop++/fft.i
 create mode 100644 HySoP/swig/hysop++/hysop++.i
 create mode 100644 HySoP/swig/hysop++/utils.i
 delete mode 100644 HySoP/swig/types.i

diff --git a/.gitignore b/.gitignore
index aa4dfb4ff..9a8bdc053 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,4 @@
 HySoP/hysop/__init__.py
 .#*
 HySoP/hysop/.pyflymakercc
-.DS_Store
\ No newline at end of file
+.DS_Store
diff --git a/HySoP/.gitignore b/HySoP/.gitignore
new file mode 100644
index 000000000..c4bde9e9b
--- /dev/null
+++ b/HySoP/.gitignore
@@ -0,0 +1,5 @@
+build/
+debug/
+release/
+.cache/
+hysop/f2hysop.pyf
diff --git a/HySoP/CMakeLists.txt b/HySoP/CMakeLists.txt
index d5c833b5a..c79770845 100644
--- a/HySoP/CMakeLists.txt
+++ b/HySoP/CMakeLists.txt
@@ -252,10 +252,10 @@ set(CMAKE_EXE_LINKER_FLAGS         "${CMAKE_EXE_LINKER_FLAGS}")
 
 set(CXX_FLAGS "${CMAKE_CXX_FLAGS}")
 set(CXX_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
-set(CXX_EXT_INCLUDES ${PYTHON_INCLUDE_DIR} ${FFTW_INCLUDES})
+set(CXX_EXT_INCLUDES ${PYTHON_INCLUDE_DIR} ${FFTW_INCLUDE_DIRS})
 set(CXX_EXT_LIBS ${PYTHON_LIBRARIES} ${FFTW_LIBRARIES})
 set(CXX_EXT_LIB_DIRS ${FFTW_LIBRARY_DIRS})
-set(CXX_EXTRA_DEFINES ${FFTW_DEFINES})
+set(CXX_EXTRA_DEFINES ${FFTW_DEFINES} -DHAS_EXTERN_TEMPLATES)
 
 #swig package name (lib name generated by swig)
 set(CPP_2_HYSOP "cpp2hysop")
diff --git a/HySoP/setup.py.in b/HySoP/setup.py.in
index 3f14efafa..b68a69ce7 100644
--- a/HySoP/setup.py.in
+++ b/HySoP/setup.py.in
@@ -28,7 +28,7 @@ def parseCMakeDefines(var):
     if defines == None:
         return None
    
-    # regex to match defines like -DMACRO_NAME = MACRO_VALUE
+    # regex to match compiler defines like -DMACRO_NAME or -DMACRO_NAME = MACRO_VALUE
     p = re.compile('\s*(?:-D)?\s*(\w+)(?:\s*=\s*(\w+))?\s*')
 
     res = list()
@@ -116,8 +116,8 @@ def create_swig_extension(name, inc_dirs, src_dirs=None, sources=None):
 
     name = 'hysop._' + name
     swig_opts = ['-I' + swig_dir,
-                 '-c++', '-modern']
-                 #-outdir', '/Users/Franck/toto',
+                 '-O', '-Wextra', '-Werror',
+                 '-c++', '-extranative', '-safecstrings']
     
     extern_includes = parseCMakeVar("@CXX_EXT_INCLUDES@")
     if(extern_includes != None):
@@ -147,6 +147,7 @@ def create_swig_extension(name, inc_dirs, src_dirs=None, sources=None):
                          library_dirs=library_dirs,
                          libraries=libraries,
                          define_macros=define_macros,
+                         runtime_library_dirs=library_dirs,
                          extra_compile_args=extra_compile_args,
                          extra_link_args=extra_link_args)
 
diff --git a/HySoP/src/hysop++/main/diffSolver.cpp b/HySoP/src/hysop++/main/diffSolver.cpp
index 29548ea56..3d0316e3f 100644
--- a/HySoP/src/hysop++/main/diffSolver.cpp
+++ b/HySoP/src/hysop++/main/diffSolver.cpp
@@ -69,7 +69,7 @@ std::function<T(T)> derivative(std::size_t k, int order) {
     
 template <typename T, std::size_t Dim, bool verbose=false> 
 void test(std::size_t p_maxOrder, bool includePeriodicBds=false) {
-    Shape<Dim> shape;
+    typename Shape<Dim>::type shape;
     typename Domain<T,Dim>::DomainSize domainSize;
     Domain<T,Dim> ref, inBuffer, outBuffer;
 
@@ -88,7 +88,7 @@ void test(std::size_t p_maxOrder, bool includePeriodicBds=false) {
     in  = ref;
     out = ref;
    
-    Shape<Dim> maxOrder, testCases;
+    typename Shape<Dim>::type maxOrder, testCases;
     maxOrder.fill(p_maxOrder+1);
     testCases.fill(nExtensionsPair);
     Index<Dim> orderId(maxOrder);
diff --git a/HySoP/src/hysop++/main/planner.cpp b/HySoP/src/hysop++/main/planner.cpp
new file mode 100644
index 000000000..287c6713c
--- /dev/null
+++ b/HySoP/src/hysop++/main/planner.cpp
@@ -0,0 +1,197 @@
+
+#include "maths/quad_maths.h"
+
+#include "data/multi_array/multi_array.h"
+#include "domain/domain.h"
+#include "utils/constants.h"
+#include "fft/planner.h"
+#include "fft/extension.h"
+
+
+using namespace hysop;
+using namespace hysop::domain;
+
+static constexpr std::size_t nExtensions = 4 ;
+static constexpr std::size_t nExtensionsPair = 6 ;
+static constexpr fft::Extension ext[nExtensions] = 
+{ fft::Extension::NONE, fft::Extension::ODD, fft::Extension::EVEN, fft::Extension::PERIODIC };
+static constexpr std::pair<fft::Extension,fft::Extension> pext[nExtensionsPair] {
+    std::make_pair(ext[0],ext[0]), //none-none
+        std::make_pair(ext[1],ext[1]), //odd-odd
+        std::make_pair(ext[1],ext[2]), //odd-even
+        std::make_pair(ext[1],ext[2]), //even-odd
+        std::make_pair(ext[2],ext[2]), //even-even
+        std::make_pair(ext[3],ext[3]), //periodic-periodic
+};
+
+template <typename T, std::size_t Dim, bool verbose=false> 
+void test(bool inplace, bool includePeriodicBds);
+
+
+int main(int argc, const char *argv[]) {
+
+#ifdef FFTW_HAS_FFTW3F
+    std::cout << std::endl; 
+    std::cout << "== TEST 1D - float       ==\t";
+    test<float,1>(false,true);
+    std::cout << "== TEST 2D - float       ==\t";
+    test<float,2>(false,true);
+    std::cout << "== TEST 3D - float       ==\t";
+    test<float,3>(false,true);
+#endif
+
+#ifdef FFTW_HAS_FFTW3D
+    std::cout << std::endl; 
+    std::cout << "== TEST 1D - double      ==\t";
+    test<double,1>(true,true);
+    std::cout << "== TEST 2D - double      ==\t";
+    test<double,2>(true,true);
+    std::cout << "== TEST 3D - double      ==\t";
+    test<double,3>(true,true);
+#endif
+
+#ifdef FFTW_HAS_FFTW3L
+    std::cout << std::endl; 
+    std::cout << "== TEST 1D - long double ==\t";
+    test<long double,1>(false,false);
+    std::cout << "== TEST 2D - long double ==\t";
+    test<long double,2>(false,false);
+    std::cout << "== TEST 3D - long double ==\t";
+    test<long double,3>(false,false);
+#endif
+
+#ifdef FFTW_HAS_FFTW3Q
+    std::cout << std::endl; 
+    std::cout << "== TEST 1D - __float128 ==\t";
+    test<__float128,1>(false,false);
+    std::cout << "== TEST 2D - __float128 ==\t";
+    test<__float128,2>(false,false);
+    std::cout << "== TEST 3D - __float128 ==\t";
+    test<__float128,3>(false,false);
+#endif
+    
+    return 0;
+}
+
+template <typename T, std::size_t Dim, bool verbose> 
+void test(bool inplace, bool includePeriodicBds) {
+    typename Shape<Dim>::type shape;
+    typename Domain<T,Dim>::DomainSize domainSize;
+    Domain<T,Dim> ref, inBuffer, outBuffer;
+
+    Domain<T,Dim>& in  = inBuffer;
+    Domain<T,Dim>& out = (inplace ? inBuffer : outBuffer);
+
+    fft::Planner<T,Dim> planner;
+    std::array<int,Dim> order;
+
+    const std::size_t nPoints = 16;
+    shape.fill(nPoints);
+    domainSize.fill(1.0);
+    order.fill(2);
+
+    const T eps = std::numeric_limits<T>::epsilon();
+    const std::size_t N = std::accumulate(shape.begin(), shape.end(), 1, std::multiplies<std::size_t>());
+    const auto criteria = std::make_tuple(50*eps*N,sqrt(50)*eps*N,700*eps);
+    
+    ref.resize(domainSize).reshape(shape);
+    in  = ref;
+    out = ref;
+   
+    typename Shape<Dim>::type testCases;
+    testCases.fill(nExtensionsPair);
+    Index<Dim> testCaseId(testCases);
+    std::array<T,3> meanDists{0};
+    while(!testCaseId.atMaxId()) { 
+        /* generate transform configuration */
+        std::array<std::pair<fft::Extension,fft::Extension>, Dim> extConfig;
+        for (std::size_t k=0; k<Dim; k++) {
+            std::size_t id = testCaseId[k];
+            extConfig[k] = pext[id];
+        }
+        fft::FftDomainConfiguration<Dim> domainConfig(extConfig, includePeriodicBds);
+    
+        const auto f = [&](T &val, const hysop::Index<Dim>& idx) { 
+            val = static_cast<T>(rand())/static_cast<T>(RAND_MAX);
+            for (std::size_t d=0; d<Dim; d++) {
+                if(idx[d]==0) {
+                    if(extConfig[d].first == fft::Extension::ODD) {
+                        val=T(0); 
+                        return;
+                    }
+                    else if(extConfig[d].first == fft::Extension::PERIODIC)
+                        val=T(0.42);
+                }
+                else if(std::size_t(idx[d]) == idx.dim()[d]-1) {
+                    if(extConfig[d].second == fft::Extension::ODD) {
+                        val=T(0);
+                        return;
+                    }
+                    else if(extConfig[d].second == fft::Extension::PERIODIC && includePeriodicBds)
+                        val=T(0.42);
+                }
+            }
+        };
+        
+        if(includePeriodicBds)
+            ref.resetDomainConfiguration(domainConfig.boundariesConfiguration()); 
+        
+        /* fill reference and copy into input buffer */
+        ref.data().apply(f);
+        in = ref;
+       
+        /* plan transforms and check if planning succeeded */
+        bool status = planner.plan(in.data(), out.data(), domainConfig, order, domainSize, FFTW_MEASURE, 
+                    includePeriodicBds, includePeriodicBds);
+        assert(status || testCaseId()==0);
+    
+        /* execute forward and backward inplace transforms */
+        planner.executeForwardTransform();
+        {
+            if(planner.transformType() == fft::FftTransformType::FFT_R2C)
+                planner.transformedComplexData().apply([&](std::complex<T>& val) { val /= planner.normalisationFactor(); }); 
+            else if(planner.transformType() == fft::FftTransformType::FFT_R2R)
+                planner.transformedRealData().apply([&](T& val) { val /= planner.normalisationFactor(); }); 
+        }
+        planner.executeBackwardTransform();
+        
+        std::stringstream ss;
+        ss << "[";
+        for (std::size_t k=0; k<Dim-1; k++) 
+            ss << extConfig[k].first << "/" << extConfig[k].second << ",";
+        ss << extConfig[Dim-1].first << "/" << extConfig[Dim-1].second;
+        ss << "]";
+
+        const auto dist = out.distance(ref);
+        const bool pass =      (std::get<0>(dist) < std::get<0>(criteria)) 
+                            && (std::get<1>(dist) < std::get<1>(criteria))
+                            && (std::get<2>(dist) < std::get<2>(criteria));
+
+        if((pass && verbose) || !pass) {
+            std::cout << (pass ? GREEN : RED);
+            std::cout << "\t" << std::setw(Dim*15) << ss.str() << " => " << (pass ? "OK" : "KO") 
+                << "  " << RESET << std::scientific << std::setprecision(2) << dist << std::endl;
+        }
+        if(!pass) {
+            if(!inplace)
+                in.print("IN");
+            ref.print("REF");
+            out.print("OUT");
+            std::cout << planner << std::endl;
+            exit(EXIT_FAILURE);
+        }
+
+        meanDists[0] += std::get<0>(dist);
+        meanDists[1] += std::get<1>(dist);
+        meanDists[2] += std::get<2>(dist);
+
+        ++testCaseId;
+    }
+    for (std::size_t k = 0; k < 3; k++)
+        meanDists[k] /= T(testCaseId.maxId());
+    std::cout << "Mean distances over " << std::scientific << std::setprecision(1) << std::setw(4)
+         << testCaseId.maxId() << " testcases: " << meanDists;
+    for (std::size_t k = 0; k < 3; k++)
+        meanDists[k] = std::round(meanDists[k]/eps);
+    std::cout << " ~= " << std::fixed << std::setprecision(0) << meanDists << " eps" << std::endl; 
+}
diff --git a/HySoP/src/hysop++/main/poissonSolver.cpp b/HySoP/src/hysop++/main/poissonSolver.cpp
index dfb829a49..e95a8cd50 100644
--- a/HySoP/src/hysop++/main/poissonSolver.cpp
+++ b/HySoP/src/hysop++/main/poissonSolver.cpp
@@ -45,19 +45,19 @@ std::function<T(T)> func(std::size_t k) {
 
 std::string bdsToStr(domain::Boundary bd) {
     switch(bd) {
-        case(NONE):                    return "None      ";
-        case(PERIODIC) :               return "Periodic  ";
-        case(HOMOGENEOUS_NEUMANN):     return "Hom_Neum. ";
-        case(HOMOGENEOUS_DIRICHLET):   return "Hom_Diric.";
-        case(NEUMANN):                 return "Neumann   ";
-        case(DIRICHLET):               return "Dirichlet ";
+        case(Boundary::NONE):                    return "None      ";
+        case(Boundary::PERIODIC) :               return "Periodic  ";
+        case(Boundary::HOMOGENEOUS_NEUMANN):     return "Hom_Neum. ";
+        case(Boundary::HOMOGENEOUS_DIRICHLET):   return "Hom_Diric.";
+        case(Boundary::NEUMANN):                 return "Neumann   ";
+        case(Boundary::DIRICHLET):               return "Dirichlet ";
     }
     return "";
 }
 
 template <typename T, std::size_t Dim, bool verbose=false> 
 void test(bool includePeriodicBds=false) {
-    Shape<Dim> shape;
+    typename Shape<Dim>::type shape;
     typename Domain<T,Dim>::DomainSize domainSize;
     Domain<T,Dim> ref, inBuffer, outBuffer;
 
@@ -74,7 +74,7 @@ void test(bool includePeriodicBds=false) {
     in  = ref;
     out = ref;
    
-    Shape<Dim> testCases;
+    typename Shape<Dim>::type testCases;
     testCases.fill(nBoundaryPairs);
     Index<Dim> testCaseId(testCases);
     std::array<T,3> meanDists{0};
diff --git a/HySoP/src/hysop++/src/data/multi_array/multi_array_defines.h b/HySoP/src/hysop++/src/data/multi_array/multi_array_defines.h
index 75e51a227..cc1b03018 100644
--- a/HySoP/src/hysop++/src/data/multi_array/multi_array_defines.h
+++ b/HySoP/src/hysop++/src/data/multi_array/multi_array_defines.h
@@ -60,7 +60,7 @@
 /* public const common interfaces for views and referencess */
 #define PUBLIC_COMMON_CONST_INTERFACE(TYPENAME)                                                                   \
         /* shape related */                                                                                      \
-        Shape<Dim> shape() const;                                                                                \
+        typename Shape<Dim>::type shape() const;                                                                                \
                                                                                                                  \
         /* print data */                                                                                         \
         const TYPENAME& print(const std::string& name, std::ostream& os = std::cout,                             \
@@ -146,8 +146,8 @@
 #define COMMON_CONST_IMPLEMENTATION(TYPENAME,TEMPLATES)          \
         /* shape related */                                      \
         TEMPLATES                                                \
-        Shape<Dim> TYPENAME::shape() const {                     \
-            Shape<Dim> shape;                                    \
+        typename Shape<Dim>::type TYPENAME::shape() const {                     \
+            typename Shape<Dim>::type shape;                                    \
             const std::size_t* extents = this->super::shape();   \
             for (std::size_t d = 0; d < Dim; d++)                \
                 shape[d] = static_cast<std::size_t>(extents[d]); \
diff --git a/HySoP/src/hysop++/src/data/multi_array/multi_array_impl.h b/HySoP/src/hysop++/src/data/multi_array/multi_array_impl.h
index 870595368..efb1b1c3b 100644
--- a/HySoP/src/hysop++/src/data/multi_array/multi_array_impl.h
+++ b/HySoP/src/hysop++/src/data/multi_array/multi_array_impl.h
@@ -21,7 +21,7 @@ namespace hysop {
 
                 public:
                     multi_array(const extents_gen<Dim>& extents = extents_gen<Dim>());
-                    multi_array(const Shape<Dim>& shape);
+                    multi_array(const typename Shape<Dim>::type& shape);
 
                     multi_array(const multi_array& other);
                     multi_array(multi_array&& other);
@@ -52,10 +52,10 @@ namespace hysop {
                     PUBLIC_CONST_REF_INTERFACE(SINGLE_ARG(multi_array<T,Dim,Allocator>))
                     PUBLIC_NON_CONST_REF_INTERFACE(SINGLE_ARG(multi_array<T,Dim,Allocator>))
         
-                    multi_array& reshape(const Shape<Dim>& shape);
+                    multi_array& reshape(const typename Shape<Dim>::type& shape);
 
                 protected:
-                    static extents_gen<Dim> shapeToExtents(const Shape<Dim> &shape);
+                    static extents_gen<Dim> shapeToExtents(const typename Shape<Dim>::type &shape);
             };
 
 
@@ -67,7 +67,7 @@ namespace hysop {
             boost_multi_array<T,Dim,Allocator>(extents) {}
                     
         template <typename T, std::size_t Dim, typename Allocator> 
-        multi_array<T,Dim,Allocator>::multi_array(const Shape<Dim>& shape):
+        multi_array<T,Dim,Allocator>::multi_array(const typename Shape<Dim>::type& shape):
             boost_multi_array<T,Dim,Allocator>(shapeToExtents(shape)) {}
         
         template <typename T, std::size_t Dim, typename Allocator> 
@@ -165,7 +165,7 @@ namespace hysop {
 
         /* static members */
         template <typename T, std::size_t Dim, typename Allocator> 
-        typename multi_array<T,Dim,Allocator>::template extents_gen<Dim> multi_array<T,Dim,Allocator>::shapeToExtents(const Shape<Dim> &shape) {
+        typename multi_array<T,Dim,Allocator>::template extents_gen<Dim> multi_array<T,Dim,Allocator>::shapeToExtents(const typename Shape<Dim>::type &shape) {
             return utils::buildExtents(shape);
         }
 
@@ -175,7 +175,7 @@ namespace hysop {
         
         /* multi array specific */
         template <typename T, std::size_t Dim, typename Allocator> 
-            multi_array<T,Dim,Allocator>& multi_array<T,Dim,Allocator>::reshape(const Shape<Dim>& shape) { 
+            multi_array<T,Dim,Allocator>& multi_array<T,Dim,Allocator>::reshape(const typename Shape<Dim>::type& shape) { 
                 boost::array<int,Dim> extents;
                 for (std::size_t d = 0; d < Dim; d++)
                     extents[d] = static_cast<int>(shape[d]);
diff --git a/HySoP/src/hysop++/src/domain/boundary.cpp b/HySoP/src/hysop++/src/domain/boundary.cpp
index 4cb3f491b..4a3f862af 100644
--- a/HySoP/src/hysop++/src/domain/boundary.cpp
+++ b/HySoP/src/hysop++/src/domain/boundary.cpp
@@ -14,7 +14,7 @@ namespace hysop {
         };
 
         const char* toStringBoundary(Boundary bd) {
-            return boundary_strings[bd+1];
+            return boundary_strings[static_cast<int>(bd)+1];
         }
 
         std::ostream& operator<<(std::ostream& os, const Boundary& bd) {
diff --git a/HySoP/src/hysop++/src/domain/boundary.h b/HySoP/src/hysop++/src/domain/boundary.h
index d0aa55438..9320085e0 100644
--- a/HySoP/src/hysop++/src/domain/boundary.h
+++ b/HySoP/src/hysop++/src/domain/boundary.h
@@ -1,12 +1,12 @@
-#ifndef BOUNDARY_H
-#define BOUNDARY_H
+#ifndef HYSOP_BOUNDARY_H
+#define HYSOP_BOUNDARY_H
 
 #include <iostream>
 
 namespace hysop {
     namespace domain {
 
-        enum Boundary : int {
+        enum class Boundary : int {
             NONE                  = -1,
             HOMOGENEOUS_DIRICHLET = 0,
             HOMOGENEOUS_NEUMANN   = 1,
@@ -20,4 +20,4 @@ namespace hysop {
     }
 }
 
-#endif /* end of include guard: BOUNDARY_H */
+#endif /* end of include guard: HYSOP_BOUNDARY_H */
diff --git a/HySoP/src/hysop++/src/domain/domain.h b/HySoP/src/hysop++/src/domain/domain.h
index 9a9b0d27c..70d860ece 100644
--- a/HySoP/src/hysop++/src/domain/domain.h
+++ b/HySoP/src/hysop++/src/domain/domain.h
@@ -28,7 +28,7 @@ namespace hysop {
                         m_shape{0}, m_dataShape{0}, m_leftDataOffset{0},
                         m_domainConfig(), m_domainSize{0}, m_spaceStep{0}, m_data() {}
 
-                    Domain(const Shape<Dim>& p_shape, const DomainConfiguration<Dim>& p_domainConfig, const DomainSize& p_domainSize) :
+                    Domain(const typename Shape<Dim>::type& p_shape, const DomainConfiguration<Dim>& p_domainConfig, const DomainSize& p_domainSize) :
                         m_shape{0}, m_dataShape{0}, m_leftDataOffset{0},
                         m_domainConfig(p_domainConfig), m_domainSize(p_domainSize), 
                         m_spaceStep{0}, m_data() {
@@ -39,7 +39,7 @@ namespace hysop {
                     Domain<T,Dim>& operator=(const Domain<T,Dim>& other) = default; 
                     Domain<T,Dim>& operator=(Domain<T,Dim>&& other)      = default;
 
-                    Domain<T,Dim>& reshape(const Shape<Dim>& p_domainShape) {
+                    Domain<T,Dim>& reshape(const typename Shape<Dim>::type& p_domainShape) {
                         m_shape = p_domainShape;
                         m_domainConfig.getShapeConfiguration(m_shape, m_dataShape, m_leftDataOffset);
                         m_data.reshape(m_dataShape);
@@ -68,11 +68,11 @@ namespace hysop {
                         return fft::FftDomainConfiguration<Dim>(m_domainConfig); 
                     }
 
-                    const Shape<Dim>&              shape()          const { return m_shape; }
-                    const Shape<Dim>&              dataShape()      const { return m_dataShape; }
+                    const typename Shape<Dim>::type&              shape()          const { return m_shape; }
+                    const typename Shape<Dim>::type&              dataShape()      const { return m_dataShape; }
                     const SpaceStep&               spaceStep()      const { return m_spaceStep; }
                     const DomainSize&              domainSize()     const { return m_domainSize; }
-                    const Offset<Dim>&             leftDataOffset() const { return m_leftDataOffset; }
+                    const typename Offset<Dim>::type&             leftDataOffset() const { return m_leftDataOffset; }
                     const DomainConfiguration<Dim> boundaryConfig() const { return m_domainConfig; }
 
                     const hysop::multi_array<T,Dim>&    data() const { return m_data; }
@@ -109,8 +109,8 @@ namespace hysop {
                     }
 
                 protected:
-                    Shape<Dim>  m_shape, m_dataShape;
-                    Offset<Dim> m_leftDataOffset;
+                    typename Shape<Dim>::type  m_shape, m_dataShape;
+                    typename Offset<Dim>::type m_leftDataOffset;
 
                     DomainConfiguration<Dim> m_domainConfig;
                     DomainSize m_domainSize;
diff --git a/HySoP/src/hysop++/src/domain/domainConfiguration.h b/HySoP/src/hysop++/src/domain/domainConfiguration.h
index 42af207fa..3f1c7ded7 100644
--- a/HySoP/src/hysop++/src/domain/domainConfiguration.h
+++ b/HySoP/src/hysop++/src/domain/domainConfiguration.h
@@ -22,8 +22,8 @@ namespace hysop {
             class DomainConfiguration {
 
                 public:
-                    using BoundaryPair   = std::pair<Boundary,Boundary>;
-                    using BoundaryArray  = std::array<BoundaryPair,Dim>;
+                    typedef std::pair<Boundary,Boundary> BoundaryPair;
+                    typedef std::array<BoundaryPair,Dim> BoundaryArray;
                 public: 
                     DomainConfiguration(const BoundaryArray& p_boundaries = defaultDomainBoundaries(), 
                             //bool p_includeDirichletBoundaries = true,
@@ -40,14 +40,14 @@ namespace hysop {
 
                     const BoundaryPair& operator[](std::size_t k) const { return m_boundaries[k]; }
 
-                    void getShapeConfiguration(const Shape<Dim> &p_fullShape, Shape<Dim> &p_realShape, Offset<Dim> &p_leftOffset) const {
+                    void getShapeConfiguration(const typename Shape<Dim>::type &p_fullShape, typename Shape<Dim>::type &p_realShape, typename Offset<Dim>::type &p_leftOffset) const {
                         for (std::size_t d = 0; d < Dim; d++) {
                             const BoundaryPair& pair = m_boundaries[d];
                             //bool hasDirichletLeftOffset  = (pair.first  == DIRICHLET || pair.first  == HOMOGENEOUS_DIRICHLET);
                             //bool hasDirichletRightOffset = (pair.second == DIRICHLET || pair.second == HOMOGENEOUS_DIRICHLET);
                             //std::size_t dirichletLeftOffset  = hasDirichletLeftOffset  && !this->includeDirichletBoundaries();
                             //std::size_t dirichletRightOffset = hasDirichletRightOffset && !this->includeDirichletBoundaries();
-                            bool hasPeriodicRightOffset  = (pair.second == PERIODIC);
+                            bool hasPeriodicRightOffset  = (pair.second == Boundary::PERIODIC);
                             std::size_t periodicRightOffset  = hasPeriodicRightOffset  && !this->includePeriodicBoundaries();
                             std::size_t leftOffset  = 0;
                             std::size_t rightOffset = periodicRightOffset;
@@ -62,19 +62,21 @@ namespace hysop {
                     void checkBoundaries() const {
                         for (std::size_t d = 0; d < Dim; d++) {
                             const BoundaryPair& pair = m_boundaries[d];
-                            if((pair.first == PERIODIC) ^ (pair.second == PERIODIC))
+                            if((pair.first == Boundary::PERIODIC) ^ (pair.second == Boundary::PERIODIC))
                                 throw std::runtime_error("Bad boundaries configuration on axe " + std::to_string(d) + " !");
                         }
                     }
 
-                    template <int... I>
-                    static const std::array<BoundaryPair, Dim> defaultDomainBoundariesImpl(hysop::detail::index_seq<I...>) {
-                        const BoundaryPair defaultVal[1] = { std::make_pair(Boundary::NONE,Boundary::NONE) };
-                        return { defaultVal[I]..., };
-                    }
-                    static const std::array<BoundaryPair, Dim> defaultDomainBoundaries() {
-                        return defaultDomainBoundariesImpl(hysop::detail::constant_seq_gen<0,Dim>());
-                    }
+                    #ifndef SWIG
+                        template <int... I>
+                        static const std::array<BoundaryPair, Dim> defaultDomainBoundariesImpl(hysop::detail::index_seq<I...>) {
+                            const BoundaryPair defaultVal[1] = { std::make_pair(Boundary::NONE,Boundary::NONE) };
+                            return { defaultVal[I]..., };
+                        }
+                        static const std::array<BoundaryPair, Dim> defaultDomainBoundaries() {
+                            return defaultDomainBoundariesImpl(hysop::detail::constant_seq_gen<0,Dim>());
+                        }
+                    #endif 
 
                 protected:
                     BoundaryArray  m_boundaries;
diff --git a/HySoP/src/hysop++/src/fft/extension.cpp b/HySoP/src/hysop++/src/fft/extension.cpp
index eeacb339b..6f2a67e5e 100644
--- a/HySoP/src/hysop++/src/fft/extension.cpp
+++ b/HySoP/src/hysop++/src/fft/extension.cpp
@@ -12,7 +12,7 @@ namespace hysop {
         };
 
         const char* toStringExtension(Extension ext) {
-            return extension_strings[ext+1];
+            return extension_strings[static_cast<int>(ext)+1];
         }
 
         std::ostream& operator<<(std::ostream& os, const Extension& ext) {
diff --git a/HySoP/src/hysop++/src/fft/extension.h b/HySoP/src/hysop++/src/fft/extension.h
index 815f25a65..5aaba36f2 100644
--- a/HySoP/src/hysop++/src/fft/extension.h
+++ b/HySoP/src/hysop++/src/fft/extension.h
@@ -7,7 +7,7 @@
 namespace hysop {
     namespace fft {
 
-        enum Extension : int {
+        enum class Extension : int {
             NONE=-1,
             EVEN=0,
             ODD=1,
diff --git a/HySoP/src/hysop++/src/fft/fftDomainConfiguration.h b/HySoP/src/hysop++/src/fft/fftDomainConfiguration.h
index f3ccea896..57f014d63 100644
--- a/HySoP/src/hysop++/src/fft/fftDomainConfiguration.h
+++ b/HySoP/src/hysop++/src/fft/fftDomainConfiguration.h
@@ -19,10 +19,10 @@ namespace hysop {
         class FftDomainConfiguration {
 
                 public:
-                    using BoundaryPair   = typename domain::DomainConfiguration<Dim>::BoundaryPair;
-                    using BoundaryArray  = typename domain::DomainConfiguration<Dim>::BoundaryArray;
-                    using ExtensionPair  = std::pair<fft::Extension,fft::Extension>;
-                    using ExtensionArray = std::array<ExtensionPair,Dim>;
+                    typedef typename domain::DomainConfiguration<Dim>::BoundaryPair  BoundaryPair;
+                    typedef typename domain::DomainConfiguration<Dim>::BoundaryArray BoundaryArray;
+                    typedef std::pair<fft::Extension,fft::Extension>                 ExtensionPair;
+                    typedef std::array<ExtensionPair,Dim>                            ExtensionArray;
                 public: 
                     FftDomainConfiguration(const ExtensionArray& p_extensions, bool p_includePeriodicBoundaries) :
                         m_extensions(p_extensions), m_includePeriodicBoundaries(p_includePeriodicBoundaries) {
diff --git a/HySoP/src/hysop++/src/fft/fftw3.cpp b/HySoP/src/hysop++/src/fft/fftw3.cpp
new file mode 100644
index 000000000..25a877c87
--- /dev/null
+++ b/HySoP/src/hysop++/src/fft/fftw3.cpp
@@ -0,0 +1,40 @@
+
+#include "fft/fftw3.h"
+
+namespace hysop {
+    namespace fft {
+        template struct Fftw3<float>;
+        template struct Fftw3<double>;
+        template struct Fftw3<long double>;
+        #ifdef HAS_QUADMATHS
+            template struct Fftw3<__float128>;
+        #endif
+    }
+}
+
+/* needed for swig to avoid undefined reference link error */
+#if !defined(FFTW_HAS_FFTW3F_THREADS) || !defined(FFTW_HAS_FFTW3F_OMP)
+    int  fftwf_init_threads()          { return 0; }
+    void fftwf_plan_with_nthreads(int) {}
+    void fftwf_cleanup_threads()       {}
+#endif
+
+#if !defined(FFTW_HAS_FFTW3D_THREADS) || !defined(FFTW_HAS_FFTW3D_OMP)
+    int  fftw_init_threads()          { return 0; }
+    void fftw_plan_with_nthreads(int) {}
+    void fftw_cleanup_threads()       {}
+#endif
+
+#if !defined(FFTW_HAS_FFTW3L_THREADS) || !defined(FFTW_HAS_FFTW3L_OMP)
+    int  fftwl_init_threads()          { return 0; }
+    void fftwl_plan_with_nthreads(int) {}
+    void fftwl_cleanup_threads()       {}
+#endif
+
+#ifdef HAS_QUADMATHS
+    #if !defined(FFTW_HAS_FFTW3Q_THREADS) || !defined(FFTW_HAS_FFTW3Q_OMP)
+        int  fftwq_init_threads()          { return 0; }
+        void fftwq_plan_with_nthreads(int) {}
+        void fftwq_cleanup_threads()       {}
+    #endif
+#endif
diff --git a/HySoP/src/hysop++/src/fft/fftw3.h b/HySoP/src/hysop++/src/fft/fftw3.h
index f08bca38b..56c5c1eac 100644
--- a/HySoP/src/hysop++/src/fft/fftw3.h
+++ b/HySoP/src/hysop++/src/fft/fftw3.h
@@ -13,7 +13,6 @@
 /* fftw3 c++ wrapper based on original macros in <fftw3.h> */
 /*                                                         */
 
-
 /* macros normally already defined in <fftw3.h> */
 #ifndef FFTW_CONCAT
 #define FFTW_CONCAT(prefix, name) prefix ## name
@@ -36,384 +35,459 @@
 #define FFTW_MANGLE_CLASS(name)      FFTW_CONCAT(fftw_, name)
 
 /* macro used to generate a full template specialisation of class Fftw3 for each type */
-#define FFTW_DEFINE_CXX_API(X, Y, REAL)                                                                                                   \
-template <>                                                                                                                               \
-    struct Fftw3<REAL> {                                                                                                                  \
-        using R        = REAL;                                                                                                            \
-        using C        = Y(complex);                                                                                                      \
-        using plan     = Y(plan);                                                                                                         \
-        using iodim    = Y(iodim);                                                                                                        \
-        using iodim64  = Y(iodim64);                                                                                                      \
-        using r2r_kind = Y(r2r_kind);                                                                                                     \
-        using read_char_func  = Y(read_char_func);                                                                                        \
-        using write_char_func = Y(write_char_func);                                                                                       \
-        using stdC     = std::complex<REAL>;                                                                                              \
-                                                                                                                                          \
-        void X(execute)(const plan p) const {                                                                                             \
-            Y(execute)(p);                                                                                                                \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_dft)(int rank, const int *n,                                                                                          \
-                C *in, C *out, int sign, unsigned int flags) const {                                                                      \
-            return Y(plan_dft)(rank, n, in, out, sign, flags);                                                                            \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_dft_1d)(int n, C *in, C *out, int sign,                                                                               \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_dft_1d)(n, in, out, sign, flags);                                                                               \
-        }                                                                                                                                 \
-        plan X(plan_dft_2d)(int n0, int n1,                                                                                               \
-                C *in, C *out, int sign, unsigned int flags) const {                                                                      \
-            return Y(plan_dft_2d)(n0, n1, in, out, sign, flags);                                                                          \
-        }                                                                                                                                 \
-        plan X(plan_dft_3d)(int n0, int n1, int n2,                                                                                       \
-                C *in, C *out, int sign, unsigned int flags) const {                                                                      \
-            return Y(plan_dft_3d)(n0, n1, n2, in, out, sign, flags);                                                                      \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_many_dft)(int rank, const int *n,                                                                                     \
-                int howmany,                                                                                                              \
-                C *in, const int *inembed,                                                                                                \
-                int istride, int idist,                                                                                                   \
-                C *out, const int *onembed,                                                                                               \
-                int ostride, int odist,                                                                                                   \
-                int sign, unsigned int flags) const {                                                                                     \
-            return Y(plan_many_dft)(rank, n, howmany, in, inembed, istride, idist, out, onembed, ostride, odist, sign, flags);            \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_guru_dft)(int rank, const iodim *dims,                                                                                \
-                int howmany_rank,                                                                                                         \
-                const iodim *howmany_dims,                                                                                                \
-                C *in, C *out,                                                                                                            \
-                int sign, unsigned int flags) const {                                                                                     \
-            return Y(plan_guru_dft)(rank, dims, howmany_rank, howmany_dims, in, out, sign, flags);                                        \
-        }                                                                                                                                 \
-        plan X(plan_guru_split_dft)(int rank, const iodim *dims,                                                                          \
-                int howmany_rank,                                                                                                         \
-                const iodim *howmany_dims,                                                                                                \
-                R *ri, R *ii, R *ro, R *io,                                                                                               \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_guru_split_dft)(rank, dims, howmany_rank, howmany_dims, ri, ii, ro, io, flags);                                 \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_guru64_dft)(int rank,                                                                                                 \
-                const iodim64 *dims,                                                                                                      \
-                int howmany_rank,                                                                                                         \
-                const iodim64 *howmany_dims,                                                                                              \
-                C *in, C *out,                                                                                                            \
-                int sign, unsigned int flags) const {                                                                                     \
-            return Y(plan_guru64_dft)(rank, dims, howmany_rank, howmany_dims, in, out, sign, flags);                                      \
-        }                                                                                                                                 \
-        plan X(plan_guru64_split_dft)(int rank,                                                                                           \
-                const iodim64 *dims,                                                                                                      \
-                int howmany_rank,                                                                                                         \
-                const iodim64 *howmany_dims,                                                                                              \
-                R *ri, R *ii, R *ro, R *io,                                                                                               \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_guru64_split_dft)(rank, dims, howmany_rank, howmany_dims, ri, ii, ro, io, flags);                               \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        void X(execute_dft)(const plan p, C *in, C *out) const {                                                                          \
-            Y(execute_dft)(p, in, out);                                                                                                   \
-        }                                                                                                                                 \
-        void X(execute_split_dft)(const plan p, R *ri, R *ii, R *ro, R *io) const {                                                       \
-            Y(execute_split_dft)(p, ri, ii, ro, io);                                                                                      \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_many_dft_r2c)(int rank, const int *n,                                                                                 \
-                int howmany,                                                                                                              \
-                R *in, const int *inembed,                                                                                                \
-                int istride, int idist,                                                                                                   \
-                C *out, const int *onembed,                                                                                               \
-                int ostride, int odist,                                                                                                   \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_many_dft_r2c)(rank, n, howmany, in, inembed, istride, idist, out, onembed, ostride, odist, flags);              \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_dft_r2c)(int rank, const int *n,                                                                                      \
-                R *in, C *out, unsigned int flags) const {                                                                                \
-            return Y(plan_dft_r2c)(rank, n, in, out, flags);                                                                              \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_dft_r2c_1d)(int n,R *in,C *out,unsigned int flags) const {                                                            \
-            return Y(plan_dft_r2c_1d)(n,in,out,flags);                                                                                    \
-        }                                                                                                                                 \
-        plan X(plan_dft_r2c_2d)(int n0, int n1,                                                                                           \
-                R *in, C *out, unsigned int flags) const {                                                                                \
-            return Y(plan_dft_r2c_2d)(n0, n1, in, out, flags);                                                                            \
-        }                                                                                                                                 \
-        plan X(plan_dft_r2c_3d)(int n0, int n1,                                                                                           \
-                int n2,                                                                                                                   \
-                R *in, C *out, unsigned int flags) const {                                                                                \
-            return Y(plan_dft_r2c_3d)(n0, n1, n2, in, out, flags);                                                                        \
-        }                                                                                                                                 \
-                                                                                                                                          \
-                                                                                                                                          \
-        plan X(plan_many_dft_c2r)(int rank, const int *n,                                                                                 \
-                int howmany,                                                                                                              \
-                C *in, const int *inembed,                                                                                                \
-                int istride, int idist,                                                                                                   \
-                R *out, const int *onembed,                                                                                               \
-                int ostride, int odist,                                                                                                   \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_many_dft_c2r)(rank, n, howmany, in, inembed, istride, idist, out, onembed, ostride, odist, flags);              \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_dft_c2r)(int rank, const int *n,                                                                                      \
-                C *in, R *out, unsigned int flags) const {                                                                                \
-            return Y(plan_dft_c2r)(rank, n, in, out, flags);                                                                              \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_dft_c2r_1d)(int n,C *in,R *out,unsigned int flags) const {                                                            \
-            return Y(plan_dft_c2r_1d)(n,in,out,flags);                                                                                    \
-        }                                                                                                                                 \
-        plan X(plan_dft_c2r_2d)(int n0, int n1,                                                                                           \
-                C *in, R *out, unsigned int flags) const {                                                                                \
-            return Y(plan_dft_c2r_2d)(n0, n1, in, out, flags);                                                                            \
-        }                                                                                                                                 \
-        plan X(plan_dft_c2r_3d)(int n0, int n1,                                                                                           \
-                int n2,                                                                                                                   \
-                C *in, R *out, unsigned int flags) const {                                                                                \
-            return Y(plan_dft_c2r_3d)(n0, n1, n2, in, out, flags);                                                                        \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_guru_dft_r2c)(int rank, const iodim *dims,                                                                            \
-                int howmany_rank,                                                                                                         \
-                const iodim *howmany_dims,                                                                                                \
-                R *in, C *out,                                                                                                            \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_guru_dft_r2c)(rank, dims, howmany_rank, howmany_dims, in, out, flags);                                          \
-        }                                                                                                                                 \
-        plan X(plan_guru_dft_c2r)(int rank, const iodim *dims,                                                                            \
-                int howmany_rank,                                                                                                         \
-                const iodim *howmany_dims,                                                                                                \
-                C *in, R *out,                                                                                                            \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_guru_dft_c2r)(rank, dims, howmany_rank, howmany_dims, in, out, flags);                                          \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_guru_split_dft_r2c)(                                                                                                  \
-                int rank, const iodim *dims,                                                                                              \
-                int howmany_rank,                                                                                                         \
-                const iodim *howmany_dims,                                                                                                \
-                R *in, R *ro, R *io,                                                                                                      \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_guru_split_dft_r2c)( rank, dims, howmany_rank, howmany_dims, in, ro, io, flags);                                \
-        }                                                                                                                                 \
-        plan X(plan_guru_split_dft_c2r)(                                                                                                  \
-                int rank, const iodim *dims,                                                                                              \
-                int howmany_rank,                                                                                                         \
-                const iodim *howmany_dims,                                                                                                \
-                R *ri, R *ii, R *out,                                                                                                     \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_guru_split_dft_c2r)( rank, dims, howmany_rank, howmany_dims, ri, ii, out, flags);                               \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_guru64_dft_r2c)(int rank,                                                                                             \
-                const iodim64 *dims,                                                                                                      \
-                int howmany_rank,                                                                                                         \
-                const iodim64 *howmany_dims,                                                                                              \
-                R *in, C *out,                                                                                                            \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_guru64_dft_r2c)(rank, dims, howmany_rank, howmany_dims, in, out, flags);                                        \
-        }                                                                                                                                 \
-        plan X(plan_guru64_dft_c2r)(int rank,                                                                                             \
-                const iodim64 *dims,                                                                                                      \
-                int howmany_rank,                                                                                                         \
-                const iodim64 *howmany_dims,                                                                                              \
-                C *in, R *out,                                                                                                            \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_guru64_dft_c2r)(rank, dims, howmany_rank, howmany_dims, in, out, flags);                                        \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_guru64_split_dft_r2c)(                                                                                                \
-                int rank, const iodim64 *dims,                                                                                            \
-                int howmany_rank,                                                                                                         \
-                const iodim64 *howmany_dims,                                                                                              \
-                R *in, R *ro, R *io,                                                                                                      \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_guru64_split_dft_r2c)( rank, dims, howmany_rank, howmany_dims, in, ro, io, flags);                              \
-        }                                                                                                                                 \
-        plan X(plan_guru64_split_dft_c2r)(                                                                                                \
-                int rank, const iodim64 *dims,                                                                                            \
-                int howmany_rank,                                                                                                         \
-                const iodim64 *howmany_dims,                                                                                              \
-                R *ri, R *ii, R *out,                                                                                                     \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_guru64_split_dft_c2r)( rank, dims, howmany_rank, howmany_dims, ri, ii, out, flags);                             \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        void X(execute_dft_r2c)(const plan p, R *in, C *out) const {                                                                      \
-            Y(execute_dft_r2c)(p, in, out);                                                                                               \
-        }                                                                                                                                 \
-        void X(execute_dft_c2r)(const plan p, C *in, R *out) const {                                                                      \
-            Y(execute_dft_c2r)(p, in, out);                                                                                               \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        void X(execute_split_dft_r2c)(const plan p,                                                                                       \
-                R *in, R *ro, R *io) const {                                                                                              \
-            return Y(execute_split_dft_r2c)(p, in, ro, io);                                                                               \
-        }                                                                                                                                 \
-        void X(execute_split_dft_c2r)(const plan p,                                                                                       \
-                R *ri, R *ii, R *out) const {                                                                                             \
-            return Y(execute_split_dft_c2r)(p, ri, ii, out);                                                                              \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_many_r2r)(int rank, const int *n,                                                                                     \
-                int howmany,                                                                                                              \
-                R *in, const int *inembed,                                                                                                \
-                int istride, int idist,                                                                                                   \
-                R *out, const int *onembed,                                                                                               \
-                int ostride, int odist,                                                                                                   \
-                const r2r_kind *kind, unsigned int flags) const {                                                                         \
-            return Y(plan_many_r2r)(rank, n, howmany, in, inembed, istride, idist, out, onembed, ostride, odist, kind, flags);            \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_r2r)(int rank, const int *n, R *in, R *out,                                                                           \
-                const r2r_kind *kind, unsigned int flags) const {                                                                         \
-            return Y(plan_r2r)(rank, n, in, out, kind, flags);                                                                            \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_r2r_1d)(int n, R *in, R *out,                                                                                         \
-                r2r_kind kind, unsigned int flags) const {                                                                                \
-            return Y(plan_r2r_1d)(n, in, out, kind, flags);                                                                               \
-        }                                                                                                                                 \
-        plan X(plan_r2r_2d)(int n0, int n1, R *in, R *out,                                                                                \
-                r2r_kind kind0, r2r_kind kind1,                                                                                           \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_r2r_2d)(n0, n1, in, out, kind0, kind1, flags);                                                                  \
-        }                                                                                                                                 \
-        plan X(plan_r2r_3d)(int n0, int n1, int n2,                                                                                       \
-                R *in, R *out, r2r_kind kind0,                                                                                            \
-                r2r_kind kind1, r2r_kind kind2,                                                                                           \
-                unsigned int flags) const {                                                                                               \
-            return Y(plan_r2r_3d)(n0, n1, n2, in, out, kind0, kind1, kind2, flags);                                                       \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_guru_r2r)(int rank, const iodim *dims,                                                                                \
-                int howmany_rank,                                                                                                         \
-                const iodim *howmany_dims,                                                                                                \
-                R *in, R *out,                                                                                                            \
-                const r2r_kind *kind, unsigned int flags) const {                                                                         \
-            return Y(plan_guru_r2r)(rank, dims, howmany_rank, howmany_dims, in, out, kind, flags);                                        \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        plan X(plan_guru64_r2r)(int rank, const iodim64 *dims,                                                                            \
-                int howmany_rank,                                                                                                         \
-                const iodim64 *howmany_dims,                                                                                              \
-                R *in, R *out,                                                                                                            \
-                const r2r_kind *kind, unsigned int flags) const {                                                                         \
-            return Y(plan_guru64_r2r)(rank, dims, howmany_rank, howmany_dims, in, out, kind, flags);                                      \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        void X(execute_r2r)(const plan p, R *in, R *out) const {                                                                          \
-            Y(execute_r2r)(p, in, out);                                                                                                   \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        void X(destroy_plan)(plan p) const {                                                                                              \
-            Y(destroy_plan)(p);                                                                                                           \
-        }                                                                                                                                 \
-        void X(forget_wisdom)() const {                                                                                                   \
-            Y(forget_wisdom)();                                                                                                           \
-        }                                                                                                                                 \
-        void X(cleanup)() const {                                                                                                         \
-            Y(cleanup)();                                                                                                                 \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        void X(set_timelimit)(double t) const {                                                                                           \
-            Y(set_timelimit)(t);                                                                                                          \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        void X(plan_with_nthreads)(int nthreads) const {                                                                                  \
-            Y(plan_with_nthreads)(nthreads);                                                                                              \
-        }                                                                                                                                 \
-        int X(init_threads)() const {                                                                                                     \
-            return Y(init_threads)();                                                                                                     \
-        }                                                                                                                                 \
-        void X(cleanup_threads)() const {                                                                                                 \
-            Y(cleanup_threads)();                                                                                                         \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        int X(export_wisdom_to_filename)(const char *filename) const {                                                                    \
-            return Y(export_wisdom_to_filename)(filename);                                                                                \
-        }                                                                                                                                 \
-        void X(export_wisdom_to_file)(FILE *output_file) const {                                                                          \
-            Y(export_wisdom_to_file)(output_file);                                                                                        \
-        }                                                                                                                                 \
-        char *X(export_wisdom_to_string)() const {                                                                                        \
-            return Y(export_wisdom_to_string)();                                                                                          \
-        }                                                                                                                                 \
-        void X(export_wisdom)(write_char_func write_char,                                                                                 \
-                void *data) const {                                                                                                       \
-            return Y(export_wisdom)(write_char, data);                                                                                    \
-        }                                                                                                                                 \
-        int X(import_system_wisdom)() const {                                                                                             \
-            return Y(import_system_wisdom)();                                                                                             \
-        }                                                                                                                                 \
-        int X(import_wisdom_from_filename)(const char *filename) const {                                                                  \
-            return Y(import_wisdom_from_filename)(filename);                                                                              \
-        }                                                                                                                                 \
-        int X(import_wisdom_from_file)(FILE *input_file) const {                                                                          \
-            return Y(import_wisdom_from_file)(input_file);                                                                                \
-        }                                                                                                                                 \
-        int X(import_wisdom_from_string)(const char *input_string) const {                                                                \
-            return Y(import_wisdom_from_string)(input_string);                                                                            \
-        }                                                                                                                                 \
-        int X(import_wisdom)(read_char_func read_char, void *data) const {                                                                \
-            return Y(import_wisdom)(read_char, data);                                                                                     \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        void X(fprint_plan)(const plan p, FILE *output_file) const {                                                                      \
-            Y(fprint_plan)(p, output_file);                                                                                               \
-        }                                                                                                                                 \
-        void X(print_plan)(const plan p) const {                                                                                          \
-            Y(print_plan)(p);                                                                                                             \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        void *X(malloc)(size_t n) const {                                                                                                 \
-            return Y(malloc)(n);                                                                                                          \
-        }                                                                                                                                 \
-        R *X(alloc_real)(size_t n) const {                                                                                                \
-            return Y(alloc_real)(n);                                                                                                      \
-        }                                                                                                                                 \
-        C *X(alloc_complex)(size_t n) const {                                                                                             \
-            return Y(alloc_complex)(n);                                                                                                   \
-        }                                                                                                                                 \
-        void X(free)(void *p) const {                                                                                                     \
-            Y(free)(p);                                                                                                                   \
-        }                                                                                                                                 \
-                                                                                                                                          \
-        void X(flops)(const plan p,                                                                                                       \
-                double *add, double *mul, double *fmas) const {                                                                           \
-            return Y(flops)(p, add, mul, fmas);                                                                                           \
-        }                                                                                                                                 \
-        double X(estimate_cost)(const plan p) const {                                                                                     \
-            return Y(estimate_cost)(p);                                                                                                   \
-        }                                                                                                                                 \
-        double X(cost)(const plan p) const {                                                                                              \
-            return Y(cost)(p);                                                                                                            \
-        }                                                                                                                                 \
+#define FFTW_DEFINE_CXX_API(X, Y, REAL, has_thread_support)                                                                                   \
+template <>                                                                                                                                   \
+    struct Fftw3<REAL> {                                                                                                                      \
+        typedef REAL R;                                                                                                                       \
+        typedef Y(complex) C;                                                                                                                 \
+        typedef Y(plan) plan;                                                                                                                 \
+        typedef Y(iodim) iodim;                                                                                                               \
+        typedef Y(iodim64) iodim64;                                                                                                           \
+        typedef Y(r2r_kind) r2r_kind;                                                                                                         \
+        typedef Y(read_char_func) read_char_func;                                                                                             \
+        typedef Y(write_char_func) write_char_func;                                                                                           \
+        typedef std::complex<REAL> stdC;                                                                                                      \
+                                                                                                                                              \
+        void X(execute)(const plan p) const {                                                                                                 \
+            Y(execute)(p);                                                                                                                    \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_dft)(int rank, const int *n,                                                                                              \
+                C *in, C *out, int sign, unsigned int flags) const {                                                                          \
+            return Y(plan_dft)(rank, n, in, out, sign, flags);                                                                                \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_dft_1d)(int n, C *in, C *out, int sign,                                                                                   \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_dft_1d)(n, in, out, sign, flags);                                                                                   \
+        }                                                                                                                                     \
+        plan X(plan_dft_2d)(int n0, int n1,                                                                                                   \
+                C *in, C *out, int sign, unsigned int flags) const {                                                                          \
+            return Y(plan_dft_2d)(n0, n1, in, out, sign, flags);                                                                              \
+        }                                                                                                                                     \
+        plan X(plan_dft_3d)(int n0, int n1, int n2,                                                                                           \
+                C *in, C *out, int sign, unsigned int flags) const {                                                                          \
+            return Y(plan_dft_3d)(n0, n1, n2, in, out, sign, flags);                                                                          \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_many_dft)(int rank, const int *n,                                                                                         \
+                int howmany,                                                                                                                  \
+                C *in, const int *inembed,                                                                                                    \
+                int istride, int idist,                                                                                                       \
+                C *out, const int *onembed,                                                                                                   \
+                int ostride, int odist,                                                                                                       \
+                int sign, unsigned int flags) const {                                                                                         \
+            return Y(plan_many_dft)(rank, n, howmany, in, inembed, istride, idist, out, onembed, ostride, odist, sign, flags);                \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_guru_dft)(int rank, const iodim *dims,                                                                                    \
+                int howmany_rank,                                                                                                             \
+                const iodim *howmany_dims,                                                                                                    \
+                C *in, C *out,                                                                                                                \
+                int sign, unsigned int flags) const {                                                                                         \
+            return Y(plan_guru_dft)(rank, dims, howmany_rank, howmany_dims, in, out, sign, flags);                                            \
+        }                                                                                                                                     \
+        plan X(plan_guru_split_dft)(int rank, const iodim *dims,                                                                              \
+                int howmany_rank,                                                                                                             \
+                const iodim *howmany_dims,                                                                                                    \
+                R *ri, R *ii, R *ro, R *io,                                                                                                   \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_guru_split_dft)(rank, dims, howmany_rank, howmany_dims, ri, ii, ro, io, flags);                                     \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_guru64_dft)(int rank,                                                                                                     \
+                const iodim64 *dims,                                                                                                          \
+                int howmany_rank,                                                                                                             \
+                const iodim64 *howmany_dims,                                                                                                  \
+                C *in, C *out,                                                                                                                \
+                int sign, unsigned int flags) const {                                                                                         \
+            return Y(plan_guru64_dft)(rank, dims, howmany_rank, howmany_dims, in, out, sign, flags);                                          \
+        }                                                                                                                                     \
+        plan X(plan_guru64_split_dft)(int rank,                                                                                               \
+                const iodim64 *dims,                                                                                                          \
+                int howmany_rank,                                                                                                             \
+                const iodim64 *howmany_dims,                                                                                                  \
+                R *ri, R *ii, R *ro, R *io,                                                                                                   \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_guru64_split_dft)(rank, dims, howmany_rank, howmany_dims, ri, ii, ro, io, flags);                                   \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        void X(execute_dft)(const plan p, C *in, C *out) const {                                                                              \
+            Y(execute_dft)(p, in, out);                                                                                                       \
+        }                                                                                                                                     \
+        void X(execute_split_dft)(const plan p, R *ri, R *ii, R *ro, R *io) const {                                                           \
+            Y(execute_split_dft)(p, ri, ii, ro, io);                                                                                          \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_many_dft_r2c)(int rank, const int *n,                                                                                     \
+                int howmany,                                                                                                                  \
+                R *in, const int *inembed,                                                                                                    \
+                int istride, int idist,                                                                                                       \
+                C *out, const int *onembed,                                                                                                   \
+                int ostride, int odist,                                                                                                       \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_many_dft_r2c)(rank, n, howmany, in, inembed, istride, idist, out, onembed, ostride, odist, flags);                  \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_dft_r2c)(int rank, const int *n,                                                                                          \
+                R *in, C *out, unsigned int flags) const {                                                                                    \
+            return Y(plan_dft_r2c)(rank, n, in, out, flags);                                                                                  \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_dft_r2c_1d)(int n,R *in,C *out,unsigned int flags) const {                                                                \
+            return Y(plan_dft_r2c_1d)(n,in,out,flags);                                                                                        \
+        }                                                                                                                                     \
+        plan X(plan_dft_r2c_2d)(int n0, int n1,                                                                                               \
+                R *in, C *out, unsigned int flags) const {                                                                                    \
+            return Y(plan_dft_r2c_2d)(n0, n1, in, out, flags);                                                                                \
+        }                                                                                                                                     \
+        plan X(plan_dft_r2c_3d)(int n0, int n1,                                                                                               \
+                int n2,                                                                                                                       \
+                R *in, C *out, unsigned int flags) const {                                                                                    \
+            return Y(plan_dft_r2c_3d)(n0, n1, n2, in, out, flags);                                                                            \
+        }                                                                                                                                     \
+                                                                                                                                              \
+                                                                                                                                              \
+        plan X(plan_many_dft_c2r)(int rank, const int *n,                                                                                     \
+                int howmany,                                                                                                                  \
+                C *in, const int *inembed,                                                                                                    \
+                int istride, int idist,                                                                                                       \
+                R *out, const int *onembed,                                                                                                   \
+                int ostride, int odist,                                                                                                       \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_many_dft_c2r)(rank, n, howmany, in, inembed, istride, idist, out, onembed, ostride, odist, flags);                  \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_dft_c2r)(int rank, const int *n,                                                                                          \
+                C *in, R *out, unsigned int flags) const {                                                                                    \
+            return Y(plan_dft_c2r)(rank, n, in, out, flags);                                                                                  \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_dft_c2r_1d)(int n,C *in,R *out,unsigned int flags) const {                                                                \
+            return Y(plan_dft_c2r_1d)(n,in,out,flags);                                                                                        \
+        }                                                                                                                                     \
+        plan X(plan_dft_c2r_2d)(int n0, int n1,                                                                                               \
+                C *in, R *out, unsigned int flags) const {                                                                                    \
+            return Y(plan_dft_c2r_2d)(n0, n1, in, out, flags);                                                                                \
+        }                                                                                                                                     \
+        plan X(plan_dft_c2r_3d)(int n0, int n1,                                                                                               \
+                int n2,                                                                                                                       \
+                C *in, R *out, unsigned int flags) const {                                                                                    \
+            return Y(plan_dft_c2r_3d)(n0, n1, n2, in, out, flags);                                                                            \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_guru_dft_r2c)(int rank, const iodim *dims,                                                                                \
+                int howmany_rank,                                                                                                             \
+                const iodim *howmany_dims,                                                                                                    \
+                R *in, C *out,                                                                                                                \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_guru_dft_r2c)(rank, dims, howmany_rank, howmany_dims, in, out, flags);                                              \
+        }                                                                                                                                     \
+        plan X(plan_guru_dft_c2r)(int rank, const iodim *dims,                                                                                \
+                int howmany_rank,                                                                                                             \
+                const iodim *howmany_dims,                                                                                                    \
+                C *in, R *out,                                                                                                                \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_guru_dft_c2r)(rank, dims, howmany_rank, howmany_dims, in, out, flags);                                              \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_guru_split_dft_r2c)(                                                                                                      \
+                int rank, const iodim *dims,                                                                                                  \
+                int howmany_rank,                                                                                                             \
+                const iodim *howmany_dims,                                                                                                    \
+                R *in, R *ro, R *io,                                                                                                          \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_guru_split_dft_r2c)( rank, dims, howmany_rank, howmany_dims, in, ro, io, flags);                                    \
+        }                                                                                                                                     \
+        plan X(plan_guru_split_dft_c2r)(                                                                                                      \
+                int rank, const iodim *dims,                                                                                                  \
+                int howmany_rank,                                                                                                             \
+                const iodim *howmany_dims,                                                                                                    \
+                R *ri, R *ii, R *out,                                                                                                         \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_guru_split_dft_c2r)( rank, dims, howmany_rank, howmany_dims, ri, ii, out, flags);                                   \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_guru64_dft_r2c)(int rank,                                                                                                 \
+                const iodim64 *dims,                                                                                                          \
+                int howmany_rank,                                                                                                             \
+                const iodim64 *howmany_dims,                                                                                                  \
+                R *in, C *out,                                                                                                                \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_guru64_dft_r2c)(rank, dims, howmany_rank, howmany_dims, in, out, flags);                                            \
+        }                                                                                                                                     \
+        plan X(plan_guru64_dft_c2r)(int rank,                                                                                                 \
+                const iodim64 *dims,                                                                                                          \
+                int howmany_rank,                                                                                                             \
+                const iodim64 *howmany_dims,                                                                                                  \
+                C *in, R *out,                                                                                                                \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_guru64_dft_c2r)(rank, dims, howmany_rank, howmany_dims, in, out, flags);                                            \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_guru64_split_dft_r2c)(                                                                                                    \
+                int rank, const iodim64 *dims,                                                                                                \
+                int howmany_rank,                                                                                                             \
+                const iodim64 *howmany_dims,                                                                                                  \
+                R *in, R *ro, R *io,                                                                                                          \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_guru64_split_dft_r2c)( rank, dims, howmany_rank, howmany_dims, in, ro, io, flags);                                  \
+        }                                                                                                                                     \
+        plan X(plan_guru64_split_dft_c2r)(                                                                                                    \
+                int rank, const iodim64 *dims,                                                                                                \
+                int howmany_rank,                                                                                                             \
+                const iodim64 *howmany_dims,                                                                                                  \
+                R *ri, R *ii, R *out,                                                                                                         \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_guru64_split_dft_c2r)( rank, dims, howmany_rank, howmany_dims, ri, ii, out, flags);                                 \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        void X(execute_dft_r2c)(const plan p, R *in, C *out) const {                                                                          \
+            Y(execute_dft_r2c)(p, in, out);                                                                                                   \
+        }                                                                                                                                     \
+        void X(execute_dft_c2r)(const plan p, C *in, R *out) const {                                                                          \
+            Y(execute_dft_c2r)(p, in, out);                                                                                                   \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        void X(execute_split_dft_r2c)(const plan p,                                                                                           \
+                R *in, R *ro, R *io) const {                                                                                                  \
+            return Y(execute_split_dft_r2c)(p, in, ro, io);                                                                                   \
+        }                                                                                                                                     \
+        void X(execute_split_dft_c2r)(const plan p,                                                                                           \
+                R *ri, R *ii, R *out) const {                                                                                                 \
+            return Y(execute_split_dft_c2r)(p, ri, ii, out);                                                                                  \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_many_r2r)(int rank, const int *n,                                                                                         \
+                int howmany,                                                                                                                  \
+                R *in, const int *inembed,                                                                                                    \
+                int istride, int idist,                                                                                                       \
+                R *out, const int *onembed,                                                                                                   \
+                int ostride, int odist,                                                                                                       \
+                const r2r_kind *kind, unsigned int flags) const {                                                                             \
+            return Y(plan_many_r2r)(rank, n, howmany, in, inembed, istride, idist, out, onembed, ostride, odist, kind, flags);                \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_r2r)(int rank, const int *n, R *in, R *out,                                                                               \
+                const r2r_kind *kind, unsigned int flags) const {                                                                             \
+            return Y(plan_r2r)(rank, n, in, out, kind, flags);                                                                                \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_r2r_1d)(int n, R *in, R *out,                                                                                             \
+                r2r_kind kind, unsigned int flags) const {                                                                                    \
+            return Y(plan_r2r_1d)(n, in, out, kind, flags);                                                                                   \
+        }                                                                                                                                     \
+        plan X(plan_r2r_2d)(int n0, int n1, R *in, R *out,                                                                                    \
+                r2r_kind kind0, r2r_kind kind1,                                                                                               \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_r2r_2d)(n0, n1, in, out, kind0, kind1, flags);                                                                      \
+        }                                                                                                                                     \
+        plan X(plan_r2r_3d)(int n0, int n1, int n2,                                                                                           \
+                R *in, R *out, r2r_kind kind0,                                                                                                \
+                r2r_kind kind1, r2r_kind kind2,                                                                                               \
+                unsigned int flags) const {                                                                                                   \
+            return Y(plan_r2r_3d)(n0, n1, n2, in, out, kind0, kind1, kind2, flags);                                                           \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_guru_r2r)(int rank, const iodim *dims,                                                                                    \
+                int howmany_rank,                                                                                                             \
+                const iodim *howmany_dims,                                                                                                    \
+                R *in, R *out,                                                                                                                \
+                const r2r_kind *kind, unsigned int flags) const {                                                                             \
+            return Y(plan_guru_r2r)(rank, dims, howmany_rank, howmany_dims, in, out, kind, flags);                                            \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        plan X(plan_guru64_r2r)(int rank, const iodim64 *dims,                                                                                \
+                int howmany_rank,                                                                                                             \
+                const iodim64 *howmany_dims,                                                                                                  \
+                R *in, R *out,                                                                                                                \
+                const r2r_kind *kind, unsigned int flags) const {                                                                             \
+            return Y(plan_guru64_r2r)(rank, dims, howmany_rank, howmany_dims, in, out, kind, flags);                                          \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        void X(execute_r2r)(const plan p, R *in, R *out) const {                                                                              \
+            Y(execute_r2r)(p, in, out);                                                                                                       \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        void X(destroy_plan)(plan p) const {                                                                                                  \
+            Y(destroy_plan)(p);                                                                                                               \
+        }                                                                                                                                     \
+        void X(forget_wisdom)() const {                                                                                                       \
+            Y(forget_wisdom)();                                                                                                               \
+        }                                                                                                                                     \
+        void X(cleanup)() const {                                                                                                             \
+            Y(cleanup)();                                                                                                                     \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        void X(set_timelimit)(double t) const {                                                                                               \
+            Y(set_timelimit)(t);                                                                                                              \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        template <typename T = void>                                                                                                          \
+        typename std::enable_if<has_thread_support, T>::type                                                                                  \
+        X(plan_with_nthreads)(int nthreads) const {                                                                                           \
+            Y(plan_with_nthreads)(nthreads);                                                                                                  \
+        }                                                                                                                                     \
+        template <typename T = int>                                                                                                           \
+        typename std::enable_if<has_thread_support, T>::type                                                                                  \
+        X(init_threads)() const {                                                                                                             \
+            return Y(init_threads)();                                                                                                         \
+        }                                                                                                                                     \
+        template <typename T=void>                                                                                                            \
+        typename std::enable_if<has_thread_support, T>::type                                                                                  \
+        X(cleanup_threads)() const {                                                                                                          \
+            Y(cleanup_threads)();                                                                                                             \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        int X(export_wisdom_to_filename)(const char *filename) const {                                                                        \
+            return Y(export_wisdom_to_filename)(filename);                                                                                    \
+        }                                                                                                                                     \
+        void X(export_wisdom_to_file)(FILE *output_file) const {                                                                              \
+            Y(export_wisdom_to_file)(output_file);                                                                                            \
+        }                                                                                                                                     \
+        char *X(export_wisdom_to_string)() const {                                                                                            \
+            return Y(export_wisdom_to_string)();                                                                                              \
+        }                                                                                                                                     \
+        void X(export_wisdom)(write_char_func write_char,                                                                                     \
+                void *data) const {                                                                                                           \
+            return Y(export_wisdom)(write_char, data);                                                                                        \
+        }                                                                                                                                     \
+        int X(import_system_wisdom)() const {                                                                                                 \
+            return Y(import_system_wisdom)();                                                                                                 \
+        }                                                                                                                                     \
+        int X(import_wisdom_from_filename)(const char *filename) const {                                                                      \
+            return Y(import_wisdom_from_filename)(filename);                                                                                  \
+        }                                                                                                                                     \
+        int X(import_wisdom_from_file)(FILE *input_file) const {                                                                              \
+            return Y(import_wisdom_from_file)(input_file);                                                                                    \
+        }                                                                                                                                     \
+        int X(import_wisdom_from_string)(const char *input_string) const {                                                                    \
+            return Y(import_wisdom_from_string)(input_string);                                                                                \
+        }                                                                                                                                     \
+        int X(import_wisdom)(read_char_func read_char, void *data) const {                                                                    \
+            return Y(import_wisdom)(read_char, data);                                                                                         \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        void X(fprint_plan)(const plan p, FILE *output_file) const {                                                                          \
+            Y(fprint_plan)(p, output_file);                                                                                                   \
+        }                                                                                                                                     \
+        void X(print_plan)(const plan p) const {                                                                                              \
+            Y(print_plan)(p);                                                                                                                 \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        void *X(malloc)(size_t n) const {                                                                                                     \
+            return Y(malloc)(n);                                                                                                              \
+        }                                                                                                                                     \
+        R *X(alloc_real)(size_t n) const {                                                                                                    \
+            return Y(alloc_real)(n);                                                                                                          \
+        }                                                                                                                                     \
+        C *X(alloc_complex)(size_t n) const {                                                                                                 \
+            return Y(alloc_complex)(n);                                                                                                       \
+        }                                                                                                                                     \
+        void X(free)(void *p) const {                                                                                                         \
+            Y(free)(p);                                                                                                                       \
+        }                                                                                                                                     \
+                                                                                                                                              \
+        void X(flops)(const plan p,                                                                                                           \
+                double *add, double *mul, double *fmas) const {                                                                               \
+            return Y(flops)(p, add, mul, fmas);                                                                                               \
+        }                                                                                                                                     \
+        double X(estimate_cost)(const plan p) const {                                                                                         \
+            return Y(estimate_cost)(p);                                                                                                       \
+        }                                                                                                                                     \
+        double X(cost)(const plan p) const {                                                                                                  \
+            return Y(cost)(p);                                                                                                                \
+        }                                                                                                                                     \
     };
 
 
+/* Constants */
 namespace hysop {
     namespace fft {
+        /* float */
+        #ifdef FFTW_HAS_FFTW3F
+            static constexpr bool fftw_has_float_support = true;
+            #ifdef FFTW_HAS_FFTW3F_MPI
+                static constexpr bool fftw_has_float_mpi_support = true;
+            #else 
+                static constexpr bool fftw_has_float_mpi_support = false;
+            #endif
+            #if defined(FFTW_HAS_FFTW3F_THREADS) || defined(FFTW_HAS_FFTW3F_OMP)
+                static constexpr bool fftw_has_float_thread_support = true;
+            #else
+                static constexpr bool fftw_has_float_thread_support = false;
+            #endif 
+        #else
+            static constexpr bool fftw_has_float_support        = false;
+            static constexpr bool fftw_has_float_thread_support = false;
+            static constexpr bool fftw_has_float_mpi_support    = false;
+        #endif
 
-        template <typename T> struct is_fftw_supported_type    { static constexpr bool value = false; };
-        template <> struct is_fftw_supported_type<float>       { static constexpr bool value = true;  };
-        template <> struct is_fftw_supported_type<double>      { static constexpr bool value = true;  };
-        template <> struct is_fftw_supported_type<long double> { static constexpr bool value = true;  };
+        /* double */
+        #ifdef FFTW_HAS_FFTW3D
+            static constexpr bool fftw_has_double_support = true;
+            #ifdef FFTW_HAS_FFTW3D_MPI
+                static constexpr bool fftw_has_double_mpi_support = true;
+            #else 
+                static constexpr bool fftw_has_double_mpi_support = false;
+            #endif
+            #if defined(FFTW_HAS_FFTW3D_THREADS) || defined(FFTW_HAS_FFTW3D_OMP)
+                static constexpr bool fftw_has_double_thread_support = true;
+            #else
+                static constexpr bool fftw_has_double_thread_support = false;
+            #endif 
+        #else
+            static constexpr bool fftw_has_double_support        = false;
+            static constexpr bool fftw_has_double_thread_support = false;
+            static constexpr bool fftw_has_double_mpi_support    = false;
+        #endif
         
-        template <typename T> struct is_fftw_supported_complex_type    { static constexpr bool value = false; };
-        template <> struct is_fftw_supported_complex_type<std::complex<float>>       { static constexpr bool value = true;  };
-        template <> struct is_fftw_supported_complex_type<std::complex<double>>      { static constexpr bool value = true;  };
-        template <> struct is_fftw_supported_complex_type<std::complex<long double>> { static constexpr bool value = true;  };
-        template <> struct is_fftw_supported_complex_type<fftwf_complex>             { static constexpr bool value = true;  };
-        template <> struct is_fftw_supported_complex_type<fftw_complex>              { static constexpr bool value = true;  };
-        template <> struct is_fftw_supported_complex_type<fftwl_complex>             { static constexpr bool value = true;  };
+        /* long double */
+        #ifdef FFTW_HAS_FFTW3L
+            static constexpr bool fftw_has_long_double_support = true;
+            #ifdef FFTW_HAS_FFTW3L_MPI
+                static constexpr bool fftw_has_long_double_mpi_support = true;
+            #else 
+                static constexpr bool fftw_has_long_double_mpi_support = false;
+            #endif
+            #if defined(FFTW_HAS_FFTW3L_THREADS) || defined(FFTW_HAS_FFTW3L_OMP)
+                static constexpr bool fftw_has_long_double_thread_support = true;
+            #else
+                static constexpr bool fftw_has_long_double_thread_support = false;
+            #endif 
+        #else
+            static constexpr bool fftw_has_long_double_support        = false;
+            static constexpr bool fftw_has_long_double_thread_support = false;
+            static constexpr bool fftw_has_long_double_mpi_support    = false;
+        #endif
+        
+        /* __float128  */
+        #ifdef FFTW_HAS_FFTW3Q
+            static constexpr bool fftw_has_quad_float_support = true;
+            #ifdef FFTW_HAS_FFTW3Q_MPI
+                static constexpr bool fftw_has_quad_float_mpi_support = true;
+            #else 
+                static constexpr bool fftw_has_quad_float_mpi_support = false;
+            #endif
+            #if defined(FFTW_HAS_FFTW3Q_THREADS) || defined(FFTW_HAS_FFTW3Q_OMP)
+                static constexpr bool fftw_has_quad_float_thread_support = true;
+            #else
+                static constexpr bool fftw_has_quad_float_thread_support = false;
+            #endif 
+        #else
+            static constexpr bool fftw_has_quad_float_support        = false;
+            static constexpr bool fftw_has_quad_float_thread_support = false;
+            static constexpr bool fftw_has_quad_float_mpi_support    = false;
+        #endif
+    }
+}
+
+/* Wrappers */
+namespace hysop {
+    namespace fft {
 
         template <typename T>
-            struct Fftw3 {
+        struct Fftw3 {
                 Fftw3() { 
                     throw std::runtime_error(
                             "Can only use Fftw3 wrapper with types {float, double, long double, __float128} ! "
@@ -421,18 +495,33 @@ namespace hysop {
                             );
                 }
             };
-       
+        template <typename T> struct is_fftw_supported_type          { static constexpr bool value = false; };
+        template <typename T> struct is_fftw_supported_complex_type  { static constexpr bool value = false; };
+        
+        
         /* Generate Ffftw<> template specialisations */
-        FFTW_DEFINE_CXX_API(FFTW_MANGLE_CLASS, FFTW_MANGLE_FLOAT, float)
-        FFTW_DEFINE_CXX_API(FFTW_MANGLE_CLASS, FFTW_MANGLE_DOUBLE, double)
-        FFTW_DEFINE_CXX_API(FFTW_MANGLE_CLASS, FFTW_MANGLE_LONG_DOUBLE, long double)
+        FFTW_DEFINE_CXX_API(FFTW_MANGLE_CLASS, FFTW_MANGLE_FLOAT, float, hysop::fft::fftw_has_float_thread_support)
+        FFTW_DEFINE_CXX_API(FFTW_MANGLE_CLASS, FFTW_MANGLE_DOUBLE, double, hysop::fft::fftw_has_double_thread_support)
+        FFTW_DEFINE_CXX_API(FFTW_MANGLE_CLASS, FFTW_MANGLE_LONG_DOUBLE, long double, hysop::fft::fftw_has_long_double_thread_support)
+
+        template <> struct is_fftw_supported_type<float>       { static constexpr bool value = true;  };
+        template <> struct is_fftw_supported_type<double>      { static constexpr bool value = true;  };
+        template <> struct is_fftw_supported_type<long double> { static constexpr bool value = true;  };
+        
+        template <> struct is_fftw_supported_complex_type<std::complex<float>>       { static constexpr bool value = true;  };
+        template <> struct is_fftw_supported_complex_type<std::complex<double>>      { static constexpr bool value = true;  };
+        template <> struct is_fftw_supported_complex_type<std::complex<long double>> { static constexpr bool value = true;  };
+        template <> struct is_fftw_supported_complex_type<fftwf_complex>             { static constexpr bool value = true;  };
+        template <> struct is_fftw_supported_complex_type<fftw_complex>              { static constexpr bool value = true;  };
+        template <> struct is_fftw_supported_complex_type<fftwl_complex>             { static constexpr bool value = true;  };
 
 #ifdef HAS_QUADMATHS
+        FFTW_DEFINE_CXX_API(FFTW_MANGLE_CLASS, FFTW_MANGLE_QUAD, __float128, hysop::fft::fftw_has_quad_float_thread_support)
         template <> struct is_fftw_supported_type<__float128>                        { static constexpr bool value = true;  };
         template <> struct is_fftw_supported_complex_type<std::complex<__float128>>  { static constexpr bool value = true;  };
         template <> struct is_fftw_supported_complex_type<fftwq_complex>             { static constexpr bool value = true;  };
-        FFTW_DEFINE_CXX_API(FFTW_MANGLE_CLASS, FFTW_MANGLE_QUAD, __float128)
 #endif
+
         
     }
 }
diff --git a/HySoP/src/hysop++/src/fft/planner.h b/HySoP/src/hysop++/src/fft/planner.h
index f9b5f9e0e..75b8ca852 100644
--- a/HySoP/src/hysop++/src/fft/planner.h
+++ b/HySoP/src/hysop++/src/fft/planner.h
@@ -148,7 +148,7 @@ namespace hysop {
         template <typename T, std::size_t Dim>
             void Planner<T,Dim>::reset() {
                 new (&m_realBuffer) multi_array_ref<T,Dim>();
-                m_complexBuffer.reshape(Shape<Dim>{0});
+                m_complexBuffer.reshape(typename Shape<Dim>::type{0});
                 for(fftw_plan plan : m_forward_R2R_plans)
                     this->fftw_destroy_plan(plan);
                 for(fftw_plan plan : m_backward_R2R_plans)
@@ -208,7 +208,7 @@ namespace hysop {
                 m_mirrorOutputPeriodicBoundaries = includeOutputPeriodicBoundaries && mirrorOutputPeriodicBoundaries;
                 
                 TransformArray forwardTransforms, backwardTransforms;
-                Shape<Dim>  realBufferShape, complexBufferShape;
+                typename Shape<Dim>::type  realBufferShape, complexBufferShape;
                 std::array<int,Dim> forward_transform_size, backward_transform_size, complex_transform_size;
                 std::array<int,Dim> forward_input_offset,  forward_output_offset;
                 std::array<int,Dim> backward_input_offset, backward_output_offset;
@@ -268,10 +268,10 @@ namespace hysop {
                     else {
                         if(tr.isR2R()) {
                             hasRealTransforms = true;
-                            const std::size_t firstExtOdd   = (inputExtensions.first  == ODD);
-                            const std::size_t secondExtOdd  = (inputExtensions.second == ODD);
-                            const std::size_t firstExtEven  = (inputExtensions.first  == EVEN);
-                            const std::size_t secondExtEven = (inputExtensions.second == EVEN);
+                            const std::size_t firstExtOdd   = (inputExtensions.first  == Extension::ODD);
+                            const std::size_t secondExtOdd  = (inputExtensions.second == Extension::ODD);
+                            const std::size_t firstExtEven  = (inputExtensions.first  == Extension::EVEN);
+                            const std::size_t secondExtEven = (inputExtensions.second == Extension::EVEN);
 
                             forward_transform_size[d]  -= (firstExtOdd + secondExtOdd);
                             forward_input_offset[d]   = std::ptrdiff_t(firstExtOdd);
@@ -602,7 +602,7 @@ namespace hysop {
                     this->fftw_execute(*plan);
     
                 if(m_mirrorOutputPeriodicBoundaries) {
-                    const Shape<Dim> rshape = m_realBuffer.shape();
+                    const typename Shape<Dim>::type rshape = m_realBuffer.shape();
                     T *data = m_realBuffer.rdata();
                     for(const int axe : m_periodicAxes) {
                         const int N = rshape[axe];
@@ -678,14 +678,14 @@ namespace hysop {
 
         template <typename T, std::size_t Dim>
             fft::Transform Planner<T,Dim>::findTransform(const std::pair<Extension,Extension>& ed) const {
-                if(ed.first == EVEN) {
-                    if(ed.second == EVEN)
+                if(ed.first == Extension::EVEN) {
+                    if(ed.second == Extension::EVEN)
                         return fft::Transform(FFTW_REDFT00);
                     else
                         return fft::Transform(FFTW_REDFT01);
                 }
-                else if(ed.first == ODD) {
-                    if(ed.second == EVEN)
+                else if(ed.first == Extension::ODD) {
+                    if(ed.second == Extension::EVEN)
                         return fft::Transform(FFTW_RODFT01);
                     else
                         return fft::Transform(FFTW_RODFT00);
diff --git a/HySoP/src/hysop++/src/maths/quad_maths.h b/HySoP/src/hysop++/src/maths/quad_maths.h
index a411d8041..97ae1fe0b 100644
--- a/HySoP/src/hysop++/src/maths/quad_maths.h
+++ b/HySoP/src/hysop++/src/maths/quad_maths.h
@@ -179,15 +179,15 @@ namespace std {
         __complex128 X{x.real(),x.imag()};
         return cabsq(X);
     }
-    inline __float128 carg(std::complex<__float128> x) { 
+    inline __float128 arg(std::complex<__float128> x) {
         __complex128 X{x.real(),x.imag()};
         return cargq(X);
     }
-    inline __float128 cimag(std::complex<__float128> x) { 
+    inline __float128 imag(std::complex<__float128> x) { 
         __complex128 X{x.real(),x.imag()};
         return cimagq(X);
     }
-    inline __float128 creal(std::complex<__float128> x) { 
+    inline __float128 real(std::complex<__float128> x) { 
         __complex128 X{x.real(),x.imag()};
         return crealq(X);
     }
@@ -288,7 +288,7 @@ namespace std {
     }
 
     inline std::complex< __float128 > pow(std::complex< __float128> x , __float128 y) {
-        __float128 R = powq(abs(x), y);
+        __float128 R = powq(std::abs(x), y);
         __float128 phi = atanq(x.imag()/x.real());
         return std::complex<__float128 >(R*cosq(y*phi), R*sinq(y*phi));
     }
diff --git a/HySoP/src/hysop++/src/utils/types.h b/HySoP/src/hysop++/src/utils/types.h
index 58dcdbc28..ccbd3c345 100644
--- a/HySoP/src/hysop++/src/utils/types.h
+++ b/HySoP/src/hysop++/src/utils/types.h
@@ -31,14 +31,18 @@ namespace hysop {
     } /* end of namespace types */
     
     
-    /* expose those types to namespace hysop */
-    template <std::size_t Dim>
-    using Shape = std::array<std::size_t, Dim>;
+/* expose the folowwing types to namespace hysop */
+
+/* swig does not support alias templates... */
+    template <std::size_t Dim> 
+        struct Shape { 
+            typedef std::array<std::size_t, Dim> type; 
+        };
+    template <std::size_t Dim> 
+        struct Offset { 
+            typedef std::array<std::ptrdiff_t, Dim> type; 
+        };
     
-    template <std::size_t Dim>
-    using Offset = std::array<std::ptrdiff_t, Dim>;
-
-
     template <typename T, std::size_t Dim, typename Allocator = hysop::_default::allocator<T>>
     using multi_array = hysop::data::multi_array<T,Dim,Allocator>;
 
diff --git a/HySoP/src/hysop++/tests/testDiffSolver/testDiffSolver.cpp b/HySoP/src/hysop++/tests/testDiffSolver/testDiffSolver.cpp
index 9144b1fdc..55fec62f5 100644
--- a/HySoP/src/hysop++/tests/testDiffSolver/testDiffSolver.cpp
+++ b/HySoP/src/hysop++/tests/testDiffSolver/testDiffSolver.cpp
@@ -70,7 +70,7 @@ std::function<T(T)> derivative(std::size_t k, int order) {
     
 template <typename T, std::size_t Dim, bool verbose=false> 
 void test(std::size_t p_maxOrder, bool includePeriodicBds=false) {
-    Shape<Dim> shape;
+    typename Shape<Dim>::type shape;
     typename Domain<T,Dim>::DomainSize domainSize;
     Domain<T,Dim> ref, inBuffer, outBuffer;
 
@@ -89,7 +89,7 @@ void test(std::size_t p_maxOrder, bool includePeriodicBds=false) {
     in  = ref;
     out = ref;
    
-    Shape<Dim> maxOrder, testCases;
+    typename Shape<Dim>::type maxOrder, testCases;
     maxOrder.fill(p_maxOrder+1);
     testCases.fill(nExtensionsPair);
     Index<Dim> orderId(maxOrder);
diff --git a/HySoP/src/hysop++/tests/testPlanner/testPlanner.cpp b/HySoP/src/hysop++/tests/testPlanner/testPlanner.cpp
index 09311df6a..aab308e98 100644
--- a/HySoP/src/hysop++/tests/testPlanner/testPlanner.cpp
+++ b/HySoP/src/hysop++/tests/testPlanner/testPlanner.cpp
@@ -78,7 +78,7 @@ TEST_F(PlannerTest, InplaceQuadDoubleTransforms) {
 
 template <typename T, std::size_t Dim, bool verbose> 
 void test(bool inplace, bool includePeriodicBds) {
-    Shape<Dim> shape;
+    typename Shape<Dim>::type shape;
     typename Domain<T,Dim>::DomainSize domainSize;
     Domain<T,Dim> ref, inBuffer, outBuffer;
 
@@ -101,7 +101,7 @@ void test(bool inplace, bool includePeriodicBds) {
     in  = ref;
     out = ref;
    
-    Shape<Dim> testCases;
+    typename Shape<Dim>::type testCases;
     testCases.fill(nExtensionsPair);
     Index<Dim> testCaseId(testCases);
     std::array<T,3> meanDists{0};
diff --git a/HySoP/src/hysop++/tests/testPoissonSolver/testPoissonSolver.cpp b/HySoP/src/hysop++/tests/testPoissonSolver/testPoissonSolver.cpp
index 9711a4cba..58d87d544 100644
--- a/HySoP/src/hysop++/tests/testPoissonSolver/testPoissonSolver.cpp
+++ b/HySoP/src/hysop++/tests/testPoissonSolver/testPoissonSolver.cpp
@@ -47,7 +47,7 @@ std::function<T(T)> func(std::size_t k) {
 
 template <typename T, std::size_t Dim, bool verbose=false> 
 void test(bool includePeriodicBds=false) {
-    Shape<Dim> shape;
+    typename Shape<Dim>::type shape;
     typename Domain<T,Dim>::DomainSize domainSize;
     Domain<T,Dim> ref, inBuffer, outBuffer;
 
@@ -64,7 +64,7 @@ void test(bool includePeriodicBds=false) {
     in  = ref;
     out = ref;
    
-    Shape<Dim> testCases;
+    typename Shape<Dim>::type testCases;
     testCases.fill(nBoundaryPairs);
     Index<Dim> testCaseId(testCases);
     std::array<T,3> meanDists{0};
diff --git a/HySoP/src/hysop++/tests/testPolynoms/testPolynoms.cpp b/HySoP/src/hysop++/tests/testPolynoms/testPolynoms.cpp
index e4001fa85..0849af6a4 100644
--- a/HySoP/src/hysop++/tests/testPolynoms/testPolynoms.cpp
+++ b/HySoP/src/hysop++/tests/testPolynoms/testPolynoms.cpp
@@ -76,7 +76,7 @@ void evalTest(const std::size_t p_size, const std::size_t p_samples) {
     Polynomial<T,Dim> P;
     Index<Dim> polyIdx;
     { 
-        Shape<Dim> polyShape;
+        typename Shape<Dim>::type polyShape;
         polyShape.fill(p_size);
         P.reshape(polyShape).applyToCoefficients([](T& ak, const Index<Dim>& idx){ 
                 ak = T(idx())/T(idx.maxId());
@@ -91,7 +91,7 @@ void evalTest(const std::size_t p_size, const std::size_t p_samples) {
         dX = (b-a)/(p_samples-1);   
     }
     
-    Shape<Dim> sampleShape;
+    typename Shape<Dim>::type sampleShape;
     sampleShape.fill(p_samples);
     Index<Dim> sampleIdx(sampleShape);
     while(!sampleIdx.atMaxId()) {
diff --git a/HySoP/swig/constants.i b/HySoP/swig/constants.i
deleted file mode 100644
index 929176357..000000000
--- a/HySoP/swig/constants.i
+++ /dev/null
@@ -1,7 +0,0 @@
-
-// -*- C++ -*-
-%{
-  #include "utils/constants.h"
-%}
-
-%include "utils/constants.h"
diff --git a/HySoP/swig/cpp2hysop.i b/HySoP/swig/cpp2hysop.i
index abc7b82a9..4a2ead8af 100644
--- a/HySoP/swig/cpp2hysop.i
+++ b/HySoP/swig/cpp2hysop.i
@@ -3,7 +3,6 @@
 
 %include start.i
 
-%include constants.i
-
-%include fftw.i
+%include fftw/fftw.i
+%include hysop++/hysop++.i
 
diff --git a/HySoP/swig/fftw.i b/HySoP/swig/fftw/fftw.i
similarity index 62%
rename from HySoP/swig/fftw.i
rename to HySoP/swig/fftw/fftw.i
index 912c3b467..28ab6fe64 100644
--- a/HySoP/swig/fftw.i
+++ b/HySoP/swig/fftw/fftw.i
@@ -1,6 +1,7 @@
+
 // -*- C++ -*-
 %{
-  #include "fftw.hpp"
+    #include "fftw.hpp"
 %}
 
 %include "fftw.hpp"
diff --git a/HySoP/swig/hysop++/domain.i b/HySoP/swig/hysop++/domain.i
new file mode 100644
index 000000000..8e996563f
--- /dev/null
+++ b/HySoP/swig/hysop++/domain.i
@@ -0,0 +1,38 @@
+%module domain
+
+// -*- C++ -*-
+%{
+  #include "domain/boundary.h"
+  #include "domain/domainConfiguration.h"
+%}
+
+/* domain boundary */
+%ignore hysop::domain::operator<<;
+%include "domain/boundary.h"
+
+
+/* domain configuration */
+%ignore hysop::domain::operator<<;
+%ignore hysop::domain::DomainConfiguration::operator[];
+%include "domain/domainConfiguration.h"
+
+%define INSTANTIATE_DOMAIN_CONFIG_IMPL(CLASS_NAME,CLASS_TEMPLATE) 
+    %template(CLASS_NAME) CLASS_TEMPLATE; 
+    %extend CLASS_TEMPLATE {
+        CLASS_TEMPLATE::BoundaryPair __get_item__(unsigned int k) const {
+            return $self->operator[](k);
+        }
+        const char* __str__() const {
+            std::stringstream ss;
+            ss << *($self);
+            return ss.str().c_str(); 
+        }
+    }
+%enddef
+
+%define INSTANTIATE_DOMAIN_CONFIG(INT) 
+    INSTANTIATE_DOMAIN_CONFIG_IMPL(DomainConfiguration ## INT ## D, hysop::domain::DomainConfiguration<INT>)
+%enddef
+
+%formacro(INSTANTIATE_DOMAIN_CONFIG, INSTANTIATED_DIMENSIONS)
+
diff --git a/HySoP/swig/hysop++/fft.i b/HySoP/swig/hysop++/fft.i
new file mode 100644
index 000000000..accd97cd9
--- /dev/null
+++ b/HySoP/swig/hysop++/fft.i
@@ -0,0 +1,91 @@
+
+%module fft
+
+// -*- C++ -*-
+%{
+  #include "fftw3.h"
+  #include "fft/fftw3.h"
+  #include "fft/extension.h"
+  #include "fft/transform.h"
+  #include "fft/fftDomainConfiguration.h"
+%}
+
+/* fftw3.h */
+#if !defined(FFTW_HAS_FFTW3F_THREADS) || !defined(FFTW_HAS_FFTW3F_OMP)
+    %ignore fftwf_init_threads();
+    %ignore fftwf_plan_with_nthreads(int);
+    %ignore fftwf_cleanup_threads();
+#endif
+
+#if !defined(FFTW_HAS_FFTW3D_THREADS) || !defined(FFTW_HAS_FFTW3D_OMP)
+    %ignore fftw_init_threads();
+    %ignore fftw_plan_with_nthreads(int);
+    %ignore fftw_cleanup_threads();
+#endif
+
+#if !defined(FFTW_HAS_FFTW3L_THREADS) || !defined(FFTW_HAS_FFTW3L_OMP)
+    %ignore fftwl_init_threads();
+    %ignore fftwl_plan_with_nthreads(int);
+    %ignore fftwl_cleanup_threads();
+#endif
+
+#ifdef HAS_QUADMATHS
+    #if !defined(FFTW_HAS_FFTW3Q_THREADS) || !defined(FFTW_HAS_FFTW3Q_OMP)
+        %ignore fftwq_init_threads();
+        %ignore fftwq_plan_with_nthreads(int);
+        %ignore fftwq_cleanup_threads();
+    #endif
+#endif
+%rename(is_) fftw_iodim_do_not_use_me::is;
+%rename(is_) fftw_iodim64_do_not_use_me::is;
+%include "fftw3.h"
+
+
+/* fftw3 c++ wrappers */
+%include "fft/fftw3.h"
+%template(Fftw3f) hysop::fft::Fftw3<float>;
+%template(Fftw3d) hysop::fft::Fftw3<double>;
+%template(Fftw3l) hysop::fft::Fftw3<long double>;
+%template(Fftw3q) hysop::fft::Fftw3<__float128>;
+
+
+/* fft transforms */
+%ignore hysop::fft::operator<<;
+%include "fft/transform.h"
+%extend hysop::fft::Transform {
+    const char* __str__() const { 
+        return $self->toString().c_str(); 
+    }
+}
+
+
+/* fft extensions */
+%ignore hysop::fft::operator<<;
+%include "fft/extension.h"
+
+
+/* fft domain configuration */
+%ignore hysop::fft::operator<<;
+%ignore hysop::fft::FftDomainConfiguration::operator[];
+%include "fft/fftDomainConfiguration.h"
+
+%define INSTANTIATE_FFT_DOMAIN_CONFIG_IMPL(CLASS_NAME,CLASS_TEMPLATE...) 
+    %template(CLASS_NAME) CLASS_TEMPLATE; 
+    %extend CLASS_TEMPLATE {
+        CLASS_TEMPLATE::ExtensionPair __get_item__(unsigned int k) const {
+            return $self->operator[](k);
+        }
+        const char* __str__() const {
+            std::stringstream ss;
+            ss << *($self);
+            return ss.str().c_str();
+        }
+    }
+%enddef
+
+%define INSTANTIATE_FFT_DOMAIN_CONFIG(INT) 
+    INSTANTIATE_FFT_DOMAIN_CONFIG_IMPL(FftDomainConfiguration ## INT ## D, hysop::fft::FftDomainConfiguration<INT>)
+%enddef
+
+%formacro(INSTANTIATE_FFT_DOMAIN_CONFIG, INSTANTIATED_DIMENSIONS)
+
diff --git a/HySoP/swig/hysop++/hysop++.i b/HySoP/swig/hysop++/hysop++.i
new file mode 100644
index 000000000..a681efa69
--- /dev/null
+++ b/HySoP/swig/hysop++/hysop++.i
@@ -0,0 +1,5 @@
+
+/* hysop++ */
+%include "utils.i"
+%include "domain.i"
+%include "fft.i"
diff --git a/HySoP/swig/hysop++/utils.i b/HySoP/swig/hysop++/utils.i
new file mode 100644
index 000000000..541179ea9
--- /dev/null
+++ b/HySoP/swig/hysop++/utils.i
@@ -0,0 +1,29 @@
+
+%module utils
+
+// -*- C++ -*-
+%{
+  #include "utils/types.h"
+  #include "utils/constants.h"
+%}
+
+/* types */
+%warnfilter(342) hysop::multi_array;
+%warnfilter(342) hysop::multi_array_view;
+%warnfilter(342) hysop::const_multi_array_view;
+%warnfilter(342) hysop::multi_array_ref;
+%warnfilter(342) hysop::const_multi_array_ref;
+%ignore hysop::multi_array;
+%ignore hysop::multi_array_view;
+%ignore hysop::const_multi_array_view;
+%ignore hysop::multi_array_ref;
+%ignore hysop::const_multi_array_ref;
+%include "utils/types.h"
+
+%define INSTANTIATE_SHAPE(INT)  %template(Shape  ## INT ## D) hysop::Shape<INT>;   %enddef
+%define INSTANTIATE_OFFSET(INT) %template(Offset ## INT ## D) hysop::Offset<INT>;  %enddef
+%formacro(INSTANTIATE_SHAPE,  INSTANTIATED_DIMENSIONS)
+%formacro(INSTANTIATE_OFFSET, INSTANTIATED_DIMENSIONS)
+
+/* constants */
+%include "utils/constants.h"
diff --git a/HySoP/swig/start.i b/HySoP/swig/start.i
index ee33d7837..24aa1a26a 100644
--- a/HySoP/swig/start.i
+++ b/HySoP/swig/start.i
@@ -8,3 +8,7 @@
 %init %{
   import_array();
 %}
+
+
+//usefull macros used to instanciate templates
+%define INSTANTIATED_DIMENSIONS 1,2,3,4,5,6,7 %enddef
diff --git a/HySoP/swig/types.i b/HySoP/swig/types.i
deleted file mode 100644
index 6a2ef1049..000000000
--- a/HySoP/swig/types.i
+++ /dev/null
@@ -1,7 +0,0 @@
-
-// -*- C++ -*-
-%{
-  #include "utils/types.h"
-%}
-
-%include "utils/types.h"
-- 
GitLab