LCOV - code coverage report
Current view: top level - src/PoissonSolvers - LaplaceHelpers.h (source / functions) Coverage Total Hit
Test: final_report.info Lines: 84.4 % 122 103
Test Date: 2025-07-19 00:25:23 Functions: 91.1 % 158 144

            Line data    Source code
       1              : //
       2              : // Helper functions used in PoissonCG.h
       3              : //
       4              : 
       5              : #ifndef IPPL_LAPLACE_HELPERS_H
       6              : #define IPPL_LAPLACE_HELPERS_H
       7              : namespace ippl {
       8              :     namespace detail {
       9              :         // Implements the poisson matrix acting on a d dimensional field
      10              :         template <typename E>
      11              :         struct meta_poisson : public Expression<meta_poisson<E>, sizeof(E)> {
      12              :             constexpr static unsigned dim = E::dim;
      13              : 
      14              :             KOKKOS_FUNCTION
      15              :             meta_poisson(const E& u)
      16              :                 : u_m(u) {}
      17              : 
      18              :             template <typename... Idx>
      19              :             KOKKOS_INLINE_FUNCTION auto operator()(const Idx... args) const {
      20              :                 using index_type       = std::tuple_element_t<0, std::tuple<Idx...>>;
      21              :                 using T                = typename E::Mesh_t::value_type;
      22              :                 T res                  = 0;
      23              :                 index_type coords[dim] = {args...};
      24              :                 auto&& center          = apply(u_m, coords);
      25              :                 for (unsigned d = 0; d < dim; d++) {
      26              :                     index_type coords[dim] = {args...};
      27              : 
      28              :                     coords[d] -= 1;
      29              :                     auto&& left = apply(u_m, coords);
      30              : 
      31              :                     coords[d] += 2;
      32              :                     auto&& right = apply(u_m, coords);
      33              :                     res += (2.0 * center - left - right);
      34              :                 }
      35              :                 return res;
      36              :             }
      37              : 
      38              :         private:
      39              :             const E u_m;
      40              :         };
      41              : 
      42              :         template <typename E>
      43              :         struct meta_lower_laplace
      44              :             : public Expression<meta_lower_laplace<E>,
      45              :                                 sizeof(E) + sizeof(typename E::Mesh_t::vector_type)
      46              :                                     + 2 * sizeof(typename E::Layout_t::NDIndex_t)
      47              :                                     + sizeof(unsigned)> {
      48              :             constexpr static unsigned dim = E::dim;
      49              :             using value_type              = typename E::value_type;
      50              : 
      51              :             KOKKOS_FUNCTION
      52           24 :             meta_lower_laplace(const E& u, const typename E::Mesh_t::vector_type& hvector,
      53              :                                unsigned nghosts, const typename E::Layout_t::NDIndex_t& ldom,
      54              :                                const typename E::Layout_t::NDIndex_t& domain)
      55           24 :                 : u_m(u)
      56           24 :                 , hvector_m(hvector)
      57           24 :                 , nghosts_m(nghosts)
      58           24 :                 , ldom_m(ldom)
      59           24 :                 , domain_m(domain) {}
      60              : 
      61              :             /*
      62              :              * n-dimensional lower triangular Laplacian
      63              :              */
      64              :             template <typename... Idx>
      65       238656 :             KOKKOS_INLINE_FUNCTION auto operator()(const Idx... args) const {
      66              :                 using index_type = std::tuple_element_t<0, std::tuple<Idx...>>;
      67              :                 using T          = typename E::Mesh_t::value_type;
      68       238656 :                 T res            = 0;
      69              : 
      70      1510528 :                 for (unsigned d = 0; d < dim; d++) {
      71      1271872 :                     index_type coords[dim]       = {args...};
      72      1271872 :                     const int global_index       = coords[d] + ldom_m[d].first() - nghosts_m;
      73      1271872 :                     const int size               = domain_m.length()[d];
      74      1271872 :                     const bool not_left_boundary = (global_index != 0);
      75      1271872 :                     const bool right_boundary    = (global_index == size - 1);
      76              : 
      77      1271872 :                     coords[d] -= 1;
      78      1271872 :                     auto&& left = apply(u_m, coords);
      79              : 
      80      1271872 :                     coords[d] += 2;
      81      1271872 :                     auto&& right = apply(u_m, coords);
      82              : 
      83              :                     // not_left_boundary and right_boundary are boolean values
      84              :                     // Because of periodic boundary conditions we need to add this boolean mask to
      85              :                     // obtain the lower triangular part of the Laplace Operator
      86      1271872 :                     res += hvector_m[d] * (not_left_boundary * left + right_boundary * right);
      87              :                 }
      88       238656 :                 return res;
      89              :             }
      90              : 
      91              :         private:
      92              :             using Mesh_t      = typename E::Mesh_t;
      93              :             using Layout_t    = typename E::Layout_t;
      94              :             using vector_type = typename Mesh_t::vector_type;
      95              :             using domain_type = typename Layout_t::NDIndex_t;
      96              :             const E u_m;
      97              :             const vector_type hvector_m;
      98              :             const unsigned nghosts_m;
      99              :             const domain_type ldom_m;
     100              :             const domain_type domain_m;
     101              :         };
     102              : 
     103              :         template <typename E>
     104              :         struct meta_upper_laplace
     105              :             : public Expression<meta_upper_laplace<E>,
     106              :                                 sizeof(E) + sizeof(typename E::Mesh_t::vector_type)
     107              :                                     + 2 * sizeof(typename E::Layout_t::NDIndex_t)
     108              :                                     + sizeof(unsigned)> {
     109              :             constexpr static unsigned dim = E::dim;
     110              :             using value_type              = typename E::value_type;
     111              : 
     112              :             KOKKOS_FUNCTION
     113           24 :             meta_upper_laplace(const E& u, const typename E::Mesh_t::vector_type& hvector,
     114              :                                unsigned nghosts, const typename E::Layout_t::NDIndex_t& ldom,
     115              :                                const typename E::Layout_t::NDIndex_t& domain)
     116           24 :                 : u_m(u)
     117           24 :                 , hvector_m(hvector)
     118           24 :                 , nghosts_m(nghosts)
     119           24 :                 , ldom_m(ldom)
     120           24 :                 , domain_m(domain) {}
     121              : 
     122              :             /*
     123              :              * n-dimensional upper triangular Laplacian
     124              :              */
     125              :             template <typename... Idx>
     126       238656 :             KOKKOS_INLINE_FUNCTION auto operator()(const Idx... args) const {
     127              :                 using index_type = std::tuple_element_t<0, std::tuple<Idx...>>;
     128              :                 using T          = typename E::Mesh_t::value_type;
     129       238656 :                 T res            = 0;
     130              : 
     131      1510528 :                 for (unsigned d = 0; d < dim; d++) {
     132      1271872 :                     index_type coords[dim]        = {args...};
     133      1271872 :                     const int global_index        = coords[d] + ldom_m[d].first() - nghosts_m;
     134      1271872 :                     const int size                = domain_m.length()[d];
     135      1271872 :                     const bool left_boundary      = (global_index == 0);
     136      1271872 :                     const bool not_right_boundary = (global_index != size - 1);
     137              : 
     138      1271872 :                     coords[d] -= 1;
     139      1271872 :                     auto&& left = apply(u_m, coords);
     140              : 
     141      1271872 :                     coords[d] += 2;
     142      1271872 :                     auto&& right = apply(u_m, coords);
     143              : 
     144              :                     // left_boundary and not_right_boundary are boolean values
     145              :                     // Because of periodic boundary conditions we need to add this boolean mask to
     146              :                     // obtain the upper triangular part of the Laplace Operator
     147      1271872 :                     res += hvector_m[d] * (left_boundary * left + not_right_boundary * right);
     148              :                 }
     149       238656 :                 return res;
     150              :             }
     151              : 
     152              :         private:
     153              :             using Mesh_t      = typename E::Mesh_t;
     154              :             using Layout_t    = typename E::Layout_t;
     155              :             using vector_type = typename Mesh_t::vector_type;
     156              :             using domain_type = typename Layout_t::NDIndex_t;
     157              :             const E u_m;
     158              :             const vector_type hvector_m;
     159              :             const unsigned nghosts_m;
     160              :             const domain_type ldom_m;
     161              :             const domain_type domain_m;
     162              :         };
     163              : 
     164              :         template <typename E>
     165              :         struct meta_upper_and_lower_laplace
     166              :             : public Expression<meta_upper_and_lower_laplace<E>,
     167              :                                 sizeof(E) + sizeof(typename E::Mesh_t::vector_type)> {
     168              :             constexpr static unsigned dim = E::dim;
     169              :             using value_type              = typename E::value_type;
     170              : 
     171              :             KOKKOS_FUNCTION
     172           24 :             meta_upper_and_lower_laplace(const E& u, const typename E::Mesh_t::vector_type& hvector)
     173           24 :                 : u_m(u)
     174           24 :                 , hvector_m(hvector) {}
     175              : 
     176              :             /*
     177              :              * n-dimensional upper+lower triangular Laplacian
     178              :              */
     179              :             template <typename... Idx>
     180       238656 :             KOKKOS_INLINE_FUNCTION auto operator()(const Idx... args) const {
     181              :                 using index_type = std::tuple_element_t<0, std::tuple<Idx...>>;
     182              :                 using T          = typename E::Mesh_t::value_type;
     183       238656 :                 T res            = 0;
     184      1510528 :                 for (unsigned d = 0; d < dim; d++) {
     185      1271872 :                     index_type coords[dim] = {args...};
     186      1271872 :                     coords[d] -= 1;
     187      1271872 :                     auto&& left = apply(u_m, coords);
     188      1271872 :                     coords[d] += 2;
     189      1271872 :                     auto&& right = apply(u_m, coords);
     190      1271872 :                     res += hvector_m[d] * (left + right);
     191              :                 }
     192       238656 :                 return res;
     193              :             }
     194              : 
     195              :         private:
     196              :             using vector_type = typename E::Mesh_t::vector_type;
     197              :             const E u_m;
     198              :             const vector_type hvector_m;
     199              :         };
     200              :     }  // namespace detail
     201              : 
     202              :     /*!
     203              :      * User interface of poisson
     204              :      * @param u field
     205              :      */
     206              :     template <typename Field>
     207              :     detail::meta_poisson<Field> poisson(Field& u) {
     208              :         constexpr unsigned Dim = Field::dim;
     209              : 
     210              :         u.fillHalo();
     211              :         BConds<Field, Dim>& bcField = u.getFieldBC();
     212              :         bcField.apply(u);
     213              : 
     214              :         return detail::meta_poisson<Field>(u);
     215              :     }
     216              : 
     217              :     /*!
     218              :      * User interface of lower triangular Laplacian
     219              :      * @param u field
     220              :      */
     221              :     template <typename Field>
     222           24 :     detail::meta_lower_laplace<Field> lower_laplace(Field& u) {
     223           24 :         constexpr unsigned Dim = Field::dim;
     224              : 
     225           24 :         u.fillHalo();
     226           24 :         BConds<Field, Dim>& bcField = u.getFieldBC();
     227           24 :         bcField.apply(u);
     228              : 
     229           24 :         return lower_laplace_no_comm(u);
     230              :     }
     231              : 
     232              :     /*!
     233              :      * User interface of lower triangular Laplacian without exchange of halo cells
     234              :      * @param u field
     235              :      */
     236              :     template <typename Field>
     237           24 :     detail::meta_lower_laplace<Field> lower_laplace_no_comm(Field& u) {
     238           24 :         constexpr unsigned Dim = Field::dim;
     239              : 
     240              :         using mesh_type = typename Field::Mesh_t;
     241           24 :         mesh_type& mesh = u.get_mesh();
     242           24 :         typename mesh_type::vector_type hvector(0);
     243          108 :         for (unsigned d = 0; d < Dim; d++) {
     244           84 :             hvector[d] = 1.0 / Kokkos::pow(mesh.getMeshSpacing(d), 2);
     245              :         }
     246           24 :         const auto& layout = u.getLayout();
     247           24 :         unsigned nghosts   = u.getNghost();
     248           24 :         const auto& ldom   = layout.getLocalNDIndex();
     249           24 :         const auto& domain = layout.getDomain();
     250           48 :         return detail::meta_lower_laplace<Field>(u, hvector, nghosts, ldom, domain);
     251           24 :     }
     252              : 
     253              :     /*!
     254              :      * User interface of upper triangular Laplacian
     255              :      * @param u field
     256              :      */
     257              :     template <typename Field>
     258           24 :     detail::meta_upper_laplace<Field> upper_laplace(Field& u) {
     259           24 :         constexpr unsigned Dim = Field::dim;
     260              : 
     261           24 :         u.fillHalo();
     262           24 :         BConds<Field, Dim>& bcField = u.getFieldBC();
     263           24 :         bcField.apply(u);
     264              : 
     265           24 :         return upper_laplace_no_comm(u);
     266              :     }
     267              : 
     268              :     /*!
     269              :      * User interface of upper triangular Laplacian without exchange of halo cells
     270              :      * @param u field
     271              :      */
     272              :     template <typename Field>
     273           24 :     detail::meta_upper_laplace<Field> upper_laplace_no_comm(Field& u) {
     274           24 :         constexpr unsigned Dim = Field::dim;
     275              : 
     276              :         using mesh_type = typename Field::Mesh_t;
     277           24 :         mesh_type& mesh = u.get_mesh();
     278           24 :         typename mesh_type::vector_type hvector(0);
     279          108 :         for (unsigned d = 0; d < Dim; d++) {
     280           84 :             hvector[d] = 1.0 / Kokkos::pow(mesh.getMeshSpacing(d), 2);
     281              :         }
     282           24 :         const auto& layout = u.getLayout();
     283           24 :         unsigned nghosts   = u.getNghost();
     284           24 :         const auto& ldom   = layout.getLocalNDIndex();
     285           24 :         const auto& domain = layout.getDomain();
     286           48 :         return detail::meta_upper_laplace<Field>(u, hvector, nghosts, ldom, domain);
     287           24 :     }
     288              : 
     289              :     /*!
     290              :      * User interface of upper+lower triangular Laplacian
     291              :      * @param u field
     292              :      */
     293              :     template <typename Field>
     294           24 :     detail::meta_upper_and_lower_laplace<Field> upper_and_lower_laplace(Field& u) {
     295           24 :         constexpr unsigned Dim = Field::dim;
     296              : 
     297           24 :         u.fillHalo();
     298           24 :         BConds<Field, Dim>& bcField = u.getFieldBC();
     299           24 :         bcField.apply(u);
     300              : 
     301           24 :         return upper_and_lower_laplace_no_comm(u);
     302              :     }
     303              : 
     304              :     /*!
     305              :      * User interface of upper+lower triangular Laplacian without exchange of halo cells
     306              :      * @param u field
     307              :      */
     308              :     template <typename Field>
     309           24 :     detail::meta_upper_and_lower_laplace<Field> upper_and_lower_laplace_no_comm(Field& u) {
     310           24 :         constexpr unsigned Dim = Field::dim;
     311              : 
     312              :         using mesh_type = typename Field::Mesh_t;
     313           24 :         mesh_type& mesh = u.get_mesh();
     314           24 :         typename mesh_type::vector_type hvector(0);
     315          108 :         for (unsigned d = 0; d < Dim; d++) {
     316           84 :             hvector[d] = 1.0 / Kokkos::pow(mesh.getMeshSpacing(d), 2);
     317              :         }
     318           48 :         return detail::meta_upper_and_lower_laplace<Field>(u, hvector);
     319           24 :     }
     320              : 
     321              :     /*!
     322              :      * Returns the factor by which to multiply the u field to get
     323              :      * the inverse of the diagonal of the Laplacian.
     324              :      *
     325              :      * @param u field
     326              :      */
     327              : 
     328              :     template <typename Field>
     329            0 :     double negative_inverse_diagonal_laplace(Field& u) {
     330            0 :         constexpr unsigned Dim = Field::dim;
     331              :         using mesh_type        = typename Field::Mesh_t;
     332            0 :         mesh_type& mesh = u.get_mesh();
     333            0 :         double sum    = 0.0;
     334            0 :         double factor = 1.0;
     335            0 :         typename mesh_type::vector_type hvector(0);
     336            0 :         for (unsigned d = 0; d < Dim; ++d) {
     337            0 :             hvector[d] = Kokkos::pow(mesh.getMeshSpacing(d), 2);
     338            0 :             sum += hvector[d] * Kokkos::pow(mesh.getMeshSpacing((d + 1) % Dim), 2);
     339            0 :             factor *= hvector[d];
     340              :         }
     341              : 
     342            0 :         return 0.5 * (factor / sum);
     343            0 :     }
     344              : 
     345              :     template <typename Field>
     346            0 :     double diagonal_laplace(Field& u) {
     347            0 :         constexpr unsigned Dim = Field::dim;
     348              :         using mesh_type        = typename Field::Mesh_t;
     349            0 :         mesh_type& mesh        = u.get_mesh();
     350            0 :         double sum             = 0.0;
     351            0 :         for (unsigned d = 0; d < Dim; ++d) {
     352            0 :             sum += 1 / (Kokkos::pow(mesh.getMeshSpacing(d), 2));
     353              :         }
     354              : 
     355              :         // u = - 2.0 * sum * u;
     356            0 :         return -2.0 * sum;
     357              :     }
     358              : 
     359              :     template <typename Field>
     360              :     void mult(Field& u, const double c) {
     361              :         using view_type = Field::view_type;
     362              : 
     363              :         view_type view = u.getView();
     364              : 
     365              :         Kokkos::parallel_for(
     366              :             "Field_mult_const", u.getFieldRangePolicy(),
     367              :             KOKKOS_LAMBDA(int i, int j, int k) { view(i, j, k) *= c; });
     368              :         return;
     369              :     }
     370              : }  // namespace ippl
     371              : #endif  // IPPL_LAPLACE_HELPERS_H
        

Generated by: LCOV version 2.0-1