LCOV - code coverage report
Current view: top level - src/Expression - IpplOperations.h (source / functions) Coverage Total Hit
Test: report.info Lines: 91.8 % 146 134
Test Date: 2025-05-15 13:47:30 Functions: 86.3 % 3622 3127
Branches: 42.3 % 208 88

             Branch data     Line data    Source code
       1                 :             : //
       2                 :             : // File IpplOperations.h
       3                 :             : //   Expression Templates operations.
       4                 :             : //
       5                 :             : #ifndef IPPL_OPERATIONS_H
       6                 :             : #define IPPL_OPERATIONS_H
       7                 :             : 
       8                 :             : #include <Kokkos_MathematicalFunctions.hpp>
       9                 :             : #include <tuple>
      10                 :             : 
      11                 :             : namespace ippl {
      12                 :             :     /*!
      13                 :             :      * @file IpplOperations.h
      14                 :             :      */
      15                 :             : 
      16                 :             :     /*!
      17                 :             :      * Utility function for apply (see its docstring)
      18                 :             :      * @tparam Idx... indices of the elements to take (in practice, always the sequence of natural
      19                 :             :      * numbers up to the dimension of the view)
      20                 :             :      */
      21                 :             :     template <typename View, typename Coords, size_t... Idx>
      22                 :   133628656 :     KOKKOS_INLINE_FUNCTION constexpr decltype(auto) apply_impl(const View& view,
      23                 :             :                                                                const Coords& coords,
      24                 :             :                                                                const std::index_sequence<Idx...>&) {
      25                 :   219138208 :         return view(coords[Idx]...);
      26                 :             :     }
      27                 :             : 
      28                 :             :     /*!
      29                 :             :      * Extracts the mathematical rank of an expression (i.e. the number of dimensions) based on
      30                 :             :      * its type
      31                 :             :      */
      32                 :             :     struct ExtractExpressionRank {
      33                 :             :         /*!
      34                 :             :          * Extracts the extent of an array-like expression
      35                 :             :          * @tparam Coords the array type
      36                 :             :          * @return The array's rank
      37                 :             :          */
      38                 :             :         template <typename Coords, std::enable_if_t<std::is_array_v<Coords>, int> = 0>
      39                 :             :         KOKKOS_INLINE_FUNCTION constexpr static unsigned getRank() {
      40                 :             :             return std::extent_v<Coords>;
      41                 :             :         }
      42                 :             : 
      43                 :             :         /*!
      44                 :             :          * Extracts the rank of an expression type
      45                 :             :          * @tparam Coords the expression type that evaluates to a set of coordinates
      46                 :             :          * @return The number of dimensions in the expression
      47                 :             :          */
      48                 :             :         template <typename Coords, std::enable_if_t<std::is_class_v<Coords>, int> = 0>
      49                 :             :         KOKKOS_INLINE_FUNCTION constexpr static unsigned getRank() {
      50                 :             :             return Coords::dim;
      51                 :             :         }
      52                 :             :     };
      53                 :             : 
      54                 :             :     /*!
      55                 :             :      * Accesses the element of a view at the indices contained in an array-like structure
      56                 :             :      * instead of having the indices being separate arguments
      57                 :             :      * @tparam View the view type
      58                 :             :      * @tparam Coords an array-like container of indices
      59                 :             :      * @param view the view to access
      60                 :             :      * @param coords the indices
      61                 :             :      * @return The element in the view at the given location
      62                 :             :      */
      63                 :             :     template <typename View, typename Coords>
      64                 :   133628656 :     KOKKOS_INLINE_FUNCTION constexpr decltype(auto) apply(const View& view, const Coords& coords) {
      65                 :             :         using Indices = std::make_index_sequence<ExtractExpressionRank::getRank<Coords>()>;
      66         [ +  - ]:   133628656 :         return apply_impl(view, coords, Indices{});
      67                 :             :     }
      68                 :             : 
      69                 :             : #define DefineUnaryOperation(fun, name, op1, op2)                              \
      70                 :             :     template <typename E>                                                      \
      71                 :             :     struct fun : public detail::Expression<fun<E>, sizeof(E)> {                \
      72                 :             :         constexpr static unsigned dim = E::dim;                                \
      73                 :             :                                                                                \
      74                 :             :         KOKKOS_FUNCTION                                                        \
      75                 :             :         fun(const E& u)                                                        \
      76                 :             :             : u_m(u) {}                                                        \
      77                 :             :                                                                                \
      78                 :             :         KOKKOS_INLINE_FUNCTION auto operator[](size_t i) const { return op1; } \
      79                 :             :                                                                                \
      80                 :             :         template <typename... Args>                                            \
      81                 :             :         KOKKOS_INLINE_FUNCTION auto operator()(Args... args) const {           \
      82                 :             :             return op2;                                                        \
      83                 :             :         }                                                                      \
      84                 :             :                                                                                \
      85                 :             :     private:                                                                   \
      86                 :             :         const E u_m;                                                           \
      87                 :             :     };                                                                         \
      88                 :             :                                                                                \
      89                 :             :     template <typename E, size_t N>                                            \
      90                 :             :     KOKKOS_INLINE_FUNCTION fun<E> name(const detail::Expression<E, N>& u) {    \
      91                 :             :         return fun<E>(*static_cast<const E*>(&u));                             \
      92                 :             :     }
      93                 :             : 
      94                 :             :     /// @cond
      95                 :             : 
      96                 :             :     // clang-format off
      97   [ #  #  #  # ]:         264 :     DefineUnaryOperation(UnaryMinus, operator-, -u_m[i],  -u_m(args...))
                 [ #  # ]
      98                 :             :     DefineUnaryOperation(UnaryPlus,  operator+, +u_m[i],  +u_m(args...))
      99                 :             :     DefineUnaryOperation(BitwiseNot, operator~, ~u_m[i],  ~u_m(args...))
     100                 :             :     DefineUnaryOperation(Not,        operator!, !u_m[i],  !u_m(args...))
     101                 :             : 
     102                 :      238680 :     DefineUnaryOperation(ArcCos, acos,  Kokkos::acos(u_m[i]),  Kokkos::acos(u_m(args...)))
     103                 :      238680 :     DefineUnaryOperation(ArcSin, asin,  Kokkos::asin(u_m[i]),  Kokkos::asin(u_m(args...)))
     104                 :      238680 :     DefineUnaryOperation(ArcTan, atan,  Kokkos::atan(u_m[i]),  Kokkos::atan(u_m(args...)))
     105                 :      238680 :     DefineUnaryOperation(Ceil,   ceil,  Kokkos::ceil(u_m[i]),  Kokkos::ceil(u_m(args...)))
     106                 :      238680 :     DefineUnaryOperation(Cos,    cos,   Kokkos::cos(u_m[i]),   Kokkos::cos(u_m(args...)))
     107                 :      238680 :     DefineUnaryOperation(HypCos, cosh,  Kokkos::cosh(u_m[i]),  Kokkos::cosh(u_m(args...)))
     108                 :      238680 :     DefineUnaryOperation(Exp,    exp,   Kokkos::exp(u_m[i]),   Kokkos::exp(u_m(args...)))
     109                 :      238680 :     DefineUnaryOperation(Fabs,   fabs,  Kokkos::fabs(u_m[i]),  Kokkos::fabs(u_m(args...)))
     110                 :      238680 :     DefineUnaryOperation(Floor,  floor, Kokkos::floor(u_m[i]), Kokkos::floor(u_m(args...)))
     111                 :      238680 :     DefineUnaryOperation(Log,    log,   Kokkos::log(u_m[i]),   Kokkos::log(u_m(args...)))
     112                 :      238680 :     DefineUnaryOperation(Log10,  log10, Kokkos::log10(u_m[i]), Kokkos::log10(u_m(args...)))
     113                 :      238680 :     DefineUnaryOperation(Sin,    sin,   Kokkos::sin(u_m[i]),   Kokkos::sin(u_m(args...)))
     114                 :      238680 :     DefineUnaryOperation(HypSin, sinh,  Kokkos::sinh(u_m[i]),  Kokkos::sinh(u_m(args...)))
     115                 :      238680 :     DefineUnaryOperation(Sqrt,   sqrt,  Kokkos::sqrt(u_m[i]),  Kokkos::sqrt(u_m(args...)))
     116                 :      238680 :     DefineUnaryOperation(Tan,    tan,   Kokkos::tan(u_m[i]),   Kokkos::tan(u_m(args...)))
     117                 :      238680 :     DefineUnaryOperation(HypTan, tanh,  Kokkos::tanh(u_m[i]),  Kokkos::tanh(u_m(args...)))
     118                 :      238680 :     DefineUnaryOperation(Erf,    erf,   Kokkos::erf(u_m[i]),   Kokkos::erf(u_m(args...)))
     119                 :             : // clang-format on
     120                 :             : /// @endcond
     121                 :             : 
     122                 :             : /*!
     123                 :             :  * Macro to overload C++ operators for the Scalar, BareField and Vector class.
     124                 :             :  * @param fun name of the expression template function
     125                 :             :  * @param name overloaded operator
     126                 :             :  * @param op1 operation for single index access
     127                 :             :  * @param op2 operation for multiple indices access
     128                 :             :  */
     129                 :             : #define DefineBinaryOperation(fun, name, op1, op2)                                             \
     130                 :             :     template <typename E1, typename E2>                                                        \
     131                 :             :     struct fun : public detail::Expression<fun<E1, E2>, sizeof(E1) + sizeof(E2)> {             \
     132                 :             :         constexpr static unsigned dim = std::max(E1::dim, E2::dim);                            \
     133                 :             :                                                                                                \
     134                 :             :         KOKKOS_FUNCTION                                                                        \
     135                 :             :         fun(const E1& u, const E2& v)                                                          \
     136                 :             :             : u_m(u)                                                                           \
     137                 :             :             , v_m(v) {}                                                                        \
     138                 :             :                                                                                                \
     139                 :             :         KOKKOS_INLINE_FUNCTION auto operator[](size_t i) const { return op1; }                 \
     140                 :             :                                                                                                \
     141                 :             :         template <typename... Args>                                                            \
     142                 :             :         KOKKOS_INLINE_FUNCTION auto operator()(Args... args) const {                           \
     143                 :             :             static_assert(sizeof...(Args) == dim || dim == 0);                                 \
     144                 :             :             return op2;                                                                        \
     145                 :             :         }                                                                                      \
     146                 :             :                                                                                                \
     147                 :             :     private:                                                                                   \
     148                 :             :         const E1 u_m;                                                                          \
     149                 :             :         const E2 v_m;                                                                          \
     150                 :             :     };                                                                                         \
     151                 :             :                                                                                                \
     152                 :             :     template <typename E1, size_t N1, typename E2, size_t N2>                                  \
     153                 :             :     KOKKOS_INLINE_FUNCTION fun<E1, E2> name(const detail::Expression<E1, N1>& u,               \
     154                 :             :                                             const detail::Expression<E2, N2>& v) {             \
     155                 :             :         return fun<E1, E2>(*static_cast<const E1*>(&u), *static_cast<const E2*>(&v));          \
     156                 :             :     }                                                                                          \
     157                 :             :                                                                                                \
     158                 :             :     template <typename E, size_t N, typename T,                                                \
     159                 :             :               typename = std::enable_if_t<std::is_scalar<T>::value>>                           \
     160                 :             :     KOKKOS_INLINE_FUNCTION fun<E, detail::Scalar<T>> name(const detail::Expression<E, N>& u,   \
     161                 :             :                                                           const T& v) {                        \
     162                 :             :         return fun<E, detail::Scalar<T>>(*static_cast<const E*>(&u), v);                       \
     163                 :             :     }                                                                                          \
     164                 :             :                                                                                                \
     165                 :             :     template <typename E, size_t N, typename T,                                                \
     166                 :             :               typename = std::enable_if_t<std::is_scalar<T>::value>>                           \
     167                 :             :     KOKKOS_INLINE_FUNCTION fun<detail::Scalar<T>, E> name(const T& u,                          \
     168                 :             :                                                           const detail::Expression<E, N>& v) { \
     169                 :             :         return fun<detail::Scalar<T>, E>(u, *static_cast<const E*>(&v));                       \
     170                 :             :     }
     171                 :             : 
     172                 :             :     /// @cond
     173                 :             :     // clang-format off
     174 [ +  - ][ #  #  :    96887696 :     DefineBinaryOperation(Add,      operator+,  u_m[i] + v_m[i],  u_m(args...) + v_m(args...))
             #  #  #  # ]
     175 [ +  - ][ #  #  :    24543600 :     DefineBinaryOperation(Subtract, operator-,  u_m[i] - v_m[i],  u_m(args...) - v_m(args...))
             #  #  #  # ]
     176         [ +  - ]:    92137744 :     DefineBinaryOperation(Multiply, operator*,  u_m[i] * v_m[i],  u_m(args...) * v_m(args...))
           [ #  #  #  # ]
     177         [ +  - ]:    53226170 :     DefineBinaryOperation(Divide,   operator/,  u_m[i] / v_m[i],  u_m(args...) / v_m(args...))
     178                 :             :     DefineBinaryOperation(Mod,      operator%,  u_m[i] % v_m[i],  u_m(args...) % v_m(args...))
     179                 :             :     DefineBinaryOperation(LT,       operator<,  u_m[i] < v_m[i],  u_m(args...) < v_m(args...))
     180                 :             :     DefineBinaryOperation(LE,       operator<=, u_m[i] <= v_m[i], u_m(args...) <= v_m(args...))
     181                 :             :     DefineBinaryOperation(GT,       operator>,  u_m[i] > v_m[i],  u_m(args...) > v_m(args...))
     182                 :             :     DefineBinaryOperation(GE,       operator>=, u_m[i] >= v_m[i], u_m(args...) >= v_m(args...))
     183                 :             :     DefineBinaryOperation(EQ,       operator==, u_m[i] == v_m[i], u_m(args...) == v_m(args...))
     184                 :             :     DefineBinaryOperation(NEQ,      operator!=, u_m[i] != v_m[i], u_m(args...) != v_m(args...))
     185                 :             :     DefineBinaryOperation(And,      operator&&, u_m[i] && v_m[i], u_m(args...) && v_m(args...))
     186                 :             :     DefineBinaryOperation(Or,       operator||, u_m[i] || v_m[i], u_m(args...) || v_m(args...))
     187                 :             : 
     188                 :             :     DefineBinaryOperation(BitwiseAnd, operator&, u_m[i] & v_m[i], u_m(args...) & v_m(args...))
     189                 :             :     DefineBinaryOperation(BitwiseOr,  operator|, u_m[i] | v_m[i], u_m(args...) | v_m(args...))
     190                 :             :     DefineBinaryOperation(BitwiseXor, operator^, u_m[i] ^ v_m[i], u_m(args...) ^ v_m(args...))
     191                 :             :     // clang-format on
     192                 :             : 
     193                 :             :     DefineBinaryOperation(Copysign, copysign, Kokkos::copysign(u_m[i], v_m[i]),
     194                 :             :                           Kokkos::copysign(u_m(args...), v_m(args...)))
     195                 :             :     // ldexp not provided by Kokkos
     196                 :             :     DefineBinaryOperation(Ldexp, ldexp, ldexp(u_m[i], v_m[i]), ldexp(u_m(args...), v_m(args...)))
     197                 :             :     DefineBinaryOperation(Fmod, fmod, Kokkos::fmod(u_m[i], v_m[i]),
     198                 :             :                           Kokkos::fmod(u_m(args...), v_m(args...)))
     199         [ #  # ]:           0 :     DefineBinaryOperation(Pow, pow, Kokkos::pow(u_m[i], v_m[i]),
     200                 :             :                           Kokkos::pow(u_m(args...), v_m(args...)))
     201                 :             :     DefineBinaryOperation(ArcTan2, atan2, Kokkos::atan2(u_m[i], v_m[i]),
     202                 :             :                           Kokkos::atan2(u_m(args...), v_m(args...)))
     203                 :             :     /// @endcond
     204                 :             : 
     205                 :             :     namespace detail {
     206                 :             :         /*!
     207                 :             :          * Meta function of cross product. This function is only supported for 3-dimensional
     208                 :             :          * vectors.
     209                 :             :          */
     210                 :             :         template <typename E1, typename E2>
     211                 :             :         struct meta_cross : public detail::Expression<meta_cross<E1, E2>, sizeof(E1) + sizeof(E2)> {
     212                 :             :             constexpr static unsigned dim = E1::dim;
     213                 :             :             static_assert(E1::dim == E2::dim);
     214                 :             : 
     215                 :             :             KOKKOS_FUNCTION
     216                 :           0 :             meta_cross(const E1& u, const E2& v)
     217                 :           0 :                 : u_m(u)
     218                 :           0 :                 , v_m(v) {}
     219                 :             : 
     220                 :             :             /*
     221                 :             :              * Vector::cross
     222                 :             :              */
     223                 :           0 :             KOKKOS_INLINE_FUNCTION auto operator[](size_t i) const {
     224                 :           0 :                 const size_t j = (i + 1) % 3;
     225                 :           0 :                 const size_t k = (i + 2) % 3;
     226                 :           0 :                 return u_m[j] * v_m[k] - u_m[k] * v_m[j];
     227                 :             :             }
     228                 :             : 
     229                 :             :             /*
     230                 :             :              * This is required for BareField::cross
     231                 :             :              */
     232                 :             :             template <typename... Args>
     233                 :             :             KOKKOS_INLINE_FUNCTION auto operator()(Args... args) const {
     234                 :             :                 return cross(u_m(args...), v_m(args...));
     235                 :             :             }
     236                 :             : 
     237                 :             :         private:
     238                 :             :             const E1 u_m;
     239                 :             :             const E2 v_m;
     240                 :             :         };
     241                 :             :     }  // namespace detail
     242                 :             : 
     243                 :             :     template <typename E1, size_t N1, typename E2, size_t N2>
     244                 :           0 :     KOKKOS_INLINE_FUNCTION detail::meta_cross<E1, E2> cross(const detail::Expression<E1, N1>& u,
     245                 :             :                                                             const detail::Expression<E2, N2>& v) {
     246                 :           0 :         return detail::meta_cross<E1, E2>(*static_cast<const E1*>(&u), *static_cast<const E2*>(&v));
     247                 :             :     }
     248                 :             : 
     249                 :             :     namespace detail {
     250                 :             :         /*!
     251                 :             :          * Meta function of dot product.
     252                 :             :          */
     253                 :             :         template <typename E1, typename E2>
     254                 :             :         struct meta_dot : public Expression<meta_dot<E1, E2>, sizeof(E1) + sizeof(E2)> {
     255                 :             :             constexpr static unsigned dim = E1::dim;
     256                 :             :             static_assert(E1::dim == E2::dim);
     257                 :             : 
     258                 :             :             KOKKOS_FUNCTION
     259                 :     1510540 :             meta_dot(const E1& u, const E2& v)
     260                 :     1510540 :                 : u_m(u)
     261         [ +  - ]:     1510540 :                 , v_m(v) {}
     262                 :             : 
     263                 :             :             /*
     264                 :             :              * Vector::dot
     265                 :             :              */
     266                 :     1510528 :             KOKKOS_INLINE_FUNCTION auto apply() const {
     267                 :     1510528 :                 typename E1::value_type res = 0.0;
     268                 :             :                 // Equivalent computation in 3D:
     269                 :             :                 // u_m[0] * v_m[0] + u_m[1] * v_m[1] + u_m[2] * v_m[2]
     270         [ +  + ]:     9741568 :                 for (size_t i = 0; i < E1::dim; ++i) {
     271                 :     8231040 :                     res += u_m[i] * v_m[i];
     272                 :             :                 }
     273                 :     1510528 :                 return res;
     274                 :             :             }
     275                 :             : 
     276                 :             :             /*
     277                 :             :              * This is required for BareField::dot
     278                 :             :              */
     279                 :             :             template <typename... Args>
     280                 :      238656 :             KOKKOS_INLINE_FUNCTION auto operator()(Args... args) const {
     281   [ +  -  +  -  :      238656 :                 return dot(u_m(args...), v_m(args...)).apply();
             +  -  +  - ]
     282                 :             :             }
     283                 :             : 
     284                 :             :         private:
     285                 :             :             const E1 u_m;
     286                 :             :             const E2 v_m;
     287                 :             :         };
     288                 :             :     }  // namespace detail
     289                 :             : 
     290                 :             :     template <typename E1, size_t N1, typename E2, size_t N2>
     291                 :     1510540 :     KOKKOS_INLINE_FUNCTION detail::meta_dot<E1, E2> dot(const detail::Expression<E1, N1>& u,
     292                 :             :                                                         const detail::Expression<E2, N2>& v) {
     293                 :     1510540 :         return detail::meta_dot<E1, E2>(*static_cast<const E1*>(&u), *static_cast<const E2*>(&v));
     294                 :             :     }
     295                 :             : 
     296                 :             :     namespace detail {
     297                 :             :         /*!
     298                 :             :          * Meta function of gradient
     299                 :             :          */
     300                 :             : 
     301                 :             :         template <typename E>
     302                 :             :         struct meta_grad
     303                 :             :             : public Expression<
     304                 :             :                   meta_grad<E>,
     305                 :             :                   sizeof(E) + sizeof(typename E::Mesh_t::vector_type[E::Mesh_t::Dimension])> {
     306                 :             :             constexpr static unsigned dim = E::dim;
     307                 :             : 
     308                 :             :             KOKKOS_FUNCTION
     309                 :          12 :             meta_grad(const E& u, const typename E::Mesh_t::vector_type vectors[])
     310   [ +  -  +  +  :          54 :                 : u_m(u) {
             -  -  -  - ]
                 [ #  # ]
     311         [ +  + ]:          54 :                 for (unsigned d = 0; d < E::Mesh_t::Dimension; d++) {
     312                 :          42 :                     vectors_m[d] = vectors[d];
     313                 :             :                 }
     314                 :          12 :             }
     315                 :             : 
     316                 :             :             /*
     317                 :             :              * n-dimensional grad
     318                 :             :              */
     319                 :             :             template <typename... Idx>
     320                 :      238656 :             KOKKOS_INLINE_FUNCTION auto operator()(const Idx... args) const {
     321                 :             :                 using index_type = std::tuple_element_t<0, std::tuple<Idx...>>;
     322                 :             : 
     323                 :             :                 /*
     324                 :             :                  * Equivalent computation in 3D:
     325                 :             :                  *     xvector_m * (u_m(i + 1, j, k) - u_m(i - 1, j, k))
     326                 :             :                  *   + yvector_m * (u_m(i, j + 1, k) - u_m(i, j - 1, k))
     327                 :             :                  *   + zvector_m * (u_m(i, j, k + 1) - u_m(i, j, k - 1))
     328                 :             :                  */
     329                 :             : 
     330         [ +  - ]:      238656 :                 vector_type res(0);
     331         [ +  + ]:     1510528 :                 for (unsigned d = 0; d < dim; d++) {
     332                 :     1271872 :                     index_type coords[dim] = {args...};
     333                 :             : 
     334                 :     1271872 :                     coords[d] += 1;
     335         [ +  - ]:     1271872 :                     auto&& right = apply(u_m, coords);
     336                 :             : 
     337                 :     1271872 :                     coords[d] -= 2;
     338         [ +  - ]:     1271872 :                     auto&& left = apply(u_m, coords);
     339                 :             : 
     340   [ +  -  +  - ]:     1271872 :                     res += vectors_m[d] * (right - left);
                 [ #  # ]
     341                 :             :                 }
     342                 :      238656 :                 return res;
     343                 :           0 :             }
     344                 :             : 
     345                 :             :         private:
     346                 :             :             using Mesh_t      = typename E::Mesh_t;
     347                 :             :             using vector_type = typename Mesh_t::vector_type;
     348                 :             :             const E u_m;
     349                 :             :             vector_type vectors_m[dim];
     350                 :             :         };
     351                 :             :     }  // namespace detail
     352                 :             : 
     353                 :             :     namespace detail {
     354                 :             : 
     355                 :             :         /*!
     356                 :             :          * Meta function of divergence
     357                 :             :          */
     358                 :             :         template <typename E>
     359                 :             :         struct meta_div
     360                 :             :             : public Expression<
     361                 :             :                   meta_div<E>,
     362                 :             :                   sizeof(E) + sizeof(typename E::Mesh_t::vector_type[E::Mesh_t::Dimension])> {
     363                 :             :             constexpr static unsigned dim = E::dim;
     364                 :             : 
     365                 :             :             KOKKOS_FUNCTION
     366                 :          12 :             meta_div(const E& u, const typename E::Mesh_t::vector_type vectors[])
     367   [ +  -  +  +  :          54 :                 : u_m(u) {
             -  -  -  - ]
     368         [ +  + ]:          54 :                 for (unsigned d = 0; d < E::Mesh_t::Dimension; d++) {
     369                 :          42 :                     vectors_m[d] = vectors[d];
     370                 :             :                 }
     371                 :          12 :             }
     372                 :             : 
     373                 :             :             /*
     374                 :             :              * n-dimensional div
     375                 :             :              */
     376                 :             :             template <typename... Idx>
     377                 :      238656 :             KOKKOS_INLINE_FUNCTION auto operator()(const Idx... args) const {
     378                 :             :                 using index_type = std::tuple_element_t<0, std::tuple<Idx...>>;
     379                 :             : 
     380                 :             :                 /*
     381                 :             :                  * Equivalent computation in 3D:
     382                 :             :                  *     dot(xvector_m, (u_m(i + 1, j, k) - u_m(i - 1, j, k))).apply()
     383                 :             :                  *   + dot(yvector_m, (u_m(i, j + 1, k) - u_m(i, j - 1, k))).apply()
     384                 :             :                  *   + dot(zvector_m, (u_m(i, j, k + 1) - u_m(i, j, k - 1))).apply()
     385                 :             :                  */
     386                 :      238656 :                 typename E::Mesh_t::value_type res = 0;
     387         [ +  + ]:     1510528 :                 for (unsigned d = 0; d < dim; d++) {
     388                 :     1271872 :                     index_type coords[dim] = {args...};
     389                 :             : 
     390                 :     1271872 :                     coords[d] += 1;
     391         [ +  - ]:     1271872 :                     auto&& right = apply(u_m, coords);
     392                 :             : 
     393                 :     1271872 :                     coords[d] -= 2;
     394         [ +  - ]:     1271872 :                     auto&& left = apply(u_m, coords);
     395                 :             : 
     396   [ +  -  +  -  :     1271872 :                     res += dot(vectors_m[d], right - left).apply();
                   +  - ]
     397                 :             :                 }
     398                 :      238656 :                 return res;
     399                 :             :             }
     400                 :             : 
     401                 :             :         private:
     402                 :             :             using Mesh_t      = typename E::Mesh_t;
     403                 :             :             using vector_type = typename Mesh_t::vector_type;
     404                 :             :             const E u_m;
     405                 :             :             vector_type vectors_m[dim];
     406                 :             :         };
     407                 :             : 
     408                 :             :         /*!
     409                 :             :          * Meta function of Laplacian
     410                 :             :          */
     411                 :             :         template <typename E>
     412                 :             :         struct meta_laplace
     413                 :             :             : public Expression<meta_laplace<E>,
     414                 :             :                                 sizeof(E) + sizeof(typename E::Mesh_t::vector_type)> {
     415                 :             :             constexpr static unsigned dim = E::dim;
     416                 :             : 
     417                 :             :             KOKKOS_FUNCTION
     418                 :          12 :             meta_laplace(const E& u, const typename E::Mesh_t::vector_type& hvector)
     419                 :          12 :                 : u_m(u)
     420                 :          12 :                 , hvector_m(hvector) {}
     421                 :             : 
     422                 :             :             /*
     423                 :             :              * n-dimensional Laplacian
     424                 :             :              */
     425                 :             :             template <typename... Idx>
     426                 :      238656 :             KOKKOS_INLINE_FUNCTION auto operator()(const Idx... args) const {
     427                 :             :                 using index_type = std::tuple_element_t<0, std::tuple<Idx...>>;
     428                 :             :                 using T          = typename E::Mesh_t::value_type;
     429                 :             : 
     430                 :             :                 /*
     431                 :             :                  * Equivalent computation in 3D:
     432                 :             :                  *     hvector_m[0] * (u_m(i+1, j,   k)   - 2 * u_m(i, j, k) + u_m(i-1, j,   k  ))
     433                 :             :                  *   + hvector_m[1] * (u_m(i  , j+1, k)   - 2 * u_m(i, j, k) + u_m(i  , j-1, k  ))
     434                 :             :                  *   + hvector_m[2] * (u_m(i  , j  , k+1) - 2 * u_m(i, j, k) + u_m(i  , j  , k-1))
     435                 :             :                  */
     436                 :      238656 :                 T res = 0;
     437         [ +  + ]:     1510528 :                 for (unsigned d = 0; d < dim; d++) {
     438                 :     1271872 :                     index_type coords[dim] = {args...};
     439         [ +  - ]:     1271872 :                     auto&& center          = apply(u_m, coords);
     440                 :             : 
     441                 :     1271872 :                     coords[d] -= 1;
     442         [ +  - ]:     1271872 :                     auto&& left = apply(u_m, coords);
     443                 :             : 
     444                 :     1271872 :                     coords[d] += 2;
     445         [ +  - ]:     1271872 :                     auto&& right = apply(u_m, coords);
     446                 :             : 
     447                 :     1271872 :                     res += hvector_m[d] * (left - 2 * center + right);
     448                 :             :                 }
     449                 :      238656 :                 return res;
     450                 :             :             }
     451                 :             : 
     452                 :             :         private:
     453                 :             :             using Mesh_t      = typename E::Mesh_t;
     454                 :             :             using vector_type = typename Mesh_t::vector_type;
     455                 :             :             const E u_m;
     456                 :             :             const vector_type hvector_m;
     457                 :             :         };
     458                 :             :     }  // namespace detail
     459                 :             : 
     460                 :             :     namespace detail {
     461                 :             :         /*!
     462                 :             :          * Meta function of curl
     463                 :             :          */
     464                 :             : 
     465                 :             :         template <typename E>
     466                 :             :         struct meta_curl
     467                 :             :             : public Expression<meta_curl<E>,
     468                 :             :                                 sizeof(E) + 4 * sizeof(typename E::Mesh_t::vector_type)> {
     469                 :             :             constexpr static unsigned dim = E::dim;
     470                 :             : 
     471                 :             :             KOKKOS_FUNCTION
     472                 :           2 :             meta_curl(const E& u, const typename E::Mesh_t::vector_type& xvector,
     473                 :             :                       const typename E::Mesh_t::vector_type& yvector,
     474                 :             :                       const typename E::Mesh_t::vector_type& zvector,
     475                 :             :                       const typename E::Mesh_t::vector_type& hvector)
     476                 :           2 :                 : u_m(u)
     477                 :           2 :                 , xvector_m(xvector)
     478                 :           2 :                 , yvector_m(yvector)
     479                 :           2 :                 , zvector_m(zvector)
     480                 :           2 :                 , hvector_m(hvector) {}
     481                 :             : 
     482                 :             :             /*
     483                 :             :              * 3-dimensional curl
     484                 :             :              */
     485                 :        8192 :             KOKKOS_INLINE_FUNCTION auto operator()(size_t i, size_t j, size_t k) const {
     486                 :        8192 :                 return xvector_m
     487   [ +  -  +  - ]:       24576 :                            * ((u_m(i, j + 1, k)[2] - u_m(i, j - 1, k)[2]) / (2 * hvector_m[1])
     488   [ +  -  +  -  :       16384 :                               - (u_m(i, j, k + 1)[1] - u_m(i, j, k - 1)[1]) / (2 * hvector_m[2]))
                   +  - ]
     489         [ +  - ]:       16384 :                        + yvector_m
     490   [ +  -  +  - ]:       24576 :                              * ((u_m(i, j, k + 1)[0] - u_m(i, j, k - 1)[0]) / (2 * hvector_m[2])
     491   [ +  -  +  -  :       16384 :                                 - (u_m(i + 1, j, k)[2] - u_m(i - 1, j, k)[2]) / (2 * hvector_m[0]))
                   +  - ]
     492                 :        8192 :                        + zvector_m
     493   [ +  -  +  - ]:       24576 :                              * ((u_m(i + 1, j, k)[1] - u_m(i - 1, j, k)[1]) / (2 * hvector_m[0])
     494   [ +  -  +  -  :       32768 :                                 - (u_m(i, j + 1, k)[0] - u_m(i, j - 1, k)[0]) / (2 * hvector_m[1]));
             +  -  +  - ]
     495                 :             :             }
     496                 :             : 
     497                 :             :         private:
     498                 :             :             using Mesh_t      = typename E::Mesh_t;
     499                 :             :             using vector_type = typename Mesh_t::vector_type;
     500                 :             :             const E u_m;
     501                 :             :             const vector_type xvector_m;
     502                 :             :             const vector_type yvector_m;
     503                 :             :             const vector_type zvector_m;
     504                 :             :             const vector_type hvector_m;
     505                 :             :         };
     506                 :             :     }  // namespace detail
     507                 :             : 
     508                 :             :     namespace detail {
     509                 :             : 
     510                 :             :         /*!
     511                 :             :          * Meta function of Hessian
     512                 :             :          */
     513                 :             :         template <typename E>
     514                 :             :         struct meta_hess
     515                 :             :             : public Expression<meta_hess<E>,
     516                 :             :                                 sizeof(E)
     517                 :             :                                     + sizeof(typename E::Mesh_t::vector_type[E::Mesh_t::Dimension])
     518                 :             :                                     + sizeof(typename E::Mesh_t::vector_type)> {
     519                 :             :             constexpr static unsigned dim = E::dim;
     520                 :             : 
     521                 :             :             KOKKOS_FUNCTION
     522                 :          12 :             meta_hess(const E& u, const typename E::Mesh_t::vector_type vectors[],
     523                 :             :                       const typename E::Mesh_t::vector_type& hvector)
     524                 :          12 :                 : u_m(u)
     525   [ +  -  +  +  :          54 :                 , hvector_m(hvector) {
             -  -  -  - ]
                 [ #  # ]
     526         [ +  + ]:          54 :                 for (unsigned d = 0; d < E::Mesh_t::Dimension; d++) {
     527                 :          42 :                     vectors_m[d] = vectors[d];
     528                 :             :                 }
     529                 :          12 :             }
     530                 :             : 
     531                 :             :             /*
     532                 :             :              * n-dimensional hessian (return Vector<Vector<T,n>,n>)
     533                 :             :              */
     534                 :             :             template <typename... Idx>
     535                 :      238656 :             KOKKOS_INLINE_FUNCTION auto operator()(const Idx... args) const {
     536                 :      238656 :                 matrix_type hessian;
     537         [ +  - ]:      238656 :                 computeHessian(std::make_index_sequence<dim>{}, hessian, args...);
     538                 :      238656 :                 return hessian;
     539                 :           0 :             }
     540                 :             : 
     541                 :             :         private:
     542                 :             :             using Mesh_t      = typename E::Mesh_t;
     543                 :             :             using vector_type = typename Mesh_t::vector_type;
     544                 :             :             using matrix_type = typename Mesh_t::matrix_type;
     545                 :             : 
     546                 :             :             const E u_m;
     547                 :             :             vector_type vectors_m[dim];
     548                 :             :             const vector_type hvector_m;
     549                 :             : 
     550                 :             :             /*!
     551                 :             :              * Utility function for computing the Hessian. Computes the rows of the matrix
     552                 :             :              * one by one via fold expression.
     553                 :             :              * @tparam row... the row indices (in practice, the sequence 0...Dim - 1)
     554                 :             :              * @tparam Idx... the indices at which to access the field view
     555                 :             :              * @param is index sequence (reused for row computation)
     556                 :             :              * @param hessian matrix in which to store the Hessian
     557                 :             :              * @param args... the indices
     558                 :             :              */
     559                 :             :             template <size_t... row, typename... Idx>
     560                 :      238656 :             KOKKOS_INLINE_FUNCTION constexpr void computeHessian(
     561                 :             :                 const std::index_sequence<row...>& is, matrix_type& hessian,
     562                 :             :                 const Idx... args) const {
     563                 :             :                 // The comma operator forces left-to-right evaluation order, which reduces
     564                 :             :                 // performance; therefore we apply a dummy operation to dummy values and discard the
     565                 :             :                 // result
     566                 :      238656 :                 [[maybe_unused]] auto _ = (hessianRow<row>(is, hessian, args...) + ...);
     567                 :      238656 :             }
     568                 :             : 
     569                 :             :             /*!
     570                 :             :              * Utility function for computing the Hessian. Computes the entries in a single
     571                 :             :              * row of the matrix via fold expression.
     572                 :             :              * @tparam row the row index
     573                 :             :              * @tparam col... the column indices (in practice, the sequence 0...Dim - 1)
     574                 :             :              * @tparam Idx... the indices at which to access the field view
     575                 :             :              * @param hessian matrix in which to store the hessian
     576                 :             :              * @param args... the indices
     577                 :             :              * @return An unused dummy value (required to allow use of a more performant fold
     578                 :             :              * expression)
     579                 :             :              */
     580                 :             :             template <size_t row, size_t... col, typename... Idx>
     581                 :     1271872 :             KOKKOS_INLINE_FUNCTION constexpr int hessianRow(const std::index_sequence<col...>&,
     582                 :             :                                                             matrix_type& hessian,
     583                 :             :                                                             const Idx... args) const {
     584   [ +  -  +  -  :     1271872 :                 hessian[row] = (hessianEntry<row, col>(args...) + ...);
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
           -  +  - ][ #  
          #  #  #  #  #  
             #  #  #  # ]
     585                 :     1271872 :                 return 0;
     586                 :             :             }
     587                 :             : 
     588                 :             :             /*!
     589                 :             :              * Utility function for computing the Hessian. Computes a single entry
     590                 :             :              * of the matrix
     591                 :             :              * @tparam row the row index
     592                 :             :              * @tparam col the column index
     593                 :             :              * @tparam Idx... the indices at which to access the field view
     594                 :             :              * @param args... the indices
     595                 :             :              * @return The entry of the Hessian at the given row and column
     596                 :             :              */
     597                 :             :             template <size_t row, size_t col, typename... Idx>
     598                 :     6959168 :             KOKKOS_INLINE_FUNCTION constexpr vector_type hessianEntry(const Idx... args) const {
     599                 :             :                 using index_type       = std::tuple_element_t<0, std::tuple<Idx...>>;
     600                 :     6959168 :                 index_type coords[dim] = {args...};
     601                 :             :                 if constexpr (row == col) {
     602         [ +  - ]:     1271872 :                     auto&& center = apply(u_m, coords);
     603                 :             : 
     604                 :     1271872 :                     coords[row] += 1;
     605         [ +  - ]:     1271872 :                     auto&& right = apply(u_m, coords);
     606                 :             : 
     607                 :     1271872 :                     coords[row] -= 2;
     608         [ +  - ]:     1271872 :                     auto&& left = apply(u_m, coords);
     609                 :             : 
     610                 :             :                     // The diagonal elements correspond to second derivatives w.r.t. a single
     611                 :             :                     // variable
     612                 :     1271872 :                     return vectors_m[row] * (right - 2. * center + left)
     613   [ +  -  +  -  :     2543744 :                            / (hvector_m[row] * hvector_m[row]);
                   +  - ]
     614                 :             :                 } else {
     615                 :     5687296 :                     coords[row] += 1;
     616                 :     5687296 :                     coords[col] += 1;
     617         [ +  - ]:     5687296 :                     auto&& uu = apply(u_m, coords);
     618                 :             : 
     619                 :     5687296 :                     coords[col] -= 2;
     620         [ +  - ]:     5687296 :                     auto&& ud = apply(u_m, coords);
     621                 :             : 
     622                 :     5687296 :                     coords[row] -= 2;
     623         [ +  - ]:     5687296 :                     auto&& dd = apply(u_m, coords);
     624                 :             : 
     625                 :     5687296 :                     coords[col] += 2;
     626         [ +  - ]:     5687296 :                     auto&& du = apply(u_m, coords);
     627                 :             : 
     628                 :             :                     // The non-diagonal elements are mixed derivatives, whose finite difference form
     629                 :             :                     // is slightly different from above
     630                 :     5687296 :                     return vectors_m[col] * (uu - du - ud + dd)
     631   [ +  -  +  -  :    11374592 :                            / (4. * hvector_m[row] * hvector_m[col]);
                   +  - ]
     632                 :             :                 }
     633                 :             :                 // Silences incorrect nvcc warning: missing return statement at end of non-void
     634                 :             :                 // function
     635                 :             :                 return vector_type{};
     636                 :             :             }
     637                 :             :         };
     638                 :             :     }  // namespace detail
     639                 :             : }  // namespace ippl
     640                 :             : 
     641                 :             : #endif
        

Generated by: LCOV version 2.0-1