| Base 846a5c | Head #33390 250e9c | ||||
|---|---|---|---|---|---|
| Total | Total | +/- | New | ||
| Rate | 91.29% | 91.35% | +0.06% | 100.00% | |
| Hits | 5021 | 5109 | +88 | 117 | |
| Misses | 479 | 484 | +5 | 0 | |
| Filename | Stmts | Miss | Cover |
|---|---|---|---|
| modules/contact/src/actions/ContactAction.C | +3 | -1 | +0.14% |
| modules/contact/src/constraints/ComputeFrictionalForceLMMechanicalContact.C | +1 | 0 | +0.06% |
| modules/contact/src/constraints/ComputeWeightedGapLMMechanicalContact.C | +5 | 0 | +0.62% |
| modules/contact/src/constraints/NormalMortarMechanicalContact.C | +7 | +1 | -2.94% |
| modules/contact/src/constraints/TangentialMortarMechanicalContact.C | +4 | +1 | -1.85% |
| modules/contact/src/userobjects/CohesiveZoneModelBase.C | +3 | 0 | +0.09% |
| modules/contact/src/userobjects/LMWeightedGapUserObject.C | +1 | 0 | +0.37% |
| modules/contact/src/userobjects/LMWeightedVelocitiesUserObject.C | +1 | 0 | +0.15% |
| modules/contact/src/userobjects/PenaltyWeightedGapUserObject.C | +19 | 0 | +0.75% |
| modules/contact/src/userobjects/WeightedGapUserObject.C | +42 | +4 | -2.80% |
| modules/contact/src/userobjects/WeightedVelocitiesUserObject.C | +7 | 0 | +0.41% |
| TOTAL | +93 | +5 | +0.06% |
codecodecode+
868 869 870 871 + 872 + 873 + 874 875 876 |
params.set<MooseEnum>("mortar_3d_subpatch_plane") = getParam<MooseEnum>("mortar_3d_subpatch_plane"); const bool augmented_penalty = _formulation == ContactFormulation::MORTAR_PENALTY && dynamic_cast<AugmentedLagrangianContactProblemInterface *>(_problem.get()); params.set<bool>("ghost_point_neighbors") = !_mortar_dynamics && !augmented_penalty; addRelationshipManagers(input_rm_type, params); } else |
1160 1161 1162 1163 1164 1165 1166 |
uo_params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping"); uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]}; if (ndisp > 2) uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]}; uo_params.set<VariableName>("secondary_variable") = displacements[0]; uo_params.set<bool>("use_displaced_mesh") = true; |
73 74 75 76 + 77 78 79 |
_3d(_has_disp_z) { _weighted_velocities_uo.includeNodalNormalDerivatives(); if (parameters.isParamSetByUser("mu") && _has_friction_function) paramError( |
63 64 65 66 + 67 + 68 69 70 |
"the value of c effectively depends on element size since in the constraint we compare nodal " "Lagrange Multiplier values to integrated gap values (LM nodal value is independent of " "element size, where integrated values are dependent on element size)."); params.set<bool>("ghost_point_neighbors") = true; params.suppressParameter<bool>("ghost_point_neighbors"); params.set<bool>("use_displaced_mesh") = true; params.set<bool>("interpolate_normals") = false; params.addRequiredParam<UserObjectName>("weighted_gap_uo", "The weighted gap user object"); |
89 90 91 92 + 93 94 95 96 97 98 99 + 100 + 101 102 103 |
_disp_z_var(_has_disp_z ? getVar("disp_z", 0) : nullptr), _weighted_gap_uo(getUserObject<WeightedGapUserObject>("weighted_gap_uo")) { _weighted_gap_uo.includeNodalNormalDerivatives(); if (!getParam<bool>("use_displaced_mesh")) paramError( "use_displaced_mesh", "'use_displaced_mesh' must be true for the ComputeWeightedGapLMMechanicalContact object"); if (getParam<bool>("interpolate_normals")) paramError("interpolate_normals", "Mechanical mortar contact uses normalized secondary nodal normals and cannot be " "combined with quadrature-point normal interpolation."); |
31 32 33 34 + 35 36 + 37 + 38 39 40 |
NormalMortarMechanicalContact::NormalMortarMechanicalContact(const InputParameters & parameters) : ADMortarLagrangeConstraint(parameters), _component(getParam<MooseEnum>("component")), _weighted_gap_uo(getUserObject<WeightedGapUserObject>("weighted_gap_uo")) { if (getParam<bool>("interpolate_normals")) paramError("interpolate_normals", "Mechanical mortar contact uses normalized secondary nodal normals and cannot be " "combined with quadrature-point normal interpolation."); } |
57 58 59 60 + 61 + 62 + 63 64 + 65 66 67 |
{ const auto normal_index = libmesh_map_find(_secondary_ip_lowerd_map, _i); const auto normal = _weighted_gap_uo.usesNodalNormalDerivatives() ? _weighted_gap_uo.contactNormal(*_lower_secondary_elem, normal_index) : ADRealVectorValue(_normals[normal_index]); return _test_secondary[_i][_qp] * _weighted_gap_uo.contactPressure()[_qp] * normal(_component); } case Moose::MortarType::Primary: |
70 71 72 73 + 74 + 75 + 76 77 + 78 79 80 |
{ const auto normal_index = libmesh_map_find(_primary_ip_lowerd_map, _i); const auto normal = _weighted_gap_uo.usesNodalNormalDerivatives() ? _weighted_gap_uo.contactNormal(*_lower_secondary_elem, normal_index) : ADRealVectorValue(_normals[normal_index]); return -_test_primary[_i][_qp] * _weighted_gap_uo.contactPressure()[_qp] * normal(_component); } default: return 0; |
41 42 43 44 + 45 46 + 47 + 48 49 50 |
: ADMortarLagrangeConstraint(parameters), _component(getParam<MooseEnum>("component")), _direction(getParam<MooseEnum>("direction")), _weighted_velocities_uo(getUserObject<WeightedVelocitiesUserObject>("weighted_velocities_uo")) { if (getParam<bool>("interpolate_normals")) paramError("interpolate_normals", "Mechanical mortar contact uses tangents derived from normalized secondary nodal " "normals and cannot be combined with quadrature-point normal interpolation."); } |
52 53 54 55 + 56 57 + 58 59 60 + 61 + 62 63 64 + 65 + 66 + 67 + 68 69 70 |
ADReal TangentialMortarMechanicalContact::computeQpResidual(Moose::MortarType type) { const auto tangent_component = [this](const unsigned int geometry_index) { if (_weighted_velocities_uo.usesNodalNormalDerivatives()) { const auto tangents = _weighted_velocities_uo.contactTangents(*_lower_secondary_elem, geometry_index); return tangents[_direction](_component) / tangents[_direction].norm(); } const auto & tangents = amg().getNodalTangents(*_lower_secondary_elem); return ADReal(tangents[_direction][geometry_index](_component) / tangents[_direction][geometry_index].norm()); }; MooseEnum direction("direction_1 direction_2", "direction_1"); |
85 86 87 88 + 89 + 90 91 92 93 + 94 + 95 96 97 |
// means we want the residual to be negative in that case. So the sign of this residual should // be the same as the sign of lambda { const auto geometry_index = libmesh_map_find(_secondary_ip_lowerd_map, _i); return _test_secondary[_i][_qp] * tangential_pressure * tangent_component(geometry_index); } case Moose::MortarType::Primary: { const auto geometry_index = libmesh_map_find(_primary_ip_lowerd_map, _i); return -_test_primary[_i][_qp] * tangential_pressure * tangent_component(geometry_index); } default: return 0; |
44 45 46 47 + 48 + 49 + 50 51 52 |
params.suppressParameter<Real>("penalty_multiplier"); params.suppressParameter<Real>("penetration_tolerance"); params.setParameters("penalty", 0.0); params.set<bool>("allow_nodal_normal_derivatives") = false; params.set<bool>("use_nodal_normal_derivatives") = false; params.set<bool>("ghost_point_neighbors") = false; return params; } |
33 34 35 36 + 37 38 39 |
InputParameters params = WeightedGapUserObject::validParams(); params.addClassDescription( "Provides the mortar normal Lagrange multiplier for constraint enforcement."); params.set<bool>("allow_nodal_normal_derivatives") = true; params += LMWeightedGapUserObject::newParams(); return params; } |
20 21 22 23 + 24 25 26 |
params += LMWeightedGapUserObject::newParams(); params.addClassDescription("Provides the mortar contact Lagrange multipliers (normal and " "tangential) for constraint enforcement."); params.set<bool>("allow_nodal_normal_derivatives") = true; params.renameCoupledVar("lm_variable", "lm_variable_normal", ""); params.addRequiredCoupledVar( "lm_variable_tangential_one", |
20 21 22 23 + 24 + 25 + 26 27 28 29 + 30 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 41 42 + 43 + 44 + 45 + 46 + 47 48 49 50 + 51 52 53 |
PenaltyWeightedGapUserObject::validParams() { InputParameters params = WeightedGapUserObject::validParams(); params.set<bool>("allow_nodal_normal_derivatives") = true; params.set<bool>("use_nodal_normal_derivatives") = true; params.suppressParameter<bool>("ghost_point_neighbors"); // Penalty contact has no LM constraint to contribute the nodal-normal one-ring to the matrix // graph, so its weighted-gap object supplies the coupling relationship manager directly. const auto configure_one_ring = [](const InputParameters & obj_params, InputParameters & rm_params) { rm_params.set<bool>("use_displaced_mesh") = obj_params.get<bool>("use_displaced_mesh"); rm_params.set<BoundaryName>("secondary_boundary") = obj_params.get<BoundaryName>("secondary_boundary"); rm_params.set<BoundaryName>("primary_boundary") = obj_params.get<BoundaryName>("primary_boundary"); rm_params.set<SubdomainName>("secondary_subdomain") = obj_params.get<SubdomainName>("secondary_subdomain"); rm_params.set<SubdomainName>("primary_subdomain") = obj_params.get<SubdomainName>("primary_subdomain"); // penetration_tolerance is required exactly for augmented-Lagrange contact, which uses // frozen-normal geometry. rm_params.set<bool>("ghost_point_neighbors") = obj_params.get<bool>("use_nodal_normal_derivatives") && !obj_params.isParamValid("penetration_tolerance"); }; params.addRelationshipManager("AugmentSparsityOnInterface", Moose::RelationshipManagerType::GEOMETRIC | Moose::RelationshipManagerType::ALGEBRAIC, configure_one_ring); params.addRelationshipManager( "AugmentSparsityOnInterface", Moose::RelationshipManagerType::COUPLING, configure_one_ring); params.addClassDescription("Computes the mortar normal contact force via a penalty approach."); params.addRequiredParam<Real>("penalty", "The penalty factor"); |
31 32 33 34 + 35 + 36 37 38 |
params.addCoupledVar("disp_z", "The z displacement variable"); params.set<bool>("use_displaced_mesh") = true; params.set<bool>("interpolate_normals") = false; params.addPrivateParam<bool>("allow_nodal_normal_derivatives", false); params.addPrivateParam<bool>("use_nodal_normal_derivatives", false); params.set<ExecFlagEnum>("execute_on") = {EXEC_LINEAR, EXEC_NONLINEAR}; params.suppressParameter<ExecFlagEnum>("execute_on"); return params; |
52 53 54 55 + 56 + 57 + 58 59 60 |
_primary_disp_y(_disp_y_var->adSlnNeighbor()), _secondary_disp_z(_has_disp_z ? &_disp_z_var->adSln() : nullptr), _primary_disp_z(_has_disp_z ? &_disp_z_var->adSlnNeighbor() : nullptr), _coord(_assembly.mortarCoordTransformation()), _allow_nodal_normal_derivatives(getParam<bool>("allow_nodal_normal_derivatives")), _use_nodal_normal_derivatives(false) { if (!getParam<bool>("use_displaced_mesh")) paramError("use_displaced_mesh", |
62 63 64 65 + 66 + 67 + 68 69 70 + 71 72 + 73 + 74 75 + 76 + 77 78 + 79 + 80 81 82 83 84 85 + 86 + 87 88 + 89 + 90 91 + 92 + 93 94 95 96 97 + 98 99 100 101 + 102 103 + 104 105 106 |
// A valid penetration_tolerance identifies augmented-Lagrange contact, which retains frozen // normal directions. if (getParam<bool>("use_nodal_normal_derivatives") && !isParamValid("penetration_tolerance")) includeNodalNormalDerivatives(); } void WeightedGapUserObject::includeNodalNormalDerivatives() const { if (_use_nodal_normal_derivatives) return; if (!_allow_nodal_normal_derivatives) mooseError("Nodal-normal derivatives are not supported by user object '", name(), "'."); if (getParam<bool>("interpolate_normals")) paramError("interpolate_normals", "Nodal-normal derivatives require normalized secondary nodal normals and cannot be " "combined with quadrature-point normal interpolation."); const std::array<std::pair<const MooseVariable *, const char *>, 3> displacement_variables{ {{_disp_x_var, "disp_x"}, {_disp_y_var, "disp_y"}, {_disp_z_var, "disp_z"}}}; for (const auto & [variable, parameter_name] : displacement_variables) if (variable) { if (!variable->isNodal()) paramError(parameter_name, "Nodal-normal derivatives require a nodal displacement variable."); if (&variable->sys() != &_sys) paramError(parameter_name, "Nodal-normal derivatives require displacement variables in the nonlinear " "system assembled by this contact object."); } _use_nodal_normal_derivatives = true; } bool WeightedGapUserObject::usesNodalNormalDerivatives() const { return _use_nodal_normal_derivatives && Moose::doDerivatives(_subproblem, _sys); } void |
168 169 170 171 + 172 173 174 |
void WeightedGapUserObject::computeQpIProperties() { if (usesNodalNormalDerivatives()) mooseAssert(_lower_secondary_elem->n_nodes() > _i, "Making sure that the nodal normal index is valid"); else |
179 180 181 182 + 183 + 184 185 + 186 187 188 |
auto & [weighted_gap, normalization] = _dof_to_weighted_gap[dof]; if (usesNodalNormalDerivatives()) weighted_gap += (*_test)[_i][_qp] * _qp_gap_nodal * contactNormal(*_lower_secondary_elem, _i); else weighted_gap += (*_test)[_i][_qp] * _qp_gap_nodal * _normals[_i]; normalization += (*_test)[_i][_qp] * _qp_factor; |
190 191 192 193 + 194 195 196 |
} const ADRealVectorValue & WeightedGapUserObject::contactNormal(const Elem & lower_secondary_elem, const unsigned int nodal_index) const { mooseAssert(nodal_index < lower_secondary_elem.n_nodes(), |
198 199 200 201 + 202 203 + 204 + 205 206 + 207 208 + 209 + 210 + 211 212 213 214 + 215 216 217 218 219 + 220 221 222 223 + 224 + 225 226 + 227 228 + 229 + 230 + 231 232 233 + 234 235 236 |
mooseAssert(usesNodalNormalDerivatives(), "AD contact normals should only be requested while recording nodal-normal " "derivatives."); const Node * const node = lower_secondary_elem.node_ptr(nodal_index); const auto normal_it = _ad_nodal_normals.find(node); if (normal_it != _ad_nodal_normals.end()) return normal_it->second; amg().computeADNodalNormals( [this](const Node & coordinate_node, const Point & geometry_coordinate) { return nodalCoordinate(coordinate_node, geometry_coordinate); }, _ad_nodal_normals); return libmesh_map_find(_ad_nodal_normals, node); } ADPoint WeightedGapUserObject::nodalCoordinate(const Node & node, const Point & geometry_coordinate) const { mooseAssert(usesNodalNormalDerivatives(), "AD nodal coordinates should only be requested while recording nodal-normal " "derivatives."); ADPoint point = geometry_coordinate; const std::array<std::pair<const MooseVariable *, unsigned int>, 3> displacement_variables{ {{_disp_x_var, 0}, {_disp_y_var, 1}, {_disp_z_var, 2}}}; for (const auto & [variable, component] : displacement_variables) if (variable) { const auto sys_num = variable->sys().number(); const auto var_num = variable->number(); if (node.n_dofs(sys_num, var_num)) Moose::derivInsert( point(component).derivatives(), node.dof_number(sys_num, var_num, 0), 1.0); } return point; } void |
55 56 57 58 + 59 60 61 |
} std::array<ADRealVectorValue, 2> WeightedVelocitiesUserObject::contactTangents(const Elem & lower_secondary_elem, const unsigned int nodal_index) const { mooseAssert(nodal_index < lower_secondary_elem.n_nodes(), |
63 64 65 66 + 67 68 69 |
mooseAssert(usesNodalNormalDerivatives(), "AD contact tangents should only be requested while recording nodal-normal " "derivatives."); return Moose::Mortar::householderTangents(contactNormal(lower_secondary_elem, nodal_index)); } void |
122 123 124 125 + 126 127 + 128 + 129 130 131 + 132 133 + 134 135 136 137 138 + 139 140 141 + 142 143 + 144 145 146 + 147 148 149 + 150 151 152 + 153 154 155 |
_is_weighted_gap_nodal ? static_cast<const DofObject *>(_lower_secondary_elem->node_ptr(_i)) : static_cast<const DofObject *>(_lower_secondary_elem); if (usesNodalNormalDerivatives()) { const auto tangents = contactTangents(*_lower_secondary_elem, _i); for (const auto direction : make_range(_3d ? 2 : 1)) { _dof_to_weighted_tangential_velocity[dof][direction] += (*_test)[_i][_qp] * _qp_tangential_velocity_nodal * tangents[direction]; _dof_to_real_tangential_velocity[dof][direction] += (*_test)[_i][_qp] * _qp_real_tangential_velocity_nodal * tangents[direction]; } } else { const auto & nodal_tangents = amg().getNodalTangents(*_lower_secondary_elem); _dof_to_weighted_tangential_velocity[dof][0] += (*_test)[_i][_qp] * _qp_tangential_velocity_nodal * nodal_tangents[0][_i]; _dof_to_real_tangential_velocity[dof][0] += (*_test)[_i][_qp] * _qp_real_tangential_velocity_nodal * nodal_tangents[0][_i]; // Get the _dof_to_weighted_tangential_velocity map for a second direction if (_3d) { _dof_to_weighted_tangential_velocity[dof][1] += (*_test)[_i][_qp] * _qp_tangential_velocity_nodal * nodal_tangents[1][_i]; _dof_to_real_tangential_velocity[dof][1] += (*_test)[_i][_qp] * _qp_real_tangential_velocity_nodal * nodal_tangents[1][_i]; } } } |