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)
 
MooseApp & getMooseApp () 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 InputParameters & parameters () const
 
const hit::Node * getHitNode () const
 
bool hasBase () const
 
const std::string & getBase () const
 
const T & getParam (const std::string &name) const
 
std::vector< std::pair< T1, T2 > > getParam (const std::string &param1, const std::string &param2) const
 
const T * queryParam (const std::string &name) const
 
const T & getRenamedParam (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
 
PerfGraph & perfGraph ()
 
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 T & getMeshProperty (const std::string &data_name, const std::string &prefix)
 
const T & getMeshProperty (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.
 
std::string automaticPairingGeneratorName () const
 Name of the AutomaticContactPairingGenerator appended by this action.
 
void appendAutomaticPairingGenerator ()
 Append the AutomaticContactPairingGenerator that detects contact pairs among _automatic_pairing_boundaries and, for mortar contact, creates their lower-dimensional blocks.
 
void getAutomaticContactPairs ()
 Fill _boundary_pairs from the contact pairs mesh meta-data of the appended generator.
 
std::string pairSuffix (const std::pair< BoundaryName, BoundaryName > &pair) const
 Returns a name suffix encoding the boundary pair for multi-pair mortar setups, or an empty string when there is only one pair (preserving single-pair name backwards compat).
 
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 RestartableDataValue & getMeshPropertyInternal (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 355 of file ContactAction.C.

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

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

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

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

1518{
1519 if (_current_task != "add_constraint")
1520 return;
1521
1522 std::string action_name = MooseUtils::shortName(name());
1523 std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
1524 const unsigned int ndisp = displacements.size();
1525
1526 std::string constraint_type;
1527
1528 if (_formulation == ContactFormulation::RANFS)
1529 constraint_type = "RANFSNormalMechanicalContact";
1530 else
1531 constraint_type = "MechanicalContactConstraint";
1532
1533 InputParameters params = _factory.getValidParams(constraint_type);
1534
1535 params.applyParameters(parameters(),
1536 {"displacements",
1537 "secondary_gap_offset",
1538 "mapped_primary_gap_offset",
1539 "primary",
1540 "secondary"});
1541
1542 const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
1543 .system()
1544 .variable_type(displacements[0])
1545 .order.get_order();
1546
1547 params.set<std::vector<VariableName>>("displacements") = displacements;
1548 params.set<bool>("use_displaced_mesh") = true;
1549 params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
1550
1551 for (const auto & contact_pair : _boundary_pairs)
1552 {
1553 if (_formulation != ContactFormulation::RANFS)
1554 {
1555 params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area"};
1556 params.set<BoundaryName>("boundary") = contact_pair.first;
1557 if (isParamValid("secondary_gap_offset"))
1558 params.set<std::vector<VariableName>>("secondary_gap_offset") = {
1559 getParam<VariableName>("secondary_gap_offset")};
1560 if (isParamValid("mapped_primary_gap_offset"))
1561 params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
1562 getParam<VariableName>("mapped_primary_gap_offset")};
1563 }
1564
1565 for (unsigned int i = 0; i < ndisp; ++i)
1566 {
1567 std::string name = action_name + "_constraint_" + Moose::stringify(contact_pair, "_") + "_" +
1569
1570 if (_formulation == ContactFormulation::RANFS)
1571 params.set<MooseEnum>("component") = i;
1572 else
1573 params.set<unsigned int>("component") = i;
1574
1575 params.set<BoundaryName>("primary") = contact_pair.first;
1576 params.set<BoundaryName>("secondary") = contact_pair.second;
1577 params.set<NonlinearVariableName>("variable") = displacements[i];
1578 params.set<std::vector<VariableName>>("primary_variable") = {displacements[i]};
1580 {"extra_vector_tags", "absolute_value_vector_tags"});
1581 _problem->addConstraint(constraint_type, name, params);
1582 }
1583 }
1584}

Referenced by act().

◆ addRelationshipManagers() [1/3]

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

Reimplemented from Action.

Definition at line 866 of file ContactAction.C.

867{
868 if (_formulation == ContactFormulation::MORTAR ||
869 _formulation == ContactFormulation::MORTAR_PENALTY)
870 {
871 std::string action_name = MooseUtils::shortName(name());
872 for (const auto & [primary_boundary, secondary_boundary] : _boundary_pairs)
873 {
874 const std::string suffix = pairSuffix({primary_boundary, secondary_boundary});
875 auto params = MortarConstraintBase::validParams();
876 params.set<bool>("use_displaced_mesh") = true;
877 params.set<BoundaryName>("primary_boundary") = primary_boundary;
878 params.set<BoundaryName>("secondary_boundary") = secondary_boundary;
879 params.set<SubdomainName>("primary_subdomain") = action_name + "_primary_subdomain" + suffix;
880 params.set<SubdomainName>("secondary_subdomain") =
881 action_name + "_secondary_subdomain" + suffix;
882 params.set<bool>("use_petrov_galerkin") = getParam<bool>("use_petrov_galerkin");
883 params.set<Real>("minimum_projection_angle") = getParam<Real>("minimum_projection_angle");
884 params.set<MooseEnum>("mortar_3d_subpatch_plane") =
885 getParam<MooseEnum>("mortar_3d_subpatch_plane");
886 params.set<bool>("ghost_point_neighbors") = true;
887 addRelationshipManagers(input_rm_type, params);
888 }
889 }
890 else
891 {
892 const std::string constraint_type = _formulation == ContactFormulation::RANFS
893 ? "RANFSNormalMechanicalContact"
894 : "MechanicalContactConstraint";
895
896 for (const auto & contact_pair : _boundary_pairs)
897 {
898 auto params = _factory.getValidParams(constraint_type);
899 params.set<bool>("use_displaced_mesh") = true;
900 params.set<bool>("ghost_whole_interface") = getParam<bool>("ghost_whole_interface");
901 params.set<BoundaryName>("primary") = contact_pair.first;
902 params.set<BoundaryName>("secondary") = contact_pair.second;
903 addRelationshipManagers(input_rm_type, params);
904 }
905 }
906}
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 
)

◆ appendAutomaticPairingGenerator()

void ContactAction::appendAutomaticPairingGenerator ( )
private

Append the AutomaticContactPairingGenerator that detects contact pairs among _automatic_pairing_boundaries and, for mortar contact, creates their lower-dimensional blocks.

Definition at line 1593 of file ContactAction.C.

1594{
1595 // A sub-app cloning its parent mesh runs no mesh generators, so there would be no generator to
1596 // detect the pairs
1597 if (_app.useMasterMesh())
1598 paramError("automatic_pairing_boundaries",
1599 "Automatic contact pairing is not supported when cloning the parent app mesh.");
1600 if (_app.getMeshGeneratorNames().empty())
1601 paramError("automatic_pairing_boundaries",
1602 "Automatic contact pairing requires the mesh to be built by mesh generators. Use a "
1603 "FileMeshGenerator in the [Mesh] block to read a mesh file.");
1604
1605 // The generator is appended even when recovering. Generation is then skipped, but constructing
1606 // the generator declares the contact pairs mesh meta-data, which is restored from the checkpoint
1607 auto params = _factory.getValidParams("AutomaticContactPairingGenerator");
1608 params.set<std::vector<BoundaryName>>("automatic_pairing_boundaries") =
1610 params.set<Real>("automatic_pairing_distance") = getParam<Real>("automatic_pairing_distance");
1611 params.set<MooseEnum>("automatic_pairing_method") =
1612 getParam<MooseEnum>("automatic_pairing_method");
1613 params.set<std::string>("prefix") = MooseUtils::shortName(name());
1614 params.set<bool>("create_lower_d_blocks") =
1615 (_formulation == ContactFormulation::MORTAR ||
1616 _formulation == ContactFormulation::MORTAR_PENALTY) &&
1619 "AutomaticContactPairingGenerator", automaticPairingGeneratorName(), params);
1620}
std::string automaticPairingGeneratorName() const
Name of the AutomaticContactPairingGenerator appended by this action.
std::vector< std::string > getMeshGeneratorNames() const

Referenced by act().

◆ automaticPairingGeneratorName()

std::string ContactAction::automaticPairingGeneratorName ( ) const
private

Name of the AutomaticContactPairingGenerator appended by this action.

Definition at line 1587 of file ContactAction.C.

1588{
1589 return MooseUtils::shortName(name()) + "_auto_pairing_generator";
1590}

Referenced by appendAutomaticPairingGenerator(), and getAutomaticContactPairs().

◆ commonParameters()

InputParameters ContactAction::commonParameters ( )
static

Define parameters used by multiple contact objects.

Returns
InputParameters object populated with common parameters

Definition at line 1704 of file ContactAction.C.

1705{
1707
1708 params.addParam<MooseEnum>("normal_smoothing_method",
1710 "Method to use to smooth normals");
1711 params.addParam<Real>(
1712 "normal_smoothing_distance",
1713 "Distance from edge in parametric coordinates over which to smooth contact normal");
1714
1715 params.addParam<MooseEnum>(
1716 "formulation", ContactAction::getFormulationEnum(), "The contact formulation");
1717
1718 params.addParam<MooseEnum>("model", ContactAction::getModelEnum(), "The contact model to use");
1719
1720 return params;
1721}
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().

◆ getAutomaticContactPairs()

void ContactAction::getAutomaticContactPairs ( )
private

Fill _boundary_pairs from the contact pairs mesh meta-data of the appended generator.

Definition at line 1623 of file ContactAction.C.

1624{
1625 const auto & pairs = getMeshProperty<AutomaticContactPairingGenerator::ContactPairs>(
1627 _boundary_pairs.assign(pairs.begin(), pairs.end());
1628
1629 mooseInfo("The following boundary pairs were detected automatically by the contact action:");
1630 for (const auto & [primary, secondary] : _boundary_pairs)
1631 mooseInfoRepeated("Primary boundary: ", primary, " and secondary boundary: ", secondary, ".");
1632}
void mooseInfoRepeated(Args &&... args)
static constexpr auto contact_pairs_property
Name of the mesh meta-data holding the detected contact pairs.
void mooseInfo(Args &&... args) const

Referenced by act().

◆ getFormulationEnum()

MooseEnum ContactAction::getFormulationEnum ( )
static

Get contact formulation.

Returns
enum

Definition at line 1647 of file ContactAction.C.

1648{
1649 auto formulations = MooseEnum(getContactFormulationOptions(), "kinematic");
1650
1651 formulations.addDocumentation(
1652 "ranfs",
1653 "Reduced Active Nonlinear Function Set scheme for node-on-face contact. Provides exact "
1654 "enforcement without Lagrange multipliers or penalty terms.");
1655 formulations.addDocumentation(
1656 "kinematic",
1657 "Kinematic contact constraint enforcement transfers the internal forces at secondary nodes "
1658 "to the corresponding primary face for node-on-face contact. Provides exact "
1659 "enforcement without Lagrange multipliers or penalty terms.");
1660 formulations.addDocumentation(
1661 "penalty",
1662 "Node-on-face penalty based contact constraint enforcement. Interpenetration is penalized. "
1663 "Enforcement depends on the penalty magnitude. High penalties can introduce ill conditioning "
1664 "of the system.");
1665 formulations.addDocumentation("augmented_lagrange",
1666 "Node-on-face augmented Lagrange penalty based contact constraint "
1667 "enforcement. Interpenetration is enforced up to a user specified "
1668 "tolerance, ill-conditioning is generally avoided. Requires an "
1669 "Augmented Lagrange Problem class to be used in the simulation.");
1670 formulations.addDocumentation(
1671 "tangential_penalty",
1672 "Node-on-face penalty based frictional contact constraint enforcement. Interpenetration and "
1673 "slip distance for sticking nodes are penalized. Enforcement depends on the penalty "
1674 "magnitudes. High penalties can introduce ill conditioning of the system.");
1675 formulations.addDocumentation(
1676 "mortar",
1677 "Mortar based contact constraint enforcement using Lagrange multipliers. Provides exact "
1678 "enforcement and a variationally consistent formulation. Lagrange multipliers introduce a "
1679 "saddle point character in the system matrix which can have a negative impact on scalability "
1680 "with iterative solvers");
1681 formulations.addDocumentation(
1682 "mortar_penalty",
1683 "Mortar and penalty based contact constraint enforcement. When using an Augmented Lagrange "
1684 "Problem class this provides normal (and tangential) contact constratint enforced up to a "
1685 "user specified tolerances. Without AL the enforcement depends on the penalty magnitudes. "
1686 "High penalties can introduce ill conditioning of the system.");
1687
1688 return formulations;
1689}

Referenced by commonParameters().

◆ getModelEnum()

MooseEnum ContactAction::getModelEnum ( )
static

Get contact model.

Returns
enum

Definition at line 1635 of file ContactAction.C.

1636{
1637 return MooseEnum(getContactModelOptions(), "frictionless");
1638}

Referenced by commonParameters(), and validParams().

◆ getProximityMethod()

MooseEnum ContactAction::getProximityMethod ( )
static

Get proximity method for automatic pairing.

Returns
enum

Definition at line 1641 of file ContactAction.C.

1642{
1643 return MooseEnum(getProximityMethodOptions());
1644}

Referenced by validParams().

◆ getSmoothingEnum()

MooseEnum ContactAction::getSmoothingEnum ( )
static

Get smoothing type.

Returns
enum

Definition at line 1698 of file ContactAction.C.

1699{
1700 return MooseEnum("edge_based nodal_normal_based", "");
1701}

Referenced by commonParameters().

◆ getSystemEnum()

MooseEnum ContactAction::getSystemEnum ( )
static

Get contact system.

Returns
enum

Definition at line 1692 of file ContactAction.C.

1693{
1694 return MooseEnum("Constraint", "Constraint");
1695}

◆ pairSuffix()

std::string ContactAction::pairSuffix ( const std::pair< BoundaryName, BoundaryName > &  pair) const
private

Returns a name suffix encoding the boundary pair for multi-pair mortar setups, or an empty string when there is only one pair (preserving single-pair name backwards compat).

Definition at line 909 of file ContactAction.C.

910{
912}
static std::string pairSuffix(const std::pair< BoundaryName, BoundaryName > &pair)
Name suffix identifying a (primary, secondary) boundary pair, used to build unique object names when ...

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

◆ removeRepeatedPairs()

void ContactAction::removeRepeatedPairs ( )
private

Remove repeated contact pairs from _boundary_pairs.

Definition at line 535 of file ContactAction.C.

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

Referenced by ContactAction().

◆ validParams()

InputParameters ContactAction::validParams ( )
static

Definition at line 58 of file ContactAction.C.

59{
62
63 params.addParam<std::vector<BoundaryName>>(
64 "primary", "The list of boundary IDs referring to primary sidesets");
65 params.addParam<std::vector<BoundaryName>>(
66 "secondary", "The list of boundary IDs referring to secondary sidesets");
67 params.addParam<std::vector<BoundaryName>>(
68 "automatic_pairing_boundaries",
69 {},
70 "List of boundary IDs for sidesets that are automatically paired with any other boundary in "
71 "this list having a centroid-to-centroid distance less than the value specified in the "
72 "'automatic_pairing_distance' parameter. ");
74 "automatic_pairing_distance",
75 "automatic_pairing_distance>=0",
76 "The maximum distance the centroids of the boundaries provided in the "
77 "'automatic_pairing_boundaries' parameter can be to generate a contact pair automatically. "
78 "Due to numerical error in the determination of the centroids, it is encouraged that "
79 "the user adds a tolerance to this distance (e.g. extra 10%) to make sure no suitable "
80 "contact pair is missed. If the 'automatic_pairing_method = NODE' option is chosen instead, "
81 "this distance is recommended to be set to at least twice the minimum distance between "
82 "nodes of boundaries to be paired.");
83 params.addDeprecatedParam<MeshGeneratorName>(
84 "mesh",
85 "The mesh generator for mortar method",
86 "This parameter is not used anymore and can simply be removed");
87 params.addParam<VariableName>("secondary_gap_offset",
88 "Offset to gap distance from secondary side");
89 params.addParam<VariableName>("mapped_primary_gap_offset",
90 "Offset to gap distance mapped from primary side");
91 params.addParam<std::vector<VariableName>>(
92 "displacements",
93 {},
94 "The displacements appropriate for the simulation geometry and coordinate system");
95 params.addParam<Real>(
96 "penalty",
97 1e8,
98 "The penalty to apply. This can vary depending on the stiffness of your materials");
99 params.addParam<Real>(
100 "penalty_friction",
101 1e8,
102 "The penalty factor to apply in mortar penalty frictional constraints. It is applied to the "
103 "tangential accumulated slip to build the frictional force");
105 "penalty_multiplier",
106 1.0,
107 "penalty_multiplier > 0",
108 "The growth factor for the penalty applied at the end of each augmented "
109 "Lagrange update iteration (a value larger than one, e.g., 10, tends to speed up "
110 "convergence.)");
112 "penalty_multiplier_friction",
113 1.0,
114 "penalty_multiplier_friction > 0",
115 "The penalty growth factor between augmented Lagrange "
116 "iterations for penalizing relative slip distance if the node is under stick conditions.(a "
117 "value larger than one, e.g., 10, tends to speed up convergence.)");
118 params.addParam<Real>("friction_coefficient", 0, "The friction coefficient");
119 params.addParam<Real>("tension_release",
120 0.0,
121 "Tension release threshold. A node in contact "
122 "will not be released if its tensile load is below "
123 "this value. No tension release if negative.");
124 params.addParam<MooseEnum>("model", ContactAction::getModelEnum(), "The contact model to use");
125 params.addParam<Real>("tangential_tolerance",
126 "Tangential distance to extend edges of contact surfaces");
127 params.addParam<Real>("capture_tolerance",
128 0.0,
129 "Normal distance from surface within which nodes are captured. This "
130 "parameter is used for node-face and mortar formulations.");
131 params.addParam<Real>(
132 "normal_smoothing_distance",
133 "Distance from edge in parametric coordinates over which to smooth contact normal");
134
135 params.addParam<bool>("normalize_penalty",
136 false,
137 "Whether to normalize the penalty parameter with the nodal area.");
138 params.addParam<bool>(
139 "primary_secondary_jacobian",
140 true,
141 "Whether to include Jacobian entries coupling primary and secondary nodes.");
142 params.addParam<bool>(
143 "ghost_whole_interface",
144 false,
145 "Whether to geometrically and algebraically ghost the entire primary side of the interface "
146 "for node-face contact constraints.");
147 params.addParam<Real>("al_penetration_tolerance",
148 "The tolerance of the penetration for augmented Lagrangian method.");
149 params.addParam<Real>("al_incremental_slip_tolerance",
150 "The tolerance of the incremental slip for augmented Lagrangian method.");
152 "max_penalty_multiplier",
153 1.0e3,
154 "max_penalty_multiplier >= 1.0",
155 "Maximum multiplier applied to penalty factors when adaptivity is used in an augmented "
156 "Lagrange setting. The penalty factor supplied by the user is used as a reference to "
157 "determine its maximum. If this multiplier is too large, the condition number of the system "
158 "to be solved may be negatively impacted.");
159 MooseEnum adaptivity_penalty_normal("SIMPLE BUSSETTA", "SIMPLE");
160 adaptivity_penalty_normal.addDocumentation(
161 "SIMPLE", "Keep multiplying by the penalty multiplier between AL iterations");
162 adaptivity_penalty_normal.addDocumentation(
163 "BUSSETTA",
164 "Modify the penalty using an algorithm from Bussetta et al, 2012, Comput Mech 49:259-275 "
165 "between AL iterations.");
166 params.addParam<MooseEnum>(
167 "adaptivity_penalty_normal",
168 adaptivity_penalty_normal,
169 "The augmented Lagrange update strategy used on the normal penalty coefficient.");
170 MooseEnum adaptivity_penalty_friction("SIMPLE FRICTION_LIMIT", "FRICTION_LIMIT");
171 adaptivity_penalty_friction.addDocumentation(
172 "SIMPLE", "Keep multiplying by the frictional penalty multiplier between AL iterations");
173 adaptivity_penalty_friction.addDocumentation(
174 "FRICTION_LIMIT",
175 "This strategy will be guided by the Coulomb limit and be less reliant on the initial "
176 "penalty factor provided by the user.");
177 params.addParam<MooseEnum>(
178 "adaptivity_penalty_friction",
179 adaptivity_penalty_friction,
180 "The augmented Lagrange update strategy used on the frictional penalty coefficient.");
181 params.addParam<Real>("al_frictional_force_tolerance",
182 "The tolerance of the frictional force for augmented Lagrangian method.");
183 params.addParam<Real>(
184 "c_normal",
185 1e6,
186 "Parameter for balancing the size of the gap and contact pressure for a mortar formulation. "
187 "This purely numerical "
188 "parameter affects convergence behavior and, in general, should be larger for stiffer "
189 "materials. It is recommended that the user tries out various orders of magnitude for this "
190 "parameter if the default value generates poor contact convergence.");
191 params.addParam<Real>(
192 "c_tangential", 1, "Numerical parameter for nonlinear mortar frictional constraints");
193 MooseEnum friction_projection_degree("ONE TWO", "TWO");
194 friction_projection_degree.addDocumentation(
195 "ONE", "Use the degree-one Alart-Curnier friction residual.");
196 friction_projection_degree.addDocumentation(
197 "TWO", "Use the degree-two Hueber-Stadler-Wohlmuth friction residual.");
198 params.addParam<MooseEnum>("friction_projection_degree",
199 friction_projection_degree,
200 "Degree of the friction-residual projection; see "
201 "MortarContactUtils.h. Only valid for Coulomb friction mortar "
202 "contact.");
203 params.addParam<bool>("ping_pong_protection",
204 false,
205 "Whether to protect against ping-ponging, e.g. the oscillation of the "
206 "secondary node between two "
207 "different primary faces, by tying the secondary node to the "
208 "edge between the involved primary faces");
209 params.addParam<Real>(
210 "normal_lm_scaling",
211 1.,
212 "Scaling factor to apply to the normal LM variable for a mortar formulation");
213 params.addParam<Real>(
214 "tangential_lm_scaling",
215 1.,
216 "Scaling factor to apply to the tangential LM variable for a mortar formulation");
217 MooseEnum lm_space(getContactLMSpaceOptions(), "MATCH_DISPLACEMENT");
218 lm_space.addDocumentation(
219 "MATCH_DISPLACEMENT",
220 "Use the same finite element order as the displacement variables for generated mortar "
221 "Lagrange multiplier variables.");
222 lm_space.addDocumentation(
223 "LINEAR",
224 "Use first-order LAGRANGE generated mortar Lagrange multiplier variables, independent "
225 "of the displacement variable order.");
226 params.addParam<MooseEnum>(
227 "lm_space",
228 lm_space,
229 "Finite element space for mortar Lagrange multiplier variables generated by the "
230 "contact action. This parameter only applies to the 'mortar' contact formulation.");
231 params.addParam<bool>(
232 "normalize_c",
233 false,
234 "Whether to normalize c by weighting function norm for mortar contact. When unnormalized "
235 "the value of c effectively depends on element size since in the constraint we compare nodal "
236 "Lagrange Multiplier values to integrated gap values (LM nodal value is independent of "
237 "element size, where integrated values are dependent on element size).");
238 params.addClassDescription("Sets up all objects needed for mechanical contact enforcement");
239 params.addParam<bool>(
240 "use_dual",
241 "Whether to use the dual mortar approach within a mortar formulation. It is defaulted to "
242 "true for "
243 "weighted quantity approach, and to false for the legacy approach. To avoid instabilities "
244 "in the solution and obtain the full benefits of a variational enforcement,"
245 "use of dual mortar with weighted constraints is strongly recommended. This "
246 "input is only intended for advanced users.");
247 params.addParam<bool>(
248 "correct_edge_dropping",
249 false,
250 "Whether to enable correct edge dropping treatment for mortar constraints. When disabled "
251 "any Lagrange Multiplier degree of freedom on a secondary element without full primary "
252 "contributions will be set (strongly) to 0.");
253 params.addParam<bool>(
254 "use_nodal_scaling",
255 false,
256 "Whether to apply the node-based Lagrange-multiplier scaling of Popp et al. (2013) to "
257 "improve the conditioning of the linear system when secondary elements are only partially "
258 "covered (edge dropping). See the documentation for the current limitations.");
260 params.addParam<bool>(
261 "generate_mortar_mesh",
262 true,
263 "Whether to generate the mortar mesh from the action. Typically this will be the case, but "
264 "one may also want to reuse an existing lower-dimensional mesh prior to a restart.");
265 params.addParam<MooseEnum>("automatic_pairing_method",
267 "The proximity method used for automatic pairing of boundaries.");
268 params.addParam<bool>(
269 "mortar_dynamics",
270 false,
271 "Whether to use constraints that account for the persistency condition, giving rise to "
272 "smoother normal contact pressure evolution. This flag should only be set to yes for dynamic "
273 "simulations using the Newmark-beta numerical integrator");
274 params.addParam<Real>(
275 "newmark_beta",
276 0.25,
277 "Newmark-beta beta parameter for its inclusion in the weighted gap update formula");
278 params.addParam<Real>(
279 "newmark_gamma",
280 0.5,
281 "Newmark-beta gamma parameter for its inclusion in the weighted gap update formula");
282 params.addCoupledVar("wear_depth",
283 "The name of the mortar auxiliary variable that is used to modify the "
284 "weighted gap definition");
285 params.addParam<std::vector<TagName>>(
286 "extra_vector_tags",
287 "The tag names for extra vectors that residual data should be saved into");
288 params.addParam<std::vector<TagName>>(
289 "absolute_value_vector_tags",
290 "The tags for the vectors this residual object should fill with the "
291 "absolute value of the residual contribution");
292 params.addParam<bool>(
293 "use_petrov_galerkin",
294 false,
295 "Whether to use the Petrov-Galerkin approach for the mortar-based constraints. If set to "
296 "true, we use the standard basis as the test function and dual basis as "
297 "the shape function for the interpolation of the Lagrange multiplier variable.");
298 params.addParam<bool>(
299 "debug_mesh",
300 false,
301 "Whether we are going to enable mortar segment mesh debug information. An exodus"
302 "file will be generated if the user sets this flag to true");
303 const auto mortar_constraint_params = MortarConstraintBase::validParams();
304 params.transferParam<MooseEnum>(mortar_constraint_params, "segment_quadrature");
305 params.transferParam<Real>(mortar_constraint_params, "minimum_projection_angle");
306 params.transferParam<MooseEnum>(mortar_constraint_params, "mortar_3d_subpatch_plane");
307 params.transferParam<MooseEnum>(mortar_constraint_params, "mortar_3d_qp_mapping");
308
309 // Contact surface definition
310 params.addParamNamesToGroup("primary secondary displacements", "Contact Surface Definition");
311 // Automatic pairing
312 params.addParamNamesToGroup(
313 "automatic_pairing_boundaries automatic_pairing_distance automatic_pairing_method",
314 "Automatic Contact Pair Generation");
315 // Contact formulation and model
316 params.addParamNamesToGroup("formulation model", "Contact Formulation");
317 // Penalty parameters
318 params.addParamNamesToGroup(
319 "penalty penalty_friction penalty_multiplier penalty_multiplier_friction "
320 "max_penalty_multiplier normalize_penalty",
321 "Penalty Parameters");
322 // Augmented Lagrange settings
323 params.addParamNamesToGroup(
324 "al_penetration_tolerance al_incremental_slip_tolerance al_frictional_force_tolerance "
325 "adaptivity_penalty_normal adaptivity_penalty_friction",
326 "Augmented Lagrange");
327 // Friction
328 params.addParamNamesToGroup("friction_coefficient tension_release friction_projection_degree",
329 "Friction");
330 // Mortar-specific parameters
331 params.addParamNamesToGroup("c_normal c_tangential normal_lm_scaling tangential_lm_scaling "
332 "lm_space "
333 "use_dual correct_edge_dropping normalize_c use_petrov_galerkin "
334 "use_nodal_scaling "
335 "generate_mortar_mesh segment_quadrature minimum_projection_angle "
336 "mortar_3d_subpatch_plane mortar_3d_qp_mapping wear_depth debug_mesh",
337 "Mortar");
338 // Mortar dynamics (Newmark-beta)
339 params.addParamNamesToGroup("mortar_dynamics newmark_beta newmark_gamma", "Mortar Dynamics");
340 // Gap and tolerance settings
341 params.addParamNamesToGroup(
342 "secondary_gap_offset mapped_primary_gap_offset capture_tolerance "
343 "tangential_tolerance normal_smoothing_distance normal_smoothing_method",
344 "Gap and Tolerance");
345 // Jacobian and solver options
346 params.addParamNamesToGroup("primary_secondary_jacobian ping_pong_protection", "Solver Options");
347 // Interface ghosting
348 params.addParamNamesToGroup("ghost_whole_interface", "Interface Ghosting");
349 // Residual vector tags
350 params.addParamNamesToGroup("extra_vector_tags absolute_value_vector_tags", "Residual Tags");
351
352 return params;
353}
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 act(), addMortarContact(), appendAutomaticPairingGenerator(), ContactAction(), 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

Primary/Secondary boundary name pairs for mechanical contact.

Definition at line 82 of file ContactAction.h.

Referenced by act(), addContactPressureAuxKernel(), addMortarContact(), addNodeFaceContact(), addRelationshipManagers(), ContactAction(), getAutomaticContactPairs(), pairSuffix(), and removeRepeatedPairs().

◆ _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(), and appendAutomaticPairingGenerator().

◆ _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: