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 : #include "PorousFlowLumpedKernelBase.h" 11 : 12 : template <bool is_ad> 13 4622 : PorousFlowLumpedKernelBaseTempl<is_ad>::PorousFlowLumpedKernelBaseTempl( 14 : const InputParameters & parameters) 15 4622 : : 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 4622 : if (!_var.isNodal()) 21 2 : mooseError("The variable '", 22 2 : _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 4620 : } 27 : 28 : template <bool is_ad> 29 : void 30 151065 : PorousFlowLumpedKernelBaseTempl<is_ad>::jacobianSetup() 31 : { 32 151065 : GenericKernel<is_ad>::jacobianSetup(); 33 151065 : _my_elem_lma = nullptr; 34 151065 : } 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 62 3062116 : PorousFlowLumpedKernelBaseTempl<is_ad>::computeJacobian() 63 : { 64 : if constexpr (!is_ad) 65 3062116 : GenericKernel<is_ad>::computeJacobian(); 66 : else 67 : { 68 0 : if (_my_elem_lma != this->_current_elem) 69 : { 70 0 : this->computeResidualsForJacobian(); 71 0 : this->addJacobianWithoutConstraints( 72 0 : this->_assembly, this->_residuals, this->dofIndices(), this->_var.scalingFactor()); 73 0 : _my_elem_lma = this->_current_elem; 74 : } 75 : } 76 3062116 : } 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 84 6423397 : PorousFlowLumpedKernelBaseTempl<is_ad>::computeOffDiagJacobian(unsigned int jvar) 85 : { 86 : if constexpr (!is_ad) 87 6423329 : GenericKernel<is_ad>::computeOffDiagJacobian(jvar); 88 : else 89 : { 90 : libmesh_ignore(jvar); 91 68 : if (_my_elem_lma != this->_current_elem) 92 : { 93 36 : this->computeResidualsForJacobian(); 94 36 : this->addJacobianWithoutConstraints( 95 36 : this->_assembly, this->_residuals, this->dofIndices(), this->_var.scalingFactor()); 96 36 : _my_elem_lma = this->_current_elem; 97 : } 98 : } 99 6423397 : } 100 : 101 : template class PorousFlowLumpedKernelBaseTempl<false>; 102 : template class PorousFlowLumpedKernelBaseTempl<true>;