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

Generated by: LCOV version 2.0-1