https://mooseframework.inl.gov
Loading...
Searching...
No Matches
CohesiveZoneModelBase.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
23
24#include <Eigen/Core>
25
28{
31 params.addRequiredCoupledVar("displacements",
32 "The string of displacements suitable for the problem statement");
34 "Base class for mortar-based cohesive zone model. To handle frictional cohesive interfaces, "
35 "it computes the mortar frictional contact forces using a penalty approach.");
36 params.addParam<Real>(
37 "penalty_friction",
38 "The penalty factor for frictional interaction. If not provided, the normal "
39 "penalty factor is also used for the frictional problem.");
40 params.addParam<Real>(
41 "friction_coefficient", 0.0, "The friction coefficient ruling Coulomb friction equations.");
42 // Suppress augmented Lagrange parameters. AL implementation for CZM remains to be done.
43 params.suppressParameter<Real>("max_penalty_multiplier");
44 params.suppressParameter<Real>("penalty_multiplier");
45 params.suppressParameter<Real>("penetration_tolerance");
46 params.setParameters("penalty", 0.0);
47 params.set<bool>("ghost_point_neighbors") = false;
48 return params;
49}
50
52 /*
53 * We are using virtual inheritance to avoid the "Diamond inheritance" problem. This means that
54 * we have to construct WeightedGapUserObject explicitly as it will _not_ be constructed in
55 * the intermediate base classes PenaltyWeightedGapUserObject and WeightedVelocitiesUserObject.
56 * Virtual inheritance ensures that only one instance of WeightedGapUserObject is included in this
57 * class. The inheritance diagram is as follows:
58 *
59 * WeightedGapUserObject <----- PenaltyWeightedGapUserObject
60 * ^ ^
61 * | |
62 * WeightedVelocitiesUserObject <----- CohesiveZoneModelBase
63 *
64 */
65 : WeightedGapUserObject(parameters),
68 _ndisp(coupledComponents("displacements")),
69 _penalty_friction(isParamValid("penalty_friction") ? getParam<Real>("penalty_friction")
70 : getParam<Real>("penalty")),
71 _friction_coefficient(getParam<Real>("friction_coefficient")),
72 _dof_to_accumulated_slip(
73 declareRestartableData<std::unordered_map<dof_id_type, std::pair<ADTwoVector, TwoVector>>>(
74 "dof_to_accumulated_slip",
75 std::unordered_map<dof_id_type, std::pair<ADTwoVector, TwoVector>>{})),
76 _dof_to_tangential_traction(
77 declareRestartableData<std::unordered_map<dof_id_type, std::pair<ADTwoVector, TwoVector>>>(
78 "dof_to_tangential_traction",
79 std::unordered_map<dof_id_type, std::pair<ADTwoVector, TwoVector>>{})),
80 _epsilon_tolerance(1.0e-40),
81 _dof_to_damage(declareRestartableData<std::unordered_map<dof_id_type, std::pair<ADReal, Real>>>(
82 "dof_do_damage", std::unordered_map<dof_id_type, std::pair<ADReal, Real>>{}))
83{
84 _czm_interpolated_traction.resize(_ndisp);
85
86 for (unsigned int i = 0; i < _ndisp; ++i)
87 {
88 _grad_disp.push_back(&adCoupledGradient("displacements", i));
89 _grad_disp_neighbor.push_back(&adCoupledNeighborGradient("displacements", i));
90 }
91
92 // Set non-intervening components to zero
93 for ([[maybe_unused]] const auto i : make_range(_ndisp, 3u))
94 {
95 _grad_disp.push_back(&_ad_grad_zero);
96 _grad_disp_neighbor.push_back(&_ad_grad_zero);
97 }
98
99 if (_augmented_lagrange_problem)
100 mooseError("CohesiveZoneModelBase constraints cannot be enforced with an augmented "
101 "Lagrange approach.");
102}
103
104const VariableTestValue &
109
110void
112{
114
115 // Compute F and R.
116 const auto F = (ADRankTwoTensor::Identity() +
118 (*_grad_disp[0])[_qp], (*_grad_disp[1])[_qp], (*_grad_disp[2])[_qp]));
119 const auto F_neighbor = (ADRankTwoTensor::Identity() +
122 (*_grad_disp_neighbor[2])[_qp]));
123
124 // TODO in follow-on PRs: Trim interior node variable derivatives
126 _F_neighbor_interpolation = F_neighbor * (_JxW_msm[_qp] * _coord[_qp]);
127}
128
129void
131{
133 // Get the _dof_to_weighted_gap map
134 const auto * const dof = cast_ptr<const DofObject *>(_lower_secondary_elem->node_ptr(_i));
135
137
138 // TODO: Probably better to interpolate the deformation gradients.
139 _dof_to_F[dof] += (*_test)[_i][_qp] * _F_interpolation;
141}
142
143void
145{
146 // First call does not have maps available
147 const bool return_boolean = _dof_to_F.find(node) == _dof_to_F.end();
148 if (return_boolean)
149 return;
150
151 const auto normalized_F = normalizeQuantity(_dof_to_F, node);
152 const auto normalized_F_neighbor = normalizeQuantity(_dof_to_F_neighbor, node);
153
154 // This 'averaging' assumption below can probably be improved upon.
155 _dof_to_interface_F[node] = 0.5 * (normalized_F + normalized_F_neighbor);
156
157 for (const auto i : make_range(Moose::dim))
158 for (const auto j : make_range(Moose::dim))
159 {
160 if (!std::isfinite(MetaPhysicL::raw_value(normalized_F(i, j))))
161 throw MooseException("The deformation gradient on the secondary surface is not finite in "
162 "CohesiveZoneModelBase. MOOSE needs to cut the time step size.");
163 if (!std::isfinite(MetaPhysicL::raw_value(normalized_F_neighbor(i, j))))
164 throw MooseException("The deformation gradient on the primary surface is not finite in "
165 "CohesiveZoneModelBase. MOOSE needs to cut the time step size.");
166 }
167
168 const auto dof_to_interface_F_node = libmesh_map_find(_dof_to_interface_F, node);
169
170 const ADFactorizedRankTwoTensor C = dof_to_interface_F_node.transpose() * dof_to_interface_F_node;
171 const auto Uinv = MathUtils::sqrt(C).inverse().get();
172 _dof_to_interface_R[node] = dof_to_interface_F_node * Uinv;
173
174 // Transform interface jump according to two rotation matrices
175 const auto global_interface_displacement = _dof_to_interface_displacement_jump[node];
177 (_dof_to_interface_R[node] * _dof_to_rotation_matrix[node]).transpose() *
178 global_interface_displacement;
179}
180
181void
183{
184 // these functions do not call WeightedGapUserObject::timestepSetup to avoid double initialization
187
188 // instead we call it explicitly here
190
191 // Clear step slip (values used in between AL iterations for penalty adaptivity)
192 for (auto & map_pr : _dof_to_step_slip)
193 {
194 auto & [step_slip, old_step_slip] = map_pr.second;
195 old_step_slip = {0.0, 0.0};
196 step_slip = {0.0, 0.0};
197 }
198
199 // save off accumulated slip from the last timestep
200 for (auto & map_pr : _dof_to_accumulated_slip)
201 {
202 auto & [accumulated_slip, old_accumulated_slip] = map_pr.second;
203 old_accumulated_slip = MetaPhysicL::raw_value(accumulated_slip);
204 }
205
206 for (auto & dof_lp : _dof_to_local_penalty_friction)
207 dof_lp.second = _penalty_friction;
208
209 // save off tangential traction from the last timestep
210 for (auto & map_pr : _dof_to_tangential_traction)
211 {
212 auto & [tangential_traction, old_tangential_traction] = map_pr.second;
213 old_tangential_traction = {MetaPhysicL::raw_value(tangential_traction(0)),
214 MetaPhysicL::raw_value(tangential_traction(1))};
215 tangential_traction = {0.0, 0.0};
216 }
217
218 for (auto & [dof_object, delta_tangential_lm] : _dof_to_frictional_lagrange_multipliers)
219 delta_tangential_lm.setZero();
220
221 // save off damage from the last timestep
222 for (auto & map_pr : _dof_to_damage)
223 {
224 auto & [damage, old_damage] = map_pr.second;
225 old_damage = {MetaPhysicL::raw_value(damage)};
226 damage = {0.0};
227 }
228}
229
230void
232{
233 // these functions do not call WeightedGapUserObject::initialize to avoid double initialization
236
237 // instead we call it explicitly here
239 _dof_to_F.clear();
240 _dof_to_F_neighbor.clear();
242 _dof_to_interface_F.clear();
243 _dof_to_interface_R.clear();
244 _dof_to_czm_traction.clear();
245 for (auto & map_pr : _dof_to_rotation_matrix)
246 map_pr.second.setToIdentity();
247}
248
249ADReal
251 const unsigned int direction) const
252{
253 mooseAssert(direction < 2, "There are at most two tangent directions.");
254 return libmesh_map_find(_dof_to_tangential_traction, node.id()).first(direction);
255}
256
257void
259{
260 // Normal contact pressure with penalty
262
263 // Compute all rotations that were created as material properties in CZMComputeDisplacementJump
265
266 // Reset frictional pressure
269
270 for (const auto qp : make_range(_qrule_msm->n_points()))
271 {
274 }
275
276 // zero vector
277 const static TwoVector zero{0.0, 0.0};
278
279 // iterate over nodes
280 for (const auto i : make_range(_test->size()))
281 {
282 // current node
283 const Node * const node = _lower_secondary_elem->node_ptr(i);
284
285 // Compute the weighted nodal deformation gradient and rotation tensors.
286 computeFandR(node);
287
288 // The call below is a 'macro' call. Create a utility function or user object for it.
289 computeCZMTraction(node);
290
291 // Build final traction vector
293
294 // Compute mechanical contact until end of method.
295 const auto penalty_friction = findValue(
296 _dof_to_local_penalty_friction, cast_ptr<const DofObject *>(node), _penalty_friction);
297
298 // utilized quantities
299 const auto & normal_pressure = _dof_to_normal_pressure[node];
300
301 // map the tangential traction and accumulated slip
302 auto & [tangential_traction, old_tangential_traction] = _dof_to_tangential_traction[node->id()];
303 auto & [accumulated_slip, old_accumulated_slip] = _dof_to_accumulated_slip[node->id()];
304
305 Real normal_lm = -1;
306 if (auto it = _dof_to_lagrange_multiplier.find(node->id());
307 it != _dof_to_lagrange_multiplier.end())
308 normal_lm = it->second;
309
310 // Keep active set fixed from second Uzawa loop
311 if (normal_lm < -TOLERANCE && normal_pressure > TOLERANCE)
312 {
313 using std::abs;
314
315 const auto & damage = _dof_to_damage[node->id()].first;
316
317 const auto & real_tangential_velocity =
318 libmesh_map_find(_dof_to_real_tangential_velocity, node);
319 const ADTwoVector slip_distance = {real_tangential_velocity[0] * _dt,
320 real_tangential_velocity[1] * _dt};
321
322 // frictional lagrange multiplier (delta lambda^(k)_T)
323 const auto & tangential_lm =
325
326 // tangential trial traction (Simo 3.12)
327 // Modified for implementation in MOOSE: Avoid pingponging on frictional sign (max. 0.4
328 // capacity)
329 ADTwoVector inner_iteration_penalty_friction = penalty_friction * slip_distance;
330
331 const auto slip_metric = std::abs(MetaPhysicL::raw_value(slip_distance).cwiseAbs()(0)) +
332 std::abs(MetaPhysicL::raw_value(slip_distance).cwiseAbs()(1));
333
334 const auto slip_norm = (MetaPhysicL::raw_value(slip_distance)).norm();
335 const auto friction_limit = 0.4 * _friction_coefficient * damage * abs(normal_pressure);
336
337 if (slip_metric > _epsilon_tolerance && penalty_friction * slip_norm > friction_limit)
338 {
339 inner_iteration_penalty_friction =
340 MetaPhysicL::raw_value(friction_limit / (penalty_friction * slip_norm)) *
341 penalty_friction * slip_distance;
342 }
343
344 ADTwoVector tangential_trial_traction =
345 old_tangential_traction + tangential_lm + inner_iteration_penalty_friction;
346
347 // Nonlinearity below
348 ADReal tangential_trial_traction_norm =
349 (MetaPhysicL::raw_value(tangential_trial_traction)).norm();
350 ADReal phi_trial = tangential_trial_traction_norm - _friction_coefficient * normal_pressure;
351 tangential_traction = tangential_trial_traction;
352
353 // Simo considers this a 'return mapping'; we are just capping friction to the Coulomb limit.
354 if (phi_trial > 0.0)
355 // Simo 3.13/3.14 (the penalty formulation has an error in the paper)
356 tangential_traction -=
357 phi_trial * tangential_trial_traction / tangential_trial_traction_norm;
358
359 // track accumulated slip for output purposes
360 accumulated_slip = old_accumulated_slip + slip_distance.cwiseAbs();
361 }
362 else
363 {
364 // reset slip and clear traction
365 accumulated_slip.setZero();
366 tangential_traction.setZero();
367 }
368
369 // Now that we have consistent nodal frictional values, create an interpolated frictional
370 // pressure variable.
371 const auto test_i = (*_test)[i];
372 for (const auto qp : make_range(_qrule_msm->n_points()))
373 {
374 _frictional_contact_traction_one[qp] += test_i[qp] * tangential_traction(0);
375 _frictional_contact_traction_two[qp] += test_i[qp] * tangential_traction(1);
376 }
377 }
378
379 for (const auto i : index_range(_czm_interpolated_traction))
380 {
382
383 for (const auto qp : make_range(_qrule_msm->n_points()))
384 _czm_interpolated_traction[i][qp] = 0.0;
385 }
386
387 // iterate over nodes
388 for (const auto i : make_range(_test->size()))
389 {
390 // current node
391 const Node * const node = _lower_secondary_elem->node_ptr(i);
392
393 // End of CZM bilinear computations
394 auto it = _dof_to_czm_traction.find(node);
395 if (it == _dof_to_czm_traction.end())
396 continue;
397
398 const auto & test_i = (*_test)[i];
399 for (const auto qp : make_range(_qrule_msm->n_points()))
400 for (const auto idx : index_range(_czm_interpolated_traction))
401 _czm_interpolated_traction[idx][qp] += test_i[qp] * (it->second)(idx);
402 }
403}
404
405void
407{
408 // Compute rotation matrix from secondary surface
409 // Rotation matrices and local interface displacement jump.
410 for (const auto i : make_range(_test->size()))
411 {
412 const Node * const node = _lower_secondary_elem->node_ptr(i);
413
414 // First call does not have maps available
415 const bool skip_node = _dof_to_weighted_gap.find(node) == _dof_to_weighted_gap.end();
416 if (skip_node)
417 continue;
418
419 _dof_to_rotation_matrix[node] = CohesiveZoneModelTools::computeReferenceRotation<true>(
421
422 // Every time we used quantities from a map we "denormalize" it from the mortar integral.
423 // See normalizing member functions.
424 if (auto it = _dof_to_weighted_displacements.find(node);
426 _dof_to_interface_displacement_jump[node] = it->second;
427 }
428}
429
430void
447
448const ADVariableValue &
453
454const ADVariableValue &
459
460void
462{
463 // First call does not have maps available
464 const auto it = _dof_to_czm_traction.find(node);
465 if (it == _dof_to_czm_traction.end())
466 return;
467
468 const auto local_traction_vector = it->second;
469 const auto rotation_matrix = libmesh_map_find(_dof_to_rotation_matrix, node);
470
471 _dof_to_czm_traction[node] = rotation_matrix * local_traction_vector;
472}
473
474const ADVariableValue &
476{
477 mooseAssert(i <= 3,
478 "Internal error in czmGlobalTraction. Index exceeds the traction vector size.");
479
481}
DualNumber< Real, DNDerivativeType, true > ADReal
void mooseError(Args &&... args)
std::unordered_map< dof_id_type, std::pair< ADTwoVector, TwoVector > > & _dof_to_tangential_traction
virtual const ADVariableValue & czmGlobalTraction(unsigned int i) const
std::unordered_map< const DofObject *, ADRealVectorValue > _dof_to_interface_displacement_jump
Map from degree of freedom to local displacement jump.
virtual void computeQpProperties() override
Computes properties that are functions only of the current quadrature point (_qp),...
std::unordered_map< const DofObject *, ADRankTwoTensor > _dof_to_F_neighbor
Map from degree of freedom to neighbor, interpolated deformation gradient tensor.
CohesiveZoneModelBase(const InputParameters &parameters)
virtual const ADVariableValue & contactTangentialPressureDirTwo() const override
virtual void computeQpIProperties() override
Computes properties that are functions both of _qp and _i, for example the weighted gap.
std::unordered_map< dof_id_type, std::pair< ADTwoVector, TwoVector > > & _dof_to_accumulated_slip
Map from degree of freedom to current and old accumulated slip.
ADRankTwoTensor _F_interpolation
Deformation gradient for interpolation.
std::unordered_map< const DofObject *, ADRankTwoTensor > _dof_to_F
Map from degree of freedom to secondary, interpolated deformation gradient tensor.
const Real _epsilon_tolerance
Tolerance to avoid NaN/Inf in automatic differentiation operations.
ADVariableValue _frictional_contact_traction_two
The second frictional contact pressure on the mortar segment quadrature points.
virtual void timestepSetup() override
std::unordered_map< const DofObject *, ADRankTwoTensor > _dof_to_rotation_matrix
*** Kinematics/displacement jump quantities *** Map from degree of freedom to rotation matrix
virtual const VariableTestValue & test() const override
virtual bool constrainedByOwner() const override
std::unordered_map< const DofObject *, std::pair< ADTwoVector, TwoVector > > _dof_to_step_slip
Map from degree of freedom to current and old AD iteration step slip.
virtual ADReal nodalTangentialPressure(const Node &node, unsigned int direction) const override
static InputParameters validParams()
std::unordered_map< const DofObject *, ADRealVectorValue > _dof_to_czm_traction
Total Lagrangian stress to be applied on CZM interface.
virtual void finalize() override
std::vector< const GenericVariableGradient< true > * > _grad_disp_neighbor
Coupled displacement and neighbor displacement gradient.
std::unordered_map< const DofObject *, ADRankTwoTensor > _dof_to_interface_R
Map from degree of freedom to interface rotation tensor.
const Real _penalty_friction
The penalty factor for the frictional constraints.
std::vector< ADVariableValue > _czm_interpolated_traction
The global traction.
std::unordered_map< dof_id_type, std::pair< ADReal, Real > > & _dof_to_damage
Damage values (pair of current and old) on CZM interface.
virtual void computeGlobalTraction(const Node *const node)
Compute global traction for mortar application.
std::unordered_map< const DofObject *, Real > _dof_to_local_penalty_friction
Map from degree of freedom to local friction penalty value.
const Real _friction_coefficient
The friction coefficient.
virtual const ADVariableValue & contactTangentialPressureDirOne() const override
T normalizeQuantity(const std::unordered_map< const DofObject *, T > &map, const Node *const node)
Normalize mortar quantities (remove mortar integral scaling)
ADVariableValue _frictional_contact_traction_one
The first frictional contact pressure on the mortar segment quadrature points.
std::unordered_map< const DofObject *, TwoVector > _dof_to_frictional_lagrange_multipliers
Map from degree of freedom to augmented lagrange multiplier.
virtual void computeCZMTraction(const Node *const)=0
Encapsulate the CZM constitutive behavior.
std::unordered_map< const DofObject *, ADRankTwoTensor > _dof_to_interface_F
Map from degree of freedom to interface deformation gradient tensor.
virtual void prepareJumpKinematicQuantities()
ADRankTwoTensor _F_neighbor_interpolation
Deformation gradient for interpolation of the neighbor projection.
std::vector< const GenericVariableGradient< true > * > _grad_disp
Coupled displacement gradients.
virtual void reinit() override
virtual void computeFandR(const Node *const node)
virtual void initialize() override
FactorizedRankTwoTensorTempl< T > transpose() const
void suppressParameter(const std::string &name)
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
T & set(const std::string &name, bool quiet_mode=false)
void setParameters(const std::string &name, const T &value, Ts... extra_input_parameters)
virtual unsigned int dimension() const
virtual const FieldVariablePhiValue & phiLower() const override
Elem const *const & _lower_secondary_elem
const libMesh::QBase *const & _qrule_msm
std::vector< Point > _normals
const std::vector< Real > & _JxW_msm
User object for computing weighted gaps and contact pressure for penalty based mortar constraints.
AugmentedLagrangianContactProblemInterface *const _augmented_lagrange_problem
augmented Lagrange problem and iteration number
std::unordered_map< dof_id_type, Real > & _dof_to_lagrange_multiplier
Map from node id to augmented lagrange multiplier.
const MooseVariable *const _aux_lm_var
The auxiliary Lagrange multiplier variable (used together whith the Petrov-Galerkin approach)
const Real & _dt
Current delta t... or timestep size.
std::unordered_map< const DofObject *, ADReal > _dof_to_normal_pressure
Map from degree of freedom to normal pressure for reporting.
static RankTwoTensorTempl initializeFromRows(const libMesh::TypeVector< T > &row0, const libMesh::TypeVector< T > &row1, const libMesh::TypeVector< T > &row2)
static RankTwoTensorTempl Identity()
virtual void timestepSetup()
virtual MooseMesh & mesh()=0
SubProblem & _subproblem
Creates dof object to weighted gap map.
unsigned int _i
Test function index.
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't exist.
const MooseVariable *const _disp_x_var
The x displacement variable.
unsigned int _qp
Quadrature point index for the mortar segments.
const MooseArray< Real > & _coord
Member for handling change of coordinate systems (xyz, rz, spherical)
std::unordered_map< const DofObject *, std::pair< ADReal, Real > > _dof_to_weighted_gap
A map from node to weighted gap and normalization (if requested)
ADRealVectorValue _qp_displacement_nodal
Vector for computation of relative displacement (determines mixity ratio in interface problems)
virtual void initialize() override
std::unordered_map< const DofObject *, ADRealVectorValue > _dof_to_weighted_displacements
A map from node to weighted displacements.
const VariableTestValue * _test
A pointer to the test function associated with the weighted gap.
const bool _nodal
Whether the dof objects are nodal; if they're not, then they're elemental.
Creates dof object to weighted tangential velocities map.
virtual void computeQpProperties() override
Computes properties that are functions only of the current quadrature point (_qp),...
virtual void computeQpIProperties() override
Computes properties that are functions both of _qp and _i, for example the weighted gap.
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 Parallel::Communicator & _communicator
unsigned int n_points() const
auto raw_value(const Eigen::Map< T > &in)
VariableShapeValue< true > VariableTestValue
VariableValueTempl< true > ADVariableValue
void communicateR2T(std::unordered_map< const DofObject *, ADRankTwoTensor > &dof_map_adr2t, const MooseMesh &mesh, const bool nodal, const Parallel::Communicator &communicator, const bool send_data_back)
This function is used to communicate velocities across processes.
void communicateRealObject(std::unordered_map< const DofObject *, T > &dof_to_adreal, const MooseMesh &mesh, const bool nodal, const Parallel::Communicator &communicator, const bool send_data_back)
static constexpr std::size_t dim
IntRange< T > make_range(T beg, T end)