LCOV - code coverage report
Current view: top level - include/kokkos/nodalkernels - KokkosNodalKernel.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 6f668f Lines: 54 60 90.0 %
Date: 2025-09-22 20:01:15 Functions: 43 63 68.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #pragma once
      11             : 
      12             : #include "KokkosNodalKernelBase.h"
      13             : 
      14             : namespace Moose
      15             : {
      16             : namespace Kokkos
      17             : {
      18             : 
      19             : /**
      20             :  * The base class for a user to derive their own Kokkos nodal kernels.
      21             :  *
      22             :  * The polymorphic design of the original MOOSE is reproduced statically by leveraging the Curiously
      23             :  * Recurring Template Pattern (CRTP), a programming idiom that involves a class template inheriting
      24             :  * from a template instantiation of itself. When the user derives their Kokkos object from this
      25             :  * class, the inheritance structure will look like:
      26             :  *
      27             :  * class UserNodalKernel final : public Moose::Kokkos::NodalKernel<UserNodalKernel>
      28             :  *
      29             :  * It is important to note that the template argument should point to the last derived class.
      30             :  * Therefore, if the user wants to define a derived class that can be further inherited, the derived
      31             :  * class should be a class template as well. Otherwise, it is recommended to mark the derived class
      32             :  * as final to prevent its inheritence by mistake.
      33             :  *
      34             :  * The user is expected to define computeQpResidual(), computeQpJacobian(), and
      35             :  * computeQpOffDiagJacobian() as inlined public methods in their derived class (not virtual
      36             :  * override). The signature of computeQpResidual() expected to be defined in the derived class is as
      37             :  * follows:
      38             :  *
      39             :  * @param node The contiguous node ID
      40             :  * @returns The residual contribution
      41             :  *
      42             :  * KOKKOS_FUNCTION Real computeQpResidual(const ContiguousNodeID node) const;
      43             :  *
      44             :  * The signatures of computeQpJacobian() and computeOffDiagQpJacobian() can be found in the code
      45             :  * below, and their definition in the derived class is optional. If they are defined in the derived
      46             :  * class, they will hide the default definitions in the base class.
      47             :  */
      48             : template <typename Derived>
      49             : class NodalKernel : public NodalKernelBase
      50             : {
      51             : public:
      52             :   static InputParameters validParams();
      53             : 
      54             :   /**
      55             :    * Constructor
      56             :    */
      57             :   NodalKernel(const InputParameters & parameters);
      58             : 
      59             :   /**
      60             :    * Dispatch residual calculation
      61             :    */
      62             :   virtual void computeResidual() override;
      63             :   /**
      64             :    * Dispatch diagonal and off-diagonal Jacobian calculation
      65             :    */
      66             :   virtual void computeJacobian() override;
      67             : 
      68             :   /**
      69             :    * Default methods to prevent compile errors even when these methods were not defined in the
      70             :    * derived class
      71             :    */
      72             :   ///@{
      73             :   /**
      74             :    * Compute diagonal Jacobian contribution on a node
      75             :    * @param node The contiguous node ID
      76             :    * @returns The diagonal Jacobian contribution
      77             :    */
      78           0 :   KOKKOS_FUNCTION Real computeQpJacobian(const ContiguousNodeID /* node */) const { return 0; }
      79             :   /**
      80             :    * Compute off-diagonal Jacobian contribution on a node
      81             :    * @param jvar The variable number for column
      82             :    * @param node The contiguous node ID
      83             :    * @returns The off-diagonal Jacobian contribution
      84             :    */
      85           0 :   KOKKOS_FUNCTION Real computeQpOffDiagJacobian(const unsigned int /* jvar */,
      86             :                                                 const ContiguousNodeID /* node */) const
      87             :   {
      88           0 :     return 0;
      89             :   }
      90             :   ///@}
      91             : 
      92             :   /**
      93             :    * The parallel computation entry functions called by Kokkos
      94             :    */
      95             :   ///@{
      96             :   KOKKOS_FUNCTION void operator()(ResidualLoop, const ThreadID tid) const;
      97             :   KOKKOS_FUNCTION void operator()(JacobianLoop, const ThreadID tid) const;
      98             :   KOKKOS_FUNCTION void operator()(OffDiagJacobianLoop, const ThreadID tid) const;
      99             :   ///@}
     100             : 
     101             : protected:
     102             :   /**
     103             :    * Current solution at nodes
     104             :    */
     105             :   const VariableNodalValue _u;
     106             : 
     107             : private:
     108             :   /**
     109             :    * Flag whether this kernel is boundary-restricted
     110             :    */
     111             :   const bool _boundary_restricted;
     112             :   /**
     113             :    * Flag whether computeJacobian() was not defined in the derived class
     114             :    */
     115             :   const bool _default_diag;
     116             :   /**
     117             :    * Flag whether computeQpOffDiagJacobian() was not defined in the derived class
     118             :    */
     119             :   const bool _default_offdiag;
     120             : };
     121             : 
     122             : template <typename Derived>
     123             : InputParameters
     124       64312 : NodalKernel<Derived>::validParams()
     125             : {
     126       64312 :   InputParameters params = NodalKernelBase::validParams();
     127       64312 :   return params;
     128             : }
     129             : 
     130             : template <typename Derived>
     131         272 : NodalKernel<Derived>::NodalKernel(const InputParameters & parameters)
     132             :   : NodalKernelBase(parameters, Moose::VarFieldType::VAR_FIELD_STANDARD),
     133         215 :     _u(kokkosSystems(), _var),
     134         215 :     _boundary_restricted(boundaryRestricted()),
     135         215 :     _default_diag(&Derived::computeQpJacobian == &NodalKernel::computeQpJacobian),
     136         215 :     _default_offdiag(&Derived::computeQpOffDiagJacobian == &NodalKernel::computeQpOffDiagJacobian)
     137             : {
     138         272 : }
     139             : 
     140             : template <typename Derived>
     141             : void
     142       20340 : NodalKernel<Derived>::computeResidual()
     143             : {
     144       20340 :   ::Kokkos::RangePolicy<ResidualLoop, ExecSpace, ::Kokkos::IndexType<ThreadID>> policy(
     145       16822 :       0, _boundary_restricted ? numKokkosBoundaryNodes() : numKokkosBlockNodes());
     146       20340 :   ::Kokkos::parallel_for(policy, *static_cast<Derived *>(this));
     147       20340 :   ::Kokkos::fence();
     148       20340 : }
     149             : 
     150             : template <typename Derived>
     151             : void
     152        5424 : NodalKernel<Derived>::computeJacobian()
     153             : {
     154        5424 :   if (!_default_diag)
     155             :   {
     156        3118 :     ::Kokkos::RangePolicy<JacobianLoop, ExecSpace, ::Kokkos::IndexType<ThreadID>> policy(
     157        2516 :         0, _boundary_restricted ? numKokkosBoundaryNodes() : numKokkosBlockNodes());
     158        3118 :     ::Kokkos::parallel_for(policy, *static_cast<Derived *>(this));
     159        3118 :     ::Kokkos::fence();
     160        3118 :   }
     161             : 
     162        5424 :   if (!_default_offdiag)
     163             :   {
     164        3364 :     auto & sys = kokkosSystem(_kokkos_var.sys());
     165             : 
     166        9456 :     _thread.resize({sys.getCoupling(_kokkos_var.var()).size(),
     167        2728 :                     _boundary_restricted ? numKokkosBoundaryNodes() : numKokkosBlockNodes()});
     168             : 
     169        3364 :     ::Kokkos::RangePolicy<OffDiagJacobianLoop, ExecSpace, ::Kokkos::IndexType<ThreadID>> policy(
     170             :         0, _thread.size());
     171        3364 :     ::Kokkos::parallel_for(policy, *static_cast<Derived *>(this));
     172        3364 :     ::Kokkos::fence();
     173        3364 :   }
     174        5424 : }
     175             : 
     176             : template <typename Derived>
     177             : KOKKOS_FUNCTION void
     178     1265482 : NodalKernel<Derived>::operator()(ResidualLoop, const ThreadID tid) const
     179             : {
     180     1265482 :   auto kernel = static_cast<const Derived *>(this);
     181     1265482 :   auto node = _boundary_restricted ? kokkosBoundaryNodeID(tid) : kokkosBlockNodeID(tid);
     182     1265482 :   auto & sys = kokkosSystem(_kokkos_var.sys());
     183             : 
     184     1265482 :   if (!sys.isNodalDefined(node, _kokkos_var.var()))
     185           0 :     return;
     186             : 
     187     1265482 :   Real local_re = kernel->computeQpResidual(node);
     188             : 
     189     1265482 :   accumulateTaggedNodalResidual(true, local_re, node);
     190             : }
     191             : 
     192             : template <typename Derived>
     193             : KOKKOS_FUNCTION void
     194      194664 : NodalKernel<Derived>::operator()(JacobianLoop, const ThreadID tid) const
     195             : {
     196      194664 :   auto kernel = static_cast<const Derived *>(this);
     197      194664 :   auto node = _boundary_restricted ? kokkosBoundaryNodeID(tid) : kokkosBlockNodeID(tid);
     198      194664 :   auto & sys = kokkosSystem(_kokkos_var.sys());
     199             : 
     200      194664 :   if (!sys.isNodalDefined(node, _kokkos_var.var()))
     201           0 :     return;
     202             : 
     203      194664 :   Real local_ke = kernel->computeQpJacobian(node);
     204             : 
     205      194664 :   accumulateTaggedNodalMatrix(true, local_ke, node, _kokkos_var.var());
     206             : }
     207             : 
     208             : template <typename Derived>
     209             : KOKKOS_FUNCTION void
     210      249100 : NodalKernel<Derived>::operator()(OffDiagJacobianLoop, const ThreadID tid) const
     211             : {
     212      249100 :   auto kernel = static_cast<const Derived *>(this);
     213      249100 :   auto node = _boundary_restricted ? kokkosBoundaryNodeID(_thread(tid, 1))
     214      249100 :                                    : kokkosBlockNodeID(_thread(tid, 1));
     215      249100 :   auto & sys = kokkosSystem(_kokkos_var.sys());
     216      249100 :   auto jvar = sys.getCoupling(_kokkos_var.var())[_thread(tid, 0)];
     217             : 
     218      249100 :   if (!sys.isNodalDefined(node, _kokkos_var.var()))
     219           0 :     return;
     220             : 
     221      249100 :   Real local_ke = kernel->computeQpOffDiagJacobian(jvar, node);
     222             : 
     223      249100 :   accumulateTaggedNodalMatrix(true, local_ke, node, jvar);
     224             : }
     225             : 
     226             : } // namespace Kokkos
     227             : } // namespace Moose
     228             : 
     229             : #define usingKokkosNodalKernelMembers(T)                                                           \
     230             :   usingKokkosNodalKernelBaseMembers;                                                               \
     231             :                                                                                                    \
     232             : protected:                                                                                         \
     233             :   using Moose::Kokkos::NodalKernel<T>::_u;                                                         \
     234             :                                                                                                    \
     235             : public:                                                                                            \
     236             :   using Moose::Kokkos::NodalKernel<T>::operator()

Generated by: LCOV version 1.14