https://mooseframework.inl.gov
PenaltySimpleCohesiveZoneModel.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
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 #include "MooseVariableFE.h"
12 #include "SystemBase.h"
13 #include "MortarUtils.h"
14 #include "MooseUtils.h"
15 #include "MathUtils.h"
16 
17 #include "MortarContactUtils.h"
19 
20 #include "ADReal.h"
21 
22 #include "CohesiveZoneModelTools.h"
23 
24 #include <Eigen/Core>
25 
27 
30 {
33 
34  params.addClassDescription(
35  "Computes the mortar frictional contact force via a penalty approach.");
36  params.addParam<Real>("penalty_friction",
37  "The penalty factor for frictional interaction. If not provide, the normal "
38  "penalty factor is also used for the frictional problem.");
39  params.addRequiredParam<Real>("friction_coefficient",
40  "The friction coefficient ruling Coulomb friction equations.");
41 
42  return params;
43 }
44 
46  /*
47  * We are using virtual inheritance to avoid the "Diamond inheritance" problem. This means that
48  * that we have to construct WeightedGapUserObject explicitly as it will _not_ be constructed in
49  * the intermediate base classes PenaltyWeightedGapUserObject and WeightedVelocitiesUserObject.
50  * Virtual inheritance ensures that only one instance of WeightedGapUserObject is included in this
51  * class. The inheritance diagram is as follows:
52  *
53  * WeightedGapUserObject <----- PenaltyWeightedGapUserObject
54  * ^ ^
55  * | |
56  * WeightedVelocitiesUserObject <----- PenaltySimpleCohesiveZoneModel
57  *
58  */
59  : WeightedGapUserObject(parameters),
60  PenaltyWeightedGapUserObject(parameters),
61  WeightedVelocitiesUserObject(parameters),
62  _penalty(getParam<Real>("penalty")),
63  _penalty_friction(isParamValid("penalty_friction") ? getParam<Real>("penalty_friction")
64  : getParam<Real>("penalty")),
65  _friction_coefficient(getParam<Real>("friction_coefficient")),
66  _epsilon_tolerance(1.0e-40)
67 
68 {
70  mooseError("PenaltySimpleCohesiveZoneModel constraints cannot be enforced with an augmented "
71  "Lagrange approach.");
72 }
73 
74 const VariableTestValue &
76 {
78 }
79 
80 void
82 {
83  // these functions do not call WeightedGapUserObject::timestepSetup to avoid double initialization
86 
87  // instead we call it explicitly here
89 
90  // save off accumulated slip from the last timestep
91  for (auto & map_pr : _dof_to_accumulated_slip)
92  {
93  auto & [accumulated_slip, old_accumulated_slip] = map_pr.second;
94  old_accumulated_slip = accumulated_slip;
95  }
96 
97  for (auto & dof_lp : _dof_to_local_penalty_friction)
98  dof_lp.second = _penalty_friction;
99 
100  // save off tangential traction from the last timestep
101  for (auto & map_pr : _dof_to_tangential_traction)
102  {
103  auto & [tangential_traction, old_tangential_traction] = map_pr.second;
104  old_tangential_traction = {MetaPhysicL::raw_value(tangential_traction(0)),
105  MetaPhysicL::raw_value(tangential_traction(1))};
106  tangential_traction = {0.0, 0.0};
107  }
108 
109  for (auto & [dof_object, delta_tangential_lm] : _dof_to_frictional_lagrange_multipliers)
110  delta_tangential_lm.setZero();
111 }
112 
113 void
115 {
116  // these functions do not call WeightedGapUserObject::initialize to avoid double initialization
119 
120  // instead we call it explicitly here
122 }
123 
124 void
126 {
127  // Normal contact pressure with penalty
129 
130  // Compute all rotations that were created as material properties in CZMComputeDisplacementJump
132 
133  // Reset frictional pressure
136 
137  for (const auto qp : make_range(_qrule_msm->n_points()))
138  {
141  }
142 
143  // zero vector
144  const static TwoVector zero{0.0, 0.0};
145 
146  // iterate over nodes
147  for (const auto i : make_range(_test->size()))
148  {
149  // current node
150  const Node * const node = _lower_secondary_elem->node_ptr(i);
151 
152  // Compute the weighted nodal deformation gradient and rotation tensors.
153  computeFandR(node);
154 
155  // The call below is a 'macro' call. Create a utility function or user object for it.
157 
158  // Build final traction vector
159  computeGlobalTraction(node);
160 
161  // Compute mechanical contact until end of method.
162  const auto penalty_friction = findValue(
163  _dof_to_local_penalty_friction, static_cast<const DofObject *>(node), _penalty_friction);
164 
165  // utilized quantities
166  const auto & normal_pressure = _dof_to_normal_pressure[node];
167 
168  // map the tangential traction and accumulated slip
169  auto & [tangential_traction, old_tangential_traction] = _dof_to_tangential_traction[node];
170  auto & [accumulated_slip, old_accumulated_slip] = _dof_to_accumulated_slip[node];
171 
172  Real normal_lm = -1;
174  normal_lm = libmesh_map_find(_dof_to_lagrange_multiplier, node);
175 
176  // Keep active set fixed from second Uzawa loop
177  if (normal_lm < -TOLERANCE && normal_pressure > TOLERANCE)
178  {
179  using namespace std;
180 
181  const auto & real_tangential_velocity =
182  libmesh_map_find(_dof_to_real_tangential_velocity, node);
183  const ADTwoVector slip_distance = {real_tangential_velocity[0] * _dt,
184  real_tangential_velocity[1] * _dt};
185 
186  // frictional lagrange multiplier (delta lambda^(k)_T)
187  const auto & tangential_lm =
189 
190  // tangential trial traction (Simo 3.12)
191  // Modified for implementation in MOOSE: Avoid pingponging on frictional sign (max. 0.4
192  // capacity)
193  ADTwoVector inner_iteration_penalty_friction = penalty_friction * slip_distance;
194 
195  const auto slip_metric = std::abs(MetaPhysicL::raw_value(slip_distance).cwiseAbs()(0)) +
196  std::abs(MetaPhysicL::raw_value(slip_distance).cwiseAbs()(1));
197 
198  if (slip_metric > _epsilon_tolerance &&
199  penalty_friction * slip_distance.norm() >
200  0.4 * _friction_coefficient * std::abs(normal_pressure))
201  {
202  inner_iteration_penalty_friction =
203  MetaPhysicL::raw_value(0.4 * _friction_coefficient * std::abs(normal_pressure) /
204  (penalty_friction * slip_distance.norm())) *
205  penalty_friction * slip_distance;
206  }
207 
208  ADTwoVector tangential_trial_traction =
209  old_tangential_traction + tangential_lm + inner_iteration_penalty_friction;
210 
211  // Nonlinearity below
212  ADReal tangential_trial_traction_norm = 0;
213  if (std::abs(tangential_trial_traction(0)) + std::abs(tangential_trial_traction(1)) >
215  tangential_trial_traction_norm = tangential_trial_traction.norm();
216 
217  ADReal phi_trial = tangential_trial_traction_norm - _friction_coefficient * normal_pressure;
218  tangential_traction = tangential_trial_traction;
219 
220  // Simo considers this a 'return mapping'; we are just capping friction to the Coulomb limit.
221  if (phi_trial > 0.0)
222  // Simo 3.13/3.14 (the penalty formulation has an error in the paper)
223  tangential_traction -=
224  phi_trial * tangential_trial_traction / tangential_trial_traction_norm;
225 
226  // track accumulated slip for output purposes
227  accumulated_slip = old_accumulated_slip + MetaPhysicL::raw_value(slip_distance).cwiseAbs();
228  }
229  else
230  {
231  // reset slip and clear traction
232  accumulated_slip.setZero();
233  tangential_traction.setZero();
234  }
235 
236  // Now that we have consistent nodal frictional values, create an interpolated frictional
237  // pressure variable.
238  const auto & test_i = (*_test)[i];
239  for (const auto qp : make_range(_qrule_msm->n_points()))
240  {
241  _frictional_contact_traction_one[qp] += test_i[qp] * tangential_traction(0);
242  _frictional_contact_traction_two[qp] += test_i[qp] * tangential_traction(1);
243  }
244  }
245 }
246 
247 void
249 {
252 }
253 
254 const ADVariableValue &
256 {
258 }
259 
260 const ADVariableValue &
262 {
264 }
registerMooseObject("ContactApp", PenaltySimpleCohesiveZoneModel)
std::unordered_map< const DofObject *, ADReal > _dof_to_normal_pressure
Map from degree of freedom to normal pressure for reporting.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
V findValue(const std::unordered_map< K, V > &map, const K &key, const V &default_value=0) const
Find a value in a map or return a default if the key doesn&#39;t exist.
virtual const ADVariableValue & contactTangentialPressureDirTwo() const override
std::unordered_map< const DofObject *, TwoVector > _dof_to_frictional_lagrange_multipliers
Map from degree of freedom to augmented lagrange multiplier.
AugmentedLagrangianContactProblemInterface *const _augmented_lagrange_problem
augmented Lagrange problem and iteration number
std::unordered_map< const DofObject *, std::array< ADReal, 2 > > _dof_to_real_tangential_velocity
A map from node to two interpolated, physical tangential velocities.
const Real & _dt
Current delta t... or timestep size.
PenaltySimpleCohesiveZoneModel(const InputParameters &parameters)
virtual void initialize() override
auto raw_value(const Eigen::Map< T > &in)
User object for computing weighted gaps and contact pressure for penalty based mortar constraints...
virtual const VariableTestValue & test() const override
Creates dof object to weighted tangential velocities map.
const Number zero
DualNumber< Real, DNDerivativeType, true > ADReal
const libMesh::QBase *const & _qrule_msm
void addRequiredParam(const std::string &name, const std::string &doc_string)
const Real _epsilon_tolerance
Tolerance to avoid NaN/Inf in automatic differentiation operations.
Elem const *const & _lower_secondary_elem
std::unordered_map< const DofObject *, std::pair< TwoVector, TwoVector > > _dof_to_accumulated_slip
Map from degree of freedom to current and old accumulated slip.
virtual void timestepSetup()
virtual void computeFandR(const Node *const)
const Real _penalty_friction
The penalty factor for the frictional constraints.
OutputTools< Real >::VariableTestValue VariableTestValue
const VariableTestValue * _test
A pointer to the test function associated with the weighted gap.
ADVariableValue _frictional_contact_traction_two
The second frictional contact pressure on the mortar segment quadrature points.
unsigned int n_points() const
std::unordered_map< const DofObject *, std::pair< ADTwoVector, TwoVector > > _dof_to_tangential_traction
Map from degree of freedom to current and old tangential traction.
virtual void computeBilinearMixedModeTraction(const Node *const)
Encapsulate the CZM constitutive behavior.
virtual void computeGlobalTraction(const Node *const)
Compute global traction for mortar application.
const Real _friction_coefficient
The friction coefficient.
Creates dof object to weighted gap map.
const MooseVariable *const _aux_lm_var
The auxiliary Lagrange multiplier variable (used together whith the Petrov-Galerkin approach) ...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
std::unordered_map< const DofObject *, Real > _dof_to_local_penalty_friction
Map from degree of freedom to local friction penalty value.
ADVariableValue _frictional_contact_traction_one
The first frictional contact pressure on the mortar segment quadrature points.
virtual const FieldVariablePhiValue & phiLower() const override
std::unordered_map< const DofObject *, Real > _dof_to_lagrange_multiplier
Map from degree of freedom to augmented lagrange multiplier.
IntRange< T > make_range(T beg, T end)
void resize(unsigned int size)
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
A two-component zero initialized vector used for tangential quantities.
Definition: TwoVector.h:19
User object that interface pressure resulting from a simple traction separation law.
const MooseVariable *const _disp_x_var
The x displacement variable.
virtual const ADVariableValue & contactTangentialPressureDirOne() const override