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()
|