15#include "metaphysicl/metaphysicl_version.h"
16#include "metaphysicl/dualsemidynamicsparsenumberarray.h"
17#include "metaphysicl/parallel_dualnumber.h"
18#if METAPHYSICL_MAJOR_VERSION < 2
19#include "metaphysicl/parallel_dynamic_std_array_wrapper.h"
21#include "metaphysicl/parallel_dynamic_array_wrapper.h"
23#include "metaphysicl/parallel_semidynamicsparsenumberarray.h"
34 const auto & disp_x_name = ret.
get<std::vector<VariableName>>(
"disp_x");
35 if (disp_x_name.size() != 1)
36 mooseError(
"We require that the disp_x parameter have exactly one coupled name");
39 ret.
set<VariableName>(
"secondary_variable") = disp_x_name[0];
40 ret.
set<VariableName>(
"primary_variable") = disp_x_name[0];
51 params.
set<
bool>(
"_compute_primal_gradients") =
false;
52 params.
addClassDescription(
"Computes the weighted gap that will later be used to enforce the "
53 "zero-penetration mechanical contact conditions");
58 params.
addCoupledVar(
"disp_z",
"The z displacement variable");
60 "c", 1e6,
"Parameter for balancing the size of the gap and contact pressure");
64 "Whether to normalize c by weighting function norm. When unnormalized "
65 "the value of c effectively depends on element size since in the constraint we compare nodal "
66 "Lagrange Multiplier values to integrated gap values (LM nodal value is independent of "
67 "element size, where integrated values are dependent on element size).");
70 params.
set<
bool>(
"ghost_point_neighbors") =
true;
71 params.
set<
bool>(
"use_displaced_mesh") =
true;
72 params.
set<
bool>(
"interpolate_normals") =
false;
73 params.
addRequiredParam<UserObjectName>(
"weighted_gap_uo",
"The weighted gap user object");
80 _secondary_disp_x(adCoupledValue(
"disp_x")),
81 _primary_disp_x(adCoupledNeighborValue(
"disp_x")),
82 _secondary_disp_y(adCoupledValue(
"disp_y")),
83 _primary_disp_y(adCoupledNeighborValue(
"disp_y")),
84 _has_disp_z(isCoupled(
"disp_z")),
85 _secondary_disp_z(_has_disp_z ? &adCoupledValue(
"disp_z") : nullptr),
86 _primary_disp_z(_has_disp_z ? &adCoupledNeighborValue(
"disp_z") : nullptr),
87 _c(getParam<Real>(
"c")),
88 _normalize_c(getParam<bool>(
"normalize_c")),
89 _nodal(getVar(
"disp_x", 0)->feType().family == LAGRANGE),
90 _disp_x_var(getVar(
"disp_x", 0)),
91 _disp_y_var(getVar(
"disp_y", 0)),
92 _disp_z_var(_has_disp_z ? getVar(
"disp_z", 0) : nullptr),
97 "Nodal-normal derivatives are not supported by user object '",
105 "'weighted_gap_uo' must be defined on the same secondary/primary subdomain pair as "
106 "this constraint when nodal-normal derivatives are enabled.");
108 const std::array<std::pair<const MooseVariable *, unsigned int>, 3> displacement_variables{
110 for (
const auto & [
variable, component] : displacement_variables)
113 "'weighted_gap_uo' must use the same displacement variables as this constraint "
114 "when nodal-normal derivatives are enabled.");
116 if (!getParam<bool>(
"use_displaced_mesh"))
118 "use_displaced_mesh",
119 "'use_displaced_mesh' must be true for the ComputeWeightedGapLMMechanicalContact object");
121 if (getParam<bool>(
"interpolate_normals"))
123 "Mechanical mortar contact uses normalized secondary nodal normals and cannot be "
124 "combined with quadrature-point normal interpolation.");
128 mooseError(
"Normal contact constraints only support elemental variables of CONSTANT order");
134 mooseError(
"We should never call computeQpResidual for ComputeWeightedGapLMMechanicalContact");
177 parallel_object_only();
181 for (
const auto & [dof_object, weighted_gap_pr] : dof_to_weighted_gap)
186 const auto & [weighted_gap, normalization] = weighted_gap_pr;
196 const std::unordered_set<const Node *> & inactive_lm_nodes)
200 for (
const auto & [dof_object, weighted_gap_pr] : dof_to_weighted_gap)
202 if ((inactive_lm_nodes.find(
static_cast<const Node *
>(dof_object)) !=
203 inactive_lm_nodes.end()) ||
207 const auto & [weighted_gap, normalization] = weighted_gap_pr;
234 const ADReal dof_residual = std::min(lm_value, weighted_gap *
c / kappa);
237 std::array<ADReal, 1>{{dof_residual}},
238 std::array<dof_id_type, 1>{{dof_index}},
DualNumber< Real, DNDerivativeType, true > ADReal
void mooseError(Args &&... args)
static InputParameters validParams()
const std::string & name() const
void paramError(const std::string ¶m, Args... args) const
void mooseError(Args &&... args) const
const libMesh::FEType & feType() const
void scalingFactor(const std::vector< Real > &factor)
unsigned int number() const
bool isNodal() const override
MooseVariable *const _var
const MooseVariable & variable() const override
SubdomainID primarySubdomain() const
SubdomainID secondarySubdomain() const
virtual const NumericVector< Number > *const & currentSolution() const=0
unsigned int number() const
void addResidualsAndJacobian(Assembly &assembly, const Residuals &residuals, const Indices &dof_indices, Real scaling_factor)
Creates dof object to weighted gap map.
virtual bool usesNodalNormalDerivatives() const =0
Whether this formulation includes displacement derivatives of the secondary nodal normals.
const std::unordered_map< const DofObject *, std::pair< ADReal, Real > > & dofToWeightedGap() const
Get the degree of freedom to weighted gap information.
virtual Real nodalScale(const DofObject *const) const
Node-based Lagrange-multiplier scaling factor kappa_j of Popp et al.
const MooseVariable * dispVar(unsigned int component) const
virtual Real normalizeCDivisor(const DofObject *const, const Real covered_normalization) const
processor_id_type processor_id() const
void derivInsert(SemiDynamicSparseNumberArray< Real, libMesh::dof_id_type, NWrapper< N > > &derivs, libMesh::dof_id_type index, Real value)