LCOV - code coverage report
Current view: top level - src/FFT - FFT.hpp (source / functions) Coverage Total Hit
Test: report.info Lines: 49.4 % 180 89
Test Date: 2025-05-21 16:07:51 Functions: 49.1 % 114 56
Branches: 24.8 % 843 209

             Branch data     Line data    Source code
       1                 :             : //
       2                 :             : // Class FFT
       3                 :             : //   The FFT class performs complex-to-complex,
       4                 :             : //   real-to-complex on IPPL Fields.
       5                 :             : //   FFT is templated on the type of transform to be performed,
       6                 :             : //   the dimensionality of the Field to transform, and the
       7                 :             : //   floating-point precision type of the Field (float or double).
       8                 :             : //   Currently, we use heffte for taking the transforms and the class FFT
       9                 :             : //   serves as an interface between IPPL and heffte. In making this interface,
      10                 :             : //   we have referred Cabana library.
      11                 :             : //   https://github.com/ECP-copa/Cabana.
      12                 :             : //
      13                 :             : // Copyright (c) 2021, Sriramkrishnan Muralikrishnan,
      14                 :             : // Paul Scherrer Institut, Villigen PSI, Switzerland
      15                 :             : // All rights reserved
      16                 :             : //
      17                 :             : // This file is part of IPPL.
      18                 :             : //
      19                 :             : /**
      20                 :             :    Implementations for FFT constructor/destructor and transforms
      21                 :             : */
      22                 :             : 
      23                 :             : #include "Utility/IpplTimings.h"
      24                 :             : 
      25                 :             : #include "Field/BareField.h"
      26                 :             : 
      27                 :             : #include "FieldLayout/FieldLayout.h"
      28                 :             : 
      29                 :             : namespace ippl {
      30                 :             : 
      31                 :             :     template <typename Field, template <typename...> class FFT, typename Backend, typename T>
      32         [ +  - ]:           4 :     FFTBase<Field, FFT, Backend, T>::FFTBase(const Layout_t& layout, const ParameterList& params) {
      33                 :             :         std::array<long long, 3> low;
      34                 :             :         std::array<long long, 3> high;
      35                 :             : 
      36         [ +  - ]:           4 :         const NDIndex<Dim> lDom = layout.getLocalNDIndex();
      37         [ +  - ]:           4 :         domainToBounds(lDom, low, high);
      38                 :             : 
      39                 :           4 :         heffte::box3d<long long> inbox  = {low, high};
      40                 :           4 :         heffte::box3d<long long> outbox = {low, high};
      41                 :             : 
      42         [ +  - ]:           4 :         setup(inbox, outbox, params);
      43                 :           4 :     }
      44                 :             : 
      45                 :             :     template <typename Field, template <typename...> class FFT, typename Backend, typename T>
      46                 :          12 :     void FFTBase<Field, FFT, Backend, T>::domainToBounds(const NDIndex<Dim>& domain,
      47                 :             :                                                          std::array<long long, 3>& low,
      48                 :             :                                                          std::array<long long, 3>& high) {
      49         [ +  - ]:          12 :         low.fill(0);
      50         [ +  - ]:          12 :         high.fill(0);
      51                 :             : 
      52                 :             :         /**
      53                 :             :          * Static cast to detail::long long (uint64_t) is necessary, as heffte::box3d requires it
      54                 :             :          * like that.
      55                 :             :          */
      56         [ +  + ]:          42 :         for (size_t d = 0; d < Dim; ++d) {
      57                 :          30 :             low[d]  = static_cast<long long>(domain[d].first());
      58                 :          30 :             high[d] = static_cast<long long>(domain[d].length() + domain[d].first() - 1);
      59                 :             :         }
      60                 :          12 :     }
      61                 :             : 
      62                 :             :     /**
      63                 :             :            setup performs the initialization necessary.
      64                 :             :     */
      65                 :             :     template <typename Field, template <typename...> class FFT, typename Backend, typename T>
      66                 :           8 :     void FFTBase<Field, FFT, Backend, T>::setup(const heffte::box3d<long long>& inbox,
      67                 :             :                                                 const heffte::box3d<long long>& outbox,
      68                 :             :                                                 const ParameterList& params) {
      69         [ +  - ]:           8 :         heffte::plan_options heffteOptions = heffte::default_options<heffteBackend>();
      70                 :             : 
      71   [ +  -  +  -  :          16 :         if (!params.get<bool>("use_heffte_defaults")) {
                   -  + ]
      72   [ #  #  #  # ]:           0 :             heffteOptions.use_pencils = params.get<bool>("use_pencils");
      73   [ #  #  #  # ]:           0 :             heffteOptions.use_reorder = params.get<bool>("use_reorder");
      74                 :             : #ifdef Heffte_ENABLE_GPU
      75                 :             :             heffteOptions.use_gpu_aware = params.get<bool>("use_gpu_aware");
      76                 :             : #endif
      77                 :             : 
      78   [ #  #  #  #  :           0 :             switch (params.get<int>("comm")) {
             #  #  #  #  
                      # ]
      79                 :           0 :                 case a2a:
      80                 :           0 :                     heffteOptions.algorithm = heffte::reshape_algorithm::alltoall;
      81                 :           0 :                     break;
      82                 :           0 :                 case a2av:
      83                 :           0 :                     heffteOptions.algorithm = heffte::reshape_algorithm::alltoallv;
      84                 :           0 :                     break;
      85                 :           0 :                 case p2p:
      86                 :           0 :                     heffteOptions.algorithm = heffte::reshape_algorithm::p2p;
      87                 :           0 :                     break;
      88                 :           0 :                 case p2p_pl:
      89                 :           0 :                     heffteOptions.algorithm = heffte::reshape_algorithm::p2p_plined;
      90                 :           0 :                     break;
      91                 :           0 :                 default:
      92   [ #  #  #  #  :           0 :                     throw IpplException("FFT::setup", "Unrecognized heffte communication type");
                   #  # ]
      93                 :             :             }
      94                 :             :         }
      95                 :             : 
      96                 :             :         if constexpr (std::is_same_v<FFT<heffteBackend>, heffte::fft3d<heffteBackend>>) {
      97         [ +  - ]:           4 :             heffte_m = std::make_shared<FFT<heffteBackend, long long>>(
      98                 :           4 :                 inbox, outbox, Comm->getCommunicator(), heffteOptions);
      99                 :             :         } else {
     100                 :           4 :             heffte_m = std::make_shared<FFT<heffteBackend, long long>>(
     101   [ +  -  +  -  :          12 :                 inbox, outbox, params.get<int>("r2c_direction"), Comm->getCommunicator(),
                   +  - ]
     102                 :             :                 heffteOptions);
     103                 :             :         }
     104                 :             : 
     105                 :             :         // heffte::gpu::device_set(Comm->rank() % heffte::gpu::device_count());
     106         [ +  - ]:           8 :         if (workspace_m.size() < heffte_m->size_workspace()) {
     107         [ +  - ]:          16 :             workspace_m = workspace_t(heffte_m->size_workspace());
     108                 :             :         }
     109                 :           8 :     }
     110                 :             : 
     111                 :             :     template <typename ComplexField>
     112                 :           0 :     void FFT<CCTransform, ComplexField>::warmup(ComplexField& f) {
     113                 :           0 :         this->transform(FORWARD, f);
     114                 :           0 :         this->transform(BACKWARD, f);
     115                 :           0 :     }
     116                 :             : 
     117                 :             :     template <typename ComplexField>
     118                 :           8 :     void FFT<CCTransform, ComplexField>::transform(TransformDirection direction, ComplexField& f) {
     119                 :             :         static_assert(Dim == 2 || Dim == 3, "heFFTe only supports 2D and 3D");
     120                 :             : 
     121         [ +  - ]:           8 :         auto fview       = f.getView();
     122                 :           8 :         const int nghost = f.getNghost();
     123                 :             : 
     124                 :             :         /**
     125                 :             :          *This copy to a temporary Kokkos view is needed because of following
     126                 :             :          *reasons:
     127                 :             :          *1) heffte wants the input and output fields without ghost layers
     128                 :             :          *2) heffte accepts data in layout left (by default) even though this
     129                 :             :          *can be changed during heffte box creation
     130                 :             :          */
     131                 :           8 :         auto& tempField = this->tempField;
     132   [ +  -  +  + ]:           8 :         if (tempField.size() != f.getOwned().size()) {
     133   [ +  -  +  -  :           8 :             tempField = detail::shrinkView("tempField", fview, nghost);
                   +  - ]
     134                 :             :         }
     135                 :             : 
     136                 :             :         using index_array_type = typename RangePolicy<Dim>::index_array_type;
     137   [ +  -  +  - ]:           8 :         ippl::parallel_for(
     138                 :           8 :             "copy from Kokkos FFT", getRangePolicy(fview, nghost),
     139   [ +  -  +  -  :       36880 :             KOKKOS_LAMBDA(const index_array_type& args) {
             +  -  -  - ]
     140   [ #  #  #  #  :       18432 :                 apply(tempField, args - nghost).real(apply(fview, args).real());
           #  # ][ #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     141   [ #  #  #  #  :       18432 :                 apply(tempField, args - nghost).imag(apply(fview, args).imag());
           #  # ][ #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     142                 :             :             });
     143                 :             : 
     144         [ +  + ]:           8 :         if (direction == FORWARD) {
     145   [ +  -  +  -  :           4 :             this->heffte_m->forward(tempField.data(), tempField.data(), this->workspace_m.data(),
                   +  - ]
     146                 :             :                                     heffte::scale::full);
     147         [ +  - ]:           4 :         } else if (direction == BACKWARD) {
     148   [ +  -  +  -  :           4 :             this->heffte_m->backward(tempField.data(), tempField.data(), this->workspace_m.data(),
                   +  - ]
     149                 :             :                                      heffte::scale::none);
     150                 :             :         } else {
     151         [ #  # ]:           0 :             throw std::logic_error("Only 1:forward and -1:backward are allowed as directions");
     152                 :             :         }
     153                 :             : 
     154   [ +  -  +  - ]:           8 :         ippl::parallel_for(
     155                 :           8 :             "copy to Kokkos FFT", getRangePolicy(fview, nghost),
     156   [ +  -  +  -  :       36880 :             KOKKOS_LAMBDA(const index_array_type& args) {
          +  -  -  -  -  
                      - ]
     157   [ #  #  #  #  :       18432 :                 apply(fview, args).real() = apply(tempField, args - nghost).real();
           #  # ][ #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     158   [ #  #  #  #  :       18432 :                 apply(fview, args).imag() = apply(tempField, args - nghost).imag();
           #  # ][ #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     159                 :             :             });
     160                 :           8 :     }
     161                 :             : 
     162                 :             :     //========================================================================
     163                 :             :     // FFT RCTransform Constructors
     164                 :             :     //========================================================================
     165                 :             : 
     166                 :             :     /**
     167                 :             :      *Create a new FFT object of type RCTransform, with given input and output
     168                 :             :      *layouts and heffte parameters.
     169                 :             :      */
     170                 :             : 
     171                 :             :     template <typename RealField>
     172                 :           4 :     FFT<RCTransform, RealField>::FFT(const Layout_t& layoutInput, const Layout_t& layoutOutput,
     173         [ +  - ]:           4 :                                      const ParameterList& params) {
     174                 :             :         /**
     175                 :             :          * Heffte requires to pass a 3D array even for 2D and
     176                 :             :          * 1D FFTs we just have to make the length in other
     177                 :             :          * dimensions to be 1.
     178                 :             :          */
     179                 :             :         std::array<long long, 3> lowInput;
     180                 :             :         std::array<long long, 3> highInput;
     181                 :             :         std::array<long long, 3> lowOutput;
     182                 :             :         std::array<long long, 3> highOutput;
     183                 :             : 
     184         [ +  - ]:           4 :         const NDIndex<Dim>& lDomInput  = layoutInput.getLocalNDIndex();
     185         [ +  - ]:           4 :         const NDIndex<Dim>& lDomOutput = layoutOutput.getLocalNDIndex();
     186                 :             : 
     187         [ +  - ]:           4 :         this->domainToBounds(lDomInput, lowInput, highInput);
     188         [ +  - ]:           4 :         this->domainToBounds(lDomOutput, lowOutput, highOutput);
     189                 :             : 
     190                 :           4 :         heffte::box3d<long long> inbox  = {lowInput, highInput};
     191                 :           4 :         heffte::box3d<long long> outbox = {lowOutput, highOutput};
     192                 :             : 
     193         [ +  - ]:           4 :         this->setup(inbox, outbox, params);
     194                 :           4 :     }
     195                 :             : 
     196                 :             :     template <typename RealField>
     197                 :           0 :     void FFT<RCTransform, RealField>::warmup(RealField& f, ComplexField& g) {
     198                 :           0 :         this->transform(FORWARD, f, g);
     199                 :           0 :         this->transform(BACKWARD, f, g);
     200                 :           0 :     }
     201                 :             : 
     202                 :             :     template <typename RealField>
     203                 :           8 :     void FFT<RCTransform, RealField>::transform(TransformDirection direction, RealField& f,
     204                 :             :                                                 ComplexField& g) {
     205                 :             :         static_assert(Dim == 2 || Dim == 3, "heFFTe only supports 2D and 3D");
     206                 :             : 
     207         [ +  - ]:           8 :         auto fview        = f.getView();
     208         [ +  - ]:           8 :         auto gview        = g.getView();
     209                 :           8 :         const int nghostf = f.getNghost();
     210                 :           8 :         const int nghostg = g.getNghost();
     211                 :             : 
     212                 :             :         /**
     213                 :             :          *This copy to a temporary Kokkos view is needed because of following
     214                 :             :          *reasons:
     215                 :             :          *1) heffte wants the input and output fields without ghost layers
     216                 :             :          *2) heffte accepts data in layout left (by default) eventhough this
     217                 :             :          *can be changed during heffte box creation
     218                 :             :          */
     219                 :           8 :         auto& tempFieldf = this->tempField;
     220                 :           8 :         auto& tempFieldg = this->tempFieldComplex;
     221   [ +  -  +  + ]:           8 :         if (tempFieldf.size() != f.getOwned().size()) {
     222   [ +  -  +  -  :           8 :             tempFieldf = detail::shrinkView("tempFieldf", fview, nghostf);
                   +  - ]
     223                 :             :         }
     224   [ +  -  +  + ]:           8 :         if (tempFieldg.size() != g.getOwned().size()) {
     225   [ +  -  +  -  :           8 :             tempFieldg = detail::shrinkView("tempFieldg", gview, nghostg);
                   +  - ]
     226                 :             :         }
     227                 :             : 
     228                 :             :         using index_array_type = typename RangePolicy<Dim>::index_array_type;
     229   [ +  -  +  - ]:           8 :         ippl::parallel_for(
     230                 :           8 :             "copy from Kokkos f field in FFT", getRangePolicy(fview, nghostf),
     231   [ +  -  +  -  :       36880 :             KOKKOS_LAMBDA(const index_array_type& args) {
             +  -  -  - ]
     232   [ #  #  #  # ]:       18432 :                 apply(tempFieldf, args - nghostf) = apply(fview, args);
           [ #  #  #  #  
             #  #  #  # ]
           [ +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
                   +  - ]
     233                 :             :             });
     234   [ +  -  +  - ]:           8 :         ippl::parallel_for(
     235                 :           8 :             "copy from Kokkos g field in FFT", getRangePolicy(gview, nghostg),
     236   [ +  -  +  -  :       19600 :             KOKKOS_LAMBDA(const index_array_type& args) {
             +  -  -  - ]
     237   [ #  #  #  #  :        9792 :                 apply(tempFieldg, args - nghostg).real(apply(gview, args).real());
           #  # ][ #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     238   [ #  #  #  #  :        9792 :                 apply(tempFieldg, args - nghostg).imag(apply(gview, args).imag());
           #  # ][ #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     239                 :             :             });
     240                 :             : 
     241         [ +  + ]:           8 :         if (direction == FORWARD) {
     242   [ +  -  +  -  :           4 :             this->heffte_m->forward(tempFieldf.data(), tempFieldg.data(), this->workspace_m.data(),
                   +  - ]
     243                 :             :                                     heffte::scale::full);
     244         [ +  - ]:           4 :         } else if (direction == BACKWARD) {
     245   [ +  -  +  -  :           4 :             this->heffte_m->backward(tempFieldg.data(), tempFieldf.data(), this->workspace_m.data(),
                   +  - ]
     246                 :             :                                      heffte::scale::none);
     247                 :             :         } else {
     248         [ #  # ]:           0 :             throw std::logic_error("Only 1:forward and -1:backward are allowed as directions");
     249                 :             :         }
     250                 :             : 
     251   [ +  -  +  - ]:           8 :         ippl::parallel_for(
     252                 :           8 :             "copy to Kokkos f field FFT", getRangePolicy(fview, nghostf),
     253   [ +  -  +  -  :       36880 :             KOKKOS_LAMBDA(const index_array_type& args) {
          +  -  -  -  -  
                      - ]
     254   [ #  #  #  #  :       18432 :                 apply(fview, args) = apply(tempFieldf, args - nghostf);
           #  # ][ #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     255                 :             :             });
     256                 :             : 
     257   [ +  -  +  - ]:           8 :         ippl::parallel_for(
     258                 :           8 :             "copy to Kokkos g field FFT", getRangePolicy(gview, nghostg),
     259   [ +  -  +  -  :       19600 :             KOKKOS_LAMBDA(const index_array_type& args) {
          +  -  -  -  -  
                      - ]
     260   [ #  #  #  #  :        9792 :                 apply(gview, args).real() = apply(tempFieldg, args - nghostg).real();
           #  # ][ #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     261   [ #  #  #  #  :        9792 :                 apply(gview, args).imag() = apply(tempFieldg, args - nghostg).imag();
           #  # ][ #  #  
          #  #  #  #  #  
             #  #  #  #  
           # ][ +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     262                 :             :             });
     263                 :           8 :     }
     264                 :             : 
     265                 :             :     template <typename Field>
     266                 :             :     void FFT<SineTransform, Field>::warmup(Field& f) {
     267                 :             :         this->transform(FORWARD, f);
     268                 :             :         this->transform(BACKWARD, f);
     269                 :             :     }
     270                 :             : 
     271                 :             :     template <typename Field>
     272                 :           0 :     void FFT<SineTransform, Field>::transform(TransformDirection direction, Field& f) {
     273                 :             :         static_assert(Dim == 2 || Dim == 3, "heFFTe only supports 2D and 3D");
     274                 :             : #ifdef Heffte_ENABLE_FFTW
     275                 :             :         if (direction == FORWARD) {
     276                 :             :             f = f / 8.0;
     277                 :             :         }
     278                 :             : #endif
     279                 :             : 
     280         [ #  # ]:           0 :         auto fview       = f.getView();
     281                 :           0 :         const int nghost = f.getNghost();
     282                 :             : 
     283                 :             :         /**
     284                 :             :          *This copy to a temporary Kokkos view is needed because of following
     285                 :             :          *reasons:
     286                 :             :          *1) heffte wants the input and output fields without ghost layers
     287                 :             :          *2) heffte accepts data in layout left (by default) eventhough this
     288                 :             :          *can be changed during heffte box creation
     289                 :             :          */
     290                 :           0 :         auto& tempField = this->tempField;
     291   [ #  #  #  # ]:           0 :         if (tempField.size() != f.getOwned().size()) {
     292   [ #  #  #  #  :           0 :             tempField = detail::shrinkView("tempField", fview, nghost);
                   #  # ]
     293                 :             :         }
     294                 :             : 
     295                 :             :         using index_array_type = typename RangePolicy<Dim>::index_array_type;
     296   [ #  #  #  # ]:           0 :         ippl::parallel_for(
     297                 :           0 :             "copy from Kokkos FFT", getRangePolicy(fview, nghost),
     298   [ #  #  #  #  :           0 :             KOKKOS_LAMBDA(const index_array_type& args) {
             #  #  #  # ]
     299   [ #  #  #  # ]:           0 :                 apply(tempField, args - nghost) = apply(fview, args);
     300                 :             :             });
     301                 :             : 
     302         [ #  # ]:           0 :         if (direction == FORWARD) {
     303   [ #  #  #  #  :           0 :             this->heffte_m->forward(tempField.data(), tempField.data(), this->workspace_m.data(),
                   #  # ]
     304                 :             :                                     heffte::scale::full);
     305         [ #  # ]:           0 :         } else if (direction == BACKWARD) {
     306   [ #  #  #  #  :           0 :             this->heffte_m->backward(tempField.data(), tempField.data(), this->workspace_m.data(),
                   #  # ]
     307                 :             :                                      heffte::scale::none);
     308                 :             :         } else {
     309         [ #  # ]:           0 :             throw std::logic_error("Only 1:forward and -1:backward are allowed as directions");
     310                 :             :         }
     311                 :             : 
     312   [ #  #  #  # ]:           0 :         ippl::parallel_for(
     313                 :           0 :             "copy to Kokkos FFT", getRangePolicy(fview, nghost),
     314   [ #  #  #  #  :           0 :             KOKKOS_LAMBDA(const index_array_type& args) {
          #  #  #  #  #  
                      # ]
     315   [ #  #  #  #  :           0 :                 apply(fview, args) = apply(tempField, args - nghost);
                   #  # ]
     316                 :             :             });
     317                 :             : #ifdef Heffte_ENABLE_FFTW
     318                 :             :         if (direction == BACKWARD) {
     319                 :             :             f = f * 8.0;
     320                 :             :         }
     321                 :             : #endif
     322                 :           0 :     }
     323                 :             : 
     324                 :             :     template <typename Field>
     325                 :             :     void FFT<CosTransform, Field>::warmup(Field& f) {
     326                 :             :         this->transform(FORWARD, f);
     327                 :             :         this->transform(BACKWARD, f);
     328                 :             :     }
     329                 :             : 
     330                 :             :     template <typename Field>
     331                 :           0 :     void FFT<CosTransform, Field>::transform(TransformDirection direction, Field& f) {
     332                 :             :         static_assert(Dim == 2 || Dim == 3, "heFFTe only supports 2D and 3D");
     333                 :             : #ifdef Heffte_ENABLE_FFTW
     334                 :             :         if (direction == FORWARD) {
     335                 :             :             f = f / 8.0;
     336                 :             :         }
     337                 :             : #endif
     338                 :             : 
     339         [ #  # ]:           0 :         auto fview       = f.getView();
     340                 :           0 :         const int nghost = f.getNghost();
     341                 :             : 
     342                 :             :         /**
     343                 :             :          *This copy to a temporary Kokkos view is needed because of following
     344                 :             :          *reasons:
     345                 :             :          *1) heffte wants the input and output fields without ghost layers
     346                 :             :          *2) heffte accepts data in layout left (by default) eventhough this
     347                 :             :          *can be changed during heffte box creation
     348                 :             :          */
     349                 :           0 :         auto& tempField = this->tempField;
     350   [ #  #  #  # ]:           0 :         if (tempField.size() != f.getOwned().size()) {
     351   [ #  #  #  #  :           0 :             tempField = detail::shrinkView("tempField", fview, nghost);
                   #  # ]
     352                 :             :         }
     353                 :             : 
     354                 :             :         using index_array_type = typename RangePolicy<Dim>::index_array_type;
     355   [ #  #  #  # ]:           0 :         ippl::parallel_for(
     356                 :           0 :             "copy from Kokkos FFT", getRangePolicy(fview, nghost),
     357   [ #  #  #  #  :           0 :             KOKKOS_LAMBDA(const index_array_type& args) {
             #  #  #  # ]
     358   [ #  #  #  # ]:           0 :                 apply(tempField, args - nghost) = apply(fview, args);
     359                 :             :             });
     360                 :             : 
     361         [ #  # ]:           0 :         if (direction == FORWARD) {
     362   [ #  #  #  #  :           0 :             this->heffte_m->forward(tempField.data(), tempField.data(), this->workspace_m.data(),
                   #  # ]
     363                 :             :                                     heffte::scale::full);
     364         [ #  # ]:           0 :         } else if (direction == BACKWARD) {
     365   [ #  #  #  #  :           0 :             this->heffte_m->backward(tempField.data(), tempField.data(), this->workspace_m.data(),
                   #  # ]
     366                 :             :                                      heffte::scale::none);
     367                 :             :         } else {
     368         [ #  # ]:           0 :             throw std::logic_error("Only 1:forward and -1:backward are allowed as directions");
     369                 :             :         }
     370                 :             : 
     371   [ #  #  #  # ]:           0 :         ippl::parallel_for(
     372                 :           0 :             "copy to Kokkos FFT", getRangePolicy(fview, nghost),
     373   [ #  #  #  #  :           0 :             KOKKOS_LAMBDA(const index_array_type& args) {
          #  #  #  #  #  
                      # ]
     374   [ #  #  #  #  :           0 :                 apply(fview, args) = apply(tempField, args - nghost);
                   #  # ]
     375                 :             :             });
     376                 :             : #ifdef Heffte_ENABLE_FFTW
     377                 :             :         if (direction == BACKWARD) {
     378                 :             :             f = f * 8.0;
     379                 :             :         }
     380                 :             : #endif
     381                 :           0 :     }
     382                 :             : 
     383                 :             :     template <typename Field>
     384                 :           0 :     void FFT<Cos1Transform, Field>::warmup(Field& f) {
     385                 :           0 :         this->transform(FORWARD, f);
     386                 :           0 :         this->transform(BACKWARD, f);
     387                 :           0 :     }
     388                 :             : 
     389                 :             :     template <typename Field>
     390                 :           0 :     void FFT<Cos1Transform, Field>::transform(TransformDirection direction, Field& f) {
     391                 :             :         static_assert(Dim == 2 || Dim == 3, "heFFTe only supports 2D and 3D");
     392                 :             : 
     393                 :             : /**
     394                 :             :  * This rescaling is needed to match the normalization constant
     395                 :             :  * between fftw and the other gpu interfaces. fftw rescales with an extra factor of 8.
     396                 :             :  */
     397                 :             : #ifdef Heffte_ENABLE_FFTW
     398                 :             :         if (direction == FORWARD) {
     399                 :             :             f = f / 8.0;
     400                 :             :         }
     401                 :             : #endif
     402                 :             : 
     403         [ #  # ]:           0 :         auto fview       = f.getView();
     404                 :           0 :         const int nghost = f.getNghost();
     405                 :             : 
     406                 :             :         /**
     407                 :             :          *This copy to a temporary Kokkos view is needed because of following
     408                 :             :          *reasons:
     409                 :             :          *1) heffte wants the input and output fields without ghost layers
     410                 :             :          *2) heffte accepts data in layout left (by default) eventhough this
     411                 :             :          *can be changed during heffte box creation
     412                 :             :          */
     413                 :           0 :         auto& tempField = this->tempField;
     414   [ #  #  #  # ]:           0 :         if (tempField.size() != f.getOwned().size()) {
     415   [ #  #  #  #  :           0 :             tempField = detail::shrinkView("tempField", fview, nghost);
                   #  # ]
     416                 :             :         }
     417                 :             : 
     418                 :             :         using index_array_type = typename RangePolicy<Dim>::index_array_type;
     419   [ #  #  #  # ]:           0 :         ippl::parallel_for(
     420                 :           0 :             "copy from Kokkos FFT", getRangePolicy(fview, nghost),
     421   [ #  #  #  #  :           0 :             KOKKOS_LAMBDA(const index_array_type& args) {
             #  #  #  # ]
     422   [ #  #  #  # ]:           0 :                 apply(tempField, args - nghost) = apply(fview, args);
           [ #  #  #  #  
             #  #  #  # ]
     423                 :             :             });
     424                 :             : 
     425         [ #  # ]:           0 :         if (direction == FORWARD) {
     426   [ #  #  #  #  :           0 :             this->heffte_m->forward(tempField.data(), tempField.data(), this->workspace_m.data(),
                   #  # ]
     427                 :             :                                     heffte::scale::full);
     428         [ #  # ]:           0 :         } else if (direction == BACKWARD) {
     429   [ #  #  #  #  :           0 :             this->heffte_m->backward(tempField.data(), tempField.data(), this->workspace_m.data(),
                   #  # ]
     430                 :             :                                      heffte::scale::none);
     431                 :             :         } else {
     432         [ #  # ]:           0 :             throw std::logic_error("Only 1:forward and -1:backward are allowed as directions");
     433                 :             :         }
     434                 :             : 
     435   [ #  #  #  # ]:           0 :         ippl::parallel_for(
     436                 :           0 :             "copy to Kokkos FFT", getRangePolicy(fview, nghost),
     437   [ #  #  #  #  :           0 :             KOKKOS_LAMBDA(const index_array_type& args) {
          #  #  #  #  #  
                      # ]
     438   [ #  #  #  #  :           0 :                 apply(fview, args) = apply(tempField, args - nghost);
           #  # ][ #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     439                 :             :             });
     440                 :             : 
     441                 :             : /**
     442                 :             :  * This rescaling is needed to match the normalization constant
     443                 :             :  * between fftw and the other gpu interfaces. fftw rescales with an extra factor of 8.
     444                 :             :  */
     445                 :             : #ifdef Heffte_ENABLE_FFTW
     446                 :             :         if (direction == BACKWARD) {
     447                 :             :             f = f * 8.0;
     448                 :             :         }
     449                 :             : #endif
     450                 :           0 :     }
     451                 :             : 
     452                 :             : }  // namespace ippl
     453                 :             : 
     454                 :             : // vi: set et ts=4 sw=4 sts=4:
     455                 :             : // Local Variables:
     456                 :             : // mode:c
     457                 :             : // c-basic-offset: 4
     458                 :             : // indent-tabs-mode: nil
     459                 :             : // require-final-newline: nil
     460                 :             : // End:
        

Generated by: LCOV version 2.0-1