19#include "libmesh/quadrature.h"
31 params.
addCoupledVar(
"disp_z",
"The z displacement variable");
32 params.
set<
bool>(
"use_displaced_mesh") =
true;
33 params.
set<
bool>(
"interpolate_normals") =
false;
42 params.
set<
bool>(
"ghost_point_neighbors") =
true;
43 const auto configure_point_neighbors =
46 rm_params.set<
bool>(
"use_displaced_mesh") = obj_params.
get<
bool>(
"use_displaced_mesh");
47 rm_params.set<BoundaryName>(
"secondary_boundary") =
48 obj_params.
get<BoundaryName>(
"secondary_boundary");
49 rm_params.set<BoundaryName>(
"primary_boundary") =
50 obj_params.
get<BoundaryName>(
"primary_boundary");
51 rm_params.set<SubdomainName>(
"secondary_subdomain") =
52 obj_params.
get<SubdomainName>(
"secondary_subdomain");
53 rm_params.set<SubdomainName>(
"primary_subdomain") =
54 obj_params.
get<SubdomainName>(
"primary_subdomain");
56 rm_params.set<
bool>(
"ghost_point_neighbors") = obj_params.
get<
bool>(
"ghost_point_neighbors");
59 Moose::RelationshipManagerType::COUPLING,
60 configure_point_neighbors);
65 _fe_problem(*getCheckedPointerParam<
FEProblemBase *>(
"_fe_problem_base")),
66 _nodal(getVar(
"disp_x", 0)->feType().family == LAGRANGE),
67 _disp_x_var(getVar(
"disp_x", 0)),
68 _disp_y_var(getVar(
"disp_y", 0)),
69 _has_disp_z(isCoupled(
"disp_z")),
70 _disp_z_var(_has_disp_z ? getVar(
"disp_z", 0) : nullptr),
71 _secondary_disp_x(_disp_x_var->adSln()),
72 _primary_disp_x(_disp_x_var->adSlnNeighbor()),
73 _secondary_disp_y(_disp_y_var->adSln()),
74 _primary_disp_y(_disp_y_var->adSlnNeighbor()),
75 _secondary_disp_z(_has_disp_z ? &_disp_z_var->adSln() : nullptr),
76 _primary_disp_z(_has_disp_z ? &_disp_z_var->adSlnNeighbor() : nullptr),
77 _coord(_assembly.mortarCoordTransformation())
79 if (!getParam<bool>(
"use_displaced_mesh"))
81 "'use_displaced_mesh' must be true for the WeightedGapUserObject object");
87 mooseError(
"Nodal contact pressure is not available for user object '",
name(),
"'.");
114 mooseError(
"Invalid displacement component '", component,
"' requested.");
127 if (getParam<bool>(
"interpolate_normals"))
129 "Nodal-normal derivatives require normalized secondary nodal normals and cannot be "
130 "combined with quadrature-point normal interpolation.");
132 const std::array<std::pair<const MooseVariable *, const char *>, 3> displacement_variables{
134 for (
const auto & [variable, parameter_name] : displacement_variables)
137 if (!variable->isNodal())
139 "Nodal-normal derivatives require a nodal displacement variable.");
140 if (&variable->sys() != &
_sys)
142 "Nodal-normal derivatives require displacement variables in the nonlinear "
143 "system assembled by this contact object.");
153 const auto & secondary_ip_lowerd_map =
157 std::array<ADReal, 3> primary_disp{
166 const ADReal & prim_x = primary_disp[0];
167 const ADReal & prim_y = primary_disp[1];
168 const ADReal * prim_z =
nullptr;
170 prim_z = &primary_disp[2];
172 const ADReal & sec_x = secondary_disp[0];
173 const ADReal & sec_y = secondary_disp[1];
174 const ADReal * sec_z =
nullptr;
176 sec_z = &secondary_disp[2];
189 gap_vec(0).derivatives() = prim_x.derivatives() - sec_x.derivatives();
190 gap_vec(1).derivatives() = prim_y.derivatives() - sec_y.derivatives();
192 gap_vec(2).derivatives() = prim_z->derivatives() - sec_z->derivatives();
206 "The nodal normals and secondary element must have the same number of nodes.");
223 const unsigned int nodal_index)
const
225 mooseAssert(nodal_index < lower_secondary_elem.n_nodes(),
226 "Nodal normal index must refer to a node on the secondary element.");
228 "AD contact normals should only be requested while recording nodal-normal "
230 const Node *
const node = lower_secondary_elem.node_ptr(nodal_index);
233 return normal_it->second;
245 "AD nodal coordinates should only be requested while recording nodal-normal "
248 "AD nodal coordinates require derivative recording.");
251 const std::array<std::pair<const MooseVariable *, unsigned int>, 3> displacement_variables{
253 for (
const auto & [variable, component] : displacement_variables)
256 const auto sys_num = variable->
sys().
number();
257 const auto var_num = variable->number();
261 if (node.n_dofs(sys_num, var_num))
263 point(component).derivatives(), node.dof_number(sys_num, var_num, 0), 1.0);
DualNumber< Real, DNDerivativeType, true > ADReal
const ExecFlagType EXEC_LINEAR
const ExecFlagType EXEC_NONLINEAR
std::map< unsigned int, unsigned int > getSecondaryIpToLowerElementMap(const Elem &lower_secondary_elem) const
void computeADNodalNormals(const std::function< ADPoint(const Node &)> &coordinate, std::unordered_map< const Node *, ADRealVectorValue > &nodal_normals) const
std::map< unsigned int, unsigned int > getPrimaryIpToLowerElementMap(const Elem &primary_elem, const Elem &primary_elem_ip, const Elem &lower_secondary_elem) const
const std::string & name() const
void paramError(const std::string ¶m, Args... args) const
void mooseError(Args &&... args) const
virtual const Node * nodePtr(const dof_id_type i) const
static InputParameters validParams()
Elem const *const & _lower_secondary_elem
const libMesh::QBase *const & _qrule_msm
const AutomaticMortarGeneration & amg() const
Elem const *const & _lower_primary_elem
const MooseArray< Point > & _phys_points_secondary
const MooseArray< Point > & _phys_points_primary
std::vector< Point > _normals
static void trimInteriorNodeDerivatives(const std::map< unsigned int, unsigned int > &primary_ip_lowerd_map, const Variables &moose_var, DualNumbers &ad_vars, const bool is_secondary)
const std::vector< Real > & _JxW_msm
static InputParameters validParams()
virtual void initialSetup()
virtual MooseMesh & mesh()=0
unsigned int number() const
static InputParameters validParams()
static InputParameters validParams()
virtual bool usesNodalNormalDerivatives() const =0
Whether this formulation includes displacement derivatives of the secondary nodal normals.
bool shouldRecordNodalNormalDerivatives() const
Whether the current assembly records nodal-normal derivatives for this object's system.
unsigned int _i
Test function index.
const ADVariableValue & _secondary_disp_x
x-displacement on the secondary face
const MooseVariable *const _disp_x_var
The x displacement variable.
virtual void computeQpProperties()
Computes properties that are functions only of the current quadrature point (_qp),...
virtual const VariableTestValue & tractionBasis() const
const bool _has_disp_z
For 2D mortar contact no displacement will be specified, so const pointers used.
virtual void finalize() override
virtual void execute() override
ADRealVectorValue _qp_gap_nodal
Vector for computation of weighted gap with nodal normals.
virtual void initialSetup() 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 Real getNormalGap(const Node *const) const
ADPoint nodalCoordinate(const Node &node) const
Add displacement derivatives to the node's current coordinate.
static void addNodalNormalCoupling(InputParameters ¶ms)
Request the secondary face point-neighbor matrix coupling that nodal-normal derivatives need.
const ADVariableValue & _primary_disp_y
y-displacement on the primary face
const MooseArray< Real > & _coord
Member for handling change of coordinate systems (xyz, rz, spherical)
const ADVariableValue & _secondary_disp_y
y-displacement on the secondary face
const MooseVariable * dispVar(unsigned int component) const
const ADVariableValue & _primary_disp_x
x-displacement on the primary face
const MooseVariable *const _disp_y_var
The y displacement variable.
virtual ADReal nodalContactPressure(const Node &node) const
const ADRealVectorValue & contactNormal(const Elem &lower_secondary_elem, unsigned int nodal_index) const
Return the cached contact normal for the supplied lower-dimensional secondary element node.
std::unordered_map< const DofObject *, std::pair< ADReal, Real > > _dof_to_weighted_gap
A map from node to weighted gap and normalization (if requested)
virtual const VariableTestValue & test() const =0
WeightedGapUserObject(const InputParameters ¶meters)
std::unordered_map< const Node *, ADRealVectorValue > _ad_nodal_normals
AD nodal normals, each averaged over the secondary faces containing that node.
const MooseVariable *const _disp_z_var
The z displacement variable.
ADRealVectorValue _qp_displacement_nodal
Vector for computation of relative displacement (determines mixity ratio in interface problems)
virtual void computeQpIProperties()
Computes properties that are functions both of _qp and _i, for example the weighted gap.
virtual void initialize() override
std::unordered_map< const DofObject *, ADRealVectorValue > _dof_to_weighted_displacements
A map from node to weighted displacements.
virtual bool constrainedByOwner() const =0
Real physicalGap(const std::pair< ADReal, Real > &gap) const
Compute physical gap from integration gap quantity.
const VariableTestValue * _test
A pointer to the test function associated with the weighted gap.
const bool _nodal
Whether the dof objects are nodal; if they're not, then they're elemental.
const Parallel::Communicator & _communicator
unsigned int n_points() const
VariableShapeValue< true > VariableTestValue
bool doDerivatives(const SubProblem &subproblem, const SystemBase &sys)
void derivInsert(SemiDynamicSparseNumberArray< Real, libMesh::dof_id_type, NWrapper< N > > &derivs, libMesh::dof_id_type index, Real value)