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. PorousFlow has no discontinuous-Galerkin "
25 "finite-element discretisation, so an element-local variable (eg CONSTANT "
26 "MONOMIAL) cannot be used as a PorousFlow variable.");
27}
28
29template <bool is_ad>
30void
36
37// AD-path Jacobian assembly for kernels that use mass-lumped (nodal) material properties.
38//
39// The default ADKernel path (ADKernel::computeADJacobian -> addJacobian) routes through
40// Assembly::cacheJacobian, which takes the sparse column set from residuals[0] and reuses it for
41// every row. That assumes every test function's residual depends on the same set of DOFs, which
42// holds for ordinary qp-based weak forms because the solution at any QP is sum_j u_j*phi_j(qp)
43// and therefore involves every element DOF.
44//
45// With mass lumping each residual row _i depends only on the nodal material properties at node _i
46// (i.e. on the DOFs at node _i alone), so the column set from residuals[0] is only valid for row 0;
47// the off-node rows are assembled against the wrong columns and come out zero.
48//
49// addJacobianWithoutConstraints reads each row's own column indices from
50// residuals[_i].derivatives().nude_indices(), giving the correct per-node block structure.
51//
52// This is consistent with how the framework handles analogous cases:
53// - ADNodalKernel::computeJacobian passes a size-1 residual array; Assembly::cacheJacobian's
54// residuals.size()==1 branch falls straight through to cacheJacobianWithoutConstraints.
55// - MassLumpedTimeDerivative::computeJacobian (non-AD) overrides assembly to fill only the
56// node-diagonal entries, for the same structural reason.
57//
58// constrain_element_matrix is therefore skipped. It cannot be applied to a node-diagonal block
59// structure: the constraint machinery assumes a fully-coupled local matrix where all rows share a
60// column space. Neither the non-AD lumped path nor the framework AD nodal path applies it either.
61template <bool is_ad>
62void
64{
65 if constexpr (!is_ad)
67 else
68 {
69 if (_my_elem_lma != this->_current_elem)
70 {
71 this->computeResidualsForJacobian();
72 this->addJacobianWithoutConstraints(
73 this->_assembly, this->_residuals, this->dofIndices(), this->_var.scalingFactor());
74 _my_elem_lma = this->_current_elem;
75 }
76 }
77}
78
79// A single AD residual evaluation carries derivatives wrt every coupled variable, so the
80// off-diagonal blocks are assembled by the same addJacobianWithoutConstraints call as the diagonal.
81// _my_elem_lma caches the element so computation happens once per element rather than once per
82// coupled jvar, mirroring ADKernel's own _my_elem guard in ADKernel::computeOffDiagJacobian.
83template <bool is_ad>
84void
86{
87 if constexpr (!is_ad)
89 else
90 {
91 libmesh_ignore(jvar);
92 if (_my_elem_lma != this->_current_elem)
93 {
94 this->computeResidualsForJacobian();
95 this->addJacobianWithoutConstraints(
96 this->_assembly, this->_residuals, this->dofIndices(), this->_var.scalingFactor());
97 _my_elem_lma = this->_current_elem;
98 }
99 }
100}
101
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()