www.mooseframework.org
AugmentedLagrangianContactProblem.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
11 
12 // MOOSE includes
13 #include "AuxiliarySystem.h"
14 #include "DisplacedProblem.h"
15 #include "MooseApp.h"
16 #include "MooseMesh.h"
17 #include "MooseVariable.h"
18 #include "NearestNodeLocator.h"
19 #include "NonlinearSystem.h"
20 #include "PenetrationLocator.h"
21 
22 #include "SystemBase.h"
23 #include "Assembly.h"
24 #include "Executioner.h"
25 #include "AddVariableAction.h"
26 #include "ConstraintWarehouse.h"
27 #include "MortarUserObject.h"
29 
32 
35 {
36  auto params = emptyInputParameters();
37  params.addParam<int>("maximum_lagrangian_update_iterations",
38  100,
39  "Maximum number of update Lagrangian Multiplier iterations per step");
40  return params;
41 }
42 
44  const InputParameters & params)
45  : _maximum_number_lagrangian_iterations(params.get<int>("maximum_lagrangian_update_iterations"))
46 {
47 }
48 
49 template <class T>
52 {
55  params.addClassDescription("Manages nested solution for augmented Lagrange contact");
56  return params;
57 }
58 
59 template <class T>
61  const InputParameters & params)
63 {
64 }
65 
66 template <class T>
67 void
69 {
70  _lagrangian_iteration_number = 0;
71  T::timestepSetup();
72 }
73 
74 template <class T>
77  const PetscInt it,
78  const Real xnorm,
79  const Real snorm,
80  const Real fnorm,
81  const Real rtol,
82  const Real divtol,
83  const Real stol,
84  const Real abstol,
85  const PetscInt nfuncs,
86  const PetscInt /*max_funcs*/,
87  const Real ref_resid,
88  const Real /*div_threshold*/)
89 {
90  Real my_max_funcs = std::numeric_limits<int>::max();
91  Real my_div_threshold = std::numeric_limits<Real>::max();
92 
93  MooseNonlinearConvergenceReason reason = T::checkNonlinearConvergence(msg,
94  it,
95  xnorm,
96  snorm,
97  fnorm,
98  rtol,
99  divtol,
100  stol,
101  abstol,
102  nfuncs,
103  my_max_funcs,
104  ref_resid,
105  my_div_threshold);
106 
107  _console << "Augmented Lagrangian contact iteration " << _lagrangian_iteration_number
108  << std::endl;
109 
110  bool repeat_augmented_lagrange_step = false;
111 
112  if (reason == MooseNonlinearConvergenceReason::CONVERGED_FNORM_ABS ||
113  reason == MooseNonlinearConvergenceReason::CONVERGED_FNORM_RELATIVE ||
114  reason == MooseNonlinearConvergenceReason::CONVERGED_SNORM_RELATIVE)
115  {
116  if (_lagrangian_iteration_number < _maximum_number_lagrangian_iterations)
117  {
118  auto & nonlinear_sys = currentNonlinearSystem();
119  nonlinear_sys.update();
120 
121  // Get the penetration locator from the displaced mesh if it exist, otherwise get
122  // it from the undisplaced mesh.
123  const auto displaced_problem = getDisplacedProblem();
124  const auto & penetration_locators =
125  (displaced_problem ? displaced_problem->geomSearchData() : geomSearchData())
126  ._penetration_locators;
127 
128  // loop over contact pairs (penetration locators)
129  const ConstraintWarehouse & constraints = nonlinear_sys.getConstraintWarehouse();
130  std::list<std::shared_ptr<MechanicalContactConstraint>> mccs;
131  for (const auto & pair : penetration_locators)
132  {
133  const auto & boundaries = pair.first;
134 
135  if (!constraints.hasActiveNodeFaceConstraints(boundaries.second, bool(displaced_problem)))
136  continue;
137  const auto & ncs =
138  constraints.getActiveNodeFaceConstraints(boundaries.second, bool(displaced_problem));
139 
140  mccs.emplace_back(nullptr);
141  for (const auto & nc : ncs)
142  if (const auto mcc = std::dynamic_pointer_cast<MechanicalContactConstraint>(nc); !mcc)
143  mooseError("AugmentedLagrangianContactProblem: dynamic cast of "
144  "MechanicalContactConstraint object failed.");
145  else
146  {
147  // Return if this constraint does not correspond to the primary-secondary pair
148  // prepared by the outer loops.
149  // This continue statement is required when, e.g. one secondary surface constrains
150  // more than one primary surface.
151  if (mcc->secondaryBoundary() != boundaries.second ||
152  mcc->primaryBoundary() != boundaries.first)
153  continue;
154 
155  // save one constraint pointer for each contact pair
156  if (!mccs.back())
157  mccs.back() = mcc;
158 
159  // check if any of the constraints is not yet converged
160  if (repeat_augmented_lagrange_step || !mcc->AugmentedLagrangianContactConverged())
161  {
162  repeat_augmented_lagrange_step = true;
163  break;
164  }
165  }
166  }
167 
168  // next loop over penalty mortar user objects
169  const auto & pmuos = this->_app.template getInterfaceObjects<AugmentedLagrangeInterface>();
170  for (auto * pmuo : pmuos)
171  {
172  // check if any of the constraints is not yet converged
173  if (!repeat_augmented_lagrange_step && !pmuo->isAugmentedLagrangianConverged())
174  repeat_augmented_lagrange_step = true;
175  }
176 
177  // Communicate the repeat_augmented_lagrange_step in parallel.
178  // If one proc needs to do another loop, all do.
179  this->_communicator.max(repeat_augmented_lagrange_step);
180 
181  // repeat update step if necessary
182  if (repeat_augmented_lagrange_step)
183  {
184  _lagrangian_iteration_number++;
185 
186  // Each contact pair will have constraints for all displacements, but those share the
187  // Lagrange multipliers, which are stored on the penetration locator. We call update
188  // only for the first constraint for each contact pair.
189  for (const auto & mcc : mccs)
190  mcc->updateAugmentedLagrangianMultiplier(/* beginning_of_step = */ false);
191 
192  // Update all penalty mortar user objects
193  for (const auto & pmuo : pmuos)
194  pmuo->updateAugmentedLagrangianMultipliers();
195 
196  // call AM setup again (e.g. to update active sets)
197  for (const auto & pmuo : pmuos)
198  pmuo->augmentedLagrangianSetup();
199 
200  // force it to keep iterating
201  reason = MooseNonlinearConvergenceReason::ITERATING;
202  _console << "Augmented Lagrangian Multiplier needs updating." << std::endl;
203  }
204  else
205  _console << "Augmented Lagrangian contact constraint enforcement is satisfied."
206  << std::endl;
207  }
208  else
209  {
210  // maxed out
211  _console << "Maximum Augmented Lagrangian contact iterations have been reached." << std::endl;
212  reason = MooseNonlinearConvergenceReason::DIVERGED_FUNCTION_COUNT;
213  }
214  }
215 
216  return reason;
217 }
218 
Class to manage nested solution for augmented Lagrange contact.
void mooseError(Args &&... args)
virtual MooseNonlinearConvergenceReason checkNonlinearConvergence(std::string &msg, const PetscInt it, const Real xnorm, const Real snorm, const Real fnorm, const Real rtol, const Real divtol, const Real stol, const Real abstol, const PetscInt nfuncs, const PetscInt max_funcs, const Real ref_resid, const Real div_threshold) override
const std::vector< std::shared_ptr< NodeFaceConstraint > > & getActiveNodeFaceConstraints(BoundaryID boundary_id, bool displaced) const
AugmentedLagrangianContactProblemTempl(const InputParameters &params)
InputParameters emptyInputParameters()
AugmentedLagrangianContactProblemInterface(const InputParameters &params)
bool hasActiveNodeFaceConstraints(BoundaryID boundary_id, bool displaced) const
InputParameters validParams()
registerMooseObject("ContactApp", AugmentedLagrangianContactProblem)
MooseNonlinearConvergenceReason
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void addClassDescription(const std::string &doc_string)
void ErrorVector unsigned int
const Elem & get(const ElemType type_in)