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 haveParameter (const std::string &name) 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...
 
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 31 of file ContactAction.h.

Constructor & Destructor Documentation

◆ ContactAction()

ContactAction::ContactAction ( const InputParameters params)

Definition at line 330 of file ContactAction.C.

331  : Action(params),
332  _boundary_pairs(getParam<BoundaryName, BoundaryName>("primary", "secondary")),
333  _model(getParam<MooseEnum>("model").getEnum<ContactModel>()),
334  _formulation(getParam<MooseEnum>("formulation").getEnum<ContactFormulation>()),
335  _generate_mortar_mesh(getParam<bool>("generate_mortar_mesh")),
336  _mortar_dynamics(getParam<bool>("mortar_dynamics"))
337 {
338  // Check for automatic selection of contact pairs.
339  if (getParam<std::vector<BoundaryName>>("automatic_pairing_boundaries").size() > 1)
341  getParam<std::vector<BoundaryName>>("automatic_pairing_boundaries");
342 
343  if (_automatic_pairing_boundaries.size() > 0 && !isParamValid("automatic_pairing_distance"))
344  paramError("automatic_pairing_distance",
345  "For automatic selection of contact pairs (for particular geometries) in contact "
346  "action, 'automatic_pairing_distance' needs to be provided.");
347 
348  if (_automatic_pairing_boundaries.size() > 0 && !isParamValid("automatic_pairing_method"))
349  paramError("automatic_pairing_distance",
350  "For automatic selection of contact pairs (for particular geometries) in contact "
351  "action, 'automatic_pairing_method' needs to be provided.");
352 
353  if (_automatic_pairing_boundaries.size() > 0 && _boundary_pairs.size() != 0)
354  paramError("automatic_pairing_boundaries",
355  "If a boundary list is provided, primary and secondary surfaces will be identified "
356  "automatically. Therefore, one cannot provide an automatic pairing boundary list "
357  "and primary/secondary lists.");
358  else if (_automatic_pairing_boundaries.size() == 0 && _boundary_pairs.size() == 0)
359  paramError("primary",
360  "'primary' and 'secondary' surfaces or a list of boundaries for automatic pair "
361  "generation need to be provided.");
362 
363  // End of checks for automatic selection of contact pairs.
364 
365  if (_boundary_pairs.size() != 1 && _formulation == ContactFormulation::MORTAR)
366  paramError("formulation", "When using mortar, a vector of contact pairs cannot be used");
367 
368  if ((_formulation == ContactFormulation::MORTAR ||
369  _formulation == ContactFormulation::MORTAR_PENALTY) &&
370  params.isParamSetByUser("ghost_whole_interface"))
371  paramError("ghost_whole_interface",
372  "The 'ghost_whole_interface' parameter is only supported for node-face contact "
373  "formulations. Mortar contact always geometrically and algebraically ghosts the "
374  "interface.");
375 
376  if (_formulation == ContactFormulation::TANGENTIAL_PENALTY && _model != ContactModel::COULOMB)
377  paramError("formulation",
378  "The 'tangential_penalty' formulation can only be used with the 'coulomb' model");
379 
380  if (_formulation == ContactFormulation::MORTAR_PENALTY)
381  {
382  // Use dual basis functions for contact traction interpolation
383  if (isParamValid("use_dual"))
384  _use_dual = getParam<bool>("use_dual");
385  else
386  _use_dual = true;
387 
388  if (_model == ContactModel::GLUED)
389  paramError("model", "The 'mortar_penalty' formulation does not support glued contact");
390 
391  if (getParam<bool>("mortar_dynamics"))
392  paramError("mortar_dynamics",
393  "The 'mortar_penalty' formulation does not support implicit dynamic simulations");
394 
395  if (getParam<bool>("use_petrov_galerkin"))
396  paramError("use_petrov_galerkin",
397  "The 'mortar_penalty' formulation does not support usage of the Petrov-Galerkin "
398  "flag. The default (use_dual = true) behavior is such that contact tractions are "
399  "interpolated with dual bases whereas mortar or weighted contact quantities are "
400  "interpolated with Lagrange shape functions.");
401  }
402 
403  if (_formulation == ContactFormulation::MORTAR)
404  {
405  if (_model == ContactModel::GLUED)
406  paramError("model", "The 'mortar' formulation does not support glued contact (yet)");
407 
408  // use dual basis function for Lagrange multipliers?
409  if (isParamValid("use_dual"))
410  _use_dual = getParam<bool>("use_dual");
411  else
412  _use_dual = true;
413 
414  if (!getParam<bool>("mortar_dynamics"))
415  {
416  if (params.isParamSetByUser("newmark_beta"))
417  paramError("newmark_beta", "newmark_beta can only be used with the mortar_dynamics option");
418 
419  if (params.isParamSetByUser("newmark_gamma"))
420  paramError("newmark_gamma",
421  "newmark_gamma can only be used with the mortar_dynamics option");
422  }
423 
424  if (isParamSetByUser("penalty"))
425  paramError("penalty",
426  "The 'penalty' parameter is not used for the 'mortar' formulation which instead "
427  "uses Lagrange multipliers");
428  }
429  else
430  {
431  if (params.isParamSetByUser("correct_edge_dropping"))
432  paramError(
433  "correct_edge_dropping",
434  "The 'correct_edge_dropping' option can only be used with the 'mortar' formulation "
435  "(weighted)");
436  else if (params.isParamSetByUser("use_dual") &&
437  _formulation != ContactFormulation::MORTAR_PENALTY)
438  paramError("use_dual",
439  "The 'use_dual' option can only be used with the 'mortar' formulation");
440  else if (params.isParamSetByUser("c_normal"))
441  paramError("c_normal",
442  "The 'c_normal' option can only be used with the 'mortar' formulation");
443  else if (params.isParamSetByUser("c_tangential"))
444  paramError("c_tangential",
445  "The 'c_tangential' option can only be used with the 'mortar' formulation");
446  else if (params.isParamSetByUser("mortar_dynamics"))
447  paramError("mortar_dynamics",
448  "The 'mortar_dynamics' constraint option can only be used with the 'mortar' "
449  "formulation and in dynamic simulations using Newmark-beta");
450  else if (params.isParamSetByUser("segment_quadrature"))
451  paramError("segment_quadrature",
452  "The 'segment_quadrature' option can only be used with the "
453  "'mortar' formulation.");
454  }
455 
456  if (_formulation == ContactFormulation::RANFS)
457  {
458  if (isParamValid("secondary_gap_offset"))
459  paramError("secondary_gap_offset",
460  "The 'secondary_gap_offset' option can only be used with the "
461  "'MechanicalContactConstraint'");
462  if (isParamValid("mapped_primary_gap_offset"))
463  paramError("mapped_primary_gap_offset",
464  "The 'mapped_primary_gap_offset' option can only be used with the "
465  "'MechanicalContactConstraint'");
466  }
467  else if (getParam<bool>("ping_pong_protection"))
468  paramError("ping_pong_protection",
469  "The 'ping_pong_protection' option can only be used with the 'ranfs' formulation");
470 
471  // Remove repeated pairs from input file.
473 }
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:81
std::vector< BoundaryName > _automatic_pairing_boundaries
List of all possible boundaries for contact for automatic pairing (optional)
Definition: ContactAction.h:84
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:90
const bool _generate_mortar_mesh
Whether to generate the mortar mesh (useful in a restart simulation e.g.).
Definition: ContactAction.h:96
const bool _mortar_dynamics
Whether mortar dynamic contact constraints are to be used.
Definition: ContactAction.h:99
bool isParamSetByUser(const std::string &name) const
bool _use_dual
Whether to use the dual Mortar approach.
Definition: ContactAction.h:93
bool isParamValid(const std::string &name) const
const ContactModel _model
Contact model type enum.
Definition: ContactAction.h:87
bool isParamSetByUser(const std::string &name) const

Member Function Documentation

◆ act()

void ContactAction::act ( )
overridevirtual

Implements Action.

Definition at line 517 of file ContactAction.C.

518 {
519  // proform problem checks/corrections once during the first feasible task
520  if (_current_task == "add_contact_aux_variable")
521  {
522  if (!_problem->getDisplacedProblem())
523  mooseError(
524  "Contact requires updated coordinates. Use the 'displacements = ...' parameter in the "
525  "Mesh block.");
526 
527  // It is risky to apply this optimization to contact problems
528  // since the problem configuration may be changed during Jacobian
529  // evaluation. We therefore turn it off for all contact problems so that
530  // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3.
531  if (!_problem->isSNESMFReuseBaseSetbyUser())
532  _problem->setSNESMFReuseBase(false, false);
533  }
534 
535  if (_formulation == ContactFormulation::MORTAR ||
536  _formulation == ContactFormulation::MORTAR_PENALTY)
538  else
540 
541  if (_current_task == "add_aux_kernel")
542  {
543  if (!_problem->getDisplacedProblem())
544  mooseError("Contact requires updated coordinates. Use the 'displacements = ...' line in the "
545  "Mesh block.");
546 
547  // Create auxiliary kernels for each contact pairs
548  for (const auto & contact_pair : _boundary_pairs)
549  {
550  const auto & [primary_name, secondary_name] = contact_pair;
551  if ((_formulation != ContactFormulation::MORTAR) &&
552  (_formulation != ContactFormulation::MORTAR_PENALTY))
553  {
554  InputParameters params = _factory.getValidParams("PenetrationAux");
555  params.applyParameters(parameters(),
556  {"secondary_gap_offset", "mapped_primary_gap_offset", "order"});
557 
558  std::vector<VariableName> displacements =
559  getParam<std::vector<VariableName>>("displacements");
560  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
561  .system()
562  .variable_type(displacements[0])
563  .order.get_order();
564 
565  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
566  params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR};
567  params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
568  params.set<BoundaryName>("paired_boundary") = primary_name;
569  params.set<AuxVariableName>("variable") = "penetration";
570  if (isParamValid("secondary_gap_offset"))
571  params.set<std::vector<VariableName>>("secondary_gap_offset") = {
572  getParam<VariableName>("secondary_gap_offset")};
573  if (isParamValid("mapped_primary_gap_offset"))
574  params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
575  getParam<VariableName>("mapped_primary_gap_offset")};
576  params.set<bool>("use_displaced_mesh") = true;
577  std::string name = _name + "_contact_" + Moose::stringify(contact_auxkernel_counter++);
578 
579  _problem->addAuxKernel("PenetrationAux", name, params);
580  }
581  else
582  {
583  const auto type = "MortarUserObjectAux";
585  params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
586  params.set<AuxVariableName>("variable") = "gap";
587  params.set<bool>("use_displaced_mesh") = true; // Unnecessary as this object only operates
588  // on nodes, but we'll do it for consistency
589  params.set<MooseEnum>("contact_quantity") = "normal_gap";
590  const auto & [primary_id, secondary_id, uo_name] =
591  libmesh_map_find(_bnd_pair_to_mortar_info, contact_pair);
592  params.set<UserObjectName>("user_object") = uo_name;
593  std::string name = _name + "_contact_gap_" + std::to_string(primary_id) + "_" +
594  std::to_string(secondary_id);
595 
596  _problem->addAuxKernel(type, name, params);
597  }
598  }
599 
601 
602  const unsigned int ndisp = getParam<std::vector<VariableName>>("displacements").size();
603 
604  // Add MortarFrictionalPressureVectorAux
605  if (_formulation == ContactFormulation::MORTAR && _model == ContactModel::COULOMB && ndisp > 2)
606  {
607  {
608  InputParameters params = _factory.getValidParams("MortarFrictionalPressureVectorAux");
609 
610  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
611  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
612  params.set<std::vector<BoundaryName>>("boundary") = {_boundary_pairs[0].second};
613  params.set<ExecFlagEnum>("execute_on", true) = {EXEC_NONLINEAR};
614 
615  std::string action_name = MooseUtils::shortName(name());
616  const std::string tangential_lagrange_multiplier_name = action_name + "_tangential_lm";
617  const std::string tangential_lagrange_multiplier_3d_name =
618  action_name + "_tangential_3d_lm";
619 
620  params.set<std::vector<VariableName>>("tangent_one") = {
621  tangential_lagrange_multiplier_name};
622  params.set<std::vector<VariableName>>("tangent_two") = {
623  tangential_lagrange_multiplier_3d_name};
624 
625  std::vector<std::string> disp_components({"x", "y", "z"});
626  unsigned component_index = 0;
627 
628  // Loop over three displacements
629  for (const auto & disp_component : disp_components)
630  {
631  params.set<AuxVariableName>("variable") = _name + "_tangent_" + disp_component;
632  params.set<unsigned int>("component") = component_index;
633 
634  std::string name = _name + "_mortar_frictional_pressure_" + disp_component + "_" +
636 
637  _problem->addAuxKernel("MortarFrictionalPressureVectorAux", name, params);
638  component_index++;
639  }
640  }
641  }
642  }
643 
644  if (_current_task == "add_contact_aux_variable")
645  {
646  std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
647  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
648  .system()
649  .variable_type(displacements[0])
650  .order.get_order();
651  std::unique_ptr<InputParameters> current_params;
652  const auto create_aux_var_params = [this, order, &current_params]() -> InputParameters &
653  {
654  current_params = std::make_unique<InputParameters>(_factory.getValidParams("MooseVariable"));
655  current_params->set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
656  current_params->set<MooseEnum>("family") = "LAGRANGE";
657  return *current_params;
658  };
659 
660  if ((_formulation != ContactFormulation::MORTAR) &&
661  (_formulation != ContactFormulation::MORTAR_PENALTY))
662  {
663  // Add penetration aux variable
664  _problem->addAuxVariable("MooseVariable", "penetration", create_aux_var_params());
665  // Add nodal area aux variable
666  _problem->addAuxVariable("MooseVariable", "nodal_area", create_aux_var_params());
667  }
668  else
669  _problem->addAuxVariable("MooseVariable", "gap", create_aux_var_params());
670 
671  // Add contact pressure aux variable
672  _problem->addAuxVariable("MooseVariable", "contact_pressure", create_aux_var_params());
673 
674  const unsigned int ndisp = getParam<std::vector<VariableName>>("displacements").size();
675 
676  // Add MortarFrictionalPressureVectorAux variables
677  if (_formulation == ContactFormulation::MORTAR && _model == ContactModel::COULOMB && ndisp > 2)
678  {
679  {
680  std::vector<std::string> disp_components({"x", "y", "z"});
681  // Loop over three displacements
682  for (const auto & disp_component : disp_components)
683  {
684  auto var_params = _factory.getValidParams("MooseVariable");
685  var_params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
686  var_params.set<MooseEnum>("family") = "LAGRANGE";
687 
688  _problem->addAuxVariable(
689  "MooseVariable", _name + "_tangent_" + disp_component, var_params);
690  }
691  }
692  }
693  }
694 
695  if (_current_task == "add_user_object" && (_formulation != ContactFormulation::MORTAR) &&
696  (_formulation != ContactFormulation::MORTAR_PENALTY))
697  {
698  auto var_params = _factory.getValidParams("NodalArea");
699 
700  // Get secondary_boundary_vector from possibly updated set from the
701  // ContactAction constructor cleanup
702  const auto actions = _awh.getActions<ContactAction>();
703 
704  std::vector<BoundaryName> secondary_boundary_vector;
705  for (const auto * const action : actions)
706  for (const auto j : index_range(action->_boundary_pairs))
707  secondary_boundary_vector.push_back(action->_boundary_pairs[j].second);
708 
709  var_params.set<std::vector<BoundaryName>>("boundary") = secondary_boundary_vector;
710  var_params.set<std::vector<VariableName>>("variable") = {"nodal_area"};
711 
712  mooseAssert(_problem, "Problem pointer is NULL");
713  var_params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_TIMESTEP_BEGIN};
714  var_params.set<bool>("use_displaced_mesh") = true;
715 
716  _problem->addUserObject("NodalArea",
717  "nodal_area_object_" + Moose::stringify(contact_userobject_counter++),
718  var_params);
719  }
720 }
Action class for creating constraints, kernels, and user objects necessary for mechanical contact...
Definition: ContactAction.h:31
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:81
const std::string & _name
ActionWarehouse & _awh
Factory & _factory
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:52
void applyParameters(const InputParameters &common, const std::vector< std::string > &exclude={}, const bool allow_private=false)
const ContactFormulation _formulation
Contact formulation.
Definition: ContactAction.h:90
std::string shortName(const std::string &name)
static unsigned int contact_mortar_auxkernel_counter
Definition: ContactAction.C:46
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:49
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:87
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 723 of file ContactAction.C.

Referenced by act().

724 {
725  // Increment counter for contact action objects
727 
728  if ((_formulation != ContactFormulation::MORTAR) &&
729  (_formulation != ContactFormulation::MORTAR_PENALTY))
730  {
731  // Add ContactPressureAux: Only one object for all contact pairs
732  const auto actions = _awh.getActions<ContactAction>();
733 
734  // Add auxiliary kernel if we are the last contact action object.
735  if (contact_action_counter == actions.size())
736  {
737  std::vector<BoundaryName> boundary_vector;
738  std::vector<BoundaryName> pair_boundary_vector;
739 
740  for (const auto * const action : actions)
741  for (const auto j : index_range(action->_boundary_pairs))
742  {
743  boundary_vector.push_back(action->_boundary_pairs[j].second);
744  pair_boundary_vector.push_back(action->_boundary_pairs[j].first);
745  }
746 
747  InputParameters params = _factory.getValidParams("ContactPressureAux");
748  params.applyParameters(parameters(), {"order"});
749 
750  std::vector<VariableName> displacements =
751  getParam<std::vector<VariableName>>("displacements");
752  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
753  .system()
754  .variable_type(displacements[0])
755  .order.get_order();
756 
757  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
758  params.set<std::vector<BoundaryName>>("boundary") = boundary_vector;
759  params.set<std::vector<BoundaryName>>("paired_boundary") = pair_boundary_vector;
760  params.set<AuxVariableName>("variable") = "contact_pressure";
761  params.addRequiredCoupledVar("nodal_area", "The nodal area");
762  params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area"};
763  params.set<bool>("use_displaced_mesh") = true;
764 
765  std::string name = _name + "_contact_pressure";
766  params.set<ExecFlagEnum>("execute_on",
768  _problem->addAuxKernel("ContactPressureAux", name, params);
769  }
770  }
771  else
772  for (const auto & contact_pair : _boundary_pairs)
773  {
774  const auto & [_, secondary_name] = contact_pair;
775  const auto type = "MortarUserObjectAux";
777  params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
778  params.set<AuxVariableName>("variable") = "contact_pressure";
779  params.set<bool>("use_displaced_mesh") = true; // Unecessary as this object only operates on
780  // nodes, but we'll do it for consistency
781  params.set<MooseEnum>("contact_quantity") = "normal_pressure";
782  const auto & [primary_id, secondary_id, uo_name] =
783  libmesh_map_find(_bnd_pair_to_mortar_info, contact_pair);
784  params.set<UserObjectName>("user_object") = uo_name;
785  const std::string name = _name + "_contact_pressure" + std::to_string(primary_id) + "_" +
786  std::to_string(secondary_id);
787 
788  _problem->addAuxKernel(type, name, params);
789  }
790 }
Action class for creating constraints, kernels, and user objects necessary for mechanical contact...
Definition: ContactAction.h:31
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:81
const std::string & _name
ActionWarehouse & _awh
Factory & _factory
const InputParameters & parameters() const
static unsigned int contact_action_counter
Definition: ContactAction.C:55
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:90
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 829 of file ContactAction.C.

Referenced by act().

830 {
831  std::string action_name = MooseUtils::shortName(name());
832 
833  std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
834  const unsigned int ndisp = displacements.size();
835 
836  // Definitions for mortar contact.
837  const std::string primary_subdomain_name = action_name + "_primary_subdomain";
838  const std::string secondary_subdomain_name = action_name + "_secondary_subdomain";
839  const std::string normal_lagrange_multiplier_name = action_name + "_normal_lm";
840  const std::string tangential_lagrange_multiplier_name = action_name + "_tangential_lm";
841  const std::string tangential_lagrange_multiplier_3d_name = action_name + "_tangential_3d_lm";
842  const std::string auxiliary_lagrange_multiplier_name = action_name + "_aux_lm";
843 
844  if (_current_task == "append_mesh_generator")
845  {
846  // Don't do mesh generators when recovering or when the user has requested for us not to
847  // (presumably because the lower-dimensional blocks are already in the mesh due to manual
848  // addition or because we are restarting)
851  {
852  const MeshGeneratorName primary_name = primary_subdomain_name + "_generator";
853  const MeshGeneratorName secondary_name = secondary_subdomain_name + "_generator";
854 
855  auto primary_params = _factory.getValidParams("LowerDBlockFromSidesetGenerator");
856  auto secondary_params = _factory.getValidParams("LowerDBlockFromSidesetGenerator");
857 
858  primary_params.set<SubdomainName>("new_block_name") = primary_subdomain_name;
859  secondary_params.set<SubdomainName>("new_block_name") = secondary_subdomain_name;
860 
861  primary_params.set<std::vector<BoundaryName>>("sidesets") = {_boundary_pairs[0].first};
862  secondary_params.set<std::vector<BoundaryName>>("sidesets") = {_boundary_pairs[0].second};
863 
864  _app.appendMeshGenerator("LowerDBlockFromSidesetGenerator", primary_name, primary_params);
865  _app.appendMeshGenerator("LowerDBlockFromSidesetGenerator", secondary_name, secondary_params);
866  }
867  }
868 
869  // Add the lagrange multiplier on the secondary subdomain.
870  const auto addLagrangeMultiplier =
871  [this, &secondary_subdomain_name, &displacements](const std::string & variable_name,
872  const Real scaling_factor,
873  const bool add_aux_lm,
874  const bool penalty_traction) //
875  {
876  InputParameters params = _factory.getValidParams("MooseVariableBase");
877 
878  // Allow the user to select "weighted" constraints and standard bases (use_dual = false) or
879  // "legacy" constraints and dual bases (use_dual = true). Unless it's for testing purposes,
880  // this combination isn't recommended
881  if (!add_aux_lm || penalty_traction)
882  params.set<bool>("use_dual") = _use_dual;
883 
884  mooseAssert(_problem->systemBaseNonlinear(/*nl_sys_num=*/0).hasVariable(displacements[0]),
885  "Displacement variable is missing");
886  const auto primal_type =
887  _problem->systemBaseNonlinear(/*nl_sys_num=*/0).system().variable_type(displacements[0]);
888 
889  const int lm_order = primal_type.order.get_order();
890 
891  if (primal_type.family == LAGRANGE)
892  {
893  params.set<MooseEnum>("family") = Utility::enum_to_string<FEFamily>(primal_type.family);
894  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{lm_order});
895  }
896  else
897  mooseError("Invalid bases for mortar contact.");
898 
899  params.set<std::vector<SubdomainName>>("block") = {secondary_subdomain_name};
900  if (!(add_aux_lm || penalty_traction))
901  params.set<std::vector<Real>>("scaling") = {scaling_factor};
902 
903  auto fe_type = AddVariableAction::feType(params);
904  auto var_type = AddVariableAction::variableType(fe_type);
905  if (add_aux_lm || penalty_traction)
906  _problem->addAuxVariable(var_type, variable_name, params);
907  else
908  _problem->addVariable(var_type, variable_name, params);
909  };
910 
911  if (_current_task == "add_mortar_variable" && _formulation == ContactFormulation::MORTAR)
912  {
913  addLagrangeMultiplier(
914  normal_lagrange_multiplier_name, getParam<Real>("normal_lm_scaling"), false, false);
915 
916  if (_model == ContactModel::COULOMB)
917  {
918  addLagrangeMultiplier(tangential_lagrange_multiplier_name,
919  getParam<Real>("tangential_lm_scaling"),
920  false,
921  false);
922  if (ndisp > 2)
923  addLagrangeMultiplier(tangential_lagrange_multiplier_3d_name,
924  getParam<Real>("tangential_lm_scaling"),
925  false,
926  false);
927  }
928 
929  if (getParam<bool>("use_petrov_galerkin"))
930  addLagrangeMultiplier(auxiliary_lagrange_multiplier_name, 1.0, true, false);
931  }
932  else if (_current_task == "add_mortar_variable" &&
933  _formulation == ContactFormulation::MORTAR_PENALTY)
934  {
935  if (_use_dual)
936  addLagrangeMultiplier(auxiliary_lagrange_multiplier_name, 1.0, false, true);
937  }
938 
939  if (_current_task == "add_user_object")
940  {
941  const auto register_mortar_uo_name = [this](const auto & bnd_pair, const auto & uo_prefix)
942  {
943  const auto & [primary_name, secondary_name] = bnd_pair;
944  const auto primary_id = _mesh->getBoundaryID(primary_name);
945  const auto secondary_id = _mesh->getBoundaryID(secondary_name);
946  const auto uo_name = uo_prefix + name();
947  _bnd_pair_to_mortar_info.emplace(bnd_pair, MortarInfo{primary_id, secondary_id, uo_name});
948  return uo_name;
949  };
950 
951  // check if the correct problem class is selected if AL parameters are provided
952  if (_formulation == ContactFormulation::MORTAR_PENALTY &&
953  !dynamic_cast<AugmentedLagrangianContactProblemInterface *>(_problem.get()))
954  {
955  const std::vector<std::string> params = {"penalty_multiplier",
956  "penalty_multiplier_friction",
957  "al_penetration_tolerance",
958  "al_incremental_slip_tolerance",
959  "al_frictional_force_tolerance"};
960  for (const auto & param : params)
961  if (parameters().isParamSetByUser(param))
962  paramError(param,
963  "Augmented Lagrange parameter was specified, but the selected problem type "
964  "does not support Augmented Lagrange iterations.");
965  }
966 
967  if (_model != ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR)
968  {
969  auto uo_params = _factory.getValidParams("LMWeightedGapUserObject");
970 
971  uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
972  uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
973  uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
974  uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
975  uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
976  uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
977  if (ndisp > 2)
978  uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
979  uo_params.set<bool>("use_displaced_mesh") = true;
980  uo_params.set<std::vector<VariableName>>("lm_variable") = {normal_lagrange_multiplier_name};
981  uo_params.applySpecificParameters(
982  parameters(), {"correct_edge_dropping", "use_petrov_galerkin", "debug_mesh"});
983  if (getParam<bool>("use_petrov_galerkin"))
984  uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
985 
986  _problem->addUserObject("LMWeightedGapUserObject",
987  register_mortar_uo_name(_boundary_pairs[0], "lm_weightedgap_object_"),
988  uo_params);
989  }
990  else if (_model == ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR)
991  {
992  auto uo_params = _factory.getValidParams("LMWeightedVelocitiesUserObject");
993  uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
994  uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
995  uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
996  uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
997  uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
998  uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
999  if (ndisp > 2)
1000  uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1001 
1002  uo_params.set<VariableName>("secondary_variable") = displacements[0];
1003  uo_params.set<bool>("use_displaced_mesh") = true;
1004  uo_params.set<std::vector<VariableName>>("lm_variable_normal") = {
1005  normal_lagrange_multiplier_name};
1006  uo_params.set<std::vector<VariableName>>("lm_variable_tangential_one") = {
1007  tangential_lagrange_multiplier_name};
1008  if (ndisp > 2)
1009  uo_params.set<std::vector<VariableName>>("lm_variable_tangential_two") = {
1010  tangential_lagrange_multiplier_3d_name};
1011  uo_params.applySpecificParameters(
1012  parameters(), {"correct_edge_dropping", "use_petrov_galerkin", "debug_mesh"});
1013  if (getParam<bool>("use_petrov_galerkin"))
1014  uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
1015 
1016  const auto uo_name = _problem->addUserObject(
1017  "LMWeightedVelocitiesUserObject",
1018  register_mortar_uo_name(_boundary_pairs[0], "lm_weightedvelocities_object_"),
1019  uo_params);
1020  }
1021 
1022  if (_model != ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR_PENALTY)
1023  {
1024  auto uo_params = _factory.getValidParams("PenaltyWeightedGapUserObject");
1025 
1026  uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1027  uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1028  uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1029  uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1030  uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1031  uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1032 
1033  // AL parameters
1034  uo_params.applySpecificParameters(parameters(),
1035  {"correct_edge_dropping",
1036  "penalty",
1037  "debug_mesh",
1038  "max_penalty_multiplier",
1039  "adaptivity_penalty_normal"});
1040 
1041  if (isParamValid("al_penetration_tolerance"))
1042  uo_params.set<Real>("penetration_tolerance") = getParam<Real>("al_penetration_tolerance");
1043  if (isParamValid("penalty_multiplier"))
1044  uo_params.set<Real>("penalty_multiplier") = getParam<Real>("penalty_multiplier");
1045  // In the contact action, we force the physical value of the normal gap, which also normalizes
1046  // the penalty factor with the "area" around the node
1047  uo_params.set<bool>("use_physical_gap") = true;
1048 
1049  if (_use_dual)
1050  uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
1051 
1052  if (ndisp > 2)
1053  uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1054  uo_params.set<bool>("use_displaced_mesh") = true;
1055 
1056  _problem->addUserObject(
1057  "PenaltyWeightedGapUserObject",
1058  register_mortar_uo_name(_boundary_pairs[0], "penalty_weightedgap_object_"),
1059  uo_params);
1060  _problem->haveADObjects(true);
1061  }
1062  else if (_model == ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR_PENALTY)
1063  {
1064  auto uo_params = _factory.getValidParams("PenaltyFrictionUserObject");
1065  uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1066  uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1067  uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1068  uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1069  uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1070  uo_params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
1071  uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1072  if (ndisp > 2)
1073  uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1074 
1075  uo_params.set<VariableName>("secondary_variable") = displacements[0];
1076  uo_params.set<bool>("use_displaced_mesh") = true;
1077  uo_params.set<Real>("friction_coefficient") = getParam<Real>("friction_coefficient");
1078  uo_params.set<Real>("penalty") = getParam<Real>("penalty");
1079  uo_params.set<Real>("penalty_friction") = getParam<Real>("penalty_friction");
1080 
1081  // AL parameters
1082  uo_params.set<Real>("max_penalty_multiplier") = getParam<Real>("max_penalty_multiplier");
1083  uo_params.set<MooseEnum>("adaptivity_penalty_normal") =
1084  getParam<MooseEnum>("adaptivity_penalty_normal");
1085  uo_params.set<MooseEnum>("adaptivity_penalty_friction") =
1086  getParam<MooseEnum>("adaptivity_penalty_friction");
1087  if (isParamValid("al_penetration_tolerance"))
1088  uo_params.set<Real>("penetration_tolerance") = getParam<Real>("al_penetration_tolerance");
1089  if (isParamValid("penalty_multiplier"))
1090  uo_params.set<Real>("penalty_multiplier") = getParam<Real>("penalty_multiplier");
1091  if (isParamValid("penalty_multiplier_friction"))
1092  uo_params.set<Real>("penalty_multiplier_friction") =
1093  getParam<Real>("penalty_multiplier_friction");
1094 
1095  if (isParamValid("al_incremental_slip_tolerance"))
1096  uo_params.set<Real>("slip_tolerance") = getParam<Real>("al_incremental_slip_tolerance");
1097  // In the contact action, we force the physical value of the normal gap, which also normalizes
1098  // the penalty factor with the "area" around the node
1099  uo_params.set<bool>("use_physical_gap") = true;
1100 
1101  if (_use_dual)
1102  uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
1103 
1104  uo_params.applySpecificParameters(parameters(),
1105  {"friction_coefficient", "penalty", "penalty_friction"});
1106 
1107  _problem->addUserObject(
1108  "PenaltyFrictionUserObject",
1109  register_mortar_uo_name(_boundary_pairs[0], "penalty_friction_object_"),
1110  uo_params);
1111  _problem->haveADObjects(true);
1112  }
1113  }
1114 
1115  if (_current_task == "add_constraint")
1116  {
1117  // Prepare problem for enforcement with Lagrange multipliers
1118  if (_model != ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR)
1119  {
1120  std::string mortar_constraint_name;
1121 
1122  if (!_mortar_dynamics)
1123  mortar_constraint_name = "ComputeWeightedGapLMMechanicalContact";
1124  else
1125  mortar_constraint_name = "ComputeDynamicWeightedGapLMMechanicalContact";
1126 
1127  InputParameters params = _factory.getValidParams(mortar_constraint_name);
1128  if (_mortar_dynamics)
1129  params.applySpecificParameters(
1130  parameters(), {"newmark_beta", "newmark_gamma", "capture_tolerance", "wear_depth"});
1131 
1132  else // We need user objects for quasistatic constraints
1133  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedgap_object_" + name();
1134 
1135  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1136  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1137  params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1138  params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1139  params.set<NonlinearVariableName>("variable") = normal_lagrange_multiplier_name;
1140  params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1141  params.set<Real>("c") = getParam<Real>("c_normal");
1142 
1143  if (ndisp > 1)
1144  params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1145  if (ndisp > 2)
1146  params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1147 
1148  params.set<bool>("use_displaced_mesh") = true;
1149 
1151  {"correct_edge_dropping",
1152  "normalize_c",
1153  "extra_vector_tags",
1154  "absolute_value_vector_tags",
1155  "debug_mesh"});
1156 
1157  _problem->addConstraint(
1158  mortar_constraint_name, action_name + "_normal_lm_weighted_gap", params);
1159  _problem->haveADObjects(true);
1160  }
1161  // Add the tangential and normal Lagrange's multiplier constraints on the secondary boundary.
1162  else if (_model == ContactModel::COULOMB && _formulation == ContactFormulation::MORTAR)
1163  {
1164  std::string mortar_constraint_name;
1165 
1166  if (!_mortar_dynamics)
1167  mortar_constraint_name = "ComputeFrictionalForceLMMechanicalContact";
1168  else
1169  mortar_constraint_name = "ComputeDynamicFrictionalForceLMMechanicalContact";
1170 
1171  InputParameters params = _factory.getValidParams(mortar_constraint_name);
1172  if (_mortar_dynamics)
1173  params.applySpecificParameters(
1174  parameters(), {"newmark_beta", "newmark_gamma", "capture_tolerance", "wear_depth"});
1175  else
1176  { // We need user objects for quasistatic constraints
1177  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedvelocities_object_" + name();
1178  params.set<UserObjectName>("weighted_velocities_uo") =
1179  "lm_weightedvelocities_object_" + name();
1180  }
1181 
1182  params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
1183  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1184  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1185  params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1186  params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1187  params.set<bool>("use_displaced_mesh") = true;
1188  params.set<Real>("c_t") = getParam<Real>("c_tangential");
1189  params.set<Real>("c") = getParam<Real>("c_normal");
1190  params.set<bool>("normalize_c") = getParam<bool>("normalize_c");
1191  params.set<bool>("compute_primal_residuals") = false;
1192 
1193  params.set<MooseEnum>("segment_quadrature") = getParam<MooseEnum>("segment_quadrature");
1194 
1195  params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1196 
1197  if (ndisp > 1)
1198  params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1199  if (ndisp > 2)
1200  params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1201 
1202  params.set<NonlinearVariableName>("variable") = normal_lagrange_multiplier_name;
1203  params.set<std::vector<VariableName>>("friction_lm") = {tangential_lagrange_multiplier_name};
1204 
1205  if (ndisp > 2)
1206  params.set<std::vector<VariableName>>("friction_lm_dir") = {
1207  tangential_lagrange_multiplier_3d_name};
1208 
1209  params.set<Real>("mu") = getParam<Real>("friction_coefficient");
1210  params.applySpecificParameters(
1211  parameters(), {"extra_vector_tags", "absolute_value_vector_tags", "debug_mesh"});
1212 
1213  _problem->addConstraint(mortar_constraint_name, action_name + "_tangential_lm", params);
1214  _problem->haveADObjects(true);
1215  }
1216 
1217  const auto addMechanicalContactConstraints =
1218  [this, &primary_subdomain_name, &secondary_subdomain_name, &displacements](
1219  const std::string & variable_name,
1220  const std::string & constraint_prefix,
1221  const std::string & constraint_type,
1222  const bool is_additional_frictional_constraint,
1223  const bool is_normal_constraint)
1224  {
1225  InputParameters params = _factory.getValidParams(constraint_type);
1226 
1227  params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
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 
1233  if (_formulation == ContactFormulation::MORTAR)
1234  params.set<NonlinearVariableName>("variable") = variable_name;
1235 
1236  params.set<MooseEnum>("segment_quadrature") = getParam<MooseEnum>("segment_quadrature");
1237  params.set<bool>("use_displaced_mesh") = true;
1238  params.set<bool>("compute_lm_residuals") = false;
1239 
1240  // Additional displacement residual for frictional problem
1241  // The second frictional LM acts on a perpendicular direction.
1242  if (is_additional_frictional_constraint)
1243  params.set<MooseEnum>("direction") = "direction_2";
1244  params.applySpecificParameters(
1245  parameters(), {"extra_vector_tags", "absolute_value_vector_tags", "debug_mesh"});
1246 
1247  for (unsigned int i = 0; i < displacements.size(); ++i)
1248  {
1249  std::string constraint_name = constraint_prefix + Moose::stringify(i);
1250 
1251  params.set<VariableName>("secondary_variable") = displacements[i];
1252  params.set<MooseEnum>("component") = i;
1253 
1254  if (is_normal_constraint && _model != ContactModel::COULOMB &&
1255  _formulation == ContactFormulation::MORTAR)
1256  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedgap_object_" + name();
1257  else if (is_normal_constraint && _model == ContactModel::COULOMB &&
1258  _formulation == ContactFormulation::MORTAR)
1259  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedvelocities_object_" + name();
1260  else if (_formulation == ContactFormulation::MORTAR)
1261  params.set<UserObjectName>("weighted_velocities_uo") =
1262  "lm_weightedvelocities_object_" + name();
1263  else if (is_normal_constraint && _model != ContactModel::COULOMB &&
1264  _formulation == ContactFormulation::MORTAR_PENALTY)
1265  params.set<UserObjectName>("weighted_gap_uo") = "penalty_weightedgap_object_" + name();
1266  else if (is_normal_constraint && _model == ContactModel::COULOMB &&
1267  _formulation == ContactFormulation::MORTAR_PENALTY)
1268  params.set<UserObjectName>("weighted_gap_uo") = "penalty_friction_object_" + name();
1269  else if (_formulation == ContactFormulation::MORTAR_PENALTY)
1270  params.set<UserObjectName>("weighted_velocities_uo") =
1271  "penalty_friction_object_" + name();
1272 
1273  _problem->addConstraint(constraint_type, constraint_name, params);
1274  }
1275  _problem->haveADObjects(true);
1276  };
1277 
1278  // Add mortar mechanical contact constraint objects for primal variables
1279  addMechanicalContactConstraints(normal_lagrange_multiplier_name,
1280  action_name + "_normal_constraint_",
1281  "NormalMortarMechanicalContact",
1282  /* is_additional_frictional_constraint = */ false,
1283  /* is_normal_constraint = */ true);
1284 
1285  if (_model == ContactModel::COULOMB)
1286  {
1287  addMechanicalContactConstraints(tangential_lagrange_multiplier_name,
1288  action_name + "_tangential_constraint_",
1289  "TangentialMortarMechanicalContact",
1290  /* is_additional_frictional_constraint = */ false,
1291  /* is_normal_constraint = */ false);
1292  if (ndisp > 2)
1293  addMechanicalContactConstraints(tangential_lagrange_multiplier_3d_name,
1294  action_name + "_tangential_constraint_3d_",
1295  "TangentialMortarMechanicalContact",
1296  /* is_additional_frictional_constraint = */ true,
1297  /* is_normal_constraint = */ false);
1298  }
1299  }
1300 }
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:81
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
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:90
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.).
Definition: ContactAction.h:96
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.
Definition: ContactAction.h:99
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:93
bool isParamValid(const std::string &name) const
const ContactModel _model
Contact model type enum.
Definition: ContactAction.h:87
bool isRecovering() const

◆ addNodeFaceContact()

void ContactAction::addNodeFaceContact ( )
private

Generate constraints for node to face contact.

Definition at line 1303 of file ContactAction.C.

Referenced by act().

1304 {
1305  if (_current_task == "post_mesh_prepared" && _automatic_pairing_boundaries.size() > 0)
1306  {
1307  if (getParam<MooseEnum>("automatic_pairing_method").getEnum<ProximityMethod>() ==
1308  ProximityMethod::NODE)
1310  else if (getParam<MooseEnum>("automatic_pairing_method").getEnum<ProximityMethod>() ==
1311  ProximityMethod::CENTROID)
1313  }
1314 
1315  if (_current_task != "add_constraint")
1316  return;
1317 
1318  std::string action_name = MooseUtils::shortName(name());
1319  std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
1320  const unsigned int ndisp = displacements.size();
1321 
1322  std::string constraint_type;
1323 
1324  if (_formulation == ContactFormulation::RANFS)
1325  constraint_type = "RANFSNormalMechanicalContact";
1326  else
1327  constraint_type = "MechanicalContactConstraint";
1328 
1329  InputParameters params = _factory.getValidParams(constraint_type);
1330 
1331  params.applyParameters(parameters(),
1332  {"displacements",
1333  "secondary_gap_offset",
1334  "mapped_primary_gap_offset",
1335  "primary",
1336  "secondary"});
1337 
1338  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
1339  .system()
1340  .variable_type(displacements[0])
1341  .order.get_order();
1342 
1343  params.set<std::vector<VariableName>>("displacements") = displacements;
1344  params.set<bool>("use_displaced_mesh") = true;
1345  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
1346 
1347  for (const auto & contact_pair : _boundary_pairs)
1348  {
1349  if (_formulation != ContactFormulation::RANFS)
1350  {
1351  params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area"};
1352  params.set<BoundaryName>("boundary") = contact_pair.first;
1353  if (isParamValid("secondary_gap_offset"))
1354  params.set<std::vector<VariableName>>("secondary_gap_offset") = {
1355  getParam<VariableName>("secondary_gap_offset")};
1356  if (isParamValid("mapped_primary_gap_offset"))
1357  params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
1358  getParam<VariableName>("mapped_primary_gap_offset")};
1359  }
1360 
1361  for (unsigned int i = 0; i < ndisp; ++i)
1362  {
1363  std::string name = action_name + "_constraint_" + Moose::stringify(contact_pair, "_") + "_" +
1364  Moose::stringify(i);
1365 
1366  if (_formulation == ContactFormulation::RANFS)
1367  params.set<MooseEnum>("component") = i;
1368  else
1369  params.set<unsigned int>("component") = i;
1370 
1371  params.set<BoundaryName>("primary") = contact_pair.first;
1372  params.set<BoundaryName>("secondary") = contact_pair.second;
1373  params.set<NonlinearVariableName>("variable") = displacements[i];
1374  params.set<std::vector<VariableName>>("primary_variable") = {displacements[i]};
1376  {"extra_vector_tags", "absolute_value_vector_tags"});
1377  _problem->addConstraint(constraint_type, name, params);
1378  }
1379  }
1380 }
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:81
std::vector< BoundaryName > _automatic_pairing_boundaries
List of all possible boundaries for contact for automatic pairing (optional)
Definition: ContactAction.h:84
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:90
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 793 of file ContactAction.C.

794 {
795  if (_formulation == ContactFormulation::MORTAR ||
796  _formulation == ContactFormulation::MORTAR_PENALTY)
797  {
798  auto params = MortarConstraintBase::validParams();
799  params.set<bool>("use_displaced_mesh") = true;
800  std::string action_name = MooseUtils::shortName(name());
801  const std::string primary_subdomain_name = action_name + "_primary_subdomain";
802  const std::string secondary_subdomain_name = action_name + "_secondary_subdomain";
803  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
804  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
805  params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
806  params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
807  params.set<bool>("use_petrov_galerkin") = getParam<bool>("use_petrov_galerkin");
808  addRelationshipManagers(input_rm_type, params);
809  }
810  else
811  {
812  const std::string constraint_type = _formulation == ContactFormulation::RANFS
813  ? "RANFSNormalMechanicalContact"
814  : "MechanicalContactConstraint";
815 
816  for (const auto & contact_pair : _boundary_pairs)
817  {
818  auto params = _factory.getValidParams(constraint_type);
819  params.set<bool>("use_displaced_mesh") = true;
820  params.set<bool>("ghost_whole_interface") = getParam<bool>("ghost_whole_interface");
821  params.set<BoundaryName>("primary") = contact_pair.first;
822  params.set<BoundaryName>("secondary") = contact_pair.second;
823  addRelationshipManagers(input_rm_type, params);
824  }
825  }
826 }
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:81
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:90
std::string shortName(const std::string &name)
static InputParameters validParams()
const std::string & name() const

◆ commonParameters()

InputParameters ContactAction::commonParameters ( )
static

Define parameters used by multiple contact objects.

Returns
InputParameters object populated with common parameters

Definition at line 1717 of file ContactAction.C.

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

1718 {
1720 
1721  params.addParam<MooseEnum>("normal_smoothing_method",
1723  "Method to use to smooth normals");
1724  params.addParam<Real>(
1725  "normal_smoothing_distance",
1726  "Distance from edge in parametric coordinates over which to smooth contact normal");
1727 
1728  params.addParam<MooseEnum>(
1729  "formulation", ContactAction::getFormulationEnum(), "The contact formulation");
1730 
1731  params.addParam<MooseEnum>("model", ContactAction::getModelEnum(), "The contact model to use");
1732 
1733  return params;
1734 }
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 1530 of file ContactAction.C.

Referenced by addNodeFaceContact().

1531 {
1532  mooseInfo("The contact action is reading the list of boundaries and automatically pairs them "
1533  "if their centroids fall within a specified distance of each other.");
1534 
1535  if (!_mesh)
1536  mooseError("Failed to obtain mesh for automatically generating contact pairs.");
1537 
1538  if (!_mesh->getMesh().is_serial())
1539  paramError(
1540  "automatic_pairing_boundaries",
1541  "The generation of automatic contact pairs in the contact action requires a serial mesh.");
1542 
1543  // Compute centers of gravity for each sideset
1544  std::vector<std::pair<BoundaryName, Point>> automatic_pairing_boundaries_cog;
1545  const auto & sideset_ids = _mesh->meshSidesetIds();
1546 
1547  const auto & bnd_to_elem_map = _mesh->getBoundariesToActiveSemiLocalElemIds();
1548 
1549  for (const auto & sideset_name : _automatic_pairing_boundaries)
1550  {
1551  // If the sideset provided in the input file isn't in the mesh, error out.
1552  const auto find_set = sideset_ids.find(_mesh->getBoundaryID(sideset_name));
1553  if (find_set == sideset_ids.end())
1554  paramError("automatic_pairing_boundaries",
1555  sideset_name,
1556  " is not defined as a sideset in the mesh.");
1557 
1558  auto dofs_set = bnd_to_elem_map.find(_mesh->getBoundaryID(sideset_name));
1559 
1560  // Initialize data for sideset
1561  Point center_of_gravity(0, 0, 0);
1562  Real accumulated_sideset_area(0);
1563 
1564  // Pointer to lower-dimensional element on the sideset
1565  std::unique_ptr<const Elem> side_ptr;
1566  const std::unordered_set<dof_id_type> & bnd_elems = dofs_set->second;
1567 
1568  for (auto elem_id : bnd_elems)
1569  {
1570  const Elem * elem = _mesh->elemPtr(elem_id);
1571  unsigned int side = _mesh->sideWithBoundaryID(elem, _mesh->getBoundaryID(sideset_name));
1572 
1573  // update side_ptr
1574  elem->side_ptr(side_ptr, side);
1575 
1576  // area of the (linearized) side
1577  const auto side_area = side_ptr->volume();
1578 
1579  // position of the side
1580  const auto side_position = side_ptr->true_centroid();
1581 
1582  center_of_gravity += side_position * side_area;
1583  accumulated_sideset_area += side_area;
1584  }
1585 
1586  // Average each element's center of gravity (centroid) with its area
1587  center_of_gravity /= accumulated_sideset_area;
1588 
1589  // Add sideset-cog pair to vector
1590  automatic_pairing_boundaries_cog.emplace_back(sideset_name, center_of_gravity);
1591  }
1592 
1593  // Vectors of distances for each pair
1594  std::vector<std::pair<std::pair<BoundaryName, BoundaryName>, Real>> pairs_distances;
1595 
1596  // Assign distances to identify nearby pairs.
1597  for (std::size_t i = 0; i < automatic_pairing_boundaries_cog.size() - 1; i++)
1598  for (std::size_t j = i + 1; j < automatic_pairing_boundaries_cog.size(); j++)
1599  {
1600  const Point & distance_vector =
1601  automatic_pairing_boundaries_cog[i].second - automatic_pairing_boundaries_cog[j].second;
1602 
1603  if (automatic_pairing_boundaries_cog[i].first != automatic_pairing_boundaries_cog[j].first)
1604  {
1605  const Real distance = distance_vector.norm();
1606  const std::pair pair = std::make_pair(automatic_pairing_boundaries_cog[i].first,
1607  automatic_pairing_boundaries_cog[j].first);
1608  pairs_distances.emplace_back(std::make_pair(pair, distance));
1609  }
1610  }
1611 
1612  const auto automatic_pairing_distance = getParam<Real>("automatic_pairing_distance");
1613 
1614  // Loop over all pairs
1615  std::vector<std::pair<std::pair<BoundaryName, BoundaryName>, Real>> lean_pairs_distances;
1616  for (const auto & pair_distance : pairs_distances)
1617  if (pair_distance.second <= automatic_pairing_distance)
1618  {
1619  lean_pairs_distances.emplace_back(pair_distance);
1620  mooseInfoRepeated("Generating contact pair primary--secondary ",
1621  pair_distance.first.first,
1622  "--",
1623  pair_distance.first.second,
1624  ", with a relative distance of ",
1625  pair_distance.second);
1626  }
1627 
1628  // Create the boundary pairs (possibly with repeated pairs depending on user input)
1629  for (const auto & lean_pairs_distance : lean_pairs_distances)
1630  {
1631  // Make sure secondary surface's boundary ID is less than primary surface's boundary ID.
1632  // This is done to ensure some consistency in the boundary matching, which helps in defining
1633  // auxiliary kernels in the input file.
1634  if (_mesh->getBoundaryID(lean_pairs_distance.first.first) >
1635  _mesh->getBoundaryID(lean_pairs_distance.first.second))
1636  _boundary_pairs.push_back(
1637  {lean_pairs_distance.first.first, lean_pairs_distance.first.second});
1638  else
1639  _boundary_pairs.push_back(
1640  {lean_pairs_distance.first.second, lean_pairs_distance.first.first});
1641  }
1642 
1643  // Let's remove possibly repeated pairs
1645 }
void mooseInfo(Args &&... args) const
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:81
std::vector< BoundaryName > _automatic_pairing_boundaries
List of all possible boundaries for contact for automatic pairing (optional)
Definition: ContactAction.h:84
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 1392 of file ContactAction.C.

Referenced by addNodeFaceContact().

1393 {
1394  mooseInfo("The contact action is reading the list of boundaries and automatically pairs them "
1395  "if the distance between nodes is less than a specified distance.");
1396 
1397  if (!_mesh)
1398  mooseError("Failed to obtain mesh for automatically generating contact pairs.");
1399 
1400  if (!_mesh->getMesh().is_serial())
1401  paramError(
1402  "automatic_pairing_boundaries",
1403  "The generation of automatic contact pairs in the contact action requires a serial mesh.");
1404 
1405  // Create automatic_pairing_boundaries_id
1406  std::vector<BoundaryID> _automatic_pairing_boundaries_id;
1407  for (const auto & sideset_name : _automatic_pairing_boundaries)
1408  _automatic_pairing_boundaries_id.emplace_back(_mesh->getBoundaryID(sideset_name));
1409 
1410  // Vector of pairs node-boundary id
1411  std::vector<NodeBoundaryIDInfo> node_boundary_id_vector;
1412 
1413  // Data structures to hold the boundary nodes
1414  const ConstBndNodeRange & bnd_nodes = *_mesh->getBoundaryNodeRange();
1415 
1416  for (const auto & bnode : bnd_nodes)
1417  {
1418  const BoundaryID boundary_id = bnode->_bnd_id;
1419  const Node * node_ptr = bnode->_node;
1420 
1421  // Make sure node is on a boundary chosen for contact mechanics
1422  auto it = std::find(_automatic_pairing_boundaries_id.begin(),
1423  _automatic_pairing_boundaries_id.end(),
1424  boundary_id);
1425 
1426  if (it != _automatic_pairing_boundaries_id.end())
1427  node_boundary_id_vector.emplace_back(node_ptr, boundary_id);
1428  }
1429 
1430  // sort by increasing boundary id
1431  std::sort(node_boundary_id_vector.begin(),
1432  node_boundary_id_vector.end(),
1433  [](const NodeBoundaryIDInfo & first_pair, const NodeBoundaryIDInfo & second_pair)
1434  { return first_pair.second < second_pair.second; });
1435 
1436  // build kd-tree
1437  using KDTreeType = nanoflann::KDTreeSingleIndexAdaptor<
1438  nanoflann::L2_Simple_Adaptor<Real, PointListAdaptor<NodeBoundaryIDInfo>, Real, std::size_t>,
1440  LIBMESH_DIM,
1441  std::size_t>;
1442 
1443  // This parameter can be tuned. Others use '10'
1444  const unsigned int max_leaf_size = 20;
1445 
1446  // Build point list adaptor with all nodes-sidesets pairs for possible mechanical contact
1447  auto point_list = PointListAdaptor<NodeBoundaryIDInfo>(node_boundary_id_vector.begin(),
1448  node_boundary_id_vector.end());
1449  auto kd_tree = std::make_unique<KDTreeType>(
1450  LIBMESH_DIM, point_list, nanoflann::KDTreeSingleIndexAdaptorParams(max_leaf_size));
1451 
1452  if (!kd_tree)
1453  mooseError("Internal error. KDTree was not properly initialized in the contact action.");
1454 
1455  kd_tree->buildIndex();
1456 
1457  // data structures for kd-tree search
1458  nanoflann::SearchParameters search_params;
1459  std::vector<nanoflann::ResultItem<std::size_t, Real>> ret_matches;
1460 
1461  const auto radius_for_search = getParam<Real>("automatic_pairing_distance");
1462 
1463  // For all nodes
1464  for (const auto & pair : node_boundary_id_vector)
1465  {
1466  // clear result buffer
1467  ret_matches.clear();
1468 
1469  // position where we expect a periodic partner for the current node and boundary
1470  const Point search_point = *pair.first;
1471 
1472  // search at the expected point
1473  kd_tree->radiusSearch(
1474  &(search_point)(0), radius_for_search * radius_for_search, ret_matches, search_params);
1475 
1476  for (auto & match_pair : ret_matches)
1477  {
1478  const auto & match = node_boundary_id_vector[match_pair.first];
1479 
1480  //
1481  // If the proximity node identified belongs to a boundary in the input, add boundary pair
1482  //
1483 
1484  // Make sure node is on a boundary chosen for contact mechanics
1485  auto it = std::find(_automatic_pairing_boundaries_id.begin(),
1486  _automatic_pairing_boundaries_id.end(),
1487  match.second);
1488 
1489  // If nodes are on the same boundary, pass.
1490  if (match.second == pair.second)
1491  continue;
1492 
1493  // At this point we will likely create many repeated pairs because many nodal pairs may
1494  // fulfill the distance condition imposed by the automatic_pairing_distance user input
1495  // parameter.
1496  if (it != _automatic_pairing_boundaries_id.end())
1497  {
1498  const auto index_one = cast_int<int>(it - _automatic_pairing_boundaries_id.begin());
1499  auto it_other = std::find(_automatic_pairing_boundaries_id.begin(),
1500  _automatic_pairing_boundaries_id.end(),
1501  pair.second);
1502 
1503  mooseAssert(it_other != _automatic_pairing_boundaries_id.end(),
1504  "Error in contact action. Unable to find boundary ID for node proximity "
1505  "automatic pairing.");
1506 
1507  const auto index_two = cast_int<int>(it_other - _automatic_pairing_boundaries_id.begin());
1508 
1509  if (pair.second > match.second)
1510  _boundary_pairs.push_back(
1512  else
1513  _boundary_pairs.push_back(
1515  }
1516  }
1517  }
1518 
1519  // Let's remove likely repeated pairs
1521 
1522  mooseInfo(
1523  "The following boundary pairs were created by the contact action using nodal proximity: ");
1524  for (const auto & [primary, secondary] : _boundary_pairs)
1526  "Primary boundary ID: ", primary, " and secondary boundary ID: ", secondary, ".");
1527 }
void mooseInfo(Args &&... args) const
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:81
std::vector< BoundaryName > _automatic_pairing_boundaries
List of all possible boundaries for contact for automatic pairing (optional)
Definition: ContactAction.h:84
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:43
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 1660 of file ContactAction.C.

Referenced by commonParameters().

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

◆ getModelEnum()

MooseEnum ContactAction::getModelEnum ( )
static

Get contact model.

Returns
enum

Definition at line 1648 of file ContactAction.C.

Referenced by commonParameters(), and validParams().

1649 {
1650  return MooseEnum(getContactModelOptions(), "frictionless");
1651 }

◆ getProximityMethod()

MooseEnum ContactAction::getProximityMethod ( )
static

Get proximity method for automatic pairing.

Returns
enum

Definition at line 1654 of file ContactAction.C.

Referenced by validParams().

1655 {
1656  return MooseEnum(getProximityMethodOptions());
1657 }

◆ getSmoothingEnum()

MooseEnum ContactAction::getSmoothingEnum ( )
static

Get smoothing type.

Returns
enum

Definition at line 1711 of file ContactAction.C.

Referenced by commonParameters().

1712 {
1713  return MooseEnum("edge_based nodal_normal_based", "");
1714 }

◆ getSystemEnum()

MooseEnum ContactAction::getSystemEnum ( )
static

Get contact system.

Returns
enum

Definition at line 1705 of file ContactAction.C.

1706 {
1707  return MooseEnum("Constraint", "Constraint");
1708 }

◆ removeRepeatedPairs()

void ContactAction::removeRepeatedPairs ( )
private

Remove repeated contact pairs from _boundary_pairs.

Definition at line 476 of file ContactAction.C.

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

477 {
478  if (_boundary_pairs.size() == 0 && _automatic_pairing_boundaries.size() == 0)
479  paramError(
480  "primary",
481  "Number of contact pairs in the contact action is zero. Please revise your input file.");
482 
483  // Remove repeated interactions
484  std::vector<std::pair<BoundaryName, BoundaryName>> lean_boundary_pairs;
485 
486  for (const auto & [primary, secondary] : _boundary_pairs)
487  {
488  // Structured bindings are not capturable (primary_copy, secondary_copy)
489  auto it = std::find_if(lean_boundary_pairs.begin(),
490  lean_boundary_pairs.end(),
491  [&, primary_copy = primary, secondary_copy = secondary](
492  const std::pair<BoundaryName, BoundaryName> & lean_pair)
493  {
494  const bool match_one = lean_pair.second == secondary_copy &&
495  lean_pair.first == primary_copy;
496  const bool match_two = lean_pair.second == primary_copy &&
497  lean_pair.first == secondary_copy;
498  const bool exist = match_one || match_two;
499  return exist;
500  });
501 
502  if (it == lean_boundary_pairs.end())
503  lean_boundary_pairs.emplace_back(primary, secondary);
504  else
505  mooseInfo("Contact pair ",
506  primary,
507  "--",
508  secondary,
509  " has been removed from the contact interaction list due to "
510  "duplicates in the input file.");
511  }
512 
513  _boundary_pairs = lean_boundary_pairs;
514 }
void mooseInfo(Args &&... args) const
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:81
std::vector< BoundaryName > _automatic_pairing_boundaries
List of all possible boundaries for contact for automatic pairing (optional)
Definition: ContactAction.h:84
void paramError(const std::string &param, Args... args) const

◆ validParams()

InputParameters ContactAction::validParams ( )
static

Definition at line 72 of file ContactAction.C.

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

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 84 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 109 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 96 of file ContactAction.h.

Referenced by addMortarContact().

◆ _model

const ContactModel ContactAction::_model
protected

Contact model type enum.

Definition at line 87 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 99 of file ContactAction.h.

Referenced by addMortarContact().

◆ _use_dual

bool ContactAction::_use_dual
protected

Whether to use the dual Mortar approach.

Definition at line 93 of file ContactAction.h.

Referenced by addMortarContact(), and ContactAction().


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