https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | Protected Member Functions | Static Protected Member Functions | Protected Attributes | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
ContactAction Class Reference

Action class for creating constraints, kernels, and user objects necessary for mechanical contact. More...

#include <ContactAction.h>

Inheritance diagram for ContactAction:
[legend]

Classes

struct  MortarInfo
 

Public Types

typedef DataFileName DataFileParameterType
 

Public Member Functions

 ContactAction (const InputParameters &params)
 
virtual void act () override
 
virtual void addRelationshipManagers (Moose::RelationshipManagerType input_rm_type) override
 
virtual void addRelationshipManagers (Moose::RelationshipManagerType when_type)
 
bool addRelationshipManagers (Moose::RelationshipManagerType when_type, const InputParameters &moose_object_pars)
 
void timedAct ()
 
MooseObjectName uniqueActionName () const
 
const std::string & specificTaskName () const
 
const std::set< std::string > & getAllTasks () const
 
void appendTask (const std::string &task)
 
MooseAppgetMooseApp () const
 
const std::string & type () const
 
const std::string & name () const
 
std::string typeAndName () const
 
MooseObjectParameterName uniqueParameterName (const std::string &parameter_name) const
 
MooseObjectName uniqueName () const
 
const InputParametersparameters () const
 
const hit::Node * getHitNode () const
 
bool hasBase () const
 
const std::string & getBase () const
 
const TgetParam (const std::string &name) const
 
std::vector< std::pair< T1, T2 > > getParam (const std::string &param1, const std::string &param2) const
 
const TqueryParam (const std::string &name) const
 
const TgetRenamedParam (const std::string &old_name, const std::string &new_name) const
 
T getCheckedPointerParam (const std::string &name, const std::string &error_string="") const
 
bool isParamValid (const std::string &name) const
 
bool isParamSetByUser (const std::string &name) const
 
void connectControllableParams (const std::string &parameter, const std::string &object_type, const std::string &object_name, const std::string &object_parameter) const
 
void paramError (const std::string &param, Args... args) const
 
void paramWarning (const std::string &param, Args... args) const
 
void paramWarning (const std::string &param, Args... args) const
 
void paramInfo (const std::string &param, Args... args) const
 
std::string messagePrefix (const bool hit_prefix=true) const
 
std::string errorPrefix (const std::string &) const
 
void mooseError (Args &&... args) const
 
void mooseDocumentedError (const std::string &repo_name, const unsigned int issue_num, Args &&... args) const
 
void mooseErrorNonPrefixed (Args &&... args) const
 
void mooseWarning (Args &&... args) const
 
void mooseWarning (Args &&... args) const
 
void mooseWarningNonPrefixed (Args &&... args) const
 
void mooseWarningNonPrefixed (Args &&... args) const
 
void mooseDeprecated (Args &&... args) const
 
void mooseDeprecated (Args &&... args) const
 
void mooseDeprecatedNoTrace (Args &&... args) const
 
void mooseInfo (Args &&... args) const
 
void callMooseError (std::string msg, const bool with_prefix, const hit::Node *node=nullptr, const bool show_trace=true) const
 
std::string getDataFileName (const std::string &param) const
 
std::string getDataFileNameByName (const std::string &relative_path) const
 
std::string getDataFilePath (const std::string &relative_path) const
 
PerfGraphperfGraph ()
 
const Parallel::Communicator & comm () const
 
processor_id_type n_processors () const
 
processor_id_type processor_id () const
 

Static Public Member Functions

static InputParameters validParams ()
 
static MooseEnum getModelEnum ()
 Get contact model.
 
static MooseEnum getFormulationEnum ()
 Get contact formulation.
 
static MooseEnum getSystemEnum ()
 Get contact system.
 
static MooseEnum getSmoothingEnum ()
 Get smoothing type.
 
static MooseEnum getProximityMethod ()
 Get proximity method for automatic pairing.
 
static InputParameters commonParameters ()
 Define parameters used by multiple contact objects.
 
static void callMooseError (MooseApp *const app, const InputParameters &params, std::string msg, const bool with_prefix, const hit::Node *node, const bool show_trace=true)
 

Public Attributes

 usingCombinedWarningSolutionWarnings
 
const ConsoleStream _console
 

Static Public Attributes

static const std::string unique_action_name_param
 
static const std::string type_param
 
static const std::string name_param
 
static const std::string unique_name_param
 
static const std::string app_param
 
static const std::string moose_base_param
 
static const std::string kokkos_object_param
 
static constexpr auto SYSTEM
 
static constexpr auto NAME
 

Protected Member Functions

void associateWithParameter (const std::string &param_name, InputParameters &params) const
 
void associateWithParameter (const InputParameters &from_params, const std::string &param_name, InputParameters &params) const
 
const TgetMeshProperty (const std::string &data_name, const std::string &prefix)
 
const TgetMeshProperty (const std::string &data_name)
 
bool hasMeshProperty (const std::string &data_name, const std::string &prefix) const
 
bool hasMeshProperty (const std::string &data_name, const std::string &prefix) const
 
bool hasMeshProperty (const std::string &data_name) const
 
bool hasMeshProperty (const std::string &data_name) const
 
std::string meshPropertyName (const std::string &data_name) const
 
PerfID registerTimedSection (const std::string &section_name, const unsigned int level) const
 
PerfID registerTimedSection (const std::string &section_name, const unsigned int level, const std::string &live_message, const bool print_dots=true) const
 
std::string timedSectionName (const std::string &section_name) const
 
void flagInvalidSolutionInternal (const InvalidSolutionID invalid_solution_id) const
 
InvalidSolutionID registerInvalidSolutionInternal (const std::string &message, const bool warning) const
 

Static Protected Member Functions

static std::string meshPropertyName (const std::string &data_name, const std::string &prefix)
 

Protected Attributes

std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
 Primary/Secondary boundary name pairs for mechanical contact.
 
std::vector< BoundaryName > _automatic_pairing_boundaries
 List of all possible boundaries for contact for automatic pairing (optional)
 
const ContactModel _model
 Contact model type enum.
 
const ContactFormulation _formulation
 Contact formulation.
 
const ContactLMSpace _lm_space
 Finite element space to use for action-generated mortar Lagrange multiplier variables.
 
bool _use_dual
 Whether to use the dual Mortar approach.
 
const bool _generate_mortar_mesh
 Whether to generate the mortar mesh (useful in a restart simulation e.g.).
 
const bool _mortar_dynamics
 Whether mortar dynamic contact constraints are to be used.
 
std::map< std::pair< BoundaryName, BoundaryName >, const MortarInfo_bnd_pair_to_mortar_info
 Map from boundary pair to mortar user object name.
 
std::string _registered_identifier
 
std::string _specific_task_name
 
std::set< std::string > _all_tasks
 
ActionWarehouse_awh
 
const std::string & _current_task
 
std::shared_ptr< MooseMesh > & _mesh
 
std::shared_ptr< MooseMesh > & _displaced_mesh
 
std::shared_ptr< FEProblemBase > & _problem
 
PerfID _act_timer
 
MooseApp_app
 
Factory_factory
 
ActionFactory_action_factory
 
const std::string & _type
 
const std::string & _name
 
const InputParameters_pars
 
MooseApp_pg_moose_app
 
const std::string _prefix
 
const Parallel::Communicator & _communicator
 

Private Member Functions

void addMortarContact ()
 Generate mesh and other Moose objects for Mortar contact.
 
void addNodeFaceContact ()
 Generate constraints for node to face contact.
 
void addContactPressureAuxKernel ()
 Add single contact pressure auxiliary kernel for various contact action objects.
 
void removeRepeatedPairs ()
 Remove repeated contact pairs from _boundary_pairs.
 
void createSidesetPairsFromGeometry ()
 Create contact pairs between all boundaries whose centroids are within a user-specified distance of each other.
 
void createSidesetsFromNodeProximity ()
 Create contact pairs between all boundaries by determining that nodes on both boundaries are close enough.
 
bool addRelationshipManager (Moose::RelationshipManagerType input_rm_type, const InputParameters &moose_object_pars, std::string rm_name, Moose::RelationshipManagerType rm_type, Moose::RelationshipManagerInputParameterCallback rm_input_parameter_func, Moose::RMSystemType sys_type=Moose::RMSystemType::NONE)
 
virtual std::string meshPropertyPrefix (const std::string &data_name) const
 
const RestartableDataValuegetMeshPropertyInternal (const std::string &data_name, const std::string &prefix) const
 
void mooseErrorInternal (Args &&... args) const
 

Static Private Member Functions

static const hit::Node * getHitNode (const InputParameters &params)
 
static std::string messagePrefix (const InputParameters &params, const bool hit_prefix)
 

Private Attributes

const ParallelParamObject_parent
 
MooseApp_meta_data_app
 
const MooseObject *const _meta_data_object
 
const MooseBase_si_moose_base
 
const FEProblemBase_si_problem
 

Detailed Description

Action class for creating constraints, kernels, and user objects necessary for mechanical contact.

Definition at line 32 of file ContactAction.h.

Constructor & Destructor Documentation

◆ ContactAction()

ContactAction::ContactAction ( const InputParameters params)

Definition at line 352 of file ContactAction.C.

353 : Action(params),
354 _boundary_pairs(getParam<BoundaryName, BoundaryName>("primary", "secondary")),
355 _model(getParam<MooseEnum>("model").getEnum<ContactModel>()),
356 _formulation(getParam<MooseEnum>("formulation").getEnum<ContactFormulation>()),
357 _lm_space(getParam<MooseEnum>("lm_space").getEnum<ContactLMSpace>()),
358 _generate_mortar_mesh(getParam<bool>("generate_mortar_mesh")),
359 _mortar_dynamics(getParam<bool>("mortar_dynamics"))
360{
361 // Check for automatic selection of contact pairs.
362 if (getParam<std::vector<BoundaryName>>("automatic_pairing_boundaries").size() > 1)
364 getParam<std::vector<BoundaryName>>("automatic_pairing_boundaries");
365
366 if (_automatic_pairing_boundaries.size() > 0 && !isParamValid("automatic_pairing_distance"))
367 paramError("automatic_pairing_distance",
368 "For automatic selection of contact pairs (for particular geometries) in contact "
369 "action, 'automatic_pairing_distance' needs to be provided.");
370
371 if (_automatic_pairing_boundaries.size() > 0 && !isParamValid("automatic_pairing_method"))
372 paramError("automatic_pairing_distance",
373 "For automatic selection of contact pairs (for particular geometries) in contact "
374 "action, 'automatic_pairing_method' needs to be provided.");
375
376 if (_automatic_pairing_boundaries.size() > 0 && _boundary_pairs.size() != 0)
377 paramError("automatic_pairing_boundaries",
378 "If a boundary list is provided, primary and secondary surfaces will be identified "
379 "automatically. Therefore, one cannot provide an automatic pairing boundary list "
380 "and primary/secondary lists.");
381 else if (_automatic_pairing_boundaries.size() == 0 && _boundary_pairs.size() == 0)
382 paramError("primary",
383 "'primary' and 'secondary' surfaces or a list of boundaries for automatic pair "
384 "generation need to be provided.");
385
386 // End of checks for automatic selection of contact pairs.
387
388 if (_boundary_pairs.size() != 1 && _formulation == ContactFormulation::MORTAR)
389 paramError("formulation", "When using mortar, a vector of contact pairs cannot be used");
390
391 if ((_formulation == ContactFormulation::MORTAR ||
392 _formulation == ContactFormulation::MORTAR_PENALTY) &&
393 params.isParamSetByUser("ghost_whole_interface"))
394 paramError("ghost_whole_interface",
395 "The 'ghost_whole_interface' parameter is only supported for node-face contact "
396 "formulations. Mortar contact always geometrically and algebraically ghosts the "
397 "interface.");
398
399 if (_formulation == ContactFormulation::TANGENTIAL_PENALTY && _model != ContactModel::COULOMB)
400 paramError("formulation",
401 "The 'tangential_penalty' formulation can only be used with the 'coulomb' model");
402
403 if (_formulation == ContactFormulation::MORTAR_PENALTY)
404 {
405 // Use dual basis functions for contact traction interpolation
406 if (isParamValid("use_dual"))
407 _use_dual = getParam<bool>("use_dual");
408 else
409 _use_dual = true;
410
411 if (_model == ContactModel::GLUED)
412 paramError("model", "The 'mortar_penalty' formulation does not support glued contact");
413
414 if (getParam<bool>("mortar_dynamics"))
415 paramError("mortar_dynamics",
416 "The 'mortar_penalty' formulation does not support implicit dynamic simulations");
417
418 if (getParam<bool>("use_petrov_galerkin"))
419 paramError("use_petrov_galerkin",
420 "The 'mortar_penalty' formulation does not support usage of the Petrov-Galerkin "
421 "flag. The default (use_dual = true) behavior is such that contact tractions are "
422 "interpolated with dual bases whereas mortar or weighted contact quantities are "
423 "interpolated with Lagrange shape functions.");
424 }
425
426 if (_formulation == ContactFormulation::MORTAR)
427 {
428 if (_model == ContactModel::GLUED)
429 paramError("model", "The 'mortar' formulation does not support glued contact (yet)");
430
431 // use dual basis function for Lagrange multipliers?
432 if (isParamValid("use_dual"))
433 _use_dual = getParam<bool>("use_dual");
434 else
435 _use_dual = true;
436
437 if (!getParam<bool>("mortar_dynamics"))
438 {
439 if (params.isParamSetByUser("newmark_beta"))
440 paramError("newmark_beta", "newmark_beta can only be used with the mortar_dynamics option");
441
442 if (params.isParamSetByUser("newmark_gamma"))
443 paramError("newmark_gamma",
444 "newmark_gamma can only be used with the mortar_dynamics option");
445 }
446
447 if (isParamSetByUser("penalty"))
448 paramError("penalty",
449 "The 'penalty' parameter is not used for the 'mortar' formulation which instead "
450 "uses Lagrange multipliers");
451 }
452 else
453 {
454 if (params.isParamSetByUser("correct_edge_dropping"))
456 "correct_edge_dropping",
457 "The 'correct_edge_dropping' option can only be used with the 'mortar' formulation "
458 "(weighted)");
459 else if (params.isParamSetByUser("triangulation") &&
460 _formulation != ContactFormulation::MORTAR_PENALTY)
461 paramError("triangulation",
462 "The 'triangulation' option can only be used with mortar-based formulations.");
463 else if (params.isParamSetByUser("triangulate_triangles") &&
464 _formulation != ContactFormulation::MORTAR_PENALTY)
465 paramError("triangulate_triangles",
466 "The 'triangulate_triangles' option can only be used with mortar-based "
467 "formulations.");
468 else if (params.isParamSetByUser("minimum_projection_angle") &&
469 _formulation != ContactFormulation::MORTAR_PENALTY)
470 paramError("minimum_projection_angle",
471 "The 'minimum_projection_angle' option can only be used with mortar-based "
472 "formulations.");
473 else if (params.isParamSetByUser("mortar_3d_subpatch_plane") &&
474 _formulation != ContactFormulation::MORTAR_PENALTY)
475 paramError("mortar_3d_subpatch_plane",
476 "The 'mortar_3d_subpatch_plane' option can only be used with mortar-based "
477 "formulations.");
478 else if (params.isParamSetByUser("mortar_3d_qp_mapping") &&
479 _formulation != ContactFormulation::MORTAR_PENALTY)
480 paramError("mortar_3d_qp_mapping",
481 "The 'mortar_3d_qp_mapping' option can only be used with mortar-based "
482 "formulations.");
483 else if (params.isParamSetByUser("use_dual") &&
484 _formulation != ContactFormulation::MORTAR_PENALTY)
485 paramError("use_dual",
486 "The 'use_dual' option can only be used with the 'mortar' formulation");
487 else if (params.isParamSetByUser("c_normal"))
488 paramError("c_normal",
489 "The 'c_normal' option can only be used with the 'mortar' formulation");
490 else if (params.isParamSetByUser("c_tangential"))
491 paramError("c_tangential",
492 "The 'c_tangential' option can only be used with the 'mortar' formulation");
493 else if (params.isParamSetByUser("mortar_dynamics"))
494 paramError("mortar_dynamics",
495 "The 'mortar_dynamics' constraint option can only be used with the 'mortar' "
496 "formulation and in dynamic simulations using Newmark-beta");
497 else if (params.isParamSetByUser("segment_quadrature"))
498 paramError("segment_quadrature",
499 "The 'segment_quadrature' option can only be used with the "
500 "'mortar' formulation.");
501 else if (params.isParamSetByUser("lm_space"))
502 paramError("lm_space",
503 "The 'lm_space' option can only be used with the 'mortar' formulation.");
504 }
505
506 if (_formulation == ContactFormulation::RANFS)
507 {
508 if (isParamValid("secondary_gap_offset"))
509 paramError("secondary_gap_offset",
510 "The 'secondary_gap_offset' option can only be used with the "
511 "'MechanicalContactConstraint'");
512 if (isParamValid("mapped_primary_gap_offset"))
513 paramError("mapped_primary_gap_offset",
514 "The 'mapped_primary_gap_offset' option can only be used with the "
515 "'MechanicalContactConstraint'");
516 }
517 else if (getParam<bool>("ping_pong_protection"))
518 paramError("ping_pong_protection",
519 "The 'ping_pong_protection' option can only be used with the 'ranfs' formulation");
520
521 // Remove repeated pairs from input file.
523}
bool _use_dual
Whether to use the dual Mortar approach.
const bool _mortar_dynamics
Whether mortar dynamic contact constraints are to be used.
const ContactModel _model
Contact model type enum.
const ContactFormulation _formulation
Contact formulation.
void removeRepeatedPairs()
Remove repeated contact pairs from _boundary_pairs.
std::vector< BoundaryName > _automatic_pairing_boundaries
List of all possible boundaries for contact for automatic pairing (optional)
const bool _generate_mortar_mesh
Whether to generate the mortar mesh (useful in a restart simulation e.g.).
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
const ContactLMSpace _lm_space
Finite element space to use for action-generated mortar Lagrange multiplier variables.
bool isParamSetByUser(const std::string &name) const
void paramError(const std::string &param, Args... args) const
bool isParamSetByUser(const std::string &name) const
const T & getParam(const std::string &name) const
bool isParamValid(const std::string &name) const

Member Function Documentation

◆ act()

void ContactAction::act ( )
overridevirtual

Implements Action.

Definition at line 567 of file ContactAction.C.

568{
569 // proform problem checks/corrections once during the first feasible task
570 if (_current_task == "add_contact_aux_variable")
571 {
572 if (!_problem->getDisplacedProblem())
574 "Contact requires updated coordinates. Use the 'displacements = ...' parameter in the "
575 "Mesh block.");
576
577 // It is risky to apply this optimization to contact problems
578 // since the problem configuration may be changed during Jacobian
579 // evaluation. We therefore turn it off for all contact problems so that
580 // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3.
581 if (!_problem->isSNESMFReuseBaseSetbyUser())
582 _problem->setSNESMFReuseBase(false, false);
583 }
584
585 if (_formulation == ContactFormulation::MORTAR ||
586 _formulation == ContactFormulation::MORTAR_PENALTY)
588 else
590
591 if (_current_task == "add_aux_kernel")
592 {
593 if (!_problem->getDisplacedProblem())
594 mooseError("Contact requires updated coordinates. Use the 'displacements = ...' line in the "
595 "Mesh block.");
596
597 // Create auxiliary kernels for each contact pairs
598 for (const auto & contact_pair : _boundary_pairs)
599 {
600 const auto & [primary_name, secondary_name] = contact_pair;
601 if ((_formulation != ContactFormulation::MORTAR) &&
602 (_formulation != ContactFormulation::MORTAR_PENALTY))
603 {
604 InputParameters params = _factory.getValidParams("PenetrationAux");
606 {"secondary_gap_offset", "mapped_primary_gap_offset", "order"});
607
608 std::vector<VariableName> displacements =
609 getParam<std::vector<VariableName>>("displacements");
610 const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
611 .system()
612 .variable_type(displacements[0])
613 .order.get_order();
614
615 params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
616 params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR};
617 params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
618 params.set<BoundaryName>("paired_boundary") = primary_name;
619 params.set<AuxVariableName>("variable") = "penetration";
620 if (isParamValid("secondary_gap_offset"))
621 params.set<std::vector<VariableName>>("secondary_gap_offset") = {
622 getParam<VariableName>("secondary_gap_offset")};
623 if (isParamValid("mapped_primary_gap_offset"))
624 params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
625 getParam<VariableName>("mapped_primary_gap_offset")};
626 params.set<bool>("use_displaced_mesh") = true;
627 std::string name = _name + "_contact_" + Moose::stringify(contact_auxkernel_counter++);
628
629 _problem->addAuxKernel("PenetrationAux", name, params);
630 }
631 else
632 {
633 const auto type = "MortarUserObjectAux";
635 params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
636 params.set<AuxVariableName>("variable") = "gap";
637 params.set<bool>("use_displaced_mesh") = true; // Unnecessary as this object only operates
638 // on nodes, but we'll do it for consistency
639 params.set<MooseEnum>("contact_quantity") = "normal_gap";
640 const auto & [primary_id, secondary_id, uo_name] =
641 libmesh_map_find(_bnd_pair_to_mortar_info, contact_pair);
642 params.set<UserObjectName>("user_object") = uo_name;
643 std::string name = _name + "_contact_gap_" + std::to_string(primary_id) + "_" +
644 std::to_string(secondary_id);
645
646 _problem->addAuxKernel(type, name, params);
647 }
648 }
649
651
652 const unsigned int ndisp = getParam<std::vector<VariableName>>("displacements").size();
653
654 // Add MortarFrictionalPressureVectorAux
655 if (_formulation == ContactFormulation::MORTAR && _model == ContactModel::COULOMB && ndisp > 2)
656 {
657 {
658 InputParameters params = _factory.getValidParams("MortarFrictionalPressureVectorAux");
659
660 params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
661 params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
662 params.set<std::vector<BoundaryName>>("boundary") = {_boundary_pairs[0].second};
663 params.set<ExecFlagEnum>("execute_on", true) = {EXEC_NONLINEAR};
664
665 std::string action_name = MooseUtils::shortName(name());
666 const std::string tangential_lagrange_multiplier_name = action_name + "_tangential_lm";
667 const std::string tangential_lagrange_multiplier_3d_name =
668 action_name + "_tangential_3d_lm";
669
670 params.set<std::vector<VariableName>>("tangent_one") = {
671 tangential_lagrange_multiplier_name};
672 params.set<std::vector<VariableName>>("tangent_two") = {
673 tangential_lagrange_multiplier_3d_name};
674
675 std::vector<std::string> disp_components({"x", "y", "z"});
676 unsigned component_index = 0;
677
678 // Loop over three displacements
679 for (const auto & disp_component : disp_components)
680 {
681 params.set<AuxVariableName>("variable") = _name + "_tangent_" + disp_component;
682 params.set<unsigned int>("component") = component_index;
683
684 std::string name = _name + "_mortar_frictional_pressure_" + disp_component + "_" +
686
687 _problem->addAuxKernel("MortarFrictionalPressureVectorAux", name, params);
688 component_index++;
689 }
690 }
691 }
692 }
693
694 if (_current_task == "add_contact_aux_variable")
695 {
696 std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
697 const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
698 .system()
699 .variable_type(displacements[0])
700 .order.get_order();
701 const auto mortar_lm_order =
702 _lm_space == ContactLMSpace::LINEAR ? static_cast<int>(FIRST) : order;
703 std::unique_ptr<InputParameters> current_params;
704 const auto create_aux_var_params =
705 [this, order, mortar_lm_order, &current_params]() -> InputParameters &
706 {
707 current_params = std::make_unique<InputParameters>(_factory.getValidParams("MooseVariable"));
708 // Node/face and mortar-penalty contact aux variables continue to follow the displacement
709 // order. Mortar LM contact aux variables live on the same contact surface as the generated LM
710 // field, so they use the selected generated LM space.
711 const auto aux_order = _formulation == ContactFormulation::MORTAR ? mortar_lm_order : order;
712 current_params->set<MooseEnum>("order") =
713 Utility::enum_to_string<Order>(OrderWrapper{aux_order});
714 current_params->set<MooseEnum>("family") = "LAGRANGE";
715 return *current_params;
716 };
717
718 if ((_formulation != ContactFormulation::MORTAR) &&
719 (_formulation != ContactFormulation::MORTAR_PENALTY))
720 {
721 // Add penetration aux variable
722 _problem->addAuxVariable("MooseVariable", "penetration", create_aux_var_params());
723 // Add nodal area aux variable
724 _problem->addAuxVariable("MooseVariable", "nodal_area", create_aux_var_params());
725 }
726 else
727 _problem->addAuxVariable("MooseVariable", "gap", create_aux_var_params());
728
729 // Add contact pressure aux variable
730 _problem->addAuxVariable("MooseVariable", "contact_pressure", create_aux_var_params());
731
732 const unsigned int ndisp = getParam<std::vector<VariableName>>("displacements").size();
733
734 // Add MortarFrictionalPressureVectorAux variables
735 if (_formulation == ContactFormulation::MORTAR && _model == ContactModel::COULOMB && ndisp > 2)
736 {
737 {
738 std::vector<std::string> disp_components({"x", "y", "z"});
739 // Loop over three displacements
740 for (const auto & disp_component : disp_components)
741 {
742 auto var_params = _factory.getValidParams("MooseVariable");
743 var_params.set<MooseEnum>("order") =
744 Utility::enum_to_string<Order>(OrderWrapper{mortar_lm_order});
745 var_params.set<MooseEnum>("family") = "LAGRANGE";
746
747 _problem->addAuxVariable(
748 "MooseVariable", _name + "_tangent_" + disp_component, var_params);
749 }
750 }
751 }
752 }
753
754 if (_current_task == "add_user_object" && (_formulation != ContactFormulation::MORTAR) &&
755 (_formulation != ContactFormulation::MORTAR_PENALTY))
756 {
757 auto var_params = _factory.getValidParams("NodalArea");
758
759 // Get secondary_boundary_vector from possibly updated set from the
760 // ContactAction constructor cleanup
761 const auto actions = _awh.getActions<ContactAction>();
762
763 std::vector<BoundaryName> secondary_boundary_vector;
764 for (const auto * const action : actions)
765 for (const auto j : index_range(action->_boundary_pairs))
766 secondary_boundary_vector.push_back(action->_boundary_pairs[j].second);
767
768 var_params.set<std::vector<BoundaryName>>("boundary") = secondary_boundary_vector;
769 var_params.set<std::vector<VariableName>>("variable") = {"nodal_area"};
770
771 mooseAssert(_problem, "Problem pointer is NULL");
772 var_params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_TIMESTEP_BEGIN};
773 var_params.set<bool>("use_displaced_mesh") = true;
774
775 _problem->addUserObject("NodalArea",
776 "nodal_area_object_" + Moose::stringify(contact_userobject_counter++),
777 var_params);
778 }
779}
static unsigned int contact_userobject_counter
static unsigned int contact_mortar_auxkernel_counter
static unsigned int contact_auxkernel_counter
const ExecFlagType EXEC_TIMESTEP_BEGIN
const ExecFlagType EXEC_INITIAL
const ExecFlagType EXEC_LINEAR
const ExecFlagType EXEC_NONLINEAR
for(PetscInt i=0;i< nvars;++i)
std::vector< const T * > getActions()
std::shared_ptr< FEProblemBase > & _problem
const std::string & _current_task
ActionWarehouse & _awh
Action class for creating constraints, kernels, and user objects necessary for mechanical contact.
void addNodeFaceContact()
Generate constraints for node to face contact.
std::map< std::pair< BoundaryName, BoundaryName >, const MortarInfo > _bnd_pair_to_mortar_info
Map from boundary pair to mortar user object name.
void addContactPressureAuxKernel()
Add single contact pressure auxiliary kernel for various contact action objects.
void addMortarContact()
Generate mesh and other Moose objects for Mortar contact.
InputParameters getValidParams(const std::string &name) const
T & set(const std::string &name, bool quiet_mode=false)
void applyParameters(const InputParameters &common, const std::vector< std::string > &exclude={}, const bool allow_private=false)
const InputParameters & parameters() const
const std::string & type() const
const std::string & name() const
void mooseError(Args &&... args) const
const std::string & _name
Factory & _factory
std::string shortName(const std::string &name)
std::string stringify(const T &t)
auto index_range(const T &sizable)

◆ addContactPressureAuxKernel()

void ContactAction::addContactPressureAuxKernel ( )
private

Add single contact pressure auxiliary kernel for various contact action objects.

Definition at line 782 of file ContactAction.C.

783{
784 // Increment counter for contact action objects
786
787 if ((_formulation != ContactFormulation::MORTAR) &&
788 (_formulation != ContactFormulation::MORTAR_PENALTY))
789 {
790 // Add ContactPressureAux: Only one object for all contact pairs
791 const auto actions = _awh.getActions<ContactAction>();
792
793 // Add auxiliary kernel if we are the last contact action object.
794 if (contact_action_counter == actions.size())
795 {
796 std::vector<BoundaryName> boundary_vector;
797 std::vector<BoundaryName> pair_boundary_vector;
798
799 for (const auto * const action : actions)
800 for (const auto j : index_range(action->_boundary_pairs))
801 {
802 boundary_vector.push_back(action->_boundary_pairs[j].second);
803 pair_boundary_vector.push_back(action->_boundary_pairs[j].first);
804 }
805
806 InputParameters params = _factory.getValidParams("ContactPressureAux");
807 params.applyParameters(parameters(), {"order"});
808
809 std::vector<VariableName> displacements =
810 getParam<std::vector<VariableName>>("displacements");
811 const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
812 .system()
813 .variable_type(displacements[0])
814 .order.get_order();
815
816 params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
817 params.set<std::vector<BoundaryName>>("boundary") = boundary_vector;
818 params.set<std::vector<BoundaryName>>("paired_boundary") = pair_boundary_vector;
819 params.set<AuxVariableName>("variable") = "contact_pressure";
820 params.addRequiredCoupledVar("nodal_area", "The nodal area");
821 params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area"};
822 params.set<bool>("use_displaced_mesh") = true;
823
824 std::string name = _name + "_contact_pressure";
825 params.set<ExecFlagEnum>("execute_on",
827 _problem->addAuxKernel("ContactPressureAux", name, params);
828 }
829 }
830 else
831 for (const auto & contact_pair : _boundary_pairs)
832 {
833 const auto & [_, secondary_name] = contact_pair;
834 const auto type = "MortarUserObjectAux";
836 params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
837 params.set<AuxVariableName>("variable") = "contact_pressure";
838 params.set<bool>("use_displaced_mesh") = true; // Unecessary as this object only operates on
839 // nodes, but we'll do it for consistency
840 params.set<MooseEnum>("contact_quantity") = "normal_pressure";
841 const auto & [primary_id, secondary_id, uo_name] =
842 libmesh_map_find(_bnd_pair_to_mortar_info, contact_pair);
843 params.set<UserObjectName>("user_object") = uo_name;
844 const std::string name = _name + "_contact_pressure" + std::to_string(primary_id) + "_" +
845 std::to_string(secondary_id);
846
847 _problem->addAuxKernel(type, name, params);
848 }
849}
static unsigned int contact_action_counter
const ExecFlagType EXEC_TIMESTEP_END
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)

Referenced by act().

◆ addMortarContact()

void ContactAction::addMortarContact ( )
private

Generate mesh and other Moose objects for Mortar contact.

Definition at line 891 of file ContactAction.C.

892{
893 std::string action_name = MooseUtils::shortName(name());
894
895 std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
896 const unsigned int ndisp = displacements.size();
897
898 // Definitions for mortar contact.
899 const std::string primary_subdomain_name = action_name + "_primary_subdomain";
900 const std::string secondary_subdomain_name = action_name + "_secondary_subdomain";
901 const std::string normal_lagrange_multiplier_name = action_name + "_normal_lm";
902 const std::string tangential_lagrange_multiplier_name = action_name + "_tangential_lm";
903 const std::string tangential_lagrange_multiplier_3d_name = action_name + "_tangential_3d_lm";
904 const std::string auxiliary_lagrange_multiplier_name = action_name + "_aux_lm";
905
906 if (_current_task == "append_mesh_generator")
907 {
908 // Don't do mesh generators when recovering or when the user has requested for us not to
909 // (presumably because the lower-dimensional blocks are already in the mesh due to manual
910 // addition or because we are restarting)
913 {
914 const MeshGeneratorName primary_name = primary_subdomain_name + "_generator";
915 const MeshGeneratorName secondary_name = secondary_subdomain_name + "_generator";
916
917 auto primary_params = _factory.getValidParams("LowerDBlockFromSidesetGenerator");
918 auto secondary_params = _factory.getValidParams("LowerDBlockFromSidesetGenerator");
919
920 primary_params.set<SubdomainName>("new_block_name") = primary_subdomain_name;
921 secondary_params.set<SubdomainName>("new_block_name") = secondary_subdomain_name;
922
923 primary_params.set<std::vector<BoundaryName>>("sidesets") = {_boundary_pairs[0].first};
924 secondary_params.set<std::vector<BoundaryName>>("sidesets") = {_boundary_pairs[0].second};
925
926 _app.appendMeshGenerator("LowerDBlockFromSidesetGenerator", primary_name, primary_params);
927 _app.appendMeshGenerator("LowerDBlockFromSidesetGenerator", secondary_name, secondary_params);
928 }
929 }
930
931 // Add the lagrange multiplier on the secondary subdomain.
932 const auto addLagrangeMultiplier =
933 [this, &secondary_subdomain_name, &displacements](const std::string & variable_name,
934 const Real scaling_factor,
935 const bool add_aux_lm,
936 const bool penalty_traction) //
937 {
938 InputParameters params = _factory.getValidParams("MooseVariableBase");
939
940 // Allow the user to select "weighted" constraints and standard bases (use_dual = false) or
941 // "legacy" constraints and dual bases (use_dual = true). Unless it's for testing purposes,
942 // this combination isn't recommended
943 if (!add_aux_lm || penalty_traction)
944 params.set<bool>("use_dual") = _use_dual;
945
946 mooseAssert(_problem->systemBaseNonlinear(/*nl_sys_num=*/0).hasVariable(displacements[0]),
947 "Displacement variable is missing");
948 const auto primal_type =
949 _problem->systemBaseNonlinear(/*nl_sys_num=*/0).system().variable_type(displacements[0]);
950
951 // The lm_space option is only valid for the mortar Lagrange multiplier formulation. Mortar
952 // penalty traction variables continue to use the displacement order.
953 const int lm_order =
954 _formulation == ContactFormulation::MORTAR && _lm_space == ContactLMSpace::LINEAR
955 ? static_cast<int>(FIRST)
956 : primal_type.order.get_order();
957
958 if (primal_type.family == LAGRANGE)
959 {
960 params.set<MooseEnum>("family") = Utility::enum_to_string<FEFamily>(primal_type.family);
961 params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{lm_order});
962 }
963 else
964 mooseError("Invalid bases for mortar contact.");
965
966 params.set<std::vector<SubdomainName>>("block") = {secondary_subdomain_name};
967 if (!(add_aux_lm || penalty_traction))
968 params.set<std::vector<Real>>("scaling") = {scaling_factor};
969
970 auto fe_type = AddVariableAction::feType(params);
971 auto var_type = AddVariableAction::variableType(fe_type);
972 if (add_aux_lm || penalty_traction)
973 _problem->addAuxVariable(var_type, variable_name, params);
974 else
975 _problem->addVariable(var_type, variable_name, params);
976 };
977
978 if (_current_task == "add_mortar_variable" && _formulation == ContactFormulation::MORTAR)
979 {
980 addLagrangeMultiplier(
981 normal_lagrange_multiplier_name, getParam<Real>("normal_lm_scaling"), false, false);
982
983 if (_model == ContactModel::COULOMB)
984 {
985 addLagrangeMultiplier(tangential_lagrange_multiplier_name,
986 getParam<Real>("tangential_lm_scaling"),
987 false,
988 false);
989 if (ndisp > 2)
990 addLagrangeMultiplier(tangential_lagrange_multiplier_3d_name,
991 getParam<Real>("tangential_lm_scaling"),
992 false,
993 false);
994 }
995
996 if (getParam<bool>("use_petrov_galerkin"))
997 addLagrangeMultiplier(auxiliary_lagrange_multiplier_name, 1.0, true, false);
998 }
999 else if (_current_task == "add_mortar_variable" &&
1000 _formulation == ContactFormulation::MORTAR_PENALTY)
1001 {
1002 if (_use_dual)
1003 addLagrangeMultiplier(auxiliary_lagrange_multiplier_name, 1.0, false, true);
1004 }
1005
1006 if (_current_task == "add_user_object")
1007 {
1008 const auto register_mortar_uo_name = [this](const auto & bnd_pair, const auto & uo_prefix)
1009 {
1010 const auto & [primary_name, secondary_name] = bnd_pair;
1011 const auto primary_id = _mesh->getBoundaryID(primary_name);
1012 const auto secondary_id = _mesh->getBoundaryID(secondary_name);
1013 const auto uo_name = uo_prefix + name();
1014 _bnd_pair_to_mortar_info.emplace(bnd_pair, MortarInfo{primary_id, secondary_id, uo_name});
1015 return uo_name;
1016 };
1017
1018 // check if the correct problem class is selected if AL parameters are provided
1019 if (_formulation == ContactFormulation::MORTAR_PENALTY &&
1021 {
1022 const std::vector<std::string> params = {"penalty_multiplier",
1023 "penalty_multiplier_friction",
1024 "al_penetration_tolerance",
1025 "al_incremental_slip_tolerance",
1026 "al_frictional_force_tolerance"};
1027 for (const auto & param : params)
1028 if (parameters().isParamSetByUser(param))
1029 paramError(param,
1030 "Augmented Lagrange parameter was specified, but the selected problem type "
1031 "does not support Augmented Lagrange iterations.");
1032 }
1033
1034 if (_model != ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR)
1035 {
1036 auto uo_params = _factory.getValidParams("LMWeightedGapUserObject");
1037
1038 uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1039 uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1040 uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1041 uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1042 uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1043 uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1044 if (ndisp > 2)
1045 uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1046 uo_params.set<bool>("use_displaced_mesh") = true;
1047 uo_params.set<std::vector<VariableName>>("lm_variable") = {normal_lagrange_multiplier_name};
1048 uo_params.applySpecificParameters(parameters(),
1049 {"correct_edge_dropping",
1050 "triangulation",
1051 "triangulate_triangles",
1052 "minimum_projection_angle",
1053 "mortar_3d_subpatch_plane",
1054 "mortar_3d_qp_mapping",
1055 "use_petrov_galerkin",
1056 "debug_mesh"});
1057 if (getParam<bool>("use_petrov_galerkin"))
1058 uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
1059
1060 _problem->addUserObject("LMWeightedGapUserObject",
1061 register_mortar_uo_name(_boundary_pairs[0], "lm_weightedgap_object_"),
1062 uo_params);
1063 }
1064 else if (_model == ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR)
1065 {
1066 auto uo_params = _factory.getValidParams("LMWeightedVelocitiesUserObject");
1067 uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1068 uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1069 uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1070 uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1071 uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1072 uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1073 if (ndisp > 2)
1074 uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1075
1076 uo_params.set<VariableName>("secondary_variable") = displacements[0];
1077 uo_params.set<bool>("use_displaced_mesh") = true;
1078 uo_params.set<std::vector<VariableName>>("lm_variable_normal") = {
1079 normal_lagrange_multiplier_name};
1080 uo_params.set<std::vector<VariableName>>("lm_variable_tangential_one") = {
1081 tangential_lagrange_multiplier_name};
1082 if (ndisp > 2)
1083 uo_params.set<std::vector<VariableName>>("lm_variable_tangential_two") = {
1084 tangential_lagrange_multiplier_3d_name};
1085 uo_params.applySpecificParameters(parameters(),
1086 {"correct_edge_dropping",
1087 "triangulation",
1088 "triangulate_triangles",
1089 "minimum_projection_angle",
1090 "mortar_3d_subpatch_plane",
1091 "mortar_3d_qp_mapping",
1092 "use_petrov_galerkin",
1093 "debug_mesh"});
1094 if (getParam<bool>("use_petrov_galerkin"))
1095 uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
1096
1097 const auto uo_name = _problem->addUserObject(
1098 "LMWeightedVelocitiesUserObject",
1099 register_mortar_uo_name(_boundary_pairs[0], "lm_weightedvelocities_object_"),
1100 uo_params);
1101 }
1102
1103 if (_model != ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR_PENALTY)
1104 {
1105 auto uo_params = _factory.getValidParams("PenaltyWeightedGapUserObject");
1106
1107 uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1108 uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1109 uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1110 uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1111 uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1112 uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1113
1114 // AL parameters
1115 uo_params.applySpecificParameters(parameters(),
1116 {"correct_edge_dropping",
1117 "triangulation",
1118 "triangulate_triangles",
1119 "minimum_projection_angle",
1120 "mortar_3d_subpatch_plane",
1121 "mortar_3d_qp_mapping",
1122 "penalty",
1123 "debug_mesh",
1124 "max_penalty_multiplier",
1125 "adaptivity_penalty_normal"});
1126
1127 if (isParamValid("al_penetration_tolerance"))
1128 uo_params.set<Real>("penetration_tolerance") = getParam<Real>("al_penetration_tolerance");
1129 if (isParamValid("penalty_multiplier"))
1130 uo_params.set<Real>("penalty_multiplier") = getParam<Real>("penalty_multiplier");
1131 // In the contact action, we force the physical value of the normal gap, which also normalizes
1132 // the penalty factor with the "area" around the node
1133 uo_params.set<bool>("use_physical_gap") = true;
1134
1135 if (_use_dual)
1136 uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
1137
1138 if (ndisp > 2)
1139 uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1140 uo_params.set<bool>("use_displaced_mesh") = true;
1141
1142 _problem->addUserObject(
1143 "PenaltyWeightedGapUserObject",
1144 register_mortar_uo_name(_boundary_pairs[0], "penalty_weightedgap_object_"),
1145 uo_params);
1146 _problem->haveADObjects(true);
1147 }
1148 else if (_model == ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR_PENALTY)
1149 {
1150 auto uo_params = _factory.getValidParams("PenaltyFrictionUserObject");
1151 uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1152 uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1153 uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1154 uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1155 uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1156 uo_params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
1157 uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1158 if (ndisp > 2)
1159 uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1160
1161 uo_params.set<VariableName>("secondary_variable") = displacements[0];
1162 uo_params.set<bool>("use_displaced_mesh") = true;
1163 uo_params.set<Real>("friction_coefficient") = getParam<Real>("friction_coefficient");
1164 uo_params.set<Real>("penalty") = getParam<Real>("penalty");
1165 uo_params.set<Real>("penalty_friction") = getParam<Real>("penalty_friction");
1166
1167 // AL parameters
1168 uo_params.set<Real>("max_penalty_multiplier") = getParam<Real>("max_penalty_multiplier");
1169 uo_params.set<MooseEnum>("adaptivity_penalty_normal") =
1170 getParam<MooseEnum>("adaptivity_penalty_normal");
1171 uo_params.set<MooseEnum>("adaptivity_penalty_friction") =
1172 getParam<MooseEnum>("adaptivity_penalty_friction");
1173 if (isParamValid("al_penetration_tolerance"))
1174 uo_params.set<Real>("penetration_tolerance") = getParam<Real>("al_penetration_tolerance");
1175 if (isParamValid("penalty_multiplier"))
1176 uo_params.set<Real>("penalty_multiplier") = getParam<Real>("penalty_multiplier");
1177 if (isParamValid("penalty_multiplier_friction"))
1178 uo_params.set<Real>("penalty_multiplier_friction") =
1179 getParam<Real>("penalty_multiplier_friction");
1180
1181 if (isParamValid("al_incremental_slip_tolerance"))
1182 uo_params.set<Real>("slip_tolerance") = getParam<Real>("al_incremental_slip_tolerance");
1183 // In the contact action, we force the physical value of the normal gap, which also normalizes
1184 // the penalty factor with the "area" around the node
1185 uo_params.set<bool>("use_physical_gap") = true;
1186
1187 if (_use_dual)
1188 uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
1189
1190 uo_params.applySpecificParameters(parameters(),
1191 {"triangulation",
1192 "triangulate_triangles",
1193 "minimum_projection_angle",
1194 "mortar_3d_subpatch_plane",
1195 "mortar_3d_qp_mapping",
1196 "friction_coefficient",
1197 "penalty",
1198 "penalty_friction"});
1199
1200 _problem->addUserObject(
1201 "PenaltyFrictionUserObject",
1202 register_mortar_uo_name(_boundary_pairs[0], "penalty_friction_object_"),
1203 uo_params);
1204 _problem->haveADObjects(true);
1205 }
1206 }
1207
1208 if (_current_task == "add_constraint")
1209 {
1210 // Prepare problem for enforcement with Lagrange multipliers
1211 if (_model != ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR)
1212 {
1213 std::string mortar_constraint_name;
1214
1215 if (!_mortar_dynamics)
1216 mortar_constraint_name = "ComputeWeightedGapLMMechanicalContact";
1217 else
1218 mortar_constraint_name = "ComputeDynamicWeightedGapLMMechanicalContact";
1219
1220 InputParameters params = _factory.getValidParams(mortar_constraint_name);
1221 if (_mortar_dynamics)
1223 parameters(), {"newmark_beta", "newmark_gamma", "capture_tolerance", "wear_depth"});
1224
1225 else // We need user objects for quasistatic constraints
1226 params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedgap_object_" + name();
1227
1228 params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1229 params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1230 params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1231 params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1232 params.set<NonlinearVariableName>("variable") = normal_lagrange_multiplier_name;
1233 params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1234 params.set<Real>("c") = getParam<Real>("c_normal");
1235
1236 if (ndisp > 1)
1237 params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1238 if (ndisp > 2)
1239 params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1240
1241 params.set<bool>("use_displaced_mesh") = true;
1242
1244 {"correct_edge_dropping",
1245 "triangulation",
1246 "triangulate_triangles",
1247 "minimum_projection_angle",
1248 "mortar_3d_subpatch_plane",
1249 "mortar_3d_qp_mapping",
1250 "normalize_c",
1251 "extra_vector_tags",
1252 "absolute_value_vector_tags",
1253 "debug_mesh"});
1254
1255 _problem->addConstraint(
1256 mortar_constraint_name, action_name + "_normal_lm_weighted_gap", params);
1257 _problem->haveADObjects(true);
1258 }
1259 // Add the tangential and normal Lagrange's multiplier constraints on the secondary boundary.
1260 else if (_model == ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR)
1261 {
1262 std::string mortar_constraint_name;
1263
1264 if (!_mortar_dynamics)
1265 mortar_constraint_name = "ComputeFrictionalForceLMMechanicalContact";
1266 else
1267 mortar_constraint_name = "ComputeDynamicFrictionalForceLMMechanicalContact";
1268
1269 InputParameters params = _factory.getValidParams(mortar_constraint_name);
1270 if (_mortar_dynamics)
1272 parameters(), {"newmark_beta", "newmark_gamma", "capture_tolerance", "wear_depth"});
1273 else
1274 { // We need user objects for quasistatic constraints
1275 params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedvelocities_object_" + name();
1276 params.set<UserObjectName>("weighted_velocities_uo") =
1277 "lm_weightedvelocities_object_" + name();
1278 }
1279
1280 params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
1281 params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1282 params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1283 params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1284 params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1285 params.set<bool>("use_displaced_mesh") = true;
1286 params.set<Real>("c_t") = getParam<Real>("c_tangential");
1287 params.set<Real>("c") = getParam<Real>("c_normal");
1288 params.set<bool>("normalize_c") = getParam<bool>("normalize_c");
1289 params.set<bool>("compute_primal_residuals") = false;
1290
1291 params.set<MooseEnum>("segment_quadrature") = getParam<MooseEnum>("segment_quadrature");
1292
1293 params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1294
1295 if (ndisp > 1)
1296 params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1297 if (ndisp > 2)
1298 params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1299
1300 params.set<NonlinearVariableName>("variable") = normal_lagrange_multiplier_name;
1301 params.set<std::vector<VariableName>>("friction_lm") = {tangential_lagrange_multiplier_name};
1302
1303 if (ndisp > 2)
1304 params.set<std::vector<VariableName>>("friction_lm_dir") = {
1305 tangential_lagrange_multiplier_3d_name};
1306
1307 params.set<Real>("mu") = getParam<Real>("friction_coefficient");
1309 {"triangulation",
1310 "triangulate_triangles",
1311 "minimum_projection_angle",
1312 "mortar_3d_subpatch_plane",
1313 "mortar_3d_qp_mapping",
1314 "extra_vector_tags",
1315 "absolute_value_vector_tags",
1316 "debug_mesh"});
1317
1318 _problem->addConstraint(mortar_constraint_name, action_name + "_tangential_lm", params);
1319 _problem->haveADObjects(true);
1320 }
1321
1322 const auto addMechanicalContactConstraints =
1323 [this, &primary_subdomain_name, &secondary_subdomain_name, &displacements](
1324 const std::string & variable_name,
1325 const std::string & constraint_prefix,
1326 const std::string & constraint_type,
1327 const bool is_additional_frictional_constraint,
1328 const bool is_normal_constraint)
1329 {
1330 InputParameters params = _factory.getValidParams(constraint_type);
1331
1332 params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
1333 params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1334 params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1335 params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1336 params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1337
1338 if (_formulation == ContactFormulation::MORTAR)
1339 params.set<NonlinearVariableName>("variable") = variable_name;
1340
1341 params.set<MooseEnum>("segment_quadrature") = getParam<MooseEnum>("segment_quadrature");
1342 params.set<bool>("use_displaced_mesh") = true;
1343 params.set<bool>("compute_lm_residuals") = false;
1344
1345 // Additional displacement residual for frictional problem
1346 // The second frictional LM acts on a perpendicular direction.
1347 if (is_additional_frictional_constraint)
1348 params.set<MooseEnum>("direction") = "direction_2";
1350 {"triangulation",
1351 "triangulate_triangles",
1352 "minimum_projection_angle",
1353 "mortar_3d_subpatch_plane",
1354 "mortar_3d_qp_mapping",
1355 "extra_vector_tags",
1356 "absolute_value_vector_tags",
1357 "debug_mesh"});
1358
1359 for (unsigned int i = 0; i < displacements.size(); ++i)
1360 {
1361 std::string constraint_name = constraint_prefix + Moose::stringify(i);
1362
1363 params.set<VariableName>("secondary_variable") = displacements[i];
1364 params.set<MooseEnum>("component") = i;
1365
1366 if (is_normal_constraint && _model != ContactModel::COULOMB &&
1367 _formulation == ContactFormulation::MORTAR)
1368 params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedgap_object_" + name();
1369 else if (is_normal_constraint && _model == ContactModel::COULOMB &&
1370 _formulation == ContactFormulation::MORTAR)
1371 params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedvelocities_object_" + name();
1372 else if (_formulation == ContactFormulation::MORTAR)
1373 params.set<UserObjectName>("weighted_velocities_uo") =
1374 "lm_weightedvelocities_object_" + name();
1375 else if (is_normal_constraint && _model != ContactModel::COULOMB &&
1376 _formulation == ContactFormulation::MORTAR_PENALTY)
1377 params.set<UserObjectName>("weighted_gap_uo") = "penalty_weightedgap_object_" + name();
1378 else if (is_normal_constraint && _model == ContactModel::COULOMB &&
1379 _formulation == ContactFormulation::MORTAR_PENALTY)
1380 params.set<UserObjectName>("weighted_gap_uo") = "penalty_friction_object_" + name();
1381 else if (_formulation == ContactFormulation::MORTAR_PENALTY)
1382 params.set<UserObjectName>("weighted_velocities_uo") =
1383 "penalty_friction_object_" + name();
1384
1385 _problem->addConstraint(constraint_type, constraint_name, params);
1386 }
1387 _problem->haveADObjects(true);
1388 };
1389
1390 // Add mortar mechanical contact constraint objects for primal variables
1391 addMechanicalContactConstraints(normal_lagrange_multiplier_name,
1392 action_name + "_normal_constraint_",
1393 "NormalMortarMechanicalContact",
1394 /* is_additional_frictional_constraint = */ false,
1395 /* is_normal_constraint = */ true);
1396
1397 if (_model == ContactModel::COULOMB)
1398 {
1399 addMechanicalContactConstraints(tangential_lagrange_multiplier_name,
1400 action_name + "_tangential_constraint_",
1401 "TangentialMortarMechanicalContact",
1402 /* is_additional_frictional_constraint = */ false,
1403 /* is_normal_constraint = */ false);
1404 if (ndisp > 2)
1405 addMechanicalContactConstraints(tangential_lagrange_multiplier_3d_name,
1406 action_name + "_tangential_constraint_3d_",
1407 "TangentialMortarMechanicalContact",
1408 /* is_additional_frictional_constraint = */ true,
1409 /* is_normal_constraint = */ false);
1410 }
1411 }
1412}
std::shared_ptr< MooseMesh > & _mesh
MooseApp & _app
static libMesh::FEType feType(const InputParameters &params)
static std::string variableType(const libMesh::FEType &fe_type, const bool is_fv=false, const bool is_array=false)
Class to provide an interface for parameters and routines required to check convergence for the augme...
void applySpecificParameters(const InputParameters &common, const std::vector< std::string > &include, bool allow_private=false)
bool isUltimateMaster() const
const MeshGenerator & appendMeshGenerator(const std::string &type, const std::string &name, InputParameters params)
bool isRecovering() const
bool useMasterMesh() const
if(subdm)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

Referenced by act().

◆ addNodeFaceContact()

void ContactAction::addNodeFaceContact ( )
private

Generate constraints for node to face contact.

Definition at line 1415 of file ContactAction.C.

1416{
1417 if (_current_task == "post_mesh_prepared" && _automatic_pairing_boundaries.size() > 0)
1418 {
1419 if (getParam<MooseEnum>("automatic_pairing_method").getEnum<ProximityMethod>() ==
1420 ProximityMethod::NODE)
1422 else if (getParam<MooseEnum>("automatic_pairing_method").getEnum<ProximityMethod>() ==
1423 ProximityMethod::CENTROID)
1425 }
1426
1427 if (_current_task != "add_constraint")
1428 return;
1429
1430 std::string action_name = MooseUtils::shortName(name());
1431 std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
1432 const unsigned int ndisp = displacements.size();
1433
1434 std::string constraint_type;
1435
1436 if (_formulation == ContactFormulation::RANFS)
1437 constraint_type = "RANFSNormalMechanicalContact";
1438 else
1439 constraint_type = "MechanicalContactConstraint";
1440
1441 InputParameters params = _factory.getValidParams(constraint_type);
1442
1443 params.applyParameters(parameters(),
1444 {"displacements",
1445 "secondary_gap_offset",
1446 "mapped_primary_gap_offset",
1447 "primary",
1448 "secondary"});
1449
1450 const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
1451 .system()
1452 .variable_type(displacements[0])
1453 .order.get_order();
1454
1455 params.set<std::vector<VariableName>>("displacements") = displacements;
1456 params.set<bool>("use_displaced_mesh") = true;
1457 params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
1458
1459 for (const auto & contact_pair : _boundary_pairs)
1460 {
1461 if (_formulation != ContactFormulation::RANFS)
1462 {
1463 params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area"};
1464 params.set<BoundaryName>("boundary") = contact_pair.first;
1465 if (isParamValid("secondary_gap_offset"))
1466 params.set<std::vector<VariableName>>("secondary_gap_offset") = {
1467 getParam<VariableName>("secondary_gap_offset")};
1468 if (isParamValid("mapped_primary_gap_offset"))
1469 params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
1470 getParam<VariableName>("mapped_primary_gap_offset")};
1471 }
1472
1473 for (unsigned int i = 0; i < ndisp; ++i)
1474 {
1475 std::string name = action_name + "_constraint_" + Moose::stringify(contact_pair, "_") + "_" +
1477
1478 if (_formulation == ContactFormulation::RANFS)
1479 params.set<MooseEnum>("component") = i;
1480 else
1481 params.set<unsigned int>("component") = i;
1482
1483 params.set<BoundaryName>("primary") = contact_pair.first;
1484 params.set<BoundaryName>("secondary") = contact_pair.second;
1485 params.set<NonlinearVariableName>("variable") = displacements[i];
1486 params.set<std::vector<VariableName>>("primary_variable") = {displacements[i]};
1488 {"extra_vector_tags", "absolute_value_vector_tags"});
1489 _problem->addConstraint(constraint_type, name, params);
1490 }
1491 }
1492}
void createSidesetPairsFromGeometry()
Create contact pairs between all boundaries whose centroids are within a user-specified distance of e...
void createSidesetsFromNodeProximity()
Create contact pairs between all boundaries by determining that nodes on both boundaries are close en...

Referenced by act().

◆ addRelationshipManagers() [1/3]

void ContactAction::addRelationshipManagers ( Moose::RelationshipManagerType  input_rm_type)
overridevirtual

Reimplemented from Action.

Definition at line 852 of file ContactAction.C.

853{
854 if (_formulation == ContactFormulation::MORTAR ||
855 _formulation == ContactFormulation::MORTAR_PENALTY)
856 {
857 auto params = MortarConstraintBase::validParams();
858 params.set<bool>("use_displaced_mesh") = true;
859 std::string action_name = MooseUtils::shortName(name());
860 const std::string primary_subdomain_name = action_name + "_primary_subdomain";
861 const std::string secondary_subdomain_name = action_name + "_secondary_subdomain";
862 params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
863 params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
864 params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
865 params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
866 params.set<bool>("use_petrov_galerkin") = getParam<bool>("use_petrov_galerkin");
867 params.set<Real>("minimum_projection_angle") = getParam<Real>("minimum_projection_angle");
868 params.set<MooseEnum>("mortar_3d_subpatch_plane") =
869 getParam<MooseEnum>("mortar_3d_subpatch_plane");
870 addRelationshipManagers(input_rm_type, params);
871 }
872 else
873 {
874 const std::string constraint_type = _formulation == ContactFormulation::RANFS
875 ? "RANFSNormalMechanicalContact"
876 : "MechanicalContactConstraint";
877
878 for (const auto & contact_pair : _boundary_pairs)
879 {
880 auto params = _factory.getValidParams(constraint_type);
881 params.set<bool>("use_displaced_mesh") = true;
882 params.set<bool>("ghost_whole_interface") = getParam<bool>("ghost_whole_interface");
883 params.set<BoundaryName>("primary") = contact_pair.first;
884 params.set<BoundaryName>("secondary") = contact_pair.second;
885 addRelationshipManagers(input_rm_type, params);
886 }
887 }
888}
virtual void addRelationshipManagers(Moose::RelationshipManagerType input_rm_type) override
static InputParameters validParams()

Referenced by addRelationshipManagers().

◆ addRelationshipManagers() [2/3]

virtual void Action::addRelationshipManagers ( Moose::RelationshipManagerType  when_type)
virtual

Reimplemented from Action.

◆ addRelationshipManagers() [3/3]

bool Action::addRelationshipManagers ( Moose::RelationshipManagerType  when_type,
const InputParameters moose_object_pars 
)

◆ commonParameters()

InputParameters ContactAction::commonParameters ( )
static

Define parameters used by multiple contact objects.

Returns
InputParameters object populated with common parameters

Definition at line 1829 of file ContactAction.C.

1830{
1832
1833 params.addParam<MooseEnum>("normal_smoothing_method",
1835 "Method to use to smooth normals");
1836 params.addParam<Real>(
1837 "normal_smoothing_distance",
1838 "Distance from edge in parametric coordinates over which to smooth contact normal");
1839
1840 params.addParam<MooseEnum>(
1841 "formulation", ContactAction::getFormulationEnum(), "The contact formulation");
1842
1843 params.addParam<MooseEnum>("model", ContactAction::getModelEnum(), "The contact model to use");
1844
1845 return params;
1846}
InputParameters emptyInputParameters()
static MooseEnum getFormulationEnum()
Get contact formulation.
static MooseEnum getModelEnum()
Get contact model.
static MooseEnum getSmoothingEnum()
Get smoothing type.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)

Referenced by validParams(), and MechanicalContactConstraint::validParams().

◆ createSidesetPairsFromGeometry()

void ContactAction::createSidesetPairsFromGeometry ( )
private

Create contact pairs between all boundaries whose centroids are within a user-specified distance of each other.

Definition at line 1642 of file ContactAction.C.

1643{
1644 mooseInfo("The contact action is reading the list of boundaries and automatically pairs them "
1645 "if their centroids fall within a specified distance of each other.");
1646
1647 if (!_mesh)
1648 mooseError("Failed to obtain mesh for automatically generating contact pairs.");
1649
1650 if (!_mesh->getMesh().is_serial())
1651 paramError(
1652 "automatic_pairing_boundaries",
1653 "The generation of automatic contact pairs in the contact action requires a serial mesh.");
1654
1655 // Compute centers of gravity for each sideset
1656 std::vector<std::pair<BoundaryName, Point>> automatic_pairing_boundaries_cog;
1657 const auto & sideset_ids = _mesh->meshSidesetIds();
1658
1659 const auto & bnd_to_elem_map = _mesh->getBoundariesToActiveSemiLocalElemIds();
1660
1661 for (const auto & sideset_name : _automatic_pairing_boundaries)
1662 {
1663 // If the sideset provided in the input file isn't in the mesh, error out.
1664 const auto find_set = sideset_ids.find(_mesh->getBoundaryID(sideset_name));
1665 if (find_set == sideset_ids.end())
1666 paramError("automatic_pairing_boundaries",
1667 sideset_name,
1668 " is not defined as a sideset in the mesh.");
1669
1670 auto dofs_set = bnd_to_elem_map.find(_mesh->getBoundaryID(sideset_name));
1671
1672 // Initialize data for sideset
1673 Point center_of_gravity(0, 0, 0);
1674 Real accumulated_sideset_area(0);
1675
1676 // Pointer to lower-dimensional element on the sideset
1677 std::unique_ptr<const Elem> side_ptr;
1678 const std::unordered_set<dof_id_type> & bnd_elems = dofs_set->second;
1679
1680 for (auto elem_id : bnd_elems)
1681 {
1682 const Elem * elem = _mesh->elemPtr(elem_id);
1683 unsigned int side = _mesh->sideWithBoundaryID(elem, _mesh->getBoundaryID(sideset_name));
1684
1685 // update side_ptr
1686 elem->side_ptr(side_ptr, side);
1687
1688 // area of the (linearized) side
1689 const auto side_area = side_ptr->volume();
1690
1691 // position of the side
1692 const auto side_position = side_ptr->true_centroid();
1693
1694 center_of_gravity += side_position * side_area;
1695 accumulated_sideset_area += side_area;
1696 }
1697
1698 // Average each element's center of gravity (centroid) with its area
1699 center_of_gravity /= accumulated_sideset_area;
1700
1701 // Add sideset-cog pair to vector
1702 automatic_pairing_boundaries_cog.emplace_back(sideset_name, center_of_gravity);
1703 }
1704
1705 // Vectors of distances for each pair
1706 std::vector<std::pair<std::pair<BoundaryName, BoundaryName>, Real>> pairs_distances;
1707
1708 // Assign distances to identify nearby pairs.
1709 for (std::size_t i = 0; i < automatic_pairing_boundaries_cog.size() - 1; i++)
1710 for (std::size_t j = i + 1; j < automatic_pairing_boundaries_cog.size(); j++)
1711 {
1712 const Point & distance_vector =
1713 automatic_pairing_boundaries_cog[i].second - automatic_pairing_boundaries_cog[j].second;
1714
1715 if (automatic_pairing_boundaries_cog[i].first != automatic_pairing_boundaries_cog[j].first)
1716 {
1717 const Real distance = distance_vector.norm();
1718 const std::pair pair = std::make_pair(automatic_pairing_boundaries_cog[i].first,
1719 automatic_pairing_boundaries_cog[j].first);
1720 pairs_distances.emplace_back(std::make_pair(pair, distance));
1721 }
1722 }
1723
1724 const auto automatic_pairing_distance = getParam<Real>("automatic_pairing_distance");
1725
1726 // Loop over all pairs
1727 std::vector<std::pair<std::pair<BoundaryName, BoundaryName>, Real>> lean_pairs_distances;
1728 for (const auto & pair_distance : pairs_distances)
1729 if (pair_distance.second <= automatic_pairing_distance)
1730 {
1731 lean_pairs_distances.emplace_back(pair_distance);
1732 mooseInfoRepeated("Generating contact pair primary--secondary ",
1733 pair_distance.first.first,
1734 "--",
1735 pair_distance.first.second,
1736 ", with a relative distance of ",
1737 pair_distance.second);
1738 }
1739
1740 // Create the boundary pairs (possibly with repeated pairs depending on user input)
1741 for (const auto & lean_pairs_distance : lean_pairs_distances)
1742 {
1743 // Make sure secondary surface's boundary ID is less than primary surface's boundary ID.
1744 // This is done to ensure some consistency in the boundary matching, which helps in defining
1745 // auxiliary kernels in the input file.
1746 if (_mesh->getBoundaryID(lean_pairs_distance.first.first) >
1747 _mesh->getBoundaryID(lean_pairs_distance.first.second))
1748 _boundary_pairs.push_back(
1749 {lean_pairs_distance.first.first, lean_pairs_distance.first.second});
1750 else
1751 _boundary_pairs.push_back(
1752 {lean_pairs_distance.first.second, lean_pairs_distance.first.first});
1753 }
1754
1755 // Let's remove possibly repeated pairs
1757}
void mooseInfoRepeated(Args &&... args)
void mooseInfo(Args &&... args) const
Real distance(const Point &p)

Referenced by addNodeFaceContact().

◆ createSidesetsFromNodeProximity()

void ContactAction::createSidesetsFromNodeProximity ( )
private

Create contact pairs between all boundaries by determining that nodes on both boundaries are close enough.

Definition at line 1504 of file ContactAction.C.

1505{
1506 mooseInfo("The contact action is reading the list of boundaries and automatically pairs them "
1507 "if the distance between nodes is less than a specified distance.");
1508
1509 if (!_mesh)
1510 mooseError("Failed to obtain mesh for automatically generating contact pairs.");
1511
1512 if (!_mesh->getMesh().is_serial())
1513 paramError(
1514 "automatic_pairing_boundaries",
1515 "The generation of automatic contact pairs in the contact action requires a serial mesh.");
1516
1517 // Create automatic_pairing_boundaries_id
1518 std::vector<BoundaryID> _automatic_pairing_boundaries_id;
1519 for (const auto & sideset_name : _automatic_pairing_boundaries)
1520 _automatic_pairing_boundaries_id.emplace_back(_mesh->getBoundaryID(sideset_name));
1521
1522 // Vector of pairs node-boundary id
1523 std::vector<NodeBoundaryIDInfo> node_boundary_id_vector;
1524
1525 // Data structures to hold the boundary nodes
1526 const ConstBndNodeRange & bnd_nodes = *_mesh->getBoundaryNodeRange();
1527
1528 for (const auto & bnode : bnd_nodes)
1529 {
1530 const BoundaryID boundary_id = bnode->_bnd_id;
1531 const Node * node_ptr = bnode->_node;
1532
1533 // Make sure node is on a boundary chosen for contact mechanics
1534 auto it = std::find(_automatic_pairing_boundaries_id.begin(),
1535 _automatic_pairing_boundaries_id.end(),
1536 boundary_id);
1537
1538 if (it != _automatic_pairing_boundaries_id.end())
1539 node_boundary_id_vector.emplace_back(node_ptr, boundary_id);
1540 }
1541
1542 // sort by increasing boundary id
1543 std::sort(node_boundary_id_vector.begin(),
1544 node_boundary_id_vector.end(),
1545 [](const NodeBoundaryIDInfo & first_pair, const NodeBoundaryIDInfo & second_pair)
1546 { return first_pair.second < second_pair.second; });
1547
1548 // build kd-tree
1549 using KDTreeType = nanoflann::KDTreeSingleIndexAdaptor<
1550 nanoflann::L2_Simple_Adaptor<Real, PointListAdaptor<NodeBoundaryIDInfo>, Real, std::size_t>,
1552 LIBMESH_DIM,
1553 std::size_t>;
1554
1555 // This parameter can be tuned. Others use '10'
1556 const unsigned int max_leaf_size = 20;
1557
1558 // Build point list adaptor with all nodes-sidesets pairs for possible mechanical contact
1559 auto point_list = PointListAdaptor<NodeBoundaryIDInfo>(node_boundary_id_vector.begin(),
1560 node_boundary_id_vector.end());
1561 auto kd_tree = std::make_unique<KDTreeType>(
1562 LIBMESH_DIM, point_list, nanoflann::KDTreeSingleIndexAdaptorParams(max_leaf_size));
1563
1564 if (!kd_tree)
1565 mooseError("Internal error. KDTree was not properly initialized in the contact action.");
1566
1567 kd_tree->buildIndex();
1568
1569 // data structures for kd-tree search
1570 nanoflann::SearchParameters search_params;
1571 std::vector<nanoflann::ResultItem<std::size_t, Real>> ret_matches;
1572
1573 const auto radius_for_search = getParam<Real>("automatic_pairing_distance");
1574
1575 // For all nodes
1576 for (const auto & pair : node_boundary_id_vector)
1577 {
1578 // clear result buffer
1579 ret_matches.clear();
1580
1581 // position where we expect a periodic partner for the current node and boundary
1582 const Point search_point = *pair.first;
1583
1584 // search at the expected point
1585 kd_tree->radiusSearch(
1586 &(search_point)(0), radius_for_search * radius_for_search, ret_matches, search_params);
1587
1588 for (auto & match_pair : ret_matches)
1589 {
1590 const auto & match = node_boundary_id_vector[match_pair.first];
1591
1592 //
1593 // If the proximity node identified belongs to a boundary in the input, add boundary pair
1594 //
1595
1596 // Make sure node is on a boundary chosen for contact mechanics
1597 auto it = std::find(_automatic_pairing_boundaries_id.begin(),
1598 _automatic_pairing_boundaries_id.end(),
1599 match.second);
1600
1601 // If nodes are on the same boundary, pass.
1602 if (match.second == pair.second)
1603 continue;
1604
1605 // At this point we will likely create many repeated pairs because many nodal pairs may
1606 // fulfill the distance condition imposed by the automatic_pairing_distance user input
1607 // parameter.
1608 if (it != _automatic_pairing_boundaries_id.end())
1609 {
1610 const auto index_one = cast_int<int>(it - _automatic_pairing_boundaries_id.begin());
1611 auto it_other = std::find(_automatic_pairing_boundaries_id.begin(),
1612 _automatic_pairing_boundaries_id.end(),
1613 pair.second);
1614
1615 mooseAssert(it_other != _automatic_pairing_boundaries_id.end(),
1616 "Error in contact action. Unable to find boundary ID for node proximity "
1617 "automatic pairing.");
1618
1619 const auto index_two = cast_int<int>(it_other - _automatic_pairing_boundaries_id.begin());
1620
1621 if (pair.second > match.second)
1622 _boundary_pairs.push_back(
1624 else
1625 _boundary_pairs.push_back(
1627 }
1628 }
1629 }
1630
1631 // Let's remove likely repeated pairs
1633
1634 mooseInfo(
1635 "The following boundary pairs were created by the contact action using nodal proximity: ");
1636 for (const auto & [primary, secondary] : _boundary_pairs)
1638 "Primary boundary ID: ", primary, " and secondary boundary ID: ", secondary, ".");
1639}
boundary_id_type BoundaryID
std::pair< const Node *, BoundaryID > NodeBoundaryIDInfo
BoundaryID getBoundaryID(const BoundaryName &boundary_name, const MeshBase &mesh)
SearchParams SearchParameters

Referenced by addNodeFaceContact().

◆ getFormulationEnum()

MooseEnum ContactAction::getFormulationEnum ( )
static

Get contact formulation.

Returns
enum

Definition at line 1772 of file ContactAction.C.

1773{
1774 auto formulations = MooseEnum(getContactFormulationOptions(), "kinematic");
1775
1776 formulations.addDocumentation(
1777 "ranfs",
1778 "Reduced Active Nonlinear Function Set scheme for node-on-face contact. Provides exact "
1779 "enforcement without Lagrange multipliers or penalty terms.");
1780 formulations.addDocumentation(
1781 "kinematic",
1782 "Kinematic contact constraint enforcement transfers the internal forces at secondary nodes "
1783 "to the corresponding primary face for node-on-face contact. Provides exact "
1784 "enforcement without Lagrange multipliers or penalty terms.");
1785 formulations.addDocumentation(
1786 "penalty",
1787 "Node-on-face penalty based contact constraint enforcement. Interpenetration is penalized. "
1788 "Enforcement depends on the penalty magnitude. High penalties can introduce ill conditioning "
1789 "of the system.");
1790 formulations.addDocumentation("augmented_lagrange",
1791 "Node-on-face augmented Lagrange penalty based contact constraint "
1792 "enforcement. Interpenetration is enforced up to a user specified "
1793 "tolerance, ill-conditioning is generally avoided. Requires an "
1794 "Augmented Lagrange Problem class to be used in the simulation.");
1795 formulations.addDocumentation(
1796 "tangential_penalty",
1797 "Node-on-face penalty based frictional contact constraint enforcement. Interpenetration and "
1798 "slip distance for sticking nodes are penalized. Enforcement depends on the penalty "
1799 "magnitudes. High penalties can introduce ill conditioning of the system.");
1800 formulations.addDocumentation(
1801 "mortar",
1802 "Mortar based contact constraint enforcement using Lagrange multipliers. Provides exact "
1803 "enforcement and a variationally consistent formulation. Lagrange multipliers introduce a "
1804 "saddle point character in the system matrix which can have a negative impact on scalability "
1805 "with iterative solvers");
1806 formulations.addDocumentation(
1807 "mortar_penalty",
1808 "Mortar and penalty based contact constraint enforcement. When using an Augmented Lagrange "
1809 "Problem class this provides normal (and tangential) contact constratint enforced up to a "
1810 "user specified tolerances. Without AL the enforcement depends on the penalty magnitudes. "
1811 "High penalties can introduce ill conditioning of the system.");
1812
1813 return formulations;
1814}

Referenced by commonParameters().

◆ getModelEnum()

MooseEnum ContactAction::getModelEnum ( )
static

Get contact model.

Returns
enum

Definition at line 1760 of file ContactAction.C.

1761{
1762 return MooseEnum(getContactModelOptions(), "frictionless");
1763}

Referenced by commonParameters(), and validParams().

◆ getProximityMethod()

MooseEnum ContactAction::getProximityMethod ( )
static

Get proximity method for automatic pairing.

Returns
enum

Definition at line 1766 of file ContactAction.C.

1767{
1768 return MooseEnum(getProximityMethodOptions());
1769}

Referenced by validParams().

◆ getSmoothingEnum()

MooseEnum ContactAction::getSmoothingEnum ( )
static

Get smoothing type.

Returns
enum

Definition at line 1823 of file ContactAction.C.

1824{
1825 return MooseEnum("edge_based nodal_normal_based", "");
1826}

Referenced by commonParameters().

◆ getSystemEnum()

MooseEnum ContactAction::getSystemEnum ( )
static

Get contact system.

Returns
enum

Definition at line 1817 of file ContactAction.C.

1818{
1819 return MooseEnum("Constraint", "Constraint");
1820}

◆ removeRepeatedPairs()

void ContactAction::removeRepeatedPairs ( )
private

Remove repeated contact pairs from _boundary_pairs.

Definition at line 526 of file ContactAction.C.

527{
528 if (_boundary_pairs.size() == 0 && _automatic_pairing_boundaries.size() == 0)
530 "primary",
531 "Number of contact pairs in the contact action is zero. Please revise your input file.");
532
533 // Remove repeated interactions
534 std::vector<std::pair<BoundaryName, BoundaryName>> lean_boundary_pairs;
535
536 for (const auto & [primary, secondary] : _boundary_pairs)
537 {
538 // Structured bindings are not capturable (primary_copy, secondary_copy)
539 auto it = std::find_if(lean_boundary_pairs.begin(),
540 lean_boundary_pairs.end(),
541 [&, primary_copy = primary, secondary_copy = secondary](
542 const std::pair<BoundaryName, BoundaryName> & lean_pair)
543 {
544 const bool match_one = lean_pair.second == secondary_copy &&
545 lean_pair.first == primary_copy;
546 const bool match_two = lean_pair.second == primary_copy &&
547 lean_pair.first == secondary_copy;
548 const bool exist = match_one || match_two;
549 return exist;
550 });
551
552 if (it == lean_boundary_pairs.end())
553 lean_boundary_pairs.emplace_back(primary, secondary);
554 else
555 mooseInfo("Contact pair ",
556 primary,
557 "--",
558 secondary,
559 " has been removed from the contact interaction list due to "
560 "duplicates in the input file.");
561 }
562
563 _boundary_pairs = lean_boundary_pairs;
564}

Referenced by ContactAction(), and createSidesetsFromNodeProximity().

◆ validParams()

InputParameters ContactAction::validParams ( )
static

Definition at line 73 of file ContactAction.C.

74{
77
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",
84 {},
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.");
98 params.addDeprecatedParam<MeshGeneratorName>(
99 "mesh",
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>>(
107 "displacements",
108 {},
109 "The displacements appropriate for the simulation geometry and coordinate system");
110 params.addParam<Real>(
111 "penalty",
112 1e8,
113 "The penalty to apply. This can vary depending on the stiffness of your materials");
114 params.addParam<Real>(
115 "penalty_friction",
116 1e8,
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",
121 1.0,
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 "
125 "convergence.)");
127 "penalty_multiplier_friction",
128 1.0,
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");
134 params.addParam<Real>("tension_release",
135 0.0,
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.");
139 params.addParam<MooseEnum>("model", ContactAction::getModelEnum(), "The contact model to use");
140 params.addParam<Real>("tangential_tolerance",
141 "Tangential distance to extend edges of contact surfaces");
142 params.addParam<Real>("capture_tolerance",
143 0.0,
144 "Normal distance from surface within which nodes are captured. This "
145 "parameter is used for node-face and mortar formulations.");
146 params.addParam<Real>(
147 "normal_smoothing_distance",
148 "Distance from edge in parametric coordinates over which to smooth contact normal");
149
150 params.addParam<bool>("normalize_penalty",
151 false,
152 "Whether to normalize the penalty parameter with the nodal area.");
153 params.addParam<bool>(
154 "primary_secondary_jacobian",
155 true,
156 "Whether to include Jacobian entries coupling primary and secondary nodes.");
157 params.addParam<bool>(
158 "ghost_whole_interface",
159 false,
160 "Whether to geometrically and algebraically ghost the entire primary side of the interface "
161 "for node-face contact constraints.");
162 params.addParam<Real>("al_penetration_tolerance",
163 "The tolerance of the penetration for augmented Lagrangian method.");
164 params.addParam<Real>("al_incremental_slip_tolerance",
165 "The tolerance of the incremental slip for augmented Lagrangian method.");
167 "max_penalty_multiplier",
168 1.0e3,
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(
178 "BUSSETTA",
179 "Modify the penalty using an algorithm from Bussetta et al, 2012, Comput Mech 49:259-275 "
180 "between AL iterations.");
181 params.addParam<MooseEnum>(
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(
189 "FRICTION_LIMIT",
190 "This strategy will be guided by the Coulomb limit and be less reliant on the initial "
191 "penalty factor provided by the user.");
192 params.addParam<MooseEnum>(
193 "adaptivity_penalty_friction",
194 adaptivity_penalty_friction,
195 "The augmented Lagrange update strategy used on the frictional penalty coefficient.");
196 params.addParam<Real>("al_frictional_force_tolerance",
197 "The tolerance of the frictional force for augmented Lagrangian method.");
198 params.addParam<Real>(
199 "c_normal",
200 1e6,
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.");
206 params.addParam<Real>(
207 "c_tangential", 1, "Numerical parameter for nonlinear mortar frictional constraints");
208 params.addParam<bool>("ping_pong_protection",
209 false,
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");
214 params.addParam<Real>(
215 "normal_lm_scaling",
216 1.,
217 "Scaling factor to apply to the normal LM variable for a mortar formulation");
218 params.addParam<Real>(
219 "tangential_lm_scaling",
220 1.,
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(
228 "LINEAR",
229 "Use first-order LAGRANGE generated mortar Lagrange multiplier variables, independent "
230 "of the displacement variable order.");
231 params.addParam<MooseEnum>(
232 "lm_space",
233 lm_space,
234 "Finite element space for mortar Lagrange multiplier variables generated by the "
235 "contact action. This parameter only applies to the 'mortar' contact formulation.");
236 params.addParam<bool>(
237 "normalize_c",
238 false,
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");
244 params.addParam<bool>(
245 "use_dual",
246 "Whether to use the dual mortar approach within a mortar formulation. It is defaulted to "
247 "true for "
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.");
252 params.addParam<bool>(
253 "correct_edge_dropping",
254 false,
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",
261 true,
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>(
268 "mortar_dynamics",
269 false,
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>(
274 "newmark_beta",
275 0.25,
276 "Newmark-beta beta parameter for its inclusion in the weighted gap update formula");
277 params.addParam<Real>(
278 "newmark_gamma",
279 0.5,
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>>(
285 "extra_vector_tags",
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",
293 false,
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>(
298 "debug_mesh",
299 false,
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");
302 const auto mortar_constraint_params = MortarConstraintBase::validParams();
303 params.transferParam<MooseEnum>(mortar_constraint_params, "segment_quadrature");
304 params.transferParam<Real>(mortar_constraint_params, "minimum_projection_angle");
305 params.transferParam<MooseEnum>(mortar_constraint_params, "mortar_3d_subpatch_plane");
306 params.transferParam<MooseEnum>(mortar_constraint_params, "mortar_3d_qp_mapping");
307
308 // Contact surface definition
309 params.addParamNamesToGroup("primary secondary displacements", "Contact Surface Definition");
310 // Automatic pairing
311 params.addParamNamesToGroup(
312 "automatic_pairing_boundaries automatic_pairing_distance automatic_pairing_method",
313 "Automatic Contact Pair Generation");
314 // Contact formulation and model
315 params.addParamNamesToGroup("formulation model", "Contact Formulation");
316 // Penalty parameters
317 params.addParamNamesToGroup(
318 "penalty penalty_friction penalty_multiplier penalty_multiplier_friction "
319 "max_penalty_multiplier normalize_penalty",
320 "Penalty Parameters");
321 // Augmented Lagrange settings
322 params.addParamNamesToGroup(
323 "al_penetration_tolerance al_incremental_slip_tolerance al_frictional_force_tolerance "
324 "adaptivity_penalty_normal adaptivity_penalty_friction",
325 "Augmented Lagrange");
326 // Friction
327 params.addParamNamesToGroup("friction_coefficient tension_release", "Friction");
328 // Mortar-specific parameters
329 params.addParamNamesToGroup("c_normal c_tangential normal_lm_scaling tangential_lm_scaling "
330 "lm_space "
331 "use_dual correct_edge_dropping normalize_c use_petrov_galerkin "
332 "generate_mortar_mesh segment_quadrature minimum_projection_angle "
333 "mortar_3d_subpatch_plane mortar_3d_qp_mapping wear_depth debug_mesh",
334 "Mortar");
335 // Mortar dynamics (Newmark-beta)
336 params.addParamNamesToGroup("mortar_dynamics newmark_beta newmark_gamma", "Mortar Dynamics");
337 // Gap and tolerance settings
338 params.addParamNamesToGroup(
339 "secondary_gap_offset mapped_primary_gap_offset capture_tolerance "
340 "tangential_tolerance normal_smoothing_distance normal_smoothing_method",
341 "Gap and Tolerance");
342 // Jacobian and solver options
343 params.addParamNamesToGroup("primary_secondary_jacobian ping_pong_protection", "Solver Options");
344 // Interface ghosting
345 params.addParamNamesToGroup("ghost_whole_interface", "Interface Ghosting");
346 // Residual vector tags
347 params.addParamNamesToGroup("extra_vector_tags absolute_value_vector_tags", "Residual Tags");
348
349 return params;
350}
static InputParameters validParams()
static MooseEnum getProximityMethod()
Get proximity method for automatic pairing.
static InputParameters commonParameters()
Define parameters used by multiple contact objects.
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
void addClassDescription(const std::string &doc_string)
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
static InputParameters triangulationParams()

Member Data Documentation

◆ _automatic_pairing_boundaries

std::vector<BoundaryName> ContactAction::_automatic_pairing_boundaries
protected

List of all possible boundaries for contact for automatic pairing (optional)

Definition at line 85 of file ContactAction.h.

Referenced by addNodeFaceContact(), ContactAction(), createSidesetPairsFromGeometry(), createSidesetsFromNodeProximity(), and removeRepeatedPairs().

◆ _bnd_pair_to_mortar_info

std::map<std::pair<BoundaryName, BoundaryName>, const MortarInfo> ContactAction::_bnd_pair_to_mortar_info
protected

Map from boundary pair to mortar user object name.

Definition at line 113 of file ContactAction.h.

Referenced by act(), addContactPressureAuxKernel(), and addMortarContact().

◆ _boundary_pairs

std::vector<std::pair<BoundaryName, BoundaryName> > ContactAction::_boundary_pairs
protected

◆ _formulation

const ContactFormulation ContactAction::_formulation
protected

◆ _generate_mortar_mesh

const bool ContactAction::_generate_mortar_mesh
protected

Whether to generate the mortar mesh (useful in a restart simulation e.g.).

Definition at line 100 of file ContactAction.h.

Referenced by addMortarContact().

◆ _lm_space

const ContactLMSpace ContactAction::_lm_space
protected

Finite element space to use for action-generated mortar Lagrange multiplier variables.

Definition at line 94 of file ContactAction.h.

Referenced by act(), and addMortarContact().

◆ _model

const ContactModel ContactAction::_model
protected

Contact model type enum.

Definition at line 88 of file ContactAction.h.

Referenced by act(), addMortarContact(), and ContactAction().

◆ _mortar_dynamics

const bool ContactAction::_mortar_dynamics
protected

Whether mortar dynamic contact constraints are to be used.

Definition at line 103 of file ContactAction.h.

Referenced by addMortarContact().

◆ _use_dual

bool ContactAction::_use_dual
protected

Whether to use the dual Mortar approach.

Definition at line 97 of file ContactAction.h.

Referenced by addMortarContact(), and ContactAction().


The documentation for this class was generated from the following files: