www.mooseframework.org
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]

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
 
virtual const std::string & name () const
 
std::string typeAndName () const
 
std::string errorPrefix (const std::string &error_type) const
 
void callMooseError (std::string msg, const bool with_prefix) const
 
MooseObjectParameterName uniqueParameterName (const std::string &parameter_name) const
 
const InputParametersparameters () const
 
MooseObjectName uniqueName () 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 & 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 &nm) const
 
void paramError (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
 
void connectControllableParams (const std::string &parameter, const std::string &object_type, const std::string &object_name, const std::string &object_parameter) const
 
void mooseError (Args &&... args) const
 
void mooseErrorNonPrefixed (Args &&... args) const
 
void mooseWarning (Args &&... args) const
 
void mooseWarningNonPrefixed (Args &&... args) const
 
void mooseDeprecated (Args &&... args) const
 
void mooseInfo (Args &&... args) const
 
PerfGraphperfGraph ()
 
std::string getDataFileName (const std::string &param) const
 
std::string getDataFileNameByName (const std::string &name, const std::string *param=nullptr) const
 
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...
 

Public Attributes

const ConsoleStream _console
 

Static Public Attributes

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
 

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::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
 
const std::string _type
 
const std::string _name
 
const InputParameters_pars
 
Factory_factory
 
ActionFactory_action_factory
 
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 279 of file ContactAction.C.

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

Member Function Documentation

◆ act()

void ContactAction::act ( )
overridevirtual

Implements Action.

Definition at line 449 of file ContactAction.C.

450 {
451  // proform problem checks/corrections once during the first feasible task
452  if (_current_task == "add_contact_aux_variable")
453  {
454  if (!_problem->getDisplacedProblem())
455  mooseError(
456  "Contact requires updated coordinates. Use the 'displacements = ...' parameter in the "
457  "Mesh block.");
458 
459  // It is risky to apply this optimization to contact problems
460  // since the problem configuration may be changed during Jacobian
461  // evaluation. We therefore turn it off for all contact problems so that
462  // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3.
463  if (!_problem->isSNESMFReuseBaseSetbyUser())
464  _problem->setSNESMFReuseBase(false, false);
465  }
466 
470  else
472 
473  if (_current_task == "add_aux_kernel")
474  { // Add ContactPenetrationAuxAction.
475  if (!_problem->getDisplacedProblem())
476  mooseError("Contact requires updated coordinates. Use the 'displacements = ...' line in the "
477  "Mesh block.");
478  // Create auxiliary kernels for each contact pairs
479  for (const auto & contact_pair : _boundary_pairs)
480  {
481  {
482  InputParameters params = _factory.getValidParams("PenetrationAux");
483  params.applyParameters(parameters(),
484  {"secondary_gap_offset", "mapped_primary_gap_offset", "order"});
485 
486  std::vector<VariableName> displacements =
487  getParam<std::vector<VariableName>>("displacements");
488  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
489  .system()
490  .variable_type(displacements[0])
491  .order.get_order();
492 
493  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
494  params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL, EXEC_LINEAR};
495  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
496  params.set<BoundaryName>("paired_boundary") = contact_pair.first;
497  params.set<AuxVariableName>("variable") = "penetration";
498  if (isParamValid("secondary_gap_offset"))
499  params.set<std::vector<VariableName>>("secondary_gap_offset") = {
500  getParam<VariableName>("secondary_gap_offset")};
501  if (isParamValid("mapped_primary_gap_offset"))
502  params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
503  getParam<VariableName>("mapped_primary_gap_offset")};
504  params.set<bool>("use_displaced_mesh") = true;
505  std::string name = _name + "_contact_" + Moose::stringify(contact_auxkernel_counter++);
506 
507  _problem->addAuxKernel("PenetrationAux", name, params);
508  }
509  }
510 
512 
513  const unsigned int ndisp = getParam<std::vector<VariableName>>("displacements").size();
514 
515  // Add MortarFrictionalPressureVectorAux
517  {
518  {
519  InputParameters params = _factory.getValidParams("MortarFrictionalPressureVectorAux");
520 
521  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
522  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
523  params.set<std::vector<BoundaryName>>("boundary") = {_boundary_pairs[0].second};
524  params.set<ExecFlagEnum>("execute_on", true) = {EXEC_NONLINEAR};
525 
526  std::string action_name = MooseUtils::shortName(name());
527  const std::string tangential_lagrange_multiplier_name = action_name + "_tangential_lm";
528  const std::string tangential_lagrange_multiplier_3d_name =
529  action_name + "_tangential_3d_lm";
530 
531  params.set<std::vector<VariableName>>("tangent_one") = {
532  tangential_lagrange_multiplier_name};
533  params.set<std::vector<VariableName>>("tangent_two") = {
534  tangential_lagrange_multiplier_3d_name};
535 
536  std::vector<std::string> disp_components({"x", "y", "z"});
537  unsigned component_index = 0;
538 
539  // Loop over three displacements
540  for (const auto & disp_component : disp_components)
541  {
542  params.set<AuxVariableName>("variable") = _name + "_tangent_" + disp_component;
543  params.set<unsigned int>("component") = component_index;
544 
545  std::string name = _name + "_mortar_frictional_pressure_" + disp_component + "_" +
547 
548  _problem->addAuxKernel("MortarFrictionalPressureVectorAux", name, params);
549  component_index++;
550  }
551  }
552  }
553  }
554 
555  if (_current_task == "add_contact_aux_variable")
556  {
557  std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
558  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
559  .system()
560  .variable_type(displacements[0])
561  .order.get_order();
562  // Add ContactPenetrationVarAction
563  {
564  auto var_params = _factory.getValidParams("MooseVariable");
565  var_params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
566  var_params.set<MooseEnum>("family") = "LAGRANGE";
567 
568  _problem->addAuxVariable("MooseVariable", "penetration", var_params);
569  }
570  // Add ContactPressureVarAction
571  {
572  auto var_params = _factory.getValidParams("MooseVariable");
573  var_params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
574  var_params.set<MooseEnum>("family") = "LAGRANGE";
575 
576  _problem->addAuxVariable("MooseVariable", "contact_pressure", var_params);
577  }
578  // Add nodal area contact variable
579  {
580  auto var_params = _factory.getValidParams("MooseVariable");
581  var_params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
582  var_params.set<MooseEnum>("family") = "LAGRANGE";
583 
584  _problem->addAuxVariable("MooseVariable", "nodal_area", var_params);
585  }
586 
587  const unsigned int ndisp = getParam<std::vector<VariableName>>("displacements").size();
588 
589  // Add MortarFrictionalPressureVectorAux variables
591  {
592  {
593  std::vector<std::string> disp_components({"x", "y", "z"});
594  // Loop over three displacements
595  for (const auto & disp_component : disp_components)
596  {
597  auto var_params = _factory.getValidParams("MooseVariable");
598  var_params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
599  var_params.set<MooseEnum>("family") = "LAGRANGE";
600 
601  _problem->addAuxVariable(
602  "MooseVariable", _name + "_tangent_" + disp_component, var_params);
603  }
604  }
605  }
606  }
607 
608  if (_current_task == "add_user_object")
609  {
610  auto var_params = _factory.getValidParams("NodalArea");
611 
612  // Get secondary_boundary_vector from possibly updated set from the
613  // ContactAction constructor cleanup
614  const auto actions = _awh.getActions<ContactAction>();
615 
616  std::vector<BoundaryName> secondary_boundary_vector;
617  for (const auto * const action : actions)
618  for (const auto j : index_range(action->_boundary_pairs))
619  secondary_boundary_vector.push_back(action->_boundary_pairs[j].second);
620 
621  var_params.set<std::vector<BoundaryName>>("boundary") = secondary_boundary_vector;
622  var_params.set<std::vector<VariableName>>("variable") = {"nodal_area"};
623 
624  mooseAssert(_problem, "Problem pointer is NULL");
625  var_params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_TIMESTEP_BEGIN};
626  var_params.set<bool>("use_displaced_mesh") = true;
627 
628  _problem->addUserObject("NodalArea",
629  "nodal_area_object_" + Moose::stringify(contact_userobject_counter++),
630  var_params);
631  }
632 }
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
ActionWarehouse & _awh
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.
virtual const std::string & name() const
std::string shortName(const std::string &name)
bool isParamValid(const std::string &name) const
Factory & _factory
static unsigned int contact_mortar_auxkernel_counter
Definition: ContactAction.C:46
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 & _current_task
const ExecFlagType EXEC_LINEAR
std::string stringify(const T &t)
const std::string _name
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
const InputParameters & parameters() const
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
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 635 of file ContactAction.C.

Referenced by act().

636 {
637  // Add ContactPressureAux: Only one object for all contact pairs
638  // if (_formulation != ContactFormulation::MORTAR)
639  const auto actions = _awh.getActions<ContactAction>();
640 
641  // Increment counter for contact action objects
643  // Add auxiliary kernel if we are the last contact action object.
644  if (contact_action_counter == actions.size())
645  {
646  std::vector<BoundaryName> boundary_vector;
647  std::vector<BoundaryName> pair_boundary_vector;
648 
649  for (const auto * const action : actions)
650  for (const auto j : index_range(action->_boundary_pairs))
651  {
652  boundary_vector.push_back(action->_boundary_pairs[j].second);
653  pair_boundary_vector.push_back(action->_boundary_pairs[j].first);
654  }
655 
656  InputParameters params = _factory.getValidParams("ContactPressureAux");
657  params.applyParameters(parameters(), {"order"});
658 
659  std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
660  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
661  .system()
662  .variable_type(displacements[0])
663  .order.get_order();
664 
665  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
666  params.set<std::vector<BoundaryName>>("boundary") = boundary_vector;
667  params.set<std::vector<BoundaryName>>("paired_boundary") = pair_boundary_vector;
668  params.set<AuxVariableName>("variable") = "contact_pressure";
669  params.addRequiredCoupledVar("nodal_area", "The nodal area");
670  params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area"};
671  params.set<bool>("use_displaced_mesh") = true;
672 
673  std::string name = _name + "_contact_pressure";
674  params.set<ExecFlagEnum>("execute_on",
676  _problem->addAuxKernel("ContactPressureAux", name, params);
677  }
678 }
Action class for creating constraints, kernels, and user objects necessary for mechanical contact...
Definition: ContactAction.h:44
ActionWarehouse & _awh
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 ExecFlagType EXEC_TIMESTEP_END
virtual const std::string & name() const
Factory & _factory
const ExecFlagType EXEC_TIMESTEP_BEGIN
const std::string _name
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
const ExecFlagType EXEC_NONLINEAR
std::shared_ptr< FEProblemBase > & _problem
const InputParameters & parameters() const
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 701 of file ContactAction.C.

Referenced by act().

702 {
703  std::string action_name = MooseUtils::shortName(name());
704 
705  std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
706  const unsigned int ndisp = displacements.size();
707 
708  // Definitions for mortar contact.
709  const std::string primary_subdomain_name = action_name + "_primary_subdomain";
710  const std::string secondary_subdomain_name = action_name + "_secondary_subdomain";
711  const std::string normal_lagrange_multiplier_name = action_name + "_normal_lm";
712  const std::string tangential_lagrange_multiplier_name = action_name + "_tangential_lm";
713  const std::string tangential_lagrange_multiplier_3d_name = action_name + "_tangential_3d_lm";
714  const std::string auxiliary_lagrange_multiplier_name = action_name + "_aux_lm";
715 
716  if (_current_task == "append_mesh_generator")
717  {
718  // Don't do mesh generators when recovering or when the user has requested for us not to
719  // (presumably because the lower-dimensional blocks are already in the mesh due to manual
720  // addition or because we are restarting)
721  if (!(_app.isRecovering() && _app.isUltimateMaster()) && !_app.masterMesh() &&
723  {
724  const MeshGeneratorName primary_name = primary_subdomain_name + "_generator";
725  const MeshGeneratorName secondary_name = secondary_subdomain_name + "_generator";
726 
727  auto primary_params = _factory.getValidParams("LowerDBlockFromSidesetGenerator");
728  auto secondary_params = _factory.getValidParams("LowerDBlockFromSidesetGenerator");
729 
730  primary_params.set<SubdomainName>("new_block_name") = primary_subdomain_name;
731  secondary_params.set<SubdomainName>("new_block_name") = secondary_subdomain_name;
732 
733  primary_params.set<std::vector<BoundaryName>>("sidesets") = {_boundary_pairs[0].first};
734  secondary_params.set<std::vector<BoundaryName>>("sidesets") = {_boundary_pairs[0].second};
735 
736  _app.appendMeshGenerator("LowerDBlockFromSidesetGenerator", primary_name, primary_params);
737  _app.appendMeshGenerator("LowerDBlockFromSidesetGenerator", secondary_name, secondary_params);
738  }
739  }
740 
741  // Add the lagrange multiplier on the secondary subdomain.
742  const auto addLagrangeMultiplier =
743  [this, &secondary_subdomain_name, &displacements](const std::string & variable_name,
744  const Real scaling_factor,
745  const bool add_aux_lm,
746  const bool penalty_traction) //
747  {
748  InputParameters params = _factory.getValidParams("MooseVariableBase");
749 
750  // Allow the user to select "weighted" constraints and standard bases (use_dual = false) or
751  // "legacy" constraints and dual bases (use_dual = true). Unless it's for testing purposes,
752  // this combination isn't recommended
753  if (!add_aux_lm || penalty_traction)
754  params.set<bool>("use_dual") = _use_dual;
755 
756  mooseAssert(_problem->systemBaseNonlinear(/*nl_sys_num=*/0).hasVariable(displacements[0]),
757  "Displacement variable is missing");
758  const auto primal_type =
759  _problem->systemBaseNonlinear(/*nl_sys_num=*/0).system().variable_type(displacements[0]);
760 
761  const int lm_order = primal_type.order.get_order();
762 
763  if (primal_type.family == LAGRANGE)
764  {
765  params.set<MooseEnum>("family") = Utility::enum_to_string<FEFamily>(primal_type.family);
766  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{lm_order});
767  }
768  else
769  mooseError("Invalid bases for mortar contact.");
770 
771  params.set<std::vector<SubdomainName>>("block") = {secondary_subdomain_name};
772  if (!(add_aux_lm || penalty_traction))
773  params.set<std::vector<Real>>("scaling") = {scaling_factor};
774 
775  auto fe_type = AddVariableAction::feType(params);
776  auto var_type = AddVariableAction::variableType(fe_type);
777  if (add_aux_lm || penalty_traction)
778  _problem->addAuxVariable(var_type, variable_name, params);
779  else
780  _problem->addVariable(var_type, variable_name, params);
781  };
782 
783  if (_current_task == "add_mortar_variable" && _formulation == ContactFormulation::MORTAR)
784  {
785  addLagrangeMultiplier(
786  normal_lagrange_multiplier_name, getParam<Real>("normal_lm_scaling"), false, false);
787 
789  {
790  addLagrangeMultiplier(tangential_lagrange_multiplier_name,
791  getParam<Real>("tangential_lm_scaling"),
792  false,
793  false);
794  if (ndisp > 2)
795  addLagrangeMultiplier(tangential_lagrange_multiplier_3d_name,
796  getParam<Real>("tangential_lm_scaling"),
797  false,
798  false);
799  }
800 
801  if (getParam<bool>("use_petrov_galerkin"))
802  addLagrangeMultiplier(auxiliary_lagrange_multiplier_name, 1.0, true, false);
803  }
804  else if (_current_task == "add_mortar_variable" &&
806  {
807  if (_use_dual)
808  addLagrangeMultiplier(auxiliary_lagrange_multiplier_name, 1.0, false, true);
809  }
810 
811  if (_current_task == "add_user_object")
812  {
813  // check if the correct problem class is selected if AL parameters are provided
815  !dynamic_cast<AugmentedLagrangianContactProblemInterface *>(_problem.get()))
816  {
817  const std::vector<std::string> params = {"penalty_multiplier",
818  "penalty_multiplier_friction",
819  "al_penetration_tolerance",
820  "al_incremental_slip_tolerance",
821  "al_frictional_force_tolerance"};
822  for (const auto & param : params)
823  if (parameters().isParamSetByUser(param))
824  paramError(param,
825  "Augmented Lagrange parameter was specified, but the selected problem type "
826  "does not support Augmented Lagrange iterations.");
827  }
828 
830  {
831  auto var_params = _factory.getValidParams("LMWeightedGapUserObject");
832 
833  var_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
834  var_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
835  var_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
836  var_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
837  var_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
838  var_params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
839  var_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
840  if (ndisp > 2)
841  var_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
842  var_params.set<bool>("use_displaced_mesh") = true;
843  var_params.set<std::vector<VariableName>>("lm_variable") = {normal_lagrange_multiplier_name};
844  var_params.set<bool>("use_petrov_galerkin") = getParam<bool>("use_petrov_galerkin");
845  if (getParam<bool>("use_petrov_galerkin"))
846  var_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
847 
848  _problem->addUserObject(
849  "LMWeightedGapUserObject", "lm_weightedgap_object_" + name(), var_params);
850  }
852  {
853  auto var_params = _factory.getValidParams("LMWeightedVelocitiesUserObject");
854  var_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
855  var_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
856  var_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
857  var_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
858  var_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
859  var_params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
860  var_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
861  if (ndisp > 2)
862  var_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
863 
864  var_params.set<VariableName>("secondary_variable") = displacements[0];
865  var_params.set<bool>("use_displaced_mesh") = true;
866  var_params.set<std::vector<VariableName>>("lm_variable_normal") = {
867  normal_lagrange_multiplier_name};
868  var_params.set<std::vector<VariableName>>("lm_variable_tangential_one") = {
869  tangential_lagrange_multiplier_name};
870  if (ndisp > 2)
871  var_params.set<std::vector<VariableName>>("lm_variable_tangential_two") = {
872  tangential_lagrange_multiplier_3d_name};
873  var_params.set<bool>("use_petrov_galerkin") = getParam<bool>("use_petrov_galerkin");
874  if (getParam<bool>("use_petrov_galerkin"))
875  var_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
876 
877  _problem->addUserObject(
878  "LMWeightedVelocitiesUserObject", "lm_weightedvelocities_object_" + name(), var_params);
879  }
880 
882  {
883  auto var_params = _factory.getValidParams("PenaltyWeightedGapUserObject");
884 
885  var_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
886  var_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
887  var_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
888  var_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
889  var_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
890  var_params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
891  var_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
892  var_params.set<Real>("penalty") = getParam<Real>("penalty");
893 
894  // AL parameters
895  var_params.set<Real>("max_penalty_multiplier") = getParam<Real>("max_penalty_multiplier");
896  var_params.set<MooseEnum>("adaptivity_penalty_normal") =
897  getParam<MooseEnum>("adaptivity_penalty_normal");
898  if (isParamValid("al_penetration_tolerance"))
899  var_params.set<Real>("penetration_tolerance") = getParam<Real>("al_penetration_tolerance");
900  if (isParamValid("penalty_multiplier"))
901  var_params.set<Real>("penalty_multiplier") = getParam<Real>("penalty_multiplier");
902  // In the contact action, we force the physical value of the normal gap, which also normalizes
903  // the penalty factor with the "area" around the node
904  var_params.set<bool>("use_physical_gap") = true;
905 
906  if (_use_dual)
907  var_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
908 
909  if (ndisp > 2)
910  var_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
911  var_params.set<bool>("use_displaced_mesh") = true;
912 
913  _problem->addUserObject(
914  "PenaltyWeightedGapUserObject", "penalty_weightedgap_object_" + name(), var_params);
915  _problem->haveADObjects(true);
916  }
918  {
919  auto var_params = _factory.getValidParams("PenaltyFrictionUserObject");
920  var_params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
921  var_params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
922  var_params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
923  var_params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
924  var_params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
925  var_params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
926  var_params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
927  if (ndisp > 2)
928  var_params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
929 
930  var_params.set<VariableName>("secondary_variable") = displacements[0];
931  var_params.set<bool>("use_displaced_mesh") = true;
932  var_params.set<Real>("friction_coefficient") = getParam<Real>("friction_coefficient");
933  var_params.set<Real>("penalty") = getParam<Real>("penalty");
934  var_params.set<Real>("penalty_friction") = getParam<Real>("penalty_friction");
935 
936  // AL parameters
937  var_params.set<Real>("max_penalty_multiplier") = getParam<Real>("max_penalty_multiplier");
938  var_params.set<MooseEnum>("adaptivity_penalty_normal") =
939  getParam<MooseEnum>("adaptivity_penalty_normal");
940  var_params.set<MooseEnum>("adaptivity_penalty_friction") =
941  getParam<MooseEnum>("adaptivity_penalty_friction");
942  if (isParamValid("al_penetration_tolerance"))
943  var_params.set<Real>("penetration_tolerance") = getParam<Real>("al_penetration_tolerance");
944  if (isParamValid("penalty_multiplier"))
945  var_params.set<Real>("penalty_multiplier") = getParam<Real>("penalty_multiplier");
946  if (isParamValid("penalty_multiplier_friction"))
947  var_params.set<Real>("penalty_multiplier_friction") =
948  getParam<Real>("penalty_multiplier_friction");
949 
950  if (isParamValid("al_incremental_slip_tolerance"))
951  var_params.set<Real>("slip_tolerance") = getParam<Real>("al_incremental_slip_tolerance");
952  // In the contact action, we force the physical value of the normal gap, which also normalizes
953  // the penalty factor with the "area" around the node
954  var_params.set<bool>("use_physical_gap") = true;
955 
956  if (_use_dual)
957  var_params.set<std::vector<VariableName>>("aux_lm") = {auxiliary_lagrange_multiplier_name};
958 
959  var_params.applySpecificParameters(parameters(),
960  {"friction_coefficient", "penalty", "penalty_friction"});
961 
962  _problem->addUserObject(
963  "PenaltyFrictionUserObject", "penalty_friction_object_" + name(), var_params);
964  _problem->haveADObjects(true);
965  }
966  }
967 
968  if (_current_task == "add_constraint")
969  {
970  // Prepare problem for enforcement with Lagrange multipliers
972  {
973  std::string mortar_constraint_name;
974 
975  if (!_mortar_dynamics)
976  mortar_constraint_name = "ComputeWeightedGapLMMechanicalContact";
977  else
978  mortar_constraint_name = "ComputeDynamicWeightedGapLMMechanicalContact";
979 
980  InputParameters params = _factory.getValidParams(mortar_constraint_name);
981  if (_mortar_dynamics)
983  parameters(), {"newmark_beta", "newmark_gamma", "capture_tolerance", "wear_depth"});
984 
985  else // We need user objects for quasistatic constraints
986  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedgap_object_" + name();
987 
988  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
989  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
990  params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
991  params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
992  params.set<NonlinearVariableName>("variable") = normal_lagrange_multiplier_name;
993  params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
994  params.set<Real>("c") = getParam<Real>("c_normal");
995 
996  if (ndisp > 1)
997  params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
998  if (ndisp > 2)
999  params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1000 
1001  params.set<bool>("use_displaced_mesh") = true;
1002 
1004  {"correct_edge_dropping",
1005  "normalize_c",
1006  "extra_vector_tags",
1007  "absolute_value_vector_tags"});
1008 
1009  _problem->addConstraint(
1010  mortar_constraint_name, action_name + "_normal_lm_weighted_gap", params);
1011  _problem->haveADObjects(true);
1012  }
1013  // Add the tangential and normal Lagrange's multiplier constraints on the secondary boundary.
1015  {
1016  std::string mortar_constraint_name;
1017 
1018  if (!_mortar_dynamics)
1019  mortar_constraint_name = "ComputeFrictionalForceLMMechanicalContact";
1020  else
1021  mortar_constraint_name = "ComputeDynamicFrictionalForceLMMechanicalContact";
1022 
1023  InputParameters params = _factory.getValidParams(mortar_constraint_name);
1024  if (_mortar_dynamics)
1025  params.applySpecificParameters(
1026  parameters(), {"newmark_beta", "newmark_gamma", "capture_tolerance", "wear_depth"});
1027  else
1028  { // We need user objects for quasistatic constraints
1029  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedvelocities_object_" + name();
1030  params.set<UserObjectName>("weighted_velocities_uo") =
1031  "lm_weightedvelocities_object_" + name();
1032  }
1033 
1034  params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
1035  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1036  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1037  params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1038  params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1039  params.set<bool>("use_displaced_mesh") = true;
1040  params.set<Real>("c_t") = getParam<Real>("c_tangential");
1041  params.set<Real>("c") = getParam<Real>("c_normal");
1042  params.set<bool>("normalize_c") = getParam<bool>("normalize_c");
1043  params.set<bool>("compute_primal_residuals") = false;
1044 
1045  params.set<std::vector<VariableName>>("disp_x") = {displacements[0]};
1046 
1047  if (ndisp > 1)
1048  params.set<std::vector<VariableName>>("disp_y") = {displacements[1]};
1049  if (ndisp > 2)
1050  params.set<std::vector<VariableName>>("disp_z") = {displacements[2]};
1051 
1052  params.set<NonlinearVariableName>("variable") = normal_lagrange_multiplier_name;
1053  params.set<std::vector<VariableName>>("friction_lm") = {tangential_lagrange_multiplier_name};
1054 
1055  if (ndisp > 2)
1056  params.set<std::vector<VariableName>>("friction_lm_dir") = {
1057  tangential_lagrange_multiplier_3d_name};
1058 
1059  params.set<Real>("mu") = getParam<Real>("friction_coefficient");
1061  {"extra_vector_tags", "absolute_value_vector_tags"});
1062 
1063  _problem->addConstraint(mortar_constraint_name, action_name + "_tangential_lm", params);
1064  _problem->haveADObjects(true);
1065  }
1066 
1067  const auto addMechanicalContactConstraints =
1068  [this, &primary_subdomain_name, &secondary_subdomain_name, &displacements](
1069  const std::string & variable_name,
1070  const std::string & constraint_prefix,
1071  const std::string & constraint_type,
1072  const bool is_additional_frictional_constraint,
1073  const bool is_normal_constraint)
1074  {
1075  InputParameters params = _factory.getValidParams(constraint_type);
1076 
1077  params.set<bool>("correct_edge_dropping") = getParam<bool>("correct_edge_dropping");
1078  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
1079  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
1080  params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
1081  params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
1082 
1084  params.set<NonlinearVariableName>("variable") = variable_name;
1085 
1086  params.set<bool>("use_displaced_mesh") = true;
1087  params.set<bool>("compute_lm_residuals") = false;
1088 
1089  // Additional displacement residual for frictional problem
1090  // The second frictional LM acts on a perpendicular direction.
1091  if (is_additional_frictional_constraint)
1092  params.set<MooseEnum>("direction") = "direction_2";
1094  {"extra_vector_tags", "absolute_value_vector_tags"});
1095 
1096  for (unsigned int i = 0; i < displacements.size(); ++i)
1097  {
1098  std::string constraint_name = constraint_prefix + Moose::stringify(i);
1099 
1100  params.set<VariableName>("secondary_variable") = displacements[i];
1101  params.set<MooseEnum>("component") = i;
1102 
1103  if (is_normal_constraint && _model != ContactModel::COULOMB &&
1105  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedgap_object_" + name();
1106  else if (is_normal_constraint && _model == ContactModel::COULOMB &&
1108  params.set<UserObjectName>("weighted_gap_uo") = "lm_weightedvelocities_object_" + name();
1110  params.set<UserObjectName>("weighted_velocities_uo") =
1111  "lm_weightedvelocities_object_" + name();
1112  else if (is_normal_constraint && _model != ContactModel::COULOMB &&
1114  params.set<UserObjectName>("weighted_gap_uo") = "penalty_weightedgap_object_" + name();
1115  else if (is_normal_constraint && _model == ContactModel::COULOMB &&
1117  params.set<UserObjectName>("weighted_gap_uo") = "penalty_friction_object_" + name();
1119  params.set<UserObjectName>("weighted_velocities_uo") =
1120  "penalty_friction_object_" + name();
1121 
1122  _problem->addConstraint(constraint_type, constraint_name, params);
1123  }
1124  _problem->haveADObjects(true);
1125  };
1126 
1127  // Add mortar mechanical contact constraint objects for primal variables
1128  addMechanicalContactConstraints(normal_lagrange_multiplier_name,
1129  action_name + "_normal_constraint_",
1130  "NormalMortarMechanicalContact",
1131  /* is_additional_frictional_constraint = */ false,
1132  /* is_normal_constraint = */ true);
1133 
1135  {
1136  addMechanicalContactConstraints(tangential_lagrange_multiplier_name,
1137  action_name + "_tangential_constraint_",
1138  "TangentialMortarMechanicalContact",
1139  /* is_additional_frictional_constraint = */ false,
1140  /* is_normal_constraint = */ false);
1141  if (ndisp > 2)
1142  addMechanicalContactConstraints(tangential_lagrange_multiplier_3d_name,
1143  action_name + "_tangential_constraint_3d_",
1144  "TangentialMortarMechanicalContact",
1145  /* is_additional_frictional_constraint = */ true,
1146  /* is_normal_constraint = */ false);
1147  }
1148  }
1149 }
std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for mechanical contact.
Definition: ContactAction.h:94
bool isUltimateMaster() const
static std::string variableType(const FEType &fe_type, const bool is_fv=false, const bool is_array=false)
void applySpecificParameters(const InputParameters &common, const std::vector< std::string > &include, bool allow_private=false)
MooseApp & _app
T & set(const std::string &name, bool quiet_mode=false)
InputParameters getValidParams(const std::string &name) const
const ContactFormulation _formulation
Contact formulation.
virtual const std::string & name() const
std::string shortName(const std::string &name)
bool isParamValid(const std::string &name) const
Factory & _factory
const bool _generate_mortar_mesh
Whether to generate the mortar mesh (useful in a restart simulation e.g.).
const std::string & _current_task
const MooseMesh * masterMesh() const
void paramError(const std::string &param, Args... args) const
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
static FEType feType(const InputParameters &params)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void mooseError(Args &&... args) const
std::shared_ptr< FEProblemBase > & _problem
const InputParameters & parameters() const
bool _use_dual
Whether to use the dual Mortar approach.
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 1152 of file ContactAction.C.

Referenced by act().

1153 {
1154  if (_current_task == "post_mesh_prepared" && _automatic_pairing_boundaries.size() > 0)
1155  {
1156  if (getParam<MooseEnum>("automatic_pairing_method").getEnum<ProximityMethod>() ==
1159  else if (getParam<MooseEnum>("automatic_pairing_method").getEnum<ProximityMethod>() ==
1162  }
1163 
1164  if (_current_task != "add_constraint")
1165  return;
1166 
1167  std::string action_name = MooseUtils::shortName(name());
1168  std::vector<VariableName> displacements = getParam<std::vector<VariableName>>("displacements");
1169  const unsigned int ndisp = displacements.size();
1170 
1171  std::string constraint_type;
1172 
1174  constraint_type = "RANFSNormalMechanicalContact";
1175  else
1176  constraint_type = "MechanicalContactConstraint";
1177 
1178  InputParameters params = _factory.getValidParams(constraint_type);
1179 
1180  params.applyParameters(parameters(),
1181  {"displacements",
1182  "secondary_gap_offset",
1183  "mapped_primary_gap_offset",
1184  "primary",
1185  "secondary"});
1186 
1187  const auto order = _problem->systemBaseNonlinear(/*nl_sys_num=*/0)
1188  .system()
1189  .variable_type(displacements[0])
1190  .order.get_order();
1191 
1192  params.set<std::vector<VariableName>>("displacements") = displacements;
1193  params.set<bool>("use_displaced_mesh") = true;
1194  params.set<MooseEnum>("order") = Utility::enum_to_string<Order>(OrderWrapper{order});
1195 
1196  for (const auto & contact_pair : _boundary_pairs)
1197  {
1199  {
1200  params.set<std::vector<VariableName>>("nodal_area") = {"nodal_area"};
1201  params.set<BoundaryName>("boundary") = contact_pair.first;
1202  if (isParamValid("secondary_gap_offset"))
1203  params.set<std::vector<VariableName>>("secondary_gap_offset") = {
1204  getParam<VariableName>("secondary_gap_offset")};
1205  if (isParamValid("mapped_primary_gap_offset"))
1206  params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
1207  getParam<VariableName>("mapped_primary_gap_offset")};
1208  }
1209 
1210  for (unsigned int i = 0; i < ndisp; ++i)
1211  {
1212  std::string name = action_name + "_constraint_" + Moose::stringify(contact_pair, "_") + "_" +
1213  Moose::stringify(i);
1214 
1216  params.set<MooseEnum>("component") = i;
1217  else
1218  params.set<unsigned int>("component") = i;
1219 
1220  params.set<BoundaryName>("primary") = contact_pair.first;
1221  params.set<BoundaryName>("secondary") = contact_pair.second;
1222  params.set<NonlinearVariableName>("variable") = displacements[i];
1223  params.set<std::vector<VariableName>>("primary_variable") = {displacements[i]};
1225  {"extra_vector_tags", "absolute_value_vector_tags"});
1226  _problem->addConstraint(constraint_type, name, params);
1227  }
1228  }
1229 }
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)
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...
virtual const std::string & name() const
std::string shortName(const std::string &name)
bool isParamValid(const std::string &name) const
Factory & _factory
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
const InputParameters & parameters() 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 681 of file ContactAction.C.

682 {
685  {
686  auto params = MortarConstraintBase::validParams();
687  params.set<bool>("use_displaced_mesh") = true;
688  std::string action_name = MooseUtils::shortName(name());
689  const std::string primary_subdomain_name = action_name + "_primary_subdomain";
690  const std::string secondary_subdomain_name = action_name + "_secondary_subdomain";
691  params.set<BoundaryName>("primary_boundary") = _boundary_pairs[0].first;
692  params.set<BoundaryName>("secondary_boundary") = _boundary_pairs[0].second;
693  params.set<SubdomainName>("primary_subdomain") = primary_subdomain_name;
694  params.set<SubdomainName>("secondary_subdomain") = secondary_subdomain_name;
695  params.set<bool>("use_petrov_galerkin") = getParam<bool>("use_petrov_galerkin");
696  addRelationshipManagers(input_rm_type, params);
697  }
698 }
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.
virtual const std::string & name() const
std::string shortName(const std::string &name)
static InputParameters validParams()

◆ commonParameters()

InputParameters ContactAction::commonParameters ( )
static

Define parameters used by multiple contact objects.

Returns
InputParameters object populated with common parameters

Definition at line 1568 of file ContactAction.C.

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

1569 {
1571 
1572  params.addParam<MooseEnum>("normal_smoothing_method",
1574  "Method to use to smooth normals");
1575  params.addParam<Real>(
1576  "normal_smoothing_distance",
1577  "Distance from edge in parametric coordinates over which to smooth contact normal");
1578 
1579  params.addParam<MooseEnum>(
1580  "formulation", ContactAction::getFormulationEnum(), "The contact formulation");
1581 
1582  params.addParam<MooseEnum>("model", ContactAction::getModelEnum(), "The contact model to use");
1583 
1584  return params;
1585 }
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 1379 of file ContactAction.C.

Referenced by addNodeFaceContact().

1380 {
1381  mooseInfo("The contact action is reading the list of boundaries and automatically pairs them "
1382  "if their centroids fall within a specified distance of each other.");
1383 
1384  if (!_mesh)
1385  mooseError("Failed to obtain mesh for automatically generating contact pairs.");
1386 
1387  if (!_mesh->getMesh().is_serial())
1388  paramError(
1389  "automatic_pairing_boundaries",
1390  "The generation of automatic contact pairs in the contact action requires a serial mesh.");
1391 
1392  // Compute centers of gravity for each sideset
1393  std::vector<std::pair<BoundaryName, Point>> automatic_pairing_boundaries_cog;
1394  const auto & sideset_ids = _mesh->meshSidesetIds();
1395 
1396  const auto & bnd_to_elem_map = _mesh->getBoundariesToActiveSemiLocalElemIds();
1397 
1398  for (const auto & sideset_name : _automatic_pairing_boundaries)
1399  {
1400  // If the sideset provided in the input file isn't in the mesh, error out.
1401  const auto find_set = sideset_ids.find(_mesh->getBoundaryID(sideset_name));
1402  if (find_set == sideset_ids.end())
1403  paramError("automatic_pairing_boundaries",
1404  sideset_name,
1405  " is not defined as a sideset in the mesh.");
1406 
1407  auto dofs_set = bnd_to_elem_map.find(_mesh->getBoundaryID(sideset_name));
1408 
1409  // Initialize data for sideset
1410  Point center_of_gravity(0, 0, 0);
1411  Real accumulated_sideset_area(0);
1412 
1413  // Pointer to lower-dimensional element on the sideset
1414  std::unique_ptr<const Elem> side_ptr;
1415  const std::unordered_set<dof_id_type> & bnd_elems = dofs_set->second;
1416 
1417  for (auto elem_id : bnd_elems)
1418  {
1419  const Elem * elem = _mesh->elemPtr(elem_id);
1420  unsigned int side = _mesh->sideWithBoundaryID(elem, _mesh->getBoundaryID(sideset_name));
1421 
1422  // update side_ptr
1423  elem->side_ptr(side_ptr, side);
1424 
1425  // area of the (linearized) side
1426  const auto side_area = side_ptr->volume();
1427 
1428  // position of the side
1429  const auto side_position = side_ptr->true_centroid();
1430 
1431  center_of_gravity += side_position * side_area;
1432  accumulated_sideset_area += side_area;
1433  }
1434 
1435  // Average each element's center of gravity (centroid) with its area
1436  center_of_gravity /= accumulated_sideset_area;
1437 
1438  // Add sideset-cog pair to vector
1439  automatic_pairing_boundaries_cog.emplace_back(sideset_name, center_of_gravity);
1440  }
1441 
1442  // Vectors of distances for each pair
1443  std::vector<std::pair<std::pair<BoundaryName, BoundaryName>, Real>> pairs_distances;
1444 
1445  // Assign distances to identify nearby pairs.
1446  for (std::size_t i = 0; i < automatic_pairing_boundaries_cog.size() - 1; i++)
1447  for (std::size_t j = i + 1; j < automatic_pairing_boundaries_cog.size(); j++)
1448  {
1449  const Point & distance_vector =
1450  automatic_pairing_boundaries_cog[i].second - automatic_pairing_boundaries_cog[j].second;
1451 
1452  if (automatic_pairing_boundaries_cog[i].first != automatic_pairing_boundaries_cog[j].first)
1453  {
1454  const Real distance = distance_vector.norm();
1455  const std::pair pair = std::make_pair(automatic_pairing_boundaries_cog[i].first,
1456  automatic_pairing_boundaries_cog[j].first);
1457  pairs_distances.emplace_back(std::make_pair(pair, distance));
1458  }
1459  }
1460 
1461  const auto automatic_pairing_distance = getParam<Real>("automatic_pairing_distance");
1462 
1463  // Loop over all pairs
1464  std::vector<std::pair<std::pair<BoundaryName, BoundaryName>, Real>> lean_pairs_distances;
1465  for (const auto & pair_distance : pairs_distances)
1466  if (pair_distance.second <= automatic_pairing_distance)
1467  {
1468  lean_pairs_distances.emplace_back(pair_distance);
1469  mooseInfoRepeated("Generating contact pair primary--secondary ",
1470  pair_distance.first.first,
1471  "--",
1472  pair_distance.first.second,
1473  ", with a relative distance of ",
1474  pair_distance.second);
1475  }
1476 
1477  // Create the boundary pairs (possibly with repeated pairs depending on user input)
1478  for (const auto & lean_pairs_distance : lean_pairs_distances)
1479  {
1480  // Make sure secondary surface's boundary ID is less than primary surface's boundary ID.
1481  // This is done to ensure some consistency in the boundary matching, which helps in defining
1482  // auxiliary kernels in the input file.
1483  if (_mesh->getBoundaryID(lean_pairs_distance.first.first) >
1484  _mesh->getBoundaryID(lean_pairs_distance.first.second))
1485  _boundary_pairs.push_back(
1486  {lean_pairs_distance.first.first, lean_pairs_distance.first.second});
1487  else
1488  _boundary_pairs.push_back(
1489  {lean_pairs_distance.first.second, lean_pairs_distance.first.first});
1490  }
1491 
1492  // Let's remove possibly repeated pairs
1494 }
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 mooseInfo(Args &&... args) const
void removeRepeatedPairs()
Remove repeated contact pairs from _boundary_pairs.
void mooseInfoRepeated(Args &&... args)
Real distance(const Point &p)
void paramError(const std::string &param, Args... args) const
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 1241 of file ContactAction.C.

Referenced by addNodeFaceContact().

1242 {
1243  mooseInfo("The contact action is reading the list of boundaries and automatically pairs them "
1244  "if the distance between nodes is less than a specified distance.");
1245 
1246  if (!_mesh)
1247  mooseError("Failed to obtain mesh for automatically generating contact pairs.");
1248 
1249  if (!_mesh->getMesh().is_serial())
1250  paramError(
1251  "automatic_pairing_boundaries",
1252  "The generation of automatic contact pairs in the contact action requires a serial mesh.");
1253 
1254  // Create automatic_pairing_boundaries_id
1255  std::vector<BoundaryID> _automatic_pairing_boundaries_id;
1256  for (const auto & sideset_name : _automatic_pairing_boundaries)
1257  _automatic_pairing_boundaries_id.emplace_back(_mesh->getBoundaryID(sideset_name));
1258 
1259  // Vector of pairs node-boundary id
1260  std::vector<NodeBoundaryIDInfo> node_boundary_id_vector;
1261 
1262  // Data structures to hold the boundary nodes
1263  const ConstBndNodeRange & bnd_nodes = *_mesh->getBoundaryNodeRange();
1264 
1265  for (const auto & bnode : bnd_nodes)
1266  {
1267  const BoundaryID boundary_id = bnode->_bnd_id;
1268  const Node * node_ptr = bnode->_node;
1269 
1270  // Make sure node is on a boundary chosen for contact mechanics
1271  auto it = std::find(_automatic_pairing_boundaries_id.begin(),
1272  _automatic_pairing_boundaries_id.end(),
1273  boundary_id);
1274 
1275  if (it != _automatic_pairing_boundaries_id.end())
1276  node_boundary_id_vector.emplace_back(node_ptr, boundary_id);
1277  }
1278 
1279  // sort by increasing boundary id
1280  std::sort(node_boundary_id_vector.begin(),
1281  node_boundary_id_vector.end(),
1282  [](const NodeBoundaryIDInfo & first_pair, const NodeBoundaryIDInfo & second_pair)
1283  { return first_pair.second < second_pair.second; });
1284 
1285  // build kd-tree
1286  using KDTreeType = nanoflann::KDTreeSingleIndexAdaptor<
1287  nanoflann::L2_Simple_Adaptor<Real, PointListAdaptor<NodeBoundaryIDInfo>, Real, std::size_t>,
1289  LIBMESH_DIM,
1290  std::size_t>;
1291 
1292  // This parameter can be tuned. Others use '10'
1293  const unsigned int max_leaf_size = 20;
1294 
1295  // Build point list adaptor with all nodes-sidesets pairs for possible mechanical contact
1296  auto point_list = PointListAdaptor<NodeBoundaryIDInfo>(node_boundary_id_vector.begin(),
1297  node_boundary_id_vector.end());
1298  auto kd_tree = std::make_unique<KDTreeType>(
1299  LIBMESH_DIM, point_list, nanoflann::KDTreeSingleIndexAdaptorParams(max_leaf_size));
1300 
1301  if (!kd_tree)
1302  mooseError("Internal error. KDTree was not properly initialized in the contact action.");
1303 
1304  kd_tree->buildIndex();
1305 
1306  // data structures for kd-tree search
1307  nanoflann::SearchParameters search_params;
1308  std::vector<nanoflann::ResultItem<std::size_t, Real>> ret_matches;
1309 
1310  const auto radius_for_search = getParam<Real>("automatic_pairing_distance");
1311 
1312  // For all nodes
1313  for (const auto & pair : node_boundary_id_vector)
1314  {
1315  // clear result buffer
1316  ret_matches.clear();
1317 
1318  // position where we expect a periodic partner for the current node and boundary
1319  const Point search_point = *pair.first;
1320 
1321  // search at the expected point
1322  kd_tree->radiusSearch(
1323  &(search_point)(0), radius_for_search * radius_for_search, ret_matches, search_params);
1324 
1325  for (auto & match_pair : ret_matches)
1326  {
1327  const auto & match = node_boundary_id_vector[match_pair.first];
1328 
1329  //
1330  // If the proximity node identified belongs to a boundary in the input, add boundary pair
1331  //
1332 
1333  // Make sure node is on a boundary chosen for contact mechanics
1334  auto it = std::find(_automatic_pairing_boundaries_id.begin(),
1335  _automatic_pairing_boundaries_id.end(),
1336  match.second);
1337 
1338  // If nodes are on the same boundary, pass.
1339  if (match.second == pair.second)
1340  continue;
1341 
1342  // At this point we will likely create many repeated pairs because many nodal pairs may
1343  // fulfill the distance condition imposed by the automatic_pairing_distance user input
1344  // parameter.
1345  if (it != _automatic_pairing_boundaries_id.end())
1346  {
1347  const auto index_one = cast_int<int>(it - _automatic_pairing_boundaries_id.begin());
1348  auto it_other = std::find(_automatic_pairing_boundaries_id.begin(),
1349  _automatic_pairing_boundaries_id.end(),
1350  pair.second);
1351 
1352  mooseAssert(it_other != _automatic_pairing_boundaries_id.end(),
1353  "Error in contact action. Unable to find boundary ID for node proximity "
1354  "automatic pairing.");
1355 
1356  const auto index_two = cast_int<int>(it_other - _automatic_pairing_boundaries_id.begin());
1357 
1358  if (pair.second > match.second)
1359  _boundary_pairs.push_back(
1361  else
1362  _boundary_pairs.push_back(
1364  }
1365  }
1366  }
1367 
1368  // Let's remove likely repeated pairs
1370 
1371  mooseInfo(
1372  "The following boundary pairs were created by the contact action using nodal proximity: ");
1373  for (const auto & [primary, secondary] : _boundary_pairs)
1375  "Primary boundary ID: ", primary, " and secondary boundary ID: ", secondary, ".");
1376 }
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 mooseInfo(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
void paramError(const std::string &param, Args... args) const
std::shared_ptr< MooseMesh > & _mesh
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void mooseError(Args &&... args) const
StoredRange< MooseMesh::const_bnd_node_iterator, const BndNode *> ConstBndNodeRange
SearchParams SearchParameters

◆ getFormulationEnum()

MooseEnum ContactAction::getFormulationEnum ( )
static

Get contact formulation.

Returns
enum

Definition at line 1509 of file ContactAction.C.

Referenced by commonParameters().

1510 {
1511  auto formulations = MooseEnum(
1512  "ranfs kinematic penalty augmented_lagrange tangential_penalty mortar mortar_penalty",
1513  "kinematic");
1514 
1515  formulations.addDocumentation(
1516  "ranfs",
1517  "Reduced Active Nonlinear Function Set scheme for node-on-face contact. Provides exact "
1518  "enforcement without Lagrange multipliers or penalty terms.");
1519  formulations.addDocumentation(
1520  "kinematic",
1521  "Kinematic contact constraint enforcement transfers the internal forces at secondary nodes "
1522  "to the corresponding primary face for node-on-face contact. Provides exact "
1523  "enforcement without Lagrange multipliers or penalty terms.");
1524  formulations.addDocumentation(
1525  "penalty",
1526  "Node-on-face penalty based contact constraint enforcement. Interpenetration is penalized. "
1527  "Enforcement depends on the penalty magnitude. High penalties can introduce ill conditioning "
1528  "of the system.");
1529  formulations.addDocumentation("augmented_lagrange",
1530  "Node-on-face augmented Lagrange penalty based contact constraint "
1531  "enforcement. Interpenetration is enforced up to a user specified "
1532  "tolerance, ill-conditioning is generally avoided. Requires an "
1533  "Augmented Lagrange Problem class to be used in the simulation.");
1534  formulations.addDocumentation(
1535  "tangential_penalty",
1536  "Node-on-face penalty based frictional contact constraint enforcement. Interpenetration and "
1537  "slip distance for sticking nodes are penalized. Enforcement depends on the penalty "
1538  "magnitudes. High penalties can introduce ill conditioning of the system.");
1539  formulations.addDocumentation(
1540  "mortar",
1541  "Mortar based contact constraint enforcement using Lagrange multipliers. Provides exact "
1542  "enforcement and a variationally consistent formulation. Lagrange multipliers introduce a "
1543  "saddle point character in the system matrix which can have a negative impact on scalability "
1544  "with iterative solvers");
1545  formulations.addDocumentation(
1546  "mortar_penalty",
1547  "Mortar and penalty based contact constraint enforcement. When using an Augmented Lagrange "
1548  "Problem class this provides normal (and tangential) contact constratint enforced up to a "
1549  "user specified tolerances. Without AL the enforcement depends on the penalty magnitudes. "
1550  "High penalties can introduce ill conditioning of the system.");
1551 
1552  return formulations;
1553 }

◆ getModelEnum()

MooseEnum ContactAction::getModelEnum ( )
static

Get contact model.

Returns
enum

Definition at line 1497 of file ContactAction.C.

Referenced by commonParameters(), and validParams().

1498 {
1499  return MooseEnum("frictionless glued coulomb", "frictionless");
1500 }

◆ getProximityMethod()

MooseEnum ContactAction::getProximityMethod ( )
static

Get proximity method for automatic pairing.

Returns
enum

Definition at line 1503 of file ContactAction.C.

Referenced by validParams().

1504 {
1505  return MooseEnum("node centroid");
1506 }

◆ getSmoothingEnum()

MooseEnum ContactAction::getSmoothingEnum ( )
static

Get smoothing type.

Returns
enum

Definition at line 1562 of file ContactAction.C.

Referenced by commonParameters().

1563 {
1564  return MooseEnum("edge_based nodal_normal_based", "");
1565 }

◆ getSystemEnum()

MooseEnum ContactAction::getSystemEnum ( )
static

Get contact system.

Returns
enum

Definition at line 1556 of file ContactAction.C.

1557 {
1558  return MooseEnum("Constraint", "Constraint");
1559 }

◆ removeRepeatedPairs()

void ContactAction::removeRepeatedPairs ( )
private

Remove repeated contact pairs from _boundary_pairs.

Definition at line 408 of file ContactAction.C.

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

409 {
410  if (_boundary_pairs.size() == 0 && _automatic_pairing_boundaries.size() == 0)
411  paramError(
412  "primary",
413  "Number of contact pairs in the contact action is zero. Please revise your input file.");
414 
415  // Remove repeated interactions
416  std::vector<std::pair<BoundaryName, BoundaryName>> lean_boundary_pairs;
417 
418  for (const auto & [primary, secondary] : _boundary_pairs)
419  {
420  // Structured bindings are not capturable (primary_copy, secondary_copy)
421  auto it = std::find_if(lean_boundary_pairs.begin(),
422  lean_boundary_pairs.end(),
423  [&, primary_copy = primary, secondary_copy = secondary](
424  const std::pair<BoundaryName, BoundaryName> & lean_pair)
425  {
426  const bool match_one = lean_pair.second == secondary_copy &&
427  lean_pair.first == primary_copy;
428  const bool match_two = lean_pair.second == primary_copy &&
429  lean_pair.first == secondary_copy;
430  const bool exist = match_one || match_two;
431  return exist;
432  });
433 
434  if (it == lean_boundary_pairs.end())
435  lean_boundary_pairs.emplace_back(primary, secondary);
436  else
437  mooseInfo("Contact pair ",
438  primary,
439  "--",
440  secondary,
441  " has been removed from the contact interaction list due to "
442  "duplicates in the input file.");
443  }
444 
445  _boundary_pairs = lean_boundary_pairs;
446 }
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 mooseInfo(Args &&... args) const
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  return params;
277 }
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().

◆ _boundary_pairs

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

Primary/Secondary boundary name pairs for mechanical contact.

Definition at line 94 of file ContactAction.h.

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

◆ _formulation

const ContactFormulation ContactAction::_formulation
protected

Contact formulation.

Definition at line 103 of file ContactAction.h.

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

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