8#include <unordered_set>
11#include "libmesh/libmesh.h"
12#include "libmesh/mesh.h"
13#include "libmesh/equation_systems.h"
14#include "libmesh/fe.h"
15#include "libmesh/quadrature_gauss.h"
16#include "libmesh/dof_map.h"
17#include "libmesh/sparse_matrix.h"
18#include "libmesh/numeric_vector.h"
19#include "libmesh/dense_matrix.h"
20#include "libmesh/dense_vector.h"
21#include "libmesh/elem.h"
22#include "libmesh/fe_interface.h"
23#include "libmesh/fe_compute_data.h"
24#include "libmesh/petsc_matrix_base.h"
25#include "libmesh/edge_edge2.h"
26#include "libmesh/boundary_info.h"
27#include "libmesh/tensor_value.h"
30#include "libmesh/nonlinear_solver.h"
31#include "libmesh/nonlinear_implicit_system.h"
36 Real contact_penalty_in) :
38 _contact_penalty(contact_penalty_in)
55 return i == j ? 1. : 0.;
66 const Real lambda_1 = (young_modulus*poisson_ratio)/((1.+poisson_ratio)*(1.-2.*poisson_ratio));
67 const Real lambda_2 = young_modulus/(2.*(1.+poisson_ratio));
77 std::unordered_set<dof_id_type> encountered_node_ids;
81 std::unique_ptr<NumericVector<Number>> localized_input_solution =
84 localized_input_solution->init (input_solution.
size(),
false,
SERIAL);
85 input_solution.
localize(*localized_input_solution);
87 for (
const auto & elem : input_mesh.active_element_ptr_range())
91 for (
auto node_id : elem->node_index_range())
93 Node & node = elem->node_ref(node_id);
95 if (encountered_node_ids.find(node.
id()) != encountered_node_ids.end())
98 encountered_node_ids.insert(node.
id());
100 std::vector<std::string> uvw_names(3);
106 const Point master_point = elem->master_point(node_id);
109 for (std::size_t index=0; index<uvw_names.size(); index++)
121 std::vector<dof_id_type> dof_indices_var;
124 for (std::size_t i=0; i<dof_indices_var.size(); i++)
126 Number value = (*localized_input_solution)(dof_indices_var[i]) * data.
shape[i];
128#ifdef LIBMESH_USE_COMPLEX_NUMBERS
130 uvw(index) +=
value.real();
148 std::vector<dof_id_type> nodes_on_lower_surface;
149 std::vector<dof_id_type> nodes_on_upper_surface;
152 for (
const auto & elem :
mesh.active_element_ptr_range())
153 for (
auto side : elem->side_index_range())
154 if (elem->neighbor_ptr(side) ==
nullptr)
156 bool on_lower_contact_surface =
159 bool on_upper_contact_surface =
162 libmesh_error_msg_if(on_lower_contact_surface && on_upper_contact_surface,
163 "Should not be on both surfaces at the same time");
165 if (on_lower_contact_surface || on_upper_contact_surface)
167 for (
auto node_index : elem->node_index_range())
168 if (elem->is_node_on_side(node_index, side))
170 if (on_lower_contact_surface)
171 nodes_on_lower_surface.push_back(elem->node_id(node_index));
174 _lambdas[elem->node_id(node_index)] = 0.;
175 nodes_on_upper_surface.push_back(elem->node_id(node_index));
182 libmesh_assert(nodes_on_lower_surface.size() == nodes_on_upper_surface.size());
186 for (std::size_t i=0; i<nodes_on_lower_surface.size(); i++)
188 dof_id_type lower_node_id = nodes_on_lower_surface[i];
191 Real min_distance = std::numeric_limits<Real>::max();
193 for (std::size_t j=0; j<nodes_on_upper_surface.size(); j++)
195 dof_id_type upper_node_id = nodes_on_upper_surface[j];
219 connector_elem->
set_node(0, &master_node);
220 connector_elem->
set_node(1, &slave_node);
247 fe->attach_quadrature_rule (&qrule);
251 fe_face->attach_quadrature_rule (&qface);
254 fe_neighbor_face->attach_quadrature_rule (&qface);
256 const std::vector<Real> & JxW = fe->get_JxW();
257 const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi();
281 std::vector<dof_id_type> dof_indices;
282 std::vector<std::vector<dof_id_type>> dof_indices_var(3);
284 for (
const auto & elem :
mesh.active_local_element_ptr_range())
286 if( elem->type() ==
EDGE2 )
294 for (
unsigned int var=0; var<3; var++)
295 dof_map.
dof_indices (elem, dof_indices_var[var], var);
297 const unsigned int n_dofs = dof_indices.size();
298 const unsigned int n_var_dofs = dof_indices_var[0].size();
303 for (
unsigned int var=0; var<3; var++)
304 Re_var[var].reposition (var*n_var_dofs, n_var_dofs);
306 Ke.
resize (n_dofs, n_dofs);
307 for (
unsigned int var_i=0; var_i<3; var_i++)
308 for (
unsigned int var_j=0; var_j<3; var_j++)
309 Ke_var[var_i][var_j].reposition (var_i*n_var_dofs, var_j*n_var_dofs, n_var_dofs, n_var_dofs);
311 for (
unsigned int qp=0; qp<qrule.
n_points(); qp++)
315 for (
unsigned int var_i=0; var_i<3; var_i++)
316 for (
unsigned int var_j=0; var_j<3; var_j++)
317 for (
unsigned int j=0; j<n_var_dofs; j++)
318 grad_u(var_i, var_j) += dphi[j][qp](var_j)*soln(dof_indices_var[var_i][j]);
321 for (
unsigned int dof_i=0; dof_i<n_var_dofs; dof_i++)
322 for (
unsigned int i=0; i<3; i++)
323 for (
unsigned int j=0; j<3; j++)
324 for (
unsigned int k=0; k<3; k++)
325 for (
unsigned int l=0; l<3; l++)
326 Re_var[i](dof_i) -= JxW[qp] *
327 elasticity_tensor(young_modulus, poisson_ratio, i, j, k, l) * grad_u(k,l) * dphi[dof_i][qp](j);
330 for (
unsigned int dof_i=0; dof_i<n_var_dofs; dof_i++)
331 for (
unsigned int dof_j=0; dof_j<n_var_dofs; dof_j++)
332 for (
unsigned int i=0; i<3; i++)
333 for (
unsigned int j=0; j<3; j++)
334 for (
unsigned int k=0; k<3; k++)
335 for (
unsigned int l=0; l<3; l++)
336 Ke_var[i][k](dof_i, dof_j) -= JxW[qp] *
337 elasticity_tensor(young_modulus, poisson_ratio, i, j, k, l) * dphi[dof_j][qp](l) * dphi[dof_i][qp](j);
355 std::unique_ptr<MeshBase> mesh_clone =
mesh.
clone();
364 Point upper_to_lower;
366 Point lower_node_moved = mesh_clone->point(lower_point_id);
367 Point upper_node_moved = mesh_clone->point(upper_point_id);
369 upper_to_lower = (lower_node_moved - upper_node_moved);
375 Point contact_force_direction(0., 0., 1.);
380 Real gap_function = upper_to_lower * contact_force_direction;
384 Real lambda_plus_penalty =
387 if (lambda_plus_penalty < 0.)
388 lambda_plus_penalty = 0.;
396 std::vector<dof_id_type> dof_indices_on_lower_node(3);
397 std::vector<dof_id_type> dof_indices_on_upper_node(3);
401 for (
unsigned int var=0; var<3; var++)
404 lower_contact_force_vec(var) = -lambda_plus_penalty * contact_force_direction(var);
407 upper_contact_force_vec(var) = lambda_plus_penalty * contact_force_direction(var);
410 if (lambda_plus_penalty > 0.)
414 residual->
add_vector (lower_contact_force_vec, dof_indices_on_lower_node);
415 residual->
add_vector (upper_contact_force_vec, dof_indices_on_upper_node);
421 for (
unsigned int var=0; var<3; var++)
422 for (
unsigned int j=0; j<3; j++)
424 jacobian->
add(dof_indices_on_lower_node[var],
425 dof_indices_on_upper_node[j],
426 _contact_penalty * contact_force_direction(j) * contact_force_direction(var));
428 jacobian->
add(dof_indices_on_lower_node[var],
429 dof_indices_on_lower_node[j],
430 -
_contact_penalty * contact_force_direction(j) * contact_force_direction(var));
432 jacobian->
add(dof_indices_on_upper_node[var],
433 dof_indices_on_lower_node[j],
434 _contact_penalty * contact_force_direction(j) * contact_force_direction(var));
436 jacobian->
add(dof_indices_on_upper_node[var],
437 dof_indices_on_upper_node[j],
438 -
_contact_penalty * contact_force_direction(j) * contact_force_direction(var));
449 for (
unsigned int var=0; var<3; var++)
450 for (
unsigned int j=0; j<3; j++)
452 jacobian->
add(dof_indices_on_lower_node[var],
453 dof_indices_on_upper_node[j],
456 jacobian->
add(dof_indices_on_lower_node[var],
457 dof_indices_on_lower_node[j],
460 jacobian->
add(dof_indices_on_upper_node[var],
461 dof_indices_on_lower_node[j],
464 jacobian->
add(dof_indices_on_upper_node[var],
465 dof_indices_on_upper_node[j],
481 unsigned int displacement_vars[] = {
491 fe->attach_quadrature_rule (&qrule);
493 const std::vector<Real> & JxW = fe->get_JxW();
494 const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi();
499 unsigned int sigma_vars[] = {
506 unsigned int vonMises_var = stress_system.
variable_number (
"vonMises");
509 std::vector<std::vector<dof_id_type>> dof_indices_var(
_sys.
n_vars());
510 std::vector<dof_id_type> stress_dof_indices_var;
515 for (
const auto & elem :
mesh.active_local_element_ptr_range())
517 if( elem->type() ==
EDGE2 )
523 for (
unsigned int var=0; var<3; var++)
524 dof_map.
dof_indices (elem, dof_indices_var[var], displacement_vars[var]);
526 const unsigned int n_var_dofs = dof_indices_var[0].size();
531 elem_avg_stress_tensor.
zero();
533 for (
unsigned int qp=0; qp<qrule.
n_points(); qp++)
537 for (
unsigned int var_i=0; var_i<3; var_i++)
538 for (
unsigned int var_j=0; var_j<3; var_j++)
539 for (
unsigned int j=0; j<n_var_dofs; j++)
540 grad_u(var_i, var_j) +=
544 for (
unsigned int i=0; i<3; i++)
545 for (
unsigned int j=0; j<3; j++)
546 for (
unsigned int k=0; k<3; k++)
547 for (
unsigned int l=0; l<3; l++)
548 stress_tensor(i,j) +=
553 elem_avg_stress_tensor.
add_scaled(stress_tensor, JxW[qp]);
557 elem_avg_stress_tensor /= elem->volume();
560 unsigned int stress_var_index = 0;
561 for (
unsigned int i=0; i<3; i++)
562 for (
unsigned int j=i; j<3; j++)
564 stress_dof_map.dof_indices (elem, stress_dof_indices_var, sigma_vars[stress_var_index]);
570 if ((stress_system.
solution->first_local_index() <= dof_index) &&
571 (dof_index < stress_system.solution->last_local_index()))
572 stress_system.
solution->set(dof_index, elem_avg_stress_tensor(i,j));
578 Number vonMises_value = std::sqrt(0.5*(pow(elem_avg_stress_tensor(0,0) - elem_avg_stress_tensor(1,1), 2.) +
579 pow(elem_avg_stress_tensor(1,1) - elem_avg_stress_tensor(2,2), 2.) +
580 pow(elem_avg_stress_tensor(2,2) - elem_avg_stress_tensor(0,0), 2.) +
581 6.*(pow(elem_avg_stress_tensor(0,1), 2.) +
582 pow(elem_avg_stress_tensor(1,2), 2.) +
583 pow(elem_avg_stress_tensor(2,0), 2.))));
585 stress_dof_map.dof_indices (elem, stress_dof_indices_var, vonMises_var);
588 if ((stress_system.
solution->first_local_index() <= dof_index) &&
589 (dof_index < stress_system.solution->last_local_index()))
590 stress_system.
solution->set(dof_index, vonMises_value);
600 Real max_delta_lambda = 0.;
601 Real max_new_lambda = 0.;
603 for (
auto & [upper_node_id, lambda_val] :
_lambdas)
608 Real new_lambda = new_lambda_it->second;
609 Real old_lambda = lambda_val;
611 lambda_val = new_lambda;
613 Real delta_lambda = std::abs(new_lambda-old_lambda);
614 if (delta_lambda > max_delta_lambda)
615 max_delta_lambda = delta_lambda;
617 if (std::abs(new_lambda) > max_new_lambda)
618 max_new_lambda = std::abs(new_lambda);
621 return std::make_pair(max_delta_lambda, max_new_lambda);
629 Real least_value = std::numeric_limits<Real>::max();
630 Real max_value = std::numeric_limits<Real>::min();
634 Point upper_to_lower;
636 Point lower_node_moved = mesh_clone->point(lower_point_id);
637 Point upper_node_moved = mesh_clone->point(upper_point_id);
639 upper_to_lower = (lower_node_moved - upper_node_moved);
645 Point contact_force_direction(0., 0., 1.);
650 Real gap_function = upper_to_lower * contact_force_direction;
652 if (gap_function < least_value)
653 least_value = gap_function;
655 if (gap_function > max_value)
656 max_value = gap_function;
659 return std::make_pair(least_value, max_value);
processor_id_type rank() const
bool has_boundary_id(const Node *const node, const boundary_id_type id) const
Defines a dense matrix for use in Finite Element-type computations.
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
Defines a dense submatrix for use in Finite Element-type computations.
Defines a dense subvector for use in finite element computations.
Defines a dense vector for use in Finite Element-type computations.
void resize(const unsigned int n)
Resize the vector.
This class handles the numbering of degrees of freedom on a mesh.
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
const FEType & variable_type(const unsigned int i) const
void constrain_element_matrix_and_vector(DenseMatrix< Number > &matrix, DenseVector< Number > &rhs, std::vector< dof_id_type > &elem_dofs, bool asymmetric_constraint_rows=true) const
Constrains the element matrix and vector.
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
This is the base class from which all geometric element types are derived.
virtual Node *& set_node(const unsigned int i)
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
subdomain_id_type subdomain_id() const
This is the EquationSystems class.
Parameters parameters
Data structure holding arbitrary parameters.
const T_sys & get_system(std::string_view name) const
Manages consistently variables, degrees of freedom, and coefficient vectors for explicit systems.
class FEComputeData hides arbitrary data to be passed to and from children of FEBase through the FEIn...
std::vector< Number > shape
Storage for the computed shape function values.
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
static void compute_data(const unsigned int dim, const FEType &fe_t, const Elem *elem, FEComputeData &data)
Lets the appropriate child of FEBase compute the requested data for the input specified in data,...
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Order default_quadrature_order() const
This is the MeshBase class.
virtual const Node & node_ref(const dof_id_type i) const
virtual const Point & point(const dof_id_type i) const =0
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
unsigned int mesh_dimension() const
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly created (or read) mesh for use.
virtual std::unique_ptr< MeshBase > clone() const =0
Virtual "copy constructor".
virtual const Elem * elem_ptr(const dof_id_type i) const =0
virtual void clear()
Deletes all the element and node data that is currently stored.
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
A Node is like a Point, but with more information.
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and non-linear solv...
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
virtual void add_vector(const T *v, const std::vector< numeric_index_type > &dof_indices)
Computes , where v is a pointer and each dof_indices[i] specifies where to add value v[i].
static std::unique_ptr< NumericVector< T > > build(const Parallel::Communicator &comm, SolverPackage solver_package=libMesh::default_solver_package(), ParallelType parallel_type=AUTOMATIC)
Builds a NumericVector on the processors in communicator comm using the linear solver package specifi...
virtual void localize(std::vector< T > &v_local) const =0
Creates a copy of the global vector in the local vector v_local.
virtual void zero()=0
Set all entries to zero.
virtual numeric_index_type size() const =0
const Parallel::Communicator & comm() const
const T & get(std::string_view) const
A Point defines a location in LIBMESH_DIM dimensional Real space.
unsigned int n_points() const
This class implements specific orders of Gauss quadrature.
virtual void add_matrix(const DenseMatrix< T > &dm, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols)=0
Add the full matrix dm to the SparseMatrix.
virtual void zero()=0
Set all entries to 0.
virtual void add(const numeric_index_type i, const numeric_index_type j, const T value)=0
Add value to the element (i,j).
Number current_solution(const dof_id_type global_dof_number) const
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
virtual void update()
Update the local values to reflect the solution on neighboring processors.
unsigned int variable_number(std::string_view var) const
unsigned int n_vars() const
const DofMap & get_dof_map() const
unsigned int number() const
const EquationSystems & get_equation_systems() const
const MeshBase & get_mesh() const
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
void add_scaled(const TypeTensor< T2 > &, const T &)
Add a scaled tensor to this tensor without creating a temporary.
void zero()
Set all entries of the tensor to 0.
The libMesh namespace provides an interface to certain functionality in the library.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Real distance(const Point &p)