https://mooseframework.inl.gov
Loading...
Searching...
No Matches
NodalFrictionalConstraint.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
10// MOOSE includes
13#include "MooseMesh.h"
14#include "Assembly.h"
15#include "SystemBase.h"
16
17#include "libmesh/null_output_iterator.h"
18#include "libmesh/parallel.h"
19#include "libmesh/parallel_elem.h"
20#include "libmesh/parallel_node.h"
21
22// C++ includes
23#include <limits.h>
24
25using namespace libMesh;
26
28
31{
33 params.addClassDescription("Frictional nodal constraint for contact");
34 params.addRequiredParam<BoundaryName>("boundary", "The primary boundary");
35 params.addRequiredParam<BoundaryName>("secondary", "The secondary boundary");
36 params.addRequiredParam<Real>("friction_coefficient",
37 "Friction coefficient for slippage in the normal direction");
38 params.addRequiredParam<Real>("normal_force",
39 "Normal force used together with friction_coefficient to compute "
40 "the normal frictional capacity.");
41 params.addRequiredParam<Real>("tangential_penalty",
42 "Stiffness of the spring in the tangential direction.");
43 return params;
44}
45
47 : NodalConstraint(parameters),
48 _primary_boundary_id(getParam<BoundaryName>("boundary")),
49 _secondary_boundary_id(getParam<BoundaryName>("secondary")),
50 _normal_force(getParam<Real>("normal_force")),
51 _tangential_penalty(getParam<Real>("tangential_penalty")),
52 _friction_coefficient(getParam<Real>("friction_coefficient")),
53 _u_secondary_old(_var.dofValuesOldNeighbor()),
54 _u_primary_old(_var.dofValuesOld())
55{
57 paramError("variable_secondary",
58 "Primary variable must be identical to secondary "
59 "variable. Different variables are currently not supported.");
60
62
63 MooseEnum temp_formulation = getParam<MooseEnum>("formulation");
64 if (temp_formulation == "penalty")
66 else if (temp_formulation == "kinematic")
67 mooseError("NodalFrictionalConstraint: Kinematic formulation is currently not supported for "
68 "this constraint.");
69 else
70 mooseError("Formulation must be set to Penalty.");
71}
72
73void
78
79void
81{
83 _connected_nodes.clear();
84 _primary_conn.clear();
85
86 std::vector<dof_id_type> secondary_nodelist =
88 std::vector<dof_id_type> primary_nodelist =
90
91 // Fill in _connected_nodes, which defines secondary nodes in the base class
92 for (auto in : secondary_nodelist)
93 {
95 _connected_nodes.push_back(in);
96 }
97
98 // Fill in _primary_node_vector, which defines secondary nodes in the base class
99 for (auto in : primary_nodelist)
100 _primary_node_vector.push_back(in);
101
102 const auto & node_to_elem_map = _mesh.nodeToElemMap();
103 std::vector<std::vector<dof_id_type>> elems(_primary_node_vector.size());
104
105 // Add elements connected to primary node to Ghosted Elements.
106
107 // On a distributed mesh, these elements might have already been
108 // remoted, in which case we need to gather them back first.
109 if (!_mesh.getMesh().is_serial())
110 {
111 std::set<Elem *, CompareElemsByLevel> primary_elems_to_ghost;
112 std::set<Node *> nodes_to_ghost;
113
114 for (unsigned int i = 0; i < primary_nodelist.size(); ++i)
115 {
116 auto node_to_elem_pair = node_to_elem_map.find(_primary_node_vector[i]);
117
118 bool found_elems = (node_to_elem_pair != node_to_elem_map.end());
119
120#ifndef NDEBUG
121 bool someone_found_elems = found_elems;
122 _mesh.getMesh().comm().max(someone_found_elems);
123 mooseAssert(someone_found_elems, "Missing entry in node to elem map");
124#endif
125
126 if (found_elems)
127 {
128 for (auto id : node_to_elem_pair->second)
129 {
130 Elem * elem = _mesh.queryElemPtr(id);
131 if (elem)
132 {
133 primary_elems_to_ghost.insert(elem);
134
135 const unsigned int n_nodes = elem->n_nodes();
136 for (unsigned int n = 0; n != n_nodes; ++n)
137 nodes_to_ghost.insert(elem->node_ptr(n));
138 }
139 }
140 }
141 }
142
143 // Send nodes first since elements need them
145 nodes_to_ghost.begin(),
146 nodes_to_ghost.end(),
148
150 primary_elems_to_ghost.begin(),
151 primary_elems_to_ghost.end(),
153
154 _mesh.update(); // Rebuild node_to_elem_map
155
156 // Find elems again now that we know they're there
157 const auto & new_node_to_elem_map = _mesh.nodeToElemMap();
158 auto node_to_elem_pair = new_node_to_elem_map.find(_primary_node_vector[0]);
159 bool found_elems = (node_to_elem_pair != new_node_to_elem_map.end());
160
161 if (!found_elems)
162 mooseError("Colundn't find any elements connected to primary node.");
163
164 for (unsigned int i = 0; i < _primary_node_vector.size(); ++i)
165 elems[i] = node_to_elem_pair->second;
166 }
167 else // serial mesh
168 {
169 for (unsigned int i = 0; i < _primary_node_vector.size(); ++i)
170 {
171 auto node_to_elem_pair = node_to_elem_map.find(_primary_node_vector[i]);
172 bool found_elems = (node_to_elem_pair != node_to_elem_map.end());
173
174 if (!found_elems)
175 mooseError("Couldn't find any elements connected to primary node");
176
177 elems[i] = node_to_elem_pair->second;
178 }
179 }
180
181 for (unsigned int i = 0; i < _primary_node_vector.size(); ++i)
182 {
183 if (elems[i].size() == 0)
184 mooseError("Couldn't find any elements connected to primary node");
185
186 for (unsigned int j = 0; j < elems[i].size(); ++j)
187 _subproblem.addGhostedElem(elems[i][j]);
188 }
189
190 // Cache map between secondary node and primary node
191 _connected_nodes.clear();
192 _primary_conn.clear();
193 for (unsigned int j = 0; j < secondary_nodelist.size(); ++j)
194 {
195 if (_mesh.nodeRef(secondary_nodelist[j]).processor_id() == _subproblem.processor_id())
196 {
197 Node & secondary_node = _mesh.nodeRef(secondary_nodelist[j]);
198 for (unsigned int i = 0; i < _primary_node_vector.size(); ++i)
199 {
200 Node & primary_node = _mesh.nodeRef(_primary_node_vector[i]);
201 Real d = (secondary_node - primary_node).norm();
202 if (MooseUtils::absoluteFuzzyEqual(d, 0.0))
203 {
204 _primary_conn.push_back(i);
205 _connected_nodes.push_back(secondary_nodelist[j]);
206 break;
207 }
208 }
209 }
210 }
211
212 _console << "total secondary nodes, primary nodes: " << _primary_conn.size() << ", "
213 << _primary_node_vector.size() << '\n';
214}
215
216void
218 /*residual*/)
219{
220 const auto & primarydof = _var.dofIndices();
221 const auto & secondarydof = _var.dofIndicesNeighbor();
222 std::vector<Number> re(primarydof.size());
223 std::vector<Number> neighbor_re(secondarydof.size());
224
225 for (_i = 0; _i < secondarydof.size(); ++_i)
226 {
229 neighbor_re[_i] += computeQpResidual(Moose::Secondary);
230 break;
231 }
232 addResiduals(_assembly, re, primarydof, _var.scalingFactor());
233 addResiduals(_assembly, neighbor_re, secondarydof, _var.scalingFactor());
234}
235
236Real
238{
239 // check whether the tangential spring is already in the yielded state
241 if (MooseUtils::absoluteFuzzyGreaterThan(std::abs(old_force),
243 old_force = _friction_coefficient * _normal_force * old_force / std::abs(old_force);
244
245 Real current_force =
248 old_force;
249 if (MooseUtils::absoluteFuzzyGreaterThan(std::abs(current_force),
251 current_force = _friction_coefficient * _normal_force * current_force / std::abs(current_force);
252
253 switch (type)
254 {
255 case Moose::Secondary:
256 return current_force;
257 case Moose::Primary:
258 return -current_force;
259 }
260 return 0;
261}
262
263void
265{
266 // Calculate Jacobian entries and cache those entries along with the row and column indices
267 std::vector<dof_id_type> secondarydof = _var.dofIndicesNeighbor();
268 std::vector<dof_id_type> primarydof = _var.dofIndices();
269
270 DenseMatrix<Number> Kee(primarydof.size(), primarydof.size());
271 DenseMatrix<Number> Ken(primarydof.size(), secondarydof.size());
272 DenseMatrix<Number> Kne(secondarydof.size(), primarydof.size());
273 DenseMatrix<Number> Knn(secondarydof.size(), secondarydof.size());
274
275 Kee.zero();
276 Ken.zero();
277 Kne.zero();
278 Knn.zero();
279
280 for (_i = 0; _i < secondarydof.size(); ++_i)
281 {
287 }
288 addJacobian(_assembly, Kee, primarydof, primarydof, _var.scalingFactor());
289 addJacobian(_assembly, Ken, primarydof, secondarydof, _var.scalingFactor());
290 addJacobian(_assembly, Kne, secondarydof, primarydof, _var.scalingFactor());
291 addJacobian(_assembly, Knn, secondarydof, secondarydof, _var.scalingFactor());
292}
293
294Real
296{
298
299 // set jacobian to zero if spring has yielded
301 if (MooseUtils::absoluteFuzzyGreaterThan(std::abs(old_force),
303 old_force = _friction_coefficient * _normal_force * old_force / std::abs(old_force);
304
305 Real current_force =
308 old_force;
309 if (MooseUtils::absoluteFuzzyGreaterThan(std::abs(current_force),
311 jac = 0.0;
312
313 switch (type)
314 {
316 return jac;
318 return -jac;
320 return jac;
322 return -jac;
323 default:
324 mooseError("Invalid type");
325 }
326 return 0.;
327}
registerMooseObject("SolidMechanicsApp", NodalFrictionalConstraint)
const ConsoleStream _console
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
const std::string & type() const
void paramError(const std::string &param, Args... args) const
void mooseError(Args &&... args) const
virtual const Node & nodeRef(const dof_id_type i) const
MeshBase & getMesh()
void update()
const std::unordered_map< dof_id_type, std::vector< dof_id_type > > & nodeToElemMap()
virtual Elem * queryElemPtr(const dof_id_type i)
BoundaryID getBoundaryID(const BoundaryName &boundary_name) const
const std::vector< dof_id_type > & getNodeList(boundary_id_type nodeset_id) const
void scalingFactor(const std::vector< Real > &factor)
unsigned int number() const
const std::vector< dof_id_type > & dofIndicesNeighbor() const final
const std::vector< dof_id_type > & dofIndices() const final
Moose::ConstraintFormulationType _formulation
unsigned int _i
unsigned int _j
std::vector< dof_id_type > _primary_node_vector
std::vector< dof_id_type > _connected_nodes
static InputParameters validParams()
MooseVariable & _var
MooseVariable & _var_secondary
const VariableValue & _u_secondary
const VariableValue & _u_primary
const Real & _normal_force
Normal stiffness of spring.
virtual void computeResidual() override final
void updateConstrainedNodes()
Update the sets of nodes with constrained DOFs.
virtual void meshChanged() override
const Real & _tangential_penalty
Tangential stiffness of spring.
virtual Real computeQpJacobian(Moose::ConstraintJacobianType type) override
static InputParameters validParams()
const Real & _friction_coefficient
Coefficient of friction.
const VariableValue & _u_primary_old
Old value of the constrainted variable on the primary nodes.
BoundaryName _primary_boundary_id
Holds the secondary node set or side set.
virtual Real computeQpResidual(Moose::ConstraintType type) override
virtual void computeJacobian() override final
std::vector< dof_id_type > _primary_conn
primary node id connected to each secondary node in _connected_nodes
BoundaryName _secondary_boundary_id
Holds the secondary node set or side set.
NodalFrictionalConstraint(const InputParameters &parameters)
const VariableValue & _u_secondary_old
Old value of the constrainted variable on the secondary nodes.
MooseMesh & _mesh
Assembly & _assembly
SubProblem & _subproblem
virtual void addGhostedElem(dof_id_type elem_id)=0
void max(const T &r, T &o, Request &req) const
void allgather_packed_range(Context *context, Iter range_begin, const Iter range_end, OutputIter out, std::size_t approx_buffer_size=1000000) const
void addJacobian(Assembly &assembly, const Residuals &residuals, const Indices &dof_indices, Real scaling_factor)
void addResiduals(Assembly &assembly, const Residuals &residuals, const Indices &dof_indices, Real scaling_factor)
virtual void zero() override final
processor_id_type processor_id() const
virtual unsigned int n_nodes() const=0
const Node * node_ptr(const unsigned int i) const
virtual bool is_serial() const
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
ConstraintType
ConstraintJacobianType
SecondarySecondary
SecondaryPrimary
PrimarySecondary
PrimaryPrimary
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const dof_id_type n_nodes