27 #include <unordered_map> 30 #include "libmesh/petsc_nonlinear_solver.h" 31 #include "libmesh/string_to_enum.h" 34 #if NANOFLANN_VERSION < 0x150 39 template <
typename T,
typename U>
78 params.
addParam<std::vector<BoundaryName>>(
79 "primary",
"The list of boundary IDs referring to primary sidesets");
80 params.
addParam<std::vector<BoundaryName>>(
81 "secondary",
"The list of boundary IDs referring to secondary sidesets");
82 params.
addParam<std::vector<BoundaryName>>(
83 "automatic_pairing_boundaries",
85 "List of boundary IDs for sidesets that are automatically paired with any other boundary in " 86 "this list having a centroid-to-centroid distance less than the value specified in the " 87 "'automatic_pairing_distance' parameter. ");
89 "automatic_pairing_distance",
90 "automatic_pairing_distance>=0",
91 "The maximum distance the centroids of the boundaries provided in the " 92 "'automatic_pairing_boundaries' parameter can be to generate a contact pair automatically. " 93 "Due to numerical error in the determination of the centroids, it is encouraged that " 94 "the user adds a tolerance to this distance (e.g. extra 10%) to make sure no suitable " 95 "contact pair is missed. If the 'automatic_pairing_method = NODE' option is chosen instead, " 96 "this distance is recommended to be set to at least twice the minimum distance between " 97 "nodes of boundaries to be paired.");
100 "The mesh generator for mortar method",
101 "This parameter is not used anymore and can simply be removed");
102 params.
addParam<VariableName>(
"secondary_gap_offset",
103 "Offset to gap distance from secondary side");
104 params.
addParam<VariableName>(
"mapped_primary_gap_offset",
105 "Offset to gap distance mapped from primary side");
106 params.
addParam<std::vector<VariableName>>(
109 "The displacements appropriate for the simulation geometry and coordinate system");
113 "The penalty to apply. This can vary depending on the stiffness of your materials");
117 "The penalty factor to apply in mortar penalty frictional constraints. It is applied to the " 118 "tangential accumulated slip to build the frictional force");
120 "penalty_multiplier",
122 "penalty_multiplier > 0",
123 "The growth factor for the penalty applied at the end of each augmented " 124 "Lagrange update iteration (a value larger than one, e.g., 10, tends to speed up " 127 "penalty_multiplier_friction",
129 "penalty_multiplier_friction > 0",
130 "The penalty growth factor between augmented Lagrange " 131 "iterations for penalizing relative slip distance if the node is under stick conditions.(a " 132 "value larger than one, e.g., 10, tends to speed up convergence.)");
133 params.
addParam<
Real>(
"friction_coefficient", 0,
"The friction coefficient");
136 "Tension release threshold. A node in contact " 137 "will not be released if its tensile load is below " 138 "this value. No tension release if negative.");
141 "Tangential distance to extend edges of contact surfaces");
144 "Normal distance from surface within which nodes are captured. This " 145 "parameter is used for node-face and mortar formulations.");
147 "normal_smoothing_distance",
148 "Distance from edge in parametric coordinates over which to smooth contact normal");
150 params.
addParam<
bool>(
"normalize_penalty",
152 "Whether to normalize the penalty parameter with the nodal area.");
154 "primary_secondary_jacobian",
156 "Whether to include Jacobian entries coupling primary and secondary nodes.");
158 "ghost_whole_interface",
160 "Whether to geometrically and algebraically ghost the entire primary side of the interface " 161 "for node-face contact constraints.");
163 "The tolerance of the penetration for augmented Lagrangian method.");
165 "The tolerance of the incremental slip for augmented Lagrangian method.");
167 "max_penalty_multiplier",
169 "max_penalty_multiplier >= 1.0",
170 "Maximum multiplier applied to penalty factors when adaptivity is used in an augmented " 171 "Lagrange setting. The penalty factor supplied by the user is used as a reference to " 172 "determine its maximum. If this multiplier is too large, the condition number of the system " 173 "to be solved may be negatively impacted.");
174 MooseEnum adaptivity_penalty_normal(
"SIMPLE BUSSETTA",
"SIMPLE");
175 adaptivity_penalty_normal.addDocumentation(
176 "SIMPLE",
"Keep multiplying by the penalty multiplier between AL iterations");
177 adaptivity_penalty_normal.addDocumentation(
179 "Modify the penalty using an algorithm from Bussetta et al, 2012, Comput Mech 49:259-275 " 180 "between AL iterations.");
182 "adaptivity_penalty_normal",
183 adaptivity_penalty_normal,
184 "The augmented Lagrange update strategy used on the normal penalty coefficient.");
185 MooseEnum adaptivity_penalty_friction(
"SIMPLE FRICTION_LIMIT",
"FRICTION_LIMIT");
186 adaptivity_penalty_friction.addDocumentation(
187 "SIMPLE",
"Keep multiplying by the frictional penalty multiplier between AL iterations");
188 adaptivity_penalty_friction.addDocumentation(
190 "This strategy will be guided by the Coulomb limit and be less reliant on the initial " 191 "penalty factor provided by the user.");
193 "adaptivity_penalty_friction",
194 adaptivity_penalty_friction,
195 "The augmented Lagrange update strategy used on the frictional penalty coefficient.");
197 "The tolerance of the frictional force for augmented Lagrangian method.");
201 "Parameter for balancing the size of the gap and contact pressure for a mortar formulation. " 202 "This purely numerical " 203 "parameter affects convergence behavior and, in general, should be larger for stiffer " 204 "materials. It is recommended that the user tries out various orders of magnitude for this " 205 "parameter if the default value generates poor contact convergence.");
207 "c_tangential", 1,
"Numerical parameter for nonlinear mortar frictional constraints");
208 params.
addParam<
bool>(
"ping_pong_protection",
210 "Whether to protect against ping-ponging, e.g. the oscillation of the " 211 "secondary node between two " 212 "different primary faces, by tying the secondary node to the " 213 "edge between the involved primary faces");
217 "Scaling factor to apply to the normal LM variable for a mortar formulation");
219 "tangential_lm_scaling",
221 "Scaling factor to apply to the tangential LM variable for a mortar formulation");
222 MooseEnum lm_space(getContactLMSpaceOptions(),
"MATCH_DISPLACEMENT");
223 lm_space.addDocumentation(
224 "MATCH_DISPLACEMENT",
225 "Use the same finite element order as the displacement variables for generated mortar " 226 "Lagrange multiplier variables.");
227 lm_space.addDocumentation(
229 "Use first-order LAGRANGE generated mortar Lagrange multiplier variables, independent " 230 "of the displacement variable order.");
234 "Finite element space for mortar Lagrange multiplier variables generated by the " 235 "contact action. This parameter only applies to the 'mortar' contact formulation.");
239 "Whether to normalize c by weighting function norm for mortar contact. When unnormalized " 240 "the value of c effectively depends on element size since in the constraint we compare nodal " 241 "Lagrange Multiplier values to integrated gap values (LM nodal value is independent of " 242 "element size, where integrated values are dependent on element size).");
243 params.
addClassDescription(
"Sets up all objects needed for mechanical contact enforcement");
246 "Whether to use the dual mortar approach within a mortar formulation. It is defaulted to " 248 "weighted quantity approach, and to false for the legacy approach. To avoid instabilities " 249 "in the solution and obtain the full benefits of a variational enforcement," 250 "use of dual mortar with weighted constraints is strongly recommended. This " 251 "input is only intended for advanced users.");
253 "correct_edge_dropping",
255 "Whether to enable correct edge dropping treatment for mortar constraints. When disabled " 256 "any Lagrange Multiplier degree of freedom on a secondary element without full primary " 257 "contributions will be set (strongly) to 0.");
259 params.addParam<
bool>(
260 "generate_mortar_mesh",
262 "Whether to generate the mortar mesh from the action. Typically this will be the case, but " 263 "one may also want to reuse an existing lower-dimensional mesh prior to a restart.");
264 params.addParam<
MooseEnum>(
"automatic_pairing_method",
266 "The proximity method used for automatic pairing of boundaries.");
267 params.addParam<
bool>(
270 "Whether to use constraints that account for the persistency condition, giving rise to " 271 "smoother normal contact pressure evolution. This flag should only be set to yes for dynamic " 272 "simulations using the Newmark-beta numerical integrator");
273 params.addParam<
Real>(
276 "Newmark-beta beta parameter for its inclusion in the weighted gap update formula");
277 params.addParam<
Real>(
280 "Newmark-beta gamma parameter for its inclusion in the weighted gap update formula");
281 params.addCoupledVar(
"wear_depth",
282 "The name of the mortar auxiliary variable that is used to modify the " 283 "weighted gap definition");
284 params.addParam<std::vector<TagName>>(
286 "The tag names for extra vectors that residual data should be saved into");
287 params.addParam<std::vector<TagName>>(
288 "absolute_value_vector_tags",
289 "The tags for the vectors this residual object should fill with the " 290 "absolute value of the residual contribution");
291 params.addParam<
bool>(
292 "use_petrov_galerkin",
294 "Whether to use the Petrov-Galerkin approach for the mortar-based constraints. If set to " 295 "true, we use the standard basis as the test function and dual basis as " 296 "the shape function for the interpolation of the Lagrange multiplier variable.");
297 params.addParam<
bool>(
300 "Whether we are going to enable mortar segment mesh debug information. An exodus" 301 "file will be generated if the user sets this flag to true");
305 params.addParamNamesToGroup(
"primary secondary displacements",
"Contact Surface Definition");
307 params.addParamNamesToGroup(
308 "automatic_pairing_boundaries automatic_pairing_distance automatic_pairing_method",
309 "Automatic Contact Pair Generation");
311 params.addParamNamesToGroup(
"formulation model",
"Contact Formulation");
313 params.addParamNamesToGroup(
314 "penalty penalty_friction penalty_multiplier penalty_multiplier_friction " 315 "max_penalty_multiplier normalize_penalty",
316 "Penalty Parameters");
318 params.addParamNamesToGroup(
319 "al_penetration_tolerance al_incremental_slip_tolerance al_frictional_force_tolerance " 320 "adaptivity_penalty_normal adaptivity_penalty_friction",
321 "Augmented Lagrange");
323 params.addParamNamesToGroup(
"friction_coefficient tension_release",
"Friction");
325 params.addParamNamesToGroup(
"c_normal c_tangential normal_lm_scaling tangential_lm_scaling " 327 "use_dual correct_edge_dropping normalize_c use_petrov_galerkin " 328 "generate_mortar_mesh segment_quadrature wear_depth debug_mesh",
331 params.addParamNamesToGroup(
"mortar_dynamics newmark_beta newmark_gamma",
"Mortar Dynamics");
333 params.addParamNamesToGroup(
334 "secondary_gap_offset mapped_primary_gap_offset capture_tolerance " 335 "tangential_tolerance normal_smoothing_distance normal_smoothing_method",
336 "Gap and Tolerance");
338 params.addParamNamesToGroup(
"primary_secondary_jacobian ping_pong_protection",
"Solver Options");
340 params.addParamNamesToGroup(
"ghost_whole_interface",
"Interface Ghosting");
342 params.addParamNamesToGroup(
"extra_vector_tags absolute_value_vector_tags",
"Residual Tags");
349 _boundary_pairs(getParam<BoundaryName, BoundaryName>(
"primary",
"secondary")),
350 _model(getParam<
MooseEnum>(
"model").getEnum<ContactModel>()),
351 _formulation(getParam<
MooseEnum>(
"formulation").getEnum<ContactFormulation>()),
352 _lm_space(getParam<
MooseEnum>(
"lm_space").getEnum<ContactLMSpace>()),
353 _generate_mortar_mesh(getParam<bool>(
"generate_mortar_mesh")),
354 _mortar_dynamics(getParam<bool>(
"mortar_dynamics"))
357 if (
getParam<std::vector<BoundaryName>>(
"automatic_pairing_boundaries").size() > 1)
359 getParam<std::vector<BoundaryName>>(
"automatic_pairing_boundaries");
363 "For automatic selection of contact pairs (for particular geometries) in contact " 364 "action, 'automatic_pairing_distance' needs to be provided.");
368 "For automatic selection of contact pairs (for particular geometries) in contact " 369 "action, 'automatic_pairing_method' needs to be provided.");
373 "If a boundary list is provided, primary and secondary surfaces will be identified " 374 "automatically. Therefore, one cannot provide an automatic pairing boundary list " 375 "and primary/secondary lists.");
378 "'primary' and 'secondary' surfaces or a list of boundaries for automatic pair " 379 "generation need to be provided.");
384 paramError(
"formulation",
"When using mortar, a vector of contact pairs cannot be used");
390 "The 'ghost_whole_interface' parameter is only supported for node-face contact " 391 "formulations. Mortar contact always geometrically and algebraically ghosts the " 394 if (
_formulation == ContactFormulation::TANGENTIAL_PENALTY &&
_model != ContactModel::COULOMB)
396 "The 'tangential_penalty' formulation can only be used with the 'coulomb' model");
406 if (
_model == ContactModel::GLUED)
407 paramError(
"model",
"The 'mortar_penalty' formulation does not support glued contact");
409 if (getParam<bool>(
"mortar_dynamics"))
411 "The 'mortar_penalty' formulation does not support implicit dynamic simulations");
413 if (getParam<bool>(
"use_petrov_galerkin"))
415 "The 'mortar_penalty' formulation does not support usage of the Petrov-Galerkin " 416 "flag. The default (use_dual = true) behavior is such that contact tractions are " 417 "interpolated with dual bases whereas mortar or weighted contact quantities are " 418 "interpolated with Lagrange shape functions.");
423 if (
_model == ContactModel::GLUED)
424 paramError(
"model",
"The 'mortar' formulation does not support glued contact (yet)");
432 if (!getParam<bool>(
"mortar_dynamics"))
435 paramError(
"newmark_beta",
"newmark_beta can only be used with the mortar_dynamics option");
439 "newmark_gamma can only be used with the mortar_dynamics option");
444 "The 'penalty' parameter is not used for the 'mortar' formulation which instead " 445 "uses Lagrange multipliers");
451 "correct_edge_dropping",
452 "The 'correct_edge_dropping' option can only be used with the 'mortar' formulation " 457 "The 'triangulation' option can only be used with mortar-based formulations.");
461 "The 'triangulate_triangles' option can only be used with mortar-based " 466 "The 'use_dual' option can only be used with the 'mortar' formulation");
469 "The 'c_normal' option can only be used with the 'mortar' formulation");
472 "The 'c_tangential' option can only be used with the 'mortar' formulation");
475 "The 'mortar_dynamics' constraint option can only be used with the 'mortar' " 476 "formulation and in dynamic simulations using Newmark-beta");
479 "The 'segment_quadrature' option can only be used with the " 480 "'mortar' formulation.");
483 "The 'lm_space' option can only be used with the 'mortar' formulation.");
490 "The 'secondary_gap_offset' option can only be used with the " 491 "'MechanicalContactConstraint'");
494 "The 'mapped_primary_gap_offset' option can only be used with the " 495 "'MechanicalContactConstraint'");
497 else if (getParam<bool>(
"ping_pong_protection"))
499 "The 'ping_pong_protection' option can only be used with the 'ranfs' formulation");
511 "Number of contact pairs in the contact action is zero. Please revise your input file.");
514 std::vector<std::pair<BoundaryName, BoundaryName>> lean_boundary_pairs;
519 auto it = std::find_if(lean_boundary_pairs.begin(),
520 lean_boundary_pairs.end(),
521 [&, primary_copy = primary, secondary_copy = secondary](
522 const std::pair<BoundaryName, BoundaryName> & lean_pair)
524 const bool match_one = lean_pair.second == secondary_copy &&
525 lean_pair.first == primary_copy;
526 const bool match_two = lean_pair.second == primary_copy &&
527 lean_pair.first == secondary_copy;
528 const bool exist = match_one || match_two;
532 if (it == lean_boundary_pairs.end())
533 lean_boundary_pairs.emplace_back(primary, secondary);
539 " has been removed from the contact interaction list due to " 540 "duplicates in the input file.");
552 if (!
_problem->getDisplacedProblem())
554 "Contact requires updated coordinates. Use the 'displacements = ...' parameter in the " 561 if (!
_problem->isSNESMFReuseBaseSetbyUser())
562 _problem->setSNESMFReuseBase(
false,
false);
573 if (!
_problem->getDisplacedProblem())
574 mooseError(
"Contact requires updated coordinates. Use the 'displacements = ...' line in the " 580 const auto & [primary_name, secondary_name] = contact_pair;
586 {
"secondary_gap_offset",
"mapped_primary_gap_offset",
"order"});
588 std::vector<VariableName> displacements =
589 getParam<std::vector<VariableName>>(
"displacements");
590 const auto order =
_problem->systemBaseNonlinear(0)
592 .variable_type(displacements[0])
595 params.
set<
MooseEnum>(
"order") = Utility::enum_to_string<Order>(OrderWrapper{order});
597 params.
set<std::vector<BoundaryName>>(
"boundary") = {secondary_name};
598 params.
set<BoundaryName>(
"paired_boundary") = primary_name;
599 params.
set<AuxVariableName>(
"variable") =
"penetration";
601 params.
set<std::vector<VariableName>>(
"secondary_gap_offset") = {
602 getParam<VariableName>(
"secondary_gap_offset")};
604 params.
set<std::vector<VariableName>>(
"mapped_primary_gap_offset") = {
605 getParam<VariableName>(
"mapped_primary_gap_offset")};
606 params.
set<
bool>(
"use_displaced_mesh") =
true;
613 const auto type =
"MortarUserObjectAux";
615 params.
set<std::vector<BoundaryName>>(
"boundary") = {secondary_name};
616 params.
set<AuxVariableName>(
"variable") =
"gap";
617 params.
set<
bool>(
"use_displaced_mesh") =
true;
619 params.
set<
MooseEnum>(
"contact_quantity") =
"normal_gap";
620 const auto & [primary_id, secondary_id, uo_name] =
622 params.
set<UserObjectName>(
"user_object") = uo_name;
623 std::string
name =
_name +
"_contact_gap_" + std::to_string(primary_id) +
"_" +
624 std::to_string(secondary_id);
632 const unsigned int ndisp = getParam<std::vector<VariableName>>(
"displacements").size();
635 if (
_formulation == ContactFormulation::MORTAR &&
_model == ContactModel::COULOMB && ndisp > 2)
646 const std::string tangential_lagrange_multiplier_name = action_name +
"_tangential_lm";
647 const std::string tangential_lagrange_multiplier_3d_name =
648 action_name +
"_tangential_3d_lm";
650 params.
set<std::vector<VariableName>>(
"tangent_one") = {
651 tangential_lagrange_multiplier_name};
652 params.
set<std::vector<VariableName>>(
"tangent_two") = {
653 tangential_lagrange_multiplier_3d_name};
655 std::vector<std::string> disp_components({
"x",
"y",
"z"});
656 unsigned component_index = 0;
659 for (
const auto & disp_component : disp_components)
661 params.
set<AuxVariableName>(
"variable") =
_name +
"_tangent_" + disp_component;
662 params.
set<
unsigned int>(
"component") = component_index;
664 std::string
name =
_name +
"_mortar_frictional_pressure_" + disp_component +
"_" +
667 _problem->addAuxKernel(
"MortarFrictionalPressureVectorAux",
name, params);
676 std::vector<VariableName> displacements = getParam<std::vector<VariableName>>(
"displacements");
677 const auto order =
_problem->systemBaseNonlinear(0)
679 .variable_type(displacements[0])
681 const auto mortar_lm_order =
682 _lm_space == ContactLMSpace::LINEAR ?
static_cast<int>(
FIRST) : order;
683 std::unique_ptr<InputParameters> current_params;
684 const auto create_aux_var_params =
691 const auto aux_order =
_formulation == ContactFormulation::MORTAR ? mortar_lm_order : order;
692 current_params->set<
MooseEnum>(
"order") =
693 Utility::enum_to_string<Order>(OrderWrapper{aux_order});
694 current_params->set<
MooseEnum>(
"family") =
"LAGRANGE";
695 return *current_params;
702 _problem->addAuxVariable(
"MooseVariable",
"penetration", create_aux_var_params());
704 _problem->addAuxVariable(
"MooseVariable",
"nodal_area", create_aux_var_params());
707 _problem->addAuxVariable(
"MooseVariable",
"gap", create_aux_var_params());
710 _problem->addAuxVariable(
"MooseVariable",
"contact_pressure", create_aux_var_params());
712 const unsigned int ndisp = getParam<std::vector<VariableName>>(
"displacements").size();
715 if (
_formulation == ContactFormulation::MORTAR &&
_model == ContactModel::COULOMB && ndisp > 2)
718 std::vector<std::string> disp_components({
"x",
"y",
"z"});
720 for (
const auto & disp_component : disp_components)
724 Utility::enum_to_string<Order>(OrderWrapper{mortar_lm_order});
725 var_params.set<
MooseEnum>(
"family") =
"LAGRANGE";
728 "MooseVariable",
_name +
"_tangent_" + disp_component, var_params);
743 std::vector<BoundaryName> secondary_boundary_vector;
744 for (
const auto *
const action : actions)
745 for (
const auto j :
index_range(action->_boundary_pairs))
746 secondary_boundary_vector.push_back(action->_boundary_pairs[
j].second);
748 var_params.set<std::vector<BoundaryName>>(
"boundary") = secondary_boundary_vector;
749 var_params.set<std::vector<VariableName>>(
"variable") = {
"nodal_area"};
751 mooseAssert(
_problem,
"Problem pointer is NULL");
753 var_params.set<
bool>(
"use_displaced_mesh") =
true;
755 _problem->addUserObject(
"NodalArea",
776 std::vector<BoundaryName> boundary_vector;
777 std::vector<BoundaryName> pair_boundary_vector;
779 for (
const auto *
const action : actions)
780 for (
const auto j :
index_range(action->_boundary_pairs))
782 boundary_vector.push_back(action->_boundary_pairs[
j].second);
783 pair_boundary_vector.push_back(action->_boundary_pairs[
j].first);
789 std::vector<VariableName> displacements =
790 getParam<std::vector<VariableName>>(
"displacements");
791 const auto order =
_problem->systemBaseNonlinear(0)
793 .variable_type(displacements[0])
796 params.
set<
MooseEnum>(
"order") = Utility::enum_to_string<Order>(OrderWrapper{order});
797 params.
set<std::vector<BoundaryName>>(
"boundary") = boundary_vector;
798 params.
set<std::vector<BoundaryName>>(
"paired_boundary") = pair_boundary_vector;
799 params.
set<AuxVariableName>(
"variable") =
"contact_pressure";
801 params.
set<std::vector<VariableName>>(
"nodal_area") = {
"nodal_area"};
802 params.
set<
bool>(
"use_displaced_mesh") =
true;
804 std::string
name =
_name +
"_contact_pressure";
807 _problem->addAuxKernel(
"ContactPressureAux",
name, params);
813 const auto & [_, secondary_name] = contact_pair;
814 const auto type =
"MortarUserObjectAux";
816 params.
set<std::vector<BoundaryName>>(
"boundary") = {secondary_name};
817 params.
set<AuxVariableName>(
"variable") =
"contact_pressure";
818 params.
set<
bool>(
"use_displaced_mesh") =
true;
820 params.
set<
MooseEnum>(
"contact_quantity") =
"normal_pressure";
821 const auto & [primary_id, secondary_id, uo_name] =
823 params.
set<UserObjectName>(
"user_object") = uo_name;
824 const std::string
name =
_name +
"_contact_pressure" + std::to_string(primary_id) +
"_" +
825 std::to_string(secondary_id);
838 params.set<
bool>(
"use_displaced_mesh") =
true;
840 const std::string primary_subdomain_name = action_name +
"_primary_subdomain";
841 const std::string secondary_subdomain_name = action_name +
"_secondary_subdomain";
842 params.set<BoundaryName>(
"primary_boundary") =
_boundary_pairs[0].first;
843 params.set<BoundaryName>(
"secondary_boundary") =
_boundary_pairs[0].second;
844 params.set<SubdomainName>(
"primary_subdomain") = primary_subdomain_name;
845 params.set<SubdomainName>(
"secondary_subdomain") = secondary_subdomain_name;
846 params.set<
bool>(
"use_petrov_galerkin") = getParam<bool>(
"use_petrov_galerkin");
851 const std::string constraint_type =
_formulation == ContactFormulation::RANFS
852 ?
"RANFSNormalMechanicalContact" 853 :
"MechanicalContactConstraint";
858 params.
set<
bool>(
"use_displaced_mesh") =
true;
859 params.set<
bool>(
"ghost_whole_interface") = getParam<bool>(
"ghost_whole_interface");
860 params.set<BoundaryName>(
"primary") = contact_pair.first;
861 params.set<BoundaryName>(
"secondary") = contact_pair.second;
872 std::vector<VariableName> displacements = getParam<std::vector<VariableName>>(
"displacements");
873 const unsigned int ndisp = displacements.size();
876 const std::string primary_subdomain_name = action_name +
"_primary_subdomain";
877 const std::string secondary_subdomain_name = action_name +
"_secondary_subdomain";
878 const std::string normal_lagrange_multiplier_name = action_name +
"_normal_lm";
879 const std::string tangential_lagrange_multiplier_name = action_name +
"_tangential_lm";
880 const std::string tangential_lagrange_multiplier_3d_name = action_name +
"_tangential_3d_lm";
881 const std::string auxiliary_lagrange_multiplier_name = action_name +
"_aux_lm";
891 const MeshGeneratorName primary_name = primary_subdomain_name +
"_generator";
892 const MeshGeneratorName secondary_name = secondary_subdomain_name +
"_generator";
897 primary_params.
set<SubdomainName>(
"new_block_name") = primary_subdomain_name;
898 secondary_params.set<SubdomainName>(
"new_block_name") = secondary_subdomain_name;
900 primary_params.set<std::vector<BoundaryName>>(
"sidesets") = {
_boundary_pairs[0].first};
901 secondary_params.set<std::vector<BoundaryName>>(
"sidesets") = {
_boundary_pairs[0].second};
909 const auto addLagrangeMultiplier =
910 [
this, &secondary_subdomain_name, &displacements](
const std::string & variable_name,
911 const Real scaling_factor,
912 const bool add_aux_lm,
913 const bool penalty_traction)
920 if (!add_aux_lm || penalty_traction)
923 mooseAssert(
_problem->systemBaseNonlinear(0).hasVariable(displacements[0]),
924 "Displacement variable is missing");
925 const auto primal_type =
926 _problem->systemBaseNonlinear(0).system().variable_type(displacements[0]);
932 ?
static_cast<int>(
FIRST)
933 : primal_type.order.get_order();
937 params.
set<
MooseEnum>(
"family") = Utility::enum_to_string<FEFamily>(primal_type.family);
938 params.
set<
MooseEnum>(
"order") = Utility::enum_to_string<Order>(OrderWrapper{lm_order});
941 mooseError(
"Invalid bases for mortar contact.");
943 params.
set<std::vector<SubdomainName>>(
"block") = {secondary_subdomain_name};
944 if (!(add_aux_lm || penalty_traction))
945 params.
set<std::vector<Real>>(
"scaling") = {scaling_factor};
949 if (add_aux_lm || penalty_traction)
950 _problem->addAuxVariable(var_type, variable_name, params);
952 _problem->addVariable(var_type, variable_name, params);
957 addLagrangeMultiplier(
958 normal_lagrange_multiplier_name, getParam<Real>(
"normal_lm_scaling"),
false,
false);
960 if (
_model == ContactModel::COULOMB)
962 addLagrangeMultiplier(tangential_lagrange_multiplier_name,
963 getParam<Real>(
"tangential_lm_scaling"),
967 addLagrangeMultiplier(tangential_lagrange_multiplier_3d_name,
968 getParam<Real>(
"tangential_lm_scaling"),
973 if (getParam<bool>(
"use_petrov_galerkin"))
974 addLagrangeMultiplier(auxiliary_lagrange_multiplier_name, 1.0,
true,
false);
980 addLagrangeMultiplier(auxiliary_lagrange_multiplier_name, 1.0,
false,
true);
985 const auto register_mortar_uo_name = [
this](
const auto & bnd_pair,
const auto & uo_prefix)
987 const auto & [primary_name, secondary_name] = bnd_pair;
988 const auto primary_id =
_mesh->getBoundaryID(primary_name);
989 const auto secondary_id =
_mesh->getBoundaryID(secondary_name);
990 const auto uo_name = uo_prefix +
name();
996 if (
_formulation == ContactFormulation::MORTAR_PENALTY &&
997 !dynamic_cast<AugmentedLagrangianContactProblemInterface *>(
_problem.get()))
999 const std::vector<std::string> params = {
"penalty_multiplier",
1000 "penalty_multiplier_friction",
1001 "al_penetration_tolerance",
1002 "al_incremental_slip_tolerance",
1003 "al_frictional_force_tolerance"};
1004 for (
const auto & param : params)
1007 "Augmented Lagrange parameter was specified, but the selected problem type " 1008 "does not support Augmented Lagrange iterations.");
1016 uo_params.set<BoundaryName>(
"secondary_boundary") =
_boundary_pairs[0].second;
1017 uo_params.set<SubdomainName>(
"primary_subdomain") = primary_subdomain_name;
1018 uo_params.set<SubdomainName>(
"secondary_subdomain") = secondary_subdomain_name;
1019 uo_params.set<std::vector<VariableName>>(
"disp_x") = {displacements[0]};
1020 uo_params.set<std::vector<VariableName>>(
"disp_y") = {displacements[1]};
1022 uo_params.set<std::vector<VariableName>>(
"disp_z") = {displacements[2]};
1023 uo_params.set<
bool>(
"use_displaced_mesh") =
true;
1024 uo_params.set<std::vector<VariableName>>(
"lm_variable") = {normal_lagrange_multiplier_name};
1025 uo_params.applySpecificParameters(
parameters(),
1026 {
"correct_edge_dropping",
1028 "triangulate_triangles",
1029 "use_petrov_galerkin",
1031 if (getParam<bool>(
"use_petrov_galerkin"))
1032 uo_params.set<std::vector<VariableName>>(
"aux_lm") = {auxiliary_lagrange_multiplier_name};
1034 _problem->addUserObject(
"LMWeightedGapUserObject",
1035 register_mortar_uo_name(
_boundary_pairs[0],
"lm_weightedgap_object_"),
1038 else if (
_model == ContactModel::COULOMB &&
_formulation == ContactFormulation::MORTAR)
1042 uo_params.set<BoundaryName>(
"secondary_boundary") =
_boundary_pairs[0].second;
1043 uo_params.set<SubdomainName>(
"primary_subdomain") = primary_subdomain_name;
1044 uo_params.set<SubdomainName>(
"secondary_subdomain") = secondary_subdomain_name;
1045 uo_params.set<std::vector<VariableName>>(
"disp_x") = {displacements[0]};
1046 uo_params.set<std::vector<VariableName>>(
"disp_y") = {displacements[1]};
1048 uo_params.set<std::vector<VariableName>>(
"disp_z") = {displacements[2]};
1050 uo_params.set<VariableName>(
"secondary_variable") = displacements[0];
1051 uo_params.set<
bool>(
"use_displaced_mesh") =
true;
1052 uo_params.set<std::vector<VariableName>>(
"lm_variable_normal") = {
1053 normal_lagrange_multiplier_name};
1054 uo_params.set<std::vector<VariableName>>(
"lm_variable_tangential_one") = {
1055 tangential_lagrange_multiplier_name};
1057 uo_params.set<std::vector<VariableName>>(
"lm_variable_tangential_two") = {
1058 tangential_lagrange_multiplier_3d_name};
1059 uo_params.applySpecificParameters(
parameters(),
1060 {
"correct_edge_dropping",
1062 "triangulate_triangles",
1063 "use_petrov_galerkin",
1065 if (getParam<bool>(
"use_petrov_galerkin"))
1066 uo_params.set<std::vector<VariableName>>(
"aux_lm") = {auxiliary_lagrange_multiplier_name};
1068 const auto uo_name =
_problem->addUserObject(
1069 "LMWeightedVelocitiesUserObject",
1070 register_mortar_uo_name(
_boundary_pairs[0],
"lm_weightedvelocities_object_"),
1074 if (
_model != ContactModel::COULOMB &&
_formulation == ContactFormulation::MORTAR_PENALTY)
1079 uo_params.set<BoundaryName>(
"secondary_boundary") =
_boundary_pairs[0].second;
1080 uo_params.set<SubdomainName>(
"primary_subdomain") = primary_subdomain_name;
1081 uo_params.set<SubdomainName>(
"secondary_subdomain") = secondary_subdomain_name;
1082 uo_params.set<std::vector<VariableName>>(
"disp_x") = {displacements[0]};
1083 uo_params.set<std::vector<VariableName>>(
"disp_y") = {displacements[1]};
1086 uo_params.applySpecificParameters(
parameters(),
1087 {
"correct_edge_dropping",
1089 "triangulate_triangles",
1092 "max_penalty_multiplier",
1093 "adaptivity_penalty_normal"});
1096 uo_params.set<
Real>(
"penetration_tolerance") = getParam<Real>(
"al_penetration_tolerance");
1098 uo_params.set<
Real>(
"penalty_multiplier") = getParam<Real>(
"penalty_multiplier");
1101 uo_params.set<
bool>(
"use_physical_gap") =
true;
1104 uo_params.set<std::vector<VariableName>>(
"aux_lm") = {auxiliary_lagrange_multiplier_name};
1107 uo_params.set<std::vector<VariableName>>(
"disp_z") = {displacements[2]};
1108 uo_params.set<
bool>(
"use_displaced_mesh") =
true;
1111 "PenaltyWeightedGapUserObject",
1112 register_mortar_uo_name(
_boundary_pairs[0],
"penalty_weightedgap_object_"),
1116 else if (
_model == ContactModel::COULOMB &&
_formulation == ContactFormulation::MORTAR_PENALTY)
1120 uo_params.set<BoundaryName>(
"secondary_boundary") =
_boundary_pairs[0].second;
1121 uo_params.set<SubdomainName>(
"primary_subdomain") = primary_subdomain_name;
1122 uo_params.set<SubdomainName>(
"secondary_subdomain") = secondary_subdomain_name;
1123 uo_params.set<std::vector<VariableName>>(
"disp_x") = {displacements[0]};
1124 uo_params.set<
bool>(
"correct_edge_dropping") = getParam<bool>(
"correct_edge_dropping");
1125 uo_params.set<std::vector<VariableName>>(
"disp_y") = {displacements[1]};
1127 uo_params.set<std::vector<VariableName>>(
"disp_z") = {displacements[2]};
1129 uo_params.set<VariableName>(
"secondary_variable") = displacements[0];
1130 uo_params.set<
bool>(
"use_displaced_mesh") =
true;
1131 uo_params.set<
Real>(
"friction_coefficient") = getParam<Real>(
"friction_coefficient");
1132 uo_params.set<
Real>(
"penalty") = getParam<Real>(
"penalty");
1133 uo_params.set<
Real>(
"penalty_friction") = getParam<Real>(
"penalty_friction");
1136 uo_params.set<
Real>(
"max_penalty_multiplier") = getParam<Real>(
"max_penalty_multiplier");
1137 uo_params.set<
MooseEnum>(
"adaptivity_penalty_normal") =
1138 getParam<MooseEnum>(
"adaptivity_penalty_normal");
1139 uo_params.set<
MooseEnum>(
"adaptivity_penalty_friction") =
1140 getParam<MooseEnum>(
"adaptivity_penalty_friction");
1142 uo_params.set<
Real>(
"penetration_tolerance") = getParam<Real>(
"al_penetration_tolerance");
1144 uo_params.set<
Real>(
"penalty_multiplier") = getParam<Real>(
"penalty_multiplier");
1146 uo_params.set<
Real>(
"penalty_multiplier_friction") =
1147 getParam<Real>(
"penalty_multiplier_friction");
1150 uo_params.set<
Real>(
"slip_tolerance") = getParam<Real>(
"al_incremental_slip_tolerance");
1153 uo_params.set<
bool>(
"use_physical_gap") =
true;
1156 uo_params.set<std::vector<VariableName>>(
"aux_lm") = {auxiliary_lagrange_multiplier_name};
1158 uo_params.applySpecificParameters(
parameters(),
1160 "triangulate_triangles",
1161 "friction_coefficient",
1163 "penalty_friction"});
1166 "PenaltyFrictionUserObject",
1167 register_mortar_uo_name(
_boundary_pairs[0],
"penalty_friction_object_"),
1178 std::string mortar_constraint_name;
1181 mortar_constraint_name =
"ComputeWeightedGapLMMechanicalContact";
1183 mortar_constraint_name =
"ComputeDynamicWeightedGapLMMechanicalContact";
1188 parameters(), {
"newmark_beta",
"newmark_gamma",
"capture_tolerance",
"wear_depth"});
1191 params.
set<UserObjectName>(
"weighted_gap_uo") =
"lm_weightedgap_object_" +
name();
1195 params.
set<SubdomainName>(
"primary_subdomain") = primary_subdomain_name;
1196 params.
set<SubdomainName>(
"secondary_subdomain") = secondary_subdomain_name;
1197 params.
set<NonlinearVariableName>(
"variable") = normal_lagrange_multiplier_name;
1198 params.
set<std::vector<VariableName>>(
"disp_x") = {displacements[0]};
1199 params.
set<
Real>(
"c") = getParam<Real>(
"c_normal");
1202 params.
set<std::vector<VariableName>>(
"disp_y") = {displacements[1]};
1204 params.
set<std::vector<VariableName>>(
"disp_z") = {displacements[2]};
1206 params.
set<
bool>(
"use_displaced_mesh") =
true;
1209 {
"correct_edge_dropping",
1211 "triangulate_triangles",
1213 "extra_vector_tags",
1214 "absolute_value_vector_tags",
1218 mortar_constraint_name, action_name +
"_normal_lm_weighted_gap", params);
1222 else if (
_model == ContactModel::COULOMB &&
_formulation == ContactFormulation::MORTAR)
1224 std::string mortar_constraint_name;
1227 mortar_constraint_name =
"ComputeFrictionalForceLMMechanicalContact";
1229 mortar_constraint_name =
"ComputeDynamicFrictionalForceLMMechanicalContact";
1234 parameters(), {
"newmark_beta",
"newmark_gamma",
"capture_tolerance",
"wear_depth"});
1237 params.
set<UserObjectName>(
"weighted_gap_uo") =
"lm_weightedvelocities_object_" +
name();
1238 params.
set<UserObjectName>(
"weighted_velocities_uo") =
1239 "lm_weightedvelocities_object_" +
name();
1242 params.
set<
bool>(
"correct_edge_dropping") = getParam<bool>(
"correct_edge_dropping");
1245 params.
set<SubdomainName>(
"primary_subdomain") = primary_subdomain_name;
1246 params.
set<SubdomainName>(
"secondary_subdomain") = secondary_subdomain_name;
1247 params.
set<
bool>(
"use_displaced_mesh") =
true;
1248 params.
set<
Real>(
"c_t") = getParam<Real>(
"c_tangential");
1249 params.
set<
Real>(
"c") = getParam<Real>(
"c_normal");
1250 params.
set<
bool>(
"normalize_c") = getParam<bool>(
"normalize_c");
1251 params.
set<
bool>(
"compute_primal_residuals") =
false;
1253 params.
set<
MooseEnum>(
"segment_quadrature") = getParam<MooseEnum>(
"segment_quadrature");
1255 params.
set<std::vector<VariableName>>(
"disp_x") = {displacements[0]};
1258 params.
set<std::vector<VariableName>>(
"disp_y") = {displacements[1]};
1260 params.
set<std::vector<VariableName>>(
"disp_z") = {displacements[2]};
1262 params.
set<NonlinearVariableName>(
"variable") = normal_lagrange_multiplier_name;
1263 params.
set<std::vector<VariableName>>(
"friction_lm") = {tangential_lagrange_multiplier_name};
1266 params.
set<std::vector<VariableName>>(
"friction_lm_dir") = {
1267 tangential_lagrange_multiplier_3d_name};
1269 params.
set<
Real>(
"mu") = getParam<Real>(
"friction_coefficient");
1272 "triangulate_triangles",
1273 "extra_vector_tags",
1274 "absolute_value_vector_tags",
1277 _problem->addConstraint(mortar_constraint_name, action_name +
"_tangential_lm", params);
1281 const auto addMechanicalContactConstraints =
1282 [
this, &primary_subdomain_name, &secondary_subdomain_name, &displacements](
1283 const std::string & variable_name,
1284 const std::string & constraint_prefix,
1285 const std::string & constraint_type,
1286 const bool is_additional_frictional_constraint,
1287 const bool is_normal_constraint)
1291 params.
set<
bool>(
"correct_edge_dropping") = getParam<bool>(
"correct_edge_dropping");
1294 params.
set<SubdomainName>(
"primary_subdomain") = primary_subdomain_name;
1295 params.
set<SubdomainName>(
"secondary_subdomain") = secondary_subdomain_name;
1298 params.
set<NonlinearVariableName>(
"variable") = variable_name;
1300 params.
set<
MooseEnum>(
"segment_quadrature") = getParam<MooseEnum>(
"segment_quadrature");
1301 params.
set<
bool>(
"use_displaced_mesh") =
true;
1302 params.
set<
bool>(
"compute_lm_residuals") =
false;
1306 if (is_additional_frictional_constraint)
1310 "triangulate_triangles",
1311 "extra_vector_tags",
1312 "absolute_value_vector_tags",
1315 for (
unsigned int i = 0; i < displacements.size(); ++i)
1319 params.
set<VariableName>(
"secondary_variable") = displacements[i];
1322 if (is_normal_constraint &&
_model != ContactModel::COULOMB &&
1324 params.
set<UserObjectName>(
"weighted_gap_uo") =
"lm_weightedgap_object_" +
name();
1325 else if (is_normal_constraint &&
_model == ContactModel::COULOMB &&
1327 params.
set<UserObjectName>(
"weighted_gap_uo") =
"lm_weightedvelocities_object_" +
name();
1329 params.
set<UserObjectName>(
"weighted_velocities_uo") =
1330 "lm_weightedvelocities_object_" +
name();
1331 else if (is_normal_constraint &&
_model != ContactModel::COULOMB &&
1333 params.
set<UserObjectName>(
"weighted_gap_uo") =
"penalty_weightedgap_object_" +
name();
1334 else if (is_normal_constraint &&
_model == ContactModel::COULOMB &&
1336 params.
set<UserObjectName>(
"weighted_gap_uo") =
"penalty_friction_object_" +
name();
1337 else if (
_formulation == ContactFormulation::MORTAR_PENALTY)
1338 params.
set<UserObjectName>(
"weighted_velocities_uo") =
1339 "penalty_friction_object_" +
name();
1341 _problem->addConstraint(constraint_type, constraint_name, params);
1347 addMechanicalContactConstraints(normal_lagrange_multiplier_name,
1348 action_name +
"_normal_constraint_",
1349 "NormalMortarMechanicalContact",
1353 if (
_model == ContactModel::COULOMB)
1355 addMechanicalContactConstraints(tangential_lagrange_multiplier_name,
1356 action_name +
"_tangential_constraint_",
1357 "TangentialMortarMechanicalContact",
1361 addMechanicalContactConstraints(tangential_lagrange_multiplier_3d_name,
1362 action_name +
"_tangential_constraint_3d_",
1363 "TangentialMortarMechanicalContact",
1375 if (getParam<MooseEnum>(
"automatic_pairing_method").getEnum<ProximityMethod>() ==
1376 ProximityMethod::NODE)
1378 else if (getParam<MooseEnum>(
"automatic_pairing_method").getEnum<ProximityMethod>() ==
1379 ProximityMethod::CENTROID)
1387 std::vector<VariableName> displacements = getParam<std::vector<VariableName>>(
"displacements");
1388 const unsigned int ndisp = displacements.size();
1390 std::string constraint_type;
1393 constraint_type =
"RANFSNormalMechanicalContact";
1395 constraint_type =
"MechanicalContactConstraint";
1401 "secondary_gap_offset",
1402 "mapped_primary_gap_offset",
1406 const auto order =
_problem->systemBaseNonlinear(0)
1408 .variable_type(displacements[0])
1411 params.
set<std::vector<VariableName>>(
"displacements") = displacements;
1412 params.
set<
bool>(
"use_displaced_mesh") =
true;
1413 params.
set<
MooseEnum>(
"order") = Utility::enum_to_string<Order>(OrderWrapper{order});
1419 params.
set<std::vector<VariableName>>(
"nodal_area") = {
"nodal_area"};
1420 params.
set<BoundaryName>(
"boundary") = contact_pair.first;
1422 params.
set<std::vector<VariableName>>(
"secondary_gap_offset") = {
1423 getParam<VariableName>(
"secondary_gap_offset")};
1425 params.
set<std::vector<VariableName>>(
"mapped_primary_gap_offset") = {
1426 getParam<VariableName>(
"mapped_primary_gap_offset")};
1429 for (
unsigned int i = 0; i < ndisp; ++i)
1437 params.
set<
unsigned int>(
"component") = i;
1439 params.
set<BoundaryName>(
"primary") = contact_pair.first;
1440 params.
set<BoundaryName>(
"secondary") = contact_pair.second;
1441 params.
set<NonlinearVariableName>(
"variable") = displacements[i];
1442 params.
set<std::vector<VariableName>>(
"primary_variable") = {displacements[i]};
1444 {
"extra_vector_tags",
"absolute_value_vector_tags"});
1445 _problem->addConstraint(constraint_type,
name, params);
1453 inline const Point &
1456 return *(item.first);
1462 mooseInfo(
"The contact action is reading the list of boundaries and automatically pairs them " 1463 "if the distance between nodes is less than a specified distance.");
1466 mooseError(
"Failed to obtain mesh for automatically generating contact pairs.");
1468 if (!
_mesh->getMesh().is_serial())
1470 "automatic_pairing_boundaries",
1471 "The generation of automatic contact pairs in the contact action requires a serial mesh.");
1474 std::vector<BoundaryID> _automatic_pairing_boundaries_id;
1476 _automatic_pairing_boundaries_id.emplace_back(
_mesh->getBoundaryID(sideset_name));
1479 std::vector<NodeBoundaryIDInfo> node_boundary_id_vector;
1484 for (
const auto & bnode : bnd_nodes)
1486 const BoundaryID boundary_id = bnode->_bnd_id;
1487 const Node * node_ptr = bnode->_node;
1490 auto it = std::find(_automatic_pairing_boundaries_id.begin(),
1491 _automatic_pairing_boundaries_id.end(),
1494 if (it != _automatic_pairing_boundaries_id.end())
1495 node_boundary_id_vector.emplace_back(node_ptr, boundary_id);
1499 std::sort(node_boundary_id_vector.begin(),
1500 node_boundary_id_vector.end(),
1502 {
return first_pair.second < second_pair.second; });
1505 using KDTreeType = nanoflann::KDTreeSingleIndexAdaptor<
1506 nanoflann::L2_Simple_Adaptor<Real, PointListAdaptor<NodeBoundaryIDInfo>,
Real, std::size_t>,
1512 const unsigned int max_leaf_size = 20;
1516 node_boundary_id_vector.end());
1517 auto kd_tree = std::make_unique<KDTreeType>(
1518 LIBMESH_DIM, point_list, nanoflann::KDTreeSingleIndexAdaptorParams(max_leaf_size));
1521 mooseError(
"Internal error. KDTree was not properly initialized in the contact action.");
1523 kd_tree->buildIndex();
1527 std::vector<nanoflann::ResultItem<std::size_t, Real>> ret_matches;
1529 const auto radius_for_search = getParam<Real>(
"automatic_pairing_distance");
1532 for (
const auto & pair : node_boundary_id_vector)
1535 ret_matches.clear();
1538 const Point search_point = *pair.first;
1541 kd_tree->radiusSearch(
1542 &(search_point)(0), radius_for_search * radius_for_search, ret_matches, search_params);
1544 for (
auto & match_pair : ret_matches)
1546 const auto & match = node_boundary_id_vector[match_pair.first];
1553 auto it = std::find(_automatic_pairing_boundaries_id.begin(),
1554 _automatic_pairing_boundaries_id.end(),
1558 if (match.second == pair.second)
1564 if (it != _automatic_pairing_boundaries_id.end())
1566 const auto index_one = cast_int<int>(it - _automatic_pairing_boundaries_id.begin());
1567 auto it_other = std::find(_automatic_pairing_boundaries_id.begin(),
1568 _automatic_pairing_boundaries_id.end(),
1571 mooseAssert(it_other != _automatic_pairing_boundaries_id.end(),
1572 "Error in contact action. Unable to find boundary ID for node proximity " 1573 "automatic pairing.");
1575 const auto index_two = cast_int<int>(it_other - _automatic_pairing_boundaries_id.begin());
1577 if (pair.second > match.second)
1591 "The following boundary pairs were created by the contact action using nodal proximity: ");
1594 "Primary boundary ID: ", primary,
" and secondary boundary ID: ", secondary,
".");
1600 mooseInfo(
"The contact action is reading the list of boundaries and automatically pairs them " 1601 "if their centroids fall within a specified distance of each other.");
1604 mooseError(
"Failed to obtain mesh for automatically generating contact pairs.");
1606 if (!
_mesh->getMesh().is_serial())
1608 "automatic_pairing_boundaries",
1609 "The generation of automatic contact pairs in the contact action requires a serial mesh.");
1612 std::vector<std::pair<BoundaryName, Point>> automatic_pairing_boundaries_cog;
1613 const auto & sideset_ids =
_mesh->meshSidesetIds();
1615 const auto & bnd_to_elem_map =
_mesh->getBoundariesToActiveSemiLocalElemIds();
1620 const auto find_set = sideset_ids.find(
_mesh->getBoundaryID(sideset_name));
1621 if (find_set == sideset_ids.end())
1624 " is not defined as a sideset in the mesh.");
1626 auto dofs_set = bnd_to_elem_map.find(
_mesh->getBoundaryID(sideset_name));
1629 Point center_of_gravity(0, 0, 0);
1630 Real accumulated_sideset_area(0);
1633 std::unique_ptr<const Elem> side_ptr;
1634 const std::unordered_set<dof_id_type> & bnd_elems = dofs_set->second;
1636 for (
auto elem_id : bnd_elems)
1638 const Elem * elem =
_mesh->elemPtr(elem_id);
1639 unsigned int side =
_mesh->sideWithBoundaryID(elem,
_mesh->getBoundaryID(sideset_name));
1642 elem->side_ptr(side_ptr, side);
1645 const auto side_area = side_ptr->volume();
1648 const auto side_position = side_ptr->true_centroid();
1650 center_of_gravity += side_position * side_area;
1651 accumulated_sideset_area += side_area;
1655 center_of_gravity /= accumulated_sideset_area;
1658 automatic_pairing_boundaries_cog.emplace_back(sideset_name, center_of_gravity);
1662 std::vector<std::pair<std::pair<BoundaryName, BoundaryName>,
Real>> pairs_distances;
1665 for (std::size_t i = 0; i < automatic_pairing_boundaries_cog.size() - 1; i++)
1666 for (std::size_t
j = i + 1;
j < automatic_pairing_boundaries_cog.size();
j++)
1668 const Point & distance_vector =
1669 automatic_pairing_boundaries_cog[i].second - automatic_pairing_boundaries_cog[
j].second;
1671 if (automatic_pairing_boundaries_cog[i].first != automatic_pairing_boundaries_cog[
j].first)
1674 const std::pair pair = std::make_pair(automatic_pairing_boundaries_cog[i].first,
1675 automatic_pairing_boundaries_cog[
j].first);
1676 pairs_distances.emplace_back(std::make_pair(pair,
distance));
1680 const auto automatic_pairing_distance = getParam<Real>(
"automatic_pairing_distance");
1683 std::vector<std::pair<std::pair<BoundaryName, BoundaryName>,
Real>> lean_pairs_distances;
1684 for (
const auto & pair_distance : pairs_distances)
1685 if (pair_distance.second <= automatic_pairing_distance)
1687 lean_pairs_distances.emplace_back(pair_distance);
1689 pair_distance.first.first,
1691 pair_distance.first.second,
1692 ", with a relative distance of ",
1693 pair_distance.second);
1697 for (
const auto & lean_pairs_distance : lean_pairs_distances)
1702 if (
_mesh->getBoundaryID(lean_pairs_distance.first.first) >
1703 _mesh->getBoundaryID(lean_pairs_distance.first.second))
1705 {lean_pairs_distance.first.first, lean_pairs_distance.first.second});
1708 {lean_pairs_distance.first.second, lean_pairs_distance.first.first});
1718 return MooseEnum(getContactModelOptions(),
"frictionless");
1724 return MooseEnum(getProximityMethodOptions());
1730 auto formulations =
MooseEnum(getContactFormulationOptions(),
"kinematic");
1732 formulations.addDocumentation(
1734 "Reduced Active Nonlinear Function Set scheme for node-on-face contact. Provides exact " 1735 "enforcement without Lagrange multipliers or penalty terms.");
1736 formulations.addDocumentation(
1738 "Kinematic contact constraint enforcement transfers the internal forces at secondary nodes " 1739 "to the corresponding primary face for node-on-face contact. Provides exact " 1740 "enforcement without Lagrange multipliers or penalty terms.");
1741 formulations.addDocumentation(
1743 "Node-on-face penalty based contact constraint enforcement. Interpenetration is penalized. " 1744 "Enforcement depends on the penalty magnitude. High penalties can introduce ill conditioning " 1746 formulations.addDocumentation(
"augmented_lagrange",
1747 "Node-on-face augmented Lagrange penalty based contact constraint " 1748 "enforcement. Interpenetration is enforced up to a user specified " 1749 "tolerance, ill-conditioning is generally avoided. Requires an " 1750 "Augmented Lagrange Problem class to be used in the simulation.");
1751 formulations.addDocumentation(
1752 "tangential_penalty",
1753 "Node-on-face penalty based frictional contact constraint enforcement. Interpenetration and " 1754 "slip distance for sticking nodes are penalized. Enforcement depends on the penalty " 1755 "magnitudes. High penalties can introduce ill conditioning of the system.");
1756 formulations.addDocumentation(
1758 "Mortar based contact constraint enforcement using Lagrange multipliers. Provides exact " 1759 "enforcement and a variationally consistent formulation. Lagrange multipliers introduce a " 1760 "saddle point character in the system matrix which can have a negative impact on scalability " 1761 "with iterative solvers");
1762 formulations.addDocumentation(
1764 "Mortar and penalty based contact constraint enforcement. When using an Augmented Lagrange " 1765 "Problem class this provides normal (and tangential) contact constratint enforced up to a " 1766 "user specified tolerances. Without AL the enforcement depends on the penalty magnitudes. " 1767 "High penalties can introduce ill conditioning of the system.");
1769 return formulations;
1775 return MooseEnum(
"Constraint",
"Constraint");
1781 return MooseEnum(
"edge_based nodal_normal_based",
"");
1791 "Method to use to smooth normals");
1793 "normal_smoothing_distance",
1794 "Distance from edge in parametric coordinates over which to smooth contact normal");
void mooseInfo(Args &&... args) const
bool isUltimateMaster() const
const std::string & _name
void paramError(const std::string ¶m, Args... args) const
const T & getParam(const std::string &name) const
const InputParameters & parameters() const
const Point & getPoint(const PointObject &item) const
InputParameters getValidParams(const std::string &name) const
void mooseInfoRepeated(Args &&... args)
const ExecFlagType EXEC_TIMESTEP_END
Real distance(const Point &p)
std::string shortName(const std::string &name)
static InputParameters validParams()
const std::string & name() const
static InputParameters validParams()
const ExecFlagType EXEC_TIMESTEP_BEGIN
boundary_id_type BoundaryID
const std::string & type() const
const std::string & _current_task
static std::string variableType(const libMesh::FEType &fe_type, const bool is_fv=false, const bool is_array=false)
const ExecFlagType EXEC_LINEAR
std::string stringify(const T &t)
const MeshGenerator & appendMeshGenerator(const std::string &type, const std::string &name, InputParameters params)
std::pair< T, U > ResultItem
const ExecFlagType EXEC_NONLINEAR
std::shared_ptr< MooseMesh > & _mesh
static libMesh::FEType feType(const InputParameters ¶ms)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static InputParameters triangulationParams()
bool useMasterMesh() const
void mooseError(Args &&... args) const
std::shared_ptr< FEProblemBase > & _problem
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
bool isParamValid(const std::string &name) const
std::vector< const T *> getActions()
bool isRecovering() const
SearchParams SearchParameters
bool isParamSetByUser(const std::string &name) const
auto index_range(const T &sizable)
const ExecFlagType EXEC_INITIAL