https://mooseframework.inl.gov
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 
12 template <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 
28 template <bool is_ad>
29 void
31 {
33  _my_elem_lma = nullptr;
34 }
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.
60 template <bool is_ad>
61 void
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.
82 template <bool is_ad>
83 void
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
void libmesh_ignore(const Args &...)
const std::string & name() const
bool isNodal() const override
virtual void computeJacobian() override
void mooseError(Args &&... args) const
virtual void computeOffDiagJacobian(unsigned int jvar) override
PorousFlowLumpedKernelBaseTempl(const InputParameters &parameters)
Base class for PorousFlow kernels that use mass-lumped (nodal) material properties.
virtual void computeOffDiagJacobian(unsigned int jvar) override
virtual void jacobianSetup()