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++)
116 FEInterface::compute_data(elem->dim(),
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);
245 std::unique_ptr<FEBase> fe (FEBase::build(
dim, fe_type));
247 fe->attach_quadrature_rule (&qrule);
249 std::unique_ptr<FEBase> fe_face (FEBase::build(
dim, fe_type));
251 fe_face->attach_quadrature_rule (&qface);
253 std::unique_ptr<FEBase> fe_neighbor_face (FEBase::build(
dim, fe_type));
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[] = {
489 std::unique_ptr<FEBase> fe (FEBase::build(
dim, fe_type));
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);
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
This is the EquationSystems class.
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
virtual Node *& set_node(const unsigned int i)
A Node is like a Point, but with more information.
bool has_boundary_id(const Node *const node, const boundary_id_type id) 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.
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
class FEComputeData hides arbitrary data to be passed to and from children of FEBase through the FEIn...
virtual numeric_index_type size() const =0
void resize(const unsigned int n)
Resize the vector.
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]...
void zero()
Set all entries of the tensor to 0.
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly ecreated (or read) mesh for use.
const FEType & variable_type(const unsigned int c) const
const EquationSystems & get_equation_systems() const
This is the base class from which all geometric element types are derived.
processor_id_type rank() const
const Parallel::Communicator & comm() const
Order default_quadrature_order() const
The libMesh namespace provides an interface to certain functionality in the library.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
const T_sys & get_system(std::string_view name) const
const MeshBase & get_mesh() const
virtual std::unique_ptr< MeshBase > clone() const =0
Virtual "copy constructor".
Real distance(const Point &p)
virtual void init(const numeric_index_type n, const numeric_index_type n_local, const bool fast=false, const ParallelType ptype=AUTOMATIC)=0
Change the dimension of the vector to n.
This is the MeshBase class.
virtual void zero()=0
Set all entries to zero.
Number current_solution(const dof_id_type global_dof_number) const
unsigned int variable_number(std::string_view var) const
virtual void add(const numeric_index_type i, const numeric_index_type j, const T value)=0
Add value to the element (i,j).
Defines a dense subvector for use in finite element computations.
This class handles the numbering of degrees of freedom on a mesh.
unsigned int number() const
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.
const T & get(std::string_view) const
virtual void zero()=0
Set all entries to 0.
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
Defines a dense submatrix for use in Finite Element-type computations.
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and non-linear solv...
void add_scaled(const TypeTensor< T2 > &, const T &)
Add a scaled tensor to this tensor without creating a temporary.
virtual const Elem * elem_ptr(const dof_id_type i) const =0
virtual void update()
Update the local values to reflect the solution on neighboring processors.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
subdomain_id_type subdomain_id() const
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
This class implements specific orders of Gauss quadrature.
unsigned int mesh_dimension() const
Parameters parameters
Data structure holding arbitrary parameters.
virtual const Node & node_ref(const dof_id_type i) const
virtual const Point & point(const dof_id_type i) const =0
unsigned int n_vars() const
const DofMap & get_dof_map() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
Manages consistently variables, degrees of freedom, and coefficient vectors for explicit systems...
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
virtual void localize(std::vector< T > &v_local) const =0
Creates a copy of the global vector in the local vector v_local.