From 545dc698497c6f41d153092cb28f2251e5a29ba2 Mon Sep 17 00:00:00 2001 From: yasahi-hpc <57478230+yasahi-hpc@users.noreply.github.com> Date: Fri, 4 Oct 2024 15:42:10 +0200 Subject: [PATCH] Update docs (#144) * docs: Add default explanations for APIs * Add docs for unmanaged view example * docs: Explain the meanings of axes * docs: we do not rely on assertions any more * docs: fix based on a review * docs: fix title for unmanaged view example * fix: docs of fftshift based on reviews * docs: improve the explanations for axes parameters * docs: further fix * docs: fixed typo based on reviews --------- Co-authored-by: Yuuichi Asahi --- README.md | 2 +- common/src/KokkosFFT_Helpers.hpp | 10 ++-- docs/examples.rst | 5 +- docs/intro/using.rst | 48 ++++++++++++++- docs/samples/07_unmanaged_views.rst | 14 +++++ fft/src/KokkosFFT_Plans.hpp | 7 ++- fft/src/KokkosFFT_Transform.hpp | 90 +++++++++++++++-------------- 7 files changed, 123 insertions(+), 53 deletions(-) create mode 100644 docs/samples/07_unmanaged_views.rst diff --git a/README.md b/README.md index b5dab8e7..6bf68c7d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception > EXPERIMENTAL FFT interfaces for Kokkos C++ Performance Portability Programming EcoSystem Kokkos-fft implements local interfaces between [Kokkos](https://github.com/kokkos/kokkos) and de facto standard FFT libraries, including [fftw](http://www.fftw.org), [cufft](https://developer.nvidia.com/cufft), [hipfft](https://github.com/ROCm/hipFFT) ([rocfft](https://github.com/ROCm/rocFFT)), and [oneMKL](https://spec.oneapi.io/versions/latest/elements/oneMKL/source/index.html). "Local" means not using MPI, or running within a single MPI process without knowing about MPI. We are inclined to implement the [numpy.fft](https://numpy.org/doc/stable/reference/routines.fft.html)-like interfaces adapted for [Kokkos](https://github.com/kokkos/kokkos). -A key concept is that **"As easy as numpy, as fast as vendor libraries"**. Accordingly, our API follows the API by [numpy.fft](https://numpy.org/doc/stable/reference/routines.fft.html) with minor differences. A fft library dedicated to Kokkos Device backend (e.g. [cufft](https://developer.nvidia.com/cufft) for CUDA backend) is automatically used. If something is wrong with runtime values (say `View` extents), it will raise runtime errors (C++ exceptions or assertions). See [documentations](https://kokkosfft.readthedocs.io/) for more information. +A key concept is that **"As easy as numpy, as fast as vendor libraries"**. Accordingly, our API follows the API by [numpy.fft](https://numpy.org/doc/stable/reference/routines.fft.html) with minor differences. A fft library dedicated to Kokkos Device backend (e.g. [cufft](https://developer.nvidia.com/cufft) for CUDA backend) is automatically used. If something is wrong with runtime values (say `View` extents), it will raise runtime errors (C++ `std::runtime_error`). See [documentations](https://kokkosfft.readthedocs.io/) for more information. Here is an example for 1D real to complex transform with `rfft` in Kokkos-fft. ```C++ diff --git a/common/src/KokkosFFT_Helpers.hpp b/common/src/KokkosFFT_Helpers.hpp index 91012d36..d44aa48c 100644 --- a/common/src/KokkosFFT_Helpers.hpp +++ b/common/src/KokkosFFT_Helpers.hpp @@ -151,7 +151,7 @@ namespace KokkosFFT { /// /// \param exec_space [in] Kokkos execution space /// \param n [in] Window length -/// \param d [in] Sample spacing +/// \param d [in] Sample spacing (default, 1) /// /// \return Sampling frequency template @@ -186,7 +186,7 @@ auto fftfreq(const ExecutionSpace&, const std::size_t n, /// /// \param exec_space [in] Kokkos execution space /// \param n [in] Window length -/// \param d [in] Sample spacing +/// \param d [in] Sample spacing (default, 1) /// /// \return Sampling frequency starting from zero template @@ -215,7 +215,8 @@ auto rfftfreq(const ExecutionSpace&, const std::size_t n, /// /// \param exec_space [in] Kokkos execution space /// \param inout [in,out] Spectrum -/// \param axes [in] Axes over which to shift, optional +/// \param axes [in] Axes over which to shift (default: nullopt, shifting over +/// all axes) template void fftshift(const ExecutionSpace& exec_space, ViewType& inout, std::optional axes = std::nullopt) { @@ -264,7 +265,8 @@ void fftshift(const ExecutionSpace& exec_space, ViewType& inout, /// /// \param exec_space [in] Kokkos execution space /// \param inout [in,out] Spectrum -/// \param axes [in] Axes over which to shift, optional +/// \param axes [in] Axes over which to shift (default: nullopt, shifting over +/// all axes) template void ifftshift(const ExecutionSpace& exec_space, ViewType& inout, std::optional axes = std::nullopt) { diff --git a/docs/examples.rst b/docs/examples.rst index 21ca75bb..f6cc304d 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -9,7 +9,7 @@ Examples There are some `examples `_ in the -Kokkos-fft repository. Each example includes Kokkos and numpy implementations. +Kokkos-fft repository. Most of the examples include Kokkos and numpy implementations. For example, `01_1DFFT `_ includes, @@ -32,4 +32,5 @@ Please find the examples from following links. samples/03_NDFFT.rst samples/04_batchedFFT.rst samples/05_1DFFT_HOST_DEVICE.rst - samples/06_1DFFT_reuse_plans.rst \ No newline at end of file + samples/06_1DFFT_reuse_plans.rst + samples/07_unmanaged_views.rst \ No newline at end of file diff --git a/docs/intro/using.rst b/docs/intro/using.rst index b8f669d3..81fad685 100644 --- a/docs/intro/using.rst +++ b/docs/intro/using.rst @@ -34,7 +34,7 @@ If the rank of Views is higher than the dimension of FFT, a batched FFT plan is APIs start from ``i`` represent inverse transforms. For Real FFTs, users have to pay attention to the input and output data types as well as their extents. Inconsistent data types are suppressed by compilation errors. If extents are inconsistent, -it will raise runtime errors (C++ exceptions or assertions). +it will raise runtime errors (C++ ``std::runtime_error``). The following listing shows good and bad examples of Real FFTs. .. code-block:: C++ @@ -130,3 +130,49 @@ In some backend, FFT plan creation leads to some overhead, wherein we need this .. note:: Input and Output Views used to call FFT APIs must have the same types and extents as the ones used for plan creation. + +Axes parameters +--------------- + +As well as ``numpy.fft``, you can specify negative axes to perform FFT over chosen axes, which is not common in C++. +Actually for FFT APIs, default axes are set as ``{-DIM, -(DIM-1), ...}`` where ``DIM`` is the rank of the FFT dimensions, +corresponding to the FFTs over last ``DIM`` axes. If we consider that default View layout is C layout (row-major or ``Kokkos::LayoutRight``), +this default axes parameter results in FFTs performed over the contiguous dimensions. For example, ``KokkosFFT::fft2(execution_space(), in, out)`` is equivalent to ``KokkosFFT::fft2(execution_space(), in, out, axis_type<2>({-2, -1}))``. +Negative axes are counted from the last axis, which is the same as ``numpy.fft``. +For example, ``-1`` means the last axis, ``-2`` means the second last axis, and so on. +Negative axes ``-1`` and ``-2`` respectively correspond to ``rank-1`` and ``rank-2``, where the ``rank`` is the rank of the Views. + +The following listing shows examples of axes parameters with negative or positive values. + +.. code-block:: C++ + + template using View2D = Kokkos::View; + template using View3D = Kokkos::View; + constexpr int n0 = 4, n1 = 8, n2 = 5; + + View2D x2("x2", n0, n1); + View3D x3("x3", n0, n1, n2); + View2D > x2_hat("x2_hat", n0/2+1, n1); + View3D > x3_hat("x3_hat", n0, n1/2+1, n2); + + // Following codes are all equivalent to np.fft(np.rfft(x2, axis=0), axis=1) + // negative axes are converted as follows: + // -2 -> 0 (= Rank(2) - 2), -1 -> 1 (= Rank(2) - 1) + KokkosFFT::rfft2(execution_space(), x2, x2_hat, /*axes=*/{-1, -2}); + KokkosFFT::rfft2(execution_space(), x2, x2_hat, /*axes=*/{-1, 0}); + KokkosFFT::rfft2(execution_space(), x2, x2_hat, /*axes=*/{1, -2}); + KokkosFFT::rfft2(execution_space(), x2, x2_hat, /*axes=*/{1, 0}); + + // Following codes are all equivalent to np.fft(np.rfft(x3, axis=1), axis=2) + // negative axes are converted as follows: + // -2 -> 1 (= Rank(3) - 2), -1 -> 2 (= Rank(3) - 1) + KokkosFFT::rfft2(execution_space(), x3, x3_hat, /*axes=*/{-1, -2}); + KokkosFFT::rfft2(execution_space(), x3, x3_hat, /*axes=*/{-1, 1}); + KokkosFFT::rfft2(execution_space(), x3, x3_hat, /*axes=*/{2, -2}); + KokkosFFT::rfft2(execution_space(), x3, x3_hat, /*axes=*/{2, 1}); + +.. note:: + + If you rely on negative axes, you can specify last axes no matter what the rank of Views is. + However, the corresponding positive axes to last axes are different depending on the rank of Views. + Thus, it is recommended to use negative axes for simplicity. diff --git a/docs/samples/07_unmanaged_views.rst b/docs/samples/07_unmanaged_views.rst new file mode 100644 index 00000000..5c63c110 --- /dev/null +++ b/docs/samples/07_unmanaged_views.rst @@ -0,0 +1,14 @@ +.. SPDX-FileCopyrightText: (C) The Kokkos-FFT development team, see COPYRIGHT.md file +.. +.. SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception + +.. _07_unmanaged_views: + +Using Unmanaged Views +===================== + +KokkosFFT +--------- + +.. literalinclude:: ../../examples/07_unmanaged_views/07_unmanaged_views.cpp + :language: C++ diff --git a/fft/src/KokkosFFT_Plans.hpp b/fft/src/KokkosFFT_Plans.hpp index eebc022d..05758499 100644 --- a/fft/src/KokkosFFT_Plans.hpp +++ b/fft/src/KokkosFFT_Plans.hpp @@ -153,7 +153,8 @@ class Plan { /// \param out [in] Ouput data /// \param direction [in] Direction of FFT (forward/backward) /// \param axis [in] Axis over which FFT is performed - /// \param n [in] Length of the transformed axis of the output (optional) + /// \param n [in] Length of the transformed axis of the output (default, + /// nullopt) // explicit Plan(const ExecutionSpace& exec_space, InViewType& in, OutViewType& out, KokkosFFT::Direction direction, int axis, @@ -211,11 +212,11 @@ class Plan { /// \param out [in] Ouput data /// \param direction [in] Direction of FFT (forward/backward) /// \param axes [in] Axes over which FFT is performed - /// \param s [in] Shape of the transformed axis of the output (optional) + /// \param s [in] Shape of the transformed axis of the output (default, {}) // explicit Plan(const ExecutionSpace& exec_space, InViewType& in, OutViewType& out, KokkosFFT::Direction direction, - axis_type axes, shape_type s = {0}) + axis_type axes, shape_type s = {}) : m_exec_space(exec_space), m_axes(axes), m_direction(direction) { static_assert(KokkosFFT::Impl::is_AllowedSpace_v, "Plan::Plan: ExecutionSpace is not allowed "); diff --git a/fft/src/KokkosFFT_Transform.hpp b/fft/src/KokkosFFT_Transform.hpp index 490e3d7d..7b9028ce 100644 --- a/fft/src/KokkosFFT_Transform.hpp +++ b/fft/src/KokkosFFT_Transform.hpp @@ -123,9 +123,10 @@ namespace KokkosFFT { /// \param exec_space [in] Kokkos execution space /// \param in [in] Input data (complex) /// \param out [out] Ouput data (complex) -/// \param norm [in] How the normalization is applied (optional) -/// \param axis [in] Axis over which FFT is performed (optional) -/// \param n [in] Length of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param axis [in] Axis over which FFT is performed (default, -1) +/// \param n [in] Length of the transformed axis of the output (default, +/// nullopt) template void fft(const ExecutionSpace& exec_space, const InViewType& in, OutViewType& out, @@ -152,9 +153,10 @@ void fft(const ExecutionSpace& exec_space, const InViewType& in, /// \param exec_space [in] Kokkos execution space /// \param in [in] Input data (complex) /// \param out [out] Ouput data (complex) -/// \param norm [in] How the normalization is applied (optional) -/// \param axis [in] Axis over which FFT is performed (optional) -/// \param n [in] Length of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param axis [in] Axis over which FFT is performed (default, -1) +/// \param n [in] Length of the transformed axis of the output (default, +/// nullopt) template void ifft(const ExecutionSpace& exec_space, const InViewType& in, OutViewType& out, @@ -181,9 +183,10 @@ void ifft(const ExecutionSpace& exec_space, const InViewType& in, /// \param exec_space [in] Kokkos execution space /// \param in [in] Input data (real) /// \param out [out] Ouput data (complex) -/// \param norm [in] How the normalization is applied (optional) -/// \param axis [in] Axis over which FFT is performed (optional) -/// \param n [in] Length of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param axis [in] Axis over which FFT is performed (default, -1) +/// \param n [in] Length of the transformed axis of the output (default, +/// nullopt) template void rfft(const ExecutionSpace& exec_space, const InViewType& in, OutViewType& out, @@ -216,9 +219,10 @@ void rfft(const ExecutionSpace& exec_space, const InViewType& in, /// \param exec_space [in] Kokkos execution space /// \param in [in] Input data (complex) /// \param out [out] Ouput data (real) -/// \param norm [in] How the normalization is applied (optional) -/// \param axis [in] Axis over which FFT is performed (optional) -/// \param n [in] Length of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param axis [in] Axis over which FFT is performed (default, -1) +/// \param n [in] Length of the transformed axis of the output (default, +/// nullopt) template void irfft(const ExecutionSpace& exec_space, const InViewType& in, OutViewType& out, @@ -252,9 +256,10 @@ void irfft(const ExecutionSpace& exec_space, const InViewType& in, /// \param exec_space [in] Kokkos execution space /// \param in [in] Input data (complex) /// \param out [out] Ouput data (real) -/// \param norm [in] How the normalization is applied (optional) -/// \param axis [in] Axis over which FFT is performed (optional) -/// \param n [in] Length of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param axis [in] Axis over which FFT is performed (default, -1) +/// \param n [in] Length of the transformed axis of the output (default, +/// nullopt) template void hfft(const ExecutionSpace& exec_space, const InViewType& in, OutViewType& out, @@ -295,9 +300,10 @@ void hfft(const ExecutionSpace& exec_space, const InViewType& in, /// \param exec_space [in] Kokkos execution space /// \param in [in] Input data (real) /// \param out [out] Ouput data (complex) -/// \param norm [in] How the normalization is applied (optional) -/// \param axis [in] Axis over which FFT is performed (optional) -/// \param n [in] Length of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param axis [in] Axis over which FFT is performed (default, -1) +/// \param n [in] Length of the transformed axis of the output (default, +/// nullopt) template void ihfft(const ExecutionSpace& exec_space, const InViewType& in, OutViewType& out, @@ -336,14 +342,14 @@ void ihfft(const ExecutionSpace& exec_space, const InViewType& in, /// \param exec_space [in] Kokkos execution space /// \param in [in] Input data (complex) /// \param out [out] Ouput data (complex) -/// \param norm [in] How the normalization is applied (optional) -/// \param axes [in] Axes over which FFT is performed (optional) -/// \param s [in] Shape of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param axes [in] Axes over which FFT is performed (default, {-2, -1}) +/// \param s [in] Shape of the transformed axis of the output (default, {}) template void fft2(const ExecutionSpace& exec_space, const InViewType& in, OutViewType& out, KokkosFFT::Normalization norm = KokkosFFT::Normalization::backward, - axis_type<2> axes = {-2, -1}, shape_type<2> s = {0}) { + axis_type<2> axes = {-2, -1}, shape_type<2> s = {}) { static_assert( KokkosFFT::Impl::are_operatable_views_v, @@ -365,14 +371,14 @@ void fft2(const ExecutionSpace& exec_space, const InViewType& in, /// \param exec_space [in] Kokkos execution space /// \param in [in] Input data (complex) /// \param out [out] Ouput data (complex) -/// \param norm [in] How the normalization is applied (optional) -/// \param axes [in] Axes over which FFT is performed (optional) -/// \param s [in] Shape of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param axes [in] Axes over which FFT is performed (default, {-2, -1}) +/// \param s [in] Shape of the transformed axis of the output (default, {}) template void ifft2(const ExecutionSpace& exec_space, const InViewType& in, OutViewType& out, KokkosFFT::Normalization norm = KokkosFFT::Normalization::backward, - axis_type<2> axes = {-2, -1}, shape_type<2> s = {0}) { + axis_type<2> axes = {-2, -1}, shape_type<2> s = {}) { static_assert( KokkosFFT::Impl::are_operatable_views_v, @@ -395,14 +401,14 @@ void ifft2(const ExecutionSpace& exec_space, const InViewType& in, /// \param exec_space [in] Kokkos execution space /// \param in [in] Input data (real) /// \param out [out] Ouput data (complex) -/// \param norm [in] How the normalization is applied (optional) -/// \param axes [in] Axes over which FFT is performed (optional) -/// \param s [in] Shape of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param axes [in] Axes over which FFT is performed (default, {-2, -1}) +/// \param s [in] Shape of the transformed axis of the output (default, {}) template void rfft2(const ExecutionSpace& exec_space, const InViewType& in, OutViewType& out, KokkosFFT::Normalization norm = KokkosFFT::Normalization::backward, - axis_type<2> axes = {-2, -1}, shape_type<2> s = {0}) { + axis_type<2> axes = {-2, -1}, shape_type<2> s = {}) { static_assert( KokkosFFT::Impl::are_operatable_views_v, @@ -431,14 +437,14 @@ void rfft2(const ExecutionSpace& exec_space, const InViewType& in, /// \param exec_space [in] Kokkos execution space /// \param in [in] Input data (complex) /// \param out [out] Ouput data (real) -/// \param norm [in] How the normalization is applied (optional) -/// \param axes [in] Axes over which FFT is performed (optional) -/// \param s [in] Shape of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param axes [in] Axes over which FFT is performed (default, {-2, -1}) +/// \param s [in] Shape of the transformed axis of the output (default, {}) template void irfft2(const ExecutionSpace& exec_space, const InViewType& in, OutViewType& out, KokkosFFT::Normalization norm = KokkosFFT::Normalization::backward, - axis_type<2> axes = {-2, -1}, shape_type<2> s = {0}) { + axis_type<2> axes = {-2, -1}, shape_type<2> s = {}) { static_assert( KokkosFFT::Impl::are_operatable_views_v, @@ -470,8 +476,8 @@ void irfft2(const ExecutionSpace& exec_space, const InViewType& in, /// \param in [in] Input data (complex) /// \param out [out] Ouput data (complex) /// \param axes [in] Axes over which FFT is performed (default, all axes) -/// \param norm [in] How the normalization is applied (optional) -/// \param s [in] Shape of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param s [in] Shape of the transformed axis of the output (default, {}) #if defined(DOXY) template @@ -510,8 +516,8 @@ void fftn( /// \param in [in] Input data (complex) /// \param out [out] Ouput data (complex) /// \param axes [in] Axes over which FFT is performed (default, all axes) -/// \param norm [in] How the normalization is applied (optional) -/// \param s [in] Shape of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param s [in] Shape of the transformed axis of the output (default, {}) #if defined(DOXY) template @@ -552,8 +558,8 @@ void ifftn( /// \param in [in] Input data (real) /// \param out [out] Ouput data (complex) /// \param axes [in] Axes over which FFT is performed (default, all axes) -/// \param norm [in] How the normalization is applied (optional) -/// \param s [in] Shape of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param s [in] Shape of the transformed axis of the output (default, {}) #if defined(DOXY) template @@ -600,8 +606,8 @@ void rfftn( /// \param in [in] Input data (complex) /// \param out [out] Ouput data (real) /// \param axes [in] Axes over which FFT is performed (default, all axes) -/// \param norm [in] How the normalization is applied (optional) -/// \param s [in] Shape of the transformed axis of the output (optional) +/// \param norm [in] How the normalization is applied (default, backward) +/// \param s [in] Shape of the transformed axis of the output (default, {}) #if defined(DOXY) template