From b6082098c4017d8b0aeca4a0e8ff3c6ab84a2ff9 Mon Sep 17 00:00:00 2001
From: Yuuichi Asahi <y.asahi@nr.titech.ac.jp>
Date: Wed, 20 Dec 2023 19:37:40 +0900
Subject: [PATCH 1/2] Introduce Impl namespace to functions defined in common

---
 common/src/KokkosFFT_Cuda_types.hpp     |  4 +-
 common/src/KokkosFFT_HIP_types.hpp      |  4 +-
 common/src/KokkosFFT_OpenMP_types.hpp   |  6 +-
 common/src/KokkosFFT_default_types.hpp  | 32 ++++++---
 common/src/KokkosFFT_layouts.hpp        |  8 ++-
 common/src/KokkosFFT_normalization.hpp  | 12 ++--
 common/src/KokkosFFT_transpose.hpp      | 10 +--
 common/src/KokkosFFT_utils.hpp          |  6 +-
 common/unit_test/Test_Layouts.cpp       | 84 +++++++++++-----------
 common/unit_test/Test_Normalization.cpp | 12 ++--
 common/unit_test/Test_Transpose.cpp     | 94 ++++++++++++-------------
 common/unit_test/Test_Utils.cpp         | 66 ++++++++---------
 12 files changed, 177 insertions(+), 161 deletions(-)

diff --git a/common/src/KokkosFFT_Cuda_types.hpp b/common/src/KokkosFFT_Cuda_types.hpp
index 80a69524..f8e86e78 100644
--- a/common/src/KokkosFFT_Cuda_types.hpp
+++ b/common/src/KokkosFFT_Cuda_types.hpp
@@ -4,6 +4,7 @@
 #include <cufft.h>
 
 namespace KokkosFFT {
+namespace Impl {
   #define KOKKOS_FFT_FORWARD CUFFT_FORWARD
   #define KOKKOS_FFT_BACKWARD CUFFT_INVERSE
   #define KOKKOS_FFT_R2C CUFFT_R2C
@@ -54,6 +55,7 @@ namespace KokkosFFT {
     static constexpr TransformType m_type = std::is_same_v<T1, float> ? KOKKOS_FFT_C2C : KOKKOS_FFT_Z2Z;
     static constexpr TransformType type() { return m_type; };
   };
-};
+} // namespace Impl
+}; // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/common/src/KokkosFFT_HIP_types.hpp b/common/src/KokkosFFT_HIP_types.hpp
index 9ab97f79..9c9c9700 100644
--- a/common/src/KokkosFFT_HIP_types.hpp
+++ b/common/src/KokkosFFT_HIP_types.hpp
@@ -4,6 +4,7 @@
 #include <hipfft/hipfft.h>
 
 namespace KokkosFFT {
+namespace Impl {
   #define KOKKOS_FFT_FORWARD HIPFFT_FORWARD
   #define KOKKOS_FFT_BACKWARD HIPFFT_BACKWARD
   #define KOKKOS_FFT_R2C HIPFFT_R2C
@@ -54,6 +55,7 @@ namespace KokkosFFT {
     static constexpr TransformType m_type = std::is_same_v<T1, float> ? KOKKOS_FFT_C2C : KOKKOS_FFT_Z2Z;
     static constexpr TransformType type() { return m_type; };
   };
-};
+} // namespace Impl
+}; // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/common/src/KokkosFFT_OpenMP_types.hpp b/common/src/KokkosFFT_OpenMP_types.hpp
index 1de4af14..e09755f2 100644
--- a/common/src/KokkosFFT_OpenMP_types.hpp
+++ b/common/src/KokkosFFT_OpenMP_types.hpp
@@ -5,6 +5,7 @@
 #include "KokkosFFT_utils.hpp"
 
 namespace KokkosFFT {
+namespace Impl {
   enum class TransformType {
     R2C,
     D2Z,
@@ -32,7 +33,7 @@ namespace KokkosFFT {
 
   template <typename T>
   struct FFTPlanType {
-    using type = std::conditional_t<std::is_same_v<real_type_t<T>, float>, fftwf_plan, fftw_plan>;
+    using type = std::conditional_t<std::is_same_v<KokkosFFT::Impl::real_type_t<T>, float>, fftwf_plan, fftw_plan>;
   };
 
   using FFTResultType = int;
@@ -63,6 +64,7 @@ namespace KokkosFFT {
     static constexpr TransformType m_type = std::is_same_v<T1, float> ? KOKKOS_FFT_C2C : KOKKOS_FFT_Z2Z;
     static constexpr TransformType type() { return m_type; };
   };
-};
+} // namespace Impl
+}; // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/common/src/KokkosFFT_default_types.hpp b/common/src/KokkosFFT_default_types.hpp
index 02467122..fb05d45a 100644
--- a/common/src/KokkosFFT_default_types.hpp
+++ b/common/src/KokkosFFT_default_types.hpp
@@ -23,27 +23,37 @@
 #include "KokkosFFT_utils.hpp"
 
 // Check the size of complex type
-static_assert(sizeof(KokkosFFT::FFTDataType::complex64) == sizeof(Kokkos::complex<float>));
-static_assert(alignof(KokkosFFT::FFTDataType::complex64) <= alignof(Kokkos::complex<float>));
+static_assert(sizeof(KokkosFFT::Impl::FFTDataType::complex64) == sizeof(Kokkos::complex<float>));
+static_assert(alignof(KokkosFFT::Impl::FFTDataType::complex64) <= alignof(Kokkos::complex<float>));
 
-static_assert(sizeof(KokkosFFT::FFTDataType::complex128) == sizeof(Kokkos::complex<double>));
-static_assert(alignof(KokkosFFT::FFTDataType::complex128) <= alignof(Kokkos::complex<double>));
+static_assert(sizeof(KokkosFFT::Impl::FFTDataType::complex128) == sizeof(Kokkos::complex<double>));
+static_assert(alignof(KokkosFFT::Impl::FFTDataType::complex128) <= alignof(Kokkos::complex<double>));
 
 namespace KokkosFFT {
+  // Define type to specify transform axis
+  template <std::size_t DIM>
+  using axis_type = std::array<int, DIM>;
+
+  enum class Normalization {
+    FORWARD,
+    BACKWARD,
+    ORTHO
+  };
+} // namespace KokkosFFT
+
+namespace KokkosFFT {
+namespace Impl {
   // Define fft data types
   template <typename T>
   struct fft_data_type {
-    using type = std::conditional_t<std::is_same_v<T, float>, KokkosFFT::FFTDataType::float32, KokkosFFT::FFTDataType::float64>;
+    using type = std::conditional_t<std::is_same_v<T, float>, KokkosFFT::Impl::FFTDataType::float32, KokkosFFT::Impl::FFTDataType::float64>;
   };
 
   template <typename T>
   struct fft_data_type<Kokkos::complex<T>> {
-    using type = std::conditional_t<std::is_same_v<T, float>, KokkosFFT::FFTDataType::complex64, KokkosFFT::FFTDataType::complex128>;
+    using type = std::conditional_t<std::is_same_v<T, float>, KokkosFFT::Impl::FFTDataType::complex64, KokkosFFT::Impl::FFTDataType::complex128>;
   };
-
-  // Define type to specify transform axis
-  template <std::size_t DIM>
-  using axis_type = std::array<int, DIM>;
-}
+} // namespace Impl
+} // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/common/src/KokkosFFT_layouts.hpp b/common/src/KokkosFFT_layouts.hpp
index a972092c..c7e98b26 100644
--- a/common/src/KokkosFFT_layouts.hpp
+++ b/common/src/KokkosFFT_layouts.hpp
@@ -11,6 +11,7 @@
 #include "KokkosFFT_transpose.hpp"
 
 namespace KokkosFFT {
+namespace Impl {
   /* Input and output extents exposed to the fft library
      i.e extents are converted into Layout Right
   */
@@ -21,7 +22,7 @@ namespace KokkosFFT {
     using array_layout_type = typename InViewType::array_layout;
 
     // index map after transpose over axis
-    auto [map, map_inv] = get_map_axes(in, _axes);
+    auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(in, _axes);
 
     constexpr std::size_t rank = InViewType::rank;
     int inner_most_axis = std::is_same_v<array_layout_type, typename Kokkos::LayoutLeft> ? 0 : rank - 1;
@@ -77,7 +78,7 @@ namespace KokkosFFT {
     using array_layout_type = typename InViewType::array_layout;
 
     // index map after transpose over axis
-    auto [map, map_inv] = get_map_axes(in, _axes);
+    auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(in, _axes);
 
     static_assert(InViewType::rank() >= DIM,
                   "KokkosFFT::get_map_axes: Rank of View must be larger thane or equal to the Rank of FFT axes.");
@@ -168,6 +169,7 @@ namespace KokkosFFT {
   auto get_extents_batched(InViewType& in, OutViewType& out, int _axis) {
      return get_extents_batched(in, out, axis_type<1>{_axis});
   }
-};
+} // namespace Impl
+}; // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/common/src/KokkosFFT_normalization.hpp b/common/src/KokkosFFT_normalization.hpp
index b82ef2c2..6c5ac9e3 100644
--- a/common/src/KokkosFFT_normalization.hpp
+++ b/common/src/KokkosFFT_normalization.hpp
@@ -6,12 +6,7 @@
 #include "KokkosFFT_utils.hpp"
 
 namespace KokkosFFT {
-  enum class Normalization {
-    FORWARD,
-    BACKWARD,
-    ORTHO
-  };
-
+namespace Impl {
   template <typename ExecutionSpace, typename ViewType, typename T>
   void _normalize(const ExecutionSpace& exec_space, ViewType& inout, const T coef) {
     std::size_t size = inout.size();
@@ -25,7 +20,7 @@ namespace KokkosFFT {
 
   template <typename ViewType>
   auto _coefficients(const ViewType& inout, FFTDirectionType direction, Normalization normalization, std::size_t fft_size) {
-    using value_type = real_type_t<typename ViewType::non_const_value_type>;
+    using value_type = KokkosFFT::Impl::real_type_t<typename ViewType::non_const_value_type>;
     value_type coef = 1;
     bool to_normalize = false;
 
@@ -58,6 +53,7 @@ namespace KokkosFFT {
     auto [coef, to_normalize] = _coefficients(inout, direction, normalization, fft_size);
     if(to_normalize) _normalize(exec_space, inout, coef);
   }
-};
+} // namespace Impl
+}; // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/common/src/KokkosFFT_transpose.hpp b/common/src/KokkosFFT_transpose.hpp
index 6ebfdd2f..2ad2f117 100644
--- a/common/src/KokkosFFT_transpose.hpp
+++ b/common/src/KokkosFFT_transpose.hpp
@@ -7,6 +7,7 @@
 #include "KokkosFFT_utils.hpp"
 
 namespace KokkosFFT {
+namespace Impl {
   template <typename ViewType, std::size_t DIM>
   auto get_map_axes(const ViewType& view, axis_type<DIM> _axes) {
     static_assert(ViewType::rank() >= DIM,
@@ -20,12 +21,12 @@ namespace KokkosFFT {
     // Convert the input axes to be in the range of [0, rank-1]
     std::vector<int> axes;
     for(std::size_t i=0; i<DIM; i++) {
-      int axis = convert_negative_axis(view, _axes.at(i));
+      int axis = KokkosFFT::Impl::convert_negative_axis(view, _axes.at(i));
       axes.push_back(axis);
     }
 
     // Assert if the elements are overlapped
-    assert( ! has_duplicate_values(axes) );
+    assert( ! KokkosFFT::Impl::has_duplicate_values(axes) );
 
     // how indices are map
     // For 5D View and axes are (2,3), map would be (0, 1, 4, 2, 3)
@@ -211,12 +212,13 @@ namespace KokkosFFT {
     static_assert(InViewType::rank() == OutViewType::rank(),
                   "KokkosFFT::transpose: InViewType and OutViewType must have the same rank.");
 
-    if(!is_transpose_needed(_map)) {
+    if(!KokkosFFT::Impl::is_transpose_needed(_map)) {
       throw std::runtime_error("KokkosFFT::transpose: transpose not necessary");
     }
 
     _transpose(exec_space, in, out, _map);
   }
-};
+} // namespace Impl
+} // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/common/src/KokkosFFT_utils.hpp b/common/src/KokkosFFT_utils.hpp
index 3c29420f..09d49b0e 100644
--- a/common/src/KokkosFFT_utils.hpp
+++ b/common/src/KokkosFFT_utils.hpp
@@ -8,6 +8,7 @@
 #include <numeric>
 
 namespace KokkosFFT {
+namespace Impl {
   template <typename T>
   struct real_type {
     using type = T;
@@ -90,8 +91,7 @@ namespace KokkosFFT {
                    [=](const T sequence) -> T {return start + sequence;});
     return sequence;
   }
-
-
-};
+} // namespace Impl
+}; // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/common/unit_test/Test_Layouts.cpp b/common/unit_test/Test_Layouts.cpp
index 6ba1256b..27cffb2f 100644
--- a/common/unit_test/Test_Layouts.cpp
+++ b/common/unit_test/Test_Layouts.cpp
@@ -21,7 +21,7 @@ void test_layouts_1d() {
   ref_out_extents_r2c.at(0) = n0/2+1;
   ref_fft_extents_r2c.at(0) = n0;
 
-  auto [in_extents_r2c, out_extents_r2c, fft_extents_r2c] = KokkosFFT::get_extents(xr, xc, 0);
+  auto [in_extents_r2c, out_extents_r2c, fft_extents_r2c] = KokkosFFT::Impl::get_extents(xr, xc, 0);
   EXPECT_TRUE( in_extents_r2c == ref_in_extents_r2c );
   EXPECT_TRUE( out_extents_r2c == ref_out_extents_r2c );
   EXPECT_TRUE( fft_extents_r2c == ref_fft_extents_r2c );
@@ -32,7 +32,7 @@ void test_layouts_1d() {
   ref_out_extents_c2r.at(0) = n0;
   ref_fft_extents_c2r.at(0) = n0;
 
-  auto [in_extents_c2r, out_extents_c2r, fft_extents_c2r] = KokkosFFT::get_extents(xc, xr, 0);
+  auto [in_extents_c2r, out_extents_c2r, fft_extents_c2r] = KokkosFFT::Impl::get_extents(xc, xr, 0);
   EXPECT_TRUE( in_extents_c2r == ref_in_extents_c2r );
   EXPECT_TRUE( out_extents_c2r == ref_out_extents_c2r );
   EXPECT_TRUE( fft_extents_c2r == ref_fft_extents_c2r );
@@ -43,7 +43,7 @@ void test_layouts_1d() {
   ref_out_extents_c2c.at(0) = n0;
   ref_fft_extents_c2c.at(0) = n0;
 
-  auto [in_extents_c2c, out_extents_c2c, fft_extents_c2c] = KokkosFFT::get_extents(xcin, xcout, 0);
+  auto [in_extents_c2c, out_extents_c2c, fft_extents_c2c] = KokkosFFT::Impl::get_extents(xcin, xcout, 0);
   EXPECT_TRUE( in_extents_c2c == ref_in_extents_c2c );
   EXPECT_TRUE( out_extents_c2c == ref_out_extents_c2c );
   EXPECT_TRUE( fft_extents_c2c == ref_fft_extents_c2c );
@@ -76,8 +76,8 @@ void test_layouts_2d() {
   std::vector<int> ref_out_extents_r2c_axis1{n0, n1/2+1};
 
   // R2C
-  auto [in_extents_r2c_axis0, out_extents_r2c_axis0, fft_extents_r2c_axis0] = KokkosFFT::get_extents(xr2, xc2_axis0, 0);
-  auto [in_extents_r2c_axis1, out_extents_r2c_axis1, fft_extents_r2c_axis1] = KokkosFFT::get_extents(xr2, xc2_axis1, 1);
+  auto [in_extents_r2c_axis0, out_extents_r2c_axis0, fft_extents_r2c_axis0] = KokkosFFT::Impl::get_extents(xr2, xc2_axis0, 0);
+  auto [in_extents_r2c_axis1, out_extents_r2c_axis1, fft_extents_r2c_axis1] = KokkosFFT::Impl::get_extents(xr2, xc2_axis1, 1);
   EXPECT_TRUE( in_extents_r2c_axis0 == ref_in_extents_r2c_axis0 );
   EXPECT_TRUE( in_extents_r2c_axis1 == ref_in_extents_r2c_axis1 );
 
@@ -88,8 +88,8 @@ void test_layouts_2d() {
   EXPECT_TRUE( out_extents_r2c_axis1 == ref_out_extents_r2c_axis1 );
 
   // C2R
-  auto [in_extents_c2r_axis0, out_extents_c2r_axis0, fft_extents_c2r_axis0] = KokkosFFT::get_extents(xc2_axis0, xr2, 0);
-  auto [in_extents_c2r_axis1, out_extents_c2r_axis1, fft_extents_c2r_axis1] = KokkosFFT::get_extents(xc2_axis1, xr2, 1);
+  auto [in_extents_c2r_axis0, out_extents_c2r_axis0, fft_extents_c2r_axis0] = KokkosFFT::Impl::get_extents(xc2_axis0, xr2, 0);
+  auto [in_extents_c2r_axis1, out_extents_c2r_axis1, fft_extents_c2r_axis1] = KokkosFFT::Impl::get_extents(xc2_axis1, xr2, 1);
   EXPECT_TRUE( in_extents_c2r_axis0 == ref_out_extents_r2c_axis0 );
   EXPECT_TRUE( in_extents_c2r_axis1 == ref_out_extents_r2c_axis1 );
 
@@ -100,8 +100,8 @@ void test_layouts_2d() {
   EXPECT_TRUE( out_extents_c2r_axis1 == ref_in_extents_r2c_axis1 );
 
   // C2C
-  auto [in_extents_c2c_axis0, out_extents_c2c_axis0, fft_extents_c2c_axis0] = KokkosFFT::get_extents(xcin2, xcout2, 0);
-  auto [in_extents_c2c_axis1, out_extents_c2c_axis1, fft_extents_c2c_axis1] = KokkosFFT::get_extents(xcin2, xcout2, 1);
+  auto [in_extents_c2c_axis0, out_extents_c2c_axis0, fft_extents_c2c_axis0] = KokkosFFT::Impl::get_extents(xcin2, xcout2, 0);
+  auto [in_extents_c2c_axis1, out_extents_c2c_axis1, fft_extents_c2c_axis1] = KokkosFFT::Impl::get_extents(xcin2, xcout2, 1);
   EXPECT_TRUE( in_extents_c2c_axis0 == ref_in_extents_r2c_axis0 );
   EXPECT_TRUE( in_extents_c2c_axis1 == ref_in_extents_r2c_axis1 );
 
@@ -139,39 +139,39 @@ void test_layouts_1d_batched_FFT_2d() {
   int ref_howmany_r2c_axis1 = n0;
 
   // R2C
-  auto [in_extents_r2c_axis0, out_extents_r2c_axis0, fft_extents_r2c_axis0, howmany_r2c_axis0] = KokkosFFT::get_extents_batched(xr2, xc2_axis0, 0);
+  auto [in_extents_r2c_axis0, out_extents_r2c_axis0, fft_extents_r2c_axis0, howmany_r2c_axis0] = KokkosFFT::Impl::get_extents_batched(xr2, xc2_axis0, 0);
   EXPECT_TRUE( in_extents_r2c_axis0 == ref_in_extents_r2c_axis0 );
   EXPECT_TRUE( fft_extents_r2c_axis0 == ref_fft_extents_r2c_axis0 );
   EXPECT_TRUE( out_extents_r2c_axis0 == ref_out_extents_r2c_axis0 );
   EXPECT_EQ( howmany_r2c_axis0, ref_howmany_r2c_axis0 );
 
-  auto [in_extents_r2c_axis1, out_extents_r2c_axis1, fft_extents_r2c_axis1, howmany_r2c_axis1] = KokkosFFT::get_extents_batched(xr2, xc2_axis1, 1);
+  auto [in_extents_r2c_axis1, out_extents_r2c_axis1, fft_extents_r2c_axis1, howmany_r2c_axis1] = KokkosFFT::Impl::get_extents_batched(xr2, xc2_axis1, 1);
   EXPECT_TRUE( in_extents_r2c_axis1 == ref_in_extents_r2c_axis1 );
   EXPECT_TRUE( fft_extents_r2c_axis1 == ref_fft_extents_r2c_axis1 );
   EXPECT_TRUE( out_extents_r2c_axis1 == ref_out_extents_r2c_axis1 );
   EXPECT_EQ( howmany_r2c_axis1, ref_howmany_r2c_axis1 );
 
   // C2R
-  auto [in_extents_c2r_axis0, out_extents_c2r_axis0, fft_extents_c2r_axis0, howmany_c2r_axis0] = KokkosFFT::get_extents_batched(xc2_axis0, xr2, 0);
+  auto [in_extents_c2r_axis0, out_extents_c2r_axis0, fft_extents_c2r_axis0, howmany_c2r_axis0] = KokkosFFT::Impl::get_extents_batched(xc2_axis0, xr2, 0);
   EXPECT_TRUE( in_extents_c2r_axis0 == ref_out_extents_r2c_axis0 );
   EXPECT_TRUE( fft_extents_c2r_axis0 == ref_fft_extents_r2c_axis0 );
   EXPECT_TRUE( out_extents_c2r_axis0 == ref_in_extents_r2c_axis0 );
   EXPECT_EQ( howmany_c2r_axis0, ref_howmany_r2c_axis0 );
 
-  auto [in_extents_c2r_axis1, out_extents_c2r_axis1, fft_extents_c2r_axis1, howmany_c2r_axis1] = KokkosFFT::get_extents_batched(xc2_axis1, xr2, 1);
+  auto [in_extents_c2r_axis1, out_extents_c2r_axis1, fft_extents_c2r_axis1, howmany_c2r_axis1] = KokkosFFT::Impl::get_extents_batched(xc2_axis1, xr2, 1);
   EXPECT_TRUE( in_extents_c2r_axis1 == ref_out_extents_r2c_axis1 );
   EXPECT_TRUE( fft_extents_c2r_axis1 == ref_fft_extents_r2c_axis1 );
   EXPECT_TRUE( out_extents_c2r_axis1 == ref_in_extents_r2c_axis1 );
   EXPECT_EQ( howmany_c2r_axis1, ref_howmany_r2c_axis1 );
 
   // C2C
-  auto [in_extents_c2c_axis0, out_extents_c2c_axis0, fft_extents_c2c_axis0, howmany_c2c_axis0] = KokkosFFT::get_extents_batched(xcin2, xcout2, 0);
+  auto [in_extents_c2c_axis0, out_extents_c2c_axis0, fft_extents_c2c_axis0, howmany_c2c_axis0] = KokkosFFT::Impl::get_extents_batched(xcin2, xcout2, 0);
   EXPECT_TRUE( in_extents_c2c_axis0 == ref_in_extents_r2c_axis0 );
   EXPECT_TRUE( fft_extents_c2c_axis0 == ref_fft_extents_r2c_axis0 );
   EXPECT_TRUE( out_extents_c2c_axis0 == ref_in_extents_r2c_axis0 );
   EXPECT_EQ( howmany_c2c_axis0, ref_howmany_r2c_axis0 );
 
-  auto [in_extents_c2c_axis1, out_extents_c2c_axis1, fft_extents_c2c_axis1, howmany_c2c_axis1] = KokkosFFT::get_extents_batched(xcin2, xcout2, 1);
+  auto [in_extents_c2c_axis1, out_extents_c2c_axis1, fft_extents_c2c_axis1, howmany_c2c_axis1] = KokkosFFT::Impl::get_extents_batched(xcin2, xcout2, 1);
   EXPECT_TRUE( in_extents_c2c_axis1 == ref_in_extents_r2c_axis1 );
   EXPECT_TRUE( fft_extents_c2c_axis1 == ref_fft_extents_r2c_axis1 );
   EXPECT_TRUE( out_extents_c2c_axis1 == ref_in_extents_r2c_axis1 );
@@ -215,57 +215,57 @@ void test_layouts_1d_batched_FFT_3d() {
   int ref_howmany_r2c_axis2 = n0 * n1;
 
   // R2C
-  auto [in_extents_r2c_axis0, out_extents_r2c_axis0, fft_extents_r2c_axis0, howmany_r2c_axis0] = KokkosFFT::get_extents_batched(xr3, xc3_axis0, 0);
+  auto [in_extents_r2c_axis0, out_extents_r2c_axis0, fft_extents_r2c_axis0, howmany_r2c_axis0] = KokkosFFT::Impl::get_extents_batched(xr3, xc3_axis0, 0);
   EXPECT_TRUE( in_extents_r2c_axis0 == ref_in_extents_r2c_axis0 );
   EXPECT_TRUE( fft_extents_r2c_axis0 == ref_fft_extents_r2c_axis0 );
   EXPECT_TRUE( out_extents_r2c_axis0 == ref_out_extents_r2c_axis0 );
   EXPECT_EQ( howmany_r2c_axis0, ref_howmany_r2c_axis0 );
 
-  auto [in_extents_r2c_axis1, out_extents_r2c_axis1, fft_extents_r2c_axis1, howmany_r2c_axis1] = KokkosFFT::get_extents_batched(xr3, xc3_axis1, 1);
+  auto [in_extents_r2c_axis1, out_extents_r2c_axis1, fft_extents_r2c_axis1, howmany_r2c_axis1] = KokkosFFT::Impl::get_extents_batched(xr3, xc3_axis1, 1);
   EXPECT_TRUE( in_extents_r2c_axis1 == ref_in_extents_r2c_axis1 );
   EXPECT_TRUE( fft_extents_r2c_axis1 == ref_fft_extents_r2c_axis1 );
   EXPECT_TRUE( out_extents_r2c_axis1 == ref_out_extents_r2c_axis1 );
   EXPECT_EQ( howmany_r2c_axis1, ref_howmany_r2c_axis1 );
 
-  auto [in_extents_r2c_axis2, out_extents_r2c_axis2, fft_extents_r2c_axis2, howmany_r2c_axis2] = KokkosFFT::get_extents_batched(xr3, xc3_axis2, 2);
+  auto [in_extents_r2c_axis2, out_extents_r2c_axis2, fft_extents_r2c_axis2, howmany_r2c_axis2] = KokkosFFT::Impl::get_extents_batched(xr3, xc3_axis2, 2);
   EXPECT_TRUE( in_extents_r2c_axis2 == ref_in_extents_r2c_axis2 );
   EXPECT_TRUE( fft_extents_r2c_axis2 == ref_fft_extents_r2c_axis2 );
   EXPECT_TRUE( out_extents_r2c_axis2 == ref_out_extents_r2c_axis2 );
   EXPECT_EQ( howmany_r2c_axis2, ref_howmany_r2c_axis2 );
 
   // C2R
-  auto [in_extents_c2r_axis0, out_extents_c2r_axis0, fft_extents_c2r_axis0, howmany_c2r_axis0] = KokkosFFT::get_extents_batched(xc3_axis0, xr3, 0);
+  auto [in_extents_c2r_axis0, out_extents_c2r_axis0, fft_extents_c2r_axis0, howmany_c2r_axis0] = KokkosFFT::Impl::get_extents_batched(xc3_axis0, xr3, 0);
   EXPECT_TRUE( in_extents_c2r_axis0 == ref_out_extents_r2c_axis0 );
   EXPECT_TRUE( fft_extents_c2r_axis0 == ref_fft_extents_r2c_axis0 );
   EXPECT_TRUE( out_extents_c2r_axis0 == ref_in_extents_r2c_axis0 );
   EXPECT_EQ( howmany_c2r_axis0, ref_howmany_r2c_axis0 );
 
-  auto [in_extents_c2r_axis1, out_extents_c2r_axis1, fft_extents_c2r_axis1, howmany_c2r_axis1] = KokkosFFT::get_extents_batched(xc3_axis1, xr3, 1);
+  auto [in_extents_c2r_axis1, out_extents_c2r_axis1, fft_extents_c2r_axis1, howmany_c2r_axis1] = KokkosFFT::Impl::get_extents_batched(xc3_axis1, xr3, 1);
   EXPECT_TRUE( in_extents_c2r_axis1 == ref_out_extents_r2c_axis1 );
   EXPECT_TRUE( fft_extents_c2r_axis1 == ref_fft_extents_r2c_axis1 );
   EXPECT_TRUE( out_extents_c2r_axis1 == ref_in_extents_r2c_axis1 );
   EXPECT_EQ( howmany_c2r_axis1, ref_howmany_r2c_axis1 );
 
-  auto [in_extents_c2r_axis2, out_extents_c2r_axis2, fft_extents_c2r_axis2, howmany_c2r_axis2] = KokkosFFT::get_extents_batched(xc3_axis2, xr3, 2);
+  auto [in_extents_c2r_axis2, out_extents_c2r_axis2, fft_extents_c2r_axis2, howmany_c2r_axis2] = KokkosFFT::Impl::get_extents_batched(xc3_axis2, xr3, 2);
   EXPECT_TRUE( in_extents_c2r_axis2 == ref_out_extents_r2c_axis2 );
   EXPECT_TRUE( fft_extents_c2r_axis2 == ref_fft_extents_r2c_axis2 );
   EXPECT_TRUE( out_extents_c2r_axis2 == ref_in_extents_r2c_axis2 );
   EXPECT_EQ( howmany_c2r_axis2, ref_howmany_r2c_axis2 );
 
   // C2C
-  auto [in_extents_c2c_axis0, out_extents_c2c_axis0, fft_extents_c2c_axis0, howmany_c2c_axis0] = KokkosFFT::get_extents_batched(xcin3, xcout3, 0);
+  auto [in_extents_c2c_axis0, out_extents_c2c_axis0, fft_extents_c2c_axis0, howmany_c2c_axis0] = KokkosFFT::Impl::get_extents_batched(xcin3, xcout3, 0);
   EXPECT_TRUE( in_extents_c2c_axis0 == ref_in_extents_r2c_axis0 );
   EXPECT_TRUE( fft_extents_c2c_axis0 == ref_fft_extents_r2c_axis0 );
   EXPECT_TRUE( out_extents_c2c_axis0 == ref_in_extents_r2c_axis0 );
   EXPECT_EQ( howmany_c2c_axis0, ref_howmany_r2c_axis0 );
 
-  auto [in_extents_c2c_axis1, out_extents_c2c_axis1, fft_extents_c2c_axis1, howmany_c2c_axis1] = KokkosFFT::get_extents_batched(xcin3, xcout3, 1);
+  auto [in_extents_c2c_axis1, out_extents_c2c_axis1, fft_extents_c2c_axis1, howmany_c2c_axis1] = KokkosFFT::Impl::get_extents_batched(xcin3, xcout3, 1);
   EXPECT_TRUE( in_extents_c2c_axis1 == ref_in_extents_r2c_axis1 );
   EXPECT_TRUE( fft_extents_c2c_axis1 == ref_fft_extents_r2c_axis1 );
   EXPECT_TRUE( out_extents_c2c_axis1 == ref_in_extents_r2c_axis1 );
   EXPECT_EQ( howmany_c2c_axis1, ref_howmany_r2c_axis1 );
 
-  auto [in_extents_c2c_axis2, out_extents_c2c_axis2, fft_extents_c2c_axis2, howmany_c2c_axis2] = KokkosFFT::get_extents_batched(xcin3, xcout3, 2);
+  auto [in_extents_c2c_axis2, out_extents_c2c_axis2, fft_extents_c2c_axis2, howmany_c2c_axis2] = KokkosFFT::Impl::get_extents_batched(xcin3, xcout3, 2);
   EXPECT_TRUE( in_extents_c2c_axis2 == ref_in_extents_r2c_axis2 );
   EXPECT_TRUE( fft_extents_c2c_axis2 == ref_fft_extents_r2c_axis2 );
   EXPECT_TRUE( out_extents_c2c_axis2 == ref_in_extents_r2c_axis2 );
@@ -328,111 +328,111 @@ void test_layouts_2d_batched_FFT_3d() {
   int ref_howmany_r2c_axis_21 = n0;
 
   // R2C
-  auto [in_extents_r2c_axis_01, out_extents_r2c_axis_01, fft_extents_r2c_axis_01, howmany_r2c_axis_01] = KokkosFFT::get_extents_batched(xr3, xc3_axis_01, axes_type({0, 1}));
+  auto [in_extents_r2c_axis_01, out_extents_r2c_axis_01, fft_extents_r2c_axis_01, howmany_r2c_axis_01] = KokkosFFT::Impl::get_extents_batched(xr3, xc3_axis_01, axes_type({0, 1}));
   EXPECT_TRUE( in_extents_r2c_axis_01 == ref_in_extents_r2c_axis_01 );
   EXPECT_TRUE( fft_extents_r2c_axis_01 == ref_fft_extents_r2c_axis_01 );
   EXPECT_TRUE( out_extents_r2c_axis_01 == ref_out_extents_r2c_axis_01 );
   EXPECT_EQ( howmany_r2c_axis_01, ref_howmany_r2c_axis_01 );
 
-  auto [in_extents_r2c_axis_02, out_extents_r2c_axis_02, fft_extents_r2c_axis_02, howmany_r2c_axis_02] = KokkosFFT::get_extents_batched(xr3, xc3_axis_02, axes_type({0, 2}));
+  auto [in_extents_r2c_axis_02, out_extents_r2c_axis_02, fft_extents_r2c_axis_02, howmany_r2c_axis_02] = KokkosFFT::Impl::get_extents_batched(xr3, xc3_axis_02, axes_type({0, 2}));
   EXPECT_TRUE( in_extents_r2c_axis_02 == ref_in_extents_r2c_axis_02 );
   EXPECT_TRUE( fft_extents_r2c_axis_02 == ref_fft_extents_r2c_axis_02 );
   EXPECT_TRUE( out_extents_r2c_axis_02 == ref_out_extents_r2c_axis_02 );
   EXPECT_EQ( howmany_r2c_axis_02, ref_howmany_r2c_axis_02 );
 
-  auto [in_extents_r2c_axis_10, out_extents_r2c_axis_10, fft_extents_r2c_axis_10, howmany_r2c_axis_10] = KokkosFFT::get_extents_batched(xr3, xc3_axis_10, axes_type({1, 0}));
+  auto [in_extents_r2c_axis_10, out_extents_r2c_axis_10, fft_extents_r2c_axis_10, howmany_r2c_axis_10] = KokkosFFT::Impl::get_extents_batched(xr3, xc3_axis_10, axes_type({1, 0}));
   EXPECT_TRUE( in_extents_r2c_axis_10 == ref_in_extents_r2c_axis_10 );
   EXPECT_TRUE( fft_extents_r2c_axis_10 == ref_fft_extents_r2c_axis_10 );
   EXPECT_TRUE( out_extents_r2c_axis_10 == ref_out_extents_r2c_axis_10 );
   EXPECT_EQ( howmany_r2c_axis_10, ref_howmany_r2c_axis_10 );
 
-  auto [in_extents_r2c_axis_12, out_extents_r2c_axis_12, fft_extents_r2c_axis_12, howmany_r2c_axis_12] = KokkosFFT::get_extents_batched(xr3, xc3_axis_12, axes_type({1, 2}));
+  auto [in_extents_r2c_axis_12, out_extents_r2c_axis_12, fft_extents_r2c_axis_12, howmany_r2c_axis_12] = KokkosFFT::Impl::get_extents_batched(xr3, xc3_axis_12, axes_type({1, 2}));
   EXPECT_TRUE( in_extents_r2c_axis_12 == ref_in_extents_r2c_axis_12 );
   EXPECT_TRUE( fft_extents_r2c_axis_12 == ref_fft_extents_r2c_axis_12 );
   EXPECT_TRUE( out_extents_r2c_axis_12 == ref_out_extents_r2c_axis_12 );
   EXPECT_EQ( howmany_r2c_axis_12, ref_howmany_r2c_axis_12 );
 
-  auto [in_extents_r2c_axis_20, out_extents_r2c_axis_20, fft_extents_r2c_axis_20, howmany_r2c_axis_20] = KokkosFFT::get_extents_batched(xr3, xc3_axis_20, axes_type({2, 0}));
+  auto [in_extents_r2c_axis_20, out_extents_r2c_axis_20, fft_extents_r2c_axis_20, howmany_r2c_axis_20] = KokkosFFT::Impl::get_extents_batched(xr3, xc3_axis_20, axes_type({2, 0}));
   EXPECT_TRUE( in_extents_r2c_axis_20 == ref_in_extents_r2c_axis_20 );
   EXPECT_TRUE( fft_extents_r2c_axis_20 == ref_fft_extents_r2c_axis_20 );
   EXPECT_TRUE( out_extents_r2c_axis_20 == ref_out_extents_r2c_axis_20 );
   EXPECT_EQ( howmany_r2c_axis_20, ref_howmany_r2c_axis_20 );
 
-  auto [in_extents_r2c_axis_21, out_extents_r2c_axis_21, fft_extents_r2c_axis_21, howmany_r2c_axis_21] = KokkosFFT::get_extents_batched(xr3, xc3_axis_21, axes_type({2, 1}));
+  auto [in_extents_r2c_axis_21, out_extents_r2c_axis_21, fft_extents_r2c_axis_21, howmany_r2c_axis_21] = KokkosFFT::Impl::get_extents_batched(xr3, xc3_axis_21, axes_type({2, 1}));
   EXPECT_TRUE( in_extents_r2c_axis_21 == ref_in_extents_r2c_axis_21 );
   EXPECT_TRUE( fft_extents_r2c_axis_21 == ref_fft_extents_r2c_axis_21 );
   EXPECT_TRUE( out_extents_r2c_axis_21 == ref_out_extents_r2c_axis_21 );
   EXPECT_EQ( howmany_r2c_axis_21, ref_howmany_r2c_axis_21 );
 
   // C2R
-  auto [in_extents_c2r_axis_01, out_extents_c2r_axis_01, fft_extents_c2r_axis_01, howmany_c2r_axis_01] = KokkosFFT::get_extents_batched(xc3_axis_01, xr3, axes_type({0, 1}));
+  auto [in_extents_c2r_axis_01, out_extents_c2r_axis_01, fft_extents_c2r_axis_01, howmany_c2r_axis_01] = KokkosFFT::Impl::get_extents_batched(xc3_axis_01, xr3, axes_type({0, 1}));
   EXPECT_TRUE( in_extents_c2r_axis_01 == ref_out_extents_r2c_axis_01 );
   EXPECT_TRUE( fft_extents_c2r_axis_01 == ref_fft_extents_r2c_axis_01 );
   EXPECT_TRUE( out_extents_c2r_axis_01 == ref_in_extents_r2c_axis_01 );
   EXPECT_EQ( howmany_c2r_axis_01, ref_howmany_r2c_axis_01 );
 
-  auto [in_extents_c2r_axis_02, out_extents_c2r_axis_02, fft_extents_c2r_axis_02, howmany_c2r_axis_02] = KokkosFFT::get_extents_batched(xc3_axis_02, xr3, axes_type({0, 2}));
+  auto [in_extents_c2r_axis_02, out_extents_c2r_axis_02, fft_extents_c2r_axis_02, howmany_c2r_axis_02] = KokkosFFT::Impl::get_extents_batched(xc3_axis_02, xr3, axes_type({0, 2}));
   EXPECT_TRUE( in_extents_c2r_axis_02 == ref_out_extents_r2c_axis_02 );
   EXPECT_TRUE( fft_extents_c2r_axis_02 == ref_fft_extents_r2c_axis_02 );
   EXPECT_TRUE( out_extents_c2r_axis_02 == ref_in_extents_r2c_axis_02 );
   EXPECT_EQ( howmany_c2r_axis_02, ref_howmany_r2c_axis_02 );
 
-  auto [in_extents_c2r_axis_10, out_extents_c2r_axis_10, fft_extents_c2r_axis_10, howmany_c2r_axis_10] = KokkosFFT::get_extents_batched(xc3_axis_10, xr3, axes_type({1, 0}));
+  auto [in_extents_c2r_axis_10, out_extents_c2r_axis_10, fft_extents_c2r_axis_10, howmany_c2r_axis_10] = KokkosFFT::Impl::get_extents_batched(xc3_axis_10, xr3, axes_type({1, 0}));
   EXPECT_TRUE( in_extents_c2r_axis_10 == ref_out_extents_r2c_axis_10 );
   EXPECT_TRUE( fft_extents_c2r_axis_10 == ref_fft_extents_r2c_axis_10 );
   EXPECT_TRUE( out_extents_c2r_axis_10 == ref_in_extents_r2c_axis_10 );
   EXPECT_EQ( howmany_c2r_axis_10, ref_howmany_r2c_axis_10 );
 
-  auto [in_extents_c2r_axis_12, out_extents_c2r_axis_12, fft_extents_c2r_axis_12, howmany_c2r_axis_12] = KokkosFFT::get_extents_batched(xc3_axis_12, xr3, axes_type({1, 2}));
+  auto [in_extents_c2r_axis_12, out_extents_c2r_axis_12, fft_extents_c2r_axis_12, howmany_c2r_axis_12] = KokkosFFT::Impl::get_extents_batched(xc3_axis_12, xr3, axes_type({1, 2}));
   EXPECT_TRUE( in_extents_c2r_axis_12 == ref_out_extents_r2c_axis_12 );
   EXPECT_TRUE( fft_extents_c2r_axis_12 == ref_fft_extents_r2c_axis_12 );
   EXPECT_TRUE( out_extents_c2r_axis_12 == ref_in_extents_r2c_axis_12 );
   EXPECT_EQ( howmany_c2r_axis_12, ref_howmany_r2c_axis_12 );
 
-  auto [in_extents_c2r_axis_20, out_extents_c2r_axis_20, fft_extents_c2r_axis_20, howmany_c2r_axis_20] = KokkosFFT::get_extents_batched(xc3_axis_20, xr3, axes_type({2, 0}));
+  auto [in_extents_c2r_axis_20, out_extents_c2r_axis_20, fft_extents_c2r_axis_20, howmany_c2r_axis_20] = KokkosFFT::Impl::get_extents_batched(xc3_axis_20, xr3, axes_type({2, 0}));
   EXPECT_TRUE( in_extents_c2r_axis_20 == ref_out_extents_r2c_axis_20 );
   EXPECT_TRUE( fft_extents_c2r_axis_20 == ref_fft_extents_r2c_axis_20 );
   EXPECT_TRUE( out_extents_c2r_axis_20 == ref_in_extents_r2c_axis_20 );
   EXPECT_EQ( howmany_c2r_axis_20, ref_howmany_r2c_axis_20 );
 
-  auto [in_extents_c2r_axis_21, out_extents_c2r_axis_21, fft_extents_c2r_axis_21, howmany_c2r_axis_21] = KokkosFFT::get_extents_batched(xc3_axis_21, xr3, axes_type({2, 1}));
+  auto [in_extents_c2r_axis_21, out_extents_c2r_axis_21, fft_extents_c2r_axis_21, howmany_c2r_axis_21] = KokkosFFT::Impl::get_extents_batched(xc3_axis_21, xr3, axes_type({2, 1}));
   EXPECT_TRUE( in_extents_c2r_axis_21 == ref_out_extents_r2c_axis_21 );
   EXPECT_TRUE( fft_extents_c2r_axis_21 == ref_fft_extents_r2c_axis_21 );
   EXPECT_TRUE( out_extents_c2r_axis_21 == ref_in_extents_r2c_axis_21 );
   EXPECT_EQ( howmany_c2r_axis_21, ref_howmany_r2c_axis_21 );
 
   // C2C
-  auto [in_extents_c2c_axis_01, out_extents_c2c_axis_01, fft_extents_c2c_axis_01, howmany_c2c_axis_01] = KokkosFFT::get_extents_batched(xcin3, xcout3, axes_type({0, 1}));
+  auto [in_extents_c2c_axis_01, out_extents_c2c_axis_01, fft_extents_c2c_axis_01, howmany_c2c_axis_01] = KokkosFFT::Impl::get_extents_batched(xcin3, xcout3, axes_type({0, 1}));
   EXPECT_TRUE( in_extents_c2c_axis_01 == ref_in_extents_r2c_axis_01 );
   EXPECT_TRUE( fft_extents_c2c_axis_01 == ref_fft_extents_r2c_axis_01 );
   EXPECT_TRUE( out_extents_c2c_axis_01 == ref_in_extents_r2c_axis_01 );
   EXPECT_EQ( howmany_c2c_axis_01, ref_howmany_r2c_axis_01 );
 
-  auto [in_extents_c2c_axis_02, out_extents_c2c_axis_02, fft_extents_c2c_axis_02, howmany_c2c_axis_02] = KokkosFFT::get_extents_batched(xcin3, xcout3, axes_type({0, 2}));
+  auto [in_extents_c2c_axis_02, out_extents_c2c_axis_02, fft_extents_c2c_axis_02, howmany_c2c_axis_02] = KokkosFFT::Impl::get_extents_batched(xcin3, xcout3, axes_type({0, 2}));
   EXPECT_TRUE( in_extents_c2c_axis_02 == ref_in_extents_r2c_axis_02 );
   EXPECT_TRUE( fft_extents_c2c_axis_02 == ref_fft_extents_r2c_axis_02 );
   EXPECT_TRUE( out_extents_c2c_axis_02 == ref_in_extents_r2c_axis_02 );
   EXPECT_EQ( howmany_c2c_axis_02, ref_howmany_r2c_axis_02 );
 
-  auto [in_extents_c2c_axis_10, out_extents_c2c_axis_10, fft_extents_c2c_axis_10, howmany_c2c_axis_10] = KokkosFFT::get_extents_batched(xcin3, xcout3, axes_type({1, 0}));
+  auto [in_extents_c2c_axis_10, out_extents_c2c_axis_10, fft_extents_c2c_axis_10, howmany_c2c_axis_10] = KokkosFFT::Impl::get_extents_batched(xcin3, xcout3, axes_type({1, 0}));
   EXPECT_TRUE( in_extents_c2c_axis_10 == ref_in_extents_r2c_axis_10 );
   EXPECT_TRUE( fft_extents_c2c_axis_10 == ref_fft_extents_r2c_axis_10 );
   EXPECT_TRUE( out_extents_c2c_axis_10 == ref_in_extents_r2c_axis_10 );
   EXPECT_EQ( howmany_c2c_axis_10, ref_howmany_r2c_axis_10 );
 
-  auto [in_extents_c2c_axis_12, out_extents_c2c_axis_12, fft_extents_c2c_axis_12, howmany_c2c_axis_12] = KokkosFFT::get_extents_batched(xcin3, xcout3, axes_type({1, 2}));
+  auto [in_extents_c2c_axis_12, out_extents_c2c_axis_12, fft_extents_c2c_axis_12, howmany_c2c_axis_12] = KokkosFFT::Impl::get_extents_batched(xcin3, xcout3, axes_type({1, 2}));
   EXPECT_TRUE( in_extents_c2c_axis_12 == ref_in_extents_r2c_axis_12 );
   EXPECT_TRUE( fft_extents_c2c_axis_12 == ref_fft_extents_r2c_axis_12 );
   EXPECT_TRUE( out_extents_c2c_axis_12 == ref_in_extents_r2c_axis_12 );
   EXPECT_EQ( howmany_c2c_axis_12, ref_howmany_r2c_axis_12 );
 
-  auto [in_extents_c2c_axis_20, out_extents_c2c_axis_20, fft_extents_c2c_axis_20, howmany_c2c_axis_20] = KokkosFFT::get_extents_batched(xcin3, xcout3, axes_type({2, 0}));
+  auto [in_extents_c2c_axis_20, out_extents_c2c_axis_20, fft_extents_c2c_axis_20, howmany_c2c_axis_20] = KokkosFFT::Impl::get_extents_batched(xcin3, xcout3, axes_type({2, 0}));
   EXPECT_TRUE( in_extents_c2c_axis_20 == ref_in_extents_r2c_axis_20 );
   EXPECT_TRUE( fft_extents_c2c_axis_20 == ref_fft_extents_r2c_axis_20 );
   EXPECT_TRUE( out_extents_c2c_axis_20 == ref_in_extents_r2c_axis_20 );
   EXPECT_EQ( howmany_c2c_axis_20, ref_howmany_r2c_axis_20 );
 
-  auto [in_extents_c2c_axis_21, out_extents_c2c_axis_21, fft_extents_c2c_axis_21, howmany_c2c_axis_21] = KokkosFFT::get_extents_batched(xcin3, xcout3, axes_type({2, 1}));
+  auto [in_extents_c2c_axis_21, out_extents_c2c_axis_21, fft_extents_c2c_axis_21, howmany_c2c_axis_21] = KokkosFFT::Impl::get_extents_batched(xcin3, xcout3, axes_type({2, 1}));
   EXPECT_TRUE( in_extents_c2c_axis_21 == ref_in_extents_r2c_axis_21 );
   EXPECT_TRUE( fft_extents_c2c_axis_21 == ref_fft_extents_r2c_axis_21 );
   EXPECT_TRUE( out_extents_c2c_axis_21 == ref_in_extents_r2c_axis_21 );
diff --git a/common/unit_test/Test_Normalization.cpp b/common/unit_test/Test_Normalization.cpp
index 3e5db8f5..09d6bae2 100644
--- a/common/unit_test/Test_Normalization.cpp
+++ b/common/unit_test/Test_Normalization.cpp
@@ -20,11 +20,11 @@ TEST(Normalization, Forward) {
     Kokkos::fence();
 
     // Backward FFT with Forward Normalization -> Do nothing
-    KokkosFFT::normalize(execution_space(), x, KOKKOS_FFT_BACKWARD, KokkosFFT::Normalization::FORWARD, len);
+    KokkosFFT::Impl::normalize(execution_space(), x, KOKKOS_FFT_BACKWARD, KokkosFFT::Normalization::FORWARD, len);
     EXPECT_TRUE( allclose(x, ref_b, 1.e-5, 1.e-12) );
 
     // Forward FFT with Forward Normalization -> 1/N normalization
-    KokkosFFT::normalize(execution_space(), x, KOKKOS_FFT_FORWARD, KokkosFFT::Normalization::FORWARD, len);
+    KokkosFFT::Impl::normalize(execution_space(), x, KOKKOS_FFT_FORWARD, KokkosFFT::Normalization::FORWARD, len);
     EXPECT_TRUE( allclose(x, ref_f, 1.e-5, 1.e-12) );
 }
 
@@ -44,11 +44,11 @@ TEST(Normalization, Backward) {
     Kokkos::fence();
 
     // Forward FFT with Backward Normalization -> Do nothing
-    KokkosFFT::normalize(execution_space(), x, KOKKOS_FFT_FORWARD, KokkosFFT::Normalization::BACKWARD, len);
+    KokkosFFT::Impl::normalize(execution_space(), x, KOKKOS_FFT_FORWARD, KokkosFFT::Normalization::BACKWARD, len);
     EXPECT_TRUE( allclose(x, ref_f, 1.e-5, 1.e-12) );
 
     // Backward FFT with Backward Normalization -> 1/N normalization
-    KokkosFFT::normalize(execution_space(), x, KOKKOS_FFT_BACKWARD, KokkosFFT::Normalization::BACKWARD, len);
+    KokkosFFT::Impl::normalize(execution_space(), x, KOKKOS_FFT_BACKWARD, KokkosFFT::Normalization::BACKWARD, len);
     EXPECT_TRUE( allclose(x, ref_b, 1.e-5, 1.e-12) );
 }
 
@@ -71,10 +71,10 @@ TEST(Normalization, Ortho) {
     Kokkos::fence();
 
     // Forward FFT with Ortho Normalization -> 1 / sqrt(N) normalization
-    KokkosFFT::normalize(execution_space(), x_f, KOKKOS_FFT_FORWARD, KokkosFFT::Normalization::ORTHO, len);
+    KokkosFFT::Impl::normalize(execution_space(), x_f, KOKKOS_FFT_FORWARD, KokkosFFT::Normalization::ORTHO, len);
     EXPECT_TRUE( allclose(x_f, ref_f, 1.e-5, 1.e-12) );
 
     // Backward FFT with Ortho Normalization -> 1 / sqrt(N) normalization
-    KokkosFFT::normalize(execution_space(), x_b, KOKKOS_FFT_BACKWARD, KokkosFFT::Normalization::ORTHO, len);
+    KokkosFFT::Impl::normalize(execution_space(), x_b, KOKKOS_FFT_BACKWARD, KokkosFFT::Normalization::ORTHO, len);
     EXPECT_TRUE( allclose(x_b, ref_b, 1.e-5, 1.e-12) );
 }
\ No newline at end of file
diff --git a/common/unit_test/Test_Transpose.cpp b/common/unit_test/Test_Transpose.cpp
index 4736d89b..3a695c70 100644
--- a/common/unit_test/Test_Transpose.cpp
+++ b/common/unit_test/Test_Transpose.cpp
@@ -13,8 +13,8 @@ void test_map_axes1d() {
   using RealView1Dtype = Kokkos::View<double*, LayoutType, execution_space>;
   RealView1Dtype x("x", len);
 
-  auto [map_axis, map_inv_axis] = KokkosFFT::get_map_axes(x, /*axis=*/0);
-  auto [map_axes, map_inv_axes] = KokkosFFT::get_map_axes(x, /*axes=*/ axes_type<1>({0}));
+  auto [map_axis, map_inv_axis] = KokkosFFT::Impl::get_map_axes(x, /*axis=*/0);
+  auto [map_axes, map_inv_axes] = KokkosFFT::Impl::get_map_axes(x, /*axes=*/ axes_type<1>({0}));
 
   axes_type<1> ref_map_axis = {0};
   axes_type<1> ref_map_axes = {0};
@@ -39,16 +39,16 @@ void test_map_axes2d() {
   using RealView2Dtype = Kokkos::View<double**, LayoutType, execution_space>;
   RealView2Dtype x("x", n0, n1);
 
-  auto [map_axis_0, map_inv_axis_0]               = KokkosFFT::get_map_axes(x, /*axis=*/0);
-  auto [map_axis_1, map_inv_axis_1]               = KokkosFFT::get_map_axes(x, /*axis=*/1);
-  auto [map_axis_minus1, map_inv_axis_minus1]     = KokkosFFT::get_map_axes(x, /*axis=*/-1);
-  auto [map_axes_0, map_inv_axes_0]               = KokkosFFT::get_map_axes(x, /*axes=*/ axes_type<1>({0}));
-  auto [map_axes_1, map_inv_axes_1]               = KokkosFFT::get_map_axes(x, /*axes=*/ axes_type<1>({1}));
-  auto [map_axes_minus1, map_inv_axes_minus1]     = KokkosFFT::get_map_axes(x, /*axes=*/ axes_type<1>({-1}));
-  auto [map_axes_0_minus1, map_inv_axes_0_minus1] = KokkosFFT::get_map_axes(x, /*axes=*/ axes_type<2>({0, -1}));
-  auto [map_axes_minus1_0, map_inv_axes_minus1_0] = KokkosFFT::get_map_axes(x, /*axes=*/ axes_type<2>({-1, 0}));
-  auto [map_axes_0_1, map_inv_axes_0_1]           = KokkosFFT::get_map_axes(x, /*axes=*/ axes_type<2>({0, 1}));
-  auto [map_axes_1_0, map_inv_axes_1_0]           = KokkosFFT::get_map_axes(x, /*axes=*/ axes_type<2>({1, 0}));
+  auto [map_axis_0, map_inv_axis_0]               = KokkosFFT::Impl::get_map_axes(x, /*axis=*/0);
+  auto [map_axis_1, map_inv_axis_1]               = KokkosFFT::Impl::get_map_axes(x, /*axis=*/1);
+  auto [map_axis_minus1, map_inv_axis_minus1]     = KokkosFFT::Impl::get_map_axes(x, /*axis=*/-1);
+  auto [map_axes_0, map_inv_axes_0]               = KokkosFFT::Impl::get_map_axes(x, /*axes=*/ axes_type<1>({0}));
+  auto [map_axes_1, map_inv_axes_1]               = KokkosFFT::Impl::get_map_axes(x, /*axes=*/ axes_type<1>({1}));
+  auto [map_axes_minus1, map_inv_axes_minus1]     = KokkosFFT::Impl::get_map_axes(x, /*axes=*/ axes_type<1>({-1}));
+  auto [map_axes_0_minus1, map_inv_axes_0_minus1] = KokkosFFT::Impl::get_map_axes(x, /*axes=*/ axes_type<2>({0, -1}));
+  auto [map_axes_minus1_0, map_inv_axes_minus1_0] = KokkosFFT::Impl::get_map_axes(x, /*axes=*/ axes_type<2>({-1, 0}));
+  auto [map_axes_0_1, map_inv_axes_0_1]           = KokkosFFT::Impl::get_map_axes(x, /*axes=*/ axes_type<2>({0, 1}));
+  auto [map_axes_1_0, map_inv_axes_1_0]           = KokkosFFT::Impl::get_map_axes(x, /*axes=*/ axes_type<2>({1, 0}));
 
   axes_type<2> ref_map_axis_0, ref_map_inv_axis_0;
   axes_type<2> ref_map_axis_1, ref_map_inv_axis_1;
@@ -129,27 +129,27 @@ void test_map_axes3d() {
   using RealView3Dtype = Kokkos::View<double***, LayoutType, execution_space>;
   RealView3Dtype x("x", n0, n1, n2);
 
-  auto [map_axis_0, map_inv_axis_0]    = KokkosFFT::get_map_axes(x, 0);
-  auto [map_axis_1, map_inv_axis_1]    = KokkosFFT::get_map_axes(x, 1);
-  auto [map_axis_2, map_inv_axis_2]    = KokkosFFT::get_map_axes(x, 2);
-  auto [map_axes_0, map_inv_axes_0]    = KokkosFFT::get_map_axes(x, axes_type<1>({0}));
-  auto [map_axes_1, map_inv_axes_1]    = KokkosFFT::get_map_axes(x, axes_type<1>({1}));
-  auto [map_axes_2, map_inv_axes_2]    = KokkosFFT::get_map_axes(x, axes_type<1>({2}));
+  auto [map_axis_0, map_inv_axis_0]    = KokkosFFT::Impl::get_map_axes(x, 0);
+  auto [map_axis_1, map_inv_axis_1]    = KokkosFFT::Impl::get_map_axes(x, 1);
+  auto [map_axis_2, map_inv_axis_2]    = KokkosFFT::Impl::get_map_axes(x, 2);
+  auto [map_axes_0, map_inv_axes_0]    = KokkosFFT::Impl::get_map_axes(x, axes_type<1>({0}));
+  auto [map_axes_1, map_inv_axes_1]    = KokkosFFT::Impl::get_map_axes(x, axes_type<1>({1}));
+  auto [map_axes_2, map_inv_axes_2]    = KokkosFFT::Impl::get_map_axes(x, axes_type<1>({2}));
 
-  auto [map_axes_0_1, map_inv_axes_0_1] = KokkosFFT::get_map_axes(x, axes_type<2>({0, 1}));
-  auto [map_axes_0_2, map_inv_axes_0_2] = KokkosFFT::get_map_axes(x, axes_type<2>({0, 2}));
-  auto [map_axes_1_0, map_inv_axes_1_0] = KokkosFFT::get_map_axes(x, axes_type<2>({1, 0}));
-  auto [map_axes_1_2, map_inv_axes_1_2] = KokkosFFT::get_map_axes(x, axes_type<2>({1, 2}));
-  auto [map_axes_2_0, map_inv_axes_2_0] = KokkosFFT::get_map_axes(x, axes_type<2>({2, 0}));
-  auto [map_axes_2_1, map_inv_axes_2_1] = KokkosFFT::get_map_axes(x, axes_type<2>({2, 1}));
+  auto [map_axes_0_1, map_inv_axes_0_1] = KokkosFFT::Impl::get_map_axes(x, axes_type<2>({0, 1}));
+  auto [map_axes_0_2, map_inv_axes_0_2] = KokkosFFT::Impl::get_map_axes(x, axes_type<2>({0, 2}));
+  auto [map_axes_1_0, map_inv_axes_1_0] = KokkosFFT::Impl::get_map_axes(x, axes_type<2>({1, 0}));
+  auto [map_axes_1_2, map_inv_axes_1_2] = KokkosFFT::Impl::get_map_axes(x, axes_type<2>({1, 2}));
+  auto [map_axes_2_0, map_inv_axes_2_0] = KokkosFFT::Impl::get_map_axes(x, axes_type<2>({2, 0}));
+  auto [map_axes_2_1, map_inv_axes_2_1] = KokkosFFT::Impl::get_map_axes(x, axes_type<2>({2, 1}));
 
-  auto [map_axes_0_1_2, map_inv_axes_0_1_2] = KokkosFFT::get_map_axes(x, axes_type<3>({0, 1, 2}));
-  auto [map_axes_0_2_1, map_inv_axes_0_2_1] = KokkosFFT::get_map_axes(x, axes_type<3>({0, 2, 1}));
+  auto [map_axes_0_1_2, map_inv_axes_0_1_2] = KokkosFFT::Impl::get_map_axes(x, axes_type<3>({0, 1, 2}));
+  auto [map_axes_0_2_1, map_inv_axes_0_2_1] = KokkosFFT::Impl::get_map_axes(x, axes_type<3>({0, 2, 1}));
 
-  auto [map_axes_1_0_2, map_inv_axes_1_0_2] = KokkosFFT::get_map_axes(x, axes_type<3>({1, 0, 2}));
-  auto [map_axes_1_2_0, map_inv_axes_1_2_0] = KokkosFFT::get_map_axes(x, axes_type<3>({1, 2, 0}));
-  auto [map_axes_2_0_1, map_inv_axes_2_0_1] = KokkosFFT::get_map_axes(x, axes_type<3>({2, 0, 1}));
-  auto [map_axes_2_1_0, map_inv_axes_2_1_0] = KokkosFFT::get_map_axes(x, axes_type<3>({2, 1, 0}));
+  auto [map_axes_1_0_2, map_inv_axes_1_0_2] = KokkosFFT::Impl::get_map_axes(x, axes_type<3>({1, 0, 2}));
+  auto [map_axes_1_2_0, map_inv_axes_1_2_0] = KokkosFFT::Impl::get_map_axes(x, axes_type<3>({1, 2, 0}));
+  auto [map_axes_2_0_1, map_inv_axes_2_0_1] = KokkosFFT::Impl::get_map_axes(x, axes_type<3>({2, 0, 1}));
+  auto [map_axes_2_1_0, map_inv_axes_2_1_0] = KokkosFFT::Impl::get_map_axes(x, axes_type<3>({2, 1, 0}));
 
   axes_type<3> ref_map_axis_0, ref_map_inv_axis_0;
   axes_type<3> ref_map_axis_1, ref_map_inv_axis_1;
@@ -289,7 +289,7 @@ void test_transpose_1d() {
   Kokkos::fence();
 
   EXPECT_THROW(
-    KokkosFFT::transpose(execution_space(), x, xt, axes_type<1>({0})),
+    KokkosFFT::Impl::transpose(execution_space(), x, xt, axes_type<1>({0})),
     std::runtime_error
   );
 }
@@ -325,11 +325,11 @@ TEST(Transpose, 2DLeftView) {
   Kokkos::fence();
 
   EXPECT_THROW(
-    KokkosFFT::transpose(execution_space(), x, xt_axis0, axes_type<2>({0, 1})), // xt is identical to x
+    KokkosFFT::Impl::transpose(execution_space(), x, xt_axis0, axes_type<2>({0, 1})), // xt is identical to x
     std::runtime_error
   );
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis1, axes_type<2>({1, 0})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis1, axes_type<2>({1, 0})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis1, ref_axis1, 1.e-5, 1.e-12) );
 }
 
@@ -354,11 +354,11 @@ TEST(Transpose, 2DRightView) {
   Kokkos::deep_copy(ref_axis0, h_ref_axis0);
   Kokkos::fence();
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis0, axes_type<2>({1, 0})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis0, axes_type<2>({1, 0})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis0, ref_axis0, 1.e-5, 1.e-12) );
 
   EXPECT_THROW(
-    KokkosFFT::transpose(execution_space(), x, xt_axis1, axes_type<2>({0, 1})), // xt is identical to x
+    KokkosFFT::Impl::transpose(execution_space(), x, xt_axis1, axes_type<2>({0, 1})), // xt is identical to x
     std::runtime_error
   );
 }
@@ -404,23 +404,23 @@ TEST(Transpose, 3DLeftView) {
   Kokkos::fence();
 
   EXPECT_THROW(
-    KokkosFFT::transpose(execution_space(), x, xt_axis012, axes_type<3>({0, 1, 2})), // xt is identical to x
+    KokkosFFT::Impl::transpose(execution_space(), x, xt_axis012, axes_type<3>({0, 1, 2})), // xt is identical to x
     std::runtime_error
   );
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis021, axes_type<3>({0, 2, 1})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis021, axes_type<3>({0, 2, 1})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis021, ref_axis021, 1.e-5, 1.e-12) );
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis102, axes_type<3>({1, 0, 2})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis102, axes_type<3>({1, 0, 2})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis102, ref_axis102, 1.e-5, 1.e-12) );
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis120, axes_type<3>({1, 2, 0})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis120, axes_type<3>({1, 2, 0})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis120, ref_axis120, 1.e-5, 1.e-12) );
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis201, axes_type<3>({2, 0, 1})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis201, axes_type<3>({2, 0, 1})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis201, ref_axis201, 1.e-5, 1.e-12) );
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis210, axes_type<3>({2, 1, 0})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis210, axes_type<3>({2, 1, 0})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis210, ref_axis210, 1.e-5, 1.e-12) );
 }
 
@@ -465,22 +465,22 @@ TEST(Transpose, 3DRightView) {
   Kokkos::fence();
 
   EXPECT_THROW(
-    KokkosFFT::transpose(execution_space(), x, xt_axis012, axes_type<3>({0, 1, 2})), // xt is identical to x
+    KokkosFFT::Impl::transpose(execution_space(), x, xt_axis012, axes_type<3>({0, 1, 2})), // xt is identical to x
     std::runtime_error
   );
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis021, axes_type<3>({0, 2, 1})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis021, axes_type<3>({0, 2, 1})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis021, ref_axis021, 1.e-5, 1.e-12) );
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis102, axes_type<3>({1, 0, 2})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis102, axes_type<3>({1, 0, 2})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis102, ref_axis102, 1.e-5, 1.e-12) );
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis120, axes_type<3>({1, 2, 0})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis120, axes_type<3>({1, 2, 0})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis120, ref_axis120, 1.e-5, 1.e-12) );
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis201, axes_type<3>({2, 0, 1})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis201, axes_type<3>({2, 0, 1})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis201, ref_axis201, 1.e-5, 1.e-12) );
 
-  KokkosFFT::transpose(execution_space(), x, xt_axis210, axes_type<3>({2, 1, 0})); // xt is the transpose of x
+  KokkosFFT::Impl::transpose(execution_space(), x, xt_axis210, axes_type<3>({2, 1, 0})); // xt is the transpose of x
   EXPECT_TRUE( allclose(xt_axis210, ref_axis210, 1.e-5, 1.e-12) );
 }
\ No newline at end of file
diff --git a/common/unit_test/Test_Utils.cpp b/common/unit_test/Test_Utils.cpp
index 38dce978..9cd60bcd 100644
--- a/common/unit_test/Test_Utils.cpp
+++ b/common/unit_test/Test_Utils.cpp
@@ -8,8 +8,8 @@ void test_convert_negative_axes_1d() {
   using RealView1Dtype = Kokkos::View<double*, LayoutType, execution_space>;
   RealView1Dtype x("x", len);
 
-  int converted_axis_0 = KokkosFFT::convert_negative_axis(x, /*axis=*/0);
-  int converted_axis_minus1 = KokkosFFT::convert_negative_axis(x, /*axis=*/-1);
+  int converted_axis_0 = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/0);
+  int converted_axis_minus1 = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/-1);
 
   int ref_converted_axis_0 = 0;
   int ref_converted_axis_minus1 = 0;
@@ -32,9 +32,9 @@ void test_convert_negative_axes_2d() {
   using RealView2Dtype = Kokkos::View<double**, LayoutType, execution_space>;
   RealView2Dtype x("x", n0, n1);
 
-  int converted_axis_0      = KokkosFFT::convert_negative_axis(x, /*axis=*/0);
-  int converted_axis_1      = KokkosFFT::convert_negative_axis(x, /*axis=*/1);
-  int converted_axis_minus1 = KokkosFFT::convert_negative_axis(x, /*axis=*/-1);
+  int converted_axis_0      = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/0);
+  int converted_axis_1      = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/1);
+  int converted_axis_minus1 = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/-1);
 
   int ref_converted_axis_0      = 0;
   int ref_converted_axis_1      = 1;
@@ -59,11 +59,11 @@ void test_convert_negative_axes_3d() {
   using RealView3Dtype = Kokkos::View<double***, LayoutType, execution_space>;
   RealView3Dtype x("x", n0, n1, n2);
 
-  int converted_axis_0      = KokkosFFT::convert_negative_axis(x, /*axis=*/0);
-  int converted_axis_1      = KokkosFFT::convert_negative_axis(x, /*axis=*/1);
-  int converted_axis_2      = KokkosFFT::convert_negative_axis(x, /*axis=*/2);
-  int converted_axis_minus1 = KokkosFFT::convert_negative_axis(x, /*axis=*/-1);
-  int converted_axis_minus2 = KokkosFFT::convert_negative_axis(x, /*axis=*/-2);
+  int converted_axis_0      = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/0);
+  int converted_axis_1      = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/1);
+  int converted_axis_2      = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/2);
+  int converted_axis_minus1 = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/-1);
+  int converted_axis_minus2 = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/-2);
 
   int ref_converted_axis_0      = 0;
   int ref_converted_axis_1      = 1;
@@ -92,13 +92,13 @@ void test_convert_negative_axes_4d() {
   using RealView4Dtype = Kokkos::View<double****, LayoutType, execution_space>;
   RealView4Dtype x("x", n0, n1, n2, n3);
 
-  int converted_axis_0      = KokkosFFT::convert_negative_axis(x, /*axis=*/0);
-  int converted_axis_1      = KokkosFFT::convert_negative_axis(x, /*axis=*/1);
-  int converted_axis_2      = KokkosFFT::convert_negative_axis(x, /*axis=*/2);
-  int converted_axis_3      = KokkosFFT::convert_negative_axis(x, /*axis=*/3);
-  int converted_axis_minus1 = KokkosFFT::convert_negative_axis(x, /*axis=*/-1);
-  int converted_axis_minus2 = KokkosFFT::convert_negative_axis(x, /*axis=*/-2);
-  int converted_axis_minus3 = KokkosFFT::convert_negative_axis(x, /*axis=*/-3);
+  int converted_axis_0      = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/0);
+  int converted_axis_1      = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/1);
+  int converted_axis_2      = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/2);
+  int converted_axis_3      = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/3);
+  int converted_axis_minus1 = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/-1);
+  int converted_axis_minus2 = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/-2);
+  int converted_axis_minus3 = KokkosFFT::Impl::convert_negative_axis(x, /*axis=*/-3);
 
   int ref_converted_axis_0      = 0;
   int ref_converted_axis_1      = 1;
@@ -127,11 +127,11 @@ TEST(ConvertNegativeAxis, 4DRightView) {
 
 TEST(IsTransposeNeeded, 1Dto3D) {
   std::array<int, 1> map1D ={0};
-  EXPECT_FALSE( KokkosFFT::is_transpose_needed(map1D) );
+  EXPECT_FALSE( KokkosFFT::Impl::is_transpose_needed(map1D) );
 
   std::array<int, 2> map2D ={0, 1}, map2D_axis0 = {1, 0};
-  EXPECT_FALSE( KokkosFFT::is_transpose_needed(map2D) );
-  EXPECT_TRUE( KokkosFFT::is_transpose_needed(map2D_axis0) );
+  EXPECT_FALSE( KokkosFFT::Impl::is_transpose_needed(map2D) );
+  EXPECT_TRUE( KokkosFFT::Impl::is_transpose_needed(map2D_axis0) );
 
   std::array<int, 3> map3D =     {0, 1, 2};
   std::array<int, 3> map3D_021 = {0, 2, 1};
@@ -140,30 +140,30 @@ TEST(IsTransposeNeeded, 1Dto3D) {
   std::array<int, 3> map3D_201 = {2, 0, 1};
   std::array<int, 3> map3D_210 = {2, 1, 0};
 
-  EXPECT_FALSE( KokkosFFT::is_transpose_needed(map3D) );
-  EXPECT_TRUE( KokkosFFT::is_transpose_needed(map3D_021) );
-  EXPECT_TRUE( KokkosFFT::is_transpose_needed(map3D_102) );
-  EXPECT_TRUE( KokkosFFT::is_transpose_needed(map3D_120) );
-  EXPECT_TRUE( KokkosFFT::is_transpose_needed(map3D_201) );
-  EXPECT_TRUE( KokkosFFT::is_transpose_needed(map3D_210) );
+  EXPECT_FALSE( KokkosFFT::Impl::is_transpose_needed(map3D) );
+  EXPECT_TRUE( KokkosFFT::Impl::is_transpose_needed(map3D_021) );
+  EXPECT_TRUE( KokkosFFT::Impl::is_transpose_needed(map3D_102) );
+  EXPECT_TRUE( KokkosFFT::Impl::is_transpose_needed(map3D_120) );
+  EXPECT_TRUE( KokkosFFT::Impl::is_transpose_needed(map3D_201) );
+  EXPECT_TRUE( KokkosFFT::Impl::is_transpose_needed(map3D_210) );
 }
 
 TEST(GetIndex, Vectors) {
   std::vector<int> v = {0, 1, 4, 2, 3};
 
-  EXPECT_EQ( KokkosFFT::get_index(v, 0), 0 );
-  EXPECT_EQ( KokkosFFT::get_index(v, 1), 1 );
-  EXPECT_EQ( KokkosFFT::get_index(v, 2), 3 );
-  EXPECT_EQ( KokkosFFT::get_index(v, 3), 4 );
-  EXPECT_EQ( KokkosFFT::get_index(v, 4), 2 );
+  EXPECT_EQ( KokkosFFT::Impl::get_index(v, 0), 0 );
+  EXPECT_EQ( KokkosFFT::Impl::get_index(v, 1), 1 );
+  EXPECT_EQ( KokkosFFT::Impl::get_index(v, 2), 3 );
+  EXPECT_EQ( KokkosFFT::Impl::get_index(v, 3), 4 );
+  EXPECT_EQ( KokkosFFT::Impl::get_index(v, 4), 2 );
 
   EXPECT_THROW(
-    KokkosFFT::get_index(v, -1),
+    KokkosFFT::Impl::get_index(v, -1),
     std::runtime_error
   );
 
   EXPECT_THROW(
-    KokkosFFT::get_index(v, 5),
+    KokkosFFT::Impl::get_index(v, 5),
     std::runtime_error
   );
 }
\ No newline at end of file

From e6a9122f2865de07a101d805ec899300cd764905 Mon Sep 17 00:00:00 2001
From: Yuuichi Asahi <y.asahi@nr.titech.ac.jp>
Date: Wed, 20 Dec 2023 19:38:09 +0900
Subject: [PATCH 2/2] Introduce Impl name space to functions defined in fft

---
 fft/src/KokkosFFT_Cuda_plans.hpp       |  39 ++---
 fft/src/KokkosFFT_Cuda_transform.hpp   |   4 +-
 fft/src/KokkosFFT_HIP_plans.hpp        |  39 ++---
 fft/src/KokkosFFT_HIP_transform.hpp    |   4 +-
 fft/src/KokkosFFT_OpenMP_plans.hpp     |  54 +++---
 fft/src/KokkosFFT_OpenMP_transform.hpp |   4 +-
 fft/src/KokkosFFT_Plans.hpp            |  80 ++-------
 fft/src/KokkosFFT_Transform.hpp        | 138 ++++++++-------
 fft/unit_test/Test_Plans.cpp           | 232 ++++++++-----------------
 fft/unit_test/Test_Transform.cpp       |   8 +-
 10 files changed, 231 insertions(+), 371 deletions(-)

diff --git a/fft/src/KokkosFFT_Cuda_plans.hpp b/fft/src/KokkosFFT_Cuda_plans.hpp
index 8cf8a031..30268189 100644
--- a/fft/src/KokkosFFT_Cuda_plans.hpp
+++ b/fft/src/KokkosFFT_Cuda_plans.hpp
@@ -6,8 +6,9 @@
 #include "KokkosFFT_layouts.hpp"
 
 namespace KokkosFFT {
+namespace Impl {
   // 1D transform
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType,
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType,
             std::enable_if_t<InViewType::rank()==1, std::nullptr_t> = nullptr>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType direction) {
     static_assert(Kokkos::is_view<InViewType>::value,
@@ -24,8 +25,8 @@ namespace KokkosFFT {
     const int batch = 1;
     const int axis = 0;
 
-    auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents] = get_extents(in, out, axis);
+    auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents] = KokkosFFT::Impl::get_extents(in, out, axis);
     const int nx = fft_extents.at(0);
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
 
@@ -36,7 +37,7 @@ namespace KokkosFFT {
   }
 
   // 2D transform
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType,
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType,
             std::enable_if_t<InViewType::rank()==2, std::nullptr_t> = nullptr>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType direction) {
     static_assert(Kokkos::is_view<InViewType>::value,
@@ -51,8 +52,8 @@ namespace KokkosFFT {
       throw std::runtime_error("cufftCreate failed");
 
     const int axis = 0;
-    auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents] = get_extents(in, out, axis);
+    auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents] = KokkosFFT::Impl::get_extents(in, out, axis);
     const int nx = fft_extents.at(0), ny = fft_extents.at(1);
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
 
@@ -63,7 +64,7 @@ namespace KokkosFFT {
   }
 
   // 3D transform
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType,
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType,
             std::enable_if_t<InViewType::rank()==3, std::nullptr_t> = nullptr>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType direction) {
     static_assert(Kokkos::is_view<InViewType>::value,
@@ -79,8 +80,8 @@ namespace KokkosFFT {
 
     const int axis = 0;
 
-    auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents] = get_extents(in, out, axis);
+    auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents] = KokkosFFT::Impl::get_extents(in, out, axis);
 
     const int nx = fft_extents.at(0), ny = fft_extents.at(1), nz = fft_extents.at(2);
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
@@ -92,7 +93,7 @@ namespace KokkosFFT {
   }
 
   // ND transform
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType,
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType,
             std::enable_if_t< std::isgreater(InViewType::rank(), 3), std::nullptr_t> = nullptr>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType direction) {
     static_assert(Kokkos::is_view<InViewType>::value,
@@ -109,8 +110,8 @@ namespace KokkosFFT {
     const int rank = InViewType::rank();
     const int batch = 1;
     const int axis = 0;
-    auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents] = get_extents(in, out, axis);
+    auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents] = KokkosFFT::Impl::get_extents(in, out, axis);
     int idist = std::accumulate(in_extents.begin(), in_extents.end(), 1, std::multiplies<>());
     int odist = std::accumulate(out_extents.begin(), out_extents.end(), 1, std::multiplies<>());
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
@@ -133,7 +134,7 @@ namespace KokkosFFT {
   }
 
   // batched transform, over ND Views
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, std::size_t fft_rank=1>
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType, std::size_t fft_rank=1>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType direction, axis_type<fft_rank> axes) {
     static_assert(Kokkos::is_view<InViewType>::value,
                 "KokkosFFT::_create: InViewType is not a Kokkos::View.");
@@ -145,15 +146,12 @@ namespace KokkosFFT {
     static_assert(InViewType::rank() >= fft_rank,
                   "KokkosFFT::_create: Rank of View must be larger than Rank of FFT.");
     const int rank = fft_rank;
-    constexpr auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents, howmany] = get_extents_batched(in, out, axes);
+    constexpr auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents, howmany] = KokkosFFT::Impl::get_extents_batched(in, out, axes);
     int idist = std::accumulate(in_extents.begin(), in_extents.end(), 1, std::multiplies<>());
     int odist = std::accumulate(out_extents.begin(), out_extents.end(), 1, std::multiplies<>());
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
 
-    auto* idata = reinterpret_cast<typename fft_data_type<in_value_type>::type*>(in.data());
-    auto* odata = reinterpret_cast<typename fft_data_type<out_value_type>::type*>(out.data());
-
     // For the moment, considering the contiguous layout only
     int istride = 1, ostride = 1;
 
@@ -180,9 +178,10 @@ namespace KokkosFFT {
   }
 
   template <typename T>
-  void _destroy(typename FFTPlanType<T>::type& plan) {
+  void _destroy(typename KokkosFFT::Impl::FFTPlanType<T>::type& plan) {
     cufftDestroy(plan);
   }
-};
+} // namespace Impl
+}; // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/fft/src/KokkosFFT_Cuda_transform.hpp b/fft/src/KokkosFFT_Cuda_transform.hpp
index e7643d9e..8250963e 100644
--- a/fft/src/KokkosFFT_Cuda_transform.hpp
+++ b/fft/src/KokkosFFT_Cuda_transform.hpp
@@ -4,6 +4,7 @@
 #include <cufft.h>
 
 namespace KokkosFFT {
+namespace Impl {
   void _exec(cufftHandle plan, cufftReal* idata, cufftComplex* odata, [[maybe_unused]] int direction) {
     cufftResult cufft_rt = cufftExecR2C(plan, idata, odata);
     if(cufft_rt != CUFFT_SUCCESS)
@@ -39,6 +40,7 @@ namespace KokkosFFT {
     if(cufft_rt != CUFFT_SUCCESS)
       throw std::runtime_error("cufftExecZ2Z failed");
   }
-};
+} // namespace Impl
+} // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/fft/src/KokkosFFT_HIP_plans.hpp b/fft/src/KokkosFFT_HIP_plans.hpp
index d0592ff3..bf6bba4a 100644
--- a/fft/src/KokkosFFT_HIP_plans.hpp
+++ b/fft/src/KokkosFFT_HIP_plans.hpp
@@ -6,8 +6,9 @@
 #include "KokkosFFT_layouts.hpp"
 
 namespace KokkosFFT {
+namespace Impl {
   // 1D transform
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType,
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType,
             std::enable_if_t<InViewType::rank()==1, std::nullptr_t> = nullptr>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType direction) {
     static_assert(Kokkos::is_view<InViewType>::value,
@@ -24,8 +25,8 @@ namespace KokkosFFT {
     const int batch = 1;
     const int axis = 0;
 
-    auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents] = get_extents(in, out, axis);
+    auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents] = KokkosFFT::Impl::get_extents(in, out, axis);
     const int nx = fft_extents.at(0);
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
 
@@ -36,7 +37,7 @@ namespace KokkosFFT {
   }
 
   // 2D transform
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType,
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType,
             std::enable_if_t<InViewType::rank()==2, std::nullptr_t> = nullptr>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType direction) {
     static_assert(Kokkos::is_view<InViewType>::value,
@@ -51,8 +52,8 @@ namespace KokkosFFT {
       throw std::runtime_error("hipfftCreate failed");
 
     const int axis = 0;
-    auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents] = get_extents(in, out, axis);
+    auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents] = KokkosFFT::Impl::get_extents(in, out, axis);
     const int nx = fft_extents.at(0), ny = fft_extents.at(1);
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
 
@@ -63,7 +64,7 @@ namespace KokkosFFT {
   }
 
   // 3D transform
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType,
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType,
             std::enable_if_t<InViewType::rank()==3, std::nullptr_t> = nullptr>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType direction) {
     static_assert(Kokkos::is_view<InViewType>::value,
@@ -80,8 +81,8 @@ namespace KokkosFFT {
     const int batch = 1;
     const int axis = 0;
 
-    auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents] = get_extents(in, out, axis);
+    auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents] = KokkosFFT::Impl::get_extents(in, out, axis);
 
     const int nx = fft_extents.at(0), ny = fft_extents.at(1), nz = fft_extents.at(2);
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
@@ -93,7 +94,7 @@ namespace KokkosFFT {
   }
 
   // ND transform
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType,
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType,
             std::enable_if_t< std::isgreater(InViewType::rank(), 3), std::nullptr_t> = nullptr>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType direction) {
     static_assert(Kokkos::is_view<InViewType>::value,
@@ -110,8 +111,8 @@ namespace KokkosFFT {
     const int rank = InViewType::rank();
     const int batch = 1;
     const int axis = 0;
-    auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents] = get_extents(in, out, axis);
+    auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents] = KokkosFFT::Impl::get_extents(in, out, axis);
     int idist = std::accumulate(in_extents.begin(), in_extents.end(), 1, std::multiplies<>());
     int odist = std::accumulate(out_extents.begin(), out_extents.end(), 1, std::multiplies<>());
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
@@ -134,7 +135,7 @@ namespace KokkosFFT {
   }
 
   // batched transform, over ND Views
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, std::size_t fft_rank=1>
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType, std::size_t fft_rank=1>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType direction, axis_type<fft_rank> axes) {
     static_assert(Kokkos::is_view<InViewType>::value,
                 "KokkosFFT::_create: InViewType is not a Kokkos::View.");
@@ -146,15 +147,12 @@ namespace KokkosFFT {
     static_assert(InViewType::rank() >= fft_rank,
                   "KokkosFFT::_create: Rank of View must be larger than Rank of FFT.");
     const int rank = fft_rank;
-    constexpr auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents, howmany] = get_extents_batched(in, out, axes);
+    constexpr auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents, howmany] = KokkosFFT::Impl::get_extents_batched(in, out, axes);
     int idist = std::accumulate(in_extents.begin(), in_extents.end(), 1, std::multiplies<>());
     int odist = std::accumulate(out_extents.begin(), out_extents.end(), 1, std::multiplies<>());
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
 
-    auto* idata = reinterpret_cast<typename fft_data_type<in_value_type>::type*>(in.data());
-    auto* odata = reinterpret_cast<typename fft_data_type<out_value_type>::type*>(out.data());
-
     // For the moment, considering the contiguous layout only
     int istride = 1, ostride = 1;
 
@@ -181,9 +179,10 @@ namespace KokkosFFT {
   }
 
   template <typename T>
-  void _destroy(typename FFTPlanType<T>::type& plan) {
+  void _destroy(typename KokkosFFT::Impl::FFTPlanType<T>::type& plan) {
     hipfftDestroy(plan);
   }
-};
+} // namespace Impl
+}; // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/fft/src/KokkosFFT_HIP_transform.hpp b/fft/src/KokkosFFT_HIP_transform.hpp
index 08bca6a4..220ab500 100644
--- a/fft/src/KokkosFFT_HIP_transform.hpp
+++ b/fft/src/KokkosFFT_HIP_transform.hpp
@@ -4,6 +4,7 @@
 #include <hipfft/hipfft.h>
 
 namespace KokkosFFT {
+namespace Impl {
   void _exec(hipfftHandle plan, hipfftReal* idata, hipfftComplex* odata, [[maybe_unused]] int direction) {
     hipfftResult hipfft_rt = hipfftExecR2C(plan, idata, odata);
     if(hipfft_rt != HIPFFT_SUCCESS)
@@ -39,6 +40,7 @@ namespace KokkosFFT {
     if(hipfft_rt != HIPFFT_SUCCESS)
       throw std::runtime_error("hipfftExecZ2Z failed");
   }
-};
+} // namespace Impl
+} // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/fft/src/KokkosFFT_OpenMP_plans.hpp b/fft/src/KokkosFFT_OpenMP_plans.hpp
index 6ad5f0e4..929ab9fa 100644
--- a/fft/src/KokkosFFT_OpenMP_plans.hpp
+++ b/fft/src/KokkosFFT_OpenMP_plans.hpp
@@ -6,6 +6,7 @@
 #include "KokkosFFT_layouts.hpp"
 
 namespace KokkosFFT {
+namespace Impl {
   template <typename ExecutionSpace, typename T>
   void _init_threads(const ExecutionSpace& exec_space) {
     int nthreads = exec_space.concurrency();
@@ -20,7 +21,7 @@ namespace KokkosFFT {
   }
 
   // ND transform
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType>
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType sign) {
     static_assert(Kokkos::is_view<InViewType>::value,
                 "KokkosFFT::_create: InViewType is not a Kokkos::View.");
@@ -29,22 +30,22 @@ namespace KokkosFFT {
     using in_value_type = typename InViewType::non_const_value_type;
     using out_value_type = typename OutViewType::non_const_value_type;
 
-    _init_threads<ExecutionSpace, real_type_t<in_value_type>>(exec_space);
+    _init_threads<ExecutionSpace, KokkosFFT::Impl::real_type_t<in_value_type>>(exec_space);
 
     const int rank = InViewType::rank();
     const int axis = -1;
     const int howmany = 1;
-    constexpr auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents] = get_extents(in, out, axis);
+    constexpr auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents] = KokkosFFT::Impl::get_extents(in, out, axis);
     int idist = std::accumulate(in_extents.begin(), in_extents.end(), 1, std::multiplies<>());
     int odist = std::accumulate(out_extents.begin(), out_extents.end(), 1, std::multiplies<>());
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
 
-    auto* idata = reinterpret_cast<typename fft_data_type<in_value_type>::type*>(in.data());
-    auto* odata = reinterpret_cast<typename fft_data_type<out_value_type>::type*>(out.data());
+    auto* idata = reinterpret_cast<typename KokkosFFT::Impl::fft_data_type<in_value_type>::type*>(in.data());
+    auto* odata = reinterpret_cast<typename KokkosFFT::Impl::fft_data_type<out_value_type>::type*>(out.data());
     int istride = 1, ostride = 1;
 
-    if constexpr(type == TransformType::R2C) {
+    if constexpr(type == KokkosFFT::Impl::TransformType::R2C) {
       plan = fftwf_plan_many_dft_r2c(rank,
                                      fft_extents.data(),
                                      howmany,
@@ -58,7 +59,7 @@ namespace KokkosFFT {
                                      odist,
                                      FFTW_ESTIMATE
                                     );
-    } else if constexpr(type == TransformType::D2Z) {
+    } else if constexpr(type == KokkosFFT::Impl::TransformType::D2Z) {
       plan = fftw_plan_many_dft_r2c(rank,
                                     fft_extents.data(),
                                     howmany,
@@ -72,7 +73,7 @@ namespace KokkosFFT {
                                     odist,
                                     FFTW_ESTIMATE
                                    );
-    } else if constexpr(type == TransformType::C2R) {
+    } else if constexpr(type == KokkosFFT::Impl::TransformType::C2R) {
       plan = fftwf_plan_many_dft_c2r(rank,
                                      fft_extents.data(),
                                      howmany,
@@ -86,7 +87,7 @@ namespace KokkosFFT {
                                      odist,
                                      FFTW_ESTIMATE
                                     );
-    } else if constexpr(type == TransformType::Z2D) {
+    } else if constexpr(type == KokkosFFT::Impl::TransformType::Z2D) {
       plan = fftw_plan_many_dft_c2r(rank,
                                     fft_extents.data(),
                                     howmany,
@@ -100,7 +101,7 @@ namespace KokkosFFT {
                                     odist,
                                     FFTW_ESTIMATE
                                    );
-    } else if constexpr(type == TransformType::C2C) {
+    } else if constexpr(type == KokkosFFT::Impl::TransformType::C2C) {
       plan = fftwf_plan_many_dft(rank,
                                  fft_extents.data(),
                                  howmany,
@@ -115,7 +116,7 @@ namespace KokkosFFT {
                                  sign,
                                  FFTW_ESTIMATE
                                 );
-    } else if constexpr(type == TransformType::Z2Z) {
+    } else if constexpr(type == KokkosFFT::Impl::TransformType::Z2Z) {
       plan = fftw_plan_many_dft(rank,
                                 fft_extents.data(),
                                 howmany,
@@ -136,7 +137,7 @@ namespace KokkosFFT {
   }
 
   // batched transform, over ND Views
-  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, std::size_t fft_rank=1>
+  template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType, typename FFTDirectionType, std::size_t fft_rank=1>
   auto _create(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, const OutViewType& out, [[maybe_unused]] FFTDirectionType sign, axis_type<fft_rank> axes) {
     static_assert(Kokkos::is_view<InViewType>::value,
                   "KokkosFFT::_create: InViewType is not a Kokkos::View.");
@@ -149,21 +150,21 @@ namespace KokkosFFT {
                   "KokkosFFT::_create: Rank of View must be larger than Rank of FFT.");
     const int rank = fft_rank;
 
-    _init_threads<ExecutionSpace, real_type_t<in_value_type>>(exec_space);
+    _init_threads<ExecutionSpace, KokkosFFT::Impl::real_type_t<in_value_type>>(exec_space);
 
-    constexpr auto type = transform_type<in_value_type, out_value_type>::type();
-    auto [in_extents, out_extents, fft_extents, howmany] = get_extents_batched(in, out, axes);
+    constexpr auto type = KokkosFFT::Impl::transform_type<in_value_type, out_value_type>::type();
+    auto [in_extents, out_extents, fft_extents, howmany] = KokkosFFT::Impl::get_extents_batched(in, out, axes);
     int idist = std::accumulate(in_extents.begin(), in_extents.end(), 1, std::multiplies<>());
     int odist = std::accumulate(out_extents.begin(), out_extents.end(), 1, std::multiplies<>());
     int fft_size = std::accumulate(fft_extents.begin(), fft_extents.end(), 1, std::multiplies<>());
 
-    auto* idata = reinterpret_cast<typename fft_data_type<in_value_type>::type*>(in.data());
-    auto* odata = reinterpret_cast<typename fft_data_type<out_value_type>::type*>(out.data());
+    auto* idata = reinterpret_cast<typename KokkosFFT::Impl::fft_data_type<in_value_type>::type*>(in.data());
+    auto* odata = reinterpret_cast<typename KokkosFFT::Impl::fft_data_type<out_value_type>::type*>(out.data());
 
     // For the moment, considering the contiguous layout only
     int istride = 1, ostride = 1;
 
-    if constexpr(type == TransformType::R2C) {
+    if constexpr(type == KokkosFFT::Impl::TransformType::R2C) {
       plan = fftwf_plan_many_dft_r2c(rank,
                                      fft_extents.data(),
                                      howmany,
@@ -177,7 +178,7 @@ namespace KokkosFFT {
                                      odist,
                                      FFTW_ESTIMATE
                                     );
-    } else if constexpr(type == TransformType::D2Z) {
+    } else if constexpr(type == KokkosFFT::Impl::TransformType::D2Z) {
       plan = fftw_plan_many_dft_r2c(rank,
                                     fft_extents.data(),
                                     howmany,
@@ -191,7 +192,7 @@ namespace KokkosFFT {
                                     odist,
                                     FFTW_ESTIMATE
                                    );
-    } else if constexpr(type == TransformType::C2R) {
+    } else if constexpr(type == KokkosFFT::Impl::TransformType::C2R) {
       plan = fftwf_plan_many_dft_c2r(rank,
                                      fft_extents.data(),
                                      howmany,
@@ -205,7 +206,7 @@ namespace KokkosFFT {
                                      odist,
                                      FFTW_ESTIMATE
                                     );
-    } else if constexpr(type == TransformType::Z2D) {
+    } else if constexpr(type == KokkosFFT::Impl::TransformType::Z2D) {
       plan = fftw_plan_many_dft_c2r(rank,
                                     fft_extents.data(),
                                     howmany,
@@ -219,7 +220,7 @@ namespace KokkosFFT {
                                     odist,
                                     FFTW_ESTIMATE
                                    );
-    } else if constexpr(type == TransformType::C2C) {
+    } else if constexpr(type == KokkosFFT::Impl::TransformType::C2C) {
       plan = fftwf_plan_many_dft(rank,
                                  fft_extents.data(),
                                  howmany,
@@ -234,7 +235,7 @@ namespace KokkosFFT {
                                  sign,
                                  FFTW_ESTIMATE
                                 );
-    } else if constexpr(type == TransformType::Z2Z) {
+    } else if constexpr(type == KokkosFFT::Impl::TransformType::Z2Z) {
       plan = fftw_plan_many_dft(rank,
                                 fft_extents.data(),
                                 howmany,
@@ -255,13 +256,14 @@ namespace KokkosFFT {
   }
 
   template <typename T>
-  void _destroy(typename FFTPlanType<T>::type& plan) {
+  void _destroy(typename KokkosFFT::Impl::FFTPlanType<T>::type& plan) {
     if constexpr (std::is_same_v<T, float>) {
       fftwf_destroy_plan(plan);
     } else {
       fftw_destroy_plan(plan);
     }
   }
-};
+} // namespace Impl
+}; // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/fft/src/KokkosFFT_OpenMP_transform.hpp b/fft/src/KokkosFFT_OpenMP_transform.hpp
index 18152d34..9c646061 100644
--- a/fft/src/KokkosFFT_OpenMP_transform.hpp
+++ b/fft/src/KokkosFFT_OpenMP_transform.hpp
@@ -4,6 +4,7 @@
 #include <fftw3.h>
 
 namespace KokkosFFT {
+namespace Impl {
   template <typename PlanType>
   void _exec(PlanType plan, float* idata, fftwf_complex* odata, [[maybe_unused]] int direction) {
     fftwf_execute_dft_r2c(plan, idata, odata);
@@ -33,6 +34,7 @@ namespace KokkosFFT {
   void _exec(PlanType plan, fftw_complex* idata, fftw_complex* odata, [[maybe_unused]] int direction) {
     fftw_execute_dft(plan, idata, odata);
   }
-};
+} // namespace Impl
+} // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/fft/src/KokkosFFT_Plans.hpp b/fft/src/KokkosFFT_Plans.hpp
index 44ec4ad4..e3915bde 100644
--- a/fft/src/KokkosFFT_Plans.hpp
+++ b/fft/src/KokkosFFT_Plans.hpp
@@ -24,12 +24,13 @@
 #endif
 
 namespace KokkosFFT {
+namespace Impl {
   template <typename ExecutionSpace, typename InViewType, typename OutViewType, std::size_t DIM = 1>
   class Plan {
     using in_value_type = typename InViewType::non_const_value_type;
     using out_value_type = typename OutViewType::non_const_value_type;
-    using float_type = real_type_t<in_value_type>;
-    using fft_plan_type = typename FFTPlanType< float_type >::type;
+    using float_type = KokkosFFT::Impl::real_type_t<in_value_type>;
+    using fft_plan_type = typename KokkosFFT::Impl::FFTPlanType< float_type >::type;
     using fft_size_type = std::size_t;
     using map_type = axis_type<InViewType::rank()>;
     using nonConstInViewType = std::remove_cv_t<InViewType>;
@@ -45,82 +46,26 @@ namespace KokkosFFT {
     nonConstOutViewType m_out_T;
 
   public:
-    explicit Plan(const ExecutionSpace& exec_space, InViewType& in, OutViewType& out) : m_fft_size(1), m_is_transpose_needed(false) {
-      // Available only for R2C or C2R
-      // For C2C, direction should be given by an user
+    explicit Plan(const ExecutionSpace& exec_space, InViewType& in, OutViewType& out, KokkosFFT::Impl::FFTDirectionType direction, int axis) : m_fft_size(1), m_is_transpose_needed(false) {
       static_assert(Kokkos::is_view<InViewType>::value,
                     "KokkosFFT::Plan: InViewType is not a Kokkos::View.");
       static_assert(Kokkos::is_view<OutViewType>::value,
                     "KokkosFFT::Plan: OutViewType is not a Kokkos::View.");
 
-      using in_value_type = typename InViewType::non_const_value_type;
-      using out_value_type = typename OutViewType::non_const_value_type;
-      constexpr auto type = transform_type<in_value_type, out_value_type>::type();
-      FFTDirectionType direction;
-      if constexpr (type == KOKKOS_FFT_R2C || type == KOKKOS_FFT_D2Z) {
-        direction = KOKKOS_FFT_FORWARD;
-      } else if constexpr (type == KOKKOS_FFT_C2R || type == KOKKOS_FFT_Z2D) {
-        direction = KOKKOS_FFT_BACKWARD;
-      } else {
-        throw std::runtime_error("direction not specified for Complex to Complex transform");
-      }
-
-      m_fft_size = _create(exec_space, m_plan, in, out, direction);
-    }
-
-    explicit Plan(const ExecutionSpace& exec_space, InViewType& in, OutViewType& out, axis_type<DIM> axes) : m_fft_size(1), m_is_transpose_needed(false) {
-      // Available only for R2C or C2R
-      // For C2C, direction should be given by an user
-      static_assert(Kokkos::is_view<InViewType>::value,
-                    "KokkosFFT::Plan: InViewType is not a Kokkos::View.");
-      static_assert(Kokkos::is_view<OutViewType>::value,
-                    "KokkosFFT::Plan: OutViewType is not a Kokkos::View.");
-
-      using in_value_type = typename InViewType::non_const_value_type;
-      using out_value_type = typename OutViewType::non_const_value_type;
-      constexpr auto type = transform_type<in_value_type, out_value_type>::type();
-      FFTDirectionType direction;
-      if constexpr (type == KOKKOS_FFT_R2C || type == KOKKOS_FFT_D2Z) {
-        direction = KOKKOS_FFT_FORWARD;
-      } else if constexpr (type == KOKKOS_FFT_C2R || type == KOKKOS_FFT_Z2D) {
-        direction = KOKKOS_FFT_BACKWARD;
-      } else {
-        throw std::runtime_error("direction not specified for Complex to Complex transform");
-      }
-
-      m_fft_size = _create(exec_space, m_plan, in, out, direction, axes);
-    }
-
-    explicit Plan(const ExecutionSpace& exec_space, InViewType& in, OutViewType& out, FFTDirectionType direction) : m_fft_size(1), m_is_transpose_needed(false) {
-      static_assert(Kokkos::is_view<InViewType>::value,
-                    "KokkosFFT::Plan: InViewType is not a Kokkos::View.");
-      static_assert(Kokkos::is_view<OutViewType>::value,
-                    "KokkosFFT::Plan: OutViewType is not a Kokkos::View.");
-
-      /* Apply FFT over entire axes or along inner most directions */
-      m_fft_size = _create(exec_space, m_plan, in, out, direction);
-    }
-
-    explicit Plan(const ExecutionSpace& exec_space, InViewType& in, OutViewType& out, FFTDirectionType direction, int axis) : m_fft_size(1), m_is_transpose_needed(false) {
-      static_assert(Kokkos::is_view<InViewType>::value,
-                    "KokkosFFT::Plan: InViewType is not a Kokkos::View.");
-      static_assert(Kokkos::is_view<OutViewType>::value,
-                    "KokkosFFT::Plan: OutViewType is not a Kokkos::View.");
-
-      std::tie(m_map, m_map_inv) = KokkosFFT::get_map_axes(in, axis);
-      m_is_transpose_needed = KokkosFFT::is_transpose_needed(m_map);
-      m_fft_size = _create(exec_space, m_plan, in, out, direction, axis_type<1>{axis});
+      std::tie(m_map, m_map_inv) = KokkosFFT::Impl::get_map_axes(in, axis);
+      m_is_transpose_needed = KokkosFFT::Impl::is_transpose_needed(m_map);
+      m_fft_size = KokkosFFT::Impl::_create(exec_space, m_plan, in, out, direction, axis_type<1>{axis});
     }
 
-    explicit Plan(const ExecutionSpace& exec_space, InViewType& in, OutViewType& out, FFTDirectionType direction, axis_type<DIM> axes) : m_fft_size(1), m_is_transpose_needed(false) {
+    explicit Plan(const ExecutionSpace& exec_space, InViewType& in, OutViewType& out, KokkosFFT::Impl::FFTDirectionType direction, axis_type<DIM> axes) : m_fft_size(1), m_is_transpose_needed(false) {
       static_assert(Kokkos::is_view<InViewType>::value,
                     "KokkosFFT::Plan: InViewType is not a Kokkos::View.");
       static_assert(Kokkos::is_view<OutViewType>::value,
                     "KokkosFFT::Plan: OutViewType is not a Kokkos::View.");
 
-      std::tie(m_map, m_map_inv) = KokkosFFT::get_map_axes(in, axes);
-      m_is_transpose_needed = KokkosFFT::is_transpose_needed(m_map);
-      m_fft_size = _create(exec_space, m_plan, in, out, direction, axes);
+      std::tie(m_map, m_map_inv) = KokkosFFT::Impl::get_map_axes(in, axes);
+      m_is_transpose_needed = KokkosFFT::Impl::is_transpose_needed(m_map);
+      m_fft_size = KokkosFFT::Impl::_create(exec_space, m_plan, in, out, direction, axes);
     }
 
     ~Plan() {
@@ -135,6 +80,7 @@ namespace KokkosFFT {
     nonConstInViewType& in_T() { return m_in_T; }
     nonConstOutViewType& out_T() { return m_out_T; }
   };
-};
+} // namespace Impl
+}; // namespace KokkosFFT
 
 #endif
\ No newline at end of file
diff --git a/fft/src/KokkosFFT_Transform.hpp b/fft/src/KokkosFFT_Transform.hpp
index 6e78bc89..bf41c64e 100644
--- a/fft/src/KokkosFFT_Transform.hpp
+++ b/fft/src/KokkosFFT_Transform.hpp
@@ -25,8 +25,9 @@
   #include "KokkosFFT_OpenMP_transform.hpp"
 #endif
 
-// 1D Transform
+// General Transform Interface
 namespace KokkosFFT {
+namespace Impl {
   template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType>
   void _fft(const ExecutionSpace& exec_space, PlanType& plan, const InViewType& in, OutViewType& out, KokkosFFT::Normalization norm=KokkosFFT::Normalization::BACKWARD) {
     static_assert(Kokkos::is_view<InViewType>::value,
@@ -37,11 +38,11 @@ namespace KokkosFFT {
     using in_value_type = typename InViewType::non_const_value_type;
     using out_value_type = typename OutViewType::non_const_value_type;
 
-    auto* idata = reinterpret_cast<typename fft_data_type<in_value_type>::type*>(in.data());
-    auto* odata = reinterpret_cast<typename fft_data_type<out_value_type>::type*>(out.data());
+    auto* idata = reinterpret_cast<typename KokkosFFT::Impl::fft_data_type<in_value_type>::type*>(in.data());
+    auto* odata = reinterpret_cast<typename KokkosFFT::Impl::fft_data_type<out_value_type>::type*>(out.data());
 
-    _exec(plan.plan(), idata, odata, KOKKOS_FFT_FORWARD);
-    normalize(exec_space, out, KOKKOS_FFT_FORWARD, norm, plan.fft_size());
+    KokkosFFT::Impl::_exec(plan.plan(), idata, odata, KOKKOS_FFT_FORWARD);
+    KokkosFFT::Impl::normalize(exec_space, out, KOKKOS_FFT_FORWARD, norm, plan.fft_size());
   }
 
   template <typename ExecutionSpace, typename PlanType, typename InViewType, typename OutViewType>
@@ -54,13 +55,16 @@ namespace KokkosFFT {
     using in_value_type = typename InViewType::non_const_value_type;
     using out_value_type = typename OutViewType::non_const_value_type;
 
-    auto* idata = reinterpret_cast<typename fft_data_type<in_value_type>::type*>(in.data());
-    auto* odata = reinterpret_cast<typename fft_data_type<out_value_type>::type*>(out.data());
+    auto* idata = reinterpret_cast<typename KokkosFFT::Impl::fft_data_type<in_value_type>::type*>(in.data());
+    auto* odata = reinterpret_cast<typename KokkosFFT::Impl::fft_data_type<out_value_type>::type*>(out.data());
 
-    _exec(plan.plan(), idata, odata, KOKKOS_FFT_BACKWARD);
-    normalize(exec_space, out, KOKKOS_FFT_BACKWARD, norm, plan.fft_size());
+    KokkosFFT::Impl::_exec(plan.plan(), idata, odata, KOKKOS_FFT_BACKWARD);
+    KokkosFFT::Impl::normalize(exec_space, out, KOKKOS_FFT_BACKWARD, norm, plan.fft_size());
   }
+} // namespace Impl
+} // namespace KokkosFFT
 
+namespace KokkosFFT {
   template <typename ExecutionSpace, typename InViewType, typename OutViewType>
   void fft(const ExecutionSpace& exec_space, const InViewType& in, OutViewType& out, KokkosFFT::Normalization norm=KokkosFFT::Normalization::BACKWARD, int axis=-1) {
     static_assert(Kokkos::is_view<InViewType>::value,
@@ -80,20 +84,20 @@ namespace KokkosFFT {
                                  "KokkosFFT::fft: execution_space cannot access data in OutViewType"
     );
 
-    Plan plan(exec_space, in, out, KOKKOS_FFT_FORWARD, axis);
+    KokkosFFT::Impl::Plan plan(exec_space, in, out, KOKKOS_FFT_FORWARD, axis);
     if(plan.is_transpose_needed()) {
       InViewType in_T;
       OutViewType out_T;
 
-      KokkosFFT::transpose(exec_space, in, in_T, plan.map());
-      KokkosFFT::transpose(exec_space, out, out_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, in, in_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, out, out_T, plan.map());
 
-      _fft(exec_space, plan, in_T, out_T, norm);
+      KokkosFFT::Impl::_fft(exec_space, plan, in_T, out_T, norm);
 
-      KokkosFFT::transpose(exec_space, out_T, out, plan.map_inv());
+      KokkosFFT::Impl::transpose(exec_space, out_T, out, plan.map_inv());
 
     } else {
-      _fft(exec_space, plan, in, out, norm);
+      KokkosFFT::Impl::_fft(exec_space, plan, in, out, norm);
     }
   }
 
@@ -104,20 +108,20 @@ namespace KokkosFFT {
     static_assert(Kokkos::is_view<OutViewType>::value,
                 "KokkosFFT::ifft: OutViewType is not a Kokkos::View.");
 
-    Plan plan(exec_space, in, out, KOKKOS_FFT_BACKWARD, axis);
+    KokkosFFT::Impl::Plan plan(exec_space, in, out, KOKKOS_FFT_BACKWARD, axis);
     if(plan.is_transpose_needed()) {
       InViewType in_T;
       OutViewType out_T;
 
-      KokkosFFT::transpose(exec_space, in, in_T, plan.map());
-      KokkosFFT::transpose(exec_space, out, out_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, in, in_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, out, out_T, plan.map());
 
-      _ifft(exec_space, plan, in_T, out_T, norm);
+      KokkosFFT::Impl::_ifft(exec_space, plan, in_T, out_T, norm);
 
-      KokkosFFT::transpose(exec_space, out_T, out, plan.map_inv());
+      KokkosFFT::Impl::transpose(exec_space, out_T, out, plan.map_inv());
 
     } else {
-      _ifft(exec_space, plan, in, out, norm);
+      KokkosFFT::Impl::_ifft(exec_space, plan, in, out, norm);
     }
   }
 
@@ -133,7 +137,7 @@ namespace KokkosFFT {
 
     static_assert(std::is_floating_point<in_value_type>::value,
                   "KokkosFFT::rfft: InViewType must be real");
-    static_assert(is_complex<out_value_type>::value,
+    static_assert(KokkosFFT::Impl::is_complex<out_value_type>::value,
                   "KokkosFFT::rfft: OutViewType must be complex");
 
     fft(exec_space, in, out, norm, axis);
@@ -149,7 +153,7 @@ namespace KokkosFFT {
     using in_value_type = typename InViewType::non_const_value_type;
     using out_value_type = typename OutViewType::non_const_value_type;
 
-    static_assert(is_complex<in_value_type>::value,
+    static_assert(KokkosFFT::Impl::is_complex<in_value_type>::value,
                   "KokkosFFT::irfft: InViewType must be complex");
     static_assert(std::is_floating_point<out_value_type>::value,
                   "KokkosFFT::irfft: OutViewType must be real");
@@ -164,19 +168,19 @@ namespace KokkosFFT {
     static_assert(Kokkos::is_view<OutViewType>::value,
                 "KokkosFFT::fft2: OutViewType is not a Kokkos::View.");
 
-    Plan plan(exec_space, in, out, KOKKOS_FFT_FORWARD, axes);
+    KokkosFFT::Impl::Plan plan(exec_space, in, out, KOKKOS_FFT_FORWARD, axes);
     if(plan.is_transpose_needed()) {
       InViewType in_T;
       OutViewType out_T;
 
-      KokkosFFT::transpose(exec_space, in, in_T, plan.map());
-      KokkosFFT::transpose(exec_space, out, out_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, in, in_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, out, out_T, plan.map());
 
-      _fft(exec_space, plan, in_T, out_T, norm);
+      KokkosFFT::Impl::_fft(exec_space, plan, in_T, out_T, norm);
 
-      KokkosFFT::transpose(exec_space, out_T, out, plan.map_inv());
+      KokkosFFT::Impl::transpose(exec_space, out_T, out, plan.map_inv());
     } else {
-      _fft(exec_space, plan, in, out, norm);
+      KokkosFFT::Impl::_fft(exec_space, plan, in, out, norm);
     }
   }
 
@@ -187,19 +191,19 @@ namespace KokkosFFT {
     static_assert(Kokkos::is_view<OutViewType>::value,
                 "KokkosFFT::ifft2: OutViewType is not a Kokkos::View.");
 
-    Plan plan(exec_space, in, out, KOKKOS_FFT_BACKWARD, axes);
+    KokkosFFT::Impl::Plan plan(exec_space, in, out, KOKKOS_FFT_BACKWARD, axes);
     if(plan.is_transpose_needed()) {
       InViewType in_T;
       OutViewType out_T;
 
-      KokkosFFT::transpose(exec_space, in, in_T, plan.map());
-      KokkosFFT::transpose(exec_space, out, out_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, in, in_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, out, out_T, plan.map());
 
-      _ifft(exec_space, plan, in_T, out_T, norm);
+      KokkosFFT::Impl::_ifft(exec_space, plan, in_T, out_T, norm);
 
-      KokkosFFT::transpose(exec_space, out_T, out, plan.map_inv());
+      KokkosFFT::Impl::transpose(exec_space, out_T, out, plan.map_inv());
     } else {
-      _ifft(exec_space, plan, in, out, norm);
+      KokkosFFT::Impl::_ifft(exec_space, plan, in, out, norm);
     }
   }
 
@@ -215,7 +219,7 @@ namespace KokkosFFT {
 
     static_assert(std::is_floating_point<in_value_type>::value,
                   "KokkosFFT::rfft2: InViewType must be real");
-    static_assert(is_complex<out_value_type>::value,
+    static_assert(KokkosFFT::Impl::is_complex<out_value_type>::value,
                   "KokkosFFT::rfft2: OutViewType must be complex");
 
     fft2(exec_space, in, out, norm, axes);
@@ -231,7 +235,7 @@ namespace KokkosFFT {
     using in_value_type = typename InViewType::non_const_value_type;
     using out_value_type = typename OutViewType::non_const_value_type;
 
-    static_assert(is_complex<in_value_type>::value,
+    static_assert(KokkosFFT::Impl::is_complex<in_value_type>::value,
                   "KokkosFFT::irfft2: InViewType must be complex");
     static_assert(std::is_floating_point<out_value_type>::value,
                   "KokkosFFT::irfft2: OutViewType must be real");
@@ -249,21 +253,21 @@ namespace KokkosFFT {
     // Create a default sequence of axes {-rank, -(rank-1), ..., -1}
     constexpr std::size_t rank = InViewType::rank();
     constexpr int start = -static_cast<int>(rank);
-    axis_type<rank> axes = index_sequence<rank>(start);
+    axis_type<rank> axes = KokkosFFT::Impl::index_sequence<rank>(start);
 
-    Plan plan(exec_space, in, out, KOKKOS_FFT_FORWARD, axes);
+    KokkosFFT::Impl::Plan plan(exec_space, in, out, KOKKOS_FFT_FORWARD, axes);
     if(plan.is_transpose_needed()) {
       InViewType in_T;
       OutViewType out_T;
 
-      KokkosFFT::transpose(exec_space, in, in_T, plan.map());
-      KokkosFFT::transpose(exec_space, out, out_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, in, in_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, out, out_T, plan.map());
 
-      _fft(exec_space, plan, in_T, out_T, norm);
+      KokkosFFT::Impl::_fft(exec_space, plan, in_T, out_T, norm);
 
-      KokkosFFT::transpose(exec_space, out_T, out, plan.map_inv());
+      KokkosFFT::Impl::transpose(exec_space, out_T, out, plan.map_inv());
     } else {
-      _fft(exec_space, plan, in, out, norm);
+      KokkosFFT::Impl::_fft(exec_space, plan, in, out, norm);
     }
   }
 
@@ -274,19 +278,19 @@ namespace KokkosFFT {
     static_assert(Kokkos::is_view<OutViewType>::value,
                 "KokkosFFT::fftn: OutViewType is not a Kokkos::View.");
 
-    Plan plan(exec_space, in, out, KOKKOS_FFT_FORWARD, axes);
+    KokkosFFT::Impl::Plan plan(exec_space, in, out, KOKKOS_FFT_FORWARD, axes);
     if(plan.is_transpose_needed()) {
       InViewType in_T;
       OutViewType out_T;
 
-      KokkosFFT::transpose(exec_space, in, in_T, plan.map());
-      KokkosFFT::transpose(exec_space, out, out_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, in, in_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, out, out_T, plan.map());
 
-      _fft(exec_space, plan, in_T, out_T, norm);
+      KokkosFFT::Impl::_fft(exec_space, plan, in_T, out_T, norm);
 
-      KokkosFFT::transpose(exec_space, out_T, out, plan.map_inv());
+      KokkosFFT::Impl::transpose(exec_space, out_T, out, plan.map_inv());
     } else {
-      _fft(exec_space, plan, in, out, norm);
+      KokkosFFT::Impl::_fft(exec_space, plan, in, out, norm);
     }
   }
 
@@ -300,21 +304,21 @@ namespace KokkosFFT {
     // Create a default sequence of axes {-rank, -(rank-1), ..., -1}
     constexpr std::size_t rank = InViewType::rank();
     constexpr int start = -static_cast<int>(rank);
-    axis_type<rank> axes = index_sequence<rank>(start);
+    axis_type<rank> axes = KokkosFFT::Impl::index_sequence<rank>(start);
 
-    Plan plan(exec_space, in, out, KOKKOS_FFT_BACKWARD, axes);
+    KokkosFFT::Impl::Plan plan(exec_space, in, out, KOKKOS_FFT_BACKWARD, axes);
     if(plan.is_transpose_needed()) {
       InViewType in_T;
       OutViewType out_T;
 
-      KokkosFFT::transpose(exec_space, in, in_T, plan.map());
-      KokkosFFT::transpose(exec_space, out, out_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, in, in_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, out, out_T, plan.map());
 
-      _ifft(exec_space, plan, in_T, out_T, norm);
+      KokkosFFT::Impl::_ifft(exec_space, plan, in_T, out_T, norm);
 
-      KokkosFFT::transpose(exec_space, out_T, out, plan.map_inv());
+      KokkosFFT::Impl::transpose(exec_space, out_T, out, plan.map_inv());
     } else {
-      _ifft(exec_space, plan, in, out, norm);
+      KokkosFFT::Impl::_ifft(exec_space, plan, in, out, norm);
     }
   }
 
@@ -325,19 +329,19 @@ namespace KokkosFFT {
     static_assert(Kokkos::is_view<OutViewType>::value,
                 "KokkosFFT::ifftn: OutViewType is not a Kokkos::View.");
 
-    Plan plan(exec_space, in, out, KOKKOS_FFT_BACKWARD, axes);
+    KokkosFFT::Impl::Plan plan(exec_space, in, out, KOKKOS_FFT_BACKWARD, axes);
     if(plan.is_transpose_needed()) {
       InViewType in_T;
       OutViewType out_T;
 
-      KokkosFFT::transpose(exec_space, in, in_T, plan.map());
-      KokkosFFT::transpose(exec_space, out, out_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, in, in_T, plan.map());
+      KokkosFFT::Impl::transpose(exec_space, out, out_T, plan.map());
 
-      _ifft(exec_space, plan, in_T, out_T, norm);
+      KokkosFFT::Impl::_ifft(exec_space, plan, in_T, out_T, norm);
 
-      KokkosFFT::transpose(exec_space, out_T, out, plan.map_inv());
+      KokkosFFT::Impl::transpose(exec_space, out_T, out, plan.map_inv());
     } else {
-      _ifft(exec_space, plan, in, out, norm);
+      KokkosFFT::Impl::_ifft(exec_space, plan, in, out, norm);
     }
   }
 
@@ -353,7 +357,7 @@ namespace KokkosFFT {
 
     static_assert(std::is_floating_point<in_value_type>::value,
                   "KokkosFFT::rfftn: InViewType must be real");
-    static_assert(is_complex<out_value_type>::value,
+    static_assert(KokkosFFT::Impl::is_complex<out_value_type>::value,
                   "KokkosFFT::rfftn: OutViewType must be complex");
 
     fftn(exec_space, in, out, norm);
@@ -371,7 +375,7 @@ namespace KokkosFFT {
 
     static_assert(std::is_floating_point<in_value_type>::value,
                   "KokkosFFT::rfftn: InViewType must be real");
-    static_assert(is_complex<out_value_type>::value,
+    static_assert(KokkosFFT::Impl::is_complex<out_value_type>::value,
                   "KokkosFFT::rfftn: OutViewType must be complex");
 
     fftn(exec_space, in, out, axes, norm);
@@ -387,7 +391,7 @@ namespace KokkosFFT {
     using in_value_type = typename InViewType::non_const_value_type;
     using out_value_type = typename OutViewType::non_const_value_type;
 
-    static_assert(is_complex<in_value_type>::value,
+    static_assert(KokkosFFT::Impl::is_complex<in_value_type>::value,
                   "KokkosFFT::irfftn: InViewType must be complex");
     static_assert(std::is_floating_point<out_value_type>::value,
                   "KokkosFFT::irfftn: OutViewType must be real");
@@ -405,7 +409,7 @@ namespace KokkosFFT {
     using in_value_type = typename InViewType::non_const_value_type;
     using out_value_type = typename OutViewType::non_const_value_type;
 
-    static_assert(is_complex<in_value_type>::value,
+    static_assert(KokkosFFT::Impl::is_complex<in_value_type>::value,
                   "KokkosFFT::irfftn: InViewType must be complex");
     static_assert(std::is_floating_point<out_value_type>::value,
                   "KokkosFFT::irfftn: OutViewType must be real");
diff --git a/fft/unit_test/Test_Plans.cpp b/fft/unit_test/Test_Plans.cpp
index c15bb358..685b9c20 100644
--- a/fft/unit_test/Test_Plans.cpp
+++ b/fft/unit_test/Test_Plans.cpp
@@ -16,27 +16,16 @@ void test_plan_1dfft_1dview() {
   ComplexView1DType x_cin("x_cin", n), x_cout("x_cout", n);
 
   // R2C plan
-  KokkosFFT::Plan plan_r2c(execution_space(), x, x_c);
-  KokkosFFT::Plan plan_r2c_axis_0(execution_space(), x, x_c, /*axis=*/0);
-  KokkosFFT::Plan plan_r2c_axes_0(execution_space(), x, x_c, /*axes=*/axes_type<1>({0}));
+  KokkosFFT::Impl::Plan plan_r2c_axis_0(execution_space(), x, x_c, KOKKOS_FFT_FORWARD, /*axis=*/0);
+  KokkosFFT::Impl::Plan plan_r2c_axes_0(execution_space(), x, x_c, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<1>({0}));
 
   // C2R plan
-  KokkosFFT::Plan plan_c2r(execution_space(), x_c, x);
-  KokkosFFT::Plan plan_c2r_axis0(execution_space(), x_c, x, /*axis=*/0);
-  KokkosFFT::Plan plan_c2r_axes0(execution_space(), x_c, x, /*axes=*/axes_type<1>({0}));
+  KokkosFFT::Impl::Plan plan_c2r_axis0(execution_space(), x_c, x, KOKKOS_FFT_BACKWARD, /*axis=*/0);
+  KokkosFFT::Impl::Plan plan_c2r_axes0(execution_space(), x_c, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<1>({0}));
 
   // C2C plan
-  KokkosFFT::Plan plan_c2c_f(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD);
-  KokkosFFT::Plan plan_c2c_b(execution_space(), x_cin, x_cout, KOKKOS_FFT_BACKWARD);
-  KokkosFFT::Plan plan_c2c_f_axis0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/0);
-  KokkosFFT::Plan plan_c2c_f_axes0(execution_space(), x_cin, x_cout, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<1>({0}));
-
-  EXPECT_THROW(
-    {
-      KokkosFFT::Plan plan_c2c(execution_space(), x_cin, x_cout);
-    },
-    std::runtime_error
-  );
+  KokkosFFT::Impl::Plan plan_c2c_f_axis0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/0);
+  KokkosFFT::Impl::Plan plan_c2c_f_axes0(execution_space(), x_cin, x_cout, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<1>({0}));
 }
 
 TEST(Plans, 1DFFT_1DLeftViewFloat) {
@@ -65,41 +54,16 @@ void test_plan_2dfft_2dview() {
   ComplexView2DType x_cin("x_cin", n0, n1), x_cout("x_cout", n0, n1);
 
   // R2C plan
-  KokkosFFT::Plan plan_r2c(execution_space(), x, x_c_axis_1);
-  KokkosFFT::Plan plan_r2c_axes_0_1(execution_space(), x, x_c_axis_1, /*axes=*/axes_type<2>({0, 1}));
-  KokkosFFT::Plan plan_r2c_axes_1_0(execution_space(), x, x_c_axis_0, /*axes=*/axes_type<2>({1, 0}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_0_1(execution_space(), x, x_c_axis_1, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({0, 1}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_1_0(execution_space(), x, x_c_axis_0, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({1, 0}));
 
   // C2R plan
-  KokkosFFT::Plan plan_c2r(execution_space(), x_c_axis_1, x);
-  KokkosFFT::Plan plan_c2r_axes_0_1(execution_space(), x_c_axis_1, x, /*axes=*/axes_type<2>({0, 1}));
-  KokkosFFT::Plan plan_c2r_axes_1_0(execution_space(), x_c_axis_0, x, /*axes=*/axes_type<2>({1, 0}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_0_1(execution_space(), x_c_axis_1, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<2>({0, 1}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_1_0(execution_space(), x_c_axis_0, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<2>({1, 0}));
 
   // C2C plan
-  KokkosFFT::Plan plan_c2c_f(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD);
-  KokkosFFT::Plan plan_c2c_b(execution_space(), x_cin, x_cout, KOKKOS_FFT_BACKWARD);
-  KokkosFFT::Plan plan_c2c_f_axes_0_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({0, 1}));
-  KokkosFFT::Plan plan_c2c_f_axes_1_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({1, 0}));
-
-  EXPECT_THROW(
-    {
-      KokkosFFT::Plan plan_c2c(execution_space(), x_cin, x_cout);
-    },
-    std::runtime_error
-  );
-
-  EXPECT_THROW(
-    {
-      KokkosFFT::Plan plan_c2c_axes_0_1(execution_space(), x_cin, x_cout, /*axes=*/axes_type<2>({0, 1}));
-    },
-    std::runtime_error
-  );
-
-  EXPECT_THROW(
-    {
-      KokkosFFT::Plan plan_c2c_axes_1_0(execution_space(), x_cin, x_cout, /*axes=*/axes_type<2>({1, 0}));
-    },
-    std::runtime_error
-  );
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_0_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({0, 1}));
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_1_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({1, 0}));
 }
 
 TEST(Plans, 2DFFT_2DLeftViewFloat) {
@@ -129,42 +93,28 @@ void test_plan_3dfft_3dview() {
   ComplexView3DType x_cin("x_cin", n0, n1, n2), x_cout("x_cout", n0, n1, n2);
 
   // R2C plan
-  KokkosFFT::Plan plan_r2c_axes_0_1_2(execution_space(), x, x_c_axis_2, /*axes=*/axes_type<3>({0, 1, 2}));
-  KokkosFFT::Plan plan_r2c_axes_0_2_1(execution_space(), x, x_c_axis_1, /*axes=*/axes_type<3>({0, 2, 1}));
-  KokkosFFT::Plan plan_r2c_axes_1_0_2(execution_space(), x, x_c_axis_2, /*axes=*/axes_type<3>({1, 0, 2}));
-  KokkosFFT::Plan plan_r2c_axes_1_2_0(execution_space(), x, x_c_axis_0, /*axes=*/axes_type<3>({1, 2, 0}));
-  KokkosFFT::Plan plan_r2c_axes_2_0_1(execution_space(), x, x_c_axis_1, /*axes=*/axes_type<3>({2, 0, 1}));
-  KokkosFFT::Plan plan_r2c_axes_2_1_0(execution_space(), x, x_c_axis_0, /*axes=*/axes_type<3>({2, 1, 0}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_0_1_2(execution_space(), x, x_c_axis_2, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({0, 1, 2}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_0_2_1(execution_space(), x, x_c_axis_1, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({0, 2, 1}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_1_0_2(execution_space(), x, x_c_axis_2, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({1, 0, 2}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_1_2_0(execution_space(), x, x_c_axis_0, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({1, 2, 0}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_2_0_1(execution_space(), x, x_c_axis_1, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({2, 0, 1}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_2_1_0(execution_space(), x, x_c_axis_0, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({2, 1, 0}));
 
   // C2R plan
-  KokkosFFT::Plan plan_c2r_axes_0_1_2(execution_space(), x_c_axis_2, x, /*axes=*/axes_type<3>({0, 1, 2}));
-  KokkosFFT::Plan plan_c2r_axes_0_2_1(execution_space(), x_c_axis_1, x, /*axes=*/axes_type<3>({0, 2, 1}));
-  KokkosFFT::Plan plan_c2r_axes_1_0_2(execution_space(), x_c_axis_2, x, /*axes=*/axes_type<3>({1, 0, 2}));
-  KokkosFFT::Plan plan_c2r_axes_1_2_0(execution_space(), x_c_axis_0, x, /*axes=*/axes_type<3>({1, 2, 0}));
-  KokkosFFT::Plan plan_c2r_axes_2_0_1(execution_space(), x_c_axis_1, x, /*axes=*/axes_type<3>({2, 0, 1}));
-  KokkosFFT::Plan plan_c2r_axes_2_1_0(execution_space(), x_c_axis_0, x, /*axes=*/axes_type<3>({2, 1, 0}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_0_1_2(execution_space(), x_c_axis_2, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<3>({0, 1, 2}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_0_2_1(execution_space(), x_c_axis_1, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<3>({0, 2, 1}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_1_0_2(execution_space(), x_c_axis_2, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<3>({1, 0, 2}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_1_2_0(execution_space(), x_c_axis_0, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<3>({1, 2, 0}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_2_0_1(execution_space(), x_c_axis_1, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<3>({2, 0, 1}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_2_1_0(execution_space(), x_c_axis_0, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<3>({2, 1, 0}));
 
   // C2C plan
-  KokkosFFT::Plan plan_c2c_f_axes_0_1_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({0, 1, 2}));
-  KokkosFFT::Plan plan_c2c_f_axes_0_2_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({0, 2, 1}));
-  KokkosFFT::Plan plan_c2c_f_axes_1_0_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({1, 0, 2}));
-  KokkosFFT::Plan plan_c2c_f_axes_1_2_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({1, 2, 0}));
-  KokkosFFT::Plan plan_c2c_f_axes_2_0_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({2, 0, 1}));
-  KokkosFFT::Plan plan_c2c_f_axes_2_1_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({2, 1, 0}));
-
-  EXPECT_THROW(
-    {
-      KokkosFFT::Plan plan_c2c(execution_space(), x_cin, x_cout);
-    },
-    std::runtime_error
-  );
-
-  EXPECT_THROW(
-    {
-      KokkosFFT::Plan plan_c2c_axes_0_1_2(execution_space(), x_cin, x_cout, /*axes=*/axes_type<3>({0, 1, 2}));
-    },
-    std::runtime_error
-  );
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_0_1_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({0, 1, 2}));
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_0_2_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({0, 2, 1}));
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_1_0_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({1, 0, 2}));
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_1_2_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({1, 2, 0}));
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_2_0_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({2, 0, 1}));
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_2_1_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<3>({2, 1, 0}));
 }
 
 TEST(Plans, 3DFFT_3DLeftViewFloat) {
@@ -193,34 +143,18 @@ void test_plan_1dfft_2dview() {
   ComplexView2DType x_cin("x_cin", n0, n1), x_cout("x_cout", n0, n1);
 
   // R2C plan
-  KokkosFFT::Plan plan_r2c_axis_0(execution_space(), x, x_c_axis_0, /*axis=*/0);
-  KokkosFFT::Plan plan_r2c_axis_1(execution_space(), x, x_c_axis_1, /*axis=*/1);
-  KokkosFFT::Plan plan_r2c_axis_minus1(execution_space(), x, x_c_axis_1, /*axis=*/-1);
+  KokkosFFT::Impl::Plan plan_r2c_axis_0(execution_space(), x, x_c_axis_0, KOKKOS_FFT_FORWARD, /*axis=*/0);
+  KokkosFFT::Impl::Plan plan_r2c_axis_1(execution_space(), x, x_c_axis_1, KOKKOS_FFT_FORWARD, /*axis=*/1);
+  KokkosFFT::Impl::Plan plan_r2c_axis_minus1(execution_space(), x, x_c_axis_1, KOKKOS_FFT_FORWARD, /*axis=*/-1);
 
   // C2R plan
-  KokkosFFT::Plan plan_c2r_axis_0(execution_space(), x_c_axis_0, x, /*axis=*/0);
-  KokkosFFT::Plan plan_c2r_axis_1(execution_space(), x_c_axis_1, x, /*axis=*/1);
-  KokkosFFT::Plan plan_c2r_axis_minus1(execution_space(), x_c_axis_1, x, /*axis=*/-1);
+  KokkosFFT::Impl::Plan plan_c2r_axis_0(execution_space(), x_c_axis_0, x, KOKKOS_FFT_BACKWARD, /*axis=*/0);
+  KokkosFFT::Impl::Plan plan_c2r_axis_1(execution_space(), x_c_axis_1, x, KOKKOS_FFT_BACKWARD, /*axis=*/1);
+  KokkosFFT::Impl::Plan plan_c2r_axis_minus1(execution_space(), x_c_axis_1, x, KOKKOS_FFT_BACKWARD, /*axis=*/-1);
 
   // C2C plan
-  KokkosFFT::Plan plan_c2c_f_axis_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/0);
-  KokkosFFT::Plan plan_c2c_f_axis_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/1);
-
-  // [TO DO] Fix this, this can be instanized with explicit Plan(InViewType& in, OutViewType& out, FFTDirectionType direction)
-  // Because FFTDirectionType is int for most libraries
-  //EXPECT_THROW(
-  //  {
-  //    KokkosFFT::Plan plan_c2c_axis_0(execution_space(), x_cin, x_cout, /*axis=*/0);
-  //  },
-  //  std::runtime_error
-  //);
-
-  //EXPECT_THROW(
-  //  {
-  //    KokkosFFT::Plan plan_c2c_axis_1(execution_space(), x_cin, x_cout, /*axis=*/1);
-  //  },
-  //  std::runtime_error
-  //);
+  KokkosFFT::Impl::Plan plan_c2c_f_axis_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/0);
+  KokkosFFT::Impl::Plan plan_c2c_f_axis_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/1);
 }
 
 TEST(Plans, 1DBatchedFFT_2DLeftViewFloat) {
@@ -250,45 +184,22 @@ void test_plan_1dfft_3dview() {
   ComplexView3DType x_cin("x_cin", n0, n1, n2), x_cout("x_cout", n0, n1, n2);
 
   // R2C plan
-  KokkosFFT::Plan plan_r2c_axis_0(execution_space(), x, x_c_axis_0, /*axis=*/0);
-  KokkosFFT::Plan plan_r2c_axis_1(execution_space(), x, x_c_axis_1, /*axis=*/1);
-  KokkosFFT::Plan plan_r2c_axis_2(execution_space(), x, x_c_axis_2, /*axis=*/2);
+  KokkosFFT::Impl::Plan plan_r2c_axis_0(execution_space(), x, x_c_axis_0, KOKKOS_FFT_FORWARD, /*axis=*/0);
+  KokkosFFT::Impl::Plan plan_r2c_axis_1(execution_space(), x, x_c_axis_1, KOKKOS_FFT_FORWARD, /*axis=*/1);
+  KokkosFFT::Impl::Plan plan_r2c_axis_2(execution_space(), x, x_c_axis_2, KOKKOS_FFT_FORWARD, /*axis=*/2);
 
   // C2R plan
-  KokkosFFT::Plan plan_c2r_axis_0(execution_space(), x_c_axis_0, x, /*axis=*/0);
-  KokkosFFT::Plan plan_c2r_axis_1(execution_space(), x_c_axis_1, x, /*axis=*/1);
-  KokkosFFT::Plan plan_c2r_axis_2(execution_space(), x_c_axis_2, x, /*axis=*/2);
+  KokkosFFT::Impl::Plan plan_c2r_axis_0(execution_space(), x_c_axis_0, x, KOKKOS_FFT_BACKWARD, /*axis=*/0);
+  KokkosFFT::Impl::Plan plan_c2r_axis_1(execution_space(), x_c_axis_1, x, KOKKOS_FFT_BACKWARD, /*axis=*/1);
+  KokkosFFT::Impl::Plan plan_c2r_axis_2(execution_space(), x_c_axis_2, x, KOKKOS_FFT_BACKWARD, /*axis=*/2);
 
   // C2C plan
-  KokkosFFT::Plan plan_c2c_f_axis_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/0);
-  KokkosFFT::Plan plan_c2c_f_axis_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/1);
-  KokkosFFT::Plan plan_c2c_f_axis_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/2);
-  KokkosFFT::Plan plan_c2c_b_axis_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_BACKWARD, /*axis=*/0);
-  KokkosFFT::Plan plan_c2c_b_axis_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_BACKWARD, /*axis=*/1);
-  KokkosFFT::Plan plan_c2c_b_axis_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_BACKWARD, /*axis=*/2);
-
-  // [TO DO] Fix this, this can be instanized with explicit Plan(InViewType& in, OutViewType& out, FFTDirectionType direction)
-  // Because FFTDirectionType is int for most libraries
-  //EXPECT_THROW(
-  //  {
-  //    KokkosFFT::Plan plan_c2c_axis_0(execution_space(), x_cin, x_cout, /*axis=*/0);
-  //  },
-  //  std::runtime_error
-  //);
-
-  //EXPECT_THROW(
-  //  {
-  //    KokkosFFT::Plan plan_c2c_axis_1(execution_space(), x_cin, x_cout, /*axis=*/1);
-  //  },
-  //  std::runtime_error
-  //);
-
-  //EXPECT_THROW(
-  //  {
-  //    KokkosFFT::Plan plan_c2c_axis_1(execution_space(), x_cin, x_cout, /*axis=*/2);
-  //  },
-  //  std::runtime_error
-  //);
+  KokkosFFT::Impl::Plan plan_c2c_f_axis_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/0);
+  KokkosFFT::Impl::Plan plan_c2c_f_axis_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/1);
+  KokkosFFT::Impl::Plan plan_c2c_f_axis_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axis=*/2);
+  KokkosFFT::Impl::Plan plan_c2c_b_axis_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_BACKWARD, /*axis=*/0);
+  KokkosFFT::Impl::Plan plan_c2c_b_axis_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_BACKWARD, /*axis=*/1);
+  KokkosFFT::Impl::Plan plan_c2c_b_axis_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_BACKWARD, /*axis=*/2);
 }
 
 TEST(Plans, 1DBatchedFFT_3DLeftViewFloat) {
@@ -318,35 +229,28 @@ void test_plan_2dfft_3dview() {
   ComplexView3DType x_cin("x_cin", n0, n1, n2), x_cout("x_cout", n0, n1, n2);
 
   // R2C plan
-  KokkosFFT::Plan plan_r2c_axes_0_1(execution_space(), x, x_c_axis_1, /*axes=*/axes_type<2>({0, 1}));
-  KokkosFFT::Plan plan_r2c_axes_0_2(execution_space(), x, x_c_axis_2, /*axes=*/axes_type<2>({0, 2}));
-  KokkosFFT::Plan plan_r2c_axes_1_0(execution_space(), x, x_c_axis_0, /*axes=*/axes_type<2>({1, 0}));
-  KokkosFFT::Plan plan_r2c_axes_1_2(execution_space(), x, x_c_axis_2, /*axes=*/axes_type<2>({1, 2}));
-  KokkosFFT::Plan plan_r2c_axes_2_0(execution_space(), x, x_c_axis_0, /*axes=*/axes_type<2>({2, 0}));
-  KokkosFFT::Plan plan_r2c_axes_2_1(execution_space(), x, x_c_axis_1, /*axes=*/axes_type<2>({2, 1}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_0_1(execution_space(), x, x_c_axis_1, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({0, 1}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_0_2(execution_space(), x, x_c_axis_2, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({0, 2}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_1_0(execution_space(), x, x_c_axis_0, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({1, 0}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_1_2(execution_space(), x, x_c_axis_2, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({1, 2}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_2_0(execution_space(), x, x_c_axis_0, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({2, 0}));
+  KokkosFFT::Impl::Plan plan_r2c_axes_2_1(execution_space(), x, x_c_axis_1, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({2, 1}));
 
   // C2R plan
-  KokkosFFT::Plan plan_c2r_axes_0_1(execution_space(), x_c_axis_1, x, /*axes=*/axes_type<2>({0, 1}));
-  KokkosFFT::Plan plan_c2r_axes_0_2(execution_space(), x_c_axis_2, x, /*axes=*/axes_type<2>({0, 2}));
-  KokkosFFT::Plan plan_c2r_axes_1_0(execution_space(), x_c_axis_0, x, /*axes=*/axes_type<2>({1, 0}));
-  KokkosFFT::Plan plan_c2r_axes_1_2(execution_space(), x_c_axis_2, x, /*axes=*/axes_type<2>({1, 2}));
-  KokkosFFT::Plan plan_c2r_axes_2_0(execution_space(), x_c_axis_0, x, /*axes=*/axes_type<2>({2, 0}));
-  KokkosFFT::Plan plan_c2r_axes_2_1(execution_space(), x_c_axis_1, x, /*axes=*/axes_type<2>({2, 1}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_0_1(execution_space(), x_c_axis_1, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<2>({0, 1}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_0_2(execution_space(), x_c_axis_2, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<2>({0, 2}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_1_0(execution_space(), x_c_axis_0, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<2>({1, 0}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_1_2(execution_space(), x_c_axis_2, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<2>({1, 2}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_2_0(execution_space(), x_c_axis_0, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<2>({2, 0}));
+  KokkosFFT::Impl::Plan plan_c2r_axes_2_1(execution_space(), x_c_axis_1, x, KOKKOS_FFT_BACKWARD, /*axes=*/axes_type<2>({2, 1}));
 
   // C2C plan
-  KokkosFFT::Plan plan_c2c_f_axes_0_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({0, 1}));
-  KokkosFFT::Plan plan_c2c_f_axes_0_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({0, 2}));
-  KokkosFFT::Plan plan_c2c_f_axes_1_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({1, 0}));
-  KokkosFFT::Plan plan_c2c_f_axes_1_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({1, 2}));
-  KokkosFFT::Plan plan_c2c_f_axes_2_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({2, 0}));
-  KokkosFFT::Plan plan_c2c_f_axes_2_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({2, 1}));
-
-  EXPECT_THROW(
-    {
-      KokkosFFT::Plan plan_c2c_axes_0_1(execution_space(), x_cin, x_cout, /*axes=*/axes_type<2>({0, 1}));
-    },
-    std::runtime_error
-  );
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_0_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({0, 1}));
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_0_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({0, 2}));
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_1_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({1, 0}));
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_1_2(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({1, 2}));
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_2_0(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({2, 0}));
+  KokkosFFT::Impl::Plan plan_c2c_f_axes_2_1(execution_space(), x_cin, x_cout, KOKKOS_FFT_FORWARD, /*axes=*/axes_type<2>({2, 1}));
 }
 
 TEST(Plans, 2DBatchedFFT_3DLeftViewFloat) {
diff --git a/fft/unit_test/Test_Transform.cpp b/fft/unit_test/Test_Transform.cpp
index 56e2d20b..e457af23 100644
--- a/fft/unit_test/Test_Transform.cpp
+++ b/fft/unit_test/Test_Transform.cpp
@@ -13,9 +13,9 @@
 template <typename ViewType>
 void fft1(ViewType& in, ViewType& out) {
   using value_type = typename ViewType::non_const_value_type;
-  using real_value_type = KokkosFFT::real_type_t<value_type>;
+  using real_value_type = KokkosFFT::Impl::real_type_t<value_type>;
 
-  static_assert(KokkosFFT::is_complex<value_type>::value,
+  static_assert(KokkosFFT::Impl::is_complex<value_type>::value,
                 "fft1: ViewType must be complex");
 
   const value_type I(0.0, 1.0);
@@ -53,9 +53,9 @@ void fft1(ViewType& in, ViewType& out) {
 template <typename ViewType>
 void ifft1(ViewType& in, ViewType& out) {
   using value_type = typename ViewType::non_const_value_type;
-  using real_value_type = KokkosFFT::real_type_t<value_type>;
+  using real_value_type = KokkosFFT::Impl::real_type_t<value_type>;
 
-  static_assert(KokkosFFT::is_complex<value_type>::value,
+  static_assert(KokkosFFT::Impl::is_complex<value_type>::value,
                 "ifft1: ViewType must be complex");
 
   const value_type I(0.0, 1.0);