LCOV - code coverage report
Current view: top level - src/FEM - FEMInterpolate.hpp (source / functions) Coverage Total Hit
Test: final_report.info Lines: 100.0 % 84 84
Test Date: 2025-09-03 08:53:20 Functions: 100.0 % 63 63

            Line data    Source code
       1              : #ifndef IPPL_FEMINTERPOLATE_H
       2              : #define IPPL_FEMINTERPOLATE_H
       3              : 
       4              : 
       5              : namespace ippl {
       6              : 
       7              :     /** 
       8              :     * @brief Mapping from global position to element ND index and
       9              :     * reference coordinates (xi ∈ [0,1)^Dim) on a UniformCartesian mesh.
      10              :     *
      11              :     * Assumes the input x is strictly inside the computational domain so that
      12              :     * for each dimension d: 0 ≤ (x[d]-origin[d])/h[d] < nr[d]-1.
      13              :     */
      14              :     template <typename T, unsigned Dim, class Mesh>
      15              :     KOKKOS_INLINE_FUNCTION void 
      16        24024 :     locate_element_nd_and_xi(const Mesh& mesh,
      17              :         const ippl::Vector<T,Dim>& x,
      18              :         ippl::Vector<size_t,Dim>& e_nd,
      19              :         ippl::Vector<T,Dim>& xi) {
      20              : 
      21        24024 :         const auto nr = mesh.getGridsize(); // vertices per axis
      22        24024 :         const auto h = mesh.getMeshSpacing();
      23        24024 :         const auto org = mesh.getOrigin();
      24              : 
      25              : 
      26        72072 :         for (unsigned d = 0; d < Dim; ++d) {
      27        48048 :             const T s = (x[d] - org[d]) / h[d]; // To cell units
      28        48048 :             const size_t e = static_cast<size_t>(std::floor(s));
      29        48048 :             e_nd[d] = e;
      30        48048 :             xi[d] = s - static_cast<T>(e);
      31              :         }
      32        24024 :     }
      33              : 
      34              : 
      35              :     template<class View, class IVec, std::size_t... Is>
      36              :     KOKKOS_INLINE_FUNCTION
      37        56000 :     auto view_ptr_impl(View& v, const IVec& I, std::index_sequence<Is...>)
      38              :       -> decltype(&v(I[Is]...)) {
      39       112000 :       return &v(I[Is]...);
      40              :     }
      41              : 
      42              :     template<int D, class View, class IVec>
      43              :     KOKKOS_INLINE_FUNCTION
      44        56000 :     auto view_ptr(View& v, const IVec& I)
      45              :       -> decltype(view_ptr_impl(v, I, std::make_index_sequence<D>{})) {
      46        56000 :       return view_ptr_impl(v, I, std::make_index_sequence<D>{});
      47              :     }
      48              : 
      49              :     /**
      50              :      * @brief Assemble a P1 FEM load vector (RHS) from particle attributes.
      51              :      *
      52              :      * For each particle position x, locate the owning element (ND index e_nd) and
      53              :      * reference coordinate xi. Deposit the particle attribute value into the
      54              :      * element's nodal DOFs using P1 Lagrange shape functions evaluated at xi.
      55              :      *
      56              :      * @tparam AttribIn   Particle attribute type with getView()(p) -> scalar
      57              :      * @tparam Field      ippl::Field with rank=Dim nodal coefficients (RHS)
      58              :      * @tparam PosAttrib  Particle position attribute with getView()(p) -> Vector<T,Dim>
      59              :      * @tparam Space      Lagrange space providing element/DOF/topology queries
      60              :      * @tparam policy_type Kokkos execution policy (defaults to Field::execution_space)
      61              :      */
      62              :     template <typename AttribIn, typename Field, typename PosAttrib, typename Space,
      63              :         typename policy_type = Kokkos::RangePolicy<typename Field::execution_space>>
      64           12 :     inline void assemble_rhs_from_particles(const AttribIn& attrib, Field& f,
      65              :                                              const PosAttrib& pp, const Space& space,
      66              :                                              policy_type iteration_policy)
      67              :     {
      68           12 :         constexpr unsigned Dim = Field::dim;
      69              :         using T          = typename Field::value_type;
      70              :         using view_type  = typename Field::view_type;
      71              :         using mesh_type  = typename Field::Mesh_t;
      72              : 
      73           12 :         static IpplTimings::TimerRef t = IpplTimings::getTimer("assemble_rhs_from_particles(P1)");
      74              : 
      75           12 :         IpplTimings::startTimer(t);
      76              : 
      77           12 :         view_type view = f.getView();
      78              :         
      79              :         // Mesh / layout (for locating + indexing into the field view)
      80           12 :         const mesh_type& mesh = f.get_mesh();
      81              : 
      82           12 :         const ippl::FieldLayout<Dim>& layout = f.getLayout();
      83           12 :         const ippl::NDIndex<Dim>&     lDom   = layout.getLocalNDIndex();
      84           12 :         const int                     nghost = f.getNghost();
      85              : 
      86              :         // Particle attribute/device views
      87           12 :         auto d_attr = attrib.getView();  // scalar weight per particle (e.g. charge)
      88           12 :         auto d_pos  = pp.getView();      // positions (Vector<T,Dim>) per particle
      89              : 
      90           12 :         Kokkos::parallel_for("assemble_rhs_from_particles_P1", iteration_policy,
      91        12024 :             KOKKOS_LAMBDA(const size_t p) {
      92        12000 :                 const Vector<T,Dim> x   = d_pos(p);
      93        12000 :                 const T val = d_attr(p);  
      94              : 
      95        12000 :                 Vector<size_t,Dim> e_nd;
      96        12000 :                 Vector<T,Dim>      xi;
      97        12000 :                 locate_element_nd_and_xi<T,Dim>(mesh, x, e_nd, xi);
      98              :                 // Convert to the element's linear index
      99        12000 :                 const size_t e_lin = space.getElementIndex(e_nd);
     100              : 
     101              :                 // DOFs for this element
     102        12000 :                 const auto dofs  = space.getGlobalDOFIndices(e_lin);
     103              : 
     104              :                 // Deposit into each vertex/DOF
     105        68000 :                 for (size_t a = 0; a < dofs.dim; ++a) {
     106        56000 :                     const size_t local = space.getLocalDOFIndex(e_lin, dofs[a]); 
     107        56000 :                     const T w = space.evaluateRefElementShapeFunction(local, xi);
     108              : 
     109        56000 :                     const auto v_nd = space.getMeshVertexNDIndex(dofs[a]); // ND coords (global, vertex-centered)
     110        56000 :                     ippl::Vector<size_t,Dim> I;                             // indices into view
     111              : 
     112       192000 :                     for (unsigned d = 0; d < Dim; ++d) {
     113       136000 :                         I[d] = static_cast<size_t>(v_nd[d] - lDom.first()[d] + nghost);
     114              :                     }
     115        56000 :                     Kokkos::atomic_add(view_ptr<Dim>(view, I), val * w);
     116              :                 }
     117        12000 :             }
     118              :         );
     119              : 
     120           12 :         static IpplTimings::TimerRef accumulateHaloTimer = IpplTimings::getTimer("accumulateHalo");
     121           12 :         IpplTimings::startTimer(accumulateHaloTimer);
     122           12 :         f.accumulateHalo();
     123           12 :         IpplTimings::stopTimer(accumulateHaloTimer);
     124              : 
     125           12 :     }
     126              : 
     127              :     template<class View, class IVec, std::size_t... Is>
     128              :     KOKKOS_INLINE_FUNCTION
     129        56000 :     decltype(auto) view_ref_impl(View& v, const IVec& I, std::index_sequence<Is...>) {
     130       112000 :         return v(I[Is]...);
     131              :     }
     132              : 
     133              :     template<int D, class View, class IVec>
     134              :     KOKKOS_INLINE_FUNCTION
     135        56000 :     decltype(auto) view_ref(View& v, const IVec& I) {
     136        56000 :         return view_ref_impl(v, I, std::make_index_sequence<D>{});
     137              :     }
     138              : 
     139              :     /**
     140              :      * @brief Interpolate a P1 FEM field to particle positions.
     141              :      *
     142              :      * For each particle position x, locate the owning element (ND index e_nd) and
     143              :      * reference coordinate xi. Evaluate P1 Lagrange shape functions at xi to
     144              :      * combine nodal coefficients and write u(x) to the particle attribute.
     145              :      *
     146              :      * @tparam AttribOut   Particle attribute type with getView()(p) -> scalar
     147              :      * @tparam Field       ippl::Field with rank=Dim nodal coefficients
     148              :      * @tparam PosAttrib   Particle position attribute with getView()(p) -> Vector<T,Dim>
     149              :      * @tparam Space       Lagrange space providing element/DOF/topology queries
     150              :      * @tparam policy_type Kokkos execution policy (defaults to Field::execution_space)
     151              :      */
     152              :     template <typename AttribOut, typename Field, typename PosAttrib, typename Space,
     153              :               typename policy_type = Kokkos::RangePolicy<typename Field::execution_space>>
     154           12 :     inline void interpolate_to_diracs(AttribOut& attrib_out,
     155              :                                                const Field& coeffs,
     156              :                                                const PosAttrib& pp,
     157              :                                                const Space& space,
     158              :                                                policy_type iteration_policy)
     159              :     {
     160           12 :         constexpr unsigned Dim = Field::dim;
     161              :         using T                 = typename AttribOut::value_type;
     162              :         using field_value_type  = typename Field::value_type;
     163              :         using view_type         = typename Field::view_type;
     164              :         using mesh_type         = typename Field::Mesh_t;
     165              : 
     166           12 :         static IpplTimings::TimerRef timer =
     167           12 :             IpplTimings::getTimer("interpolate_field_to_particles(P1)");
     168           12 :         IpplTimings::startTimer(timer);
     169              : 
     170           12 :         view_type view     = coeffs.getView();
     171           12 :         const mesh_type& M = coeffs.get_mesh();
     172              : 
     173              : 
     174           12 :         const ippl::FieldLayout<Dim>& layout = coeffs.getLayout();
     175           12 :         const ippl::NDIndex<Dim>&     lDom   = layout.getLocalNDIndex();
     176           12 :         const int                     nghost = coeffs.getNghost();
     177              : 
     178              :         // Particle device views
     179           12 :         auto d_pos = pp.getView();
     180           12 :         auto d_out = attrib_out.getView();
     181              : 
     182           12 :         Kokkos::parallel_for("interpolate_to_diracs_P1", iteration_policy,
     183        12024 :                 KOKKOS_LAMBDA(const size_t p) {
     184              : 
     185        18000 :             const Vector<T,Dim> x   = d_pos(p);
     186              : 
     187        12000 :             ippl::Vector<size_t,Dim> e_nd;
     188        12000 :             ippl::Vector<T,Dim>      xi;
     189        12000 :             locate_element_nd_and_xi<T,Dim>(M, x, e_nd, xi);
     190        12000 :             const size_t e_lin = space.getElementIndex(e_nd);
     191              : 
     192        12000 :             const auto dofs  = space.getGlobalDOFIndices(e_lin);
     193              : 
     194        12000 :             field_value_type up = field_value_type(0);
     195              : 
     196        68000 :             for (size_t a = 0; a < dofs.dim; ++a) {
     197        56000 :                 const size_t local = space.getLocalDOFIndex(e_lin, dofs[a]);
     198        56000 :                 const field_value_type w = space.evaluateRefElementShapeFunction(local, xi);
     199              : 
     200        56000 :                 const auto v_nd = space.getMeshVertexNDIndex(dofs[a]);
     201        56000 :                 ippl::Vector<size_t,Dim> I;
     202       192000 :                 for (unsigned d = 0; d < Dim; ++d) {
     203       136000 :                     I[d] = static_cast<size_t>(v_nd[d] - lDom.first()[d] + nghost);
     204              :                 }
     205              : 
     206        56000 :                 up += view_ref<Dim>(view, I) * w;
     207              :             }
     208        12000 :             d_out(p) = static_cast<T>(up);
     209        12000 :         });
     210           12 :     }
     211              : 
     212              : } // namespace ippl
     213              : #endif
        

Generated by: LCOV version 2.0-1