https://mooseframework.inl.gov
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 | List of all members
ContactAction Class Reference

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

#include <ContactAction.h>

Inheritance diagram for ContactAction:
[legend]

Classes

struct  MortarInfo
 

Public Types

typedef DataFileName DataFileParameterType
 

Public Member Functions

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

Static Public Member Functions

static InputParameters validParams ()
 
static MooseEnum getModelEnum ()
 Get contact model. More...
 
static MooseEnum getFormulationEnum ()
 Get contact formulation. More...
 
static MooseEnum getSystemEnum ()
 Get contact system. More...
 
static MooseEnum getSmoothingEnum ()
 Get smoothing type. More...
 
static MooseEnum getProximityMethod ()
 Get proximity method for automatic pairing. More...
 
static InputParameters commonParameters ()
 Define parameters used by multiple contact objects. More...
 
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

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

Static Protected Member Functions

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

Protected Attributes

std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
 Primary/Secondary boundary name pairs for mechanical contact. More...
 
std::vector< BoundaryName > _automatic_pairing_boundaries
 List of all possible boundaries for contact for automatic pairing (optional) More...
 
const ContactModel _model
 Contact model type enum. More...
 
const ContactFormulation _formulation
 Contact formulation. More...
 
const ContactLMSpace _lm_space
 Finite element space to use for action-generated mortar Lagrange multiplier variables. More...
 
bool _use_dual
 Whether to use the dual Mortar approach. More...
 
const bool _generate_mortar_mesh
 Whether to generate the mortar mesh (useful in a restart simulation e.g.). More...
 
const bool _mortar_dynamics
 Whether mortar dynamic contact constraints are to be used. More...
 
std::map< std::pair< BoundaryName, BoundaryName >, const MortarInfo_bnd_pair_to_mortar_info
 Map from boundary pair to mortar user object name. More...
 
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. More...
 
void addNodeFaceContact ()
 Generate constraints for node to face contact. More...
 
void addContactPressureAuxKernel ()
 Add single contact pressure auxiliary kernel for various contact action objects. More...
 
void removeRepeatedPairs ()
 Remove repeated contact pairs from _boundary_pairs. More...
 
void createSidesetPairsFromGeometry ()
 Create contact pairs between all boundaries whose centroids are within a user-specified distance of each other. More...
 
void createSidesetsFromNodeProximity ()
 Create contact pairs between all boundaries by determining that nodes on both boundaries are close enough. More...
 

Detailed Description

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

Definition at line 32 of file ContactAction.h.

Constructor & Destructor Documentation

◆ ContactAction()

ContactAction::ContactAction ( const InputParameters params)

Definition at line 352 of file ContactAction.C.

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

Member Function Documentation

◆ act()

void ContactAction::act ( )
overridevirtual

Implements Action.

Definition at line 567 of file ContactAction.C.

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

◆ addContactPressureAuxKernel()

void ContactAction::addContactPressureAuxKernel ( )
private

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

Definition at line 782 of file ContactAction.C.

Referenced by act().

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

◆ addMortarContact()

void ContactAction::addMortarContact ( )
private

Generate mesh and other Moose objects for Mortar contact.

Definition at line 891 of file ContactAction.C.

Referenced by act().

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

◆ addNodeFaceContact()

void ContactAction::addNodeFaceContact ( )
private

Generate constraints for node to face contact.

Definition at line 1415 of file ContactAction.C.

Referenced by act().

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

◆ addRelationshipManagers() [1/3]

bool Action::addRelationshipManagers

◆ addRelationshipManagers() [2/3]

virtual void Action::addRelationshipManagers

◆ addRelationshipManagers() [3/3]

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

Reimplemented from Action.

Definition at line 852 of file ContactAction.C.

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

◆ commonParameters()

InputParameters ContactAction::commonParameters ( )
static

Define parameters used by multiple contact objects.

Returns
InputParameters object populated with common parameters

Definition at line 1829 of file ContactAction.C.

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

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

◆ createSidesetPairsFromGeometry()

void ContactAction::createSidesetPairsFromGeometry ( )
private

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

Definition at line 1642 of file ContactAction.C.

Referenced by addNodeFaceContact().

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

◆ createSidesetsFromNodeProximity()

void ContactAction::createSidesetsFromNodeProximity ( )
private

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

Definition at line 1504 of file ContactAction.C.

Referenced by addNodeFaceContact().

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

◆ getFormulationEnum()

MooseEnum ContactAction::getFormulationEnum ( )
static

Get contact formulation.

Returns
enum

Definition at line 1772 of file ContactAction.C.

Referenced by commonParameters().

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

◆ getModelEnum()

MooseEnum ContactAction::getModelEnum ( )
static

Get contact model.

Returns
enum

Definition at line 1760 of file ContactAction.C.

Referenced by commonParameters(), and validParams().

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

◆ getProximityMethod()

MooseEnum ContactAction::getProximityMethod ( )
static

Get proximity method for automatic pairing.

Returns
enum

Definition at line 1766 of file ContactAction.C.

Referenced by validParams().

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

◆ getSmoothingEnum()

MooseEnum ContactAction::getSmoothingEnum ( )
static

Get smoothing type.

Returns
enum

Definition at line 1823 of file ContactAction.C.

Referenced by commonParameters().

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

◆ getSystemEnum()

MooseEnum ContactAction::getSystemEnum ( )
static

Get contact system.

Returns
enum

Definition at line 1817 of file ContactAction.C.

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

◆ removeRepeatedPairs()

void ContactAction::removeRepeatedPairs ( )
private

Remove repeated contact pairs from _boundary_pairs.

Definition at line 526 of file ContactAction.C.

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

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

◆ validParams()

InputParameters ContactAction::validParams ( )
static

Definition at line 73 of file ContactAction.C.

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

Member Data Documentation

◆ _automatic_pairing_boundaries

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

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

Definition at line 85 of file ContactAction.h.

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

◆ _bnd_pair_to_mortar_info

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

Map from boundary pair to mortar user object name.

Definition at line 113 of file ContactAction.h.

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

◆ _boundary_pairs

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

◆ _formulation

const ContactFormulation ContactAction::_formulation
protected

◆ _generate_mortar_mesh

const bool ContactAction::_generate_mortar_mesh
protected

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

Definition at line 100 of file ContactAction.h.

Referenced by addMortarContact().

◆ _lm_space

const ContactLMSpace ContactAction::_lm_space
protected

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

Definition at line 94 of file ContactAction.h.

Referenced by act(), and addMortarContact().

◆ _model

const ContactModel ContactAction::_model
protected

Contact model type enum.

Definition at line 88 of file ContactAction.h.

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

◆ _mortar_dynamics

const bool ContactAction::_mortar_dynamics
protected

Whether mortar dynamic contact constraints are to be used.

Definition at line 103 of file ContactAction.h.

Referenced by addMortarContact().

◆ _use_dual

bool ContactAction::_use_dual
protected

Whether to use the dual Mortar approach.

Definition at line 97 of file ContactAction.h.

Referenced by addMortarContact(), and ContactAction().


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