16#include "libmesh/fe.h"
24 params.addRequiredCoupledVar(
25 "lm_variable",
"The Lagrange multiplier variable representing the contact pressure.");
26 params.addParam<
bool>(
27 "use_petrov_galerkin",
false,
"Whether to use the Petrov-Galerkin approach.");
28 params.addCoupledVar(
"aux_lm",
29 "Auxiliary Lagrange multiplier variable that is utilized together with the "
30 "Petrov-Galerkin approach.");
31 params.addParam<
bool>(
34 "Whether to apply the node-based Lagrange-multiplier scaling of Popp et al. (2013) to "
35 "improve the conditioning of the linear system when secondary elements are only partially "
36 "covered (edge dropping). See the documentation for the current limitations.");
45 "Provides the mortar normal Lagrange multiplier for constraint enforcement.");
52 _lm_var(getVar(
"lm_variable", 0)),
53 _use_petrov_galerkin(getParam<bool>(
"use_petrov_galerkin")),
54 _aux_lm_var(isCoupled(
"aux_lm") ? getVar(
"aux_lm", 0) : nullptr),
55 _use_nodal_scaling(getParam<bool>(
"use_nodal_scaling"))
62 "We need to specify an auxiliary variable `aux_lm` while using the Petrov-Galerkin "
67 "Auxiliary LM variable needs to use standard shape function, i.e., set `use_dual = "
78 "Node-based scaling is only implemented for first-order Lagrange multiplier and "
79 "displacement variables.");
82 if (!getParam<bool>(
"correct_edge_dropping"))
84 "Node-based scaling requires 'correct_edge_dropping = true'.");
87 const FEType fe_type(FIRST, LAGRANGE);
97 const std::string & var_param_name)
const
101 "The Lagrange multiplier variable must be an actual variable and not a constant.");
104 "The Lagrange multiplier variables must be provided and be actual variables.");
109 const std::string & var_param_name)
const
112 paramError(var_param_name,
"The Lagrange multiplier variables must be of Lagrange type");
209 fraction_sum / libmesh_map_find(nodes_to_secondary_elem, dof->id()).size();
212const std::vector<Real> &
225 std::vector<Real> integrals(phi.size(), 0);
230 for (
const auto j : index_range(integrals))
231 integrals[j] += phi[j][qp] * JxW[qp] * coord;
252 mooseAssert(phi.size(),
"The Lagrange multiplier should have lower-dimensional shape functions");
253 const std::size_t n_qp = phi[0].size();
255 for (
const auto qp : make_range(n_qp))
260 for (
const auto j : index_range(phi))
262 const Node *
const node = lower_elem->node_ptr(j);
263 const auto dof_index = node->dof_number(sys_num, var_num, 0);
264 ADReal lm_value = current_solution(dof_index);
267 for (
const auto qp : make_range(n_qp))
277 if (!node->n_dofs(sys_num, var_num))
278 mooseError(
"No degrees of freedom for the Lagrange multiplier at the node. If this is being "
279 "called from an aux kernel make sure that your aux variable has the same order as "
280 "your Lagrange multiplier");
282 const auto dof_number = node->dof_number(sys_num, var_num, 0);
DualNumber< Real, DNDerivativeType, true > ADReal
void coordTransformFactor(const SubProblem &s, SubdomainID sub_id, const P &point, C &factor, SubdomainID neighbor_sub_id=libMesh::Elem::invalid_subdomain_id)
registerMooseObject("ContactApp", LMWeightedGapUserObject)
const OutputTools< OutputType >::VariablePhiValue & fePhiLower(FEType type) const
const Elem *const & lowerDElem() const
const std::unordered_map< dof_id_type, std::vector< const Elem * > > & nodesToSecondaryElem() const
virtual bool isCoupledConstant(const std::string &var_name) const
User object for computing weighted gaps and contact pressure for Lagrange multipler based mortar cons...
const std::vector< Real > & fullNodalIntegrals(const Elem *elem)
Full coordinate-weighted integral int_e N_j per local node on the secondary lower-dimensional element...
void initializeNodalScaling()
The node-based scaling steps, kept out of initialize()/finalize()/computeQpIProperties() so that a cl...
void computeQpINodalScaling()
std::unordered_map< const DofObject *, std::unordered_set< dof_id_type > > _full_normalization_elems
Elements already folded into _dof_to_full_normalization for a given node, to avoid double counting wh...
std::unordered_map< const DofObject *, Real > _dof_to_full_normalization
Per-node sum, over each distinct adjacent secondary element, of the full-element integral int_e N_j (...
const bool _use_nodal_scaling
Whether to apply the Popp et al.
void finalizeNodalScaling()
virtual void reinit() override
virtual void initialize() override
virtual Real nodalScale(const DofObject *const dof) const override
Node-based Lagrange-multiplier scaling factor kappa_j of Popp et al.
virtual void finalize() override
LMWeightedGapUserObject(const InputParameters ¶meters)
std::unordered_map< dof_id_type, std::vector< Real > > _elem_to_full_nodal_integral
Cache of the per-node full integrals int_e N_j (see fullNodalIntegrals()), keyed by element id; clear...
static InputParameters validParams()
const MooseVariable *const _aux_lm_var
The auxiliary Lagrange multiplier variable (used together whith the Petrov-Galerkin approach)
virtual const ADVariableValue & contactPressure() const override
std::unique_ptr< libMesh::FEBase > _nodal_scaling_fe
Finite element and quadrature rule used to evaluate fullNodalIntegrals()
const bool _use_petrov_galerkin
Whether to use Petrov-Galerkin approach.
void verifyLagrange(const MooseVariable &var, const std::string &var_name) const
Verify that the provided variables have degrees of freedom at nodes.
std::unordered_map< const DofObject *, Real > _dof_to_covered_fraction_sum
Per-node numerator of kappa_j (Popp 2013 eq.
ADVariableValue _scaled_contact_pressure
Physical contact pressure sum_j Phi_j (zhat_j / kappa_j) at the segment quadrature points when node-b...
void checkInput(const MooseVariable *const var, const std::string &var_name) const
Check user input validity for provided variable.
virtual void computeQpIProperties() override
Computes properties that are functions both of _qp and _i, for example the weighted gap.
std::unique_ptr< libMesh::QGauss > _nodal_scaling_qrule
virtual Real getNormalContactPressure(const Node *const) const override
virtual const VariableTestValue & test() const override
const MooseVariableFE< Real > *const _lm_var
The Lagrange multiplier variable representing the contact pressure.
std::unordered_map< const DofObject *, Real > _dof_to_nodal_scale
A map from node to its node-based scaling factor kappa_j (see nodalScale())
static InputParameters newParams()
New parameters that this sub-class introduces.
void paramError(const std::string ¶m, Args... args) const
void mooseError(Args &&... args) const
bool isParamValid(const std::string &name) const
virtual unsigned int dimension() const
virtual const Node * nodePtr(const dof_id_type i) const
const libMesh::FEType & feType() const
unsigned int number() const
const ADTemplateVariableValue< OutputType > & adSlnLower() const
virtual const FieldVariablePhiValue & phiLower() const override
Elem const *const & _lower_secondary_elem
const AutomaticMortarGeneration & amg() const
virtual MooseMesh & mesh()=0
virtual const NumericVector< Number > *const & currentSolution() const=0
unsigned int number() const
Creates dof object to weighted gap map.
static InputParameters validParams()
unsigned int _i
Test function index.
const MooseVariable *const _disp_x_var
The x displacement variable.
virtual void finalize() override
unsigned int _qp
Quadrature point index for the mortar segments.
Real _qp_factor
The value of the LM at the current quadrature point.
virtual void computeQpIProperties()
Computes properties that are functions both of _qp and _i, for example the weighted gap.
virtual void initialize() override
const bool _nodal
Whether the dof objects are nodal; if they're not, then they're elemental.
const Parallel::Communicator & _communicator
VariableShapeValue< true > VariableTestValue
VariableValueTempl< true > ADVariableValue
void derivInsert(SemiDynamicSparseNumberArray< Real, libMesh::dof_id_type, NWrapper< N > > &derivs, libMesh::dof_id_type index, Real value)