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 370 of file ContactAction.C.

371 : Action(params),
372 _boundary_pairs(getParam<BoundaryName, BoundaryName>("primary", "secondary")),
373 _model(getParam<MooseEnum>("model").getEnum<ContactModel>()),
374 _formulation(getParam<MooseEnum>("formulation").getEnum<ContactFormulation>()),
375 _lm_space(getParam<MooseEnum>("lm_space").getEnum<ContactLMSpace>()),
376 _generate_mortar_mesh(getParam<bool>("generate_mortar_mesh")),
377 _mortar_dynamics(getParam<bool>("mortar_dynamics"))
378{
379 // Check for automatic selection of contact pairs.
380 if (getParam<std::vector<BoundaryName>>("automatic_pairing_boundaries").size() > 1)
382 getParam<std::vector<BoundaryName>>("automatic_pairing_boundaries");
383
384 if (_automatic_pairing_boundaries.size() > 0 && !isParamValid("automatic_pairing_distance"))
385 paramError("automatic_pairing_distance",
386 "For automatic selection of contact pairs (for particular geometries) in contact "
387 "action, 'automatic_pairing_distance' needs to be provided.");
388
389 if (_automatic_pairing_boundaries.size() > 0 && !isParamValid("automatic_pairing_method"))
390 paramError("automatic_pairing_distance",
391 "For automatic selection of contact pairs (for particular geometries) in contact "
392 "action, 'automatic_pairing_method' needs to be provided.");
393
394 if (_automatic_pairing_boundaries.size() > 0 && _boundary_pairs.size() != 0)
395 paramError("automatic_pairing_boundaries",
396 "If a boundary list is provided, primary and secondary surfaces will be identified "
397 "automatically. Therefore, one cannot provide an automatic pairing boundary list "
398 "and primary/secondary lists.");
399 else if (_automatic_pairing_boundaries.size() == 0 && _boundary_pairs.size() == 0)
400 paramError("primary",
401 "'primary' and 'secondary' surfaces or a list of boundaries for automatic pair "
402 "generation need to be provided.");
403
404 // End of checks for automatic selection of contact pairs.
405
406 if (_boundary_pairs.size() != 1 && _formulation == ContactFormulation::MORTAR)
407 paramError("formulation", "When using mortar, a vector of contact pairs cannot be used");
408
409 if ((_formulation == ContactFormulation::MORTAR ||
410 _formulation == ContactFormulation::MORTAR_PENALTY) &&
411 params.isParamSetByUser("ghost_whole_interface"))
412 paramError("ghost_whole_interface",
413 "The 'ghost_whole_interface' parameter is only supported for node-face contact "
414 "formulations. Mortar contact always geometrically and algebraically ghosts the "
415 "interface.");
416
417 if (_formulation == ContactFormulation::TANGENTIAL_PENALTY && _model != ContactModel::COULOMB)
418 paramError("formulation",
419 "The 'tangential_penalty' formulation can only be used with the 'coulomb' model");
420
421 if (_formulation == ContactFormulation::MORTAR_PENALTY)
422 {
423 // Use dual basis functions for contact traction interpolation
424 if (isParamValid("use_dual"))
425 _use_dual = getParam<bool>("use_dual");
426 else
427 _use_dual = true;
428
429 if (_model == ContactModel::GLUED)
430 paramError("model", "The 'mortar_penalty' formulation does not support glued contact");
431
432 if (getParam<bool>("mortar_dynamics"))
433 paramError("mortar_dynamics",
434 "The 'mortar_penalty' formulation does not support implicit dynamic simulations");
435
436 if (getParam<bool>("use_petrov_galerkin"))
437 paramError("use_petrov_galerkin",
438 "The 'mortar_penalty' formulation does not support usage of the Petrov-Galerkin "
439 "flag. The default (use_dual = true) behavior is such that contact tractions are "
440 "interpolated with dual bases whereas mortar or weighted contact quantities are "
441 "interpolated with Lagrange shape functions.");
442 }
443
444 if (_formulation == ContactFormulation::MORTAR)
445 {
446 if (_model == ContactModel::GLUED)
447 paramError("model", "The 'mortar' formulation does not support glued contact (yet)");
448
449 // use dual basis function for Lagrange multipliers?
450 if (isParamValid("use_dual"))
451 _use_dual = getParam<bool>("use_dual");
452 else
453 _use_dual = true;
454
455 if (!getParam<bool>("mortar_dynamics"))
456 {
457 if (params.isParamSetByUser("newmark_beta"))
458 paramError("newmark_beta", "newmark_beta can only be used with the mortar_dynamics option");
459
460 if (params.isParamSetByUser("newmark_gamma"))
461 paramError("newmark_gamma",
462 "newmark_gamma can only be used with the mortar_dynamics option");
463 }
464
465 if (isParamSetByUser("penalty"))
466 paramError("penalty",
467 "The 'penalty' parameter is not used for the 'mortar' formulation which instead "
468 "uses Lagrange multipliers");
469
470 if (isParamSetByUser("friction_projection_degree") && _model != ContactModel::COULOMB)
471 paramError("friction_projection_degree",
472 "'friction_projection_degree' is only valid for Coulomb friction mortar "
473 "contact.");
474 }
475 else
476 {
477 if (params.isParamSetByUser("correct_edge_dropping"))
479 "correct_edge_dropping",
480 "The 'correct_edge_dropping' option can only be used with the 'mortar' formulation "
481 "(weighted)");
482 else if (params.isParamSetByUser("use_nodal_scaling"))
483 paramError("use_nodal_scaling",
484 "The 'use_nodal_scaling' option can only be used with the 'mortar' formulation "
485 "(weighted)");
486 else if (params.isParamSetByUser("triangulation") &&
487 _formulation != ContactFormulation::MORTAR_PENALTY)
488 paramError("triangulation",
489 "The 'triangulation' option can only be used with mortar-based formulations.");
490 else if (params.isParamSetByUser("triangulate_triangles") &&
491 _formulation != ContactFormulation::MORTAR_PENALTY)
492 paramError("triangulate_triangles",
493 "The 'triangulate_triangles' option can only be used with mortar-based "
494 "formulations.");
495 else if (params.isParamSetByUser("minimum_projection_angle") &&
496 _formulation != ContactFormulation::MORTAR_PENALTY)
497 paramError("minimum_projection_angle",
498 "The 'minimum_projection_angle' option can only be used with mortar-based "
499 "formulations.");
500 else if (params.isParamSetByUser("mortar_3d_subpatch_plane") &&
501 _formulation != ContactFormulation::MORTAR_PENALTY)
502 paramError("mortar_3d_subpatch_plane",
503 "The 'mortar_3d_subpatch_plane' option can only be used with mortar-based "
504 "formulations.");
505 else if (params.isParamSetByUser("mortar_3d_qp_mapping") &&
506 _formulation != ContactFormulation::MORTAR_PENALTY)
507 paramError("mortar_3d_qp_mapping",
508 "The 'mortar_3d_qp_mapping' option can only be used with mortar-based "
509 "formulations.");
510 else if (params.isParamSetByUser("use_dual") &&
511 _formulation != ContactFormulation::MORTAR_PENALTY)
512 paramError("use_dual",
513 "The 'use_dual' option can only be used with the 'mortar' formulation");
514 else if (params.isParamSetByUser("c_normal"))
515 paramError("c_normal",
516 "The 'c_normal' option can only be used with the 'mortar' formulation");
517 else if (params.isParamSetByUser("c_tangential"))
518 paramError("c_tangential",
519 "The 'c_tangential' option can only be used with the 'mortar' formulation");
520 else if (params.isParamSetByUser("mortar_dynamics"))
521 paramError("mortar_dynamics",
522 "The 'mortar_dynamics' constraint option can only be used with the 'mortar' "
523 "formulation and in dynamic simulations using Newmark-beta");
524 else if (params.isParamSetByUser("segment_quadrature"))
525 paramError("segment_quadrature",
526 "The 'segment_quadrature' option can only be used with the "
527 "'mortar' formulation.");
528 else if (params.isParamSetByUser("lm_space"))
529 paramError("lm_space",
530 "The 'lm_space' option can only be used with the 'mortar' formulation.");
531 }
532
533 if (_formulation == ContactFormulation::RANFS)
534 {
535 if (isParamValid("secondary_gap_offset"))
536 paramError("secondary_gap_offset",
537 "The 'secondary_gap_offset' option can only be used with the "
538 "'MechanicalContactConstraint'");
539 if (isParamValid("mapped_primary_gap_offset"))
540 paramError("mapped_primary_gap_offset",
541 "The 'mapped_primary_gap_offset' option can only be used with the "
542 "'MechanicalContactConstraint'");
543 }
544 else if (getParam<bool>("ping_pong_protection"))
545 paramError("ping_pong_protection",
546 "The 'ping_pong_protection' option can only be used with the 'ranfs' formulation");
547
548 // Remove repeated pairs from input file.
550}
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 594 of file ContactAction.C.

595{
596 // proform problem checks/corrections once during the first feasible task
597 if (_current_task == "add_contact_aux_variable")
598 {
599 if (!_problem->getDisplacedProblem())
601 "Contact requires updated coordinates. Use the 'displacements = ...' parameter in the "
602 "Mesh block.");
603
604 // It is risky to apply this optimization to contact problems
605 // since the problem configuration may be changed during Jacobian
606 // evaluation. We therefore turn it off for all contact problems so that
607 // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3.
608 if (!_problem->isSNESMFReuseBaseSetbyUser())
609 _problem->setSNESMFReuseBase(false, false);
610 }
611
612 if (_formulation == ContactFormulation::MORTAR ||
613 _formulation == ContactFormulation::MORTAR_PENALTY)
615 else
617
618 if (_current_task == "add_aux_kernel")
619 {
620 if (!_problem->getDisplacedProblem())
621 mooseError("Contact requires updated coordinates. Use the 'displacements = ...' line in the "
622 "Mesh block.");
623
624 // Create auxiliary kernels for each contact pairs
625 for (const auto & contact_pair : _boundary_pairs)
626 {
627 const auto & [primary_name, secondary_name] = contact_pair;
628 if ((_formulation != ContactFormulation::MORTAR) &&
629 (_formulation != ContactFormulation::MORTAR_PENALTY))
630 {
631 InputParameters params = _factory.getValidParams("PenetrationAux");
633 {"secondary_gap_offset", "mapped_primary_gap_offset", "order"});
634
635 std::vector<VariableName> displacements =
636 getParam<std::vector<VariableName>>("displacements");
637 const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
638 .system()
639 .variable_type(displacements[0])
640 .order.get_order();
641
642 params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
643 params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR};
644 params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
645 params.set<BoundaryName>("paired_boundary") = primary_name;
646 params.set<AuxVariableName>("variable") = "penetration";
647 if (isParamValid("secondary_gap_offset"))
648 params.set<std::vector<VariableName>>("secondary_gap_offset") = {
649 getParam<VariableName>("secondary_gap_offset")};
650 if (isParamValid("mapped_primary_gap_offset"))
651 params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
652 getParam<VariableName>("mapped_primary_gap_offset")};
653 params.set<bool>("use_displaced_mesh") = true;
654 std::string name = _name + "_contact_" + Moose::stringify(contact_auxkernel_counter++);
655
656 _problem->addAuxKernel("PenetrationAux", name, params);
657 }
658 else
659 {
660 const auto type = "MortarUserObjectAux";
662 params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
663 params.set<AuxVariableName>("variable") = "gap";
664 params.set<bool>("use_displaced_mesh") = true; // Unnecessary as this object only operates
665 // on nodes, but we'll do it for consistency
666 params.set<MooseEnum>("contact_quantity") = "normal_gap";
667 const auto & [primary_id, secondary_id, uo_name] =
668 libmesh_map_find(_bnd_pair_to_mortar_info, contact_pair);
669 params.set<UserObjectName>("user_object") = uo_name;
670 std::string name = _name + "_contact_gap_" + std::to_string(primary_id) + "_" +
671 std::to_string(secondary_id);
672
673 _problem->addAuxKernel(type, name, params);
674 }
675 }
676
678
679 const unsigned int ndisp = getParam<std::vector<VariableName>>("displacements").size();
680
681 // Add MortarFrictionalPressureVectorAux
682 if (_formulation == ContactFormulation::MORTAR && _model == ContactModel::COULOMB && ndisp > 2)
683 {
684 {
685 InputParameters params = _factory.getValidParams("MortarFrictionalPressureVectorAux");
686
687 params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
688 params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
689 params.set<std::vector<BoundaryName>>("boundary") = {_boundary_pairs[0].second};
690 params.set<ExecFlagEnum>("execute_on", true) = {EXEC_NONLINEAR};
691
692 std::string action_name = MooseUtils::shortName(name());
693 const std::string tangential_lagrange_multiplier_name = action_name + "_tangential_lm";
694 const std::string tangential_lagrange_multiplier_3d_name =
695 action_name + "_tangential_3d_lm";
696
697 params.set<std::vector<VariableName>>("tangent_one") = {
698 tangential_lagrange_multiplier_name};
699 params.set<std::vector<VariableName>>("tangent_two") = {
700 tangential_lagrange_multiplier_3d_name};
701
702 std::vector<std::string> disp_components({"x", "y", "z"});
703 unsigned component_index = 0;
704
705 // Loop over three displacements
706 for (const auto & disp_component : disp_components)
707 {
708 params.set<AuxVariableName>("variable") = _name + "_tangent_" + disp_component;
709 params.set<unsigned int>("component") = component_index;
710
711 std::string name = _name + "_mortar_frictional_pressure_" + disp_component + "_" +
713
714 _problem->addAuxKernel("MortarFrictionalPressureVectorAux", name, params);
715 component_index++;
716 }
717 }
718 }
719 }
720
721 if (_current_task == "add_contact_aux_variable")
722 {
723 std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
724 const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
725 .system()
726 .variable_type(displacements[0])
727 .order.get_order();
728 const auto mortar_lm_order =
729 _lm_space == ContactLMSpace::LINEAR ? static_cast<int>(FIRST) : order;
730 std::unique_ptr<InputParameters> current_params;
731 const auto create_aux_var_params =
732 [this, order, mortar_lm_order, &current_params]() -> InputParameters &
733 {
734 current_params = std::make_unique<InputParameters>(_factory.getValidParams("MooseVariable"));
735 // Node/face and mortar-penalty contact aux variables continue to follow the displacement
736 // order. Mortar LM contact aux variables live on the same contact surface as the generated LM
737 // field, so they use the selected generated LM space.
738 const auto aux_order = _formulation == ContactFormulation::MORTAR ? mortar_lm_order : order;
739 current_params->set<MooseEnum>("order") =
740 Utility::enum_to_string<Order>(OrderWrapper{aux_order});
741 current_params->set<MooseEnum>("family") = "LAGRANGE";
742 return *current_params;
743 };
744
745 if ((_formulation != ContactFormulation::MORTAR) &&
746 (_formulation != ContactFormulation::MORTAR_PENALTY))
747 {
748 // Add penetration aux variable
749 _problem->addAuxVariable("MooseVariable", "penetration", create_aux_var_params());
750 // Add nodal area aux variable
751 _problem->addAuxVariable("MooseVariable", "nodal_area", create_aux_var_params());
752 }
753 else
754 _problem->addAuxVariable("MooseVariable", "gap", create_aux_var_params());
755
756 // Add contact pressure aux variable
757 _problem->addAuxVariable("MooseVariable", "contact_pressure", create_aux_var_params());
758
759 const unsigned int ndisp = getParam<std::vector<VariableName>>("displacements").size();
760
761 // Add MortarFrictionalPressureVectorAux variables
762 if (_formulation == ContactFormulation::MORTAR && _model == ContactModel::COULOMB && ndisp > 2)
763 {
764 {
765 std::vector<std::string> disp_components({"x", "y", "z"});
766 // Loop over three displacements
767 for (const auto & disp_component : disp_components)
768 {
769 auto var_params = _factory.getValidParams("MooseVariable");
770 var_params.set<MooseEnum>("order") =
771 Utility::enum_to_string<Order>(OrderWrapper{mortar_lm_order});
772 var_params.set<MooseEnum>("family") = "LAGRANGE";
773
774 _problem->addAuxVariable(
775 "MooseVariable", _name + "_tangent_" + disp_component, var_params);
776 }
777 }
778 }
779 }
780
781 if (_current_task == "add_user_object" && (_formulation != ContactFormulation::MORTAR) &&
782 (_formulation != ContactFormulation::MORTAR_PENALTY))
783 {
784 auto var_params = _factory.getValidParams("NodalArea");
785
786 // Get secondary_boundary_vector from possibly updated set from the
787 // ContactAction constructor cleanup
788 const auto actions = _awh.getActions<ContactAction>();
789
790 std::vector<BoundaryName> secondary_boundary_vector;
791 for (const auto * const action : actions)
792 for (const auto j : index_range(action->_boundary_pairs))
793 secondary_boundary_vector.push_back(action->_boundary_pairs[j].second);
794
795 var_params.set<std::vector<BoundaryName>>("boundary") = secondary_boundary_vector;
796 var_params.set<std::vector<VariableName>>("variable") = {"nodal_area"};
797
798 mooseAssert(_problem, "Problem pointer is NULL");
799 var_params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_TIMESTEP_BEGIN};
800 var_params.set<bool>("use_displaced_mesh") = true;
801
802 _problem->addUserObject("NodalArea",
803 "nodal_area_object_" + Moose::stringify(contact_userobject_counter++),
804 var_params);
805 }
806}
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 809 of file ContactAction.C.

810{
811 // Increment counter for contact action objects
813
814 if ((_formulation != ContactFormulation::MORTAR) &&
815 (_formulation != ContactFormulation::MORTAR_PENALTY))
816 {
817 // Add ContactPressureAux: Only one object for all contact pairs
818 const auto actions = _awh.getActions<ContactAction>();
819
820 // Add auxiliary kernel if we are the last contact action object.
821 if (contact_action_counter == actions.size())
822 {
823 std::vector<BoundaryName> boundary_vector;
824 std::vector<BoundaryName> pair_boundary_vector;
825
826 for (const auto * const action : actions)
827 for (const auto j : index_range(action->_boundary_pairs))
828 {
829 boundary_vector.push_back(action->_boundary_pairs[j].second);
830 pair_boundary_vector.push_back(action->_boundary_pairs[j].first);
831 }
832
833 InputParameters params = _factory.getValidParams("ContactPressureAux");
834 params.applyParameters(parameters(), {"order"});
835
836 std::vector<VariableName> displacements =
837 getParam<std::vector<VariableName>>("displacements");
838 const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
839 .system()
840 .variable_type(displacements[0])
841 .order.get_order();
842
843 params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
844 params.set<std::vector<BoundaryName>>("boundary") = boundary_vector;
845 params.set<std::vector<BoundaryName>>("paired_boundary") = pair_boundary_vector;
846 params.set<AuxVariableName>("variable") = "contact_pressure";
847 params.addRequiredCoupledVar("nodal_area", "The nodal area");
848 params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area"};
849 params.set<bool>("use_displaced_mesh") = true;
850
851 std::string name = _name + "_contact_pressure";
852 params.set<ExecFlagEnum>("execute_on",
854 _problem->addAuxKernel("ContactPressureAux", name, params);
855 }
856 }
857 else
858 for (const auto & contact_pair : _boundary_pairs)
859 {
860 const auto & [_, secondary_name] = contact_pair;
861 const auto type = "MortarUserObjectAux";
863 params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
864 params.set<AuxVariableName>("variable") = "contact_pressure";
865 params.set<bool>("use_displaced_mesh") = true; // Unecessary as this object only operates on
866 // nodes, but we'll do it for consistency
867 params.set<MooseEnum>("contact_quantity") = "normal_pressure";
868 const auto & [primary_id, secondary_id, uo_name] =
869 libmesh_map_find(_bnd_pair_to_mortar_info, contact_pair);
870 params.set<UserObjectName>("user_object") = uo_name;
871 const std::string name = _name + "_contact_pressure" + std::to_string(primary_id) + "_" +
872 std::to_string(secondary_id);
873
874 _problem->addAuxKernel(type, name, params);
875 }
876}
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 918 of file ContactAction.C.

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

1447{
1448 if (_current_task == "post_mesh_prepared" && _automatic_pairing_boundaries.size() > 0)
1449 {
1450 if (getParam<MooseEnum>("automatic_pairing_method").getEnum<ProximityMethod>() ==
1451 ProximityMethod::NODE)
1453 else if (getParam<MooseEnum>("automatic_pairing_method").getEnum<ProximityMethod>() ==
1454 ProximityMethod::CENTROID)
1456 }
1457
1458 if (_current_task != "add_constraint")
1459 return;
1460
1461 std::string action_name = MooseUtils::shortName(name());
1462 std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
1463 const unsigned int ndisp = displacements.size();
1464
1465 std::string constraint_type;
1466
1467 if (_formulation == ContactFormulation::RANFS)
1468 constraint_type = "RANFSNormalMechanicalContact";
1469 else
1470 constraint_type = "MechanicalContactConstraint";
1471
1472 InputParameters params = _factory.getValidParams(constraint_type);
1473
1474 params.applyParameters(parameters(),
1475 {"displacements",
1476 "secondary_gap_offset",
1477 "mapped_primary_gap_offset",
1478 "primary",
1479 "secondary"});
1480
1481 const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
1482 .system()
1483 .variable_type(displacements[0])
1484 .order.get_order();
1485
1486 params.set<std::vector<VariableName>>("displacements") = displacements;
1487 params.set<bool>("use_displaced_mesh") = true;
1488 params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
1489
1490 for (const auto & contact_pair : _boundary_pairs)
1491 {
1492 if (_formulation != ContactFormulation::RANFS)
1493 {
1494 params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area"};
1495 params.set<BoundaryName>("boundary") = contact_pair.first;
1496 if (isParamValid("secondary_gap_offset"))
1497 params.set<std::vector<VariableName>>("secondary_gap_offset") = {
1498 getParam<VariableName>("secondary_gap_offset")};
1499 if (isParamValid("mapped_primary_gap_offset"))
1500 params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
1501 getParam<VariableName>("mapped_primary_gap_offset")};
1502 }
1503
1504 for (unsigned int i = 0; i < ndisp; ++i)
1505 {
1506 std::string name = action_name + "_constraint_" + Moose::stringify(contact_pair, "_") + "_" +
1508
1509 if (_formulation == ContactFormulation::RANFS)
1510 params.set<MooseEnum>("component") = i;
1511 else
1512 params.set<unsigned int>("component") = i;
1513
1514 params.set<BoundaryName>("primary") = contact_pair.first;
1515 params.set<BoundaryName>("secondary") = contact_pair.second;
1516 params.set<NonlinearVariableName>("variable") = displacements[i];
1517 params.set<std::vector<VariableName>>("primary_variable") = {displacements[i]};
1519 {"extra_vector_tags", "absolute_value_vector_tags"});
1520 _problem->addConstraint(constraint_type, name, params);
1521 }
1522 }
1523}
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 879 of file ContactAction.C.

880{
881 if (_formulation == ContactFormulation::MORTAR ||
882 _formulation == ContactFormulation::MORTAR_PENALTY)
883 {
884 auto params = MortarConstraintBase::validParams();
885 params.set<bool>("use_displaced_mesh") = true;
886 std::string action_name = MooseUtils::shortName(name());
887 const std::string primary_subdomain_name = action_name + "_primary_subdomain";
888 const std::string secondary_subdomain_name = action_name + "_secondary_subdomain";
889 params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
890 params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
891 params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
892 params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
893 params.set<bool>("use_petrov_galerkin") = getParam<bool>("use_petrov_galerkin");
894 params.set<Real>("minimum_projection_angle") = getParam<Real>("minimum_projection_angle");
895 params.set<MooseEnum>("mortar_3d_subpatch_plane") =
896 getParam<MooseEnum>("mortar_3d_subpatch_plane");
897 addRelationshipManagers(input_rm_type, params);
898 }
899 else
900 {
901 const std::string constraint_type = _formulation == ContactFormulation::RANFS
902 ? "RANFSNormalMechanicalContact"
903 : "MechanicalContactConstraint";
904
905 for (const auto & contact_pair : _boundary_pairs)
906 {
907 auto params = _factory.getValidParams(constraint_type);
908 params.set<bool>("use_displaced_mesh") = true;
909 params.set<bool>("ghost_whole_interface") = getParam<bool>("ghost_whole_interface");
910 params.set<BoundaryName>("primary") = contact_pair.first;
911 params.set<BoundaryName>("secondary") = contact_pair.second;
912 addRelationshipManagers(input_rm_type, params);
913 }
914 }
915}
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 1860 of file ContactAction.C.

1861{
1863
1864 params.addParam<MooseEnum>("normal_smoothing_method",
1866 "Method to use to smooth normals");
1867 params.addParam<Real>(
1868 "normal_smoothing_distance",
1869 "Distance from edge in parametric coordinates over which to smooth contact normal");
1870
1871 params.addParam<MooseEnum>(
1872 "formulation", ContactAction::getFormulationEnum(), "The contact formulation");
1873
1874 params.addParam<MooseEnum>("model", ContactAction::getModelEnum(), "The contact model to use");
1875
1876 return params;
1877}
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 1673 of file ContactAction.C.

1674{
1675 mooseInfo("The contact action is reading the list of boundaries and automatically pairs them "
1676 "if their centroids fall within a specified distance of each other.");
1677
1678 if (!_mesh)
1679 mooseError("Failed to obtain mesh for automatically generating contact pairs.");
1680
1681 if (!_mesh->getMesh().is_serial())
1682 paramError(
1683 "automatic_pairing_boundaries",
1684 "The generation of automatic contact pairs in the contact action requires a serial mesh.");
1685
1686 // Compute centers of gravity for each sideset
1687 std::vector<std::pair<BoundaryName, Point>> automatic_pairing_boundaries_cog;
1688 const auto & sideset_ids = _mesh->meshSidesetIds();
1689
1690 const auto & bnd_to_elem_map = _mesh->getBoundariesToActiveSemiLocalElemIds();
1691
1692 for (const auto & sideset_name : _automatic_pairing_boundaries)
1693 {
1694 // If the sideset provided in the input file isn't in the mesh, error out.
1695 const auto find_set = sideset_ids.find(_mesh->getBoundaryID(sideset_name));
1696 if (find_set == sideset_ids.end())
1697 paramError("automatic_pairing_boundaries",
1698 sideset_name,
1699 " is not defined as a sideset in the mesh.");
1700
1701 auto dofs_set = bnd_to_elem_map.find(_mesh->getBoundaryID(sideset_name));
1702
1703 // Initialize data for sideset
1704 Point center_of_gravity(0, 0, 0);
1705 Real accumulated_sideset_area(0);
1706
1707 // Pointer to lower-dimensional element on the sideset
1708 std::unique_ptr<const Elem> side_ptr;
1709 const std::unordered_set<dof_id_type> & bnd_elems = dofs_set->second;
1710
1711 for (auto elem_id : bnd_elems)
1712 {
1713 const Elem * elem = _mesh->elemPtr(elem_id);
1714 unsigned int side = _mesh->sideWithBoundaryID(elem, _mesh->getBoundaryID(sideset_name));
1715
1716 // update side_ptr
1717 elem->side_ptr(side_ptr, side);
1718
1719 // area of the (linearized) side
1720 const auto side_area = side_ptr->volume();
1721
1722 // position of the side
1723 const auto side_position = side_ptr->true_centroid();
1724
1725 center_of_gravity += side_position * side_area;
1726 accumulated_sideset_area += side_area;
1727 }
1728
1729 // Average each element's center of gravity (centroid) with its area
1730 center_of_gravity /= accumulated_sideset_area;
1731
1732 // Add sideset-cog pair to vector
1733 automatic_pairing_boundaries_cog.emplace_back(sideset_name, center_of_gravity);
1734 }
1735
1736 // Vectors of distances for each pair
1737 std::vector<std::pair<std::pair<BoundaryName, BoundaryName>, Real>> pairs_distances;
1738
1739 // Assign distances to identify nearby pairs.
1740 for (std::size_t i = 0; i < automatic_pairing_boundaries_cog.size() - 1; i++)
1741 for (std::size_t j = i + 1; j < automatic_pairing_boundaries_cog.size(); j++)
1742 {
1743 const Point & distance_vector =
1744 automatic_pairing_boundaries_cog[i].second - automatic_pairing_boundaries_cog[j].second;
1745
1746 if (automatic_pairing_boundaries_cog[i].first != automatic_pairing_boundaries_cog[j].first)
1747 {
1748 const Real distance = distance_vector.norm();
1749 const std::pair pair = std::make_pair(automatic_pairing_boundaries_cog[i].first,
1750 automatic_pairing_boundaries_cog[j].first);
1751 pairs_distances.emplace_back(std::make_pair(pair, distance));
1752 }
1753 }
1754
1755 const auto automatic_pairing_distance = getParam<Real>("automatic_pairing_distance");
1756
1757 // Loop over all pairs
1758 std::vector<std::pair<std::pair<BoundaryName, BoundaryName>, Real>> lean_pairs_distances;
1759 for (const auto & pair_distance : pairs_distances)
1760 if (pair_distance.second <= automatic_pairing_distance)
1761 {
1762 lean_pairs_distances.emplace_back(pair_distance);
1763 mooseInfoRepeated("Generating contact pair primary--secondary ",
1764 pair_distance.first.first,
1765 "--",
1766 pair_distance.first.second,
1767 ", with a relative distance of ",
1768 pair_distance.second);
1769 }
1770
1771 // Create the boundary pairs (possibly with repeated pairs depending on user input)
1772 for (const auto & lean_pairs_distance : lean_pairs_distances)
1773 {
1774 // Make sure secondary surface's boundary ID is less than primary surface's boundary ID.
1775 // This is done to ensure some consistency in the boundary matching, which helps in defining
1776 // auxiliary kernels in the input file.
1777 if (_mesh->getBoundaryID(lean_pairs_distance.first.first) >
1778 _mesh->getBoundaryID(lean_pairs_distance.first.second))
1779 _boundary_pairs.push_back(
1780 {lean_pairs_distance.first.first, lean_pairs_distance.first.second});
1781 else
1782 _boundary_pairs.push_back(
1783 {lean_pairs_distance.first.second, lean_pairs_distance.first.first});
1784 }
1785
1786 // Let's remove possibly repeated pairs
1788}
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 1535 of file ContactAction.C.

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

1804{
1805 auto formulations = MooseEnum(getContactFormulationOptions(), "kinematic");
1806
1807 formulations.addDocumentation(
1808 "ranfs",
1809 "Reduced Active Nonlinear Function Set scheme for node-on-face contact. Provides exact "
1810 "enforcement without Lagrange multipliers or penalty terms.");
1811 formulations.addDocumentation(
1812 "kinematic",
1813 "Kinematic contact constraint enforcement transfers the internal forces at secondary nodes "
1814 "to the corresponding primary face for node-on-face contact. Provides exact "
1815 "enforcement without Lagrange multipliers or penalty terms.");
1816 formulations.addDocumentation(
1817 "penalty",
1818 "Node-on-face penalty based contact constraint enforcement. Interpenetration is penalized. "
1819 "Enforcement depends on the penalty magnitude. High penalties can introduce ill conditioning "
1820 "of the system.");
1821 formulations.addDocumentation("augmented_lagrange",
1822 "Node-on-face augmented Lagrange penalty based contact constraint "
1823 "enforcement. Interpenetration is enforced up to a user specified "
1824 "tolerance, ill-conditioning is generally avoided. Requires an "
1825 "Augmented Lagrange Problem class to be used in the simulation.");
1826 formulations.addDocumentation(
1827 "tangential_penalty",
1828 "Node-on-face penalty based frictional contact constraint enforcement. Interpenetration and "
1829 "slip distance for sticking nodes are penalized. Enforcement depends on the penalty "
1830 "magnitudes. High penalties can introduce ill conditioning of the system.");
1831 formulations.addDocumentation(
1832 "mortar",
1833 "Mortar based contact constraint enforcement using Lagrange multipliers. Provides exact "
1834 "enforcement and a variationally consistent formulation. Lagrange multipliers introduce a "
1835 "saddle point character in the system matrix which can have a negative impact on scalability "
1836 "with iterative solvers");
1837 formulations.addDocumentation(
1838 "mortar_penalty",
1839 "Mortar and penalty based contact constraint enforcement. When using an Augmented Lagrange "
1840 "Problem class this provides normal (and tangential) contact constratint enforced up to a "
1841 "user specified tolerances. Without AL the enforcement depends on the penalty magnitudes. "
1842 "High penalties can introduce ill conditioning of the system.");
1843
1844 return formulations;
1845}

Referenced by commonParameters().

◆ getModelEnum()

MooseEnum ContactAction::getModelEnum ( )
static

Get contact model.

Returns
enum

Definition at line 1791 of file ContactAction.C.

1792{
1793 return MooseEnum(getContactModelOptions(), "frictionless");
1794}

Referenced by commonParameters(), and validParams().

◆ getProximityMethod()

MooseEnum ContactAction::getProximityMethod ( )
static

Get proximity method for automatic pairing.

Returns
enum

Definition at line 1797 of file ContactAction.C.

1798{
1799 return MooseEnum(getProximityMethodOptions());
1800}

Referenced by validParams().

◆ getSmoothingEnum()

MooseEnum ContactAction::getSmoothingEnum ( )
static

Get smoothing type.

Returns
enum

Definition at line 1854 of file ContactAction.C.

1855{
1856 return MooseEnum("edge_based nodal_normal_based", "");
1857}

Referenced by commonParameters().

◆ getSystemEnum()

MooseEnum ContactAction::getSystemEnum ( )
static

Get contact system.

Returns
enum

Definition at line 1848 of file ContactAction.C.

1849{
1850 return MooseEnum("Constraint", "Constraint");
1851}

◆ removeRepeatedPairs()

void ContactAction::removeRepeatedPairs ( )
private

Remove repeated contact pairs from _boundary_pairs.

Definition at line 553 of file ContactAction.C.

554{
555 if (_boundary_pairs.size() == 0 && _automatic_pairing_boundaries.size() == 0)
557 "primary",
558 "Number of contact pairs in the contact action is zero. Please revise your input file.");
559
560 // Remove repeated interactions
561 std::vector<std::pair<BoundaryName, BoundaryName>> lean_boundary_pairs;
562
563 for (const auto & [primary, secondary] : _boundary_pairs)
564 {
565 // Structured bindings are not capturable (primary_copy, secondary_copy)
566 auto it = std::find_if(lean_boundary_pairs.begin(),
567 lean_boundary_pairs.end(),
568 [&, primary_copy = primary, secondary_copy = secondary](
569 const std::pair<BoundaryName, BoundaryName> & lean_pair)
570 {
571 const bool match_one = lean_pair.second == secondary_copy &&
572 lean_pair.first == primary_copy;
573 const bool match_two = lean_pair.second == primary_copy &&
574 lean_pair.first == secondary_copy;
575 const bool exist = match_one || match_two;
576 return exist;
577 });
578
579 if (it == lean_boundary_pairs.end())
580 lean_boundary_pairs.emplace_back(primary, secondary);
581 else
582 mooseInfo("Contact pair ",
583 primary,
584 "--",
585 secondary,
586 " has been removed from the contact interaction list due to "
587 "duplicates in the input file.");
588 }
589
590 _boundary_pairs = lean_boundary_pairs;
591}

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 MooseEnum friction_projection_degree("ONE TWO", "TWO");
209 friction_projection_degree.addDocumentation(
210 "ONE", "Use the degree-one Alart-Curnier friction residual.");
211 friction_projection_degree.addDocumentation(
212 "TWO", "Use the degree-two Hueber-Stadler-Wohlmuth friction residual.");
213 params.addParam<MooseEnum>("friction_projection_degree",
214 friction_projection_degree,
215 "Degree of the friction-residual projection; see "
216 "MortarContactUtils.h. Only valid for Coulomb friction mortar "
217 "contact.");
218 params.addParam<bool>("ping_pong_protection",
219 false,
220 "Whether to protect against ping-ponging, e.g. the oscillation of the "
221 "secondary node between two "
222 "different primary faces, by tying the secondary node to the "
223 "edge between the involved primary faces");
224 params.addParam<Real>(
225 "normal_lm_scaling",
226 1.,
227 "Scaling factor to apply to the normal LM variable for a mortar formulation");
228 params.addParam<Real>(
229 "tangential_lm_scaling",
230 1.,
231 "Scaling factor to apply to the tangential LM variable for a mortar formulation");
232 MooseEnum lm_space(getContactLMSpaceOptions(), "MATCH_DISPLACEMENT");
233 lm_space.addDocumentation(
234 "MATCH_DISPLACEMENT",
235 "Use the same finite element order as the displacement variables for generated mortar "
236 "Lagrange multiplier variables.");
237 lm_space.addDocumentation(
238 "LINEAR",
239 "Use first-order LAGRANGE generated mortar Lagrange multiplier variables, independent "
240 "of the displacement variable order.");
241 params.addParam<MooseEnum>(
242 "lm_space",
243 lm_space,
244 "Finite element space for mortar Lagrange multiplier variables generated by the "
245 "contact action. This parameter only applies to the 'mortar' contact formulation.");
246 params.addParam<bool>(
247 "normalize_c",
248 false,
249 "Whether to normalize c by weighting function norm for mortar contact. When unnormalized "
250 "the value of c effectively depends on element size since in the constraint we compare nodal "
251 "Lagrange Multiplier values to integrated gap values (LM nodal value is independent of "
252 "element size, where integrated values are dependent on element size).");
253 params.addClassDescription("Sets up all objects needed for mechanical contact enforcement");
254 params.addParam<bool>(
255 "use_dual",
256 "Whether to use the dual mortar approach within a mortar formulation. It is defaulted to "
257 "true for "
258 "weighted quantity approach, and to false for the legacy approach. To avoid instabilities "
259 "in the solution and obtain the full benefits of a variational enforcement,"
260 "use of dual mortar with weighted constraints is strongly recommended. This "
261 "input is only intended for advanced users.");
262 params.addParam<bool>(
263 "correct_edge_dropping",
264 false,
265 "Whether to enable correct edge dropping treatment for mortar constraints. When disabled "
266 "any Lagrange Multiplier degree of freedom on a secondary element without full primary "
267 "contributions will be set (strongly) to 0.");
268 params.addParam<bool>(
269 "use_nodal_scaling",
270 false,
271 "Whether to apply the node-based Lagrange-multiplier scaling of Popp et al. (2013) to "
272 "improve the conditioning of the linear system when secondary elements are only partially "
273 "covered (edge dropping). See the documentation for the current limitations.");
275 params.addParam<bool>(
276 "generate_mortar_mesh",
277 true,
278 "Whether to generate the mortar mesh from the action. Typically this will be the case, but "
279 "one may also want to reuse an existing lower-dimensional mesh prior to a restart.");
280 params.addParam<MooseEnum>("automatic_pairing_method",
282 "The proximity method used for automatic pairing of boundaries.");
283 params.addParam<bool>(
284 "mortar_dynamics",
285 false,
286 "Whether to use constraints that account for the persistency condition, giving rise to "
287 "smoother normal contact pressure evolution. This flag should only be set to yes for dynamic "
288 "simulations using the Newmark-beta numerical integrator");
289 params.addParam<Real>(
290 "newmark_beta",
291 0.25,
292 "Newmark-beta beta parameter for its inclusion in the weighted gap update formula");
293 params.addParam<Real>(
294 "newmark_gamma",
295 0.5,
296 "Newmark-beta gamma parameter for its inclusion in the weighted gap update formula");
297 params.addCoupledVar("wear_depth",
298 "The name of the mortar auxiliary variable that is used to modify the "
299 "weighted gap definition");
300 params.addParam<std::vector<TagName>>(
301 "extra_vector_tags",
302 "The tag names for extra vectors that residual data should be saved into");
303 params.addParam<std::vector<TagName>>(
304 "absolute_value_vector_tags",
305 "The tags for the vectors this residual object should fill with the "
306 "absolute value of the residual contribution");
307 params.addParam<bool>(
308 "use_petrov_galerkin",
309 false,
310 "Whether to use the Petrov-Galerkin approach for the mortar-based constraints. If set to "
311 "true, we use the standard basis as the test function and dual basis as "
312 "the shape function for the interpolation of the Lagrange multiplier variable.");
313 params.addParam<bool>(
314 "debug_mesh",
315 false,
316 "Whether we are going to enable mortar segment mesh debug information. An exodus"
317 "file will be generated if the user sets this flag to true");
318 const auto mortar_constraint_params = MortarConstraintBase::validParams();
319 params.transferParam<MooseEnum>(mortar_constraint_params, "segment_quadrature");
320 params.transferParam<Real>(mortar_constraint_params, "minimum_projection_angle");
321 params.transferParam<MooseEnum>(mortar_constraint_params, "mortar_3d_subpatch_plane");
322 params.transferParam<MooseEnum>(mortar_constraint_params, "mortar_3d_qp_mapping");
323
324 // Contact surface definition
325 params.addParamNamesToGroup("primary secondary displacements", "Contact Surface Definition");
326 // Automatic pairing
327 params.addParamNamesToGroup(
328 "automatic_pairing_boundaries automatic_pairing_distance automatic_pairing_method",
329 "Automatic Contact Pair Generation");
330 // Contact formulation and model
331 params.addParamNamesToGroup("formulation model", "Contact Formulation");
332 // Penalty parameters
333 params.addParamNamesToGroup(
334 "penalty penalty_friction penalty_multiplier penalty_multiplier_friction "
335 "max_penalty_multiplier normalize_penalty",
336 "Penalty Parameters");
337 // Augmented Lagrange settings
338 params.addParamNamesToGroup(
339 "al_penetration_tolerance al_incremental_slip_tolerance al_frictional_force_tolerance "
340 "adaptivity_penalty_normal adaptivity_penalty_friction",
341 "Augmented Lagrange");
342 // Friction
343 params.addParamNamesToGroup("friction_coefficient tension_release friction_projection_degree",
344 "Friction");
345 // Mortar-specific parameters
346 params.addParamNamesToGroup("c_normal c_tangential normal_lm_scaling tangential_lm_scaling "
347 "lm_space "
348 "use_dual correct_edge_dropping normalize_c use_petrov_galerkin "
349 "use_nodal_scaling "
350 "generate_mortar_mesh segment_quadrature minimum_projection_angle "
351 "mortar_3d_subpatch_plane mortar_3d_qp_mapping wear_depth debug_mesh",
352 "Mortar");
353 // Mortar dynamics (Newmark-beta)
354 params.addParamNamesToGroup("mortar_dynamics newmark_beta newmark_gamma", "Mortar Dynamics");
355 // Gap and tolerance settings
356 params.addParamNamesToGroup(
357 "secondary_gap_offset mapped_primary_gap_offset capture_tolerance "
358 "tangential_tolerance normal_smoothing_distance normal_smoothing_method",
359 "Gap and Tolerance");
360 // Jacobian and solver options
361 params.addParamNamesToGroup("primary_secondary_jacobian ping_pong_protection", "Solver Options");
362 // Interface ghosting
363 params.addParamNamesToGroup("ghost_whole_interface", "Interface Ghosting");
364 // Residual vector tags
365 params.addParamNamesToGroup("extra_vector_tags absolute_value_vector_tags", "Residual Tags");
366
367 return params;
368}
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: