Skip to content

File fftwplanholder.h

File List > code_source > templat > include > TempLat > fft > external > fftw > fftwplanholder.h

Go to the documentation of this file

#ifndef TEMPLAT_FFT_EXTERNAL_FFTW_FFTWPLANHOLDER_H
#define TEMPLAT_FFT_EXTERNAL_FFTW_FFTWPLANHOLDER_H

/* This file is part of TempLat, available at https://cosmolattice.github.io/templat .
   Copyright 2021-2026 The TempLat authors, see AUTHORS.md.
   Released under the MIT license, see LICENSE.md. */

// File info: Main contributor(s): Wessel Valkenburg, Year: 2019

#include <type_traits>

#ifndef NOFFT
#ifdef HAVE_MPI
#include "fftw3-mpi.h"
#endif
#endif

#ifndef NOFFT
#include "fftw3.h"
#endif

#include "TempLat/fft/fftlibraryinterface.h"
#include "TempLat/parallel/mpi/cartesian/mpicartesiangroup.h"

namespace TempLat
{

  template <typename T, size_t NDim> class FFTWPlanHolder : public FFTPlanInterface<T, NDim>
  {
  public:
#ifdef HAVE_FFTFLOAT
    using plan = typename std::conditional_t<std::is_same_v<float, T>, fftwf_plan, fftw_plan>;
#else
    using plan = fftw_plan;
#endif
    // Put public methods here. These should change very little over time.
    FFTWPlanHolder(MPICartesianGroup group, plan planR2C, plan planC2R)
        : mGroup(group), /* need a reference to the group, to make sure the group is alive as long as the plans are
                            alive. */
          mPlanR2C(std::make_shared<plan>(planR2C)), mPlanC2R(std::make_shared<plan>(planC2R))
    {
    }

    ~FFTWPlanHolder()
    {
      if (mPlanR2C.use_count() < 2) {
        // say << "FFTWPlanHolder is correctly being destructed.\n";
        destroy(*mPlanR2C);
        destroy(*mPlanC2R);
      }
    }

    virtual void c2r(MemoryBlock<T, NDim> &mBlock) { execute_c2r(*mPlanC2R, mBlock); };
    virtual void r2c(MemoryBlock<T, NDim> &mBlock) { execute_r2c(*mPlanR2C, mBlock); };

  private:
    /* Put all member variables and private methods here. These may change arbitrarily. */
    MPICartesianGroup mGroup;
    std::shared_ptr<plan> mPlanR2C, mPlanC2R;

    template <typename S = T>
      requires std::is_same_v<S, double>
    void destroy(plan somePlan)
    {
      fftw_destroy_plan(somePlan);
    }

#ifdef HAVE_FFTFLOAT
    template <typename S = T>
      requires std::is_same_v<S, float>
    void destroy(plan somePlan)
    {
      fftwf_destroy_plan(somePlan);
    }
#endif
    template <typename S = T>
      requires std::is_same_v<S, double>
    void execute_r2c(plan somePlan, MemoryBlock<S, NDim> &mBlock)
    {
      auto block_view = mBlock.getRawHostView();
      fftw_execute_dft_r2c(somePlan, block_view.data(), (fftw_complex *)block_view.data());
      mBlock.pushHostView(); // make sure the data is pushed to the device
    }

#ifdef HAVE_FFTFLOAT
    template <typename S = T>
      requires std::is_same_v<S, float>
    void execute_r2c(plan somePlan, MemoryBlock<S, NDim> &mBlock)
    {
      auto block_view = mBlock.getRawHostView();
      fftwf_execute_dft_r2c(somePlan, block_view.data(), (fftwf_complex *)block_view.data());
      mBlock.pushHostView(); // make sure the data is pushed to the device
    }
#endif

    template <typename S = T>
      requires std::is_same_v<S, double>
    void execute_c2r(plan somePlan, MemoryBlock<S, NDim> &mBlock)
    {
      // sayMPI << "FFTW double c2r starting. Plan: " << somePlan << "\n";
      // sayMPI << "with block size: " << mBlock.size() << "\n";
      auto block_view = mBlock.getRawHostView();
      fftw_execute_dft_c2r(somePlan, (fftw_complex *)block_view.data(), block_view.data());
      // sayMPI << "FFTW double c2r done.\n";
      mBlock.pushHostView(); // make sure the data is pushed to the device
    }

#ifdef HAVE_FFTFLOAT
    template <typename S = T>
      requires std::is_same_v<S, float>
    void execute_c2r(plan somePlan, MemoryBlock<S, NDim> &mBlock)
    {
      auto block_view = mBlock.getRawHostView();
      fftwf_execute_dft_c2r(somePlan, (fftwf_complex *)block_view.data(), block_view.data());
      mBlock.pushHostView(); // make sure the data is pushed to the device
    }
#endif
  };

} // namespace TempLat

#endif