// The libMesh Finite Element Library. // Copyright (C) 2002-2020 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //

Systems Example 4 - Linear Elastic Cantilever

// \author David Knezevic // \date 2012 // // In this example we model a homogeneous isotropic cantilever // using the equations of linear elasticity. We set the Poisson ratio to // \nu = 0.3 and clamp the left boundary and apply a vertical load at the // right boundary. // C++ include files that we need #include #include #include // libMesh includes #include "libmesh/libmesh.h" #include "libmesh/mesh.h" #include "libmesh/mesh_generation.h" #include "libmesh/exodusII_io.h" #include "libmesh/gnuplot_io.h" #include "libmesh/linear_implicit_system.h" #include "libmesh/equation_systems.h" #include "libmesh/fe.h" #include "libmesh/quadrature_gauss.h" #include "libmesh/dof_map.h" #include "libmesh/sparse_matrix.h" #include "libmesh/numeric_vector.h" #include "libmesh/dense_matrix.h" #include "libmesh/dense_submatrix.h" #include "libmesh/dense_vector.h" #include "libmesh/dense_subvector.h" #include "libmesh/perf_log.h" #include "libmesh/elem.h" #include "libmesh/boundary_info.h" #include "libmesh/zero_function.h" #include "libmesh/dirichlet_boundaries.h" #include "libmesh/string_to_enum.h" #include "libmesh/getpot.h" #include "libmesh/enum_solver_package.h" // Bring in everything from the libMesh namespace using namespace libMesh; // Matrix and right-hand side assemble void assemble_elasticity(EquationSystems & es, const std::string & system_name); // Define the elasticity tensor, which is a fourth-order tensor // i.e. it has four indices i, j, k, l Real eval_elasticity_tensor(unsigned int i, unsigned int j, unsigned int k, unsigned int l); // Begin the main program. int main (int argc, char ** argv) { // Initialize libMesh and any dependent libraries LibMeshInit init (argc, argv); // This example requires a linear solver package. libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE, "--enable-petsc, --enable-trilinos, or --enable-eigen"); // Initialize the cantilever mesh const unsigned int dim = 2; // Skip this 2D example if libMesh was compiled as 1D-only. libmesh_example_requires(dim <= LIBMESH_DIM, "2D support"); // We use Dirichlet boundary conditions here #ifndef LIBMESH_ENABLE_DIRICHLET libmesh_example_requires(false, "--enable-dirichlet"); #endif // Create a 2D mesh distributed across the default MPI communicator. Mesh mesh(init.comm(), dim); MeshTools::Generation::build_square (mesh, 50, 10, 0., 1., 0., 0.2, QUAD9); // Print information about the mesh to the screen. mesh.print_info(); // Create an equation systems object. EquationSystems equation_systems (mesh); // Declare the system and its variables. // Create a system named "Elasticity" LinearImplicitSystem & system = equation_systems.add_system ("Elasticity"); system.attach_assemble_function (assemble_elasticity); #ifdef LIBMESH_ENABLE_DIRICHLET // Add two displacement variables, u and v, to the system unsigned int u_var = system.add_variable("u", SECOND, LAGRANGE); unsigned int v_var = system.add_variable("v", SECOND, LAGRANGE); // Construct a Dirichlet boundary condition object // We impose a "clamped" boundary condition on the // "left" boundary, i.e. bc_id = 3 std::set boundary_ids; boundary_ids.insert(3); // Create a vector storing the variable numbers which the BC applies to std::vector variables(2); variables[0] = u_var; variables[1] = v_var; // Create a ZeroFunction to initialize dirichlet_bc ZeroFunction<> zf; // Most DirichletBoundary users will want to supply a "locally // indexed" functor DirichletBoundary dirichlet_bc(boundary_ids, variables, zf, LOCAL_VARIABLE_ORDER); // We must add the Dirichlet boundary condition _before_ // we call equation_systems.init() system.get_dof_map().add_dirichlet_boundary(dirichlet_bc); #endif // LIBMESH_ENABLE_DIRICHLET // Initialize the data structures for the equation system. equation_systems.init(); // Print information about the system to the screen. equation_systems.print_info(); // Solve the system system.solve(); // Plot the solution #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO (mesh).write_equation_systems("displacement.e", equation_systems); #endif // #ifdef LIBMESH_HAVE_EXODUS_API // All done. return 0; } void assemble_elasticity(EquationSystems & es, const std::string & libmesh_dbg_var(system_name)) { libmesh_assert_equal_to (system_name, "Elasticity"); const MeshBase & mesh = es.get_mesh(); const unsigned int dim = mesh.mesh_dimension(); LinearImplicitSystem & system = es.get_system("Elasticity"); const unsigned int u_var = system.variable_number ("u"); const unsigned int v_var = system.variable_number ("v"); const DofMap & dof_map = system.get_dof_map(); FEType fe_type = dof_map.variable_type(0); std::unique_ptr fe (FEBase::build(dim, fe_type)); QGauss qrule (dim, fe_type.default_quadrature_order()); fe->attach_quadrature_rule (&qrule); std::unique_ptr fe_face (FEBase::build(dim, fe_type)); QGauss qface(dim-1, fe_type.default_quadrature_order()); fe_face->attach_quadrature_rule (&qface); const std::vector & JxW = fe->get_JxW(); const std::vector> & dphi = fe->get_dphi(); DenseMatrix Ke; DenseVector Fe; DenseSubMatrix Kuu(Ke), Kuv(Ke), Kvu(Ke), Kvv(Ke); DenseSubVector Fu(Fe), Fv(Fe); std::vector dof_indices; std::vector dof_indices_u; std::vector dof_indices_v; for (const auto & elem : mesh.active_local_element_ptr_range()) { dof_map.dof_indices (elem, dof_indices); dof_map.dof_indices (elem, dof_indices_u, u_var); dof_map.dof_indices (elem, dof_indices_v, v_var); const unsigned int n_dofs = dof_indices.size(); const unsigned int n_u_dofs = dof_indices_u.size(); const unsigned int n_v_dofs = dof_indices_v.size(); fe->reinit (elem); Ke.resize (n_dofs, n_dofs); Fe.resize (n_dofs); Kuu.reposition (u_var*n_u_dofs, u_var*n_u_dofs, n_u_dofs, n_u_dofs); Kuv.reposition (u_var*n_u_dofs, v_var*n_u_dofs, n_u_dofs, n_v_dofs); Kvu.reposition (v_var*n_v_dofs, u_var*n_v_dofs, n_v_dofs, n_u_dofs); Kvv.reposition (v_var*n_v_dofs, v_var*n_v_dofs, n_v_dofs, n_v_dofs); Fu.reposition (u_var*n_u_dofs, n_u_dofs); Fv.reposition (v_var*n_u_dofs, n_v_dofs); for (unsigned int qp=0; qpside_index_range()) if (elem->neighbor_ptr(side) == nullptr) { const std::vector> & phi_face = fe_face->get_phi(); const std::vector & JxW_face = fe_face->get_JxW(); fe_face->reinit(elem, side); if (mesh.get_boundary_info().has_boundary_id (elem, side, 1)) // Apply a traction on the right side { for (unsigned int qp=0; qpadd_matrix (Ke, dof_indices); system.rhs->add_vector (Fe, dof_indices); } } Real eval_elasticity_tensor(unsigned int i, unsigned int j, unsigned int k, unsigned int l) { // Define the Poisson ratio const Real nu = 0.3; // Define the Lame constants (lambda_1 and lambda_2) based on Poisson ratio const Real lambda_1 = nu / ((1. + nu) * (1. - 2.*nu)); const Real lambda_2 = 0.5 / (1 + nu); // Define the Kronecker delta functions that we need here Real delta_ij = (i == j) ? 1. : 0.; Real delta_il = (i == l) ? 1. : 0.; Real delta_ik = (i == k) ? 1. : 0.; Real delta_jl = (j == l) ? 1. : 0.; Real delta_jk = (j == k) ? 1. : 0.; Real delta_kl = (k == l) ? 1. : 0.; return lambda_1 * delta_ij * delta_kl + lambda_2 * (delta_ik * delta_jl + delta_il * delta_jk); }