diff --git a/examples/08_awful_usage/08_awful_usage.cpp b/examples/08_awful_usage/08_awful_usage.cpp new file mode 100644 index 00000000..c08b57e6 --- /dev/null +++ b/examples/08_awful_usage/08_awful_usage.cpp @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: (C) The Kokkos-FFT development team, see COPYRIGHT.md file +// +// SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using execution_space = Kokkos::DefaultExecutionSpace; +template +using View1D = Kokkos::View; + +template +using View2D = Kokkos::View; + +template +using View3D = Kokkos::View; + +template +using axis_type = KokkosFFT::axis_type; +template +using shape_type = KokkosFFT::shape_type; + +int main(int argc, char* argv[]) { + Kokkos::initialize(argc, argv); + { + constexpr int n0 = 128, n1 = 128, n2 = 16; + const Kokkos::complex I(1.0, 1.0); + + shape_type<3> shape; + shape[0] = n0; + shape[1] = n1; + shape[2] = n2; + + View1D > xc("xc", n0); + View2D > xc2("xc2", n0, n1); + View1D xr("xr", n0); + View2D xr2("xr2", n0, n1); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + execution_space exec; + Kokkos::fill_random(exec, xc, random_pool, I); + exec.fence(); + +#if 0 + // Compilte time error for inconsistent types + // You will get the following compilation errors if you uncomment this block + // error: static assertion failed with "rfft: InViewType must be real" + // error: static assertion failed with "rfft: OutViewType must be complex" + KokkosFFT::rfft(exec, xc, xr); // Incorrect, input is complex and output is real + KokkosFFT::rfft(exec, xr, xc); // Correct, input is real and output is complex +#endif + +#if 0 + // Compilte time error if FFT rank > View rank (2D FFT on 1D View) + // You will get the following compilation errors if you uncomment this block + // error: static assertion failed with "rfft2: View rank must be larger than or equal to 2" + KokkosFFT::rfft2(exec, xr, xc); // Incorrect, input and output are 1D Views + KokkosFFT::rfft2(exec, xr2, xc2); // Correct, input and output are 2D Views +#endif + +#if 0 + // Compilte time error if FFT plan and execution is inconsistent + // You will get the following compilation errors if you uncomment this block + // error: static assertion failed with "Plan::good: InViewType for plan and execution are not identical." + // error: static assertion failed with "Plan::good: OutViewType for plan and execution are not identical." + int axis = -1; + KokkosFFT::Impl::Plan rfft_plan(exec, xr, xc, + KokkosFFT::Direction::forward, axis); + KokkosFFT::Impl::fft_exec_impl(rfft_plan, xc, xr); // Incorrect, input and output are reversed + KokkosFFT::Impl::fft_exec_impl(rfft_plan, xr, xc); // Correct, same input and output +#endif + + exec.fence(); + } + Kokkos::finalize(); + + return 0; +} diff --git a/examples/08_awful_usage/CMakeLists.txt b/examples/08_awful_usage/CMakeLists.txt new file mode 100644 index 00000000..5949ebdf --- /dev/null +++ b/examples/08_awful_usage/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: (C) The Kokkos-FFT development team, see COPYRIGHT.md file +# +# SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception + +add_executable(08_awful_usage 08_awful_usage.cpp) +target_link_libraries(08_awful_usage PUBLIC KokkosFFT::fft) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f587f4c2..27704f63 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -9,3 +9,4 @@ add_subdirectory(04_batchedFFT) add_subdirectory(05_1DFFT_HOST_DEVICE) add_subdirectory(06_1DFFT_reuse_plans) add_subdirectory(07_unmanaged_views) +add_subdirectory(08_awful_usage) diff --git a/fft/src/KokkosFFT_Transform.hpp b/fft/src/KokkosFFT_Transform.hpp index b8923b15..52817599 100644 --- a/fft/src/KokkosFFT_Transform.hpp +++ b/fft/src/KokkosFFT_Transform.hpp @@ -82,36 +82,41 @@ void fft_exec_impl( "same rank. ExecutionSpace must be accessible to the data in InViewType " "and OutViewType."); - plan.template good(in, out); - - const auto exec_space = plan.exec_space(); - using ManagableInViewType = - typename KokkosFFT::Impl::managable_view_type::type; - using ManagableOutViewType = - typename KokkosFFT::Impl::managable_view_type::type; - ManagableInViewType _in_s; - InViewType _in; - if (plan.is_crop_or_pad_needed()) { - auto new_shape = plan.shape(); - KokkosFFT::Impl::crop_or_pad(exec_space, in, _in_s, new_shape); - _in = _in_s; - } else { - _in = in; - } - - if (plan.is_transpose_needed()) { - ManagableInViewType in_T; - ManagableOutViewType out_T; - - KokkosFFT::Impl::transpose(exec_space, _in, in_T, plan.map()); - KokkosFFT::Impl::transpose(exec_space, out, out_T, plan.map()); - - KokkosFFT::Impl::exec_impl(plan, in_T, out_T, norm); - - KokkosFFT::Impl::transpose(exec_space, out_T, out, plan.map_inv()); - - } else { - KokkosFFT::Impl::exec_impl(plan, _in, out, norm); + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType>) { + plan.template good(in, out); + + const auto exec_space = plan.exec_space(); + using ManagableInViewType = + typename KokkosFFT::Impl::managable_view_type::type; + using ManagableOutViewType = + typename KokkosFFT::Impl::managable_view_type::type; + ManagableInViewType _in_s; + InViewType _in; + if (plan.is_crop_or_pad_needed()) { + auto new_shape = plan.shape(); + KokkosFFT::Impl::crop_or_pad(exec_space, in, _in_s, new_shape); + _in = _in_s; + } else { + _in = in; + } + + if (plan.is_transpose_needed()) { + ManagableInViewType in_T; + ManagableOutViewType out_T; + + KokkosFFT::Impl::transpose(exec_space, _in, in_T, plan.map()); + KokkosFFT::Impl::transpose(exec_space, out, out_T, plan.map()); + + KokkosFFT::Impl::exec_impl(plan, in_T, out_T, norm); + + KokkosFFT::Impl::transpose(exec_space, out_T, out, plan.map_inv()); + + } else { + KokkosFFT::Impl::exec_impl(plan, _in, out, norm); + } } } @@ -141,11 +146,19 @@ void fft(const ExecutionSpace& exec_space, const InViewType& in, "and OutViewType."); static_assert(InViewType::rank() >= 1, "fft: View rank must be larger than or equal to 1"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), - "axes are invalid for in/out views"); - KokkosFFT::Impl::Plan plan(exec_space, in, out, KokkosFFT::Direction::forward, - axis, n); - KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + InViewType::rank() >= 1) { + KOKKOSFFT_THROW_IF( + !KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), + "axes are invalid for in/out views"); + KokkosFFT::Impl::Plan plan(exec_space, in, out, + KokkosFFT::Direction::forward, axis, n); + KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + } } /// \brief One dimensional FFT in backward direction @@ -170,11 +183,19 @@ void ifft(const ExecutionSpace& exec_space, const InViewType& in, "and OutViewType."); static_assert(InViewType::rank() >= 1, "ifft: View rank must be larger than or equal to 1"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), - "axes are invalid for in/out views"); - KokkosFFT::Impl::Plan plan(exec_space, in, out, - KokkosFFT::Direction::backward, axis, n); - KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + InViewType::rank() >= 1) { + KOKKOSFFT_THROW_IF( + !KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), + "axes are invalid for in/out views"); + KokkosFFT::Impl::Plan plan(exec_space, in, out, + KokkosFFT::Direction::backward, axis, n); + KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + } } /// \brief One dimensional FFT for real input @@ -207,9 +228,19 @@ void rfft(const ExecutionSpace& exec_space, const InViewType& in, "rfft: InViewType must be real"); static_assert(KokkosFFT::Impl::is_complex_v, "rfft: OutViewType must be complex"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), - "axes are invalid for in/out views"); - fft(exec_space, in, out, norm, axis, n); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + InViewType::rank() >= 1 && + KokkosFFT::Impl::is_real_v && + KokkosFFT::Impl::is_complex_v) { + KOKKOSFFT_THROW_IF( + !KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), + "axes are invalid for in/out views"); + fft(exec_space, in, out, norm, axis, n); + } } /// \brief Inverse of rfft @@ -243,9 +274,19 @@ void irfft(const ExecutionSpace& exec_space, const InViewType& in, "irfft: InViewType must be complex"); static_assert(KokkosFFT::Impl::is_real_v, "irfft: OutViewType must be real"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), - "axes are invalid for in/out views"); - ifft(exec_space, in, out, norm, axis, n); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + InViewType::rank() >= 1 && + KokkosFFT::Impl::is_complex_v && + KokkosFFT::Impl::is_real_v) { + KOKKOSFFT_THROW_IF( + !KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), + "axes are invalid for in/out views"); + ifft(exec_space, in, out, norm, axis, n); + } } /// \brief One dimensional FFT of a signal that has Hermitian symmetry @@ -280,15 +321,25 @@ void hfft(const ExecutionSpace& exec_space, const InViewType& in, "hfft: InViewType must be complex"); static_assert(KokkosFFT::Impl::is_real_v, "hfft: OutViewType must be real"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), - "axes are invalid for in/out views"); - auto new_norm = KokkosFFT::Impl::swap_direction(norm); - // using ComplexViewType = typename - // KokkosFFT::Impl::complex_view_type::type; - // ComplexViewType in_conj; - InViewType in_conj; - KokkosFFT::Impl::conjugate(exec_space, in, in_conj); - irfft(exec_space, in_conj, out, new_norm, axis, n); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + InViewType::rank() >= 1 && + KokkosFFT::Impl::is_complex_v && + KokkosFFT::Impl::is_real_v) { + KOKKOSFFT_THROW_IF( + !KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), + "axes are invalid for in/out views"); + auto new_norm = KokkosFFT::Impl::swap_direction(norm); + // using ComplexViewType = typename + // KokkosFFT::Impl::complex_view_type::type; + // ComplexViewType in_conj; + InViewType in_conj; + KokkosFFT::Impl::conjugate(exec_space, in, in_conj); + irfft(exec_space, in_conj, out, new_norm, axis, n); + } } /// \brief Inverse of hfft @@ -321,13 +372,23 @@ void ihfft(const ExecutionSpace& exec_space, const InViewType& in, "ihfft: InViewType must be real"); static_assert(KokkosFFT::Impl::is_complex_v, "ihfft: OutViewType must be complex"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), - "axes are invalid for in/out views"); - auto new_norm = KokkosFFT::Impl::swap_direction(norm); - OutViewType out_conj; - rfft(exec_space, in, out, new_norm, axis, n); - KokkosFFT::Impl::conjugate(exec_space, out, out_conj); - out = out_conj; + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + InViewType::rank() >= 1 && + KokkosFFT::Impl::is_real_v && + KokkosFFT::Impl::is_complex_v) { + KOKKOSFFT_THROW_IF( + !KokkosFFT::Impl::are_valid_axes(in, axis_type<1>({axis})), + "axes are invalid for in/out views"); + auto new_norm = KokkosFFT::Impl::swap_direction(norm); + OutViewType out_conj; + rfft(exec_space, in, out, new_norm, axis, n); + KokkosFFT::Impl::conjugate(exec_space, out, out_conj); + out = out_conj; + } } // 2D FFT @@ -354,11 +415,18 @@ void fft2(const ExecutionSpace& exec_space, const InViewType& in, "and OutViewType."); static_assert(InViewType::rank() >= 2, "fft2: View rank must be larger than or equal to 2"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), - "axes are invalid for in/out views"); - KokkosFFT::Impl::Plan plan(exec_space, in, out, KokkosFFT::Direction::forward, - axes, s); - KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + InViewType::rank() >= 2) { + KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), + "axes are invalid for in/out views"); + KokkosFFT::Impl::Plan plan(exec_space, in, out, + KokkosFFT::Direction::forward, axes, s); + KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + } } /// \brief Two dimensional FFT in backward direction @@ -384,11 +452,18 @@ void ifft2(const ExecutionSpace& exec_space, const InViewType& in, "and OutViewType."); static_assert(InViewType::rank() >= 2, "ifft2: View rank must be larger than or equal to 2"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), - "axes are invalid for in/out views"); - KokkosFFT::Impl::Plan plan(exec_space, in, out, - KokkosFFT::Direction::backward, axes, s); - KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + InViewType::rank() >= 2) { + KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), + "axes are invalid for in/out views"); + KokkosFFT::Impl::Plan plan(exec_space, in, out, + KokkosFFT::Direction::backward, axes, s); + KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + } } /// \brief Two dimensional FFT for real input @@ -422,9 +497,18 @@ void rfft2(const ExecutionSpace& exec_space, const InViewType& in, "rfft2: InViewType must be real"); static_assert(KokkosFFT::Impl::is_complex_v, "rfft2: OutViewType must be complex"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), - "axes are invalid for in/out views"); - fft2(exec_space, in, out, norm, axes, s); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + InViewType::rank() >= 2 && + KokkosFFT::Impl::is_real_v && + KokkosFFT::Impl::is_complex_v) { + KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), + "axes are invalid for in/out views"); + fft2(exec_space, in, out, norm, axes, s); + } } /// \brief Inverse of rfft2 with a given plan @@ -458,9 +542,18 @@ void irfft2(const ExecutionSpace& exec_space, const InViewType& in, "irfft2: InViewType must be complex"); static_assert(KokkosFFT::Impl::is_real_v, "irfft2: OutViewType must be real"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), - "axes are invalid for in/out views"); - ifft2(exec_space, in, out, norm, axes, s); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + InViewType::rank() >= 2 && + KokkosFFT::Impl::is_complex_v && + KokkosFFT::Impl::is_real_v) { + KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), + "axes are invalid for in/out views"); + ifft2(exec_space, in, out, norm, axes, s); + } } // ND FFT @@ -491,11 +584,19 @@ void fftn(const ExecutionSpace& exec_space, const InViewType& in, static_assert( InViewType::rank() >= DIM, "fftn: View rank must be larger than or equal to the Rank of FFT axes"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), - "axes are invalid for in/out views"); - KokkosFFT::Impl::Plan plan(exec_space, in, out, KokkosFFT::Direction::forward, - axes, s); - KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + DIM >= 1 && DIM <= KokkosFFT::MAX_FFT_DIM && + InViewType::rank() >= DIM) { + KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), + "axes are invalid for in/out views"); + KokkosFFT::Impl::Plan plan(exec_space, in, out, + KokkosFFT::Direction::forward, axes, s); + KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + } } /// \brief N-dimensional FFT in backward direction with a given plan @@ -526,11 +627,19 @@ void ifftn(const ExecutionSpace& exec_space, const InViewType& in, static_assert( InViewType::rank() >= DIM, "ifftn: View rank must be larger than or equal to the Rank of FFT axes"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), - "axes are invalid for in/out views"); - KokkosFFT::Impl::Plan plan(exec_space, in, out, - KokkosFFT::Direction::backward, axes, s); - KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + DIM >= 1 && DIM <= KokkosFFT::MAX_FFT_DIM && + InViewType::rank() >= DIM) { + KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), + "axes are invalid for in/out views"); + KokkosFFT::Impl::Plan plan(exec_space, in, out, + KokkosFFT::Direction::backward, axes, s); + KokkosFFT::Impl::fft_exec_impl(plan, in, out, norm); + } } /// \brief N-dimensional FFT for real input @@ -569,9 +678,19 @@ void rfftn(const ExecutionSpace& exec_space, const InViewType& in, "rfftn: InViewType must be real"); static_assert(KokkosFFT::Impl::is_complex_v, "rfftn: OutViewType must be complex"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), - "axes are invalid for in/out views"); - fftn(exec_space, in, out, axes, norm, s); + + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + DIM >= 1 && DIM <= KokkosFFT::MAX_FFT_DIM && + InViewType::rank() >= DIM && + KokkosFFT::Impl::is_real_v && + KokkosFFT::Impl::is_complex_v) { + KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), + "axes are invalid for in/out views"); + fftn(exec_space, in, out, axes, norm, s); + } } /// \brief Inverse of rfftn @@ -610,9 +729,18 @@ void irfftn(const ExecutionSpace& exec_space, const InViewType& in, "irfftn: InViewType must be complex"); static_assert(KokkosFFT::Impl::is_real_v, "irfftn: OutViewType must be real"); - KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), - "axes are invalid for in/out views"); - ifftn(exec_space, in, out, axes, norm, s); + // Do not proceed if conditions are not satisfied. + // This is to avoid useless static assertions. + if constexpr (KokkosFFT::Impl::are_operatable_views_v< + ExecutionSpace, InViewType, OutViewType> && + DIM >= 1 && DIM <= KokkosFFT::MAX_FFT_DIM && + InViewType::rank() >= DIM && + KokkosFFT::Impl::is_complex_v && + KokkosFFT::Impl::is_real_v) { + KOKKOSFFT_THROW_IF(!KokkosFFT::Impl::are_valid_axes(in, axes), + "axes are invalid for in/out views"); + ifftn(exec_space, in, out, axes, norm, s); + } } } // namespace KokkosFFT