https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PorousFlowLumpedKernelBase.C
Go to the documentation of this file.
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
11
12template <bool is_ad>
14 const InputParameters & parameters)
15 : GenericKernel<is_ad>(parameters)
16{
17 // Mass lumping evaluates each residual row using the nodal material property at that node, which
18 // identifies each element test function with a mesh node. This is only valid for nodal
19 // (Lagrange) variables.
20 if (!_var.isNodal())
21 mooseError("The variable '",
22 _var.name(),
23 "' is not a nodal (Lagrange) variable. This kernel uses mass lumping, which "
24 "requires a nodal variable. For non-nodal variables use the non-lumped "
25 "PorousFlowFullySaturated* kernels instead.");
26}
27
28template <bool is_ad>
29void
35
36// AD-path Jacobian assembly for kernels that use mass-lumped (nodal) material properties.
37//
38// The default ADKernel path (ADKernel::computeADJacobian -> addJacobian) routes through
39// Assembly::cacheJacobian, which takes the sparse column set from residuals[0] and reuses it for
40// every row. That assumes every test function's residual depends on the same set of DOFs, which
41// holds for ordinary qp-based weak forms because the solution at any QP is sum_j u_j*phi_j(qp)
42// and therefore involves every element DOF.
43//
44// With mass lumping each residual row _i depends only on the nodal material properties at node _i
45// (i.e. on the DOFs at node _i alone), so the column set from residuals[0] is only valid for row 0;
46// the off-node rows are assembled against the wrong columns and come out zero.
47//
48// addJacobianWithoutConstraints reads each row's own column indices from
49// residuals[_i].derivatives().nude_indices(), giving the correct per-node block structure.
50//
51// This is consistent with how the framework handles analogous cases:
52// - ADNodalKernel::computeJacobian passes a size-1 residual array; Assembly::cacheJacobian's
53// residuals.size()==1 branch falls straight through to cacheJacobianWithoutConstraints.
54// - MassLumpedTimeDerivative::computeJacobian (non-AD) overrides assembly to fill only the
55// node-diagonal entries, for the same structural reason.
56//
57// constrain_element_matrix is therefore skipped. It cannot be applied to a node-diagonal block
58// structure: the constraint machinery assumes a fully-coupled local matrix where all rows share a
59// column space. Neither the non-AD lumped path nor the framework AD nodal path applies it either.
60template <bool is_ad>
61void
63{
64 if constexpr (!is_ad)
66 else
67 {
68 if (_my_elem_lma != this->_current_elem)
69 {
70 this->computeResidualsForJacobian();
71 this->addJacobianWithoutConstraints(
72 this->_assembly, this->_residuals, this->dofIndices(), this->_var.scalingFactor());
73 _my_elem_lma = this->_current_elem;
74 }
75 }
76}
77
78// A single AD residual evaluation carries derivatives wrt every coupled variable, so the
79// off-diagonal blocks are assembled by the same addJacobianWithoutConstraints call as the diagonal.
80// _my_elem_lma caches the element so computation happens once per element rather than once per
81// coupled jvar, mirroring ADKernel's own _my_elem guard in ADKernel::computeOffDiagJacobian.
82template <bool is_ad>
83void
85{
86 if constexpr (!is_ad)
88 else
89 {
90 libmesh_ignore(jvar);
91 if (_my_elem_lma != this->_current_elem)
92 {
93 this->computeResidualsForJacobian();
94 this->addJacobianWithoutConstraints(
95 this->_assembly, this->_residuals, this->dofIndices(), this->_var.scalingFactor());
96 _my_elem_lma = this->_current_elem;
97 }
98 }
99}
100
MooseVariable & _var
const std::string & name() const
void mooseError(Args &&... args) const
bool isNodal() const override
Base class for PorousFlow kernels that use mass-lumped (nodal) material properties.
virtual void computeOffDiagJacobian(unsigned int jvar) override
PorousFlowLumpedKernelBaseTempl(const InputParameters &parameters)
virtual void jacobianSetup()