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 T & getParam (const std::string &name) const
 
std::vector< std::pair< T1, T2 > > getParam (const std::string &param1, const std::string &param2) const
 
const T * queryParam (const std::string &name) const
 
const T & getRenamedParam (const std::string &old_name, const std::string &new_name) const
 
getCheckedPointerParam (const std::string &name, const std::string &error_string="") const
 
bool isParamValid (const std::string &name) const
 
bool isParamSetByUser (const std::string &name) const
 
void connectControllableParams (const std::string &parameter, const std::string &object_type, const std::string &object_name, const std::string &object_parameter) const
 
void paramError (const std::string &param, Args... args) const
 
void paramWarning (const std::string &param, Args... args) const
 
void paramWarning (const std::string &param, Args... args) const
 
void paramInfo (const std::string &param, Args... args) const
 
std::string messagePrefix (const bool hit_prefix=true) const
 
std::string errorPrefix (const std::string &) const
 
void mooseError (Args &&... args) const
 
void mooseDocumentedError (const std::string &repo_name, const unsigned int issue_num, Args &&... args) const
 
void mooseErrorNonPrefixed (Args &&... args) const
 
void mooseWarning (Args &&... args) const
 
void mooseWarning (Args &&... args) const
 
void mooseWarningNonPrefixed (Args &&... args) const
 
void mooseWarningNonPrefixed (Args &&... args) const
 
void mooseDeprecated (Args &&... args) const
 
void mooseDeprecated (Args &&... args) const
 
void mooseInfo (Args &&... args) const
 
void callMooseError (std::string msg, const bool with_prefix, const hit::Node *node=nullptr) 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)
 

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 T & getMeshProperty (const std::string &data_name, const std::string &prefix)
 
const T & getMeshProperty (const std::string &data_name)
 
bool hasMeshProperty (const std::string &data_name, const std::string &prefix) const
 
bool hasMeshProperty (const std::string &data_name, const std::string &prefix) const
 
bool hasMeshProperty (const std::string &data_name) const
 
bool hasMeshProperty (const std::string &data_name) const
 
std::string meshPropertyName (const std::string &data_name) const
 
PerfID registerTimedSection (const std::string &section_name, const unsigned int level) const
 
PerfID registerTimedSection (const std::string &section_name, const unsigned int level, const std::string &live_message, const bool print_dots=true) const
 
std::string timedSectionName (const std::string &section_name) const
 
void flagInvalidSolutionInternal (const InvalidSolutionID invalid_solution_id) const
 
InvalidSolutionID registerInvalidSolutionInternal (const std::string &message, const bool warning) const
 

Static Protected Member Functions

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

Protected Attributes

std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
 Primary/Secondary boundary name pairs for mechanical contact. 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 44 of file ContactAction.h.

Constructor & Destructor Documentation

◆ ContactAction()

ContactAction::ContactAction ( const InputParameters params)

Definition at line 284 of file ContactAction.C.

285  : Action(params),
286  _boundary_pairs(getParam<BoundaryName, BoundaryName>("primary", "secondary")),
287  _model(getParam<MooseEnum>("model").getEnum<ContactModel>()),
288  _formulation(getParam<MooseEnum>("formulation").getEnum<ContactFormulation>()),
289  _generate_mortar_mesh(getParam<bool>("generate_mortar_mesh")),
290  _mortar_dynamics(getParam<bool>("mortar_dynamics"))
291 {
292  // Check for automatic selection of contact pairs.
293  if (getParam<std::vector<BoundaryName>>("automatic_pairing_boundaries").size() > 1)
295  getParam<std::vector<BoundaryName>>("automatic_pairing_boundaries");
296 
297  if (_automatic_pairing_boundaries.size() > 0 && !isParamValid("automatic_pairing_distance"))
298  paramError("automatic_pairing_distance",
299  "For automatic selection of contact pairs (for particular geometries) in contact "
300  "action, 'automatic_pairing_distance' needs to be provided.");
301 
302  if (_automatic_pairing_boundaries.size() > 0 && !isParamValid("automatic_pairing_method"))
303  paramError("automatic_pairing_distance",
304  "For automatic selection of contact pairs (for particular geometries) in contact "
305  "action, 'automatic_pairing_method' needs to be provided.");
306 
307  if (_automatic_pairing_boundaries.size() > 0 && _boundary_pairs.size() != 0)
308  paramError("automatic_pairing_boundaries",
309  "If a boundary list is provided, primary and secondary surfaces will be identified "
310  "automatically. Therefore, one cannot provide an automatic pairing boundary list "
311  "and primary/secondary lists.");
312  else if (_automatic_pairing_boundaries.size() == 0 && _boundary_pairs.size() == 0)
313  paramError("primary",
314  "'primary' and 'secondary' surfaces or a list of boundaries for automatic pair "
315  "generation need to be provided.");
316 
317  // End of checks for automatic selection of contact pairs.
318 
320  paramError("formulation", "When using mortar, a vector of contact pairs cannot be used");
321 
323  paramError("formulation",
324  "The 'tangential_penalty' formulation can only be used with the 'coulomb' model");
325 
327  {
328  // Use dual basis functions for contact traction interpolation
329  if (isParamValid("use_dual"))
330  _use_dual = getParam<bool>("use_dual");
331  else
332  _use_dual = true;
333 
335  paramError("model", "The 'mortar_penalty' formulation does not support glued contact");
336 
337  if (getParam<bool>("mortar_dynamics"))
338  paramError("mortar_dynamics",
339  "The 'mortar_penalty' formulation does not support implicit dynamic simulations");
340 
341  if (getParam<bool>("use_petrov_galerkin"))
342  paramError("use_petrov_galerkin",
343  "The 'mortar_penalty' formulation does not support usage of the Petrov-Galerkin "
344  "flag. The default (use_dual = true) behavior is such that contact tractions are "
345  "interpolated with dual bases whereas mortar or weighted contact quantities are "
346  "interpolated with Lagrange shape functions.");
347  }
348 
350  {
352  paramError("model", "The 'mortar' formulation does not support glued contact (yet)");
353 
354  // use dual basis function for Lagrange multipliers?
355  if (isParamValid("use_dual"))
356  _use_dual = getParam<bool>("use_dual");
357  else
358  _use_dual = true;
359 
360  if (!getParam<bool>("mortar_dynamics"))
361  {
362  if (params.isParamSetByUser("newmark_beta"))
363  paramError("newmark_beta", "newmark_beta can only be used with the mortar_dynamics option");
364 
365  if (params.isParamSetByUser("newmark_gamma"))
366  paramError("newmark_gamma",
367  "newmark_gamma can only be used with the mortar_dynamics option");
368  }
369 
370  if (isParamSetByUser("penalty"))
371  paramError("penalty",
372  "The 'penalty' parameter is not used for the 'mortar' formulation which instead "
373  "uses Lagrange multipliers");
374  }
375  else
376  {
377  if (params.isParamSetByUser("correct_edge_dropping"))
378  paramError(
379  "correct_edge_dropping",
380  "The 'correct_edge_dropping' option can only be used with the 'mortar' formulation "
381  "(weighted)");
382  else if (params.isParamSetByUser("use_dual") &&
384  paramError("use_dual",
385  "The 'use_dual' option can only be used with the 'mortar' formulation");
386  else if (params.isParamSetByUser("c_normal"))
387  paramError("c_normal",
388  "The 'c_normal' option can only be used with the 'mortar' formulation");
389  else if (params.isParamSetByUser("c_tangential"))
390  paramError("c_tangential",
391  "The 'c_tangential' option can only be used with the 'mortar' formulation");
392  else if (params.isParamSetByUser("mortar_dynamics"))
393  paramError("mortar_dynamics",
394  "The 'mortar_dynamics' constraint option can only be used with the 'mortar' "
395  "formulation and in dynamic simulations using Newmark-beta");
396  }
397 
399  {
400  if (isParamValid("secondary_gap_offset"))
401  paramError("secondary_gap_offset",
402  "The 'secondary_gap_offset' option can only be used with the "
403  "'MechanicalContactConstraint'");
404  if (isParamValid("mapped_primary_gap_offset"))
405  paramError("mapped_primary_gap_offset",
406  "The 'mapped_primary_gap_offset' option can only be used with the "
407  "'MechanicalContactConstraint'");
408  }
409  else if (getParam<bool>("ping_pong_protection"))
410  paramError("ping_pong_protection",
411  "The 'ping_pong_protection' option can only be used with the 'ranfs' formulation");
412 
413  // Remove repeated pairs from input file.
415 }
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:94
std::vector< BoundaryName > _automatic_pairing_boundaries
List of all possible boundaries for contact for automatic pairing (optional)
Definition: ContactAction.h:97
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.
const bool _generate_mortar_mesh
Whether to generate the mortar mesh (useful in a restart simulation e.g.).
const bool _mortar_dynamics
Whether mortar dynamic contact constraints are to be used.
bool isParamSetByUser(const std::string &name) const
bool _use_dual
Whether to use the dual Mortar approach.
bool isParamValid(const std::string &name) const
const ContactModel _model
Contact model type enum.
bool isParamSetByUser(const std::string &name) const

Member Function Documentation

◆ act()

void ContactAction::act ( )
overridevirtual

Implements Action.

Definition at line 459 of file ContactAction.C.

460 {
461  // proform problem checks/corrections once during the first feasible task
462  if (_current_task == "add_contact_aux_variable")
463  {
464  if (!_problem->getDisplacedProblem())
465  mooseError(
466  "Contact requires updated coordinates. Use the 'displacements = ...' parameter in the "
467  "Mesh block.");
468 
469  // It is risky to apply this optimization to contact problems
470  // since the problem configuration may be changed during Jacobian
471  // evaluation. We therefore turn it off for all contact problems so that
472  // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3.
473  if (!_problem->isSNESMFReuseBaseSetbyUser())
474  _problem->setSNESMFReuseBase(false, false);
475  }
476 
480  else
482 
483  if (_current_task == "add_aux_kernel")
484  {
485  if (!_problem->getDisplacedProblem())
486  mooseError("Contact requires updated coordinates. Use the 'displacements = ...' line in the "
487  "Mesh block.");
488 
489  // Create auxiliary kernels for each contact pairs
490  for (const auto & contact_pair : _boundary_pairs)
491  {
492  const auto & [primary_name, secondary_name] = contact_pair;
495  {
496  InputParameters params = _factory.getValidParams("PenetrationAux");
497  params.applyParameters(parameters(),
498  {"secondary_gap_offset", "mapped_primary_gap_offset", "order"});
499 
500  std::vector<VariableName> displacements =
501  getParam<std::vector<VariableName>>("displacements");
502  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
503  .system()
504  .variable_type(displacements[0])
505  .order.get_order();
506 
507  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
508  params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR};
509  params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
510  params.set<BoundaryName>("paired_boundary") = primary_name;
511  params.set<AuxVariableName>("variable") = "penetration";
512  if (isParamValid("secondary_gap_offset"))
513  params.set<std::vector<VariableName>>("secondary_gap_offset") = {
514  getParam<VariableName>("secondary_gap_offset")};
515  if (isParamValid("mapped_primary_gap_offset"))
516  params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
517  getParam<VariableName>("mapped_primary_gap_offset")};
518  params.set<bool>("use_displaced_mesh") = true;
519  std::string name = _name + "_contact_" + Moose::stringify(contact_auxkernel_counter++);
520 
521  _problem->addAuxKernel("PenetrationAux", name, params);
522  }
523  else
524  {
525  const auto type = "MortarUserObjectAux";
527  params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
528  params.set<AuxVariableName>("variable") = "gap";
529  params.set<bool>("use_displaced_mesh") = true; // Unnecessary as this object only operates
530  // on nodes, but we'll do it for consistency
531  params.set<MooseEnum>("contact_quantity") = "normal_gap";
532  const auto & [primary_id, secondary_id, uo_name] =
533  libmesh_map_find(_bnd_pair_to_mortar_info, contact_pair);
534  params.set<UserObjectName>("user_object") = uo_name;
535  std::string name = _name + "_contact_gap_" + std::to_string(primary_id) + "_" +
536  std::to_string(secondary_id);
537 
538  _problem->addAuxKernel(type, name, params);
539  }
540  }
541 
543 
544  const unsigned int ndisp = getParam<std::vector<VariableName>>("displacements").size();
545 
546  // Add MortarFrictionalPressureVectorAux
548  {
549  {
550  InputParameters params = _factory.getValidParams("MortarFrictionalPressureVectorAux");
551 
552  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
553  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
554  params.set<std::vector<BoundaryName>>("boundary") = {_boundary_pairs[0].second};
555  params.set<ExecFlagEnum>("execute_on", true) = {EXEC_NONLINEAR};
556 
557  std::string action_name = MooseUtils::shortName(name());
558  const std::string tangential_lagrange_multiplier_name = action_name + "_tangential_lm";
559  const std::string tangential_lagrange_multiplier_3d_name =
560  action_name + "_tangential_3d_lm";
561 
562  params.set<std::vector<VariableName>>("tangent_one") = {
563  tangential_lagrange_multiplier_name};
564  params.set<std::vector<VariableName>>("tangent_two") = {
565  tangential_lagrange_multiplier_3d_name};
566 
567  std::vector<std::string> disp_components({"x", "y", "z"});
568  unsigned component_index = 0;
569 
570  // Loop over three displacements
571  for (const auto & disp_component : disp_components)
572  {
573  params.set<AuxVariableName>("variable") = _name + "_tangent_" + disp_component;
574  params.set<unsigned int>("component") = component_index;
575 
576  std::string name = _name + "_mortar_frictional_pressure_" + disp_component + "_" +
578 
579  _problem->addAuxKernel("MortarFrictionalPressureVectorAux", name, params);
580  component_index++;
581  }
582  }
583  }
584  }
585 
586  if (_current_task == "add_contact_aux_variable")
587  {
588  std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
589  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
590  .system()
591  .variable_type(displacements[0])
592  .order.get_order();
593  std::unique_ptr<InputParameters> current_params;
594  const auto create_aux_var_params = [this, order, &current_params]() -> InputParameters &
595  {
596  current_params = std::make_unique<InputParameters>(_factory.getValidParams("MooseVariable"));
597  current_params->set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
598  current_params->set<MooseEnum>("family") = "LAGRANGE";
599  return *current_params;
600  };
601 
604  {
605  // Add penetration aux variable
606  _problem->addAuxVariable("MooseVariable", "penetration", create_aux_var_params());
607  // Add nodal area aux variable
608  _problem->addAuxVariable("MooseVariable", "nodal_area", create_aux_var_params());
609  }
610  else
611  _problem->addAuxVariable("MooseVariable", "gap", create_aux_var_params());
612 
613  // Add contact pressure aux variable
614  _problem->addAuxVariable("MooseVariable", "contact_pressure", create_aux_var_params());
615 
616  const unsigned int ndisp = getParam<std::vector<VariableName>>("displacements").size();
617 
618  // Add MortarFrictionalPressureVectorAux variables
620  {
621  {
622  std::vector<std::string> disp_components({"x", "y", "z"});
623  // Loop over three displacements
624  for (const auto & disp_component : disp_components)
625  {
626  auto var_params = _factory.getValidParams("MooseVariable");
627  var_params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
628  var_params.set<MooseEnum>("family") = "LAGRANGE";
629 
630  _problem->addAuxVariable(
631  "MooseVariable", _name + "_tangent_" + disp_component, var_params);
632  }
633  }
634  }
635  }
636 
637  if (_current_task == "add_user_object" && (_formulation != ContactFormulation::MORTAR) &&
639  {
640  auto var_params = _factory.getValidParams("NodalArea");
641 
642  // Get secondary_boundary_vector from possibly updated set from the
643  // ContactAction constructor cleanup
644  const auto actions = _awh.getActions<ContactAction>();
645 
646  std::vector<BoundaryName> secondary_boundary_vector;
647  for (const auto * const action : actions)
648  for (const auto j : index_range(action->_boundary_pairs))
649  secondary_boundary_vector.push_back(action->_boundary_pairs[j].second);
650 
651  var_params.set<std::vector<BoundaryName>>("boundary") = secondary_boundary_vector;
652  var_params.set<std::vector<VariableName>>("variable") = {"nodal_area"};
653 
654  mooseAssert(_problem, "Problem pointer is NULL");
655  var_params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_TIMESTEP_BEGIN};
656  var_params.set<bool>("use_displaced_mesh") = true;
657 
658  _problem->addUserObject("NodalArea",
659  "nodal_area_object_" + Moose::stringify(contact_userobject_counter++),
660  var_params);
661  }
662 }
Action class for creating constraints, kernels, and user objects necessary for mechanical contact...
Definition: ContactAction.h:44
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:94
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.
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.
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 665 of file ContactAction.C.

Referenced by act().

666 {
667  // Increment counter for contact action objects
669 
672  {
673  // Add ContactPressureAux: Only one object for all contact pairs
674  const auto actions = _awh.getActions<ContactAction>();
675 
676  // Add auxiliary kernel if we are the last contact action object.
677  if (contact_action_counter == actions.size())
678  {
679  std::vector<BoundaryName> boundary_vector;
680  std::vector<BoundaryName> pair_boundary_vector;
681 
682  for (const auto * const action : actions)
683  for (const auto j : index_range(action->_boundary_pairs))
684  {
685  boundary_vector.push_back(action->_boundary_pairs[j].second);
686  pair_boundary_vector.push_back(action->_boundary_pairs[j].first);
687  }
688 
689  InputParameters params = _factory.getValidParams("ContactPressureAux");
690  params.applyParameters(parameters(), {"order"});
691 
692  std::vector<VariableName> displacements =
693  getParam<std::vector<VariableName>>("displacements");
694  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
695  .system()
696  .variable_type(displacements[0])
697  .order.get_order();
698 
699  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
700  params.set<std::vector<BoundaryName>>("boundary") = boundary_vector;
701  params.set<std::vector<BoundaryName>>("paired_boundary") = pair_boundary_vector;
702  params.set<AuxVariableName>("variable") = "contact_pressure";
703  params.addRequiredCoupledVar("nodal_area", "The nodal area");
704  params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area"};
705  params.set<bool>("use_displaced_mesh") = true;
706 
707  std::string name = _name + "_contact_pressure";
708  params.set<ExecFlagEnum>("execute_on",
710  _problem->addAuxKernel("ContactPressureAux", name, params);
711  }
712  }
713  else
714  for (const auto & contact_pair : _boundary_pairs)
715  {
716  const auto & [_, secondary_name] = contact_pair;
717  const auto type = "MortarUserObjectAux";
719  params.set<std::vector<BoundaryName>>("boundary") = {secondary_name};
720  params.set<AuxVariableName>("variable") = "contact_pressure";
721  params.set<bool>("use_displaced_mesh") = true; // Unecessary as this object only operates on
722  // nodes, but we'll do it for consistency
723  params.set<MooseEnum>("contact_quantity") = "normal_pressure";
724  const auto & [primary_id, secondary_id, uo_name] =
725  libmesh_map_find(_bnd_pair_to_mortar_info, contact_pair);
726  params.set<UserObjectName>("user_object") = uo_name;
727  const std::string name = _name + "_contact_pressure" + std::to_string(primary_id) + "_" +
728  std::to_string(secondary_id);
729 
730  _problem->addAuxKernel(type, name, params);
731  }
732 }
Action class for creating constraints, kernels, and user objects necessary for mechanical contact...
Definition: ContactAction.h:44
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:94
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.
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 755 of file ContactAction.C.

Referenced by act().

756 {
757  std::string action_name = MooseUtils::shortName(name());
758 
759  std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
760  const unsigned int ndisp = displacements.size();
761 
762  // Definitions for mortar contact.
763  const std::string primary_subdomain_name = action_name + "_primary_subdomain";
764  const std::string secondary_subdomain_name = action_name + "_secondary_subdomain";
765  const std::string normal_lagrange_multiplier_name = action_name + "_normal_lm";
766  const std::string tangential_lagrange_multiplier_name = action_name + "_tangential_lm";
767  const std::string tangential_lagrange_multiplier_3d_name = action_name + "_tangential_3d_lm";
768  const std::string auxiliary_lagrange_multiplier_name = action_name + "_aux_lm";
769 
770  if (_current_task == "append_mesh_generator")
771  {
772  // Don't do mesh generators when recovering or when the user has requested for us not to
773  // (presumably because the lower-dimensional blocks are already in the mesh due to manual
774  // addition or because we are restarting)
777  {
778  const MeshGeneratorName primary_name = primary_subdomain_name + "_generator";
779  const MeshGeneratorName secondary_name = secondary_subdomain_name + "_generator";
780 
781  auto primary_params = _factory.getValidParams("LowerDBlockFromSidesetGenerator");
782  auto secondary_params = _factory.getValidParams("LowerDBlockFromSidesetGenerator");
783 
784  primary_params.set<SubdomainName>("new_block_name") = primary_subdomain_name;
785  secondary_params.set<SubdomainName>("new_block_name") = secondary_subdomain_name;
786 
787  primary_params.set<std::vector<BoundaryName>>("sidesets") = {_boundary_pairs[0].first};
788  secondary_params.set<std::vector<BoundaryName>>("sidesets") = {_boundary_pairs[0].second};
789 
790  _app.appendMeshGenerator("LowerDBlockFromSidesetGenerator", primary_name, primary_params);
791  _app.appendMeshGenerator("LowerDBlockFromSidesetGenerator", secondary_name, secondary_params);
792  }
793  }
794 
795  // Add the lagrange multiplier on the secondary subdomain.
796  const auto addLagrangeMultiplier =
797  [this, &secondary_subdomain_name, &displacements](const std::string & variable_name,
798  const Real scaling_factor,
799  const bool add_aux_lm,
800  const bool penalty_traction) //
801  {
802  InputParameters params = _factory.getValidParams("MooseVariableBase");
803 
804  // Allow the user to select "weighted" constraints and standard bases (use_dual = false) or
805  // "legacy" constraints and dual bases (use_dual = true). Unless it's for testing purposes,
806  // this combination isn't recommended
807  if (!add_aux_lm || penalty_traction)
808  params.set<bool>("use_dual") = _use_dual;
809 
810  mooseAssert(_problem->systemBaseNonlinear(/*nl_sys_num=*/0).hasVariable(displacements[0]),
811  "Displacement variable is missing");
812  const auto primal_type =
813  _problem->systemBaseNonlinear(/*nl_sys_num=*/0).system().variable_type(displacements[0]);
814 
815  const int lm_order = primal_type.order.get_order();
816 
817  if (primal_type.family == LAGRANGE)
818  {
819  params.set<MooseEnum>("family") = Utility::enum_to_string<FEFamily>(primal_type.family);
820  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{lm_order});
821  }
822  else
823  mooseError("Invalid bases for mortar contact.");
824 
825  params.set<std::vector<SubdomainName>>("block") = {secondary_subdomain_name};
826  if (!(add_aux_lm || penalty_traction))
827  params.set<std::vector<Real>>("scaling") = {scaling_factor};
828 
829  auto fe_type = AddVariableAction::feType(params);
830  auto var_type = AddVariableAction::variableType(fe_type);
831  if (add_aux_lm || penalty_traction)
832  _problem->addAuxVariable(var_type, variable_name, params);
833  else
834  _problem->addVariable(var_type, variable_name, params);
835  };
836 
837  if (_current_task == "add_mortar_variable" && _formulation == ContactFormulation::MORTAR)
838  {
839  addLagrangeMultiplier(
840  normal_lagrange_multiplier_name, getParam<Real>("normal_lm_scaling"), false, false);
841 
843  {
844  addLagrangeMultiplier(tangential_lagrange_multiplier_name,
845  getParam<Real>("tangential_lm_scaling"),
846  false,
847  false);
848  if (ndisp > 2)
849  addLagrangeMultiplier(tangential_lagrange_multiplier_3d_name,
850  getParam<Real>("tangential_lm_scaling"),
851  false,
852  false);
853  }
854 
855  if (getParam<bool>("use_petrov_galerkin"))
856  addLagrangeMultiplier(auxiliary_lagrange_multiplier_name, 1.0, true, false);
857  }
858  else if (_current_task == "add_mortar_variable" &&
860  {
861  if (_use_dual)
862  addLagrangeMultiplier(auxiliary_lagrange_multiplier_name, 1.0, false, true);
863  }
864 
865  if (_current_task == "add_user_object")
866  {
867  const auto register_mortar_uo_name = [this](const auto & bnd_pair, const auto & uo_prefix)
868  {
869  const auto & [primary_name, secondary_name] = bnd_pair;
870  const auto primary_id = _mesh->getBoundaryID(primary_name);
871  const auto secondary_id = _mesh->getBoundaryID(secondary_name);
872  const auto uo_name = uo_prefix + name();
873  _bnd_pair_to_mortar_info.emplace(bnd_pair, MortarInfo{primary_id, secondary_id, uo_name});
874  return uo_name;
875  };
876 
877  // check if the correct problem class is selected if AL parameters are provided
879  !dynamic_cast<AugmentedLagrangianContactProblemInterface *>(_problem.get()))
880  {
881  const std::vector<std::string> params = {"penalty_multiplier",
882  "penalty_multiplier_friction",
883  "al_penetration_tolerance",
884  "al_incremental_slip_tolerance",
885  "al_frictional_force_tolerance"};
886  for (const auto & param : params)
887  if (parameters().isParamSetByUser(param))
888  paramError(param,
889  "Augmented Lagrange parameter was specified, but the selected problem type "
890  "does not support Augmented Lagrange iterations.");
891  }
892 
894  {
895  auto uo_params = _factory.getValidParams("LMWeightedGapUserObject");
896 
897  uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
898  uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
899  uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
900  uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
901  uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
902  uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
903  if (ndisp > 2)
904  uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
905  uo_params.set<bool>("use_displaced_mesh") = true;
906  uo_params.set<std::vector<VariableName>>("lm_variable") = {normal_lagrange_multiplier_name};
907  uo_params.applySpecificParameters(
908  parameters(), {"correct_edge_dropping", "use_petrov_galerkin", "debug_mesh"});
909  if (getParam<bool>("use_petrov_galerkin"))
910  uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
911 
912  _problem->addUserObject("LMWeightedGapUserObject",
913  register_mortar_uo_name(_boundary_pairs[0], "lm_weightedgap_object_"),
914  uo_params);
915  }
917  {
918  auto uo_params = _factory.getValidParams("LMWeightedVelocitiesUserObject");
919  uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
920  uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
921  uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
922  uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
923  uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
924  uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
925  if (ndisp > 2)
926  uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
927 
928  uo_params.set<VariableName>("secondary_variable") = displacements[0];
929  uo_params.set<bool>("use_displaced_mesh") = true;
930  uo_params.set<std::vector<VariableName>>("lm_variable_normal") = {
931  normal_lagrange_multiplier_name};
932  uo_params.set<std::vector<VariableName>>("lm_variable_tangential_one") = {
933  tangential_lagrange_multiplier_name};
934  if (ndisp > 2)
935  uo_params.set<std::vector<VariableName>>("lm_variable_tangential_two") = {
936  tangential_lagrange_multiplier_3d_name};
937  uo_params.applySpecificParameters(
938  parameters(), {"correct_edge_dropping", "use_petrov_galerkin", "debug_mesh"});
939  if (getParam<bool>("use_petrov_galerkin"))
940  uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
941 
942  const auto uo_name = _problem->addUserObject(
943  "LMWeightedVelocitiesUserObject",
944  register_mortar_uo_name(_boundary_pairs[0], "lm_weightedvelocities_object_"),
945  uo_params);
946  }
947 
949  {
950  auto uo_params = _factory.getValidParams("PenaltyWeightedGapUserObject");
951 
952  uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
953  uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
954  uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
955  uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
956  uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
957  uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
958 
959  // AL parameters
960  uo_params.applySpecificParameters(parameters(),
961  {"correct_edge_dropping",
962  "penalty",
963  "debug_mesh",
964  "max_penalty_multiplier",
965  "adaptivity_penalty_normal"});
966 
967  if (isParamValid("al_penetration_tolerance"))
968  uo_params.set<Real>("penetration_tolerance") = getParam<Real>("al_penetration_tolerance");
969  if (isParamValid("penalty_multiplier"))
970  uo_params.set<Real>("penalty_multiplier") = getParam<Real>("penalty_multiplier");
971  // In the contact action, we force the physical value of the normal gap, which also normalizes
972  // the penalty factor with the "area" around the node
973  uo_params.set<bool>("use_physical_gap") = true;
974 
975  if (_use_dual)
976  uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
977 
978  if (ndisp > 2)
979  uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
980  uo_params.set<bool>("use_displaced_mesh") = true;
981 
982  _problem->addUserObject(
983  "PenaltyWeightedGapUserObject",
984  register_mortar_uo_name(_boundary_pairs[0], "penalty_weightedgap_object_"),
985  uo_params);
986  _problem->haveADObjects(true);
987  }
989  {
990  auto uo_params = _factory.getValidParams("PenaltyFrictionUserObject");
991  uo_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
992  uo_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
993  uo_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
994  uo_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
995  uo_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
996  uo_params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
997  uo_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
998  if (ndisp > 2)
999  uo_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1000 
1001  uo_params.set<VariableName>("secondary_variable") = displacements[0];
1002  uo_params.set<bool>("use_displaced_mesh") = true;
1003  uo_params.set<Real>("friction_coefficient") = getParam<Real>("friction_coefficient");
1004  uo_params.set<Real>("penalty") = getParam<Real>("penalty");
1005  uo_params.set<Real>("penalty_friction") = getParam<Real>("penalty_friction");
1006 
1007  // AL parameters
1008  uo_params.set<Real>("max_penalty_multiplier") = getParam<Real>("max_penalty_multiplier");
1009  uo_params.set<MooseEnum>("adaptivity_penalty_normal") =
1010  getParam<MooseEnum>("adaptivity_penalty_normal");
1011  uo_params.set<MooseEnum>("adaptivity_penalty_friction") =
1012  getParam<MooseEnum>("adaptivity_penalty_friction");
1013  if (isParamValid("al_penetration_tolerance"))
1014  uo_params.set<Real>("penetration_tolerance") = getParam<Real>("al_penetration_tolerance");
1015  if (isParamValid("penalty_multiplier"))
1016  uo_params.set<Real>("penalty_multiplier") = getParam<Real>("penalty_multiplier");
1017  if (isParamValid("penalty_multiplier_friction"))
1018  uo_params.set<Real>("penalty_multiplier_friction") =
1019  getParam<Real>("penalty_multiplier_friction");
1020 
1021  if (isParamValid("al_incremental_slip_tolerance"))
1022  uo_params.set<Real>("slip_tolerance") = getParam<Real>("al_incremental_slip_tolerance");
1023  // In the contact action, we force the physical value of the normal gap, which also normalizes
1024  // the penalty factor with the "area" around the node
1025  uo_params.set<bool>("use_physical_gap") = true;
1026 
1027  if (_use_dual)
1028  uo_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
1029 
1030  uo_params.applySpecificParameters(parameters(),
1031  {"friction_coefficient", "penalty", "penalty_friction"});
1032 
1033  _problem->addUserObject(
1034  "PenaltyFrictionUserObject",
1035  register_mortar_uo_name(_boundary_pairs[0], "penalty_friction_object_"),
1036  uo_params);
1037  _problem->haveADObjects(true);
1038  }
1039  }
1040 
1041  if (_current_task == "add_constraint")
1042  {
1043  // Prepare problem for enforcement with Lagrange multipliers
1045  {
1046  std::string mortar_constraint_name;
1047 
1048  if (!_mortar_dynamics)
1049  mortar_constraint_name = "ComputeWeightedGapLMMechanicalContact";
1050  else
1051  mortar_constraint_name = "ComputeDynamicWeightedGapLMMechanicalContact";
1052 
1053  InputParameters params = _factory.getValidParams(mortar_constraint_name);
1054  if (_mortar_dynamics)
1055  params.applySpecificParameters(
1056  parameters(), {"newmark_beta", "newmark_gamma", "capture_tolerance", "wear_depth"});
1057 
1058  else // We need user objects for quasistatic constraints
1059  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedgap_object_" + name();
1060 
1061  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1062  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1063  params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1064  params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1065  params.set<NonlinearVariableName>("variable") = normal_lagrange_multiplier_name;
1066  params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1067  params.set<Real>("c") = getParam<Real>("c_normal");
1068 
1069  if (ndisp > 1)
1070  params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1071  if (ndisp > 2)
1072  params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1073 
1074  params.set<bool>("use_displaced_mesh") = true;
1075 
1077  {"correct_edge_dropping",
1078  "normalize_c",
1079  "extra_vector_tags",
1080  "absolute_value_vector_tags",
1081  "debug_mesh"});
1082 
1083  _problem->addConstraint(
1084  mortar_constraint_name, action_name + "_normal_lm_weighted_gap", params);
1085  _problem->haveADObjects(true);
1086  }
1087  // Add the tangential and normal Lagrange's multiplier constraints on the secondary boundary.
1089  {
1090  std::string mortar_constraint_name;
1091 
1092  if (!_mortar_dynamics)
1093  mortar_constraint_name = "ComputeFrictionalForceLMMechanicalContact";
1094  else
1095  mortar_constraint_name = "ComputeDynamicFrictionalForceLMMechanicalContact";
1096 
1097  InputParameters params = _factory.getValidParams(mortar_constraint_name);
1098  if (_mortar_dynamics)
1099  params.applySpecificParameters(
1100  parameters(), {"newmark_beta", "newmark_gamma", "capture_tolerance", "wear_depth"});
1101  else
1102  { // We need user objects for quasistatic constraints
1103  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedvelocities_object_" + name();
1104  params.set<UserObjectName>("weighted_velocities_uo") =
1105  "lm_weightedvelocities_object_" + name();
1106  }
1107 
1108  params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
1109  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1110  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1111  params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1112  params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1113  params.set<bool>("use_displaced_mesh") = true;
1114  params.set<Real>("c_t") = getParam<Real>("c_tangential");
1115  params.set<Real>("c") = getParam<Real>("c_normal");
1116  params.set<bool>("normalize_c") = getParam<bool>("normalize_c");
1117  params.set<bool>("compute_primal_residuals") = false;
1118 
1119  params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1120 
1121  if (ndisp > 1)
1122  params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1123  if (ndisp > 2)
1124  params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1125 
1126  params.set<NonlinearVariableName>("variable") = normal_lagrange_multiplier_name;
1127  params.set<std::vector<VariableName>>("friction_lm") = {tangential_lagrange_multiplier_name};
1128 
1129  if (ndisp > 2)
1130  params.set<std::vector<VariableName>>("friction_lm_dir") = {
1131  tangential_lagrange_multiplier_3d_name};
1132 
1133  params.set<Real>("mu") = getParam<Real>("friction_coefficient");
1134  params.applySpecificParameters(
1135  parameters(), {"extra_vector_tags", "absolute_value_vector_tags", "debug_mesh"});
1136 
1137  _problem->addConstraint(mortar_constraint_name, action_name + "_tangential_lm", params);
1138  _problem->haveADObjects(true);
1139  }
1140 
1141  const auto addMechanicalContactConstraints =
1142  [this, &primary_subdomain_name, &secondary_subdomain_name, &displacements](
1143  const std::string & variable_name,
1144  const std::string & constraint_prefix,
1145  const std::string & constraint_type,
1146  const bool is_additional_frictional_constraint,
1147  const bool is_normal_constraint)
1148  {
1149  InputParameters params = _factory.getValidParams(constraint_type);
1150 
1151  params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
1152  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1153  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1154  params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1155  params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1156 
1158  params.set<NonlinearVariableName>("variable") = variable_name;
1159 
1160  params.set<bool>("use_displaced_mesh") = true;
1161  params.set<bool>("compute_lm_residuals") = false;
1162 
1163  // Additional displacement residual for frictional problem
1164  // The second frictional LM acts on a perpendicular direction.
1165  if (is_additional_frictional_constraint)
1166  params.set<MooseEnum>("direction") = "direction_2";
1167  params.applySpecificParameters(
1168  parameters(), {"extra_vector_tags", "absolute_value_vector_tags", "debug_mesh"});
1169 
1170  for (unsigned int i = 0; i < displacements.size(); ++i)
1171  {
1172  std::string constraint_name = constraint_prefix + Moose::stringify(i);
1173 
1174  params.set<VariableName>("secondary_variable") = displacements[i];
1175  params.set<MooseEnum>("component") = i;
1176 
1177  if (is_normal_constraint && _model != ContactModel::COULOMB &&
1179  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedgap_object_" + name();
1180  else if (is_normal_constraint && _model == ContactModel::COULOMB &&
1182  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedvelocities_object_" + name();
1184  params.set<UserObjectName>("weighted_velocities_uo") =
1185  "lm_weightedvelocities_object_" + name();
1186  else if (is_normal_constraint && _model != ContactModel::COULOMB &&
1188  params.set<UserObjectName>("weighted_gap_uo") = "penalty_weightedgap_object_" + name();
1189  else if (is_normal_constraint && _model == ContactModel::COULOMB &&
1191  params.set<UserObjectName>("weighted_gap_uo") = "penalty_friction_object_" + name();
1193  params.set<UserObjectName>("weighted_velocities_uo") =
1194  "penalty_friction_object_" + name();
1195 
1196  _problem->addConstraint(constraint_type, constraint_name, params);
1197  }
1198  _problem->haveADObjects(true);
1199  };
1200 
1201  // Add mortar mechanical contact constraint objects for primal variables
1202  addMechanicalContactConstraints(normal_lagrange_multiplier_name,
1203  action_name + "_normal_constraint_",
1204  "NormalMortarMechanicalContact",
1205  /* is_additional_frictional_constraint = */ false,
1206  /* is_normal_constraint = */ true);
1207 
1209  {
1210  addMechanicalContactConstraints(tangential_lagrange_multiplier_name,
1211  action_name + "_tangential_constraint_",
1212  "TangentialMortarMechanicalContact",
1213  /* is_additional_frictional_constraint = */ false,
1214  /* is_normal_constraint = */ false);
1215  if (ndisp > 2)
1216  addMechanicalContactConstraints(tangential_lagrange_multiplier_3d_name,
1217  action_name + "_tangential_constraint_3d_",
1218  "TangentialMortarMechanicalContact",
1219  /* is_additional_frictional_constraint = */ true,
1220  /* is_normal_constraint = */ false);
1221  }
1222  }
1223 }
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:94
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.
std::string shortName(const std::string &name)
std::map< std::pair< BoundaryName, BoundaryName >, const MortarInfo > _bnd_pair_to_mortar_info
Map from boundary pair to mortar user object name.
const std::string & name() const
const bool _generate_mortar_mesh
Whether to generate the mortar mesh (useful in a restart simulation e.g.).
const std::string & _current_task
static std::string variableType(const libMesh::FEType &fe_type, const bool is_fv=false, const bool is_array=false)
std::string stringify(const T &t)
const MeshGenerator & appendMeshGenerator(const std::string &type, const std::string &name, InputParameters params)
const bool _mortar_dynamics
Whether mortar dynamic contact constraints are to be used.
bool isParamSetByUser(const std::string &name) const
std::shared_ptr< MooseMesh > & _mesh
static libMesh::FEType feType(const InputParameters &params)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
bool useMasterMesh() const
void mooseError(Args &&... args) const
std::shared_ptr< FEProblemBase > & _problem
bool _use_dual
Whether to use the dual Mortar approach.
bool isParamValid(const std::string &name) const
const ContactModel _model
Contact model type enum.
bool isRecovering() const

◆ addNodeFaceContact()

void ContactAction::addNodeFaceContact ( )
private

Generate constraints for node to face contact.

Definition at line 1226 of file ContactAction.C.

Referenced by act().

1227 {
1228  if (_current_task == "post_mesh_prepared" && _automatic_pairing_boundaries.size() > 0)
1229  {
1230  if (getParam<MooseEnum>("automatic_pairing_method").getEnum<ProximityMethod>() ==
1233  else if (getParam<MooseEnum>("automatic_pairing_method").getEnum<ProximityMethod>() ==
1236  }
1237 
1238  if (_current_task != "add_constraint")
1239  return;
1240 
1241  std::string action_name = MooseUtils::shortName(name());
1242  std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
1243  const unsigned int ndisp = displacements.size();
1244 
1245  std::string constraint_type;
1246 
1248  constraint_type = "RANFSNormalMechanicalContact";
1249  else
1250  constraint_type = "MechanicalContactConstraint";
1251 
1252  InputParameters params = _factory.getValidParams(constraint_type);
1253 
1254  params.applyParameters(parameters(),
1255  {"displacements",
1256  "secondary_gap_offset",
1257  "mapped_primary_gap_offset",
1258  "primary",
1259  "secondary"});
1260 
1261  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
1262  .system()
1263  .variable_type(displacements[0])
1264  .order.get_order();
1265 
1266  params.set<std::vector<VariableName>>("displacements") = displacements;
1267  params.set<bool>("use_displaced_mesh") = true;
1268  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
1269 
1270  for (const auto & contact_pair : _boundary_pairs)
1271  {
1273  {
1274  params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area"};
1275  params.set<BoundaryName>("boundary") = contact_pair.first;
1276  if (isParamValid("secondary_gap_offset"))
1277  params.set<std::vector<VariableName>>("secondary_gap_offset") = {
1278  getParam<VariableName>("secondary_gap_offset")};
1279  if (isParamValid("mapped_primary_gap_offset"))
1280  params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
1281  getParam<VariableName>("mapped_primary_gap_offset")};
1282  }
1283 
1284  for (unsigned int i = 0; i < ndisp; ++i)
1285  {
1286  std::string name = action_name + "_constraint_" + Moose::stringify(contact_pair, "_") + "_" +
1287  Moose::stringify(i);
1288 
1290  params.set<MooseEnum>("component") = i;
1291  else
1292  params.set<unsigned int>("component") = i;
1293 
1294  params.set<BoundaryName>("primary") = contact_pair.first;
1295  params.set<BoundaryName>("secondary") = contact_pair.second;
1296  params.set<NonlinearVariableName>("variable") = displacements[i];
1297  params.set<std::vector<VariableName>>("primary_variable") = {displacements[i]};
1299  {"extra_vector_tags", "absolute_value_vector_tags"});
1300  _problem->addConstraint(constraint_type, name, params);
1301  }
1302  }
1303 }
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:94
std::vector< BoundaryName > _automatic_pairing_boundaries
List of all possible boundaries for contact for automatic pairing (optional)
Definition: ContactAction.h:97
void applySpecificParameters(const InputParameters &common, const std::vector< std::string > &include, bool allow_private=false)
Factory & _factory
const InputParameters & parameters() const
ProximityMethod
Definition: ContactAction.h:34
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.
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 735 of file ContactAction.C.

736 {
739  {
740  auto params = MortarConstraintBase::validParams();
741  params.set<bool>("use_displaced_mesh") = true;
742  std::string action_name = MooseUtils::shortName(name());
743  const std::string primary_subdomain_name = action_name + "_primary_subdomain";
744  const std::string secondary_subdomain_name = action_name + "_secondary_subdomain";
745  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
746  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
747  params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
748  params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
749  params.set<bool>("use_petrov_galerkin") = getParam<bool>("use_petrov_galerkin");
750  addRelationshipManagers(input_rm_type, params);
751  }
752 }
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:94
virtual void addRelationshipManagers(Moose::RelationshipManagerType input_rm_type) override
const ContactFormulation _formulation
Contact formulation.
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 1642 of file ContactAction.C.

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

1643 {
1645 
1646  params.addParam<MooseEnum>("normal_smoothing_method",
1648  "Method to use to smooth normals");
1649  params.addParam<Real>(
1650  "normal_smoothing_distance",
1651  "Distance from edge in parametric coordinates over which to smooth contact normal");
1652 
1653  params.addParam<MooseEnum>(
1654  "formulation", ContactAction::getFormulationEnum(), "The contact formulation");
1655 
1656  params.addParam<MooseEnum>("model", ContactAction::getModelEnum(), "The contact model to use");
1657 
1658  return params;
1659 }
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 1453 of file ContactAction.C.

Referenced by addNodeFaceContact().

1454 {
1455  mooseInfo("The contact action is reading the list of boundaries and automatically pairs them "
1456  "if their centroids fall within a specified distance of each other.");
1457 
1458  if (!_mesh)
1459  mooseError("Failed to obtain mesh for automatically generating contact pairs.");
1460 
1461  if (!_mesh->getMesh().is_serial())
1462  paramError(
1463  "automatic_pairing_boundaries",
1464  "The generation of automatic contact pairs in the contact action requires a serial mesh.");
1465 
1466  // Compute centers of gravity for each sideset
1467  std::vector<std::pair<BoundaryName, Point>> automatic_pairing_boundaries_cog;
1468  const auto & sideset_ids = _mesh->meshSidesetIds();
1469 
1470  const auto & bnd_to_elem_map = _mesh->getBoundariesToActiveSemiLocalElemIds();
1471 
1472  for (const auto & sideset_name : _automatic_pairing_boundaries)
1473  {
1474  // If the sideset provided in the input file isn't in the mesh, error out.
1475  const auto find_set = sideset_ids.find(_mesh->getBoundaryID(sideset_name));
1476  if (find_set == sideset_ids.end())
1477  paramError("automatic_pairing_boundaries",
1478  sideset_name,
1479  " is not defined as a sideset in the mesh.");
1480 
1481  auto dofs_set = bnd_to_elem_map.find(_mesh->getBoundaryID(sideset_name));
1482 
1483  // Initialize data for sideset
1484  Point center_of_gravity(0, 0, 0);
1485  Real accumulated_sideset_area(0);
1486 
1487  // Pointer to lower-dimensional element on the sideset
1488  std::unique_ptr<const Elem> side_ptr;
1489  const std::unordered_set<dof_id_type> & bnd_elems = dofs_set->second;
1490 
1491  for (auto elem_id : bnd_elems)
1492  {
1493  const Elem * elem = _mesh->elemPtr(elem_id);
1494  unsigned int side = _mesh->sideWithBoundaryID(elem, _mesh->getBoundaryID(sideset_name));
1495 
1496  // update side_ptr
1497  elem->side_ptr(side_ptr, side);
1498 
1499  // area of the (linearized) side
1500  const auto side_area = side_ptr->volume();
1501 
1502  // position of the side
1503  const auto side_position = side_ptr->true_centroid();
1504 
1505  center_of_gravity += side_position * side_area;
1506  accumulated_sideset_area += side_area;
1507  }
1508 
1509  // Average each element's center of gravity (centroid) with its area
1510  center_of_gravity /= accumulated_sideset_area;
1511 
1512  // Add sideset-cog pair to vector
1513  automatic_pairing_boundaries_cog.emplace_back(sideset_name, center_of_gravity);
1514  }
1515 
1516  // Vectors of distances for each pair
1517  std::vector<std::pair<std::pair<BoundaryName, BoundaryName>, Real>> pairs_distances;
1518 
1519  // Assign distances to identify nearby pairs.
1520  for (std::size_t i = 0; i < automatic_pairing_boundaries_cog.size() - 1; i++)
1521  for (std::size_t j = i + 1; j < automatic_pairing_boundaries_cog.size(); j++)
1522  {
1523  const Point & distance_vector =
1524  automatic_pairing_boundaries_cog[i].second - automatic_pairing_boundaries_cog[j].second;
1525 
1526  if (automatic_pairing_boundaries_cog[i].first != automatic_pairing_boundaries_cog[j].first)
1527  {
1528  const Real distance = distance_vector.norm();
1529  const std::pair pair = std::make_pair(automatic_pairing_boundaries_cog[i].first,
1530  automatic_pairing_boundaries_cog[j].first);
1531  pairs_distances.emplace_back(std::make_pair(pair, distance));
1532  }
1533  }
1534 
1535  const auto automatic_pairing_distance = getParam<Real>("automatic_pairing_distance");
1536 
1537  // Loop over all pairs
1538  std::vector<std::pair<std::pair<BoundaryName, BoundaryName>, Real>> lean_pairs_distances;
1539  for (const auto & pair_distance : pairs_distances)
1540  if (pair_distance.second <= automatic_pairing_distance)
1541  {
1542  lean_pairs_distances.emplace_back(pair_distance);
1543  mooseInfoRepeated("Generating contact pair primary--secondary ",
1544  pair_distance.first.first,
1545  "--",
1546  pair_distance.first.second,
1547  ", with a relative distance of ",
1548  pair_distance.second);
1549  }
1550 
1551  // Create the boundary pairs (possibly with repeated pairs depending on user input)
1552  for (const auto & lean_pairs_distance : lean_pairs_distances)
1553  {
1554  // Make sure secondary surface's boundary ID is less than primary surface's boundary ID.
1555  // This is done to ensure some consistency in the boundary matching, which helps in defining
1556  // auxiliary kernels in the input file.
1557  if (_mesh->getBoundaryID(lean_pairs_distance.first.first) >
1558  _mesh->getBoundaryID(lean_pairs_distance.first.second))
1559  _boundary_pairs.push_back(
1560  {lean_pairs_distance.first.first, lean_pairs_distance.first.second});
1561  else
1562  _boundary_pairs.push_back(
1563  {lean_pairs_distance.first.second, lean_pairs_distance.first.first});
1564  }
1565 
1566  // Let's remove possibly repeated pairs
1568 }
void mooseInfo(Args &&... args) const
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:94
std::vector< BoundaryName > _automatic_pairing_boundaries
List of all possible boundaries for contact for automatic pairing (optional)
Definition: ContactAction.h:97
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 1315 of file ContactAction.C.

Referenced by addNodeFaceContact().

1316 {
1317  mooseInfo("The contact action is reading the list of boundaries and automatically pairs them "
1318  "if the distance between nodes is less than a specified distance.");
1319 
1320  if (!_mesh)
1321  mooseError("Failed to obtain mesh for automatically generating contact pairs.");
1322 
1323  if (!_mesh->getMesh().is_serial())
1324  paramError(
1325  "automatic_pairing_boundaries",
1326  "The generation of automatic contact pairs in the contact action requires a serial mesh.");
1327 
1328  // Create automatic_pairing_boundaries_id
1329  std::vector<BoundaryID> _automatic_pairing_boundaries_id;
1330  for (const auto & sideset_name : _automatic_pairing_boundaries)
1331  _automatic_pairing_boundaries_id.emplace_back(_mesh->getBoundaryID(sideset_name));
1332 
1333  // Vector of pairs node-boundary id
1334  std::vector<NodeBoundaryIDInfo> node_boundary_id_vector;
1335 
1336  // Data structures to hold the boundary nodes
1337  const ConstBndNodeRange & bnd_nodes = *_mesh->getBoundaryNodeRange();
1338 
1339  for (const auto & bnode : bnd_nodes)
1340  {
1341  const BoundaryID boundary_id = bnode->_bnd_id;
1342  const Node * node_ptr = bnode->_node;
1343 
1344  // Make sure node is on a boundary chosen for contact mechanics
1345  auto it = std::find(_automatic_pairing_boundaries_id.begin(),
1346  _automatic_pairing_boundaries_id.end(),
1347  boundary_id);
1348 
1349  if (it != _automatic_pairing_boundaries_id.end())
1350  node_boundary_id_vector.emplace_back(node_ptr, boundary_id);
1351  }
1352 
1353  // sort by increasing boundary id
1354  std::sort(node_boundary_id_vector.begin(),
1355  node_boundary_id_vector.end(),
1356  [](const NodeBoundaryIDInfo & first_pair, const NodeBoundaryIDInfo & second_pair)
1357  { return first_pair.second < second_pair.second; });
1358 
1359  // build kd-tree
1360  using KDTreeType = nanoflann::KDTreeSingleIndexAdaptor<
1361  nanoflann::L2_Simple_Adaptor<Real, PointListAdaptor<NodeBoundaryIDInfo>, Real, std::size_t>,
1363  LIBMESH_DIM,
1364  std::size_t>;
1365 
1366  // This parameter can be tuned. Others use '10'
1367  const unsigned int max_leaf_size = 20;
1368 
1369  // Build point list adaptor with all nodes-sidesets pairs for possible mechanical contact
1370  auto point_list = PointListAdaptor<NodeBoundaryIDInfo>(node_boundary_id_vector.begin(),
1371  node_boundary_id_vector.end());
1372  auto kd_tree = std::make_unique<KDTreeType>(
1373  LIBMESH_DIM, point_list, nanoflann::KDTreeSingleIndexAdaptorParams(max_leaf_size));
1374 
1375  if (!kd_tree)
1376  mooseError("Internal error. KDTree was not properly initialized in the contact action.");
1377 
1378  kd_tree->buildIndex();
1379 
1380  // data structures for kd-tree search
1381  nanoflann::SearchParameters search_params;
1382  std::vector<nanoflann::ResultItem<std::size_t, Real>> ret_matches;
1383 
1384  const auto radius_for_search = getParam<Real>("automatic_pairing_distance");
1385 
1386  // For all nodes
1387  for (const auto & pair : node_boundary_id_vector)
1388  {
1389  // clear result buffer
1390  ret_matches.clear();
1391 
1392  // position where we expect a periodic partner for the current node and boundary
1393  const Point search_point = *pair.first;
1394 
1395  // search at the expected point
1396  kd_tree->radiusSearch(
1397  &(search_point)(0), radius_for_search * radius_for_search, ret_matches, search_params);
1398 
1399  for (auto & match_pair : ret_matches)
1400  {
1401  const auto & match = node_boundary_id_vector[match_pair.first];
1402 
1403  //
1404  // If the proximity node identified belongs to a boundary in the input, add boundary pair
1405  //
1406 
1407  // Make sure node is on a boundary chosen for contact mechanics
1408  auto it = std::find(_automatic_pairing_boundaries_id.begin(),
1409  _automatic_pairing_boundaries_id.end(),
1410  match.second);
1411 
1412  // If nodes are on the same boundary, pass.
1413  if (match.second == pair.second)
1414  continue;
1415 
1416  // At this point we will likely create many repeated pairs because many nodal pairs may
1417  // fulfill the distance condition imposed by the automatic_pairing_distance user input
1418  // parameter.
1419  if (it != _automatic_pairing_boundaries_id.end())
1420  {
1421  const auto index_one = cast_int<int>(it - _automatic_pairing_boundaries_id.begin());
1422  auto it_other = std::find(_automatic_pairing_boundaries_id.begin(),
1423  _automatic_pairing_boundaries_id.end(),
1424  pair.second);
1425 
1426  mooseAssert(it_other != _automatic_pairing_boundaries_id.end(),
1427  "Error in contact action. Unable to find boundary ID for node proximity "
1428  "automatic pairing.");
1429 
1430  const auto index_two = cast_int<int>(it_other - _automatic_pairing_boundaries_id.begin());
1431 
1432  if (pair.second > match.second)
1433  _boundary_pairs.push_back(
1435  else
1436  _boundary_pairs.push_back(
1438  }
1439  }
1440  }
1441 
1442  // Let's remove likely repeated pairs
1444 
1445  mooseInfo(
1446  "The following boundary pairs were created by the contact action using nodal proximity: ");
1447  for (const auto & [primary, secondary] : _boundary_pairs)
1449  "Primary boundary ID: ", primary, " and secondary boundary ID: ", secondary, ".");
1450 }
void mooseInfo(Args &&... args) const
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:94
std::vector< BoundaryName > _automatic_pairing_boundaries
List of all possible boundaries for contact for automatic pairing (optional)
Definition: ContactAction.h:97
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 1583 of file ContactAction.C.

Referenced by commonParameters().

1584 {
1585  auto formulations = MooseEnum(
1586  "ranfs kinematic penalty augmented_lagrange tangential_penalty mortar mortar_penalty",
1587  "kinematic");
1588 
1589  formulations.addDocumentation(
1590  "ranfs",
1591  "Reduced Active Nonlinear Function Set scheme for node-on-face contact. Provides exact "
1592  "enforcement without Lagrange multipliers or penalty terms.");
1593  formulations.addDocumentation(
1594  "kinematic",
1595  "Kinematic contact constraint enforcement transfers the internal forces at secondary nodes "
1596  "to the corresponding primary face for node-on-face contact. Provides exact "
1597  "enforcement without Lagrange multipliers or penalty terms.");
1598  formulations.addDocumentation(
1599  "penalty",
1600  "Node-on-face penalty based contact constraint enforcement. Interpenetration is penalized. "
1601  "Enforcement depends on the penalty magnitude. High penalties can introduce ill conditioning "
1602  "of the system.");
1603  formulations.addDocumentation("augmented_lagrange",
1604  "Node-on-face augmented Lagrange penalty based contact constraint "
1605  "enforcement. Interpenetration is enforced up to a user specified "
1606  "tolerance, ill-conditioning is generally avoided. Requires an "
1607  "Augmented Lagrange Problem class to be used in the simulation.");
1608  formulations.addDocumentation(
1609  "tangential_penalty",
1610  "Node-on-face penalty based frictional contact constraint enforcement. Interpenetration and "
1611  "slip distance for sticking nodes are penalized. Enforcement depends on the penalty "
1612  "magnitudes. High penalties can introduce ill conditioning of the system.");
1613  formulations.addDocumentation(
1614  "mortar",
1615  "Mortar based contact constraint enforcement using Lagrange multipliers. Provides exact "
1616  "enforcement and a variationally consistent formulation. Lagrange multipliers introduce a "
1617  "saddle point character in the system matrix which can have a negative impact on scalability "
1618  "with iterative solvers");
1619  formulations.addDocumentation(
1620  "mortar_penalty",
1621  "Mortar and penalty based contact constraint enforcement. When using an Augmented Lagrange "
1622  "Problem class this provides normal (and tangential) contact constratint enforced up to a "
1623  "user specified tolerances. Without AL the enforcement depends on the penalty magnitudes. "
1624  "High penalties can introduce ill conditioning of the system.");
1625 
1626  return formulations;
1627 }

◆ getModelEnum()

MooseEnum ContactAction::getModelEnum ( )
static

Get contact model.

Returns
enum

Definition at line 1571 of file ContactAction.C.

Referenced by commonParameters(), and validParams().

1572 {
1573  return MooseEnum("frictionless glued coulomb", "frictionless");
1574 }

◆ getProximityMethod()

MooseEnum ContactAction::getProximityMethod ( )
static

Get proximity method for automatic pairing.

Returns
enum

Definition at line 1577 of file ContactAction.C.

Referenced by validParams().

1578 {
1579  return MooseEnum("node centroid");
1580 }

◆ getSmoothingEnum()

MooseEnum ContactAction::getSmoothingEnum ( )
static

Get smoothing type.

Returns
enum

Definition at line 1636 of file ContactAction.C.

Referenced by commonParameters().

1637 {
1638  return MooseEnum("edge_based nodal_normal_based", "");
1639 }

◆ getSystemEnum()

MooseEnum ContactAction::getSystemEnum ( )
static

Get contact system.

Returns
enum

Definition at line 1630 of file ContactAction.C.

1631 {
1632  return MooseEnum("Constraint", "Constraint");
1633 }

◆ removeRepeatedPairs()

void ContactAction::removeRepeatedPairs ( )
private

Remove repeated contact pairs from _boundary_pairs.

Definition at line 418 of file ContactAction.C.

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

419 {
420  if (_boundary_pairs.size() == 0 && _automatic_pairing_boundaries.size() == 0)
421  paramError(
422  "primary",
423  "Number of contact pairs in the contact action is zero. Please revise your input file.");
424 
425  // Remove repeated interactions
426  std::vector<std::pair<BoundaryName, BoundaryName>> lean_boundary_pairs;
427 
428  for (const auto & [primary, secondary] : _boundary_pairs)
429  {
430  // Structured bindings are not capturable (primary_copy, secondary_copy)
431  auto it = std::find_if(lean_boundary_pairs.begin(),
432  lean_boundary_pairs.end(),
433  [&, primary_copy = primary, secondary_copy = secondary](
434  const std::pair<BoundaryName, BoundaryName> & lean_pair)
435  {
436  const bool match_one = lean_pair.second == secondary_copy &&
437  lean_pair.first == primary_copy;
438  const bool match_two = lean_pair.second == primary_copy &&
439  lean_pair.first == secondary_copy;
440  const bool exist = match_one || match_two;
441  return exist;
442  });
443 
444  if (it == lean_boundary_pairs.end())
445  lean_boundary_pairs.emplace_back(primary, secondary);
446  else
447  mooseInfo("Contact pair ",
448  primary,
449  "--",
450  secondary,
451  " has been removed from the contact interaction list due to "
452  "duplicates in the input file.");
453  }
454 
455  _boundary_pairs = lean_boundary_pairs;
456 }
void mooseInfo(Args &&... args) const
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:94
std::vector< BoundaryName > _automatic_pairing_boundaries
List of all possible boundaries for contact for automatic pairing (optional)
Definition: ContactAction.h:97
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<Real>("al_penetration_tolerance",
157  "The tolerance of the penetration for augmented Lagrangian method.");
158  params.addParam<Real>("al_incremental_slip_tolerance",
159  "The tolerance of the incremental slip for augmented Lagrangian method.");
160  params.addRangeCheckedParam<Real>(
161  "max_penalty_multiplier",
162  1.0e3,
163  "max_penalty_multiplier >= 1.0",
164  "Maximum multiplier applied to penalty factors when adaptivity is used in an augmented "
165  "Lagrange setting. The penalty factor supplied by the user is used as a reference to "
166  "determine its maximum. If this multiplier is too large, the condition number of the system "
167  "to be solved may be negatively impacted.");
168  MooseEnum adaptivity_penalty_normal("SIMPLE BUSSETTA", "SIMPLE");
169  adaptivity_penalty_normal.addDocumentation(
170  "SIMPLE", "Keep multiplying by the penalty multiplier between AL iterations");
171  adaptivity_penalty_normal.addDocumentation(
172  "BUSSETTA",
173  "Modify the penalty using an algorithm from Bussetta et al, 2012, Comput Mech 49:259-275 "
174  "between AL iterations.");
175  params.addParam<MooseEnum>(
176  "adaptivity_penalty_normal",
177  adaptivity_penalty_normal,
178  "The augmented Lagrange update strategy used on the normal penalty coefficient.");
179  MooseEnum adaptivity_penalty_friction("SIMPLE FRICTION_LIMIT", "FRICTION_LIMIT");
180  adaptivity_penalty_friction.addDocumentation(
181  "SIMPLE", "Keep multiplying by the frictional penalty multiplier between AL iterations");
182  adaptivity_penalty_friction.addDocumentation(
183  "FRICTION_LIMIT",
184  "This strategy will be guided by the Coulomb limit and be less reliant on the initial "
185  "penalty factor provided by the user.");
186  params.addParam<MooseEnum>(
187  "adaptivity_penalty_friction",
188  adaptivity_penalty_friction,
189  "The augmented Lagrange update strategy used on the frictional penalty coefficient.");
190  params.addParam<Real>("al_frictional_force_tolerance",
191  "The tolerance of the frictional force for augmented Lagrangian method.");
192  params.addParam<Real>(
193  "c_normal",
194  1e6,
195  "Parameter for balancing the size of the gap and contact pressure for a mortar formulation. "
196  "This purely numerical "
197  "parameter affects convergence behavior and, in general, should be larger for stiffer "
198  "materials. It is recommended that the user tries out various orders of magnitude for this "
199  "parameter if the default value generates poor contact convergence.");
200  params.addParam<Real>(
201  "c_tangential", 1, "Numerical parameter for nonlinear mortar frictional constraints");
202  params.addParam<bool>("ping_pong_protection",
203  false,
204  "Whether to protect against ping-ponging, e.g. the oscillation of the "
205  "secondary node between two "
206  "different primary faces, by tying the secondary node to the "
207  "edge between the involved primary faces");
208  params.addParam<Real>(
209  "normal_lm_scaling",
210  1.,
211  "Scaling factor to apply to the normal LM variable for a mortar formulation");
212  params.addParam<Real>(
213  "tangential_lm_scaling",
214  1.,
215  "Scaling factor to apply to the tangential LM variable for a mortar formulation");
216  params.addParam<bool>(
217  "normalize_c",
218  false,
219  "Whether to normalize c by weighting function norm for mortar contact. When unnormalized "
220  "the value of c effectively depends on element size since in the constraint we compare nodal "
221  "Lagrange Multiplier values to integrated gap values (LM nodal value is independent of "
222  "element size, where integrated values are dependent on element size).");
223  params.addClassDescription("Sets up all objects needed for mechanical contact enforcement");
224  params.addParam<bool>(
225  "use_dual",
226  "Whether to use the dual mortar approach within a mortar formulation. It is defaulted to "
227  "true for "
228  "weighted quantity approach, and to false for the legacy approach. To avoid instabilities "
229  "in the solution and obtain the full benefits of a variational enforcement,"
230  "use of dual mortar with weighted constraints is strongly recommended. This "
231  "input is only intended for advanced users.");
232  params.addParam<bool>(
233  "correct_edge_dropping",
234  false,
235  "Whether to enable correct edge dropping treatment for mortar constraints. When disabled "
236  "any Lagrange Multiplier degree of freedom on a secondary element without full primary "
237  "contributions will be set (strongly) to 0.");
238  params.addParam<bool>(
239  "generate_mortar_mesh",
240  true,
241  "Whether to generate the mortar mesh from the action. Typically this will be the case, but "
242  "one may also want to reuse an existing lower-dimensional mesh prior to a restart.");
243  params.addParam<MooseEnum>("automatic_pairing_method",
245  "The proximity method used for automatic pairing of boundaries.");
246  params.addParam<bool>(
247  "mortar_dynamics",
248  false,
249  "Whether to use constraints that account for the persistency condition, giving rise to "
250  "smoother normal contact pressure evolution. This flag should only be set to yes for dynamic "
251  "simulations using the Newmark-beta numerical integrator");
252  params.addParam<Real>(
253  "newmark_beta",
254  0.25,
255  "Newmark-beta beta parameter for its inclusion in the weighted gap update formula");
256  params.addParam<Real>(
257  "newmark_gamma",
258  0.5,
259  "Newmark-beta gamma parameter for its inclusion in the weighted gap update formula");
260  params.addCoupledVar("wear_depth",
261  "The name of the mortar auxiliary variable that is used to modify the "
262  "weighted gap definition");
263  params.addParam<std::vector<TagName>>(
264  "extra_vector_tags",
265  "The tag names for extra vectors that residual data should be saved into");
266  params.addParam<std::vector<TagName>>(
267  "absolute_value_vector_tags",
268  "The tags for the vectors this residual object should fill with the "
269  "absolute value of the residual contribution");
270  params.addParam<bool>(
271  "use_petrov_galerkin",
272  false,
273  "Whether to use the Petrov-Galerkin approach for the mortar-based constraints. If set to "
274  "true, we use the standard basis as the test function and dual basis as "
275  "the shape function for the interpolation of the Lagrange multiplier variable.");
276  params.addParam<bool>(
277  "debug_mesh",
278  false,
279  "Whether we are going to enable mortar segment mesh debug information. An exodus"
280  "file will be generated if the user sets this flag to true");
281  return params;
282 }
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()
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)

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 97 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 122 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 109 of file ContactAction.h.

Referenced by addMortarContact().

◆ _model

const ContactModel ContactAction::_model
protected

Contact model type enum.

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

Referenced by addMortarContact().

◆ _use_dual

bool ContactAction::_use_dual
protected

Whether to use the dual Mortar approach.

Definition at line 106 of file ContactAction.h.

Referenced by addMortarContact(), and ContactAction().


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