www.mooseframework.org
Public Member Functions | Protected Member Functions | Protected Attributes | List of all members
RANFSNormalMechanicalContact Class Reference

#include <RANFSNormalMechanicalContact.h>

Inheritance diagram for RANFSNormalMechanicalContact:
[legend]

Public Member Functions

 RANFSNormalMechanicalContact (const InputParameters &parameters)
 
bool shouldApply () override
 
void residualSetup () override
 
void timestepSetup () override
 
void initialSetup () override
 
bool overwriteSlaveResidual () override
 
void computeSlaveValue (NumericVector< Number > &solution) override
 

Protected Member Functions

virtual Real computeQpSlaveValue () override
 
virtual Real computeQpResidual (Moose::ConstraintType type) override
 
virtual Real computeQpJacobian (Moose::ConstraintJacobianType type) override
 

Protected Attributes

const MooseEnum _component
 
const unsigned int _mesh_dimension
 
NumericVector< Number > & _residual_copy
 
unsigned int _largest_component
 
std::vector< unsigned int > _vars
 
std::vector< MooseVariable * > _var_objects
 
std::unordered_map< dof_id_type, Real > _node_to_contact_lm
 
std::unordered_map< dof_id_type, Real > _node_to_tied_lm
 
std::unordered_map< dof_id_type, std::vector< const Elem * > > _node_to_master_elem_sequence
 
Real _contact_lm
 
Real _tied_lm
 
PenetrationInfo * _pinfo
 
std::unordered_map< dof_id_type, const Node * > _ping_pong_slave_node_to_master_node
 
Real _distance
 
bool _tie_nodes
 
unsigned int _master_index
 
RealVectorValue _res_vec
 
const Node * _nearest_node
 
std::vector< std::unordered_map< dof_id_type, Number > > _dof_number_to_value
 
CouplingMatrix _disp_coupling
 

Detailed Description

Definition at line 33 of file RANFSNormalMechanicalContact.h.

Constructor & Destructor Documentation

◆ RANFSNormalMechanicalContact()

RANFSNormalMechanicalContact::RANFSNormalMechanicalContact ( const InputParameters &  parameters)

Definition at line 42 of file RANFSNormalMechanicalContact.C.

43  : NodeFaceConstraint(parameters),
44  _component(getParam<MooseEnum>("component")),
45  _mesh_dimension(_mesh.dimension()),
46  _residual_copy(_sys.residualGhosted()),
47  _dof_number_to_value(coupledComponents("displacements")),
48  _disp_coupling(coupledComponents("displacements"))
49 {
50  // modern parameter scheme for displacements
51  for (unsigned int i = 0; i < coupledComponents("displacements"); ++i)
52  {
53  _vars.push_back(coupled("displacements", i));
54  _var_objects.push_back(getVar("displacements", i));
55  }
56 
57  for (auto & var : _var_objects)
58  if (var->feType().family != LAGRANGE)
59  mooseError("This object only works when the displacement variables use a Lagrange basis");
60 
61  if (_vars.size() != _mesh_dimension)
62  mooseError("The number of displacement variables does not match the mesh dimension!");
63 }

Member Function Documentation

◆ computeQpJacobian()

Real RANFSNormalMechanicalContact::computeQpJacobian ( Moose::ConstraintJacobianType  type)
overrideprotectedvirtual

Definition at line 303 of file RANFSNormalMechanicalContact.C.

304 {
305  switch (type)
306  {
307  case Moose::ConstraintJacobianType::SlaveSlave:
308  {
309  if (_tie_nodes)
310  return _phi_slave[_j][_qp];
311 
312  // doing contact
313  else
314  {
315  // corresponds to gap equation
316  if (_largest_component == static_cast<unsigned int>(_component))
317  // _phi_slave has been set such that it is 1 when _j corresponds to the degree of freedom
318  // associated with the _current node and 0 otherwise
319  return std::abs(_pinfo->_normal(_component)) * _phi_slave[_j][_qp];
320 
321  // corresponds to regular residual with Lagrange Multiplier applied
322  else
323  {
324  Real ret_val = 0;
325  for (MooseIndex(_disp_coupling) i = 0; i < _disp_coupling.size(); ++i)
326  if (_disp_coupling(_component, i))
327  {
328  mooseAssert(
329  _dof_number_to_value[i].find(_connected_dof_indices[_j]) !=
330  _dof_number_to_value[i].end(),
331  "The connected dof index is not found in the _dof_number_to_value container. "
332  "This must mean that insufficient sparsity was allocated");
333  ret_val += -_pinfo->_normal(_component) * _pinfo->_normal(i) *
334  _dof_number_to_value[i][_connected_dof_indices[_j]];
335  }
336  return ret_val;
337  }
338  }
339  }
340 
341  case Moose::ConstraintJacobianType::SlaveMaster:
342  {
343  if (_tie_nodes)
344  {
345  if (_master_index == _j)
346  return -1;
347 
348  // We're tying the slave node to only one node on the master side (specified by
349  // _master_index). If the current _j doesn't correspond to that tied master node, then the
350  // slave residual doesn't depend on it
351  else
352  return 0;
353  }
354  else
355  {
356  if (_largest_component == static_cast<unsigned int>(_component))
357  return -std::abs(_pinfo->_normal(_component)) * _phi_master[_j][_qp];
358 
359  // If we're not applying the gap constraint equation on this _component, then we're
360  // applying a Lagrange multiplier, and consequently there is no dependence of the slave
361  // residual on the master dofs because the Lagrange multiplier is only a functon of the
362  // slave residuals
363  else
364  return 0;
365  }
366  }
367 
368  case Moose::ConstraintJacobianType::MasterSlave:
369  {
370  if (_tie_nodes)
371  {
372  if (_i == _master_index)
373  {
374  mooseAssert(_dof_number_to_value[_component].find(_connected_dof_indices[_j]) !=
376  "The connected dof index is not found in the _dof_number_to_value container. "
377  "This must mean that insufficient sparsity was allocated");
378  return _dof_number_to_value[_component][_connected_dof_indices[_j]];
379  }
380 
381  // We only apply the tied node Lagrange multiplier to the closest master node
382  else
383  return 0;
384  }
385  else
386  {
387  Real ret_val = 0;
388  for (MooseIndex(_disp_coupling) i = 0; i < _disp_coupling.size(); ++i)
389  if (_disp_coupling(_component, i))
390  {
391  mooseAssert(
392  _dof_number_to_value[i].find(_connected_dof_indices[_j]) !=
393  _dof_number_to_value[i].end(),
394  "The connected dof index is not found in the _dof_number_to_value container. "
395  "This must mean that insufficient sparsity was allocated");
396  ret_val += _test_master[_i][_qp] * _pinfo->_normal(_component) * _pinfo->_normal(i) *
397  _dof_number_to_value[i][_connected_dof_indices[_j]];
398  }
399  return ret_val;
400  }
401  }
402 
403  // The only master-master dependence would come from the dependence of the normal and also the
404  // location of the integration (quadrature) points. We assume (valid or not) that this
405  // dependence is weak
406  // case MooseConstraintJacobianType::MasterMaster
407 
408  default:
409  return 0;
410  }
411 }

◆ computeQpResidual()

Real RANFSNormalMechanicalContact::computeQpResidual ( Moose::ConstraintType  type)
overrideprotectedvirtual

Definition at line 259 of file RANFSNormalMechanicalContact.C.

260 {
261  switch (type)
262  {
263  case Moose::ConstraintType::Slave:
264  {
265  if (_tie_nodes)
266  return (*_current_node - *_nearest_node)(_component);
267  else
268  {
269  if (_largest_component == static_cast<unsigned int>(_component))
270  {
271  mooseAssert(_pinfo->_normal(_component) != 0,
272  "We should be selecting the largest normal component, hence it should be "
273  "impossible for this normal component to be zero");
274 
275  return _distance;
276  }
277 
278  else
279  // The normal points out of the master face
280  return _contact_lm * -_pinfo->_normal(_component);
281  }
282  }
283 
284  case Moose::ConstraintType::Master:
285  {
286  if (_tie_nodes)
287  {
288  if (_i == _master_index)
289  return _tied_lm;
290  else
291  return 0;
292  }
293  else
294  return _test_master[_i][_qp] * _contact_lm * _pinfo->_normal(_component);
295  }
296 
297  default:
298  return 0;
299  }
300 }

◆ computeQpSlaveValue()

Real RANFSNormalMechanicalContact::computeQpSlaveValue ( )
overrideprotectedvirtual

Definition at line 419 of file RANFSNormalMechanicalContact.C.

420 {
421  mooseError("We overrode commputeSlaveValue so computeQpSlaveValue should never get called");
422 }

◆ computeSlaveValue()

void RANFSNormalMechanicalContact::computeSlaveValue ( NumericVector< Number > &  solution)
override

Definition at line 414 of file RANFSNormalMechanicalContact.C.

415 {
416 }

◆ initialSetup()

void RANFSNormalMechanicalContact::initialSetup ( )
override

Definition at line 66 of file RANFSNormalMechanicalContact.C.

67 {
68  auto system_coupling_matrix = _subproblem.couplingMatrix();
69 
70  for (MooseIndex(_vars) i = 0; i < _vars.size(); ++i)
71  for (MooseIndex(_vars) j = 0; j < _vars.size(); ++j)
72  _disp_coupling(i, j) = (*system_coupling_matrix)(_vars[i], _vars[j]);
73 }

◆ overwriteSlaveResidual()

bool RANFSNormalMechanicalContact::overwriteSlaveResidual ( )
override

Definition at line 91 of file RANFSNormalMechanicalContact.C.

92 {
93  if (_tie_nodes)
94  return true;
95  else
96  return _largest_component == static_cast<unsigned int>(_component);
97 }

◆ residualSetup()

void RANFSNormalMechanicalContact::residualSetup ( )
override

Definition at line 83 of file RANFSNormalMechanicalContact.C.

84 {
85  _node_to_contact_lm.clear();
86  _node_to_tied_lm.clear();
87  NodeFaceConstraint::residualSetup();
88 }

◆ shouldApply()

bool RANFSNormalMechanicalContact::shouldApply ( )
override

Definition at line 100 of file RANFSNormalMechanicalContact.C.

101 {
102  std::map<dof_id_type, PenetrationInfo *>::iterator found =
103  _penetration_locator._penetration_info.find(_current_node->id());
104  if (found != _penetration_locator._penetration_info.end())
105  {
106  _pinfo = found->second;
107  if (_pinfo)
108  {
109  // We overwrite the slave residual when constraints are active so we cannot use the residual
110  // copy for determining the Lagrange multiplier when computing the Jacobian
111  if (!_subproblem.currentlyComputingJacobian())
112  {
113  // Build up residual vector corresponding to contact forces
114  _res_vec.zero();
115  for (unsigned int i = 0; i < _mesh_dimension; ++i)
116  {
117  dof_id_type dof_number = _current_node->dof_number(0, _vars[i], 0);
118  _res_vec(i) = _residual_copy(dof_number) / _var_objects[i]->scalingFactor();
119  }
120 
121  _node_to_contact_lm.insert(std::make_pair(_current_node->id(), _res_vec * _pinfo->_normal));
122  _node_to_tied_lm.insert(std::make_pair(_current_node->id(), _res_vec(_component)));
123  }
124  else
125  {
126  std::vector<dof_id_type> cols;
127  std::vector<Number> values;
128 
129  for (auto & d_to_v : _dof_number_to_value)
130  d_to_v.clear();
131 
132  mooseAssert(_vars.size() == _dof_number_to_value.size() &&
133  _vars.size() == _var_objects.size(),
134  "Somehow the sizes of our variable containers got out of sync");
135  for (MooseIndex(_var_objects) i = 0; i < _var_objects.size(); ++i)
136  {
137  auto slave_dof_number = _current_node->dof_number(0, _vars[i], 0);
138 
139  _jacobian->get_row(slave_dof_number, cols, values);
140  mooseAssert(cols.size() == values.size(),
141  "The size of the dof container and value container are different");
142 
143  for (MooseIndex(cols) j = 0; j < cols.size(); ++j)
144  _dof_number_to_value[i].insert(
145  std::make_pair(cols[j], values[j] / _var_objects[i]->scalingFactor()));
146  }
147  }
148 
149  mooseAssert(_node_to_contact_lm.find(_current_node->id()) != _node_to_contact_lm.end(),
150  "The node " << _current_node->id()
151  << " should map to a contact lagrange multiplier");
152  mooseAssert(_node_to_tied_lm.find(_current_node->id()) != _node_to_tied_lm.end(),
153  "The node " << _current_node->id()
154  << " should map to a tied lagrange multiplier");
155  _contact_lm = _node_to_contact_lm[_current_node->id()];
156  _tied_lm = _node_to_tied_lm[_current_node->id()];
157 
158  // Check to see whether we've locked a ping-ponging node
159  if (_ping_pong_slave_node_to_master_node.find(_current_node->id()) ==
161  {
162  if (_contact_lm > -_pinfo->_distance)
163  {
164  // Ok, our math is telling us we should apply the constraint, but what if we are
165  // ping-ponging back and forth between different master faces?
166 
167  // This only works for a basic line search! Write assertion here
168  if (_subproblem.computingNonlinearResid())
169  {
170  auto & master_elem_sequence = _node_to_master_elem_sequence[_current_node->id()];
171  mooseAssert(
172  _current_master == _pinfo->_elem,
173  "The current master element and the PenetrationInfo object's element should "
174  "be the same");
175  master_elem_sequence.push_back(_pinfo->_elem);
176 
177  // 5 here is a heuristic choice. In testing, generally speaking, if a node ping-pongs
178  // back and forth 5 times then it will ping pong indefinitely. However, if it goes 3
179  // times for example, it is not guaranteed to ping-pong indefinitely and the Newton
180  // iteration may naturally resolve the correct face dofs that need to be involved in the
181  // constraint.
182  if (master_elem_sequence.size() >= 5 &&
183  _pinfo->_elem == *(master_elem_sequence.rbegin() + 2) &&
184  _pinfo->_elem == *(master_elem_sequence.rbegin() + 4) &&
185  _pinfo->_elem != *(master_elem_sequence.rbegin() + 1) &&
186  *(master_elem_sequence.rbegin() + 1) == *(master_elem_sequence.rbegin() + 3))
187  {
188  // Ok we are ping-ponging. Determine the master node
189  auto master_node =
190  _penetration_locator._nearest_node.nearestNode(_current_node->id());
191 
192  // Sanity checks
193  mooseAssert(_pinfo->_elem->get_node_index(master_node) != libMesh::invalid_uint,
194  "The master node is not on the current element");
195  mooseAssert((*(master_elem_sequence.rbegin() + 1))->get_node_index(master_node) !=
196  libMesh::invalid_uint,
197  "The master node is not on the other ping-ponging element");
198 
200  std::make_pair(_current_node->id(), master_node));
201  }
202  }
203  }
204  else
205  // We have not locked the node into contact nor is the gap smaller than the Lagrange
206  // Multiplier so we should not apply
207  return false;
208  }
209 
210  // Determine whether we're going to apply the tied node equality constraint or the contact
211  // inequality constraint
212  auto it = _ping_pong_slave_node_to_master_node.find(_current_node->id());
213  if (it != _ping_pong_slave_node_to_master_node.end())
214  {
215  _tie_nodes = true;
216  _nearest_node = it->second;
217  _master_index = _current_master->get_node_index(_nearest_node);
218  mooseAssert(_master_index != libMesh::invalid_uint,
219  "nearest node not a node on the current master element");
220  }
221  else
222  {
223  _distance = _pinfo->_distance;
224  // Do this to make sure constraint equation has a positive on the diagonal
225  if (_pinfo->_normal(_component) > 0)
226  _distance *= -1;
227  _tie_nodes = false;
228 
229  // The contact constraint is active -> we're going to use our linear solve to ensure that
230  // the gap is driven to zero. We only have one zero-penetration constraint per node, so we
231  // choose to apply the zero penetration constraint only to the displacement component with
232  // the largest magnitude normal
233  auto largest_component_magnitude = std::abs(_pinfo->_normal(0));
234  _largest_component = 0;
235  for (MooseIndex(_mesh_dimension) i = 1; i < _mesh_dimension; ++i)
236  {
237  auto component_magnitude = std::abs(_pinfo->_normal(i));
238  if (component_magnitude > largest_component_magnitude)
239  {
240  largest_component_magnitude = component_magnitude;
241  _largest_component = i;
242  }
243  }
244  }
245 
246  return true;
247  }
248  }
249 
250  // If we're not applying the constraint then we can clear the node to master elem sequence for
251  // this node
252  if (_node_to_master_elem_sequence.find(_current_node->id()) !=
254  _node_to_master_elem_sequence[_current_node->id()].clear();
255  return false;
256 }

◆ timestepSetup()

void RANFSNormalMechanicalContact::timestepSetup ( )
override

Definition at line 76 of file RANFSNormalMechanicalContact.C.

Member Data Documentation

◆ _component

const MooseEnum RANFSNormalMechanicalContact::_component
protected

◆ _contact_lm

Real RANFSNormalMechanicalContact::_contact_lm
protected

Definition at line 61 of file RANFSNormalMechanicalContact.h.

Referenced by computeQpResidual(), and shouldApply().

◆ _disp_coupling

CouplingMatrix RANFSNormalMechanicalContact::_disp_coupling
protected

Definition at line 71 of file RANFSNormalMechanicalContact.h.

Referenced by computeQpJacobian(), and initialSetup().

◆ _distance

Real RANFSNormalMechanicalContact::_distance
protected

Definition at line 65 of file RANFSNormalMechanicalContact.h.

Referenced by computeQpResidual(), and shouldApply().

◆ _dof_number_to_value

std::vector<std::unordered_map<dof_id_type, Number> > RANFSNormalMechanicalContact::_dof_number_to_value
protected

Definition at line 70 of file RANFSNormalMechanicalContact.h.

Referenced by computeQpJacobian(), and shouldApply().

◆ _largest_component

unsigned int RANFSNormalMechanicalContact::_largest_component
protected

◆ _master_index

unsigned int RANFSNormalMechanicalContact::_master_index
protected

◆ _mesh_dimension

const unsigned int RANFSNormalMechanicalContact::_mesh_dimension
protected

Definition at line 52 of file RANFSNormalMechanicalContact.h.

Referenced by RANFSNormalMechanicalContact(), and shouldApply().

◆ _nearest_node

const Node* RANFSNormalMechanicalContact::_nearest_node
protected

Definition at line 69 of file RANFSNormalMechanicalContact.h.

Referenced by computeQpResidual(), and shouldApply().

◆ _node_to_contact_lm

std::unordered_map<dof_id_type, Real> RANFSNormalMechanicalContact::_node_to_contact_lm
protected

Definition at line 58 of file RANFSNormalMechanicalContact.h.

Referenced by residualSetup(), and shouldApply().

◆ _node_to_master_elem_sequence

std::unordered_map<dof_id_type, std::vector<const Elem *> > RANFSNormalMechanicalContact::_node_to_master_elem_sequence
protected

Definition at line 60 of file RANFSNormalMechanicalContact.h.

Referenced by shouldApply(), and timestepSetup().

◆ _node_to_tied_lm

std::unordered_map<dof_id_type, Real> RANFSNormalMechanicalContact::_node_to_tied_lm
protected

Definition at line 59 of file RANFSNormalMechanicalContact.h.

Referenced by residualSetup(), and shouldApply().

◆ _pinfo

PenetrationInfo* RANFSNormalMechanicalContact::_pinfo
protected

◆ _ping_pong_slave_node_to_master_node

std::unordered_map<dof_id_type, const Node *> RANFSNormalMechanicalContact::_ping_pong_slave_node_to_master_node
protected

Definition at line 64 of file RANFSNormalMechanicalContact.h.

Referenced by shouldApply(), and timestepSetup().

◆ _res_vec

RealVectorValue RANFSNormalMechanicalContact::_res_vec
protected

Definition at line 68 of file RANFSNormalMechanicalContact.h.

Referenced by shouldApply().

◆ _residual_copy

NumericVector<Number>& RANFSNormalMechanicalContact::_residual_copy
protected

Definition at line 53 of file RANFSNormalMechanicalContact.h.

Referenced by shouldApply().

◆ _tie_nodes

bool RANFSNormalMechanicalContact::_tie_nodes
protected

◆ _tied_lm

Real RANFSNormalMechanicalContact::_tied_lm
protected

Definition at line 62 of file RANFSNormalMechanicalContact.h.

Referenced by computeQpResidual(), and shouldApply().

◆ _var_objects

std::vector<MooseVariable *> RANFSNormalMechanicalContact::_var_objects
protected

Definition at line 57 of file RANFSNormalMechanicalContact.h.

Referenced by RANFSNormalMechanicalContact(), and shouldApply().

◆ _vars

std::vector<unsigned int> RANFSNormalMechanicalContact::_vars
protected

The documentation for this class was generated from the following files:
RANFSNormalMechanicalContact::_node_to_tied_lm
std::unordered_map< dof_id_type, Real > _node_to_tied_lm
Definition: RANFSNormalMechanicalContact.h:59
RANFSNormalMechanicalContact::_largest_component
unsigned int _largest_component
Definition: RANFSNormalMechanicalContact.h:55
RANFSNormalMechanicalContact::_tied_lm
Real _tied_lm
Definition: RANFSNormalMechanicalContact.h:62
RANFSNormalMechanicalContact::_contact_lm
Real _contact_lm
Definition: RANFSNormalMechanicalContact.h:61
RANFSNormalMechanicalContact::_disp_coupling
CouplingMatrix _disp_coupling
Definition: RANFSNormalMechanicalContact.h:71
RANFSNormalMechanicalContact::_mesh_dimension
const unsigned int _mesh_dimension
Definition: RANFSNormalMechanicalContact.h:52
RANFSNormalMechanicalContact::_var_objects
std::vector< MooseVariable * > _var_objects
Definition: RANFSNormalMechanicalContact.h:57
RANFSNormalMechanicalContact::_residual_copy
NumericVector< Number > & _residual_copy
Definition: RANFSNormalMechanicalContact.h:53
RANFSNormalMechanicalContact::_master_index
unsigned int _master_index
Definition: RANFSNormalMechanicalContact.h:67
RANFSNormalMechanicalContact::_vars
std::vector< unsigned int > _vars
Definition: RANFSNormalMechanicalContact.h:56
RANFSNormalMechanicalContact::_res_vec
RealVectorValue _res_vec
Definition: RANFSNormalMechanicalContact.h:68
RANFSNormalMechanicalContact::_node_to_master_elem_sequence
std::unordered_map< dof_id_type, std::vector< const Elem * > > _node_to_master_elem_sequence
Definition: RANFSNormalMechanicalContact.h:60
RANFSNormalMechanicalContact::_node_to_contact_lm
std::unordered_map< dof_id_type, Real > _node_to_contact_lm
Definition: RANFSNormalMechanicalContact.h:58
RANFSNormalMechanicalContact::_distance
Real _distance
Definition: RANFSNormalMechanicalContact.h:65
RANFSNormalMechanicalContact::_dof_number_to_value
std::vector< std::unordered_map< dof_id_type, Number > > _dof_number_to_value
Definition: RANFSNormalMechanicalContact.h:70
RANFSNormalMechanicalContact::_nearest_node
const Node * _nearest_node
Definition: RANFSNormalMechanicalContact.h:69
RANFSNormalMechanicalContact::_pinfo
PenetrationInfo * _pinfo
Definition: RANFSNormalMechanicalContact.h:63
RANFSNormalMechanicalContact::_ping_pong_slave_node_to_master_node
std::unordered_map< dof_id_type, const Node * > _ping_pong_slave_node_to_master_node
Definition: RANFSNormalMechanicalContact.h:64
RANFSNormalMechanicalContact::_component
const MooseEnum _component
Definition: RANFSNormalMechanicalContact.h:51
RANFSNormalMechanicalContact::_tie_nodes
bool _tie_nodes
Definition: RANFSNormalMechanicalContact.h:66