LCOV - code coverage report
Current view: top level - src/PoissonSolvers - LaplaceHelpers.h (source / functions) Coverage Total Hit
Test: report.info Lines: 84.4 % 122 103
Test Date: 2025-05-21 12:58:26 Functions: 91.1 % 158 144
Branches: 53.2 % 62 33

             Branch data     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                 :          12 :             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                 :          12 :                 : u_m(u)
      56                 :          12 :                 , hvector_m(hvector)
      57                 :          12 :                 , nghosts_m(nghosts)
      58                 :          12 :                 , ldom_m(ldom)
      59                 :          12 :                 , 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                 :          12 :             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                 :          12 :                 : u_m(u)
     117                 :          12 :                 , hvector_m(hvector)
     118                 :          12 :                 , nghosts_m(nghosts)
     119                 :          12 :                 , ldom_m(ldom)
     120                 :          12 :                 , 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                 :          12 :             meta_upper_and_lower_laplace(const E& u, const typename E::Mesh_t::vector_type& hvector)
     173                 :          12 :                 : u_m(u)
     174                 :          12 :                 , 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                 :          12 :     detail::meta_lower_laplace<Field> lower_laplace(Field& u) {
     223                 :          12 :         constexpr unsigned Dim = Field::dim;
     224                 :             : 
     225                 :          12 :         u.fillHalo();
     226                 :          12 :         BConds<Field, Dim>& bcField = u.getFieldBC();
     227                 :          12 :         bcField.apply(u);
     228                 :             : 
     229                 :          12 :         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                 :          12 :     detail::meta_lower_laplace<Field> lower_laplace_no_comm(Field& u) {
     238                 :          12 :         constexpr unsigned Dim = Field::dim;
     239                 :             : 
     240                 :             :         using mesh_type = typename Field::Mesh_t;
     241                 :          12 :         mesh_type& mesh = u.get_mesh();
     242         [ +  - ]:          12 :         typename mesh_type::vector_type hvector(0);
     243         [ +  + ]:          54 :         for (unsigned d = 0; d < Dim; d++) {
     244         [ +  - ]:          42 :             hvector[d] = 1.0 / Kokkos::pow(mesh.getMeshSpacing(d), 2);
     245                 :             :         }
     246         [ +  - ]:          12 :         const auto& layout = u.getLayout();
     247                 :          12 :         unsigned nghosts   = u.getNghost();
     248         [ +  - ]:          12 :         const auto& ldom   = layout.getLocalNDIndex();
     249                 :          12 :         const auto& domain = layout.getDomain();
     250         [ +  - ]:          24 :         return detail::meta_lower_laplace<Field>(u, hvector, nghosts, ldom, domain);
     251                 :          12 :     }
     252                 :             : 
     253                 :             :     /*!
     254                 :             :      * User interface of upper triangular Laplacian
     255                 :             :      * @param u field
     256                 :             :      */
     257                 :             :     template <typename Field>
     258                 :          12 :     detail::meta_upper_laplace<Field> upper_laplace(Field& u) {
     259                 :          12 :         constexpr unsigned Dim = Field::dim;
     260                 :             : 
     261                 :          12 :         u.fillHalo();
     262                 :          12 :         BConds<Field, Dim>& bcField = u.getFieldBC();
     263                 :          12 :         bcField.apply(u);
     264                 :             : 
     265                 :          12 :         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                 :          12 :     detail::meta_upper_laplace<Field> upper_laplace_no_comm(Field& u) {
     274                 :          12 :         constexpr unsigned Dim = Field::dim;
     275                 :             : 
     276                 :             :         using mesh_type = typename Field::Mesh_t;
     277                 :          12 :         mesh_type& mesh = u.get_mesh();
     278         [ +  - ]:          12 :         typename mesh_type::vector_type hvector(0);
     279         [ +  + ]:          54 :         for (unsigned d = 0; d < Dim; d++) {
     280         [ +  - ]:          42 :             hvector[d] = 1.0 / Kokkos::pow(mesh.getMeshSpacing(d), 2);
     281                 :             :         }
     282         [ +  - ]:          12 :         const auto& layout = u.getLayout();
     283                 :          12 :         unsigned nghosts   = u.getNghost();
     284         [ +  - ]:          12 :         const auto& ldom   = layout.getLocalNDIndex();
     285                 :          12 :         const auto& domain = layout.getDomain();
     286         [ +  - ]:          24 :         return detail::meta_upper_laplace<Field>(u, hvector, nghosts, ldom, domain);
     287                 :          12 :     }
     288                 :             : 
     289                 :             :     /*!
     290                 :             :      * User interface of upper+lower triangular Laplacian
     291                 :             :      * @param u field
     292                 :             :      */
     293                 :             :     template <typename Field>
     294                 :          12 :     detail::meta_upper_and_lower_laplace<Field> upper_and_lower_laplace(Field& u) {
     295                 :          12 :         constexpr unsigned Dim = Field::dim;
     296                 :             : 
     297                 :          12 :         u.fillHalo();
     298                 :          12 :         BConds<Field, Dim>& bcField = u.getFieldBC();
     299                 :          12 :         bcField.apply(u);
     300                 :             : 
     301                 :          12 :         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                 :          12 :     detail::meta_upper_and_lower_laplace<Field> upper_and_lower_laplace_no_comm(Field& u) {
     310                 :          12 :         constexpr unsigned Dim = Field::dim;
     311                 :             : 
     312                 :             :         using mesh_type = typename Field::Mesh_t;
     313                 :          12 :         mesh_type& mesh = u.get_mesh();
     314         [ +  - ]:          12 :         typename mesh_type::vector_type hvector(0);
     315         [ +  + ]:          54 :         for (unsigned d = 0; d < Dim; d++) {
     316         [ +  - ]:          42 :             hvector[d] = 1.0 / Kokkos::pow(mesh.getMeshSpacing(d), 2);
     317                 :             :         }
     318         [ +  - ]:          24 :         return detail::meta_upper_and_lower_laplace<Field>(u, hvector);
     319                 :          12 :     }
     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