<h1>Results</h1>

The program produces a series of <code>.eps</code> files of the
triangulations. The methods are discussed above.


<h3>Next steps: Curved boundaries</h3>

As mentioned in the introduction,
creating a coarse mesh using the methods discussed here is only the first
step. In order to refine a mesh, the Triangulation needs to know where to put
new vertices on the mid-points of edges and faces. By default, these new
points will be placed at the centers of the old edge but this isn't what you
want if you need curved boundaries that aren't already adequately resolved by
the coarse mesh. Several of the meshes shown in the introduction section fall
into this category. For example, for this mesh the central hole is supposed to
be round:

<img
 src="http://www.dealii.org/images/steps/developer/step-49.grid-2a.png"
 alt="" height="200px">

On the other hand, if you simply refine it, the Triangulation class can not
know whether you wanted the hole to be round or to be an octagon. The default
is to place new points along existing edges. After two mesh refinement steps,
this would yield the following mesh, which is not what we wanted:

<img
 src="http://www.dealii.org/images/steps/developer/step-49.grid-2d-refined.png"
 alt="" height="200px">

What needs to happen is that you tell the triangulation that you in fact want
to use a curved boundary. The way to do this requires three steps:
- Create an object that describes the boundary in terms that allow the
  Triangulation::execute_coarsening_and_refinement function to ask the
  boundary description where a new point should be located upon mesh
  refinement.
- Tell the triangulation object that you want this object to be used for all
  boundaries with boundary indicates equal to a particular value (for more
  information on boundary indicators, see the
  @ref GlossBoundaryIndicator "glossary entry on this topic".)
- Mark those parts of the boundary of the domain for which you want the
  boundary to be so treated with the value of the boundary indicator used in
  the previous step. (The order of this step and the previous one does not
  matter.)

To illustrate this process in more detail, let us consider an example created
by Yuhan Zhou as part of a 2013 semester project at Texas A&amp;M University.
The goal was to generate (and use) a geometry that describes a
microstructured electric device. In a CAD program, the geometry looks like
this:

<img
 src="http://www.dealii.org/images/steps/developer/step-49.yuhan.1.png"
 alt="">

In the following, we will walk you through the entire process of creating a
mesh for this geometry, including a number of common pitfalls by showing the
things that can go wrong.

The first step in getting there was to create a coarse mesh, which was done
by creating a 2d coarse mesh for each of the two cross section, extruding them
into the third direction, and gluing them together. The following code does
this, using the techniques previously described:

@code
// Given a list of points and how vertices connect to cells,
// create a mesh. This is in the same way as we do in step 14.
void create_2d_grid (const Point<2> vertices_1[],
	  	     const unsigned int n_vertices,
		     const int cell_vertices[][4],
		     const unsigned int n_cells,
                     Triangulation<2> &coarse_grid)
{
  const std::vector<Point<2> > vertices (&vertices_1[0],
			    	         &vertices_1[n_vertices]);

  std::vector<CellData<2> > cells (n_cells, CellData<2>());
  for (unsigned int i=0; i<n_cells; ++i)
    {
      for (unsigned int j=0;
	   j<GeometryInfo<2>::vertices_per_cell;
	   ++j)
	cells[i].vertices[j] = cell_vertices[i][j];
    }

  coarse_grid.create_triangulation (vertices,
				    cells,
				    SubCellData());
}


// Create a triangulation that covers the entire volume
void create_3d_grid (Triangulation<3> &triangulation)
{
  // Generate first cross section
  const Point<2> vertices_1[]
    = {  Point<2> (-1.5,   0.),
	 Point<2> (-0.5,   0.),
	 Point<2> ( 0.5,   0.),
	 Point<2> ( 1.5,   0.),

	 Point<2> (-1.5,  1.5),
	 Point<2> (-0.5,  1.5),
	 Point<2> ( 0.5,  1.5),
	 Point<2> ( 1.5,  1.5),

	 Point<2> (-1.5,   3.),
	 Point<2> (-0.5,   3.),
	 Point<2> ( 0.5,   3.),
	 Point<2> ( 1.5,   3.),

	 Point<2> (-0.5,   3+0.5*sqrt(3)),
	 Point<2> ( 0.5,   3+0.5*sqrt(3)),

	 Point<2> (-0.75,  3+0.75*sqrt(3)),
	 Point<2> ( 0.75,  3+0.75*sqrt(3))
  };
  const int cell_vertices_1[][GeometryInfo<2>::vertices_per_cell]
    = {{0, 1, 4, 5},
       {1, 2, 5, 6},
       {3, 7, 2, 6},
       {4, 5, 8, 9},
       {5, 6, 9, 10},
       {7,11, 6,10},
       {8, 9, 14,12},
       {9, 10,12,13},
       {11,15,10,13},
       {14,12,15,13}
  };

  // Copy vertices into a 2d triangulation
  Triangulation<2> triangulation_2d_1;
  create_2d_grid (vertices_1,
                  sizeof(vertices_1)/sizeof(vertices_1[0]),
		  cell_vertices_1,
                  sizeof(cell_vertices_1)/sizeof(cell_vertices_1[0]),
                  triangulation_2d_1);

  // Then extrude it into a 3d piece
  Triangulation<3> triangulation_3d_1;
  GridGenerator::extrude_triangulation (triangulation_2d_1,
                                        5, 2.5,
                                        triangulation_3d_1);

  // Now do the same with the second volume
  const Point<2> vertices_2[]
    = {  Point<2> (-2.5,   0.),
	 Point<2> (-1.5,   0.),
	 Point<2> (-0.5,   0.),
	 Point<2> ( 0.5,   0.),
	 Point<2> ( 1.5,   0.),
	 Point<2> ( 2.5,   0.),

	 Point<2> (-2.5,  1.5),
	 Point<2> (-1.5,  1.5),
	 Point<2> (-0.5,  1.5),
	 Point<2> ( 0.5,  1.5),
	 Point<2> ( 1.5,  1.5),
	 Point<2> ( 2.5,  1.5),

	 Point<2> (-2.5,  3.),
	 Point<2> (-1.5,  3.),
	 Point<2> (-0.5,  3.),
	 Point<2> ( 0.5,  3.),
	 Point<2> ( 1.5,  3.),
	 Point<2> ( 2.5,  3.),

	 Point<2> (-0.5,   3.+0.5*sqrt(3)),
	 Point<2> ( 0.5,   3.+0.5*sqrt(3)),

	 Point<2> (-0.75,  3.+0.75*sqrt(3)),
	 Point<2> ( 0.75,  3.+0.75*sqrt(3)),

	 Point<2> (-1.25,  3.+1.25*sqrt(3)),
	 Point<2> ( 1.25,  3.+1.25*sqrt(3))
  };
  const int cell_vertices_2[][GeometryInfo<2>::vertices_per_cell]
    = {{0, 1, 6, 7},
       {1, 2, 7, 8},
       {2, 3, 8, 9},
       {4, 10, 3, 9},
       {5, 11, 4, 10},
       {6, 7, 12, 13},
       {7, 8, 13, 14},
       {8, 9, 14, 15},
       {10, 16, 9, 15},
       {11, 17, 10, 16},
       {12, 13, 22, 20},
       {13, 14, 20, 18},
       {14, 15, 18, 19},
       {16, 21, 15, 19},
       {17, 23, 16, 21},
       {20, 18, 21, 19},
       {22, 20, 23, 21}
  };

  Triangulation<2> triangulation_2d_2;
  create_2d_grid (vertices_2,
                  sizeof(vertices_2)/sizeof(vertices_2[0]),
		  cell_vertices_2,
                  sizeof(cell_vertices_2)/sizeof(cell_vertices_2[0]),
                  triangulation_2d_2);

  Triangulation<3> triangulation_3d_2;
  GridGenerator::extrude_triangulation (triangulation_2d_2,
                                        5, 2.5,
                                        triangulation_3d_2);

  // Also shift this triangulation in the z-direction so
  // that it matches the end face of the first part
  GridTools::shift (Point<3>(0,0,2.5),
                    triangulation_3d_2);


  // Now first merge these two pieces, then shift the
  // first piece in z-direction beyond the second, and
  // merge the shifted piece with the two previously
  // merged one into the final one:
  Triangulation<3> triangulation_3d_tmp;
  GridGenerator::merge_triangulations (triangulation_3d_1,
                                       triangulation_3d_2,
                                       triangulation_3d_tmp);

  GridTools::shift (Point<3>(0,0,5),
                    triangulation_3d_1);

  GridGenerator::merge_triangulations (triangulation_3d_tmp,
                                       triangulation_3d_1,
                                       triangulation);
}
@endcode

With this code, you get a mesh that looks like this:

<img
 src="http://www.dealii.org/images/steps/developer/step-49.yuhan.2.png"
 alt="">

The next step is to teach each of the top surfaces that they should be
curved. We can do this by creating CylinderBoundary objects that
describe this. A first attempt looks like this:

@code
  Triangulation<3> triangulation;
  create_3d_grid (triangulation);

  // Create the objects that describe the boundaries and attach them
  // to the triangulation as the ones to use on boundaries marked
  // with boundary indicators 8 and 9
  const double inner_radius = 1.5;
  const double outer_radius = 2.5;

  static const CylinderBoundary<3> inner_cylinder(inner_radius, 2);
  static const CylinderBoundary<3> outer_cylinder(outer_radius, 2);

  triangulation.set_boundary (8, inner_cylinder);
  triangulation.set_boundary (9, outer_cylinder);

  // Then loop over all faces of the domain and, if for the position
  // of the center of a face the following holds then set boundary
  // indicators:
  // - if y>3 and z<=2.5 or z>=5 then use boundary indicator 8
  // - if y>3 and 2.5<=z<=5 then use boundary indicator 9
  typename Triangulation<3>::active_cell_iterator
    cell = triangulation.begin_active(),
    endc = triangulation.end();
  for (; cell!=endc; ++cell)
    for (unsigned int f=0;
	 f < GeometryInfo<3>::faces_per_cell;
	 ++f)
      {
	const Point<3> face_center = cell->face(f)->center();

	if (cell->face(f)->at_boundary())
	  {
	    if ((face_center[2] <= 2.5 || face_center[2] >= 5) &&
	        face_center[1] >= 3)
	      cell->face(f)->set_boundary_indicator(8);

	    if (face_center[2] >= 2.5 &&
	        face_center[2] <= 5
	        && face_center[1] >= 3)
	      cell->face(f)->set_boundary_indicator(9);
	  }
      }

  // Then refine the mesh once
  triangulation.refine_global (1);
@endcode

With this code, we get a mesh that looks like this:

<img
 src="http://www.dealii.org/images/steps/developer/step-49.yuhan.3.png"
 alt="">

This is clearly not correct: The new vertices that have been entered at
mid-edge and mid-face points are not where they should have been. Upon some
reflection, it turns out that while the radii of the cylinders are correct,
the axes of the two cylinder objects should not have been along coordinate
axes but shifted. This can be corrected by creating them as follows, the
two points given as arguments indicating the direction and a point on the
axis:

@code
  static const CylinderBoundary<3> inner_cylinder (inner_radius,
                                                   Point<3>(0,0,1),
                                                   Point<3>(0,3,0));
  static const CylinderBoundary<3> outer_cylinder (outer_radius,
                                                   Point<3>(0,0,1),
                                                   Point<3>(0,3,0));
  triangulation.set_boundary (9, outer_cylinder);
@endcode

This yields an improvement, though it is still not quite correct:

<img
 src="http://www.dealii.org/images/steps/developer/step-49.yuhan.4.png"
 alt="">

Looking closely at this mesh, we realize that the new points on mid-face
vertices are where they should be, though the new vertices inserted at
mid-edge points are in the wrong place (you see this by comparing the
picture with the one of the coarse mesh). What is happening is that we
are only telling the triangulation to use these geometry objects for
the <i>faces</i> but not for the adjacent <i>edges</i> as well. This is
easily fixed by using the function TriaAccessor::set_all_boundary_indicators()
instead of TriaAccessor::set_boundary_indicator() used above. With this change,
the grid now looks like this:

<img
 src="http://www.dealii.org/images/steps/developer/step-49.yuhan.5.png"
 alt="">

This is already better. However, something is still going wrong on the
front left face. On second look, we can also see that the faces where
the geometry widens have been refined at the bottom, that there is one
transition face that looks wrong because it has a triangle rather than
a quadrilateral, and that finally the transition faces in the cylindrical
region appear not to have been refined at all in radial direction.

This due to the fact that we have (erroneously) marked all boundary faces
between $0\le z\le 2.5$ with the boundary indicator for the small cylinder
and similarly for the other regions. This condition includes the faces parallel
to the x-y plane. To fix it, we need to exclude faces whose center points have
$z$ values equal to (or at least close to, since we should not compare
for equality in floating point arithmetic) 0, 2.5, 5 or 7.5. This replacement
code does the trick:

@code
  // Then loop over all faces of the domain and, if for the position
  // of the center of a face the following holds then set boundary
  // indicators:
  // - if y>3 and z<2.5 or z>5 then use boundary indicator 8
  // - if y>3 and 2.5<z<5 then use boundary indicator 9
  // In this process, exclude faces whose z-coordinates are
  // within a small distance of z=0, z=2.5, z=5 or z=7.5.
  typename Triangulation<3>::active_cell_iterator
    cell = triangulation.begin_active(),
    endc = triangulation.end();
  for (; cell!=endc; ++cell)
    for (unsigned int f=0;
         f < GeometryInfo<3>::faces_per_cell;
         ++f)
      {
        const Point<3> face_center = cell->face(f)->center();

        if (cell->face(f)->at_boundary())
          if ((face_center[2]>1e-6) &&
              (face_center[2]<7.5-1e-6) &&
              (std::fabs(face_center[2]-2.5)>1e-6) &&
              (std::fabs(face_center[2]-5.0)>1e-6))
            {
              if ((face_center[2] < 2.5 || face_center[2] > 5)
                  && face_center[1] >= 3)
                cell->face(f)->set_all_boundary_indicators(8);

              if (face_center[2] > 2.5 && face_center[2] < 5
                  && face_center[1] >= 3)
                cell->face(f)->set_all_boundary_indicators(9);
            }
      }
}
@endcode

With this, we finally get a mesh that looks good:

<img
 src="http://www.dealii.org/images/steps/developer/step-49.yuhan.6.png"
 alt="">

We can then refine the mesh two more times to see in more detail what
happens to the curved part of the boundary:

 <img
 src="http://www.dealii.org/images/steps/developer/step-49.yuhan.7.png"
 alt="">

 So, yes!, this is finally what we were looking for!
