void build_mesh()
  {
    _mesh = new SerialMesh(*TestCommWorld);

    /*
      (0,1)           (1,1)
        x---------------x
        |               |
        |               |
        |               |
        |               |
        |               |
        x---------------x
       (0,0)           (1,0)
        |               |
        |               |
        |               |
        |               |
        x---------------x
       (0,-1)          (1,-1)
     */

    _mesh->set_mesh_dimension(2);

    _mesh->add_point( Point(0.0,-1.0), 4 );
    _mesh->add_point( Point(1.0,-1.0), 5 );
    _mesh->add_point( Point(1.0, 0.0), 1 );
    _mesh->add_point( Point(1.0, 1.0), 2 );
    _mesh->add_point( Point(0.0, 1.0), 3 );
    _mesh->add_point( Point(0.0, 0.0), 0 );

    {
      Elem* elem_top = _mesh->add_elem( new Quad4 );
      elem_top->set_node(0) = _mesh->node_ptr(0);
      elem_top->set_node(1) = _mesh->node_ptr(1);
      elem_top->set_node(2) = _mesh->node_ptr(2);
      elem_top->set_node(3) = _mesh->node_ptr(3);

      Elem* elem_bottom = _mesh->add_elem( new Quad4 );
      elem_bottom->set_node(0) = _mesh->node_ptr(4);
      elem_bottom->set_node(1) = _mesh->node_ptr(5);
      elem_bottom->set_node(2) = _mesh->node_ptr(1);
      elem_bottom->set_node(3) = _mesh->node_ptr(0);

      Elem* edge = _mesh->add_elem( new Edge2 );
      edge->set_node(0) = _mesh->node_ptr(0);
      edge->set_node(1) = _mesh->node_ptr(1);

      // 2D elements will have subdomain id 0, this one will have 1
      edge->subdomain_id() = 1;
    }

    // libMesh will renumber, but we numbered according to its scheme
    // anyway. We do this because when we call uniformly_refine subsequenly,
    // it's going use skip_renumber=false.
    _mesh->prepare_for_use(false /*skip_renumber*/);
  }
Example #2
0
// Begin the main program.
int main (int argc, char** argv)
{
  // Initialize libMesh.
  LibMeshInit init (argc, argv);

  // Skip this 3D example if libMesh was compiled as 1D/2D-only.
  libmesh_example_requires (3 == LIBMESH_DIM, "3D support");

  // Skip this example without --enable-node-valence
#ifndef LIBMESH_ENABLE_NODE_VALENCE
  libmesh_example_requires (false, "--enable-node-valence");
#endif

  // Skip this example without --enable-amr; requires MeshRefinement
#ifndef LIBMESH_ENABLE_AMR
  libmesh_example_requires(false, "--enable-amr");
#else

  // Skip this example without --enable-second; requires d2phi
#ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES
  libmesh_example_requires(false, "--enable-second");
#else

  // Create a 2D mesh distributed across the default MPI communicator.
  // Subdivision surfaces do not appear to work with ParallelMesh yet.
  SerialMesh mesh (init.comm(), 2);

  // Read the coarse square mesh.
  mesh.read ("square_mesh.off");

  // Resize the square plate to edge length L.
  const Real L = 100.;
  MeshTools::Modification::scale(mesh, L, L, L);

  // Quadrisect the mesh triangles a few times to obtain a
  // finer mesh.  Subdivision surface elements require the
  // refinement data to be removed afterwards.
  MeshRefinement mesh_refinement (mesh);
  mesh_refinement.uniformly_refine (3);
  MeshTools::Modification::flatten (mesh);

  // Write the mesh before the ghost elements are added.
#if defined(LIBMESH_HAVE_VTK)
  VTKIO(mesh).write ("without_ghosts.pvtu");
#endif
#if defined(LIBMESH_HAVE_EXODUS_API)
  ExodusII_IO(mesh).write ("without_ghosts.e");
#endif

  // Print information about the triangulated mesh to the screen.
  mesh.print_info();

  // Turn the triangulated mesh into a subdivision mesh
  // and add an additional row of "ghost" elements around
  // it in order to complete the extended local support of
  // the triangles at the boundaries.  If the second
  // argument is set to true, the outermost existing
  // elements are converted into ghost elements, and the
  // actual physical mesh is thus getting smaller.
  MeshTools::Subdivision::prepare_subdivision_mesh (mesh, false);

  // Print information about the subdivision mesh to the screen.
  mesh.print_info();

  // Write the mesh with the ghost elements added.
  // Compare this to the original mesh to see the difference.
#if defined(LIBMESH_HAVE_VTK)
  VTKIO(mesh).write ("with_ghosts.pvtu");
#endif
#if defined(LIBMESH_HAVE_EXODUS_API)
  ExodusII_IO(mesh).write ("with_ghosts.e");
#endif

  // Create an equation systems object.
  EquationSystems equation_systems (mesh);

  // Declare the system and its variables.
  // Create a linear implicit system named "Shell".
  LinearImplicitSystem & system = equation_systems.add_system<LinearImplicitSystem> ("Shell");

  // Add the three translational deformation variables
  // "u", "v", "w" to "Shell".  Since subdivision shell
  // elements meet the C1-continuity requirement, no
  // rotational or other auxiliary variables are needed.
  // Loop Subdivision Elements are always interpolated
  // by quartic box splines, hence the order must always
  // be \p FOURTH.
  system.add_variable ("u", FOURTH, SUBDIVISION);
  system.add_variable ("v", FOURTH, SUBDIVISION);
  system.add_variable ("w", FOURTH, SUBDIVISION);

  // Give the system a pointer to the matrix and rhs assembly
  // function.
  system.attach_assemble_function (assemble_shell);

  // Use the parameters of the equation systems object to
  // tell the shell system about the material properties, the
  // shell thickness, and the external load.
  const Real h  = 1.;
  const Real E  = 1.e7;
  const Real nu = 0.;
  const Real q  = 1.;
  equation_systems.parameters.set<Real> ("thickness")       = h;
  equation_systems.parameters.set<Real> ("young's modulus") = E;
  equation_systems.parameters.set<Real> ("poisson ratio")   = nu;
  equation_systems.parameters.set<Real> ("uniform load")    = q;

  // 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 linear system.
  system.solve();

  // After solving the system, write the solution to a VTK
  // or ExodusII output file ready for import in, e.g.,
  // Paraview.
#if defined(LIBMESH_HAVE_VTK)
  VTKIO(mesh).write_equation_systems ("out.pvtu", equation_systems);
#endif
#if defined(LIBMESH_HAVE_EXODUS_API)
  ExodusII_IO(mesh).write_equation_systems ("out.e", equation_systems);
#endif

  // Find the center node to measure the maximum deformation of the plate.
  Node* center_node = 0;
  Real nearest_dist_sq = mesh.point(0).size_sq();
  for (unsigned int nid=1; nid<mesh.n_nodes(); ++nid)
  {
    const Real dist_sq = mesh.point(nid).size_sq();
    if (dist_sq < nearest_dist_sq)
    {
      nearest_dist_sq = dist_sq;
      center_node = mesh.node_ptr(nid);
    }
  }

  // Finally, we evaluate the z-displacement "w" at the center node.
  const unsigned int w_var = system.variable_number ("w");
  dof_id_type w_dof = center_node->dof_number (system.number(), w_var, 0);
  Number w = 0;
  if (w_dof >= system.get_dof_map().first_dof() &&
      w_dof <  system.get_dof_map().end_dof())
    w = system.current_solution(w_dof);
  system.comm().sum(w);


  // The analytic solution for the maximum displacement of
  // a clamped square plate in pure bending, from Taylor,
  // Govindjee, Commun. Numer. Meth. Eng. 20, 757-765, 2004.
  const Real D = E * h*h*h / (12*(1-nu*nu));
  const Real w_analytic = 0.001265319 * L*L*L*L * q / D;

  // Print the finite element solution and the analytic
  // prediction of the maximum displacement of the clamped
  // square plate to the screen.
  std::cout << "z-displacement of the center point: " << w << std::endl;
  std::cout << "Analytic solution for pure bending: " << w_analytic << std::endl;

#endif // #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES

#endif // #ifdef LIBMESH_ENABLE_AMR

  // All done.
  return 0;
}