13 #include "FEProblem.h"
14 #include "Conversion.h"
15 #include "AddVariableAction.h"
16 #include "MortarConstraintBase.h"
17 #include "NonlinearSystemBase.h"
19 #include "libmesh/petsc_nonlinear_solver.h"
20 #include "libmesh/string_to_enum.h"
34 InputParameters params = validParams<Action>();
37 params.addRequiredParam<BoundaryName>(
"master",
"The master surface");
38 params.addRequiredParam<BoundaryName>(
"slave",
"The slave surface");
40 params.addParam<MeshGeneratorName>(
"mesh",
"",
"The mesh generator for mortar method");
42 params.addParam<VariableName>(
"disp_x",
"The x displacement");
43 params.addParam<VariableName>(
"disp_y",
"The y displacement");
44 params.addParam<VariableName>(
"disp_z",
"The z displacement");
46 params.addParam<std::vector<VariableName>>(
48 "The displacements appropriate for the simulation geometry and coordinate system");
50 params.addParam<Real>(
53 "The penalty to apply. This can vary depending on the stiffness of your materials");
54 params.addParam<Real>(
"friction_coefficient", 0,
"The friction coefficient");
55 params.addParam<Real>(
"tension_release",
57 "Tension release threshold. A node in contact "
58 "will not be released if its tensile load is below "
59 "this value. No tension release if negative.");
61 params.addParam<Real>(
"tangential_tolerance",
62 "Tangential distance to extend edges of contact surfaces");
63 params.addParam<Real>(
64 "capture_tolerance", 0.0,
"Normal distance from surface within which nodes are captured");
65 params.addParam<Real>(
66 "normal_smoothing_distance",
67 "Distance from edge in parametric coordinates over which to smooth contact normal");
69 params.addParam<MooseEnum>(
71 params.addParam<
bool>(
"normalize_penalty",
73 "Whether to normalize the penalty parameter with the nodal area.");
74 params.addParam<
bool>(
"master_slave_jacobian",
76 "Whether to include Jacobian entries coupling master and slave nodes.");
77 params.addParam<Real>(
"al_penetration_tolerance",
78 "The tolerance of the penetration for augmented Lagrangian method.");
79 params.addParam<Real>(
"al_incremental_slip_tolerance",
80 "The tolerance of the incremental slip for augmented Lagrangian method.");
82 params.addParam<Real>(
"al_frictional_force_tolerance",
83 "The tolerance of the frictional force for augmented Lagrangian method.");
84 params.addParam<Real>(
85 "c_normal", 1,
"Parameter for balancing the size of the gap and contact pressure");
86 params.addParam<Real>(
87 "c_tangential", 1,
"Parameter for balancing the contact pressure and velocity");
94 _master(getParam<BoundaryName>(
"master")),
95 _slave(getParam<BoundaryName>(
"slave")),
96 _model(getParam<MooseEnum>(
"model")),
97 _formulation(getParam<MooseEnum>(
"formulation")),
98 _system(getParam<MooseEnum>(
"system")),
99 _mesh_gen_name(getParam<MeshGeneratorName>(
"mesh"))
107 "The 'tangential_penalty' formulation can only be used with the 'Constraint' system");
109 paramError(
"formulation",
110 "The 'tangential_penalty' formulation can only be used with the 'coulomb' model");
116 paramError(
"formulation",
117 "The 'mortar' formulation can only be used with the 'Constraint' system");
119 paramError(
"mesh",
"The 'mortar' formulation requires 'mesh' to be supplied");
121 paramError(
"model",
"The 'mortar' formulation does not support glued contact (yet)");
125 MooseEnum makeDiracDeprecated = params.get<MooseEnum>(
"system");
126 makeDiracDeprecated.deprecate(
"DiracKernel",
"Constraint");
130 "The DiracKernel-based system for mechanical contact enforcement is deprecated, "
131 "and will be removed on April 1, 2020. It is being replaced by the Constraint-based "
132 "system, which is selected by setting 'system=Constraint'.\n");
142 if (_current_task ==
"add_dirac_kernel")
148 if (!_problem->isSNESMFReuseBaseSetbyUser())
149 _problem->setSNESMFReuseBase(
false,
false);
151 if (!_problem->getDisplacedProblem())
153 "Contact requires updated coordinates. Use the 'displacements = ...' line in the "
160 else if (
_system ==
"DiracKernel")
176 std::string action_name = MooseUtils::shortName(
name());
179 const unsigned int ndisp = displacements.size();
182 const std::string master_subdomain_name = action_name +
"_master_subdomain";
183 const std::string slave_subdomain_name = action_name +
"_slave_subdomain";
184 const std::string normal_lagrange_multiplier_name = action_name +
"_normal_lm";
185 const std::string tangential_lagrange_multiplier_name = action_name +
"_tangential_lm";
187 if (_current_task ==
"add_mesh_generator")
190 if (!(_app.isRecovering() && _app.isUltimateMaster()) && !_app.masterMesh())
192 const MeshGeneratorName master_name = master_subdomain_name +
"_generator";
193 const MeshGeneratorName slave_name = slave_subdomain_name +
"_generator";
195 auto master_params = _factory.getValidParams(
"LowerDBlockFromSidesetGenerator");
196 auto slave_params = _factory.getValidParams(
"LowerDBlockFromSidesetGenerator");
199 slave_params.set<MeshGeneratorName>(
"input") = master_name;
201 master_params.set<SubdomainName>(
"new_block_name") = master_subdomain_name;
202 slave_params.set<SubdomainName>(
"new_block_name") = slave_subdomain_name;
204 master_params.set<std::vector<BoundaryName>>(
"sidesets") = {
_master};
205 slave_params.set<std::vector<BoundaryName>>(
"sidesets") = {
_slave};
207 _app.addMeshGenerator(
"LowerDBlockFromSidesetGenerator", master_name, master_params);
208 _app.addMeshGenerator(
"LowerDBlockFromSidesetGenerator", slave_name, slave_params);
212 if (_current_task ==
"add_variable")
215 const auto addLagrangeMultiplier =
216 [
this, &slave_subdomain_name, &displacements](
const std::string & variable_name,
217 const int codimension)
219 InputParameters params = _factory.getValidParams(
"MooseVariableBase");
221 mooseAssert(_problem->systemBaseNonlinear().hasVariable(displacements[0]),
222 "Displacement variable is missing");
223 const auto primal_type =
224 _problem->systemBaseNonlinear().system().variable_type(displacements[0]);
225 const int lm_order = std::max(primal_type.order.get_order() - codimension, 0);
227 if (primal_type.family == MONOMIAL || (primal_type.family == LAGRANGE && lm_order < 1))
229 params.set<MooseEnum>(
"family") =
"MONOMIAL";
230 params.set<MooseEnum>(
"order") =
"CONSTANT";
232 else if (primal_type.family == LAGRANGE)
234 params.set<MooseEnum>(
"family") = Utility::enum_to_string<FEFamily>(primal_type.family);
235 params.set<MooseEnum>(
"order") = Utility::enum_to_string<Order>(OrderWrapper{lm_order});
238 mooseError(
"Primal variable type must be either MONOMIAL or LAGRANGE for mortar contact.");
240 params.set<std::vector<SubdomainName>>(
"block") = {slave_subdomain_name};
241 auto fe_type = AddVariableAction::feType(params);
242 auto var_type = AddVariableAction::determineType(fe_type, 1);
243 _problem->addVariable(var_type, variable_name, params);
247 addLagrangeMultiplier(normal_lagrange_multiplier_name, 0);
249 addLagrangeMultiplier(tangential_lagrange_multiplier_name, 1);
252 if (_current_task ==
"add_constraint")
256 InputParameters params = _factory.getValidParams(
"NormalNodalLMMechanicalContact");
258 params.set<BoundaryName>(
"master") =
_master;
259 params.set<BoundaryName>(
"slave") =
_slave;
260 params.set<NonlinearVariableName>(
"variable") = normal_lagrange_multiplier_name;
261 params.set<
bool>(
"use_displaced_mesh") =
true;
262 params.set<MooseEnum>(
"ncp_function_type") =
"min";
263 params.set<Real>(
"c") = getParam<Real>(
"c_normal");
265 params.set<std::vector<VariableName>>(
"master_variable") = {displacements[0]};
267 params.set<std::vector<VariableName>>(
"disp_y") = {displacements[1]};
269 params.set<std::vector<VariableName>>(
"disp_z") = {displacements[2]};
271 _problem->addConstraint(
"NormalNodalLMMechanicalContact", action_name +
"_normal_lm", params);
277 InputParameters params =
278 _factory.getValidParams(
"TangentialMortarLMMechanicalContact<RESIDUAL>");
280 params.set<BoundaryName>(
"master_boundary") =
_master;
281 params.set<BoundaryName>(
"slave_boundary") =
_slave;
282 params.set<SubdomainName>(
"master_subdomain") = master_subdomain_name;
283 params.set<SubdomainName>(
"slave_subdomain") = slave_subdomain_name;
284 params.set<NonlinearVariableName>(
"variable") = tangential_lagrange_multiplier_name;
285 params.set<
bool>(
"use_displaced_mesh") =
true;
286 params.set<MooseEnum>(
"ncp_function_type") =
"fb";
287 params.set<Real>(
"c") = getParam<Real>(
"c_tangential");
288 params.set<
bool>(
"compute_primal_residuals") =
false;
289 params.set<NonlinearVariableName>(
"contact_pressure") = normal_lagrange_multiplier_name;
290 params.set<Real>(
"friction_coefficient") = getParam<Real>(
"friction_coefficient");
292 params.set<VariableName>(
"slave_variable") = displacements[0];
294 params.set<NonlinearVariableName>(
"slave_disp_y") = displacements[1];
297 _problem->addConstraint(
"TangentialMortarLMMechanicalContact<RESIDUAL>",
298 action_name +
"_tangential_lm_residual",
300 _problem->addConstraint(
"TangentialMortarLMMechanicalContact<JACOBIAN>",
301 action_name +
"_tangential_lm_jacobian",
305 const auto addMechanicalContactConstraints =
306 [
this, &master_subdomain_name, &slave_subdomain_name, &displacements](
307 const std::string & variable_name,
308 const std::string & constraint_prefix,
309 const std::string & constraint_type)
311 InputParameters params = _factory.getValidParams(constraint_type +
"<RESIDUAL>");
313 params.set<BoundaryName>(
"master_boundary") =
_master;
314 params.set<BoundaryName>(
"slave_boundary") =
_slave;
315 params.set<SubdomainName>(
"master_subdomain") = master_subdomain_name;
316 params.set<SubdomainName>(
"slave_subdomain") = slave_subdomain_name;
317 params.set<NonlinearVariableName>(
"variable") = variable_name;
318 params.set<
bool>(
"use_displaced_mesh") =
true;
319 params.set<
bool>(
"compute_lm_residuals") =
false;
321 for (
unsigned int i = 0; i < displacements.size(); ++i)
323 std::string constraint_name = constraint_prefix + Moose::stringify(i);
325 params.set<VariableName>(
"slave_variable") = displacements[i];
326 params.set<MooseEnum>(
"component") = i;
328 _problem->addConstraint(
329 constraint_type +
"<RESIDUAL>", constraint_name +
"_residual", params);
330 _problem->addConstraint(
331 constraint_type +
"<JACOBIAN>", constraint_name +
"_jacobian", params);
333 _problem->haveADObjects(
true);
337 addMechanicalContactConstraints(normal_lagrange_multiplier_name,
338 action_name +
"_normal_constraint_",
339 "NormalMortarMechanicalContact");
341 addMechanicalContactConstraints(tangential_lagrange_multiplier_name,
342 action_name +
"_tangential_constraint_",
343 "TangentialMortarMechanicalContact");
350 std::string action_name = MooseUtils::shortName(
name());
353 const unsigned int ndisp = displacements.size();
355 InputParameters params = _factory.getValidParams(
"MechanicalContactConstraint");
356 params.applyParameters(parameters(), {
"displacements"});
357 params.set<std::vector<VariableName>>(
"nodal_area") = {
"nodal_area_" +
name()};
358 params.set<std::vector<VariableName>>(
"displacements") = displacements;
359 params.set<BoundaryName>(
"boundary") =
_master;
360 params.set<
bool>(
"use_displaced_mesh") =
true;
362 for (
unsigned int i = 0; i < ndisp; ++i)
364 std::string
name = action_name +
"_constraint_" + Moose::stringify(i);
366 params.set<
unsigned int>(
"component") = i;
367 params.set<NonlinearVariableName>(
"variable") = displacements[i];
368 params.set<std::vector<VariableName>>(
"master_variable") = {displacements[i]};
369 _problem->addConstraint(
"MechanicalContactConstraint",
name, params);
376 std::string action_name = MooseUtils::shortName(
name());
379 const unsigned int ndisp = displacements.size();
382 InputParameters params = _factory.getValidParams(
"ContactMaster");
383 params.applyParameters(parameters(), {
"displacements"});
384 params.set<std::vector<VariableName>>(
"nodal_area") = {
"nodal_area_" +
name()};
385 params.set<std::vector<VariableName>>(
"displacements") = displacements;
386 params.set<BoundaryName>(
"boundary") =
_master;
387 params.set<
bool>(
"use_displaced_mesh") =
true;
389 for (
unsigned int i = 0; i < ndisp; ++i)
391 std::string
name = action_name +
"_master_" + Moose::stringify(i);
392 params.set<
unsigned int>(
"component") = i;
393 params.set<NonlinearVariableName>(
"variable") = displacements[i];
394 _problem->addDiracKernel(
"ContactMaster",
name, params);
399 InputParameters params = _factory.getValidParams(
"SlaveConstraint");
400 params.applyParameters(parameters(), {
"displacements"});
401 params.set<std::vector<VariableName>>(
"nodal_area") = {
"nodal_area_" +
name()};
402 params.set<std::vector<VariableName>>(
"displacements") = displacements;
403 params.set<BoundaryName>(
"boundary") =
_slave;
404 params.set<
bool>(
"use_displaced_mesh") =
true;
406 for (
unsigned int i = 0; i < ndisp; ++i)
408 std::string
name = action_name +
"_slave_" + Moose::stringify(i);
409 params.set<
unsigned int>(
"component") = i;
410 params.set<NonlinearVariableName>(
"variable") = displacements[i];
411 _problem->addDiracKernel(
"SlaveConstraint",
name, params);
419 return MooseEnum(
"frictionless glued coulomb",
"frictionless");
425 return MooseEnum(
"kinematic penalty augmented_lagrange tangential_penalty mortar",
"kinematic");
431 return MooseEnum(
"DiracKernel Constraint",
"DiracKernel");
437 return MooseEnum(
"edge_based nodal_normal_based",
"");
443 InputParameters params = emptyInputParameters();
445 MooseEnum orders(AddVariableAction::getNonlinearVariableOrders());
446 params.addParam<MooseEnum>(
"order", orders,
"The finite element order: FIRST, SECOND, etc.");
448 params.addParam<MooseEnum>(
"normal_smoothing_method",
450 "Method to use to smooth normals");
451 params.addParam<Real>(
452 "normal_smoothing_distance",
453 "Distance from edge in parametric coordinates over which to smooth contact normal");
455 params.addParam<MooseEnum>(
463 std::vector<VariableName>
466 std::vector<VariableName> displacements;
467 if (isParamValid(
"displacements"))
468 displacements = getParam<std::vector<VariableName>>(
"displacements");
472 if (!isParamValid(
"disp_x"))
473 mooseError(
"Specify displacement variables using the `displacements` parameter.");
474 displacements.push_back(getParam<VariableName>(
"disp_x"));
476 if (isParamValid(
"disp_y"))
478 displacements.push_back(getParam<VariableName>(
"disp_y"));
479 if (isParamValid(
"disp_z"))
480 displacements.push_back(getParam<VariableName>(
"disp_z"));
483 mooseDeprecated(
"use the `displacements` parameter rather than the `disp_*` parameters (those "
484 "will go away with the deprecation of the Solid Mechanics module).");
487 return displacements;