]> https://gitweb.dealii.org/ - dealii-svn.git/commitdiff
Move things local to each program into a local namespace.
authorbangerth <bangerth@0785d39b-7218-0410-832d-ea1e28bc413d>
Fri, 9 Sep 2011 03:55:52 +0000 (03:55 +0000)
committerbangerth <bangerth@0785d39b-7218-0410-832d-ea1e28bc413d>
Fri, 9 Sep 2011 03:55:52 +0000 (03:55 +0000)
git-svn-id: https://svn.dealii.org/trunk@24293 0785d39b-7218-0410-832d-ea1e28bc413d

deal.II/examples/step-30/step-30.cc
deal.II/examples/step-31/step-31.cc
deal.II/examples/step-33/step-33.cc
deal.II/examples/step-34/step-34.cc
deal.II/examples/step-35/step-35.cc
deal.II/examples/step-36/step-36.cc
deal.II/examples/step-38/step-38.cc
deal.II/examples/step-39/step-39.cc

index 8d096406a65c3cfa3ec8623df12bea0ddeda98c2..bf85b9f58b2e969ebfe4b8decfc351d896235424 100644 (file)
@@ -4,7 +4,7 @@
 /*    $Id$       */
 /*    Version: $Name$                                          */
 /*                                                                */
-/*    Copyright (C) 2007, 2008 by the deal.II authors */
+/*    Copyright (C) 2007, 2008, 2011 by the deal.II authors */
 /*                                                                */
 /*    This file is subject to QPL and may not be  distributed     */
 /*    without copyright and license information. Please refer     */
 
                                 // The last step is as in all
                                 // previous programs:
-using namespace dealii;
-
-                                // @sect3{Equation data}
-                                //
-                                // The classes describing equation data and the
-                                // actual assembly of individual terms are
-                                // almost entirely copied from step-12. We will
-                                // comment on differences.
-template <int dim>
-class RHS:  public Function<dim>
+namespace Step30
 {
-  public:
-    virtual void value_list (const std::vector<Point<dim> > &points,
-                            std::vector<double> &values,
-                            const unsigned int component=0) const;
-};
-
-
-template <int dim>
-class BoundaryValues:  public Function<dim>
-{
-  public:
-    virtual void value_list (const std::vector<Point<dim> > &points,
-                            std::vector<double> &values,
-                            const unsigned int component=0) const;
-};
-
-
-template <int dim>
-class Beta
-{
-  public:
-    Beta () {}
-    void value_list (const std::vector<Point<dim> > &points,
-                    std::vector<Point<dim> > &values) const;
-};
-
-
-template <int dim>
-void RHS<dim>::value_list(const std::vector<Point<dim> > &points,
-                         std::vector<double> &values,
-                         const unsigned int) const
-{
-  Assert(values.size()==points.size(),
-        ExcDimensionMismatch(values.size(),points.size()));
-
-  for (unsigned int i=0; i<values.size(); ++i)
-    values[i]=0;
-}
-
-
-                                // The flow field is chosen to be a
-                                // quarter circle with
-                                // counterclockwise flow direction
-                                // and with the origin as midpoint
-                                // for the right half of the domain
-                                // with positive $x$ values, whereas
-                                // the flow simply goes to the left
-                                // in the left part of the domain at
-                                // a velocity that matches the one
-                                // coming in from the right. In the
-                                // circular part the magnitude of the
-                                // flow velocity is proportional to
-                                // the distance from the origin. This
-                                // is a difference to step-12, where
-                                // the magnitude was 1
-                                // evereywhere. the new definition
-                                // leads to a linear variation of
-                                // $\beta$ along each given face of a
-                                // cell. On the other hand, the
-                                // solution $u(x,y)$ is exactly the
-                                // same as before.
-template <int dim>
-void Beta<dim>::value_list(const std::vector<Point<dim> > &points,
-                          std::vector<Point<dim> > &values) const
-{
-  Assert(values.size()==points.size(),
-        ExcDimensionMismatch(values.size(),points.size()));
-
-  for (unsigned int i=0; i<points.size(); ++i)
-    {
-      if (points[i](0) > 0)
-       {
-         values[i](0) = -points[i](1);
-         values[i](1) = points[i](0);
-       }
-      else
-       {
-         values[i] = Point<dim>();
-         values[i](0) = -points[i](1);
-       }
-    }
-}
+  using namespace dealii;
+
+                                  // @sect3{Equation data}
+                                  //
+                                  // The classes describing equation data and the
+                                  // actual assembly of individual terms are
+                                  // almost entirely copied from step-12. We will
+                                  // comment on differences.
+  template <int dim>
+  class RHS:  public Function<dim>
+  {
+    public:
+      virtual void value_list (const std::vector<Point<dim> > &points,
+                              std::vector<double> &values,
+                              const unsigned int component=0) const;
+  };
+
+
+  template <int dim>
+  class BoundaryValues:  public Function<dim>
+  {
+    public:
+      virtual void value_list (const std::vector<Point<dim> > &points,
+                              std::vector<double> &values,
+                              const unsigned int component=0) const;
+  };
+
+
+  template <int dim>
+  class Beta
+  {
+    public:
+      Beta () {}
+      void value_list (const std::vector<Point<dim> > &points,
+                      std::vector<Point<dim> > &values) const;
+  };
+
+
+  template <int dim>
+  void RHS<dim>::value_list(const std::vector<Point<dim> > &points,
+                           std::vector<double> &values,
+                           const unsigned int) const
+  {
+    Assert(values.size()==points.size(),
+          ExcDimensionMismatch(values.size(),points.size()));
+
+    for (unsigned int i=0; i<values.size(); ++i)
+      values[i]=0;
+  }
+
+
+                                  // The flow field is chosen to be a
+                                  // quarter circle with
+                                  // counterclockwise flow direction
+                                  // and with the origin as midpoint
+                                  // for the right half of the domain
+                                  // with positive $x$ values, whereas
+                                  // the flow simply goes to the left
+                                  // in the left part of the domain at
+                                  // a velocity that matches the one
+                                  // coming in from the right. In the
+                                  // circular part the magnitude of the
+                                  // flow velocity is proportional to
+                                  // the distance from the origin. This
+                                  // is a difference to step-12, where
+                                  // the magnitude was 1
+                                  // evereywhere. the new definition
+                                  // leads to a linear variation of
+                                  // $\beta$ along each given face of a
+                                  // cell. On the other hand, the
+                                  // solution $u(x,y)$ is exactly the
+                                  // same as before.
+  template <int dim>
+  void Beta<dim>::value_list(const std::vector<Point<dim> > &points,
+                            std::vector<Point<dim> > &values) const
+  {
+    Assert(values.size()==points.size(),
+          ExcDimensionMismatch(values.size(),points.size()));
+
+    for (unsigned int i=0; i<points.size(); ++i)
+      {
+       if (points[i](0) > 0)
+         {
+           values[i](0) = -points[i](1);
+           values[i](1) = points[i](0);
+         }
+       else
+         {
+           values[i] = Point<dim>();
+           values[i](0) = -points[i](1);
+         }
+      }
+  }
 
 
-template <int dim>
-void BoundaryValues<dim>::value_list(const std::vector<Point<dim> > &points,
+  template <int dim>
+  void BoundaryValues<dim>::value_list(const std::vector<Point<dim> > &points,
                                       std::vector<double> &values,
                                       const unsigned int) const
-{
-  Assert(values.size()==points.size(),
-        ExcDimensionMismatch(values.size(),points.size()));
+  {
+    Assert(values.size()==points.size(),
+          ExcDimensionMismatch(values.size(),points.size()));
 
-  for (unsigned int i=0; i<values.size(); ++i)
-    {
-      if (points[i](0)<0.5)
-       values[i]=1.;
-      else
-       values[i]=0.;
-    }
-}
-
-
-                                // @sect3{Class: DGTransportEquation}
-                                //
-                                // This declaration of this 
-                                // class is utterly unaffected by our
-                                // current changes.  The only
-                                // substantial change is that we use
-                                // only the second assembly scheme
-                                // described in step-12.
-template <int dim>
-class DGTransportEquation
-{
-  public:
-    DGTransportEquation();
-
-    void assemble_cell_term(const FEValues<dim>& fe_v,
-                           FullMatrix<double> &ui_vi_matrix,
-                           Vector<double> &cell_vector) const;
-    
-    void assemble_boundary_term(const FEFaceValues<dim>& fe_v,
-                               FullMatrix<double> &ui_vi_matrix,
-                               Vector<double> &cell_vector) const;
-    
-    void assemble_face_term2(const FEFaceValuesBase<dim>& fe_v,
-                            const FEFaceValuesBase<dim>& fe_v_neighbor,
-                            FullMatrix<double> &ui_vi_matrix,
-                            FullMatrix<double> &ue_vi_matrix,
-                            FullMatrix<double> &ui_ve_matrix,
-                            FullMatrix<double> &ue_ve_matrix) const;
-  private:
-    const Beta<dim> beta_function;
-    const RHS<dim> rhs_function;
-    const BoundaryValues<dim> boundary_function;
-};
-
-
-                                // Likewise, the constructor of the
-                                // class as well as the functions
-                                // assembling the terms corresponding
-                                // to cell interiors and boundary
-                                // faces are unchanged from
-                                // before. The function that
-                                // assembles face terms between cells
-                                // also did not change because all it
-                                // does is operate on two objects of
-                                // type FEFaceValuesBase (which is
-                                // the base class of both
-                                // FEFaceValues and
-                                // FESubfaceValues). Where these
-                                // objects come from, i.e. how they
-                                // are initialized, is of no concern
-                                // to this function: it simply
-                                // assumes that the quadrature points
-                                // on faces or subfaces represented
-                                // by the two objects correspond to
-                                // the same points in physical space.
-template <int dim>
-DGTransportEquation<dim>::DGTransportEquation ()
-               :
-               beta_function (),
-               rhs_function (),
-               boundary_function ()
-{}
-
-
-template <int dim>
-void DGTransportEquation<dim>::assemble_cell_term(
-  const FEValues<dim> &fe_v,
-  FullMatrix<double> &ui_vi_matrix,
-  Vector<double> &cell_vector) const
-{
-  const std::vector<double> &JxW = fe_v.get_JxW_values ();
-
-  std::vector<Point<dim> > beta (fe_v.n_quadrature_points);
-  std::vector<double> rhs (fe_v.n_quadrature_points);
-  
-  beta_function.value_list (fe_v.get_quadrature_points(), beta);
-  rhs_function.value_list (fe_v.get_quadrature_points(), rhs);
-  
-  for (unsigned int point=0; point<fe_v.n_quadrature_points; ++point)
-    for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i) 
+    for (unsigned int i=0; i<values.size(); ++i)
       {
-       for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
-         ui_vi_matrix(i,j) -= beta[point]*fe_v.shape_grad(i,point)*
-                             fe_v.shape_value(j,point) *
-                             JxW[point];
-       
-       cell_vector(i) += rhs[point] * fe_v.shape_value(i,point) * JxW[point];
+       if (points[i](0)<0.5)
+         values[i]=1.;
+       else
+         values[i]=0.;
       }
-}
-
-
-template <int dim>
-void DGTransportEquation<dim>::assemble_boundary_term(
-  const FEFaceValues<dim>& fe_v,    
-  FullMatrix<double> &ui_vi_matrix,
-  Vector<double> &cell_vector) const
-{
-  const std::vector<double> &JxW = fe_v.get_JxW_values ();
-  const std::vector<Point<dim> > &normals = fe_v.get_normal_vectors ();
-
-  std::vector<Point<dim> > beta (fe_v.n_quadrature_points);
-  std::vector<double> g(fe_v.n_quadrature_points);
-  
-  beta_function.value_list (fe_v.get_quadrature_points(), beta);
-  boundary_function.value_list (fe_v.get_quadrature_points(), g);
-
-  for (unsigned int point=0; point<fe_v.n_quadrature_points; ++point)
-    {
-      const double beta_n=beta[point] * normals[point];      
-      if (beta_n>0)
-       for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
-         for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
-           ui_vi_matrix(i,j) += beta_n *
-                              fe_v.shape_value(j,point) *
-                              fe_v.shape_value(i,point) *
-                              JxW[point];
-      else 
-       for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
-         cell_vector(i) -= beta_n *
-                           g[point] *
-                           fe_v.shape_value(i,point) *
-                           JxW[point];
-    }
-}
-
-
-template <int dim>
-void DGTransportEquation<dim>::assemble_face_term2(
-  const FEFaceValuesBase<dim>& fe_v,
-  const FEFaceValuesBase<dim>& fe_v_neighbor,      
-  FullMatrix<double> &ui_vi_matrix,
-  FullMatrix<double> &ue_vi_matrix,
-  FullMatrix<double> &ui_ve_matrix,
-  FullMatrix<double> &ue_ve_matrix) const
-{
-  const std::vector<double> &JxW = fe_v.get_JxW_values ();
-  const std::vector<Point<dim> > &normals = fe_v.get_normal_vectors ();
-
-  std::vector<Point<dim> > beta (fe_v.n_quadrature_points);
-  
-  beta_function.value_list (fe_v.get_quadrature_points(), beta);
-
-  for (unsigned int point=0; point<fe_v.n_quadrature_points; ++point)
-    {
-      const double beta_n=beta[point] * normals[point];
-      if (beta_n>0)
+  }
+
+
+                                  // @sect3{Class: DGTransportEquation}
+                                  //
+                                  // This declaration of this
+                                  // class is utterly unaffected by our
+                                  // current changes.  The only
+                                  // substantial change is that we use
+                                  // only the second assembly scheme
+                                  // described in step-12.
+  template <int dim>
+  class DGTransportEquation
+  {
+    public:
+      DGTransportEquation();
+
+      void assemble_cell_term(const FEValues<dim>& fe_v,
+                             FullMatrix<double> &ui_vi_matrix,
+                             Vector<double> &cell_vector) const;
+
+      void assemble_boundary_term(const FEFaceValues<dim>& fe_v,
+                                 FullMatrix<double> &ui_vi_matrix,
+                                 Vector<double> &cell_vector) const;
+
+      void assemble_face_term2(const FEFaceValuesBase<dim>& fe_v,
+                              const FEFaceValuesBase<dim>& fe_v_neighbor,
+                              FullMatrix<double> &ui_vi_matrix,
+                              FullMatrix<double> &ue_vi_matrix,
+                              FullMatrix<double> &ui_ve_matrix,
+                              FullMatrix<double> &ue_ve_matrix) const;
+    private:
+      const Beta<dim> beta_function;
+      const RHS<dim> rhs_function;
+      const BoundaryValues<dim> boundary_function;
+  };
+
+
+                                  // Likewise, the constructor of the
+                                  // class as well as the functions
+                                  // assembling the terms corresponding
+                                  // to cell interiors and boundary
+                                  // faces are unchanged from
+                                  // before. The function that
+                                  // assembles face terms between cells
+                                  // also did not change because all it
+                                  // does is operate on two objects of
+                                  // type FEFaceValuesBase (which is
+                                  // the base class of both
+                                  // FEFaceValues and
+                                  // FESubfaceValues). Where these
+                                  // objects come from, i.e. how they
+                                  // are initialized, is of no concern
+                                  // to this function: it simply
+                                  // assumes that the quadrature points
+                                  // on faces or subfaces represented
+                                  // by the two objects correspond to
+                                  // the same points in physical space.
+  template <int dim>
+  DGTransportEquation<dim>::DGTransportEquation ()
+                 :
+                 beta_function (),
+                 rhs_function (),
+                 boundary_function ()
+  {}
+
+
+  template <int dim>
+  void DGTransportEquation<dim>::assemble_cell_term(
+    const FEValues<dim> &fe_v,
+    FullMatrix<double> &ui_vi_matrix,
+    Vector<double> &cell_vector) const
+  {
+    const std::vector<double> &JxW = fe_v.get_JxW_values ();
+
+    std::vector<Point<dim> > beta (fe_v.n_quadrature_points);
+    std::vector<double> rhs (fe_v.n_quadrature_points);
+
+    beta_function.value_list (fe_v.get_quadrature_points(), beta);
+    rhs_function.value_list (fe_v.get_quadrature_points(), rhs);
+
+    for (unsigned int point=0; point<fe_v.n_quadrature_points; ++point)
+      for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
        {
-         for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
-           for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
-             ui_vi_matrix(i,j) += beta_n *
+         for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
+           ui_vi_matrix(i,j) -= beta[point]*fe_v.shape_grad(i,point)*
                                 fe_v.shape_value(j,point) *
-                                fe_v.shape_value(i,point) *
                                 JxW[point];
 
-         for (unsigned int k=0; k<fe_v_neighbor.dofs_per_cell; ++k)
-           for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
-             ui_ve_matrix(k,j) -= beta_n *
-                                 fe_v.shape_value(j,point) *
-                                 fe_v_neighbor.shape_value(k,point) *
-                                 JxW[point];
+         cell_vector(i) += rhs[point] * fe_v.shape_value(i,point) * JxW[point];
        }
-      else
-       {
-         for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
-           for (unsigned int l=0; l<fe_v_neighbor.dofs_per_cell; ++l)
-             ue_vi_matrix(i,l) += beta_n *
-                                 fe_v_neighbor.shape_value(l,point) *
-                                 fe_v.shape_value(i,point) *
-                                 JxW[point];
-
-         for (unsigned int k=0; k<fe_v_neighbor.dofs_per_cell; ++k)
-           for (unsigned int l=0; l<fe_v_neighbor.dofs_per_cell; ++l)
-             ue_ve_matrix(k,l) -= beta_n *
-                                  fe_v_neighbor.shape_value(l,point) *
-                                  fe_v_neighbor.shape_value(k,point) *
-                                  JxW[point];
-       }
-    }
-}
-
-
-                                // @sect3{Class: DGMethod}
-                                //
-                                // Even the main class of this
-                                // program stays more or less the
-                                // same. We omit one of the assembly
-                                // routines and use only the second,
-                                // more effective one of the two
-                                // presented in step-12. However, we
-                                // introduce a new routine
-                                // (set_anisotropic_flags) and modify
-                                // another one (refine_grid).
-template <int dim>
-class DGMethod
-{
-  public:
-    DGMethod (const bool anisotropic);
-    ~DGMethod ();
-
-    void run ();
-    
-  private:
-    void setup_system ();
-    void assemble_system1 ();
-    void assemble_system2 ();
-    void solve (Vector<double> &solution);
-    void refine_grid ();
-    void set_anisotropic_flags ();
-    void output_results (const unsigned int cycle) const;
-
-    Triangulation<dim>   triangulation;
-    const MappingQ1<dim> mapping;
-                                    // Again we want to use DG elements of
-                                    // degree 1 (but this is only specified in
-                                    // the constructor). If you want to use a
-                                    // DG method of a different degree replace
-                                    // 1 in the constructor by the new degree.
-    const unsigned int   degree;    
-    FE_DGQ<dim>          fe;
-    DoFHandler<dim>      dof_handler;
-
-    SparsityPattern      sparsity_pattern;
-    SparseMatrix<double> system_matrix;
-                                    // This is new, the threshold value used in
-                                    // the evaluation of the anisotropic jump
-                                    // indicator explained in the
-                                    // introduction. Its value is set to 3.0 in
-                                    // the constructor, but it can easily be
-                                    // changed to a different value greater
-                                    // than 1.
-    const double anisotropic_threshold_ratio;
-                                    // This is a bool flag indicating whether
-                                    // anisotropic refinement shall be used or
-                                    // not. It is set by the constructor, which
-                                    // takes an argument of the same name.
-    const bool anisotropic;
-    
-    const QGauss<dim>   quadrature;
-    const QGauss<dim-1> face_quadrature;
-    
-    Vector<double>       solution2;
-    Vector<double>       right_hand_side;
-    
-    const DGTransportEquation<dim> dg;
-};
-
-
-template <int dim>
-DGMethod<dim>::DGMethod (const bool anisotropic)
-               :
-               mapping (),
-                                                // Change here for DG
-                                                // methods of
-                                                // different degrees.
-               degree(1),
-               fe (degree),
-               dof_handler (triangulation),
-               anisotropic_threshold_ratio(3.),
-               anisotropic(anisotropic),
-                                                // As beta is a
-                                                // linear function,
-                                                // we can choose the
-                                                // degree of the
-                                                // quadrature for
-                                                // which the
-                                                // resulting
-                                                // integration is
-                                                // correct. Thus, we
-                                                // choose to use
-                                                // <code>degree+1</code>
-                                                // gauss points,
-                                                // which enables us
-                                                // to integrate
-                                                // exactly
-                                                // polynomials of
-                                                // degree
-                                                // <code>2*degree+1</code>,
-                                                // enough for all the
-                                                // integrals we will
-                                                // perform in this
-                                                // program.
-               quadrature (degree+1),
-               face_quadrature (degree+1),
-               dg ()
-{}
-
-
-template <int dim>
-DGMethod<dim>::~DGMethod () 
-{
-  dof_handler.clear ();
-}
-
-
-template <int dim>
-void DGMethod<dim>::setup_system ()
-{
-  dof_handler.distribute_dofs (fe);
-  sparsity_pattern.reinit (dof_handler.n_dofs(),
-                          dof_handler.n_dofs(),
-                          (GeometryInfo<dim>::faces_per_cell
-                           *GeometryInfo<dim>::max_children_per_face+1)*fe.dofs_per_cell);
-
-  DoFTools::make_flux_sparsity_pattern (dof_handler, sparsity_pattern);
-  
-  sparsity_pattern.compress();
-  
-  system_matrix.reinit (sparsity_pattern);
-
-  solution2.reinit (dof_handler.n_dofs());
-  right_hand_side.reinit (dof_handler.n_dofs());
-}
+  }
 
 
-                                // @sect4{Function: assemble_system2}
-                                //
-                                // We proceed with the
-                                // <code>assemble_system2</code> function that
-                                // implements the DG discretization in its
-                                // second version. This function is very
-                                // similar to the <code>assemble_system2</code>
-                                // function from step-12, even the four cases
-                                // considered for the neighbor-relations of a
-                                // cell are the same, namely a) cell is at the
-                                // boundary, b) there are finer neighboring
-                                // cells, c) the neighbor is neither coarser
-                                // nor finer and d) the neighbor is coarser.
-                                // However, the way in which we decide upon
-                                // which case we have are modified in the way
-                                // described in the introduction.
-template <int dim>
-void DGMethod<dim>::assemble_system2 () 
-{
-  const unsigned int dofs_per_cell = dof_handler.get_fe().dofs_per_cell;
-  std::vector<unsigned int> dofs (dofs_per_cell);
-  std::vector<unsigned int> dofs_neighbor (dofs_per_cell);
-
-  const UpdateFlags update_flags = update_values
-                                   | update_gradients
-                                   | update_quadrature_points
-                                   | update_JxW_values;
-  
-  const UpdateFlags face_update_flags = update_values
-                                        | update_quadrature_points
-                                        | update_JxW_values
-                                        | update_normal_vectors;
-  
-  const UpdateFlags neighbor_face_update_flags = update_values;
-
-  FEValues<dim> fe_v (
-    mapping, fe, quadrature, update_flags);
-  FEFaceValues<dim> fe_v_face (
-    mapping, fe, face_quadrature, face_update_flags);
-  FESubfaceValues<dim> fe_v_subface (
-    mapping, fe, face_quadrature, face_update_flags);
-  FEFaceValues<dim> fe_v_face_neighbor (
-    mapping, fe, face_quadrature, neighbor_face_update_flags);
-
-
-  FullMatrix<double> ui_vi_matrix (dofs_per_cell, dofs_per_cell);
-  FullMatrix<double> ue_vi_matrix (dofs_per_cell, dofs_per_cell);
-  
-  FullMatrix<double> ui_ve_matrix (dofs_per_cell, dofs_per_cell);
-  FullMatrix<double> ue_ve_matrix (dofs_per_cell, dofs_per_cell);
-  
-  Vector<double>  cell_vector (dofs_per_cell);
-
-  typename DoFHandler<dim>::active_cell_iterator
-    cell = dof_handler.begin_active(),
-    endc = dof_handler.end();
-  for (;cell!=endc; ++cell) 
-    {
-      ui_vi_matrix = 0;
-      cell_vector = 0;
-
-      fe_v.reinit (cell);
+  template <int dim>
+  void DGTransportEquation<dim>::assemble_boundary_term(
+    const FEFaceValues<dim>& fe_v,
+    FullMatrix<double> &ui_vi_matrix,
+    Vector<double> &cell_vector) const
+  {
+    const std::vector<double> &JxW = fe_v.get_JxW_values ();
+    const std::vector<Point<dim> > &normals = fe_v.get_normal_vectors ();
 
-      dg.assemble_cell_term(fe_v,
-                           ui_vi_matrix,
-                           cell_vector);
-      
-      cell->get_dof_indices (dofs);
-
-      for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell; ++face_no)
-       {
-         typename DoFHandler<dim>::face_iterator face=
-           cell->face(face_no);
+    std::vector<Point<dim> > beta (fe_v.n_quadrature_points);
+    std::vector<double> g(fe_v.n_quadrature_points);
 
-                                          // Case a)
-         if (face->at_boundary())
-           {
-             fe_v_face.reinit (cell, face_no);
+    beta_function.value_list (fe_v.get_quadrature_points(), beta);
+    boundary_function.value_list (fe_v.get_quadrature_points(), g);
 
-             dg.assemble_boundary_term(fe_v_face,
-                                       ui_vi_matrix,
-                                       cell_vector);
-           }
-         else
-           {
-             Assert (cell->neighbor(face_no).state() == IteratorState::valid,
-                     ExcInternalError());
-             typename DoFHandler<dim>::cell_iterator neighbor=
-               cell->neighbor(face_no);
-                                              // Case b), we decide that there
-                                              // are finer cells as neighbors
-                                              // by asking the face, whether it
-                                              // has children. if so, then
-                                              // there must also be finer cells
-                                              // which are children or farther
-                                              // offsprings of our neighbor.
-             if (face->has_children())
-               {
-                                                  // We need to know, which of
-                                                  // the neighbors faces points
-                                                  // in the direction of our
-                                                  // cell. Using the @p
-                                                  // neighbor_face_no function
-                                                  // we get this information
-                                                  // for both coarser and
-                                                  // non-coarser neighbors.
-                 const unsigned int neighbor2=
-                   cell->neighbor_face_no(face_no);
-
-                                                  // Now we loop over all
-                                                  // subfaces, i.e. the
-                                                  // children and possibly
-                                                  // grandchildren of the
-                                                  // current face.
-                 for (unsigned int subface_no=0;
-                      subface_no<face->number_of_children(); ++subface_no)
-                   {
-                                                      // To get the cell behind
-                                                      // the current subface we
-                                                      // can use the @p
-                                                      // neighbor_child_on_subface
-                                                      // function. it takes
-                                                      // care of all the
-                                                      // complicated situations
-                                                      // of anisotropic
-                                                      // refinement and
-                                                      // non-standard faces.
-                     typename DoFHandler<dim>::cell_iterator neighbor_child
-                        = cell->neighbor_child_on_subface (face_no, subface_no);
-                     Assert (!neighbor_child->has_children(), ExcInternalError());
-
-                                                      // The remaining part of
-                                                      // this case is
-                                                      // unchanged.
-                     ue_vi_matrix = 0;
-                     ui_ve_matrix = 0;
-                     ue_ve_matrix = 0;
-                     
-                     fe_v_subface.reinit (cell, face_no, subface_no);
-                     fe_v_face_neighbor.reinit (neighbor_child, neighbor2);
-
-                     dg.assemble_face_term2(fe_v_subface,
-                                            fe_v_face_neighbor,
-                                            ui_vi_matrix,
-                                            ue_vi_matrix,
-                                            ui_ve_matrix,
-                                            ue_ve_matrix);
-                 
-                     neighbor_child->get_dof_indices (dofs_neighbor);
-                                                               
-                     for (unsigned int i=0; i<dofs_per_cell; ++i)
-                       for (unsigned int j=0; j<dofs_per_cell; ++j)
-                         {
-                           system_matrix.add(dofs[i], dofs_neighbor[j],
-                                             ue_vi_matrix(i,j));
-                           system_matrix.add(dofs_neighbor[i], dofs[j],
-                                             ui_ve_matrix(i,j));
-                           system_matrix.add(dofs_neighbor[i], dofs_neighbor[j],
-                                             ue_ve_matrix(i,j));
-                         }
-                   }
-               }
-             else
-               {
-                                                  // Case c). We simply ask,
-                                                  // whether the neighbor is
-                                                  // coarser. If not, then it
-                                                  // is neither coarser nor
-                                                  // finer, since finer
-                                                  // neighbor would have been
-                                                  // reated above withz case
-                                                  // b). Of all the cases with
-                                                  // thesame refinement
-                                                  // situation of our cell and
-                                                  // the neighbor we want to
-                                                  // treat only one half, so
-                                                  // that each face is
-                                                  // considered only once. Thus
-                                                  // we have the additional
-                                                  // condition, that the cell
-                                                  // with the lower index does
-                                                  // the work. In the rare case
-                                                  // that both cells have the
-                                                  // same index, the cell with
-                                                  // lower level is selected.
-                 if (!cell->neighbor_is_coarser(face_no) &&
-                     (neighbor->index() > cell->index() ||
-                     (neighbor->level() < cell->level() &&
-                      neighbor->index() == cell->index())))
-                   {
-                                                      // Here we know, that the
-                                                      // neigbor is not coarser
-                                                      // so we can use the
-                                                      // usual @p
-                                                      // neighbor_of_neighbor
-                                                      // function. However, we
-                                                      // could also use the
-                                                      // more general @p
-                                                      // neighbor_face_no
-                                                      // function.
-                     const unsigned int neighbor2=cell->neighbor_of_neighbor(face_no);
-                     
-                     ue_vi_matrix = 0;
-                     ui_ve_matrix = 0;
-                     ue_ve_matrix = 0;
-                     
-                     fe_v_face.reinit (cell, face_no);
-                     fe_v_face_neighbor.reinit (neighbor, neighbor2);
-                     
-                     dg.assemble_face_term2(fe_v_face,
-                                            fe_v_face_neighbor,
-                                            ui_vi_matrix,
-                                            ue_vi_matrix,
-                                            ui_ve_matrix,
-                                            ue_ve_matrix);
-
-                     neighbor->get_dof_indices (dofs_neighbor);
-
-                     for (unsigned int i=0; i<dofs_per_cell; ++i)
-                       for (unsigned int j=0; j<dofs_per_cell; ++j)
-                         {
-                           system_matrix.add(dofs[i], dofs_neighbor[j],
-                                             ue_vi_matrix(i,j));
-                           system_matrix.add(dofs_neighbor[i], dofs[j],
-                                             ui_ve_matrix(i,j));
-                           system_matrix.add(dofs_neighbor[i], dofs_neighbor[j],
-                                             ue_ve_matrix(i,j));
-                         }
-                   }
+    for (unsigned int point=0; point<fe_v.n_quadrature_points; ++point)
+      {
+       const double beta_n=beta[point] * normals[point];
+       if (beta_n>0)
+         for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
+           for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
+             ui_vi_matrix(i,j) += beta_n *
+                                  fe_v.shape_value(j,point) *
+                                  fe_v.shape_value(i,point) *
+                                  JxW[point];
+       else
+         for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
+           cell_vector(i) -= beta_n *
+                             g[point] *
+                             fe_v.shape_value(i,point) *
+                             JxW[point];
+      }
+  }
 
-                                                  // We do not need to consider
-                                                  // case d), as those faces
-                                                  // are treated 'from the
-                                                  // other side within case b).
-               }
-           }
-       }
-      
-      for (unsigned int i=0; i<dofs_per_cell; ++i)
-       for (unsigned int j=0; j<dofs_per_cell; ++j)
-         system_matrix.add(dofs[i], dofs[j], ui_vi_matrix(i,j));
-      
-      for (unsigned int i=0; i<dofs_per_cell; ++i)
-       right_hand_side(dofs[i]) += cell_vector(i);
-    }
-}
 
+  template <int dim>
+  void DGTransportEquation<dim>::assemble_face_term2(
+    const FEFaceValuesBase<dim>& fe_v,
+    const FEFaceValuesBase<dim>& fe_v_neighbor,
+    FullMatrix<double> &ui_vi_matrix,
+    FullMatrix<double> &ue_vi_matrix,
+    FullMatrix<double> &ui_ve_matrix,
+    FullMatrix<double> &ue_ve_matrix) const
+  {
+    const std::vector<double> &JxW = fe_v.get_JxW_values ();
+    const std::vector<Point<dim> > &normals = fe_v.get_normal_vectors ();
 
-                                // @sect3{Solver}
-                                //
-                                // For this simple problem we use the simple
-                                // Richardson iteration again. The solver is
-                                // completely unaffected by our anisotropic
-                                // changes.
-template <int dim>
-void DGMethod<dim>::solve (Vector<double> &solution) 
-{
-  SolverControl           solver_control (1000, 1e-12, false, false);
-  SolverRichardson<>      solver (solver_control);
+    std::vector<Point<dim> > beta (fe_v.n_quadrature_points);
 
-  PreconditionBlockSSOR<SparseMatrix<double> > preconditioner;
+    beta_function.value_list (fe_v.get_quadrature_points(), beta);
 
-  preconditioner.initialize(system_matrix, fe.dofs_per_cell);
+    for (unsigned int point=0; point<fe_v.n_quadrature_points; ++point)
+      {
+       const double beta_n=beta[point] * normals[point];
+       if (beta_n>0)
+         {
+           for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
+             for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
+               ui_vi_matrix(i,j) += beta_n *
+                                    fe_v.shape_value(j,point) *
+                                    fe_v.shape_value(i,point) *
+                                    JxW[point];
+
+           for (unsigned int k=0; k<fe_v_neighbor.dofs_per_cell; ++k)
+             for (unsigned int j=0; j<fe_v.dofs_per_cell; ++j)
+               ui_ve_matrix(k,j) -= beta_n *
+                                    fe_v.shape_value(j,point) *
+                                    fe_v_neighbor.shape_value(k,point) *
+                                    JxW[point];
+         }
+       else
+         {
+           for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
+             for (unsigned int l=0; l<fe_v_neighbor.dofs_per_cell; ++l)
+               ue_vi_matrix(i,l) += beta_n *
+                                    fe_v_neighbor.shape_value(l,point) *
+                                    fe_v.shape_value(i,point) *
+                                    JxW[point];
+
+           for (unsigned int k=0; k<fe_v_neighbor.dofs_per_cell; ++k)
+             for (unsigned int l=0; l<fe_v_neighbor.dofs_per_cell; ++l)
+               ue_ve_matrix(k,l) -= beta_n *
+                                    fe_v_neighbor.shape_value(l,point) *
+                                    fe_v_neighbor.shape_value(k,point) *
+                                    JxW[point];
+         }
+      }
+  }
+
+
+                                  // @sect3{Class: DGMethod}
+                                  //
+                                  // Even the main class of this
+                                  // program stays more or less the
+                                  // same. We omit one of the assembly
+                                  // routines and use only the second,
+                                  // more effective one of the two
+                                  // presented in step-12. However, we
+                                  // introduce a new routine
+                                  // (set_anisotropic_flags) and modify
+                                  // another one (refine_grid).
+  template <int dim>
+  class DGMethod
+  {
+    public:
+      DGMethod (const bool anisotropic);
+      ~DGMethod ();
+
+      void run ();
+
+    private:
+      void setup_system ();
+      void assemble_system1 ();
+      void assemble_system2 ();
+      void solve (Vector<double> &solution);
+      void refine_grid ();
+      void set_anisotropic_flags ();
+      void output_results (const unsigned int cycle) const;
+
+      Triangulation<dim>   triangulation;
+      const MappingQ1<dim> mapping;
+                                      // Again we want to use DG elements of
+                                      // degree 1 (but this is only specified in
+                                      // the constructor). If you want to use a
+                                      // DG method of a different degree replace
+                                      // 1 in the constructor by the new degree.
+      const unsigned int   degree;
+      FE_DGQ<dim>          fe;
+      DoFHandler<dim>      dof_handler;
+
+      SparsityPattern      sparsity_pattern;
+      SparseMatrix<double> system_matrix;
+                                      // This is new, the threshold value used in
+                                      // the evaluation of the anisotropic jump
+                                      // indicator explained in the
+                                      // introduction. Its value is set to 3.0 in
+                                      // the constructor, but it can easily be
+                                      // changed to a different value greater
+                                      // than 1.
+      const double anisotropic_threshold_ratio;
+                                      // This is a bool flag indicating whether
+                                      // anisotropic refinement shall be used or
+                                      // not. It is set by the constructor, which
+                                      // takes an argument of the same name.
+      const bool anisotropic;
+
+      const QGauss<dim>   quadrature;
+      const QGauss<dim-1> face_quadrature;
+
+      Vector<double>       solution2;
+      Vector<double>       right_hand_side;
+
+      const DGTransportEquation<dim> dg;
+  };
+
+
+  template <int dim>
+  DGMethod<dim>::DGMethod (const bool anisotropic)
+                 :
+                 mapping (),
+                                                  // Change here for DG
+                                                  // methods of
+                                                  // different degrees.
+                 degree(1),
+                 fe (degree),
+                 dof_handler (triangulation),
+                 anisotropic_threshold_ratio(3.),
+                 anisotropic(anisotropic),
+                                                  // As beta is a
+                                                  // linear function,
+                                                  // we can choose the
+                                                  // degree of the
+                                                  // quadrature for
+                                                  // which the
+                                                  // resulting
+                                                  // integration is
+                                                  // correct. Thus, we
+                                                  // choose to use
+                                                  // <code>degree+1</code>
+                                                  // gauss points,
+                                                  // which enables us
+                                                  // to integrate
+                                                  // exactly
+                                                  // polynomials of
+                                                  // degree
+                                                  // <code>2*degree+1</code>,
+                                                  // enough for all the
+                                                  // integrals we will
+                                                  // perform in this
+                                                  // program.
+                 quadrature (degree+1),
+                 face_quadrature (degree+1),
+                 dg ()
+  {}
+
+
+  template <int dim>
+  DGMethod<dim>::~DGMethod ()
+  {
+    dof_handler.clear ();
+  }
+
+
+  template <int dim>
+  void DGMethod<dim>::setup_system ()
+  {
+    dof_handler.distribute_dofs (fe);
+    sparsity_pattern.reinit (dof_handler.n_dofs(),
+                            dof_handler.n_dofs(),
+                            (GeometryInfo<dim>::faces_per_cell
+                             *GeometryInfo<dim>::max_children_per_face+1)*fe.dofs_per_cell);
+
+    DoFTools::make_flux_sparsity_pattern (dof_handler, sparsity_pattern);
+
+    sparsity_pattern.compress();
+
+    system_matrix.reinit (sparsity_pattern);
+
+    solution2.reinit (dof_handler.n_dofs());
+    right_hand_side.reinit (dof_handler.n_dofs());
+  }
+
+
+                                  // @sect4{Function: assemble_system2}
+                                  //
+                                  // We proceed with the
+                                  // <code>assemble_system2</code> function that
+                                  // implements the DG discretization in its
+                                  // second version. This function is very
+                                  // similar to the <code>assemble_system2</code>
+                                  // function from step-12, even the four cases
+                                  // considered for the neighbor-relations of a
+                                  // cell are the same, namely a) cell is at the
+                                  // boundary, b) there are finer neighboring
+                                  // cells, c) the neighbor is neither coarser
+                                  // nor finer and d) the neighbor is coarser.
+                                  // However, the way in which we decide upon
+                                  // which case we have are modified in the way
+                                  // described in the introduction.
+  template <int dim>
+  void DGMethod<dim>::assemble_system2 ()
+  {
+    const unsigned int dofs_per_cell = dof_handler.get_fe().dofs_per_cell;
+    std::vector<unsigned int> dofs (dofs_per_cell);
+    std::vector<unsigned int> dofs_neighbor (dofs_per_cell);
+
+    const UpdateFlags update_flags = update_values
+                                    | update_gradients
+                                    | update_quadrature_points
+                                    | update_JxW_values;
+
+    const UpdateFlags face_update_flags = update_values
+                                         | update_quadrature_points
+                                         | update_JxW_values
+                                         | update_normal_vectors;
+
+    const UpdateFlags neighbor_face_update_flags = update_values;
+
+    FEValues<dim> fe_v (
+      mapping, fe, quadrature, update_flags);
+    FEFaceValues<dim> fe_v_face (
+      mapping, fe, face_quadrature, face_update_flags);
+    FESubfaceValues<dim> fe_v_subface (
+      mapping, fe, face_quadrature, face_update_flags);
+    FEFaceValues<dim> fe_v_face_neighbor (
+      mapping, fe, face_quadrature, neighbor_face_update_flags);
+
+
+    FullMatrix<double> ui_vi_matrix (dofs_per_cell, dofs_per_cell);
+    FullMatrix<double> ue_vi_matrix (dofs_per_cell, dofs_per_cell);
+
+    FullMatrix<double> ui_ve_matrix (dofs_per_cell, dofs_per_cell);
+    FullMatrix<double> ue_ve_matrix (dofs_per_cell, dofs_per_cell);
+
+    Vector<double>  cell_vector (dofs_per_cell);
+
+    typename DoFHandler<dim>::active_cell_iterator
+      cell = dof_handler.begin_active(),
+      endc = dof_handler.end();
+    for (;cell!=endc; ++cell)
+      {
+       ui_vi_matrix = 0;
+       cell_vector = 0;
 
-  solver.solve (system_matrix, solution, right_hand_side,
-               preconditioner);
-}
+       fe_v.reinit (cell);
 
+       dg.assemble_cell_term(fe_v,
+                             ui_vi_matrix,
+                             cell_vector);
 
-                                // @sect3{Refinement}
-                                //
-                                // We refine the grid according to the same
-                                // simple refinement criterion used in step-12,
-                                // namely an approximation to the
-                                // gradient of the solution.
-template <int dim>
-void DGMethod<dim>::refine_grid ()
-{
-  Vector<float> gradient_indicator (triangulation.n_active_cells());
-
-                                  // We approximate the gradient,
-  DerivativeApproximation::approximate_gradient (mapping,
-                                                dof_handler,
-                                                solution2,
-                                                gradient_indicator);
-
-                                  // and scale it to obtain an error indicator.
-  typename DoFHandler<dim>::active_cell_iterator
-    cell = dof_handler.begin_active(),
-    endc = dof_handler.end();
-  for (unsigned int cell_no=0; cell!=endc; ++cell, ++cell_no)
-    gradient_indicator(cell_no)*=std::pow(cell->diameter(), 1+1.0*dim/2);
-                                  // Then we use this indicator to flag the 30
-                                  // percent of the cells with highest error
-                                  // indicator to be refined.
-  GridRefinement::refine_and_coarsen_fixed_number (triangulation,
-                                                  gradient_indicator,
-                                                  0.3, 0.1);
-                                  // Now the refinement flags are set for those
-                                  // cells with a large error indicator. If
-                                  // nothing is done to change this, those
-                                  // cells will be refined isotropically. If
-                                  // the @p anisotropic flag given to this
-                                  // function is set, we now call the
-                                  // set_anisotropic_flags() function, which
-                                  // uses the jump indicator to reset some of
-                                  // the refinement flags to anisotropic
-                                  // refinement.
-  if (anisotropic)
-    set_anisotropic_flags();
-                                  // Now execute the refinement considering
-                                  // anisotropic as well as isotropic
-                                  // refinement flags.
-  triangulation.execute_coarsening_and_refinement ();
-}
+       cell->get_dof_indices (dofs);
 
-                                // Once an error indicator has been evaluated
-                                // and the cells with largerst error are
-                                // flagged for refinement we want to loop over
-                                // the flagged cells again to decide whether
-                                // they need isotropic refinemnt or whether
-                                // anisotropic refinement is more
-                                // appropriate. This is the anisotropic jump
-                                // indicator explained in the introduction.
-template <int dim>
-void DGMethod<dim>::set_anisotropic_flags ()
-{
-                                  // We want to evaluate the jump over faces of
-                                  // the flagged cells, so we need some objects
-                                  // to evaluate values of the solution on
-                                  // faces.
-  UpdateFlags face_update_flags
-    = UpdateFlags(update_values | update_JxW_values);
-
-  FEFaceValues<dim> fe_v_face (mapping, fe, face_quadrature, face_update_flags);
-  FESubfaceValues<dim> fe_v_subface (mapping, fe, face_quadrature, face_update_flags);
-  FEFaceValues<dim> fe_v_face_neighbor (mapping, fe, face_quadrature, update_values);
-
-                                  // Now we need to loop over all active cells.
-  typename DoFHandler<dim>::active_cell_iterator cell=dof_handler.begin_active(),
-                                                endc=dof_handler.end();
-  
-  for (; cell!=endc; ++cell)
-                                    // We only need to consider cells which are
-                                    // flaged for refinement.
-    if (cell->refine_flag_set())
-      {
-       Point<dim> jump;
-       Point<dim> area;
-       
        for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell; ++face_no)
          {
-           typename DoFHandler<dim>::face_iterator face = cell->face(face_no);
-      
-           if (!face->at_boundary())
+           typename DoFHandler<dim>::face_iterator face=
+             cell->face(face_no);
+
+                                            // Case a)
+           if (face->at_boundary())
              {
-               Assert (cell->neighbor(face_no).state() == IteratorState::valid, ExcInternalError());
-               typename DoFHandler<dim>::cell_iterator neighbor = cell->neighbor(face_no);
-               
-               std::vector<double> u (fe_v_face.n_quadrature_points);
-               std::vector<double> u_neighbor (fe_v_face.n_quadrature_points);
-
-                                                // The four cases of different
-                                                // neighbor relations senn in
-                                                // the assembly routines are
-                                                // repeated much in the same
-                                                // way here.
+               fe_v_face.reinit (cell, face_no);
+
+               dg.assemble_boundary_term(fe_v_face,
+                                         ui_vi_matrix,
+                                         cell_vector);
+             }
+           else
+             {
+               Assert (cell->neighbor(face_no).state() == IteratorState::valid,
+                       ExcInternalError());
+               typename DoFHandler<dim>::cell_iterator neighbor=
+                 cell->neighbor(face_no);
+                                                // Case b), we decide that there
+                                                // are finer cells as neighbors
+                                                // by asking the face, whether it
+                                                // has children. if so, then
+                                                // there must also be finer cells
+                                                // which are children or farther
+                                                // offsprings of our neighbor.
                if (face->has_children())
                  {
-                                                    // The neighbor is refined.
-                                                    // First we store the
-                                                    // information, which of
-                                                    // the neighbor's faces
-                                                    // points in the direction
-                                                    // of our current
-                                                    // cell. This property is
-                                                    // inherited to the
-                                                    // children.
-                   unsigned int neighbor2=cell->neighbor_face_no(face_no);
-                                                    // Now we loop over all subfaces,
-                   for (unsigned int subface_no=0; subface_no<face->number_of_children(); ++subface_no)
+                                                    // We need to know, which of
+                                                    // the neighbors faces points
+                                                    // in the direction of our
+                                                    // cell. Using the @p
+                                                    // neighbor_face_no function
+                                                    // we get this information
+                                                    // for both coarser and
+                                                    // non-coarser neighbors.
+                   const unsigned int neighbor2=
+                     cell->neighbor_face_no(face_no);
+
+                                                    // Now we loop over all
+                                                    // subfaces, i.e. the
+                                                    // children and possibly
+                                                    // grandchildren of the
+                                                    // current face.
+                   for (unsigned int subface_no=0;
+                        subface_no<face->number_of_children(); ++subface_no)
                      {
-                                                        // get an iterator
-                                                        // pointing to the cell
-                                                        // behind the present
-                                                        // subface...
-                       typename DoFHandler<dim>::cell_iterator neighbor_child = cell->neighbor_child_on_subface(face_no,subface_no);
+                                                        // To get the cell behind
+                                                        // the current subface we
+                                                        // can use the @p
+                                                        // neighbor_child_on_subface
+                                                        // function. it takes
+                                                        // care of all the
+                                                        // complicated situations
+                                                        // of anisotropic
+                                                        // refinement and
+                                                        // non-standard faces.
+                       typename DoFHandler<dim>::cell_iterator neighbor_child
+                         = cell->neighbor_child_on_subface (face_no, subface_no);
                        Assert (!neighbor_child->has_children(), ExcInternalError());
-                                                        // ... and reinit the
-                                                        // respective
-                                                        // FEFaceValues und
-                                                        // FESubFaceValues
-                                                        // objects.
+
+                                                        // The remaining part of
+                                                        // this case is
+                                                        // unchanged.
+                       ue_vi_matrix = 0;
+                       ui_ve_matrix = 0;
+                       ue_ve_matrix = 0;
+
                        fe_v_subface.reinit (cell, face_no, subface_no);
                        fe_v_face_neighbor.reinit (neighbor_child, neighbor2);
-                                                        // We obtain the function values
-                       fe_v_subface.get_function_values(solution2, u);
-                       fe_v_face_neighbor.get_function_values(solution2, u_neighbor);
-                                                        // as well as the
-                                                        // quadrature weights,
-                                                        // multiplied by the
-                                                        // jacobian determinant.
-                       const std::vector<double> &JxW = fe_v_subface.get_JxW_values ();
-                                                        // Now we loop over all
-                                                        // quadrature points
-                       for (unsigned int x=0; x<fe_v_subface.n_quadrature_points; ++x)
-                         {
-                                                            // and integrate
-                                                            // the absolute
-                                                            // value of the
-                                                            // jump of the
-                                                            // solution,
-                                                            // i.e. the
-                                                            // absolute value
-                                                            // of the
-                                                            // difference
-                                                            // between the
-                                                            // function value
-                                                            // seen from the
-                                                            // current cell and
-                                                            // the neighboring
-                                                            // cell,
-                                                            // respectively. We
-                                                            // know, that the
-                                                            // first two faces
-                                                            // are orthogonal
-                                                            // to the first
-                                                            // coordinate
-                                                            // direction on the
-                                                            // unit cell, the
-                                                            // second two faces
-                                                            // are orthogonal
-                                                            // to the second
-                                                            // coordinate
-                                                            // direction and so
-                                                            // on, so we
-                                                            // accumulate these
-                                                            // values ito
-                                                            // vectors with
-                                                            // <code>dim</code>
-                                                            // components.
-                           jump[face_no/2]+=std::fabs(u[x]-u_neighbor[x])*JxW[x];
-                                                            // We also sum up
-                                                            // the scaled
-                                                            // weights to
-                                                            // obtain the
-                                                            // measure of the
-                                                            // face.
-                           area[face_no/2]+=JxW[x];
-                         }
+
+                       dg.assemble_face_term2(fe_v_subface,
+                                              fe_v_face_neighbor,
+                                              ui_vi_matrix,
+                                              ue_vi_matrix,
+                                              ui_ve_matrix,
+                                              ue_ve_matrix);
+
+                       neighbor_child->get_dof_indices (dofs_neighbor);
+
+                       for (unsigned int i=0; i<dofs_per_cell; ++i)
+                         for (unsigned int j=0; j<dofs_per_cell; ++j)
+                           {
+                             system_matrix.add(dofs[i], dofs_neighbor[j],
+                                               ue_vi_matrix(i,j));
+                             system_matrix.add(dofs_neighbor[i], dofs[j],
+                                               ui_ve_matrix(i,j));
+                             system_matrix.add(dofs_neighbor[i], dofs_neighbor[j],
+                                               ue_ve_matrix(i,j));
+                           }
                      }
                  }
-               else 
+               else
                  {
-                   if (!cell->neighbor_is_coarser(face_no)) 
+                                                    // Case c). We simply ask,
+                                                    // whether the neighbor is
+                                                    // coarser. If not, then it
+                                                    // is neither coarser nor
+                                                    // finer, since finer
+                                                    // neighbor would have been
+                                                    // reated above withz case
+                                                    // b). Of all the cases with
+                                                    // thesame refinement
+                                                    // situation of our cell and
+                                                    // the neighbor we want to
+                                                    // treat only one half, so
+                                                    // that each face is
+                                                    // considered only once. Thus
+                                                    // we have the additional
+                                                    // condition, that the cell
+                                                    // with the lower index does
+                                                    // the work. In the rare case
+                                                    // that both cells have the
+                                                    // same index, the cell with
+                                                    // lower level is selected.
+                   if (!cell->neighbor_is_coarser(face_no) &&
+                       (neighbor->index() > cell->index() ||
+                        (neighbor->level() < cell->level() &&
+                         neighbor->index() == cell->index())))
                      {
-                                                        // Our current cell and
-                                                        // the neighbor have
-                                                        // the same refinement
-                                                        // along the face under
-                                                        // consideration. Apart
-                                                        // from that, we do
-                                                        // much the same as
-                                                        // with one of the
-                                                        // subcells in the
-                                                        // above case.
-                       unsigned int neighbor2=cell->neighbor_of_neighbor(face_no);
-                 
+                                                        // Here we know, that the
+                                                        // neigbor is not coarser
+                                                        // so we can use the
+                                                        // usual @p
+                                                        // neighbor_of_neighbor
+                                                        // function. However, we
+                                                        // could also use the
+                                                        // more general @p
+                                                        // neighbor_face_no
+                                                        // function.
+                       const unsigned int neighbor2=cell->neighbor_of_neighbor(face_no);
+
+                       ue_vi_matrix = 0;
+                       ui_ve_matrix = 0;
+                       ue_ve_matrix = 0;
+
                        fe_v_face.reinit (cell, face_no);
                        fe_v_face_neighbor.reinit (neighbor, neighbor2);
-                 
-                       fe_v_face.get_function_values(solution2, u);
-                       fe_v_face_neighbor.get_function_values(solution2, u_neighbor);
-                 
-                       const std::vector<double> &JxW = fe_v_face.get_JxW_values ();
-                 
-                       for (unsigned int x=0; x<fe_v_face.n_quadrature_points; ++x)
-                         {
-                           jump[face_no/2]+=std::fabs(u[x]-u_neighbor[x])*JxW[x];
-                           area[face_no/2]+=JxW[x];
-                         }
-                     }
-                   else //i.e. neighbor is coarser than cell
-                     {
-                                                        // Now the neighbor is
-                                                        // actually
-                                                        // coarser. This case
-                                                        // is new, in that it
-                                                        // did not occur in the
-                                                        // assembly
-                                                        // routine. Here, we
-                                                        // have to consider it,
-                                                        // but this is not
-                                                        // overly
-                                                        // complicated. We
-                                                        // simply use the @p
-                                                        // neighbor_of_coarser_neighbor
-                                                        // function, which
-                                                        // again takes care of
-                                                        // anisotropic
-                                                        // refinement and
-                                                        // non-standard face
-                                                        // orientation by
-                                                        // itself.
-                       std::pair<unsigned int,unsigned int> neighbor_face_subface
-                         = cell->neighbor_of_coarser_neighbor(face_no);
-                       Assert (neighbor_face_subface.first<GeometryInfo<dim>::faces_per_cell, ExcInternalError());
-                       Assert (neighbor_face_subface.second<neighbor->face(neighbor_face_subface.first)->number_of_children(),
-                               ExcInternalError());
-                       Assert (neighbor->neighbor_child_on_subface(neighbor_face_subface.first, neighbor_face_subface.second)
-                               == cell, ExcInternalError());
-                 
-                       fe_v_face.reinit (cell, face_no);
-                       fe_v_subface.reinit (neighbor, neighbor_face_subface.first,
-                                            neighbor_face_subface.second);
-                 
-                       fe_v_face.get_function_values(solution2, u);
-                       fe_v_subface.get_function_values(solution2, u_neighbor);
-                       
-                       const std::vector<double> &JxW = fe_v_face.get_JxW_values ();
-                 
-                       for (unsigned int x=0; x<fe_v_face.n_quadrature_points; ++x)
-                         {
-                           jump[face_no/2]+=std::fabs(u[x]-u_neighbor[x])*JxW[x];
-                           area[face_no/2]+=JxW[x];
-                         }
+
+                       dg.assemble_face_term2(fe_v_face,
+                                              fe_v_face_neighbor,
+                                              ui_vi_matrix,
+                                              ue_vi_matrix,
+                                              ui_ve_matrix,
+                                              ue_ve_matrix);
+
+                       neighbor->get_dof_indices (dofs_neighbor);
+
+                       for (unsigned int i=0; i<dofs_per_cell; ++i)
+                         for (unsigned int j=0; j<dofs_per_cell; ++j)
+                           {
+                             system_matrix.add(dofs[i], dofs_neighbor[j],
+                                               ue_vi_matrix(i,j));
+                             system_matrix.add(dofs_neighbor[i], dofs[j],
+                                               ui_ve_matrix(i,j));
+                             system_matrix.add(dofs_neighbor[i], dofs_neighbor[j],
+                                               ue_ve_matrix(i,j));
+                           }
                      }
+
+                                                    // We do not need to consider
+                                                    // case d), as those faces
+                                                    // are treated 'from the
+                                                    // other side within case b).
                  }
              }
          }
-                                        // Now we analyze the size of the mean
-                                        // jumps, which we get dividing the
-                                        // jumps by the measure of the
-                                        // respective faces.
-       double average_jumps[dim];
-       double sum_of_average_jumps=0.;
-       for (unsigned int i=0; i<dim; ++i)
-         {
-           average_jumps[i] = jump(i)/area(i);
-           sum_of_average_jumps += average_jumps[i];
-         }
 
-                                        // Now we loop over the <code>dim</code>
-                                        // coordinate directions of the unit
-                                        // cell and compare the average jump
-                                        // over the faces orthogional to that
-                                        // direction with the average jumnps
-                                        // over faces orthogonal to the
-                                        // remining direction(s). If the first
-                                        // is larger than the latter by a given
-                                        // factor, we refine only along hat
-                                        // axis. Otherwise we leave the
-                                        // refinement flag unchanged, resulting
-                                        // in isotropic refinement.
-       for (unsigned int i=0; i<dim; ++i)
-         if (average_jumps[i] > anisotropic_threshold_ratio*(sum_of_average_jumps-average_jumps[i]))
-           cell->set_refine_flag(RefinementCase<dim>::cut_axis(i));
+       for (unsigned int i=0; i<dofs_per_cell; ++i)
+         for (unsigned int j=0; j<dofs_per_cell; ++j)
+           system_matrix.add(dofs[i], dofs[j], ui_vi_matrix(i,j));
+
+       for (unsigned int i=0; i<dofs_per_cell; ++i)
+         right_hand_side(dofs[i]) += cell_vector(i);
       }
-}
-  
-                                // @sect3{The Rest}
-                                //
-                                // The remaining part of the program is again
-                                // unmodified. Only the creation of the
-                                // original triangulation is changed in order
-                                // to reproduce the new domain.
-template <int dim>
-void DGMethod<dim>::output_results (const unsigned int cycle) const
-{
-  std::string refine_type;
-  if (anisotropic)
-    refine_type=".aniso";
-  else
-    refine_type=".iso";
-  
-  std::string filename = "grid-";
-  filename += ('0' + cycle);
-  Assert (cycle < 10, ExcInternalError());
-
-  filename += refine_type + ".eps";
-  std::cout << "Writing grid to <" << filename << ">..." << std::endl;
-  std::ofstream eps_output (filename.c_str());
-
-  GridOut grid_out;
-  grid_out.write_eps (triangulation, eps_output);
-
-  filename = "grid-";
-  filename += ('0' + cycle);
-  Assert (cycle < 10, ExcInternalError());
-  
-  filename += refine_type + ".gnuplot";
-  std::cout << "Writing grid to <" << filename << ">..." << std::endl;
-  std::ofstream gnuplot_grid_output (filename.c_str());
-
-  grid_out.write_gnuplot (triangulation, gnuplot_grid_output);
-  
-  filename = "sol-";
-  filename += ('0' + cycle);
-  Assert (cycle < 10, ExcInternalError());
-  
-  filename += refine_type + ".gnuplot";
-  std::cout << "Writing solution to <" << filename << ">..."
-           << std::endl;
-  std::ofstream gnuplot_output (filename.c_str());
-  
-  DataOut<dim> data_out;
-  data_out.attach_dof_handler (dof_handler);
-  data_out.add_data_vector (solution2, "u");
-
-  data_out.build_patches (degree);
-  
-  data_out.write_gnuplot(gnuplot_output);
-}
+  }
+
+
+                                  // @sect3{Solver}
+                                  //
+                                  // For this simple problem we use the simple
+                                  // Richardson iteration again. The solver is
+                                  // completely unaffected by our anisotropic
+                                  // changes.
+  template <int dim>
+  void DGMethod<dim>::solve (Vector<double> &solution)
+  {
+    SolverControl           solver_control (1000, 1e-12, false, false);
+    SolverRichardson<>      solver (solver_control);
+
+    PreconditionBlockSSOR<SparseMatrix<double> > preconditioner;
+
+    preconditioner.initialize(system_matrix, fe.dofs_per_cell);
+
+    solver.solve (system_matrix, solution, right_hand_side,
+                 preconditioner);
+  }
+
+
+                                  // @sect3{Refinement}
+                                  //
+                                  // We refine the grid according to the same
+                                  // simple refinement criterion used in step-12,
+                                  // namely an approximation to the
+                                  // gradient of the solution.
+  template <int dim>
+  void DGMethod<dim>::refine_grid ()
+  {
+    Vector<float> gradient_indicator (triangulation.n_active_cells());
+
+                                    // We approximate the gradient,
+    DerivativeApproximation::approximate_gradient (mapping,
+                                                  dof_handler,
+                                                  solution2,
+                                                  gradient_indicator);
+
+                                    // and scale it to obtain an error indicator.
+    typename DoFHandler<dim>::active_cell_iterator
+      cell = dof_handler.begin_active(),
+      endc = dof_handler.end();
+    for (unsigned int cell_no=0; cell!=endc; ++cell, ++cell_no)
+      gradient_indicator(cell_no)*=std::pow(cell->diameter(), 1+1.0*dim/2);
+                                    // Then we use this indicator to flag the 30
+                                    // percent of the cells with highest error
+                                    // indicator to be refined.
+    GridRefinement::refine_and_coarsen_fixed_number (triangulation,
+                                                    gradient_indicator,
+                                                    0.3, 0.1);
+                                    // Now the refinement flags are set for those
+                                    // cells with a large error indicator. If
+                                    // nothing is done to change this, those
+                                    // cells will be refined isotropically. If
+                                    // the @p anisotropic flag given to this
+                                    // function is set, we now call the
+                                    // set_anisotropic_flags() function, which
+                                    // uses the jump indicator to reset some of
+                                    // the refinement flags to anisotropic
+                                    // refinement.
+    if (anisotropic)
+      set_anisotropic_flags();
+                                    // Now execute the refinement considering
+                                    // anisotropic as well as isotropic
+                                    // refinement flags.
+    triangulation.execute_coarsening_and_refinement ();
+  }
+
+                                  // Once an error indicator has been evaluated
+                                  // and the cells with largerst error are
+                                  // flagged for refinement we want to loop over
+                                  // the flagged cells again to decide whether
+                                  // they need isotropic refinemnt or whether
+                                  // anisotropic refinement is more
+                                  // appropriate. This is the anisotropic jump
+                                  // indicator explained in the introduction.
+  template <int dim>
+  void DGMethod<dim>::set_anisotropic_flags ()
+  {
+                                    // We want to evaluate the jump over faces of
+                                    // the flagged cells, so we need some objects
+                                    // to evaluate values of the solution on
+                                    // faces.
+    UpdateFlags face_update_flags
+      = UpdateFlags(update_values | update_JxW_values);
+
+    FEFaceValues<dim> fe_v_face (mapping, fe, face_quadrature, face_update_flags);
+    FESubfaceValues<dim> fe_v_subface (mapping, fe, face_quadrature, face_update_flags);
+    FEFaceValues<dim> fe_v_face_neighbor (mapping, fe, face_quadrature, update_values);
+
+                                    // Now we need to loop over all active cells.
+    typename DoFHandler<dim>::active_cell_iterator cell=dof_handler.begin_active(),
+                                                  endc=dof_handler.end();
+
+    for (; cell!=endc; ++cell)
+                                      // We only need to consider cells which are
+                                      // flaged for refinement.
+      if (cell->refine_flag_set())
+       {
+         Point<dim> jump;
+         Point<dim> area;
 
+         for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell; ++face_no)
+           {
+             typename DoFHandler<dim>::face_iterator face = cell->face(face_no);
 
-template <int dim>
-void DGMethod<dim>::run () 
-{
-  for (unsigned int cycle=0; cycle<6; ++cycle)
-    {
-      std::cout << "Cycle " << cycle << ':' << std::endl;
+             if (!face->at_boundary())
+               {
+                 Assert (cell->neighbor(face_no).state() == IteratorState::valid, ExcInternalError());
+                 typename DoFHandler<dim>::cell_iterator neighbor = cell->neighbor(face_no);
+
+                 std::vector<double> u (fe_v_face.n_quadrature_points);
+                 std::vector<double> u_neighbor (fe_v_face.n_quadrature_points);
+
+                                                  // The four cases of different
+                                                  // neighbor relations senn in
+                                                  // the assembly routines are
+                                                  // repeated much in the same
+                                                  // way here.
+                 if (face->has_children())
+                   {
+                                                      // The neighbor is refined.
+                                                      // First we store the
+                                                      // information, which of
+                                                      // the neighbor's faces
+                                                      // points in the direction
+                                                      // of our current
+                                                      // cell. This property is
+                                                      // inherited to the
+                                                      // children.
+                     unsigned int neighbor2=cell->neighbor_face_no(face_no);
+                                                      // Now we loop over all subfaces,
+                     for (unsigned int subface_no=0; subface_no<face->number_of_children(); ++subface_no)
+                       {
+                                                          // get an iterator
+                                                          // pointing to the cell
+                                                          // behind the present
+                                                          // subface...
+                         typename DoFHandler<dim>::cell_iterator neighbor_child = cell->neighbor_child_on_subface(face_no,subface_no);
+                         Assert (!neighbor_child->has_children(), ExcInternalError());
+                                                          // ... and reinit the
+                                                          // respective
+                                                          // FEFaceValues und
+                                                          // FESubFaceValues
+                                                          // objects.
+                         fe_v_subface.reinit (cell, face_no, subface_no);
+                         fe_v_face_neighbor.reinit (neighbor_child, neighbor2);
+                                                          // We obtain the function values
+                         fe_v_subface.get_function_values(solution2, u);
+                         fe_v_face_neighbor.get_function_values(solution2, u_neighbor);
+                                                          // as well as the
+                                                          // quadrature weights,
+                                                          // multiplied by the
+                                                          // jacobian determinant.
+                         const std::vector<double> &JxW = fe_v_subface.get_JxW_values ();
+                                                          // Now we loop over all
+                                                          // quadrature points
+                         for (unsigned int x=0; x<fe_v_subface.n_quadrature_points; ++x)
+                           {
+                                                              // and integrate
+                                                              // the absolute
+                                                              // value of the
+                                                              // jump of the
+                                                              // solution,
+                                                              // i.e. the
+                                                              // absolute value
+                                                              // of the
+                                                              // difference
+                                                              // between the
+                                                              // function value
+                                                              // seen from the
+                                                              // current cell and
+                                                              // the neighboring
+                                                              // cell,
+                                                              // respectively. We
+                                                              // know, that the
+                                                              // first two faces
+                                                              // are orthogonal
+                                                              // to the first
+                                                              // coordinate
+                                                              // direction on the
+                                                              // unit cell, the
+                                                              // second two faces
+                                                              // are orthogonal
+                                                              // to the second
+                                                              // coordinate
+                                                              // direction and so
+                                                              // on, so we
+                                                              // accumulate these
+                                                              // values ito
+                                                              // vectors with
+                                                              // <code>dim</code>
+                                                              // components.
+                             jump[face_no/2]+=std::fabs(u[x]-u_neighbor[x])*JxW[x];
+                                                              // We also sum up
+                                                              // the scaled
+                                                              // weights to
+                                                              // obtain the
+                                                              // measure of the
+                                                              // face.
+                             area[face_no/2]+=JxW[x];
+                           }
+                       }
+                   }
+                 else
+                   {
+                     if (!cell->neighbor_is_coarser(face_no))
+                       {
+                                                          // Our current cell and
+                                                          // the neighbor have
+                                                          // the same refinement
+                                                          // along the face under
+                                                          // consideration. Apart
+                                                          // from that, we do
+                                                          // much the same as
+                                                          // with one of the
+                                                          // subcells in the
+                                                          // above case.
+                         unsigned int neighbor2=cell->neighbor_of_neighbor(face_no);
+
+                         fe_v_face.reinit (cell, face_no);
+                         fe_v_face_neighbor.reinit (neighbor, neighbor2);
+
+                         fe_v_face.get_function_values(solution2, u);
+                         fe_v_face_neighbor.get_function_values(solution2, u_neighbor);
+
+                         const std::vector<double> &JxW = fe_v_face.get_JxW_values ();
+
+                         for (unsigned int x=0; x<fe_v_face.n_quadrature_points; ++x)
+                           {
+                             jump[face_no/2]+=std::fabs(u[x]-u_neighbor[x])*JxW[x];
+                             area[face_no/2]+=JxW[x];
+                           }
+                       }
+                     else //i.e. neighbor is coarser than cell
+                       {
+                                                          // Now the neighbor is
+                                                          // actually
+                                                          // coarser. This case
+                                                          // is new, in that it
+                                                          // did not occur in the
+                                                          // assembly
+                                                          // routine. Here, we
+                                                          // have to consider it,
+                                                          // but this is not
+                                                          // overly
+                                                          // complicated. We
+                                                          // simply use the @p
+                                                          // neighbor_of_coarser_neighbor
+                                                          // function, which
+                                                          // again takes care of
+                                                          // anisotropic
+                                                          // refinement and
+                                                          // non-standard face
+                                                          // orientation by
+                                                          // itself.
+                         std::pair<unsigned int,unsigned int> neighbor_face_subface
+                           = cell->neighbor_of_coarser_neighbor(face_no);
+                         Assert (neighbor_face_subface.first<GeometryInfo<dim>::faces_per_cell, ExcInternalError());
+                         Assert (neighbor_face_subface.second<neighbor->face(neighbor_face_subface.first)->number_of_children(),
+                                 ExcInternalError());
+                         Assert (neighbor->neighbor_child_on_subface(neighbor_face_subface.first, neighbor_face_subface.second)
+                                 == cell, ExcInternalError());
+
+                         fe_v_face.reinit (cell, face_no);
+                         fe_v_subface.reinit (neighbor, neighbor_face_subface.first,
+                                              neighbor_face_subface.second);
+
+                         fe_v_face.get_function_values(solution2, u);
+                         fe_v_subface.get_function_values(solution2, u_neighbor);
+
+                         const std::vector<double> &JxW = fe_v_face.get_JxW_values ();
+
+                         for (unsigned int x=0; x<fe_v_face.n_quadrature_points; ++x)
+                           {
+                             jump[face_no/2]+=std::fabs(u[x]-u_neighbor[x])*JxW[x];
+                             area[face_no/2]+=JxW[x];
+                           }
+                       }
+                   }
+               }
+           }
+                                          // Now we analyze the size of the mean
+                                          // jumps, which we get dividing the
+                                          // jumps by the measure of the
+                                          // respective faces.
+         double average_jumps[dim];
+         double sum_of_average_jumps=0.;
+         for (unsigned int i=0; i<dim; ++i)
+           {
+             average_jumps[i] = jump(i)/area(i);
+             sum_of_average_jumps += average_jumps[i];
+           }
 
-      if (cycle == 0)
-       {
-                                          // Create the rectangular domain.
-         Point<dim> p1,p2;
-         p1(0)=0;
-         p1(0)=-1;
+                                          // Now we loop over the <code>dim</code>
+                                          // coordinate directions of the unit
+                                          // cell and compare the average jump
+                                          // over the faces orthogional to that
+                                          // direction with the average jumnps
+                                          // over faces orthogonal to the
+                                          // remining direction(s). If the first
+                                          // is larger than the latter by a given
+                                          // factor, we refine only along hat
+                                          // axis. Otherwise we leave the
+                                          // refinement flag unchanged, resulting
+                                          // in isotropic refinement.
          for (unsigned int i=0; i<dim; ++i)
-           p2(i)=1.;
-                                          // Adjust the number of cells in
-                                          // different directions to obtain
-                                          // completely isotropic cells for the
-                                          // original mesh.
-         std::vector<unsigned int> repetitions(dim,1);
-         repetitions[0]=2;
-         GridGenerator::subdivided_hyper_rectangle (triangulation,
-                                                    repetitions,
-                                                    p1,
-                                                    p2);
-
-         triangulation.refine_global (5-dim);
+           if (average_jumps[i] > anisotropic_threshold_ratio*(sum_of_average_jumps-average_jumps[i]))
+             cell->set_refine_flag(RefinementCase<dim>::cut_axis(i));
        }
-      else
-       refine_grid ();
-      
+  }
+
+                                  // @sect3{The Rest}
+                                  //
+                                  // The remaining part of the program is again
+                                  // unmodified. Only the creation of the
+                                  // original triangulation is changed in order
+                                  // to reproduce the new domain.
+  template <int dim>
+  void DGMethod<dim>::output_results (const unsigned int cycle) const
+  {
+    std::string refine_type;
+    if (anisotropic)
+      refine_type=".aniso";
+    else
+      refine_type=".iso";
+
+    std::string filename = "grid-";
+    filename += ('0' + cycle);
+    Assert (cycle < 10, ExcInternalError());
+
+    filename += refine_type + ".eps";
+    std::cout << "Writing grid to <" << filename << ">..." << std::endl;
+    std::ofstream eps_output (filename.c_str());
+
+    GridOut grid_out;
+    grid_out.write_eps (triangulation, eps_output);
+
+    filename = "grid-";
+    filename += ('0' + cycle);
+    Assert (cycle < 10, ExcInternalError());
+
+    filename += refine_type + ".gnuplot";
+    std::cout << "Writing grid to <" << filename << ">..." << std::endl;
+    std::ofstream gnuplot_grid_output (filename.c_str());
+
+    grid_out.write_gnuplot (triangulation, gnuplot_grid_output);
+
+    filename = "sol-";
+    filename += ('0' + cycle);
+    Assert (cycle < 10, ExcInternalError());
+
+    filename += refine_type + ".gnuplot";
+    std::cout << "Writing solution to <" << filename << ">..."
+             << std::endl;
+    std::ofstream gnuplot_output (filename.c_str());
+
+    DataOut<dim> data_out;
+    data_out.attach_dof_handler (dof_handler);
+    data_out.add_data_vector (solution2, "u");
+
+    data_out.build_patches (degree);
+
+    data_out.write_gnuplot(gnuplot_output);
+  }
+
+
+  template <int dim>
+  void DGMethod<dim>::run ()
+  {
+    for (unsigned int cycle=0; cycle<6; ++cycle)
+      {
+       std::cout << "Cycle " << cycle << ':' << std::endl;
 
-      std::cout << "   Number of active cells:       "
-               << triangulation.n_active_cells()
-               << std::endl;
+       if (cycle == 0)
+         {
+                                            // Create the rectangular domain.
+           Point<dim> p1,p2;
+           p1(0)=0;
+           p1(0)=-1;
+           for (unsigned int i=0; i<dim; ++i)
+             p2(i)=1.;
+                                            // Adjust the number of cells in
+                                            // different directions to obtain
+                                            // completely isotropic cells for the
+                                            // original mesh.
+           std::vector<unsigned int> repetitions(dim,1);
+           repetitions[0]=2;
+           GridGenerator::subdivided_hyper_rectangle (triangulation,
+                                                      repetitions,
+                                                      p1,
+                                                      p2);
+
+           triangulation.refine_global (5-dim);
+         }
+       else
+         refine_grid ();
 
-      setup_system ();
 
-      std::cout << "   Number of degrees of freedom: "
-               << dof_handler.n_dofs()
-               << std::endl;
+       std::cout << "   Number of active cells:       "
+                 << triangulation.n_active_cells()
+                 << std::endl;
 
-      Timer assemble_timer;
-      assemble_system2 ();
-      std::cout << "Time of assemble_system2: "
-               << assemble_timer()
-               << std::endl;
-      solve (solution2);
+       setup_system ();
 
-      output_results (cycle);
-    }
+       std::cout << "   Number of degrees of freedom: "
+                 << dof_handler.n_dofs()
+                 << std::endl;
+
+       Timer assemble_timer;
+       assemble_system2 ();
+       std::cout << "Time of assemble_system2: "
+                 << assemble_timer()
+                 << std::endl;
+       solve (solution2);
+
+       output_results (cycle);
+      }
+  }
 }
 
-int main () 
+
+
+int main ()
 {
   try
     {
+      using namespace dealii;
+      using namespace Step30;
+
                                       // If you want to run the program in 3D,
                                       // simply change the following line to
                                       // <code>const unsigned int dim = 3;</code>.
       const unsigned int dim = 2;
-      
+
       {
                                         // First, we perform a run with
                                         // isotropic refinement.
@@ -1155,7 +1163,7 @@ int main ()
        DGMethod<dim> dgmethod_iso(false);
        dgmethod_iso.run ();
       }
-      
+
       {
                                         // Now we do a second run, this time
                                         // with anisotropic refinement.
@@ -1178,7 +1186,7 @@ int main ()
                << std::endl;
       return 1;
     }
-  catch (...) 
+  catch (...)
     {
       std::cerr << std::endl << std::endl
                << "----------------------------------------------------"
@@ -1189,7 +1197,7 @@ int main ()
                << std::endl;
       return 1;
     };
-  
+
   return 0;
 }
 
index 936167672802ed8cae7bfb9b5b413d277a49e027..75e96b14b6751b3fc79334a7c251671705c174a9 100644 (file)
@@ -4,7 +4,7 @@
 
 /*    $Id$       */
 /*                                                                */
-/*    Copyright (C) 2007, 2008, 2009, 2010 by the deal.II authors */
+/*    Copyright (C) 2007, 2008, 2009, 2010, 2011 by the deal.II authors */
 /*                                                                */
 /*    This file is subject to QPL and may not be  distributed     */
 /*    without copyright and license information. Please refer     */
                                 // At the end of this top-matter, we import
                                 // all deal.II names into the global
                                 // namespace:
-using namespace dealii;
-
-
-                                // @sect3{Equation data}
-
-                                // Again, the next stage in the program is
-                                // the definition of the equation data, that
-                                // is, the various boundary conditions, the
-                                // right hand sides and the initial condition
-                                // (remember that we're about to solve a
-                                // time-dependent system). The basic strategy
-                                // for this definition is the same as in
-                                // step-22. Regarding the details, though,
-                                // there are some differences.
-
-                                // The first thing is that we don't set any
-                                // non-homogenous boundary conditions on the
-                                // velocity, since as is explained in the
-                                // introduction we will use no-flux
-                                // conditions
-                                // $\mathbf{n}\cdot\mathbf{u}=0$. So what is
-                                // left are <code>dim-1</code> conditions for
-                                // the tangential part of the normal
-                                // component of the stress tensor,
-                                // $\textbf{n} \cdot [p \textbf{1} -
-                                // \eta\varepsilon(\textbf{u})]$; we assume
-                                // homogenous values for these components,
-                                // i.e. a natural boundary condition that
-                                // requires no specific action (it appears as
-                                // a zero term in the right hand side of the
-                                // weak form).
-                                //
-                                // For the temperature <i>T</i>, we assume no
-                                // thermal energy flux, i.e. $\mathbf{n}
-                                // \cdot \kappa \nabla T=0$. This, again, is
-                                // a boundary condition that does not require
-                                // us to do anything in particular.
-                                //
-                                // Secondly, we have to set initial
-                                // conditions for the temperature (no initial
-                                // conditions are required for the velocity
-                                // and pressure, since the Stokes equations
-                                // for the quasi-stationary case we consider
-                                // here have no time derivatives of the
-                                // velocity or pressure). Here, we choose a
-                                // very simple test case, where the initial
-                                // temperature is zero, and all dynamics are
-                                // driven by the temperature right hand side.
-                                //
-                                // Thirdly, we need to define the right hand
-                                // side of the temperature equation. We
-                                // choose it to be constant within three
-                                // circles (or spheres in 3d) somewhere at
-                                // the bottom of the domain, as explained in
-                                // the introduction, and zero outside.
-                                //
-                                // Finally, or maybe firstly, at the top of
-                                // this namespace, we define the various
-                                // material constants we need ($\eta,\kappa$,
-                                // density $\rho$ and the thermal expansion
-                                // coefficient $\beta$):
-namespace EquationData
+namespace Step31
 {
-  const double eta = 1;
-  const double kappa = 1e-6;
-  const double beta = 10;
-  const double density = 1;
+  using namespace dealii;
+
+
+                                  // @sect3{Equation data}
+
+                                  // Again, the next stage in the program is
+                                  // the definition of the equation data, that
+                                  // is, the various boundary conditions, the
+                                  // right hand sides and the initial condition
+                                  // (remember that we're about to solve a
+                                  // time-dependent system). The basic strategy
+                                  // for this definition is the same as in
+                                  // step-22. Regarding the details, though,
+                                  // there are some differences.
+
+                                  // The first thing is that we don't set any
+                                  // non-homogenous boundary conditions on the
+                                  // velocity, since as is explained in the
+                                  // introduction we will use no-flux
+                                  // conditions
+                                  // $\mathbf{n}\cdot\mathbf{u}=0$. So what is
+                                  // left are <code>dim-1</code> conditions for
+                                  // the tangential part of the normal
+                                  // component of the stress tensor,
+                                  // $\textbf{n} \cdot [p \textbf{1} -
+                                  // \eta\varepsilon(\textbf{u})]$; we assume
+                                  // homogenous values for these components,
+                                  // i.e. a natural boundary condition that
+                                  // requires no specific action (it appears as
+                                  // a zero term in the right hand side of the
+                                  // weak form).
+                                  //
+                                  // For the temperature <i>T</i>, we assume no
+                                  // thermal energy flux, i.e. $\mathbf{n}
+                                  // \cdot \kappa \nabla T=0$. This, again, is
+                                  // a boundary condition that does not require
+                                  // us to do anything in particular.
+                                  //
+                                  // Secondly, we have to set initial
+                                  // conditions for the temperature (no initial
+                                  // conditions are required for the velocity
+                                  // and pressure, since the Stokes equations
+                                  // for the quasi-stationary case we consider
+                                  // here have no time derivatives of the
+                                  // velocity or pressure). Here, we choose a
+                                  // very simple test case, where the initial
+                                  // temperature is zero, and all dynamics are
+                                  // driven by the temperature right hand side.
+                                  //
+                                  // Thirdly, we need to define the right hand
+                                  // side of the temperature equation. We
+                                  // choose it to be constant within three
+                                  // circles (or spheres in 3d) somewhere at
+                                  // the bottom of the domain, as explained in
+                                  // the introduction, and zero outside.
+                                  //
+                                  // Finally, or maybe firstly, at the top of
+                                  // this namespace, we define the various
+                                  // material constants we need ($\eta,\kappa$,
+                                  // density $\rho$ and the thermal expansion
+                                  // coefficient $\beta$):
+  namespace EquationData
+  {
+    const double eta = 1;
+    const double kappa = 1e-6;
+    const double beta = 10;
+    const double density = 1;
 
 
-  template <int dim>
-  class TemperatureInitialValues : public Function<dim>
-  {
-    public:
-      TemperatureInitialValues () : Function<dim>(1) {}
+    template <int dim>
+    class TemperatureInitialValues : public Function<dim>
+    {
+      public:
+       TemperatureInitialValues () : Function<dim>(1) {}
 
-      virtual double value (const Point<dim>   &p,
-                           const unsigned int  component = 0) const;
+       virtual double value (const Point<dim>   &p,
+                             const unsigned int  component = 0) const;
 
-      virtual void vector_value (const Point<dim> &p,
-                                Vector<double>   &value) const;
-  };
+       virtual void vector_value (const Point<dim> &p,
+                                  Vector<double>   &value) const;
+    };
 
 
-  template <int dim>
-  double
-  TemperatureInitialValues<dim>::value (const Point<dim>  &,
-                                       const unsigned int) const
-  {
-    return 0;
-  }
+    template <int dim>
+    double
+    TemperatureInitialValues<dim>::value (const Point<dim>  &,
+                                         const unsigned int) const
+    {
+      return 0;
+    }
 
 
-  template <int dim>
-  void
-  TemperatureInitialValues<dim>::vector_value (const Point<dim> &p,
-                                              Vector<double>   &values) const
-  {
-    for (unsigned int c=0; c<this->n_components; ++c)
-      values(c) = TemperatureInitialValues<dim>::value (p, c);
-  }
+    template <int dim>
+    void
+    TemperatureInitialValues<dim>::vector_value (const Point<dim> &p,
+                                                Vector<double>   &values) const
+    {
+      for (unsigned int c=0; c<this->n_components; ++c)
+       values(c) = TemperatureInitialValues<dim>::value (p, c);
+    }
 
 
-  template <int dim>
-  class TemperatureRightHandSide : public Function<dim>
-  {
-    public:
-      TemperatureRightHandSide () : Function<dim>(1) {}
+    template <int dim>
+    class TemperatureRightHandSide : public Function<dim>
+    {
+      public:
+       TemperatureRightHandSide () : Function<dim>(1) {}
 
-      virtual double value (const Point<dim>   &p,
-                           const unsigned int  component = 0) const;
+       virtual double value (const Point<dim>   &p,
+                             const unsigned int  component = 0) const;
 
-      virtual void vector_value (const Point<dim> &p,
-                                Vector<double>   &value) const;
-  };
+       virtual void vector_value (const Point<dim> &p,
+                                  Vector<double>   &value) const;
+    };
 
 
-  template <int dim>
-  double
-  TemperatureRightHandSide<dim>::value (const Point<dim>  &p,
-                                       const unsigned int component) const
-  {
-    Assert (component == 0,
-           ExcMessage ("Invalid operation for a scalar function."));
-
-    Assert ((dim==2) || (dim==3), ExcNotImplemented());
-
-    static const Point<dim> source_centers[3]
-      = { (dim == 2 ? Point<dim>(.3,.1) : Point<dim>(.3,.5,.1)),
-         (dim == 2 ? Point<dim>(.45,.1) : Point<dim>(.45,.5,.1)),
-         (dim == 2 ? Point<dim>(.75,.1) : Point<dim>(.75,.5,.1)) };
-    static const double source_radius
-      = (dim == 2 ? 1./32 : 1./8);
-
-    return ((source_centers[0].distance (p) < source_radius)
-           ||
-           (source_centers[1].distance (p) < source_radius)
-           ||
-           (source_centers[2].distance (p) < source_radius)
-           ?
-           1
-           :
-           0);
-  }
+    template <int dim>
+    double
+    TemperatureRightHandSide<dim>::value (const Point<dim>  &p,
+                                         const unsigned int component) const
+    {
+      Assert (component == 0,
+             ExcMessage ("Invalid operation for a scalar function."));
+
+      Assert ((dim==2) || (dim==3), ExcNotImplemented());
+
+      static const Point<dim> source_centers[3]
+       = { (dim == 2 ? Point<dim>(.3,.1) : Point<dim>(.3,.5,.1)),
+           (dim == 2 ? Point<dim>(.45,.1) : Point<dim>(.45,.5,.1)),
+           (dim == 2 ? Point<dim>(.75,.1) : Point<dim>(.75,.5,.1)) };
+      static const double source_radius
+       = (dim == 2 ? 1./32 : 1./8);
+
+      return ((source_centers[0].distance (p) < source_radius)
+             ||
+             (source_centers[1].distance (p) < source_radius)
+             ||
+             (source_centers[2].distance (p) < source_radius)
+             ?
+             1
+             :
+             0);
+    }
 
 
-  template <int dim>
-  void
-  TemperatureRightHandSide<dim>::vector_value (const Point<dim> &p,
-                                              Vector<double>   &values) const
-  {
-    for (unsigned int c=0; c<this->n_components; ++c)
-      values(c) = TemperatureRightHandSide<dim>::value (p, c);
+    template <int dim>
+    void
+    TemperatureRightHandSide<dim>::vector_value (const Point<dim> &p,
+                                                Vector<double>   &values) const
+    {
+      for (unsigned int c=0; c<this->n_components; ++c)
+       values(c) = TemperatureRightHandSide<dim>::value (p, c);
+    }
   }
-}
 
 
 
-                                // @sect3{Linear solvers and preconditioners}
-
-                                // This section introduces some objects
-                                // that are used for the solution of the
-                                // linear equations of the Stokes system
-                                // that we need to solve in each time
-                                // step. Many of the ideas used here are
-                                // the same as in step-20, where Schur
-                                // complement based preconditioners and
-                                // solvers have been introduced, with the
-                                // actual interface taken from step-22 (in
-                                // particular the discussion in the
-                                // "Results" section of step-22, in which
-                                // we introduce alternatives to the direct
-                                // Schur complement approach). Note,
-                                // however, that here we don't use the
-                                // Schur complement to solve the Stokes
-                                // equations, though an approximate Schur
-                                // complement (the mass matrix on the
-                                // pressure space) appears in the
-                                // preconditioner.
-namespace LinearSolvers
-{
-
-                                  // @sect4{The <code>InverseMatrix</code> class template}
-
-                                  // This class is an interface to
-                                  // calculate the action of an
-                                  // "inverted" matrix on a vector
-                                  // (using the <code>vmult</code>
-                                  // operation) in the same way as
-                                  // the corresponding class in
-                                  // step-22: when the product of an
-                                  // object of this class is
-                                  // requested, we solve a linear
-                                  // equation system with that matrix
-                                  // using the CG method, accelerated
-                                  // by a preconditioner of
-                                  // (templated) class
-                                  // <code>Preconditioner</code>.
-                                  //
-                                  // In a minor deviation from the
-                                  // implementation of the same class in
-                                  // step-22 (and step-20), we make the
-                                  // <code>vmult</code> function take any
-                                  // kind of vector type (it will yield
-                                  // compiler errors, however, if the matrix
-                                  // does not allow a matrix-vector product
-                                  // with this kind of vector).
-                                  //
-                                  // Secondly, we catch any exceptions that
-                                  // the solver may have thrown. The reason
-                                  // is as follows: When debugging a program
-                                  // like this one occasionally makes a
-                                  // mistake of passing an indefinite or
-                                  // non-symmetric matrix or preconditioner
-                                  // to the current class. The solver will,
-                                  // in that case, not converge and throw a
-                                  // run-time exception. If not caught here
-                                  // it will propagate up the call stack and
-                                  // may end up in <code>main()</code> where
-                                  // we output an error message that will say
-                                  // that the CG solver failed. The question
-                                  // then becomes: Which CG solver? The one
-                                  // that inverted the mass matrix? The one
-                                  // that inverted the top left block with
-                                  // the Laplace operator? Or a CG solver in
-                                  // one of the several other nested places
-                                  // where we use linear solvers in the
-                                  // current code? No indication about this
-                                  // is present in a run-time exception
-                                  // because it doesn't store the stack of
-                                  // calls through which we got to the place
-                                  // where the exception was generated.
-                                  //
-                                  // So rather than letting the exception
-                                  // propagate freely up to
-                                  // <code>main()</code> we realize that
-                                  // there is little that an outer function
-                                  // can do if the inner solver fails and
-                                  // rather convert the run-time exception
-                                  // into an assertion that fails and
-                                  // triggers a call to <code>abort()</code>,
-                                  // allowing us to trace back in a debugger
-                                  // how we got to the current place.
-  template <class Matrix, class Preconditioner>
-  class InverseMatrix : public Subscriptor
+                                  // @sect3{Linear solvers and preconditioners}
+
+                                  // This section introduces some objects
+                                  // that are used for the solution of the
+                                  // linear equations of the Stokes system
+                                  // that we need to solve in each time
+                                  // step. Many of the ideas used here are
+                                  // the same as in step-20, where Schur
+                                  // complement based preconditioners and
+                                  // solvers have been introduced, with the
+                                  // actual interface taken from step-22 (in
+                                  // particular the discussion in the
+                                  // "Results" section of step-22, in which
+                                  // we introduce alternatives to the direct
+                                  // Schur complement approach). Note,
+                                  // however, that here we don't use the
+                                  // Schur complement to solve the Stokes
+                                  // equations, though an approximate Schur
+                                  // complement (the mass matrix on the
+                                  // pressure space) appears in the
+                                  // preconditioner.
+  namespace LinearSolvers
   {
-    public:
-      InverseMatrix (const Matrix         &m,
-                    const Preconditioner &preconditioner);
 
+                                    // @sect4{The <code>InverseMatrix</code> class template}
+
+                                    // This class is an interface to
+                                    // calculate the action of an
+                                    // "inverted" matrix on a vector
+                                    // (using the <code>vmult</code>
+                                    // operation) in the same way as
+                                    // the corresponding class in
+                                    // step-22: when the product of an
+                                    // object of this class is
+                                    // requested, we solve a linear
+                                    // equation system with that matrix
+                                    // using the CG method, accelerated
+                                    // by a preconditioner of
+                                    // (templated) class
+                                    // <code>Preconditioner</code>.
+                                    //
+                                    // In a minor deviation from the
+                                    // implementation of the same class in
+                                    // step-22 (and step-20), we make the
+                                    // <code>vmult</code> function take any
+                                    // kind of vector type (it will yield
+                                    // compiler errors, however, if the matrix
+                                    // does not allow a matrix-vector product
+                                    // with this kind of vector).
+                                    //
+                                    // Secondly, we catch any exceptions that
+                                    // the solver may have thrown. The reason
+                                    // is as follows: When debugging a program
+                                    // like this one occasionally makes a
+                                    // mistake of passing an indefinite or
+                                    // non-symmetric matrix or preconditioner
+                                    // to the current class. The solver will,
+                                    // in that case, not converge and throw a
+                                    // run-time exception. If not caught here
+                                    // it will propagate up the call stack and
+                                    // may end up in <code>main()</code> where
+                                    // we output an error message that will say
+                                    // that the CG solver failed. The question
+                                    // then becomes: Which CG solver? The one
+                                    // that inverted the mass matrix? The one
+                                    // that inverted the top left block with
+                                    // the Laplace operator? Or a CG solver in
+                                    // one of the several other nested places
+                                    // where we use linear solvers in the
+                                    // current code? No indication about this
+                                    // is present in a run-time exception
+                                    // because it doesn't store the stack of
+                                    // calls through which we got to the place
+                                    // where the exception was generated.
+                                    //
+                                    // So rather than letting the exception
+                                    // propagate freely up to
+                                    // <code>main()</code> we realize that
+                                    // there is little that an outer function
+                                    // can do if the inner solver fails and
+                                    // rather convert the run-time exception
+                                    // into an assertion that fails and
+                                    // triggers a call to <code>abort()</code>,
+                                    // allowing us to trace back in a debugger
+                                    // how we got to the current place.
+    template <class Matrix, class Preconditioner>
+    class InverseMatrix : public Subscriptor
+    {
+      public:
+       InverseMatrix (const Matrix         &m,
+                      const Preconditioner &preconditioner);
 
-      template <typename VectorType>
-      void vmult (VectorType       &dst,
-                 const VectorType &src) const;
 
-    private:
-      const SmartPointer<const Matrix> matrix;
-      const Preconditioner &preconditioner;
-  };
+       template <typename VectorType>
+       void vmult (VectorType       &dst,
+                   const VectorType &src) const;
 
+      private:
+       const SmartPointer<const Matrix> matrix;
+       const Preconditioner &preconditioner;
+    };
 
-  template <class Matrix, class Preconditioner>
-  InverseMatrix<Matrix,Preconditioner>::
-  InverseMatrix (const Matrix &m,
-                const Preconditioner &preconditioner)
-                 :
-                 matrix (&m),
-                 preconditioner (preconditioner)
-  {}
 
+    template <class Matrix, class Preconditioner>
+    InverseMatrix<Matrix,Preconditioner>::
+    InverseMatrix (const Matrix &m,
+                  const Preconditioner &preconditioner)
+                   :
+                   matrix (&m),
+                   preconditioner (preconditioner)
+    {}
 
 
-  template <class Matrix, class Preconditioner>
-  template <typename VectorType>
-  void
-  InverseMatrix<Matrix,Preconditioner>::
-  vmult (VectorType       &dst,
-        const VectorType &src) const
-  {
-    SolverControl solver_control (src.size(), 1e-7*src.l2_norm());
-    SolverCG<VectorType> cg (solver_control);
 
-    dst = 0;
+    template <class Matrix, class Preconditioner>
+    template <typename VectorType>
+    void
+    InverseMatrix<Matrix,Preconditioner>::
+    vmult (VectorType       &dst,
+          const VectorType &src) const
+    {
+      SolverControl solver_control (src.size(), 1e-7*src.l2_norm());
+      SolverCG<VectorType> cg (solver_control);
+
+      dst = 0;
 
-    try
-      {
-       cg.solve (*matrix, dst, src, preconditioner);
-      }
-    catch (std::exception &e)
-      {
-       Assert (false, ExcMessage(e.what()));
-      }
+      try
+       {
+         cg.solve (*matrix, dst, src, preconditioner);
+       }
+      catch (std::exception &e)
+       {
+         Assert (false, ExcMessage(e.what()));
+       }
+    }
+
+                                    // @sect4{Schur complement preconditioner}
+
+                                    // This is the implementation of the
+                                    // Schur complement preconditioner as
+                                    // described in detail in the
+                                    // introduction. As opposed to step-20
+                                    // and step-22, we solve the block system
+                                    // all-at-once using GMRES, and use the
+                                    // Schur complement of the block
+                                    // structured matrix to build a good
+                                    // preconditioner instead.
+                                    //
+                                    // Let's have a look at the ideal
+                                    // preconditioner matrix
+                                    // $P=\left(\begin{array}{cc} A & 0 \\ B
+                                    // & -S \end{array}\right)$ described in
+                                    // the introduction. If we apply this
+                                    // matrix in the solution of a linear
+                                    // system, convergence of an iterative
+                                    // GMRES solver will be governed by the
+                                    // matrix
+                                    // @f{eqnarray*}
+                                    // P^{-1}\left(\begin{array}{cc} A
+                                    // & B^T \\ B & 0
+                                    // \end{array}\right) =
+                                    // \left(\begin{array}{cc} I &
+                                    // A^{-1} B^T \\ 0 & I
+                                    // \end{array}\right),
+                                    // @f}
+                                    // which indeed is very simple. A GMRES
+                                    // solver based on exact matrices would
+                                    // converge in one iteration, since all
+                                    // eigenvalues are equal (any Krylov
+                                    // method takes at most as many
+                                    // iterations as there are distinct
+                                    // eigenvalues). Such a preconditioner
+                                    // for the blocked Stokes system has been
+                                    // proposed by Silvester and Wathen
+                                    // ("Fast iterative solution of
+                                    // stabilised Stokes systems part II.
+                                    // Using general block preconditioners",
+                                    // SIAM J. Numer. Anal., 31 (1994),
+                                    // pp. 1352-1367).
+                                    //
+                                    // Replacing <i>P</i> by $\tilde{P}$
+                                    // keeps that spirit alive: the product
+                                    // $P^{-1} A$ will still be close to a
+                                    // matrix with eigenvalues 1 with a
+                                    // distribution that does not depend on
+                                    // the problem size. This lets us hope to
+                                    // be able to get a number of GMRES
+                                    // iterations that is problem-size
+                                    // independent.
+                                    //
+                                    // The deal.II users who have already
+                                    // gone through the step-20 and step-22
+                                    // tutorials can certainly imagine how
+                                    // we're going to implement this.  We
+                                    // replace the exact inverse matrices in
+                                    // $P^{-1}$ by some approximate inverses
+                                    // built from the InverseMatrix class,
+                                    // and the inverse Schur complement will
+                                    // be approximated by the pressure mass
+                                    // matrix $M_p$ (weighted by $\eta^{-1}$
+                                    // as mentioned in the introduction). As
+                                    // pointed out in the results section of
+                                    // step-22, we can replace the exact
+                                    // inverse of <i>A</i> by just the
+                                    // application of a preconditioner, in
+                                    // this case on a vector Laplace matrix
+                                    // as was explained in the
+                                    // introduction. This does increase the
+                                    // number of (outer) GMRES iterations,
+                                    // but is still significantly cheaper
+                                    // than an exact inverse, which would
+                                    // require between 20 and 35 CG
+                                    // iterations for <em>each</em> outer
+                                    // solver step (using the AMG
+                                    // preconditioner).
+                                    //
+                                    // Having the above explanations in mind,
+                                    // we define a preconditioner class with
+                                    // a <code>vmult</code> functionality,
+                                    // which is all we need for the
+                                    // interaction with the usual solver
+                                    // functions further below in the program
+                                    // code.
+                                    //
+                                    // First the declarations. These are
+                                    // similar to the definition of the Schur
+                                    // complement in step-20, with the
+                                    // difference that we need some more
+                                    // preconditioners in the constructor and
+                                    // that the matrices we use here are
+                                    // built upon Trilinos:
+    template <class PreconditionerA, class PreconditionerMp>
+    class BlockSchurPreconditioner : public Subscriptor
+    {
+      public:
+       BlockSchurPreconditioner (
+         const TrilinosWrappers::BlockSparseMatrix     &S,
+         const InverseMatrix<TrilinosWrappers::SparseMatrix,
+         PreconditionerMp>         &Mpinv,
+         const PreconditionerA                         &Apreconditioner);
+
+       void vmult (TrilinosWrappers::BlockVector       &dst,
+                   const TrilinosWrappers::BlockVector &src) const;
+
+      private:
+       const SmartPointer<const TrilinosWrappers::BlockSparseMatrix> stokes_matrix;
+       const SmartPointer<const InverseMatrix<TrilinosWrappers::SparseMatrix,
+                                              PreconditionerMp > > m_inverse;
+       const PreconditionerA &a_preconditioner;
+
+       mutable TrilinosWrappers::Vector tmp;
+    };
+
+
+
+    template <class PreconditionerA, class PreconditionerMp>
+    BlockSchurPreconditioner<PreconditionerA, PreconditionerMp>::
+    BlockSchurPreconditioner(const TrilinosWrappers::BlockSparseMatrix  &S,
+                            const InverseMatrix<TrilinosWrappers::SparseMatrix,
+                            PreconditionerMp>      &Mpinv,
+                            const PreconditionerA                      &Apreconditioner)
+                   :
+                   stokes_matrix           (&S),
+                   m_inverse               (&Mpinv),
+                   a_preconditioner        (Apreconditioner),
+                   tmp                     (stokes_matrix->block(1,1).m())
+    {}
+
+
+                                    // Next is the <code>vmult</code>
+                                    // function. We implement the action of
+                                    // $P^{-1}$ as described above in three
+                                    // successive steps.  In formulas, we want
+                                    // to compute $Y=P^{-1}X$ where $X,Y$ are
+                                    // both vectors with two block components.
+                                    //
+                                    // The first step multiplies the velocity
+                                    // part of the vector by a preconditioner
+                                    // of the matrix <i>A</i>, i.e. we compute
+                                    // $Y_0={\tilde A}^{-1}X_0$.  The resulting
+                                    // velocity vector is then multiplied by
+                                    // $B$ and subtracted from the pressure,
+                                    // i.e. we want to compute $X_1-BY_0$.
+                                    // This second step only acts on the
+                                    // pressure vector and is accomplished by
+                                    // the residual function of our matrix
+                                    // classes, except that the sign is
+                                    // wrong. Consequently, we change the sign
+                                    // in the temporary pressure vector and
+                                    // finally multiply by the inverse pressure
+                                    // mass matrix to get the final pressure
+                                    // vector, completing our work on the
+                                    // Stokes preconditioner:
+    template <class PreconditionerA, class PreconditionerMp>
+    void BlockSchurPreconditioner<PreconditionerA, PreconditionerMp>::vmult (
+      TrilinosWrappers::BlockVector       &dst,
+      const TrilinosWrappers::BlockVector &src) const
+    {
+      a_preconditioner.vmult (dst.block(0), src.block(0));
+      stokes_matrix->block(1,0).residual(tmp, dst.block(0), src.block(1));
+      tmp *= -1;
+      m_inverse->vmult (dst.block(1), tmp);
+    }
   }
 
-                                  // @sect4{Schur complement preconditioner}
-
-                                  // This is the implementation of the
-                                  // Schur complement preconditioner as
-                                  // described in detail in the
-                                  // introduction. As opposed to step-20
-                                  // and step-22, we solve the block system
-                                  // all-at-once using GMRES, and use the
-                                  // Schur complement of the block
-                                  // structured matrix to build a good
-                                  // preconditioner instead.
-                                  //
-                                  // Let's have a look at the ideal
-                                  // preconditioner matrix
-                                  // $P=\left(\begin{array}{cc} A & 0 \\ B
-                                  // & -S \end{array}\right)$ described in
-                                  // the introduction. If we apply this
-                                  // matrix in the solution of a linear
-                                  // system, convergence of an iterative
-                                  // GMRES solver will be governed by the
-                                  // matrix
-                                  // @f{eqnarray*}
-                                  // P^{-1}\left(\begin{array}{cc} A
-                                  // & B^T \\ B & 0
-                                  // \end{array}\right) =
-                                  // \left(\begin{array}{cc} I &
-                                  // A^{-1} B^T \\ 0 & I
-                                  // \end{array}\right),
-                                  // @f}
-                                  // which indeed is very simple. A GMRES
-                                  // solver based on exact matrices would
-                                  // converge in one iteration, since all
-                                  // eigenvalues are equal (any Krylov
-                                  // method takes at most as many
-                                  // iterations as there are distinct
-                                  // eigenvalues). Such a preconditioner
-                                  // for the blocked Stokes system has been
-                                  // proposed by Silvester and Wathen
-                                  // ("Fast iterative solution of
-                                  // stabilised Stokes systems part II.
-                                  // Using general block preconditioners",
-                                  // SIAM J. Numer. Anal., 31 (1994),
-                                  // pp. 1352-1367).
-                                  //
-                                  // Replacing <i>P</i> by $\tilde{P}$
-                                  // keeps that spirit alive: the product
-                                  // $P^{-1} A$ will still be close to a
-                                  // matrix with eigenvalues 1 with a
-                                  // distribution that does not depend on
-                                  // the problem size. This lets us hope to
-                                  // be able to get a number of GMRES
-                                  // iterations that is problem-size
-                                  // independent.
-                                  //
-                                  // The deal.II users who have already
-                                  // gone through the step-20 and step-22
-                                  // tutorials can certainly imagine how
-                                  // we're going to implement this.  We
-                                  // replace the exact inverse matrices in
-                                  // $P^{-1}$ by some approximate inverses
-                                  // built from the InverseMatrix class,
-                                  // and the inverse Schur complement will
-                                  // be approximated by the pressure mass
-                                  // matrix $M_p$ (weighted by $\eta^{-1}$
-                                  // as mentioned in the introduction). As
-                                  // pointed out in the results section of
-                                  // step-22, we can replace the exact
-                                  // inverse of <i>A</i> by just the
-                                  // application of a preconditioner, in
-                                  // this case on a vector Laplace matrix
-                                  // as was explained in the
-                                  // introduction. This does increase the
-                                  // number of (outer) GMRES iterations,
-                                  // but is still significantly cheaper
-                                  // than an exact inverse, which would
-                                  // require between 20 and 35 CG
-                                  // iterations for <em>each</em> outer
-                                  // solver step (using the AMG
-                                  // preconditioner).
+
+
+                                  // @sect3{The <code>BoussinesqFlowProblem</code> class template}
+
+                                  // The definition of the class that defines
+                                  // the top-level logic of solving the
+                                  // time-dependent Boussinesq problem is
+                                  // mainly based on the step-22 tutorial
+                                  // program. The main differences are that now
+                                  // we also have to solve for the temperature
+                                  // equation, which forces us to have a second
+                                  // DoFHandler object for the temperature
+                                  // variable as well as matrices, right hand
+                                  // sides, and solution vectors for the
+                                  // current and previous time steps. As
+                                  // mentioned in the introduction, all linear
+                                  // algebra objects are going to use wrappers
+                                  // of the corresponding Trilinos
+                                  // functionality.
                                   //
-                                  // Having the above explanations in mind,
-                                  // we define a preconditioner class with
-                                  // a <code>vmult</code> functionality,
-                                  // which is all we need for the
-                                  // interaction with the usual solver
-                                  // functions further below in the program
-                                  // code.
+                                  // The member functions of this class are
+                                  // reminiscent of step-21, where we also used
+                                  // a staggered scheme that first solve the
+                                  // flow equations (here the Stokes equations,
+                                  // in step-21 Darcy flow) and then update
+                                  // the advected quantity (here the
+                                  // temperature, there the saturation). The
+                                  // functions that are new are mainly
+                                  // concerned with determining the time step,
+                                  // as well as the proper size of the
+                                  // artificial viscosity stabilization.
                                   //
-                                  // First the declarations. These are
-                                  // similar to the definition of the Schur
-                                  // complement in step-20, with the
-                                  // difference that we need some more
-                                  // preconditioners in the constructor and
-                                  // that the matrices we use here are
-                                  // built upon Trilinos:
-  template <class PreconditionerA, class PreconditionerMp>
-  class BlockSchurPreconditioner : public Subscriptor
+                                  // The last three variables indicate whether
+                                  // the various matrices or preconditioners
+                                  // need to be rebuilt the next time the
+                                  // corresponding build functions are
+                                  // called. This allows us to move the
+                                  // corresponding <code>if</code> into the
+                                  // respective function and thereby keeping
+                                  // our main <code>run()</code> function clean
+                                  // and easy to read.
+  template <int dim>
+  class BoussinesqFlowProblem
   {
     public:
-      BlockSchurPreconditioner (
-       const TrilinosWrappers::BlockSparseMatrix     &S,
-       const InverseMatrix<TrilinosWrappers::SparseMatrix,
-                           PreconditionerMp>         &Mpinv,
-       const PreconditionerA                         &Apreconditioner);
-
-      void vmult (TrilinosWrappers::BlockVector       &dst,
-                 const TrilinosWrappers::BlockVector &src) const;
+      BoussinesqFlowProblem ();
+      void run ();
 
     private:
-      const SmartPointer<const TrilinosWrappers::BlockSparseMatrix> stokes_matrix;
-      const SmartPointer<const InverseMatrix<TrilinosWrappers::SparseMatrix,
-                                            PreconditionerMp > > m_inverse;
-      const PreconditionerA &a_preconditioner;
-
-      mutable TrilinosWrappers::Vector tmp;
+      void setup_dofs ();
+      void assemble_stokes_preconditioner ();
+      void build_stokes_preconditioner ();
+      void assemble_stokes_system ();
+      void assemble_temperature_system (const double maximal_velocity);
+      void assemble_temperature_matrix ();
+      double get_maximal_velocity () const;
+      std::pair<double,double> get_extrapolated_temperature_range () const;
+      void solve ();
+      void output_results () const;
+      void refine_mesh (const unsigned int max_grid_level);
+
+      double
+      compute_viscosity(const std::vector<double>          &old_temperature,
+                       const std::vector<double>          &old_old_temperature,
+                       const std::vector<Tensor<1,dim> >  &old_temperature_grads,
+                       const std::vector<Tensor<1,dim> >  &old_old_temperature_grads,
+                       const std::vector<double>          &old_temperature_laplacians,
+                       const std::vector<double>          &old_old_temperature_laplacians,
+                       const std::vector<Tensor<1,dim> >  &old_velocity_values,
+                       const std::vector<Tensor<1,dim> >  &old_old_velocity_values,
+                       const std::vector<double>          &gamma_values,
+                       const double                        global_u_infty,
+                       const double                        global_T_variation,
+                       const double                        cell_diameter) const;
+
+
+      Triangulation<dim>                  triangulation;
+      double                              global_Omega_diameter;
+
+      const unsigned int                  stokes_degree;
+      FESystem<dim>                       stokes_fe;
+      DoFHandler<dim>                     stokes_dof_handler;
+      ConstraintMatrix                    stokes_constraints;
+
+      std::vector<unsigned int>           stokes_block_sizes;
+      TrilinosWrappers::BlockSparseMatrix stokes_matrix;
+      TrilinosWrappers::BlockSparseMatrix stokes_preconditioner_matrix;
+
+      TrilinosWrappers::BlockVector       stokes_solution;
+      TrilinosWrappers::BlockVector       old_stokes_solution;
+      TrilinosWrappers::BlockVector       stokes_rhs;
+
+
+      const unsigned int                  temperature_degree;
+      FE_Q<dim>                           temperature_fe;
+      DoFHandler<dim>                     temperature_dof_handler;
+      ConstraintMatrix                    temperature_constraints;
+
+      TrilinosWrappers::SparseMatrix      temperature_mass_matrix;
+      TrilinosWrappers::SparseMatrix      temperature_stiffness_matrix;
+      TrilinosWrappers::SparseMatrix      temperature_matrix;
+
+      TrilinosWrappers::Vector            temperature_solution;
+      TrilinosWrappers::Vector            old_temperature_solution;
+      TrilinosWrappers::Vector            old_old_temperature_solution;
+      TrilinosWrappers::Vector            temperature_rhs;
+
+
+      double time_step;
+      double old_time_step;
+      unsigned int timestep_number;
+
+      std_cxx1x::shared_ptr<TrilinosWrappers::PreconditionAMG> Amg_preconditioner;
+      std_cxx1x::shared_ptr<TrilinosWrappers::PreconditionIC>  Mp_preconditioner;
+
+      bool rebuild_stokes_matrix;
+      bool rebuild_temperature_matrices;
+      bool rebuild_stokes_preconditioner;
   };
 
 
+                                  // @sect3{BoussinesqFlowProblem class implementation}
 
-  template <class PreconditionerA, class PreconditionerMp>
-  BlockSchurPreconditioner<PreconditionerA, PreconditionerMp>::
-  BlockSchurPreconditioner(const TrilinosWrappers::BlockSparseMatrix  &S,
-                          const InverseMatrix<TrilinosWrappers::SparseMatrix,
-                                              PreconditionerMp>      &Mpinv,
-                          const PreconditionerA                      &Apreconditioner)
+                                  // @sect4{BoussinesqFlowProblem::BoussinesqFlowProblem}
+                                  //
+                                  // The constructor of this class is an
+                                  // extension of the constructor in
+                                  // step-22. We need to add the various
+                                  // variables that concern the temperature. As
+                                  // discussed in the introduction, we are
+                                  // going to use $Q_2\times Q_1$ (Taylor-Hood)
+                                  // elements again for the Stokes part, and
+                                  // $Q_2$ elements for the
+                                  // temperature. However, by using variables
+                                  // that store the polynomial degree of the
+                                  // Stokes and temperature finite elements, it
+                                  // is easy to consistently modify the degree
+                                  // of the elements as well as all quadrature
+                                  // formulas used on them
+                                  // downstream. Moreover, we initialize the
+                                  // time stepping as well as the options for
+                                  // matrix assembly and preconditioning:
+  template <int dim>
+  BoussinesqFlowProblem<dim>::BoussinesqFlowProblem ()
                  :
-                 stokes_matrix           (&S),
-                 m_inverse               (&Mpinv),
-                 a_preconditioner        (Apreconditioner),
-                 tmp                     (stokes_matrix->block(1,1).m())
+                 triangulation (Triangulation<dim>::maximum_smoothing),
+
+                 stokes_degree (1),
+                 stokes_fe (FE_Q<dim>(stokes_degree+1), dim,
+                            FE_Q<dim>(stokes_degree), 1),
+                 stokes_dof_handler (triangulation),
+
+                 temperature_degree (2),
+                 temperature_fe (temperature_degree),
+                 temperature_dof_handler (triangulation),
+
+                 time_step (0),
+                 old_time_step (0),
+                 timestep_number (0),
+                 rebuild_stokes_matrix (true),
+                 rebuild_temperature_matrices (true),
+                 rebuild_stokes_preconditioner (true)
   {}
 
 
-                                  // Next is the <code>vmult</code>
-                                  // function. We implement the action of
-                                  // $P^{-1}$ as described above in three
-                                  // successive steps.  In formulas, we want
-                                  // to compute $Y=P^{-1}X$ where $X,Y$ are
-                                  // both vectors with two block components.
+
+                                  // @sect4{BoussinesqFlowProblem::get_maximal_velocity}
+
+                                  // Starting the real functionality of this
+                                  // class is a helper function that determines
+                                  // the maximum ($L_\infty$) velocity in the
+                                  // domain (at the quadrature points, in
+                                  // fact). How it works should be relatively
+                                  // obvious to all who have gotten to this
+                                  // point of the tutorial. Note that since we
+                                  // are only interested in the velocity,
+                                  // rather than using
+                                  // <code>stokes_fe_values.get_function_values</code>
+                                  // to get the values of the entire Stokes
+                                  // solution (velocities and pressures) we use
+                                  // <code>stokes_fe_values[velocities].get_function_values</code>
+                                  // to extract only the velocities part. This
+                                  // has the additional benefit that we get it
+                                  // as a Tensor<1,dim>, rather than some
+                                  // components in a Vector<double>, allowing
+                                  // us to process it right away using the
+                                  // <code>norm()</code> function to get the
+                                  // magnitude of the velocity.
+                                  //
+                                  // The only point worth thinking about a bit
+                                  // is how to choose the quadrature points we
+                                  // use here. Since the goal of this function
+                                  // is to find the maximal velocity over a
+                                  // domain by looking at quadrature points on
+                                  // each cell. So we should ask how we should
+                                  // best choose these quadrature points on
+                                  // each cell. To this end, recall that if we
+                                  // had a single $Q_1$ field (rather than the
+                                  // vector-valued field of higher order) then
+                                  // the maximum would be attained at a vertex
+                                  // of the mesh. In other words, we should use
+                                  // the QTrapez class that has quadrature
+                                  // points only at the vertices of cells.
+                                  //
+                                  // For higher order shape functions, the
+                                  // situation is more complicated: the maxima
+                                  // and minima may be attained at points
+                                  // between the support points of shape
+                                  // functions (for the usual $Q_p$ elements
+                                  // the support points are the equidistant
+                                  // Lagrange interpolation points);
+                                  // furthermore, since we are looking for the
+                                  // maximum magnitude of a vector-valued
+                                  // quantity, we can even less say with
+                                  // certainty where the set of potential
+                                  // maximal points are. Nevertheless,
+                                  // intuitively if not provably, the Lagrange
+                                  // interpolation points appear to be a better
+                                  // choice than the Gauss points.
                                   //
-                                  // The first step multiplies the velocity
-                                  // part of the vector by a preconditioner
-                                  // of the matrix <i>A</i>, i.e. we compute
-                                  // $Y_0={\tilde A}^{-1}X_0$.  The resulting
-                                  // velocity vector is then multiplied by
-                                  // $B$ and subtracted from the pressure,
-                                  // i.e. we want to compute $X_1-BY_0$.
-                                  // This second step only acts on the
-                                  // pressure vector and is accomplished by
-                                  // the residual function of our matrix
-                                  // classes, except that the sign is
-                                  // wrong. Consequently, we change the sign
-                                  // in the temporary pressure vector and
-                                  // finally multiply by the inverse pressure
-                                  // mass matrix to get the final pressure
-                                  // vector, completing our work on the
-                                  // Stokes preconditioner:
-  template <class PreconditionerA, class PreconditionerMp>
-  void BlockSchurPreconditioner<PreconditionerA, PreconditionerMp>::vmult (
-    TrilinosWrappers::BlockVector       &dst,
-    const TrilinosWrappers::BlockVector &src) const
+                                  // There are now different methods to produce
+                                  // a quadrature formula with quadrature
+                                  // points equal to the interpolation points
+                                  // of the finite element. One option would be
+                                  // to use the
+                                  // FiniteElement::get_unit_support_points()
+                                  // function, reduce the output to a unique
+                                  // set of points to avoid duplicate function
+                                  // evaluations, and create a Quadrature
+                                  // object using these points. Another option,
+                                  // chosen here, is to use the QTrapez class
+                                  // and combine it with the QIterated class
+                                  // that repeats the QTrapez formula on a
+                                  // number of sub-cells in each coordinate
+                                  // direction. To cover all support points, we
+                                  // need to iterate it
+                                  // <code>stokes_degree+1</code> times since
+                                  // this is the polynomial degree of the
+                                  // Stokes element in use:
+  template <int dim>
+  double BoussinesqFlowProblem<dim>::get_maximal_velocity () const
   {
-    a_preconditioner.vmult (dst.block(0), src.block(0));
-    stokes_matrix->block(1,0).residual(tmp, dst.block(0), src.block(1));
-    tmp *= -1;
-    m_inverse->vmult (dst.block(1), tmp);
-  }
-}
+    const QIterated<dim> quadrature_formula (QTrapez<1>(),
+                                            stokes_degree+1);
+    const unsigned int n_q_points = quadrature_formula.size();
 
+    FEValues<dim> fe_values (stokes_fe, quadrature_formula, update_values);
+    std::vector<Tensor<1,dim> > velocity_values(n_q_points);
+    double max_velocity = 0;
 
+    const FEValuesExtractors::Vector velocities (0);
 
-                                // @sect3{The <code>BoussinesqFlowProblem</code> class template}
-
-                                // The definition of the class that defines
-                                // the top-level logic of solving the
-                                // time-dependent Boussinesq problem is
-                                // mainly based on the step-22 tutorial
-                                // program. The main differences are that now
-                                // we also have to solve for the temperature
-                                // equation, which forces us to have a second
-                                // DoFHandler object for the temperature
-                                // variable as well as matrices, right hand
-                                // sides, and solution vectors for the
-                                // current and previous time steps. As
-                                // mentioned in the introduction, all linear
-                                // algebra objects are going to use wrappers
-                                // of the corresponding Trilinos
-                                // functionality.
-                                //
-                                // The member functions of this class are
-                                // reminiscent of step-21, where we also used
-                                // a staggered scheme that first solve the
-                                // flow equations (here the Stokes equations,
-                                // in step-21 Darcy flow) and then update
-                                // the advected quantity (here the
-                                // temperature, there the saturation). The
-                                // functions that are new are mainly
-                                // concerned with determining the time step,
-                                // as well as the proper size of the
-                                // artificial viscosity stabilization.
-                                //
-                                // The last three variables indicate whether
-                                // the various matrices or preconditioners
-                                // need to be rebuilt the next time the
-                                // corresponding build functions are
-                                // called. This allows us to move the
-                                // corresponding <code>if</code> into the
-                                // respective function and thereby keeping
-                                // our main <code>run()</code> function clean
-                                // and easy to read.
-template <int dim>
-class BoussinesqFlowProblem
-{
-  public:
-    BoussinesqFlowProblem ();
-    void run ();
-
-  private:
-    void setup_dofs ();
-    void assemble_stokes_preconditioner ();
-    void build_stokes_preconditioner ();
-    void assemble_stokes_system ();
-    void assemble_temperature_system (const double maximal_velocity);
-    void assemble_temperature_matrix ();
-    double get_maximal_velocity () const;
-    std::pair<double,double> get_extrapolated_temperature_range () const;
-    void solve ();
-    void output_results () const;
-    void refine_mesh (const unsigned int max_grid_level);
+    typename DoFHandler<dim>::active_cell_iterator
+      cell = stokes_dof_handler.begin_active(),
+      endc = stokes_dof_handler.end();
+    for (; cell!=endc; ++cell)
+      {
+       fe_values.reinit (cell);
+       fe_values[velocities].get_function_values (stokes_solution,
+                                                  velocity_values);
 
-    double
-    compute_viscosity(const std::vector<double>          &old_temperature,
-                     const std::vector<double>          &old_old_temperature,
-                     const std::vector<Tensor<1,dim> >  &old_temperature_grads,
-                     const std::vector<Tensor<1,dim> >  &old_old_temperature_grads,
-                     const std::vector<double>          &old_temperature_laplacians,
-                     const std::vector<double>          &old_old_temperature_laplacians,
-                     const std::vector<Tensor<1,dim> >  &old_velocity_values,
-                     const std::vector<Tensor<1,dim> >  &old_old_velocity_values,
-                     const std::vector<double>          &gamma_values,
-                     const double                        global_u_infty,
-                     const double                        global_T_variation,
-                     const double                        cell_diameter) const;
+       for (unsigned int q=0; q<n_q_points; ++q)
+         max_velocity = std::max (max_velocity, velocity_values[q].norm());
+      }
 
+    return max_velocity;
+  }
 
-    Triangulation<dim>                  triangulation;
-    double                              global_Omega_diameter;
 
-    const unsigned int                  stokes_degree;
-    FESystem<dim>                       stokes_fe;
-    DoFHandler<dim>                     stokes_dof_handler;
-    ConstraintMatrix                    stokes_constraints;
 
-    std::vector<unsigned int>           stokes_block_sizes;
-    TrilinosWrappers::BlockSparseMatrix stokes_matrix;
-    TrilinosWrappers::BlockSparseMatrix stokes_preconditioner_matrix;
 
-    TrilinosWrappers::BlockVector       stokes_solution;
-    TrilinosWrappers::BlockVector       old_stokes_solution;
-    TrilinosWrappers::BlockVector       stokes_rhs;
+                                  // @sect4{BoussinesqFlowProblem::get_extrapolated_temperature_range}
 
+                                  // Next a function that determines the
+                                  // minimum and maximum temperature at
+                                  // quadrature points inside $\Omega$ when
+                                  // extrapolated from the two previous time
+                                  // steps to the current one. We need this
+                                  // information in the computation of the
+                                  // artificial viscosity parameter $\nu$ as
+                                  // discussed in the introduction.
+                                  //
+                                  // The formula for the extrapolated
+                                  // temperature is
+                                  // $\left(1+\frac{k_n}{k_{n-1}}
+                                  // \right)T^{n-1} + \frac{k_n}{k_{n-1}}
+                                  // T^{n-2}$. The way to compute it is to loop
+                                  // over all quadrature points and update the
+                                  // maximum and minimum value if the current
+                                  // value is bigger/smaller than the previous
+                                  // one. We initialize the variables that
+                                  // store the max and min before the loop over
+                                  // all quadrature points by the smallest and
+                                  // the largest number representable as a
+                                  // double. Then we know for a fact that it is
+                                  // larger/smaller than the minimum/maximum
+                                  // and that the loop over all quadrature
+                                  // points is ultimately going to update the
+                                  // initial value with the correct one.
+                                  //
+                                  // The only other complication worth
+                                  // mentioning here is that in the first time
+                                  // step, $T^{k-2}$ is not yet available of
+                                  // course. In that case, we can only use
+                                  // $T^{k-1}$ which we have from the initial
+                                  // temperature. As quadrature points, we use
+                                  // the same choice as in the previous
+                                  // function though with the difference that
+                                  // now the number of repetitions is
+                                  // determined by the polynomial degree of the
+                                  // temperature field.
+  template <int dim>
+  std::pair<double,double>
+  BoussinesqFlowProblem<dim>::get_extrapolated_temperature_range () const
+  {
+    const QIterated<dim> quadrature_formula (QTrapez<1>(),
+                                            temperature_degree);
+    const unsigned int n_q_points = quadrature_formula.size();
 
-    const unsigned int                  temperature_degree;
-    FE_Q<dim>                           temperature_fe;
-    DoFHandler<dim>                     temperature_dof_handler;
-    ConstraintMatrix                    temperature_constraints;
+    FEValues<dim> fe_values (temperature_fe, quadrature_formula,
+                            update_values);
+    std::vector<double> old_temperature_values(n_q_points);
+    std::vector<double> old_old_temperature_values(n_q_points);
 
-    TrilinosWrappers::SparseMatrix      temperature_mass_matrix;
-    TrilinosWrappers::SparseMatrix      temperature_stiffness_matrix;
-    TrilinosWrappers::SparseMatrix      temperature_matrix;
+    if (timestep_number != 0)
+      {
+       double min_temperature = std::numeric_limits<double>::max(),
+              max_temperature = -std::numeric_limits<double>::max();
+
+       typename DoFHandler<dim>::active_cell_iterator
+         cell = temperature_dof_handler.begin_active(),
+         endc = temperature_dof_handler.end();
+       for (; cell!=endc; ++cell)
+         {
+           fe_values.reinit (cell);
+           fe_values.get_function_values (old_temperature_solution,
+                                          old_temperature_values);
+           fe_values.get_function_values (old_old_temperature_solution,
+                                          old_old_temperature_values);
+
+           for (unsigned int q=0; q<n_q_points; ++q)
+             {
+               const double temperature =
+                 (1. + time_step/old_time_step) * old_temperature_values[q]-
+                 time_step/old_time_step * old_old_temperature_values[q];
 
-    TrilinosWrappers::Vector            temperature_solution;
-    TrilinosWrappers::Vector            old_temperature_solution;
-    TrilinosWrappers::Vector            old_old_temperature_solution;
-    TrilinosWrappers::Vector            temperature_rhs;
+               min_temperature = std::min (min_temperature, temperature);
+               max_temperature = std::max (max_temperature, temperature);
+             }
+         }
 
+       return std::make_pair(min_temperature, max_temperature);
+      }
+    else
+      {
+       double min_temperature = std::numeric_limits<double>::max(),
+              max_temperature = -std::numeric_limits<double>::max();
+
+       typename DoFHandler<dim>::active_cell_iterator
+         cell = temperature_dof_handler.begin_active(),
+         endc = temperature_dof_handler.end();
+       for (; cell!=endc; ++cell)
+         {
+           fe_values.reinit (cell);
+           fe_values.get_function_values (old_temperature_solution,
+                                          old_temperature_values);
+
+           for (unsigned int q=0; q<n_q_points; ++q)
+             {
+               const double temperature = old_temperature_values[q];
 
-    double time_step;
-    double old_time_step;
-    unsigned int timestep_number;
+               min_temperature = std::min (min_temperature, temperature);
+               max_temperature = std::max (max_temperature, temperature);
+             }
+         }
 
-    std_cxx1x::shared_ptr<TrilinosWrappers::PreconditionAMG> Amg_preconditioner;
-    std_cxx1x::shared_ptr<TrilinosWrappers::PreconditionIC>  Mp_preconditioner;
+       return std::make_pair(min_temperature, max_temperature);
+      }
+  }
 
-    bool rebuild_stokes_matrix;
-    bool rebuild_temperature_matrices;
-    bool rebuild_stokes_preconditioner;
-};
 
 
-                                // @sect3{BoussinesqFlowProblem class implementation}
+                                  // @sect4{BoussinesqFlowProblem::compute_viscosity}
 
-                                // @sect4{BoussinesqFlowProblem::BoussinesqFlowProblem}
-                                //
-                                // The constructor of this class is an
-                                // extension of the constructor in
-                                // step-22. We need to add the various
-                                // variables that concern the temperature. As
-                                // discussed in the introduction, we are
-                                // going to use $Q_2\times Q_1$ (Taylor-Hood)
-                                // elements again for the Stokes part, and
-                                // $Q_2$ elements for the
-                                // temperature. However, by using variables
-                                // that store the polynomial degree of the
-                                // Stokes and temperature finite elements, it
-                                // is easy to consistently modify the degree
-                                // of the elements as well as all quadrature
-                                // formulas used on them
-                                // downstream. Moreover, we initialize the
-                                // time stepping as well as the options for
-                                // matrix assembly and preconditioning:
-template <int dim>
-BoussinesqFlowProblem<dim>::BoussinesqFlowProblem ()
-                :
-               triangulation (Triangulation<dim>::maximum_smoothing),
-
-                stokes_degree (1),
-                stokes_fe (FE_Q<dim>(stokes_degree+1), dim,
-                          FE_Q<dim>(stokes_degree), 1),
-               stokes_dof_handler (triangulation),
-
-               temperature_degree (2),
-               temperature_fe (temperature_degree),
-                temperature_dof_handler (triangulation),
-
-                time_step (0),
-               old_time_step (0),
-               timestep_number (0),
-               rebuild_stokes_matrix (true),
-               rebuild_temperature_matrices (true),
-               rebuild_stokes_preconditioner (true)
-{}
-
-
-
-                                // @sect4{BoussinesqFlowProblem::get_maximal_velocity}
-
-                                // Starting the real functionality of this
-                                // class is a helper function that determines
-                                // the maximum ($L_\infty$) velocity in the
-                                // domain (at the quadrature points, in
-                                // fact). How it works should be relatively
-                                // obvious to all who have gotten to this
-                                // point of the tutorial. Note that since we
-                                // are only interested in the velocity,
-                                // rather than using
-                                // <code>stokes_fe_values.get_function_values</code>
-                                // to get the values of the entire Stokes
-                                // solution (velocities and pressures) we use
-                                // <code>stokes_fe_values[velocities].get_function_values</code>
-                                // to extract only the velocities part. This
-                                // has the additional benefit that we get it
-                                // as a Tensor<1,dim>, rather than some
-                                // components in a Vector<double>, allowing
-                                // us to process it right away using the
-                                // <code>norm()</code> function to get the
-                                // magnitude of the velocity.
-                                //
-                                // The only point worth thinking about a bit
-                                // is how to choose the quadrature points we
-                                // use here. Since the goal of this function
-                                // is to find the maximal velocity over a
-                                // domain by looking at quadrature points on
-                                // each cell. So we should ask how we should
-                                // best choose these quadrature points on
-                                // each cell. To this end, recall that if we
-                                // had a single $Q_1$ field (rather than the
-                                // vector-valued field of higher order) then
-                                // the maximum would be attained at a vertex
-                                // of the mesh. In other words, we should use
-                                // the QTrapez class that has quadrature
-                                // points only at the vertices of cells.
-                                //
-                                // For higher order shape functions, the
-                                // situation is more complicated: the maxima
-                                // and minima may be attained at points
-                                // between the support points of shape
-                                // functions (for the usual $Q_p$ elements
-                                // the support points are the equidistant
-                                // Lagrange interpolation points);
-                                // furthermore, since we are looking for the
-                                // maximum magnitude of a vector-valued
-                                // quantity, we can even less say with
-                                // certainty where the set of potential
-                                // maximal points are. Nevertheless,
-                                // intuitively if not provably, the Lagrange
-                                // interpolation points appear to be a better
-                                // choice than the Gauss points.
-                                //
-                                // There are now different methods to produce
-                                // a quadrature formula with quadrature
-                                // points equal to the interpolation points
-                                // of the finite element. One option would be
-                                // to use the
-                                // FiniteElement::get_unit_support_points()
-                                // function, reduce the output to a unique
-                                // set of points to avoid duplicate function
-                                // evaluations, and create a Quadrature
-                                // object using these points. Another option,
-                                // chosen here, is to use the QTrapez class
-                                // and combine it with the QIterated class
-                                // that repeats the QTrapez formula on a
-                                // number of sub-cells in each coordinate
-                                // direction. To cover all support points, we
-                                // need to iterate it
-                                // <code>stokes_degree+1</code> times since
-                                // this is the polynomial degree of the
-                                // Stokes element in use:
-template <int dim>
-double BoussinesqFlowProblem<dim>::get_maximal_velocity () const
-{
-  const QIterated<dim> quadrature_formula (QTrapez<1>(),
-                                          stokes_degree+1);
-  const unsigned int n_q_points = quadrature_formula.size();
+                                  // The last of the tool functions computes
+                                  // the artificial viscosity parameter
+                                  // $\nu|_K$ on a cell $K$ as a function of
+                                  // the extrapolated temperature, its
+                                  // gradient and Hessian (second
+                                  // derivatives), the velocity, the right
+                                  // hand side $\gamma$ all on the quadrature
+                                  // points of the current cell, and various
+                                  // other parameters as described in detail
+                                  // in the introduction.
+                                  //
+                                  // There are some universal constants worth
+                                  // mentioning here. First, we need to fix
+                                  // $\beta$; we choose $\beta=0.015\cdot
+                                  // dim$, a choice discussed in detail in
+                                  // the results section of this tutorial
+                                  // program. The second is the exponent
+                                  // $\alpha$; $\alpha=1$ appears to work
+                                  // fine for the current program, even
+                                  // though some additional benefit might be
+                                  // expected from chosing $\alpha =
+                                  // 2$. Finally, there is one thing that
+                                  // requires special casing: In the first
+                                  // time step, the velocity equals zero, and
+                                  // the formula for $\nu|_K$ is not
+                                  // defined. In that case, we return
+                                  // $\nu|_K=5\cdot 10^3 \cdot h_K$, a choice
+                                  // admittedly more motivated by heuristics
+                                  // than anything else (it is in the same
+                                  // order of magnitude, however, as the
+                                  // value returned for most cells on the
+                                  // second time step).
+                                  //
+                                  // The rest of the function should be
+                                  // mostly obvious based on the material
+                                  // discussed in the introduction:
+  template <int dim>
+  double
+  BoussinesqFlowProblem<dim>::
+  compute_viscosity (const std::vector<double>          &old_temperature,
+                    const std::vector<double>          &old_old_temperature,
+                    const std::vector<Tensor<1,dim> >  &old_temperature_grads,
+                    const std::vector<Tensor<1,dim> >  &old_old_temperature_grads,
+                    const std::vector<double>          &old_temperature_laplacians,
+                    const std::vector<double>          &old_old_temperature_laplacians,
+                    const std::vector<Tensor<1,dim> >  &old_velocity_values,
+                    const std::vector<Tensor<1,dim> >  &old_old_velocity_values,
+                    const std::vector<double>          &gamma_values,
+                    const double                        global_u_infty,
+                    const double                        global_T_variation,
+                    const double                        cell_diameter) const
+  {
+    const double beta = 0.015 * dim;
+    const double alpha = 1;
 
-  FEValues<dim> fe_values (stokes_fe, quadrature_formula, update_values);
-  std::vector<Tensor<1,dim> > velocity_values(n_q_points);
-  double max_velocity = 0;
+    if (global_u_infty == 0)
+      return 5e-3 * cell_diameter;
 
-  const FEValuesExtractors::Vector velocities (0);
+    const unsigned int n_q_points = old_temperature.size();
 
-  typename DoFHandler<dim>::active_cell_iterator
-    cell = stokes_dof_handler.begin_active(),
-    endc = stokes_dof_handler.end();
-  for (; cell!=endc; ++cell)
-    {
-      fe_values.reinit (cell);
-      fe_values[velocities].get_function_values (stokes_solution,
-                                                velocity_values);
+    double max_residual = 0;
+    double max_velocity = 0;
 
-      for (unsigned int q=0; q<n_q_points; ++q)
-       max_velocity = std::max (max_velocity, velocity_values[q].norm());
-    }
+    for (unsigned int q=0; q < n_q_points; ++q)
+      {
+       const Tensor<1,dim> u = (old_velocity_values[q] +
+                                old_old_velocity_values[q]) / 2;
 
-  return max_velocity;
-}
+       const double dT_dt = (old_temperature[q] - old_old_temperature[q])
+                            / old_time_step;
+       const double u_grad_T = u * (old_temperature_grads[q] +
+                                    old_old_temperature_grads[q]) / 2;
 
+       const double kappa_Delta_T = EquationData::kappa
+                                    * (old_temperature_laplacians[q] +
+                                       old_old_temperature_laplacians[q]) / 2;
 
+       const double residual
+         = std::abs((dT_dt + u_grad_T - kappa_Delta_T - gamma_values[q]) *
+                    std::pow((old_temperature[q]+old_old_temperature[q]) / 2,
+                             alpha-1.));
 
+       max_residual = std::max (residual,        max_residual);
+       max_velocity = std::max (std::sqrt (u*u), max_velocity);
+      }
 
-                                // @sect4{BoussinesqFlowProblem::get_extrapolated_temperature_range}
+    const double c_R = std::pow (2., (4.-2*alpha)/dim);
+    const double global_scaling = c_R * global_u_infty * global_T_variation *
+                                 std::pow(global_Omega_diameter, alpha - 2.);
 
-                                // Next a function that determines the
-                                // minimum and maximum temperature at
-                                // quadrature points inside $\Omega$ when
-                                // extrapolated from the two previous time
-                                // steps to the current one. We need this
-                                // information in the computation of the
-                                // artificial viscosity parameter $\nu$ as
-                                // discussed in the introduction.
-                                //
-                                // The formula for the extrapolated
-                                // temperature is
-                                // $\left(1+\frac{k_n}{k_{n-1}}
-                                // \right)T^{n-1} + \frac{k_n}{k_{n-1}}
-                                // T^{n-2}$. The way to compute it is to loop
-                                // over all quadrature points and update the
-                                // maximum and minimum value if the current
-                                // value is bigger/smaller than the previous
-                                // one. We initialize the variables that
-                                // store the max and min before the loop over
-                                // all quadrature points by the smallest and
-                                // the largest number representable as a
-                                // double. Then we know for a fact that it is
-                                // larger/smaller than the minimum/maximum
-                                // and that the loop over all quadrature
-                                // points is ultimately going to update the
-                                // initial value with the correct one.
-                                //
-                                // The only other complication worth
-                                // mentioning here is that in the first time
-                                // step, $T^{k-2}$ is not yet available of
-                                // course. In that case, we can only use
-                                // $T^{k-1}$ which we have from the initial
-                                // temperature. As quadrature points, we use
-                                // the same choice as in the previous
-                                // function though with the difference that
-                                // now the number of repetitions is
-                                // determined by the polynomial degree of the
-                                // temperature field.
-template <int dim>
-std::pair<double,double>
-BoussinesqFlowProblem<dim>::get_extrapolated_temperature_range () const
-{
-  const QIterated<dim> quadrature_formula (QTrapez<1>(),
-                                          temperature_degree);
-  const unsigned int n_q_points = quadrature_formula.size();
+    return (beta *
+           max_velocity *
+           std::min (cell_diameter,
+                     std::pow(cell_diameter,alpha) *
+                     max_residual / global_scaling));
+  }
 
-  FEValues<dim> fe_values (temperature_fe, quadrature_formula,
-                           update_values);
-  std::vector<double> old_temperature_values(n_q_points);
-  std::vector<double> old_old_temperature_values(n_q_points);
 
-  if (timestep_number != 0)
-    {
-      double min_temperature = std::numeric_limits<double>::max(),
-            max_temperature = -std::numeric_limits<double>::max();
 
-      typename DoFHandler<dim>::active_cell_iterator
-       cell = temperature_dof_handler.begin_active(),
-       endc = temperature_dof_handler.end();
-      for (; cell!=endc; ++cell)
-       {
-         fe_values.reinit (cell);
-         fe_values.get_function_values (old_temperature_solution,
-                                        old_temperature_values);
-         fe_values.get_function_values (old_old_temperature_solution,
-                                        old_old_temperature_values);
-
-         for (unsigned int q=0; q<n_q_points; ++q)
-           {
-             const double temperature =
-               (1. + time_step/old_time_step) * old_temperature_values[q]-
-               time_step/old_time_step * old_old_temperature_values[q];
-
-             min_temperature = std::min (min_temperature, temperature);
-             max_temperature = std::max (max_temperature, temperature);
-           }
-       }
+                                  // @sect4{BoussinesqFlowProblem::setup_dofs}
+                                  //
+                                  // This is the function that sets up the
+                                  // DoFHandler objects we have here (one for
+                                  // the Stokes part and one for the
+                                  // temperature part) as well as set to the
+                                  // right sizes the various objects required
+                                  // for the linear algebra in this
+                                  // program. Its basic operations are similar
+                                  // to what we do in step-22.
+                                  //
+                                  // The body of the function first
+                                  // enumerates all degrees of freedom for
+                                  // the Stokes and temperature systems. For
+                                  // the Stokes part, degrees of freedom are
+                                  // then sorted to ensure that velocities
+                                  // precede pressure DoFs so that we can
+                                  // partition the Stokes matrix into a
+                                  // $2\times 2$ matrix. As a difference to
+                                  // step-22, we do not perform any
+                                  // additional DoF renumbering. In that
+                                  // program, it paid off since our solver
+                                  // was heavily dependent on ILU's, whereas
+                                  // we use AMG here which is not sensitive
+                                  // to the DoF numbering. The IC
+                                  // preconditioner for the inversion of the
+                                  // pressure mass matrix would of course
+                                  // take advantage of a Cuthill-McKee like
+                                  // renumbering, but its costs are low
+                                  // compared to the velocity portion, so the
+                                  // additional work does not pay off.
+                                  //
+                                  // We then proceed with the generation of the
+                                  // hanging node constraints that arise from
+                                  // adaptive grid refinement for both
+                                  // DoFHandler objects. For the velocity, we
+                                  // impose no-flux boundary conditions
+                                  // $\mathbf{u}\cdot \mathbf{n}=0$ by adding
+                                  // constraints to the object that already
+                                  // stores the hanging node constraints
+                                  // matrix. The second parameter in the
+                                  // function describes the first of the
+                                  // velocity components in the total dof
+                                  // vector, which is zero here. The variable
+                                  // <code>no_normal_flux_boundaries</code>
+                                  // denotes the boundary indicators for which
+                                  // to set the no flux boundary conditions;
+                                  // here, this is boundary indicator zero.
+                                  //
+                                  // After having done so, we count the number
+                                  // of degrees of freedom in the various
+                                  // blocks:
+  template <int dim>
+  void BoussinesqFlowProblem<dim>::setup_dofs ()
+  {
+    std::vector<unsigned int> stokes_sub_blocks (dim+1,0);
+    stokes_sub_blocks[dim] = 1;
 
-      return std::make_pair(min_temperature, max_temperature);
+    {
+      stokes_dof_handler.distribute_dofs (stokes_fe);
+      DoFRenumbering::component_wise (stokes_dof_handler, stokes_sub_blocks);
+
+      stokes_constraints.clear ();
+      DoFTools::make_hanging_node_constraints (stokes_dof_handler,
+                                              stokes_constraints);
+      std::set<unsigned char> no_normal_flux_boundaries;
+      no_normal_flux_boundaries.insert (0);
+      VectorTools::compute_no_normal_flux_constraints (stokes_dof_handler, 0,
+                                                      no_normal_flux_boundaries,
+                                                      stokes_constraints);
+      stokes_constraints.close ();
     }
-  else
     {
-      double min_temperature = std::numeric_limits<double>::max(),
-            max_temperature = -std::numeric_limits<double>::max();
-
-      typename DoFHandler<dim>::active_cell_iterator
-       cell = temperature_dof_handler.begin_active(),
-       endc = temperature_dof_handler.end();
-      for (; cell!=endc; ++cell)
-       {
-         fe_values.reinit (cell);
-         fe_values.get_function_values (old_temperature_solution,
-                                        old_temperature_values);
+      temperature_dof_handler.distribute_dofs (temperature_fe);
 
-         for (unsigned int q=0; q<n_q_points; ++q)
-           {
-             const double temperature = old_temperature_values[q];
+      temperature_constraints.clear ();
+      DoFTools::make_hanging_node_constraints (temperature_dof_handler,
+                                              temperature_constraints);
+      temperature_constraints.close ();
+    }
 
-             min_temperature = std::min (min_temperature, temperature);
-             max_temperature = std::max (max_temperature, temperature);
-           }
-       }
+    std::vector<unsigned int> stokes_dofs_per_block (2);
+    DoFTools::count_dofs_per_block (stokes_dof_handler, stokes_dofs_per_block,
+                                   stokes_sub_blocks);
+
+    const unsigned int n_u = stokes_dofs_per_block[0],
+                      n_p = stokes_dofs_per_block[1],
+                      n_T = temperature_dof_handler.n_dofs();
+
+    std::cout << "Number of active cells: "
+             << triangulation.n_active_cells()
+             << " (on "
+             << triangulation.n_levels()
+             << " levels)"
+             << std::endl
+             << "Number of degrees of freedom: "
+             << n_u + n_p + n_T
+             << " (" << n_u << '+' << n_p << '+'<< n_T <<')'
+             << std::endl
+             << std::endl;
 
-      return std::make_pair(min_temperature, max_temperature);
-    }
-}
+                                    // The next step is to create the sparsity
+                                    // pattern for the Stokes and temperature
+                                    // system matrices as well as the
+                                    // preconditioner matrix from which we
+                                    // build the Stokes preconditioner. As in
+                                    // step-22, we choose to create the pattern
+                                    // not as in the first few tutorial
+                                    // programs, but by using the blocked
+                                    // version of CompressedSimpleSparsityPattern.
+                                    // The reason for doing this is mainly
+                                    // memory, that is, the SparsityPattern
+                                    // class would consume too much memory when
+                                    // used in three spatial dimensions as we
+                                    // intend to do for this program.
+                                    //
+                                    // So, we first release the memory stored
+                                    // in the matrices, then set up an object
+                                    // of type
+                                    // BlockCompressedSimpleSparsityPattern
+                                    // consisting of $2\times 2$ blocks (for
+                                    // the Stokes system matrix and
+                                    // preconditioner) or
+                                    // CompressedSimpleSparsityPattern (for
+                                    // the temperature part). We then fill
+                                    // these objects with the nonzero
+                                    // pattern, taking into account that for
+                                    // the Stokes system matrix, there are no
+                                    // entries in the pressure-pressure block
+                                    // (but all velocity vector components
+                                    // couple with each other and with the
+                                    // pressure). Similarly, in the Stokes
+                                    // preconditioner matrix, only the
+                                    // diagonal blocks are nonzero, since we
+                                    // use the vector Laplacian as discussed
+                                    // in the introduction. This operator
+                                    // only couples each vector component of
+                                    // the Laplacian with itself, but not
+                                    // with the other vector
+                                    // components. (Application of the
+                                    // constraints resulting from the no-flux
+                                    // boundary conditions will couple vector
+                                    // components at the boundary again,
+                                    // however.)
+                                    //
+                                    // When generating the sparsity pattern,
+                                    // we directly apply the constraints from
+                                    // hanging nodes and no-flux boundary
+                                    // conditions. This approach was already
+                                    // used in step-27, but is different from
+                                    // the one in early tutorial programs
+                                    // where we first built the original
+                                    // sparsity pattern and only then added
+                                    // the entries resulting from
+                                    // constraints. The reason for doing so
+                                    // is that later during assembly we are
+                                    // going to distribute the constraints
+                                    // immediately when transferring local to
+                                    // global dofs. Consequently, there will
+                                    // be no data written at positions of
+                                    // constrained degrees of freedom, so we
+                                    // can let the
+                                    // DoFTools::make_sparsity_pattern
+                                    // function omit these entries by setting
+                                    // the last boolean flag to
+                                    // <code>false</code>. Once the sparsity
+                                    // pattern is ready, we can use it to
+                                    // initialize the Trilinos
+                                    // matrices. Since the Trilinos matrices
+                                    // store the sparsity pattern internally,
+                                    // there is no need to keep the sparsity
+                                    // pattern around after the
+                                    // initialization of the matrix.
+    stokes_block_sizes.resize (2);
+    stokes_block_sizes[0] = n_u;
+    stokes_block_sizes[1] = n_p;
+    {
+      stokes_matrix.clear ();
 
+      BlockCompressedSimpleSparsityPattern csp (2,2);
 
+      csp.block(0,0).reinit (n_u, n_u);
+      csp.block(0,1).reinit (n_u, n_p);
+      csp.block(1,0).reinit (n_p, n_u);
+      csp.block(1,1).reinit (n_p, n_p);
 
-                                // @sect4{BoussinesqFlowProblem::compute_viscosity}
+      csp.collect_sizes ();
 
-                                // The last of the tool functions computes
-                                // the artificial viscosity parameter
-                                // $\nu|_K$ on a cell $K$ as a function of
-                                // the extrapolated temperature, its
-                                // gradient and Hessian (second
-                                // derivatives), the velocity, the right
-                                // hand side $\gamma$ all on the quadrature
-                                // points of the current cell, and various
-                                // other parameters as described in detail
-                                // in the introduction.
-                                //
-                                // There are some universal constants worth
-                                // mentioning here. First, we need to fix
-                                // $\beta$; we choose $\beta=0.015\cdot
-                                // dim$, a choice discussed in detail in
-                                // the results section of this tutorial
-                                // program. The second is the exponent
-                                // $\alpha$; $\alpha=1$ appears to work
-                                // fine for the current program, even
-                                // though some additional benefit might be
-                                // expected from chosing $\alpha =
-                                // 2$. Finally, there is one thing that
-                                // requires special casing: In the first
-                                // time step, the velocity equals zero, and
-                                // the formula for $\nu|_K$ is not
-                                // defined. In that case, we return
-                                // $\nu|_K=5\cdot 10^3 \cdot h_K$, a choice
-                                // admittedly more motivated by heuristics
-                                // than anything else (it is in the same
-                                // order of magnitude, however, as the
-                                // value returned for most cells on the
-                                // second time step).
-                                //
-                                // The rest of the function should be
-                                // mostly obvious based on the material
-                                // discussed in the introduction:
-template <int dim>
-double
-BoussinesqFlowProblem<dim>::
-compute_viscosity (const std::vector<double>          &old_temperature,
-                  const std::vector<double>          &old_old_temperature,
-                  const std::vector<Tensor<1,dim> >  &old_temperature_grads,
-                  const std::vector<Tensor<1,dim> >  &old_old_temperature_grads,
-                  const std::vector<double>          &old_temperature_laplacians,
-                  const std::vector<double>          &old_old_temperature_laplacians,
-                  const std::vector<Tensor<1,dim> >  &old_velocity_values,
-                  const std::vector<Tensor<1,dim> >  &old_old_velocity_values,
-                  const std::vector<double>          &gamma_values,
-                  const double                        global_u_infty,
-                  const double                        global_T_variation,
-                  const double                        cell_diameter) const
-{
-  const double beta = 0.015 * dim;
-  const double alpha = 1;
+      Table<2,DoFTools::Coupling> coupling (dim+1, dim+1);
 
-  if (global_u_infty == 0)
-    return 5e-3 * cell_diameter;
+      for (unsigned int c=0; c<dim+1; ++c)
+       for (unsigned int d=0; d<dim+1; ++d)
+         if (! ((c==dim) && (d==dim)))
+           coupling[c][d] = DoFTools::always;
+         else
+           coupling[c][d] = DoFTools::none;
 
-  const unsigned int n_q_points = old_temperature.size();
+      DoFTools::make_sparsity_pattern (stokes_dof_handler, coupling, csp,
+                                      stokes_constraints, false);
 
-  double max_residual = 0;
-  double max_velocity = 0;
+      stokes_matrix.reinit (csp);
+    }
 
-  for (unsigned int q=0; q < n_q_points; ++q)
     {
-      const Tensor<1,dim> u = (old_velocity_values[q] +
-                              old_old_velocity_values[q]) / 2;
+      Amg_preconditioner.reset ();
+      Mp_preconditioner.reset ();
+      stokes_preconditioner_matrix.clear ();
 
-      const double dT_dt = (old_temperature[q] - old_old_temperature[q])
-                          / old_time_step;
-      const double u_grad_T = u * (old_temperature_grads[q] +
-                                  old_old_temperature_grads[q]) / 2;
+      BlockCompressedSimpleSparsityPattern csp (2,2);
 
-      const double kappa_Delta_T = EquationData::kappa
-                                  * (old_temperature_laplacians[q] +
-                                     old_old_temperature_laplacians[q]) / 2;
+      csp.block(0,0).reinit (n_u, n_u);
+      csp.block(0,1).reinit (n_u, n_p);
+      csp.block(1,0).reinit (n_p, n_u);
+      csp.block(1,1).reinit (n_p, n_p);
 
-      const double residual
-       = std::abs((dT_dt + u_grad_T - kappa_Delta_T - gamma_values[q]) *
-                  std::pow((old_temperature[q]+old_old_temperature[q]) / 2,
-                           alpha-1.));
+      csp.collect_sizes ();
 
-      max_residual = std::max (residual,        max_residual);
-      max_velocity = std::max (std::sqrt (u*u), max_velocity);
-    }
+      Table<2,DoFTools::Coupling> coupling (dim+1, dim+1);
+      for (unsigned int c=0; c<dim+1; ++c)
+       for (unsigned int d=0; d<dim+1; ++d)
+         if (c == d)
+           coupling[c][d] = DoFTools::always;
+         else
+           coupling[c][d] = DoFTools::none;
 
-  const double c_R = std::pow (2., (4.-2*alpha)/dim);
-  const double global_scaling = c_R * global_u_infty * global_T_variation *
-                               std::pow(global_Omega_diameter, alpha - 2.);
+      DoFTools::make_sparsity_pattern (stokes_dof_handler, coupling, csp,
+                                      stokes_constraints, false);
 
-  return (beta *
-         max_velocity *
-         std::min (cell_diameter,
-                   std::pow(cell_diameter,alpha) *
-                   max_residual / global_scaling));
-}
+      stokes_preconditioner_matrix.reinit (csp);
+    }
 
+                                    // The creation of the temperature matrix
+                                    // (or, rather, matrices, since we
+                                    // provide a temperature mass matrix and
+                                    // a temperature stiffness matrix, that
+                                    // will be added together for time
+                                    // discretization) follows the generation
+                                    // of the Stokes matrix &ndash; except
+                                    // that it is much easier here since we
+                                    // do not need to take care of any blocks
+                                    // or coupling between components. Note
+                                    // how we initialize the three
+                                    // temperature matrices: We only use the
+                                    // sparsity pattern for reinitialization
+                                    // of the first matrix, whereas we use
+                                    // the previously generated matrix for
+                                    // the two remaining reinits. The reason
+                                    // for doing so is that reinitialization
+                                    // from an already generated matrix
+                                    // allows Trilinos to reuse the sparsity
+                                    // pattern instead of generating a new
+                                    // one for each copy. This saves both
+                                    // some time and memory.
+    {
+      temperature_mass_matrix.clear ();
+      temperature_stiffness_matrix.clear ();
+      temperature_matrix.clear ();
 
+      CompressedSimpleSparsityPattern csp (n_T, n_T);
+      DoFTools::make_sparsity_pattern (temperature_dof_handler, csp,
+                                      temperature_constraints, false);
 
-                                // @sect4{BoussinesqFlowProblem::setup_dofs}
-                                //
-                                // This is the function that sets up the
-                                // DoFHandler objects we have here (one for
-                                // the Stokes part and one for the
-                                // temperature part) as well as set to the
-                                // right sizes the various objects required
-                                // for the linear algebra in this
-                                // program. Its basic operations are similar
-                                // to what we do in step-22.
-                                //
-                                // The body of the function first
-                                // enumerates all degrees of freedom for
-                                // the Stokes and temperature systems. For
-                                // the Stokes part, degrees of freedom are
-                                // then sorted to ensure that velocities
-                                // precede pressure DoFs so that we can
-                                // partition the Stokes matrix into a
-                                // $2\times 2$ matrix. As a difference to
-                                // step-22, we do not perform any
-                                // additional DoF renumbering. In that
-                                // program, it paid off since our solver
-                                // was heavily dependent on ILU's, whereas
-                                // we use AMG here which is not sensitive
-                                // to the DoF numbering. The IC
-                                // preconditioner for the inversion of the
-                                // pressure mass matrix would of course
-                                // take advantage of a Cuthill-McKee like
-                                // renumbering, but its costs are low
-                                // compared to the velocity portion, so the
-                                // additional work does not pay off.
-                                //
-                                // We then proceed with the generation of the
-                                // hanging node constraints that arise from
-                                // adaptive grid refinement for both
-                                // DoFHandler objects. For the velocity, we
-                                // impose no-flux boundary conditions
-                                // $\mathbf{u}\cdot \mathbf{n}=0$ by adding
-                                // constraints to the object that already
-                                // stores the hanging node constraints
-                                // matrix. The second parameter in the
-                                // function describes the first of the
-                                // velocity components in the total dof
-                                // vector, which is zero here. The variable
-                                // <code>no_normal_flux_boundaries</code>
-                                // denotes the boundary indicators for which
-                                // to set the no flux boundary conditions;
-                                // here, this is boundary indicator zero.
-                                //
-                                // After having done so, we count the number
-                                // of degrees of freedom in the various
-                                // blocks:
-template <int dim>
-void BoussinesqFlowProblem<dim>::setup_dofs ()
-{
-  std::vector<unsigned int> stokes_sub_blocks (dim+1,0);
-  stokes_sub_blocks[dim] = 1;
+      temperature_matrix.reinit (csp);
+      temperature_mass_matrix.reinit (temperature_matrix);
+      temperature_stiffness_matrix.reinit (temperature_matrix);
+    }
 
-  {
-    stokes_dof_handler.distribute_dofs (stokes_fe);
-    DoFRenumbering::component_wise (stokes_dof_handler, stokes_sub_blocks);
-
-    stokes_constraints.clear ();
-    DoFTools::make_hanging_node_constraints (stokes_dof_handler,
-                                            stokes_constraints);
-    std::set<unsigned char> no_normal_flux_boundaries;
-    no_normal_flux_boundaries.insert (0);
-    VectorTools::compute_no_normal_flux_constraints (stokes_dof_handler, 0,
-                                                    no_normal_flux_boundaries,
-                                                    stokes_constraints);
-    stokes_constraints.close ();
+                                    // Lastly, we set the vectors for the
+                                    // Stokes solutions $\mathbf u^{n-1}$ and
+                                    // $\mathbf u^{n-2}$, as well as for the
+                                    // temperatures $T^{n}$, $T^{n-1}$ and
+                                    // $T^{n-2}$ (required for time stepping)
+                                    // and all the system right hand sides to
+                                    // their correct sizes and block
+                                    // structure:
+    stokes_solution.reinit (stokes_block_sizes);
+    old_stokes_solution.reinit (stokes_block_sizes);
+    stokes_rhs.reinit (stokes_block_sizes);
+
+    temperature_solution.reinit (temperature_dof_handler.n_dofs());
+    old_temperature_solution.reinit (temperature_dof_handler.n_dofs());
+    old_old_temperature_solution.reinit (temperature_dof_handler.n_dofs());
+
+    temperature_rhs.reinit (temperature_dof_handler.n_dofs());
   }
-  {
-    temperature_dof_handler.distribute_dofs (temperature_fe);
 
-    temperature_constraints.clear ();
-    DoFTools::make_hanging_node_constraints (temperature_dof_handler,
-                                            temperature_constraints);
-    temperature_constraints.close ();
-  }
 
-  std::vector<unsigned int> stokes_dofs_per_block (2);
-  DoFTools::count_dofs_per_block (stokes_dof_handler, stokes_dofs_per_block,
-                                 stokes_sub_blocks);
-
-  const unsigned int n_u = stokes_dofs_per_block[0],
-                     n_p = stokes_dofs_per_block[1],
-                    n_T = temperature_dof_handler.n_dofs();
-
-  std::cout << "Number of active cells: "
-            << triangulation.n_active_cells()
-           << " (on "
-           << triangulation.n_levels()
-           << " levels)"
-            << std::endl
-            << "Number of degrees of freedom: "
-            << n_u + n_p + n_T
-            << " (" << n_u << '+' << n_p << '+'<< n_T <<')'
-            << std::endl
-            << std::endl;
-
-                                  // The next step is to create the sparsity
-                                  // pattern for the Stokes and temperature
-                                  // system matrices as well as the
-                                  // preconditioner matrix from which we
-                                  // build the Stokes preconditioner. As in
-                                  // step-22, we choose to create the pattern
-                                  // not as in the first few tutorial
-                                  // programs, but by using the blocked
-                                  // version of CompressedSimpleSparsityPattern.
-                                  // The reason for doing this is mainly
-                                  // memory, that is, the SparsityPattern
-                                  // class would consume too much memory when
-                                  // used in three spatial dimensions as we
-                                  // intend to do for this program.
-                                  //
-                                  // So, we first release the memory stored
-                                  // in the matrices, then set up an object
-                                  // of type
-                                  // BlockCompressedSimpleSparsityPattern
-                                  // consisting of $2\times 2$ blocks (for
-                                  // the Stokes system matrix and
-                                  // preconditioner) or
-                                  // CompressedSimpleSparsityPattern (for
-                                  // the temperature part). We then fill
-                                  // these objects with the nonzero
-                                  // pattern, taking into account that for
-                                  // the Stokes system matrix, there are no
-                                  // entries in the pressure-pressure block
-                                  // (but all velocity vector components
-                                  // couple with each other and with the
-                                  // pressure). Similarly, in the Stokes
-                                  // preconditioner matrix, only the
-                                  // diagonal blocks are nonzero, since we
-                                  // use the vector Laplacian as discussed
-                                  // in the introduction. This operator
-                                  // only couples each vector component of
-                                  // the Laplacian with itself, but not
-                                  // with the other vector
-                                  // components. (Application of the
-                                  // constraints resulting from the no-flux
-                                  // boundary conditions will couple vector
-                                  // components at the boundary again,
-                                  // however.)
+
+                                  // @sect4{BoussinesqFlowProblem::assemble_stokes_preconditioner}
                                   //
-                                  // When generating the sparsity pattern,
-                                  // we directly apply the constraints from
-                                  // hanging nodes and no-flux boundary
-                                  // conditions. This approach was already
-                                  // used in step-27, but is different from
-                                  // the one in early tutorial programs
-                                  // where we first built the original
-                                  // sparsity pattern and only then added
-                                  // the entries resulting from
-                                  // constraints. The reason for doing so
-                                  // is that later during assembly we are
-                                  // going to distribute the constraints
-                                  // immediately when transferring local to
-                                  // global dofs. Consequently, there will
-                                  // be no data written at positions of
-                                  // constrained degrees of freedom, so we
-                                  // can let the
-                                  // DoFTools::make_sparsity_pattern
-                                  // function omit these entries by setting
-                                  // the last boolean flag to
-                                  // <code>false</code>. Once the sparsity
-                                  // pattern is ready, we can use it to
-                                  // initialize the Trilinos
-                                  // matrices. Since the Trilinos matrices
-                                  // store the sparsity pattern internally,
-                                  // there is no need to keep the sparsity
-                                  // pattern around after the
-                                  // initialization of the matrix.
-  stokes_block_sizes.resize (2);
-  stokes_block_sizes[0] = n_u;
-  stokes_block_sizes[1] = n_p;
+                                  // This function assembles the matrix we use
+                                  // for preconditioning the Stokes
+                                  // system. What we need are a vector Laplace
+                                  // matrix on the velocity components and a
+                                  // mass matrix weighted by $\eta^{-1}$ on the
+                                  // pressure component. We start by generating
+                                  // a quadrature object of appropriate order,
+                                  // the FEValues object that can give values
+                                  // and gradients at the quadrature points
+                                  // (together with quadrature weights). Next
+                                  // we create data structures for the cell
+                                  // matrix and the relation between local and
+                                  // global DoFs. The vectors
+                                  // <code>phi_grad_u</code> and
+                                  // <code>phi_p</code> are going to hold the
+                                  // values of the basis functions in order to
+                                  // faster build up the local matrices, as was
+                                  // already done in step-22. Before we start
+                                  // the loop over all active cells, we have to
+                                  // specify which components are pressure and
+                                  // which are velocity.
+  template <int dim>
+  void
+  BoussinesqFlowProblem<dim>::assemble_stokes_preconditioner ()
   {
-    stokes_matrix.clear ();
-
-    BlockCompressedSimpleSparsityPattern csp (2,2);
-
-    csp.block(0,0).reinit (n_u, n_u);
-    csp.block(0,1).reinit (n_u, n_p);
-    csp.block(1,0).reinit (n_p, n_u);
-    csp.block(1,1).reinit (n_p, n_p);
+    stokes_preconditioner_matrix = 0;
 
-    csp.collect_sizes ();
+    const QGauss<dim> quadrature_formula(stokes_degree+2);
+    FEValues<dim>     stokes_fe_values (stokes_fe, quadrature_formula,
+                                       update_JxW_values |
+                                       update_values |
+                                       update_gradients);
 
-    Table<2,DoFTools::Coupling> coupling (dim+1, dim+1);
+    const unsigned int   dofs_per_cell   = stokes_fe.dofs_per_cell;
+    const unsigned int   n_q_points      = quadrature_formula.size();
 
-    for (unsigned int c=0; c<dim+1; ++c)
-      for (unsigned int d=0; d<dim+1; ++d)
-       if (! ((c==dim) && (d==dim)))
-         coupling[c][d] = DoFTools::always;
-       else
-         coupling[c][d] = DoFTools::none;
+    FullMatrix<double>   local_matrix (dofs_per_cell, dofs_per_cell);
+    std::vector<unsigned int> local_dof_indices (dofs_per_cell);
 
-    DoFTools::make_sparsity_pattern (stokes_dof_handler, coupling, csp,
-                                    stokes_constraints, false);
+    std::vector<Tensor<2,dim> > phi_grad_u (dofs_per_cell);
+    std::vector<double>         phi_p      (dofs_per_cell);
 
-    stokes_matrix.reinit (csp);
-  }
+    const FEValuesExtractors::Vector velocities (0);
+    const FEValuesExtractors::Scalar pressure (dim);
 
-  {
-    Amg_preconditioner.reset ();
-    Mp_preconditioner.reset ();
-    stokes_preconditioner_matrix.clear ();
-
-    BlockCompressedSimpleSparsityPattern csp (2,2);
-
-    csp.block(0,0).reinit (n_u, n_u);
-    csp.block(0,1).reinit (n_u, n_p);
-    csp.block(1,0).reinit (n_p, n_u);
-    csp.block(1,1).reinit (n_p, n_p);
-
-    csp.collect_sizes ();
-
-    Table<2,DoFTools::Coupling> coupling (dim+1, dim+1);
-    for (unsigned int c=0; c<dim+1; ++c)
-      for (unsigned int d=0; d<dim+1; ++d)
-       if (c == d)
-         coupling[c][d] = DoFTools::always;
-       else
-         coupling[c][d] = DoFTools::none;
+    typename DoFHandler<dim>::active_cell_iterator
+      cell = stokes_dof_handler.begin_active(),
+      endc = stokes_dof_handler.end();
+    for (; cell!=endc; ++cell)
+      {
+       stokes_fe_values.reinit (cell);
+       local_matrix = 0;
+
+                                        // The creation of the local matrix is
+                                        // rather simple. There are only a
+                                        // Laplace term (on the velocity) and a
+                                        // mass matrix weighted by $\eta^{-1}$
+                                        // to be generated, so the creation of
+                                        // the local matrix is done in two
+                                        // lines. Once the local matrix is
+                                        // ready (loop over rows and columns in
+                                        // the local matrix on each quadrature
+                                        // point), we get the local DoF indices
+                                        // and write the local information into
+                                        // the global matrix. We do this as in
+                                        // step-27, i.e. we directly apply the
+                                        // constraints from hanging nodes
+                                        // locally. By doing so, we don't have
+                                        // to do that afterwards, and we don't
+                                        // also write into entries of the
+                                        // matrix that will actually be set to
+                                        // zero again later when eliminating
+                                        // constraints.
+       for (unsigned int q=0; q<n_q_points; ++q)
+         {
+           for (unsigned int k=0; k<dofs_per_cell; ++k)
+             {
+               phi_grad_u[k] = stokes_fe_values[velocities].gradient(k,q);
+               phi_p[k]      = stokes_fe_values[pressure].value (k, q);
+             }
 
-    DoFTools::make_sparsity_pattern (stokes_dof_handler, coupling, csp,
-                                    stokes_constraints, false);
+           for (unsigned int i=0; i<dofs_per_cell; ++i)
+             for (unsigned int j=0; j<dofs_per_cell; ++j)
+               local_matrix(i,j) += (EquationData::eta *
+                                     scalar_product (phi_grad_u[i], phi_grad_u[j])
+                                     +
+                                     (1./EquationData::eta) *
+                                     phi_p[i] * phi_p[j])
+                                    * stokes_fe_values.JxW(q);
+         }
 
-    stokes_preconditioner_matrix.reinit (csp);
+       cell->get_dof_indices (local_dof_indices);
+       stokes_constraints.distribute_local_to_global (local_matrix,
+                                                      local_dof_indices,
+                                                      stokes_preconditioner_matrix);
+      }
   }
 
-                                  // The creation of the temperature matrix
-                                  // (or, rather, matrices, since we
-                                  // provide a temperature mass matrix and
-                                  // a temperature stiffness matrix, that
-                                  // will be added together for time
-                                  // discretization) follows the generation
-                                  // of the Stokes matrix &ndash; except
-                                  // that it is much easier here since we
-                                  // do not need to take care of any blocks
-                                  // or coupling between components. Note
-                                  // how we initialize the three
-                                  // temperature matrices: We only use the
-                                  // sparsity pattern for reinitialization
-                                  // of the first matrix, whereas we use
-                                  // the previously generated matrix for
-                                  // the two remaining reinits. The reason
-                                  // for doing so is that reinitialization
-                                  // from an already generated matrix
-                                  // allows Trilinos to reuse the sparsity
-                                  // pattern instead of generating a new
-                                  // one for each copy. This saves both
-                                  // some time and memory.
-  {
-    temperature_mass_matrix.clear ();
-    temperature_stiffness_matrix.clear ();
-    temperature_matrix.clear ();
 
-    CompressedSimpleSparsityPattern csp (n_T, n_T);
-    DoFTools::make_sparsity_pattern (temperature_dof_handler, csp,
-                                    temperature_constraints, false);
 
-    temperature_matrix.reinit (csp);
-    temperature_mass_matrix.reinit (temperature_matrix);
-    temperature_stiffness_matrix.reinit (temperature_matrix);
+                                  // @sect4{BoussinesqFlowProblem::build_stokes_preconditioner}
+                                  //
+                                  // This function generates the inner
+                                  // preconditioners that are going to be used
+                                  // for the Schur complement block
+                                  // preconditioner. Since the preconditioners
+                                  // need only to be regenerated when the
+                                  // matrices change, this function does not
+                                  // have to do anything in case the matrices
+                                  // have not changed (i.e., the flag
+                                  // <code>rebuild_stokes_preconditioner</code>
+                                  // has the value
+                                  // <code>false</code>). Otherwise its first
+                                  // task is to call
+                                  // <code>assemble_stokes_preconditioner</code>
+                                  // to generate the preconditioner matrices.
+                                  //
+                                  // Next, we set up the preconditioner for
+                                  // the velocity-velocity matrix
+                                  // <i>A</i>. As explained in the
+                                  // introduction, we are going to use an
+                                  // AMG preconditioner based on a vector
+                                  // Laplace matrix $\hat{A}$ (which is
+                                  // spectrally close to the Stokes matrix
+                                  // <i>A</i>). Usually, the
+                                  // TrilinosWrappers::PreconditionAMG
+                                  // class can be seen as a good black-box
+                                  // preconditioner which does not need any
+                                  // special knowledge. In this case,
+                                  // however, we have to be careful: since
+                                  // we build an AMG for a vector problem,
+                                  // we have to tell the preconditioner
+                                  // setup which dofs belong to which
+                                  // vector component. We do this using the
+                                  // function
+                                  // DoFTools::extract_constant_modes, a
+                                  // function that generates a set of
+                                  // <code>dim</code> vectors, where each one
+                                  // has ones in the respective component
+                                  // of the vector problem and zeros
+                                  // elsewhere. Hence, these are the
+                                  // constant modes on each component,
+                                  // which explains the name of the
+                                  // variable.
+  template <int dim>
+  void
+  BoussinesqFlowProblem<dim>::build_stokes_preconditioner ()
+  {
+    if (rebuild_stokes_preconditioner == false)
+      return;
+
+    std::cout << "   Rebuilding Stokes preconditioner..." << std::flush;
+
+    assemble_stokes_preconditioner ();
+
+    Amg_preconditioner = std_cxx1x::shared_ptr<TrilinosWrappers::PreconditionAMG>
+                        (new TrilinosWrappers::PreconditionAMG());
+
+    std::vector<std::vector<bool> > constant_modes;
+    std::vector<bool>  velocity_components (dim+1,true);
+    velocity_components[dim] = false;
+    DoFTools::extract_constant_modes (stokes_dof_handler, velocity_components,
+                                     constant_modes);
+    TrilinosWrappers::PreconditionAMG::AdditionalData amg_data;
+    amg_data.constant_modes = constant_modes;
+
+                                    // Next, we set some more options of the
+                                    // AMG preconditioner. In particular, we
+                                    // need to tell the AMG setup that we use
+                                    // quadratic basis functions for the
+                                    // velocity matrix (this implies more
+                                    // nonzero elements in the matrix, so
+                                    // that a more rubust algorithm needs to
+                                    // be chosen internally). Moreover, we
+                                    // want to be able to control how the
+                                    // coarsening structure is build up. The
+                                    // way the Trilinos smoothed aggregation
+                                    // AMG does this is to look which matrix
+                                    // entries are of similar size as the
+                                    // diagonal entry in order to
+                                    // algebraically build a coarse-grid
+                                    // structure. By setting the parameter
+                                    // <code>aggregation_threshold</code> to
+                                    // 0.02, we specify that all entries that
+                                    // are more than two precent of size of
+                                    // some diagonal pivots in that row
+                                    // should form one coarse grid
+                                    // point. This parameter is rather
+                                    // ad-hoc, and some fine-tuning of it can
+                                    // influence the performance of the
+                                    // preconditioner. As a rule of thumb,
+                                    // larger values of
+                                    // <code>aggregation_threshold</code>
+                                    // will decrease the number of
+                                    // iterations, but increase the costs per
+                                    // iteration. A look at the Trilinos
+                                    // documentation will provide more
+                                    // information on these parameters. With
+                                    // this data set, we then initialize the
+                                    // preconditioner with the matrix we want
+                                    // it to apply to.
+                                    //
+                                    // Finally, we also initialize the
+                                    // preconditioner for the inversion of
+                                    // the pressure mass matrix. This matrix
+                                    // is symmetric and well-behaved, so we
+                                    // can chose a simple preconditioner. We
+                                    // stick with an incomple Cholesky (IC)
+                                    // factorization preconditioner, which is
+                                    // designed for symmetric matrices. We
+                                    // could have also chosen an SSOR
+                                    // preconditioner with relaxation factor
+                                    // around 1.2, but IC is cheaper for our
+                                    // example. We wrap the preconditioners
+                                    // into a <code>std_cxx1x::shared_ptr</code>
+                                    // pointer, which makes it easier to
+                                    // recreate the preconditioner next time
+                                    // around since we do not have to care
+                                    // about destroying the previously used
+                                    // object.
+    amg_data.elliptic = true;
+    amg_data.higher_order_elements = true;
+    amg_data.smoother_sweeps = 2;
+    amg_data.aggregation_threshold = 0.02;
+    Amg_preconditioner->initialize(stokes_preconditioner_matrix.block(0,0),
+                                  amg_data);
+
+    Mp_preconditioner = std_cxx1x::shared_ptr<TrilinosWrappers::PreconditionIC>
+                       (new TrilinosWrappers::PreconditionIC());
+    Mp_preconditioner->initialize(stokes_preconditioner_matrix.block(1,1));
+
+    std::cout << std::endl;
+
+    rebuild_stokes_preconditioner = false;
   }
 
-                                  // Lastly, we set the vectors for the
-                                  // Stokes solutions $\mathbf u^{n-1}$ and
-                                  // $\mathbf u^{n-2}$, as well as for the
-                                  // temperatures $T^{n}$, $T^{n-1}$ and
-                                  // $T^{n-2}$ (required for time stepping)
-                                  // and all the system right hand sides to
-                                  // their correct sizes and block
-                                  // structure:
-  stokes_solution.reinit (stokes_block_sizes);
-  old_stokes_solution.reinit (stokes_block_sizes);
-  stokes_rhs.reinit (stokes_block_sizes);
-
-  temperature_solution.reinit (temperature_dof_handler.n_dofs());
-  old_temperature_solution.reinit (temperature_dof_handler.n_dofs());
-  old_old_temperature_solution.reinit (temperature_dof_handler.n_dofs());
-
-  temperature_rhs.reinit (temperature_dof_handler.n_dofs());
-}
-
-
-
-                                // @sect4{BoussinesqFlowProblem::assemble_stokes_preconditioner}
-                                //
-                                 // This function assembles the matrix we use
-                                 // for preconditioning the Stokes
-                                 // system. What we need are a vector Laplace
-                                 // matrix on the velocity components and a
-                                 // mass matrix weighted by $\eta^{-1}$ on the
-                                 // pressure component. We start by generating
-                                 // a quadrature object of appropriate order,
-                                 // the FEValues object that can give values
-                                 // and gradients at the quadrature points
-                                 // (together with quadrature weights). Next
-                                 // we create data structures for the cell
-                                 // matrix and the relation between local and
-                                 // global DoFs. The vectors
-                                 // <code>phi_grad_u</code> and
-                                 // <code>phi_p</code> are going to hold the
-                                 // values of the basis functions in order to
-                                 // faster build up the local matrices, as was
-                                 // already done in step-22. Before we start
-                                 // the loop over all active cells, we have to
-                                 // specify which components are pressure and
-                                 // which are velocity.
-template <int dim>
-void
-BoussinesqFlowProblem<dim>::assemble_stokes_preconditioner ()
-{
-  stokes_preconditioner_matrix = 0;
-
-  const QGauss<dim> quadrature_formula(stokes_degree+2);
-  FEValues<dim>     stokes_fe_values (stokes_fe, quadrature_formula,
-                                     update_JxW_values |
-                                     update_values |
-                                     update_gradients);
 
-  const unsigned int   dofs_per_cell   = stokes_fe.dofs_per_cell;
-  const unsigned int   n_q_points      = quadrature_formula.size();
 
-  FullMatrix<double>   local_matrix (dofs_per_cell, dofs_per_cell);
-  std::vector<unsigned int> local_dof_indices (dofs_per_cell);
-
-  std::vector<Tensor<2,dim> > phi_grad_u (dofs_per_cell);
-  std::vector<double>         phi_p      (dofs_per_cell);
-
-  const FEValuesExtractors::Vector velocities (0);
-  const FEValuesExtractors::Scalar pressure (dim);
+                                  // @sect4{BoussinesqFlowProblem::assemble_stokes_system}
+                                  //
+                                  // The time lag scheme we use for advancing
+                                  // the coupled Stokes-temperature system
+                                  // forces us to split up the assembly (and
+                                  // the solution of linear systems) into two
+                                  // step. The first one is to create the
+                                  // Stokes system matrix and right hand
+                                  // side, and the second is to create matrix
+                                  // and right hand sides for the temperature
+                                  // dofs, which depends on the result of the
+                                  // linear system for the velocity.
+                                  //
+                                  // This function is called at the beginning
+                                  // of each time step. In the first time step
+                                  // or if the mesh has changed, indicated by
+                                  // the <code>rebuild_stokes_matrix</code>, we
+                                  // need to assemble the Stokes matrix; on the
+                                  // other hand, if the mesh hasn't changed and
+                                  // the matrix is already available, this is
+                                  // not necessary and all we need to do is
+                                  // assemble the right hand side vector which
+                                  // changes in each time step.
+                                  //
+                                  // Regarding the technical details of
+                                  // implementation, not much has changed from
+                                  // step-22. We reset matrix and vector,
+                                  // create a quadrature formula on the cells,
+                                  // and then create the respective FEValues
+                                  // object. For the update flags, we require
+                                  // basis function derivatives only in case of
+                                  // a full assembly, since they are not needed
+                                  // for the right hand side; as always,
+                                  // choosing the minimal set of flags
+                                  // depending on what is currently needed
+                                  // makes the call to FEValues::reinit further
+                                  // down in the program more efficient.
+                                  //
+                                  // There is one thing that needs to be
+                                  // commented &ndash; since we have a separate
+                                  // finite element and DoFHandler for the
+                                  // temperature, we need to generate a second
+                                  // FEValues object for the proper evaluation
+                                  // of the temperature solution. This isn't
+                                  // too complicated to realize here: just use
+                                  // the temperature structures and set an
+                                  // update flag for the basis function values
+                                  // which we need for evaluation of the
+                                  // temperature solution. The only important
+                                  // part to remember here is that the same
+                                  // quadrature formula is used for both
+                                  // FEValues objects to ensure that we get
+                                  // matching information when we loop over the
+                                  // quadrature points of the two objects.
+                                  //
+                                  // The declarations proceed with some
+                                  // shortcuts for array sizes, the creation
+                                  // of the local matrix and right hand side
+                                  // as well as the vector for the indices of
+                                  // the local dofs compared to the global
+                                  // system.
+  template <int dim>
+  void BoussinesqFlowProblem<dim>::assemble_stokes_system ()
+  {
+    std::cout << "   Assembling..." << std::flush;
+
+    if (rebuild_stokes_matrix == true)
+      stokes_matrix=0;
+
+    stokes_rhs=0;
+
+    const QGauss<dim> quadrature_formula (stokes_degree+2);
+    FEValues<dim>     stokes_fe_values (stokes_fe, quadrature_formula,
+                                       update_values    |
+                                       update_quadrature_points  |
+                                       update_JxW_values |
+                                       (rebuild_stokes_matrix == true
+                                        ?
+                                        update_gradients
+                                        :
+                                        UpdateFlags(0)));
+
+    FEValues<dim>     temperature_fe_values (temperature_fe, quadrature_formula,
+                                            update_values);
+
+    const unsigned int   dofs_per_cell   = stokes_fe.dofs_per_cell;
+    const unsigned int   n_q_points      = quadrature_formula.size();
+
+    FullMatrix<double>   local_matrix (dofs_per_cell, dofs_per_cell);
+    Vector<double>       local_rhs    (dofs_per_cell);
+
+    std::vector<unsigned int> local_dof_indices (dofs_per_cell);
+
+                                    // Next we need a vector that will contain
+                                    // the values of the temperature solution
+                                    // at the previous time level at the
+                                    // quadrature points to assemble the source
+                                    // term in the right hand side of the
+                                    // momentum equation. Let's call this vector
+                                    // <code>old_solution_values</code>.
+                                    //
+                                    // The set of vectors we create next hold
+                                    // the evaluations of the basis functions
+                                    // as well as their gradients and
+                                    // symmetrized gradients that will be used
+                                    // for creating the matrices. Putting these
+                                    // into their own arrays rather than asking
+                                    // the FEValues object for this information
+                                    // each time it is needed is an
+                                    // optimization to accelerate the assembly
+                                    // process, see step-22 for details.
+                                    //
+                                    // The last two declarations are used to
+                                    // extract the individual blocks
+                                    // (velocity, pressure, temperature) from
+                                    // the total FE system.
+    std::vector<double>               old_temperature_values(n_q_points);
+
+    std::vector<Tensor<1,dim> >          phi_u       (dofs_per_cell);
+    std::vector<SymmetricTensor<2,dim> > grads_phi_u (dofs_per_cell);
+    std::vector<double>                  div_phi_u   (dofs_per_cell);
+    std::vector<double>                  phi_p       (dofs_per_cell);
+
+    const FEValuesExtractors::Vector velocities (0);
+    const FEValuesExtractors::Scalar pressure (dim);
+
+                                    // Now start the loop over all cells in
+                                    // the problem. We are working on two
+                                    // different DoFHandlers for this
+                                    // assembly routine, so we must have two
+                                    // different cell iterators for the two
+                                    // objects in use. This might seem a bit
+                                    // peculiar, since both the Stokes system
+                                    // and the temperature system use the
+                                    // same grid, but that's the only way to
+                                    // keep degrees of freedom in sync. The
+                                    // first statements within the loop are
+                                    // again all very familiar, doing the
+                                    // update of the finite element data as
+                                    // specified by the update flags, zeroing
+                                    // out the local arrays and getting the
+                                    // values of the old solution at the
+                                    // quadrature points. Then we are ready to
+                                    // loop over the quadrature points on the
+                                    // cell.
+    typename DoFHandler<dim>::active_cell_iterator
+      cell = stokes_dof_handler.begin_active(),
+      endc = stokes_dof_handler.end();
+    typename DoFHandler<dim>::active_cell_iterator
+      temperature_cell = temperature_dof_handler.begin_active();
 
-  typename DoFHandler<dim>::active_cell_iterator
-    cell = stokes_dof_handler.begin_active(),
-    endc = stokes_dof_handler.end();
-  for (; cell!=endc; ++cell)
-    {
-      stokes_fe_values.reinit (cell);
-      local_matrix = 0;
-
-                                      // The creation of the local matrix is
-                                      // rather simple. There are only a
-                                      // Laplace term (on the velocity) and a
-                                      // mass matrix weighted by $\eta^{-1}$
-                                      // to be generated, so the creation of
-                                      // the local matrix is done in two
-                                      // lines. Once the local matrix is
-                                      // ready (loop over rows and columns in
-                                      // the local matrix on each quadrature
-                                      // point), we get the local DoF indices
-                                      // and write the local information into
-                                      // the global matrix. We do this as in
-                                      // step-27, i.e. we directly apply the
-                                      // constraints from hanging nodes
-                                      // locally. By doing so, we don't have
-                                      // to do that afterwards, and we don't
-                                      // also write into entries of the
-                                      // matrix that will actually be set to
-                                      // zero again later when eliminating
-                                      // constraints.
-      for (unsigned int q=0; q<n_q_points; ++q)
-       {
-         for (unsigned int k=0; k<dofs_per_cell; ++k)
-           {
-             phi_grad_u[k] = stokes_fe_values[velocities].gradient(k,q);
-             phi_p[k]      = stokes_fe_values[pressure].value (k, q);
-           }
-
-         for (unsigned int i=0; i<dofs_per_cell; ++i)
-           for (unsigned int j=0; j<dofs_per_cell; ++j)
-             local_matrix(i,j) += (EquationData::eta *
-                                   scalar_product (phi_grad_u[i], phi_grad_u[j])
-                                   +
-                                   (1./EquationData::eta) *
-                                   phi_p[i] * phi_p[j])
-                                  * stokes_fe_values.JxW(q);
-       }
+    for (; cell!=endc; ++cell, ++temperature_cell)
+      {
+       stokes_fe_values.reinit (cell);
+       temperature_fe_values.reinit (temperature_cell);
+
+       local_matrix = 0;
+       local_rhs = 0;
+
+       temperature_fe_values.get_function_values (old_temperature_solution,
+                                                  old_temperature_values);
+
+       for (unsigned int q=0; q<n_q_points; ++q)
+         {
+           const double old_temperature = old_temperature_values[q];
+
+                                            // Next we extract the values and
+                                            // gradients of basis functions
+                                            // relevant to the terms in the
+                                            // inner products. As shown in
+                                            // step-22 this helps accelerate
+                                            // assembly.
+                                            //
+                                            // Once this is done, we start the
+                                            // loop over the rows and columns
+                                            // of the local matrix and feed the
+                                            // matrix with the relevant
+                                            // products. The right hand side is
+                                            // filled with the forcing term
+                                            // driven by temperature in
+                                            // direction of gravity (which is
+                                            // vertical in our example).  Note
+                                            // that the right hand side term is
+                                            // always generated, whereas the
+                                            // matrix contributions are only
+                                            // updated when it is requested by
+                                            // the
+                                            // <code>rebuild_matrices</code>
+                                            // flag.
+           for (unsigned int k=0; k<dofs_per_cell; ++k)
+             {
+               phi_u[k] = stokes_fe_values[velocities].value (k,q);
+               if (rebuild_stokes_matrix)
+                 {
+                   grads_phi_u[k] = stokes_fe_values[velocities].symmetric_gradient(k,q);
+                   div_phi_u[k]   = stokes_fe_values[velocities].divergence (k, q);
+                   phi_p[k]       = stokes_fe_values[pressure].value (k, q);
+                 }
+             }
 
-      cell->get_dof_indices (local_dof_indices);
-      stokes_constraints.distribute_local_to_global (local_matrix,
-                                                    local_dof_indices,
-                                                    stokes_preconditioner_matrix);
-    }
-}
+           if (rebuild_stokes_matrix)
+             for (unsigned int i=0; i<dofs_per_cell; ++i)
+               for (unsigned int j=0; j<dofs_per_cell; ++j)
+                 local_matrix(i,j) += (EquationData::eta * 2 *
+                                       (grads_phi_u[i] * grads_phi_u[j])
+                                       - div_phi_u[i] * phi_p[j]
+                                       - phi_p[i] * div_phi_u[j])
+                                      * stokes_fe_values.JxW(q);
+
+           const Point<dim> gravity = -( (dim == 2) ? (Point<dim> (0,1)) :
+                                         (Point<dim> (0,0,1)) );
+           for (unsigned int i=0; i<dofs_per_cell; ++i)
+             local_rhs(i) += (-EquationData::density *
+                              EquationData::beta *
+                              gravity * phi_u[i] * old_temperature)*
+                             stokes_fe_values.JxW(q);
+         }
+
+                                        // The last step in the loop over all
+                                        // cells is to enter the local
+                                        // contributions into the global matrix
+                                        // and vector structures to the
+                                        // positions specified in
+                                        // <code>local_dof_indices</code>.
+                                        // Again, we let the ConstraintMatrix
+                                        // class do the insertion of the cell
+                                        // matrix elements to the global
+                                        // matrix, which already condenses the
+                                        // hanging node constraints.
+       cell->get_dof_indices (local_dof_indices);
+
+       if (rebuild_stokes_matrix == true)
+         stokes_constraints.distribute_local_to_global (local_matrix,
+                                                        local_rhs,
+                                                        local_dof_indices,
+                                                        stokes_matrix,
+                                                        stokes_rhs);
+       else
+         stokes_constraints.distribute_local_to_global (local_rhs,
+                                                        local_dof_indices,
+                                                        stokes_rhs);
+      }
 
+    rebuild_stokes_matrix = false;
 
+    std::cout << std::endl;
+  }
 
-                                // @sect4{BoussinesqFlowProblem::build_stokes_preconditioner}
-                                //
-                                // This function generates the inner
-                                // preconditioners that are going to be used
-                                // for the Schur complement block
-                                // preconditioner. Since the preconditioners
-                                // need only to be regenerated when the
-                                // matrices change, this function does not
-                                // have to do anything in case the matrices
-                                // have not changed (i.e., the flag
-                                // <code>rebuild_stokes_preconditioner</code>
-                                // has the value
-                                // <code>false</code>). Otherwise its first
-                                // task is to call
-                                // <code>assemble_stokes_preconditioner</code>
-                                // to generate the preconditioner matrices.
-                                //
-                                // Next, we set up the preconditioner for
-                                // the velocity-velocity matrix
-                                // <i>A</i>. As explained in the
-                                // introduction, we are going to use an
-                                // AMG preconditioner based on a vector
-                                // Laplace matrix $\hat{A}$ (which is
-                                // spectrally close to the Stokes matrix
-                                // <i>A</i>). Usually, the
-                                // TrilinosWrappers::PreconditionAMG
-                                // class can be seen as a good black-box
-                                // preconditioner which does not need any
-                                // special knowledge. In this case,
-                                // however, we have to be careful: since
-                                // we build an AMG for a vector problem,
-                                // we have to tell the preconditioner
-                                // setup which dofs belong to which
-                                // vector component. We do this using the
-                                // function
-                                // DoFTools::extract_constant_modes, a
-                                // function that generates a set of
-                                // <code>dim</code> vectors, where each one
-                                // has ones in the respective component
-                                // of the vector problem and zeros
-                                // elsewhere. Hence, these are the
-                                // constant modes on each component,
-                                // which explains the name of the
-                                // variable.
-template <int dim>
-void
-BoussinesqFlowProblem<dim>::build_stokes_preconditioner ()
-{
-  if (rebuild_stokes_preconditioner == false)
-    return;
-
-  std::cout << "   Rebuilding Stokes preconditioner..." << std::flush;
-
-  assemble_stokes_preconditioner ();
-
-  Amg_preconditioner = std_cxx1x::shared_ptr<TrilinosWrappers::PreconditionAMG>
-                      (new TrilinosWrappers::PreconditionAMG());
-
-  std::vector<std::vector<bool> > constant_modes;
-  std::vector<bool>  velocity_components (dim+1,true);
-  velocity_components[dim] = false;
-  DoFTools::extract_constant_modes (stokes_dof_handler, velocity_components,
-                                   constant_modes);
-  TrilinosWrappers::PreconditionAMG::AdditionalData amg_data;
-  amg_data.constant_modes = constant_modes;
-
-                                  // Next, we set some more options of the
-                                  // AMG preconditioner. In particular, we
-                                  // need to tell the AMG setup that we use
-                                  // quadratic basis functions for the
-                                  // velocity matrix (this implies more
-                                  // nonzero elements in the matrix, so
-                                  // that a more rubust algorithm needs to
-                                  // be chosen internally). Moreover, we
-                                  // want to be able to control how the
-                                  // coarsening structure is build up. The
-                                  // way the Trilinos smoothed aggregation
-                                  // AMG does this is to look which matrix
-                                  // entries are of similar size as the
-                                  // diagonal entry in order to
-                                  // algebraically build a coarse-grid
-                                  // structure. By setting the parameter
-                                  // <code>aggregation_threshold</code> to
-                                  // 0.02, we specify that all entries that
-                                  // are more than two precent of size of
-                                  // some diagonal pivots in that row
-                                  // should form one coarse grid
-                                  // point. This parameter is rather
-                                  // ad-hoc, and some fine-tuning of it can
-                                  // influence the performance of the
-                                  // preconditioner. As a rule of thumb,
-                                  // larger values of
-                                  // <code>aggregation_threshold</code>
-                                  // will decrease the number of
-                                  // iterations, but increase the costs per
-                                  // iteration. A look at the Trilinos
-                                  // documentation will provide more
-                                  // information on these parameters. With
-                                  // this data set, we then initialize the
-                                  // preconditioner with the matrix we want
-                                  // it to apply to.
-                                  //
-                                  // Finally, we also initialize the
-                                  // preconditioner for the inversion of
-                                  // the pressure mass matrix. This matrix
-                                  // is symmetric and well-behaved, so we
-                                  // can chose a simple preconditioner. We
-                                  // stick with an incomple Cholesky (IC)
-                                  // factorization preconditioner, which is
-                                  // designed for symmetric matrices. We
-                                  // could have also chosen an SSOR
-                                  // preconditioner with relaxation factor
-                                  // around 1.2, but IC is cheaper for our
-                                  // example. We wrap the preconditioners
-                                  // into a <code>std_cxx1x::shared_ptr</code>
-                                  // pointer, which makes it easier to
-                                  // recreate the preconditioner next time
-                                  // around since we do not have to care
-                                  // about destroying the previously used
-                                  // object.
-  amg_data.elliptic = true;
-  amg_data.higher_order_elements = true;
-  amg_data.smoother_sweeps = 2;
-  amg_data.aggregation_threshold = 0.02;
-  Amg_preconditioner->initialize(stokes_preconditioner_matrix.block(0,0),
-                                amg_data);
-
-  Mp_preconditioner = std_cxx1x::shared_ptr<TrilinosWrappers::PreconditionIC>
-                     (new TrilinosWrappers::PreconditionIC());
-  Mp_preconditioner->initialize(stokes_preconditioner_matrix.block(1,1));
-
-  std::cout << std::endl;
-
-  rebuild_stokes_preconditioner = false;
-}
 
 
 
-                                // @sect4{BoussinesqFlowProblem::assemble_stokes_system}
-                                //
-                                // The time lag scheme we use for advancing
-                                // the coupled Stokes-temperature system
-                                // forces us to split up the assembly (and
-                                // the solution of linear systems) into two
-                                // step. The first one is to create the
-                                // Stokes system matrix and right hand
-                                // side, and the second is to create matrix
-                                // and right hand sides for the temperature
-                                // dofs, which depends on the result of the
-                                // linear system for the velocity.
-                                //
-                                // This function is called at the beginning
-                                // of each time step. In the first time step
-                                // or if the mesh has changed, indicated by
-                                // the <code>rebuild_stokes_matrix</code>, we
-                                // need to assemble the Stokes matrix; on the
-                                // other hand, if the mesh hasn't changed and
-                                // the matrix is already available, this is
-                                // not necessary and all we need to do is
-                                // assemble the right hand side vector which
-                                // changes in each time step.
-                                //
-                                // Regarding the technical details of
-                                // implementation, not much has changed from
-                                // step-22. We reset matrix and vector,
-                                // create a quadrature formula on the cells,
-                                // and then create the respective FEValues
-                                // object. For the update flags, we require
-                                // basis function derivatives only in case of
-                                // a full assembly, since they are not needed
-                                // for the right hand side; as always,
-                                // choosing the minimal set of flags
-                                // depending on what is currently needed
-                                // makes the call to FEValues::reinit further
-                                // down in the program more efficient.
-                                 //
-                                // There is one thing that needs to be
-                                // commented &ndash; since we have a separate
-                                // finite element and DoFHandler for the
-                                // temperature, we need to generate a second
-                                // FEValues object for the proper evaluation
-                                // of the temperature solution. This isn't
-                                // too complicated to realize here: just use
-                                // the temperature structures and set an
-                                // update flag for the basis function values
-                                // which we need for evaluation of the
-                                // temperature solution. The only important
-                                // part to remember here is that the same
-                                // quadrature formula is used for both
-                                // FEValues objects to ensure that we get
-                                // matching information when we loop over the
-                                // quadrature points of the two objects.
-                                //
-                                // The declarations proceed with some
-                                // shortcuts for array sizes, the creation
-                                // of the local matrix and right hand side
-                                // as well as the vector for the indices of
-                                // the local dofs compared to the global
-                                // system.
-template <int dim>
-void BoussinesqFlowProblem<dim>::assemble_stokes_system ()
-{
-  std::cout << "   Assembling..." << std::flush;
-
-  if (rebuild_stokes_matrix == true)
-    stokes_matrix=0;
-
-  stokes_rhs=0;
-
-  const QGauss<dim> quadrature_formula (stokes_degree+2);
-  FEValues<dim>     stokes_fe_values (stokes_fe, quadrature_formula,
-                                     update_values    |
-                                     update_quadrature_points  |
-                                     update_JxW_values |
-                                     (rebuild_stokes_matrix == true
-                                      ?
-                                      update_gradients
-                                      :
-                                      UpdateFlags(0)));
-
-  FEValues<dim>     temperature_fe_values (temperature_fe, quadrature_formula,
-                                          update_values);
-
-  const unsigned int   dofs_per_cell   = stokes_fe.dofs_per_cell;
-  const unsigned int   n_q_points      = quadrature_formula.size();
-
-  FullMatrix<double>   local_matrix (dofs_per_cell, dofs_per_cell);
-  Vector<double>       local_rhs    (dofs_per_cell);
-
-  std::vector<unsigned int> local_dof_indices (dofs_per_cell);
-
-                                  // Next we need a vector that will contain
-                                  // the values of the temperature solution
-                                  // at the previous time level at the
-                                  // quadrature points to assemble the source
-                                  // term in the right hand side of the
-                                  // momentum equation. Let's call this vector
-                                  // <code>old_solution_values</code>.
+                                  // @sect4{BoussinesqFlowProblem::assemble_temperature_matrix}
                                   //
-                                  // The set of vectors we create next hold
-                                  // the evaluations of the basis functions
-                                  // as well as their gradients and
-                                  // symmetrized gradients that will be used
-                                  // for creating the matrices. Putting these
-                                  // into their own arrays rather than asking
-                                  // the FEValues object for this information
-                                  // each time it is needed is an
-                                  // optimization to accelerate the assembly
-                                  // process, see step-22 for details.
+                                  // This function assembles the matrix in
+                                  // the temperature equation. The
+                                  // temperature matrix consists of two
+                                  // parts, a mass matrix and the time step
+                                  // size times a stiffness matrix given by
+                                  // a Laplace term times the amount of
+                                  // diffusion. Since the matrix depends on
+                                  // the time step size (which varies from
+                                  // one step to another), the temperature
+                                  // matrix needs to be updated every time
+                                  // step. We could simply regenerate the
+                                  // matrices in every time step, but this
+                                  // is not really efficient since mass and
+                                  // Laplace matrix do only change when we
+                                  // change the mesh. Hence, we do this
+                                  // more efficiently by generating two
+                                  // separate matrices in this function,
+                                  // one for the mass matrix and one for
+                                  // the stiffness (diffusion) matrix. We
+                                  // will then sum up the matrix plus the
+                                  // stiffness matrix times the time step
+                                  // size once we know the actual time step.
                                   //
-                                  // The last two declarations are used to
-                                  // extract the individual blocks
-                                  // (velocity, pressure, temperature) from
-                                  // the total FE system.
-  std::vector<double>               old_temperature_values(n_q_points);
-
-  std::vector<Tensor<1,dim> >          phi_u       (dofs_per_cell);
-  std::vector<SymmetricTensor<2,dim> > grads_phi_u (dofs_per_cell);
-  std::vector<double>                  div_phi_u   (dofs_per_cell);
-  std::vector<double>                  phi_p       (dofs_per_cell);
-
-  const FEValuesExtractors::Vector velocities (0);
-  const FEValuesExtractors::Scalar pressure (dim);
-
-                                  // Now start the loop over all cells in
-                                  // the problem. We are working on two
-                                  // different DoFHandlers for this
-                                  // assembly routine, so we must have two
-                                  // different cell iterators for the two
-                                  // objects in use. This might seem a bit
-                                  // peculiar, since both the Stokes system
-                                  // and the temperature system use the
-                                  // same grid, but that's the only way to
-                                  // keep degrees of freedom in sync. The
-                                  // first statements within the loop are
-                                  // again all very familiar, doing the
-                                  // update of the finite element data as
-                                  // specified by the update flags, zeroing
-                                  // out the local arrays and getting the
-                                  // values of the old solution at the
-                                  // quadrature points. Then we are ready to
-                                  // loop over the quadrature points on the
-                                  // cell.
-  typename DoFHandler<dim>::active_cell_iterator
-    cell = stokes_dof_handler.begin_active(),
-    endc = stokes_dof_handler.end();
-  typename DoFHandler<dim>::active_cell_iterator
-    temperature_cell = temperature_dof_handler.begin_active();
-
-  for (; cell!=endc; ++cell, ++temperature_cell)
-    {
-      stokes_fe_values.reinit (cell);
-      temperature_fe_values.reinit (temperature_cell);
-
-      local_matrix = 0;
-      local_rhs = 0;
+                                  // So the details for this first step are
+                                  // very simple. In case we need to
+                                  // rebuild the matrix (i.e., the mesh has
+                                  // changed), we zero the data structures,
+                                  // get a quadrature formula and a
+                                  // FEValues object, and create local
+                                  // matrices, local dof indices and
+                                  // evaluation structures for the basis
+                                  // functions.
+  template <int dim>
+  void BoussinesqFlowProblem<dim>::assemble_temperature_matrix ()
+  {
+    if (rebuild_temperature_matrices == false)
+      return;
+
+    temperature_mass_matrix = 0;
+    temperature_stiffness_matrix = 0;
+
+    QGauss<dim>   quadrature_formula (temperature_degree+2);
+    FEValues<dim> temperature_fe_values (temperature_fe, quadrature_formula,
+                                        update_values    | update_gradients |
+                                        update_JxW_values);
+
+    const unsigned int   dofs_per_cell   = temperature_fe.dofs_per_cell;
+    const unsigned int   n_q_points      = quadrature_formula.size();
+
+    FullMatrix<double>   local_mass_matrix (dofs_per_cell, dofs_per_cell);
+    FullMatrix<double>   local_stiffness_matrix (dofs_per_cell, dofs_per_cell);
+
+    std::vector<unsigned int> local_dof_indices (dofs_per_cell);
+
+    std::vector<double>         phi_T       (dofs_per_cell);
+    std::vector<Tensor<1,dim> > grad_phi_T  (dofs_per_cell);
+
+                                    // Now, let's start the loop over all cells
+                                    // in the triangulation. We need to zero
+                                    // out the local matrices, update the
+                                    // finite element evaluations, and then
+                                    // loop over the rows and columns of the
+                                    // matrices on each quadrature point, where
+                                    // we then create the mass matrix and the
+                                    // stiffness matrix (Laplace terms times
+                                    // the diffusion
+                                    // <code>EquationData::kappa</code>. Finally,
+                                    // we let the constraints object insert
+                                    // these values into the global matrix, and
+                                    // directly condense the constraints into
+                                    // the matrix.
+    typename DoFHandler<dim>::active_cell_iterator
+      cell = temperature_dof_handler.begin_active(),
+      endc = temperature_dof_handler.end();
+    for (; cell!=endc; ++cell)
+      {
+       local_mass_matrix = 0;
+       local_stiffness_matrix = 0;
 
-      temperature_fe_values.get_function_values (old_temperature_solution,
-                                                old_temperature_values);
+       temperature_fe_values.reinit (cell);
 
-      for (unsigned int q=0; q<n_q_points; ++q)
-       {
-         const double old_temperature = old_temperature_values[q];
-
-                                          // Next we extract the values and
-                                          // gradients of basis functions
-                                          // relevant to the terms in the
-                                          // inner products. As shown in
-                                          // step-22 this helps accelerate
-                                          // assembly.
-                                          //
-                                          // Once this is done, we start the
-                                          // loop over the rows and columns
-                                          // of the local matrix and feed the
-                                          // matrix with the relevant
-                                          // products. The right hand side is
-                                          // filled with the forcing term
-                                          // driven by temperature in
-                                          // direction of gravity (which is
-                                          // vertical in our example).  Note
-                                          // that the right hand side term is
-                                          // always generated, whereas the
-                                          // matrix contributions are only
-                                          // updated when it is requested by
-                                          // the
-                                          // <code>rebuild_matrices</code>
-                                          // flag.
-         for (unsigned int k=0; k<dofs_per_cell; ++k)
-           {
-             phi_u[k] = stokes_fe_values[velocities].value (k,q);
-             if (rebuild_stokes_matrix)
-               {
-                 grads_phi_u[k] = stokes_fe_values[velocities].symmetric_gradient(k,q);
-                 div_phi_u[k]   = stokes_fe_values[velocities].divergence (k, q);
-                 phi_p[k]       = stokes_fe_values[pressure].value (k, q);
-               }
-           }
+       for (unsigned int q=0; q<n_q_points; ++q)
+         {
+           for (unsigned int k=0; k<dofs_per_cell; ++k)
+             {
+               grad_phi_T[k] = temperature_fe_values.shape_grad (k,q);
+               phi_T[k]      = temperature_fe_values.shape_value (k, q);
+             }
 
-         if (rebuild_stokes_matrix)
            for (unsigned int i=0; i<dofs_per_cell; ++i)
              for (unsigned int j=0; j<dofs_per_cell; ++j)
-               local_matrix(i,j) += (EquationData::eta * 2 *
-                                     (grads_phi_u[i] * grads_phi_u[j])
-                                     - div_phi_u[i] * phi_p[j]
-                                     - phi_p[i] * div_phi_u[j])
-                                    * stokes_fe_values.JxW(q);
-
-         const Point<dim> gravity = -( (dim == 2) ? (Point<dim> (0,1)) :
-                                       (Point<dim> (0,0,1)) );
-         for (unsigned int i=0; i<dofs_per_cell; ++i)
-           local_rhs(i) += (-EquationData::density *
-                            EquationData::beta *
-                            gravity * phi_u[i] * old_temperature)*
-                           stokes_fe_values.JxW(q);
-       }
+               {
+                 local_mass_matrix(i,j)
+                   += (phi_T[i] * phi_T[j]
+                       *
+                       temperature_fe_values.JxW(q));
+                 local_stiffness_matrix(i,j)
+                   += (EquationData::kappa * grad_phi_T[i] * grad_phi_T[j]
+                       *
+                       temperature_fe_values.JxW(q));
+               }
+         }
 
-                                      // The last step in the loop over all
-                                      // cells is to enter the local
-                                      // contributions into the global matrix
-                                      // and vector structures to the
-                                      // positions specified in
-                                      // <code>local_dof_indices</code>.
-                                      // Again, we let the ConstraintMatrix
-                                      // class do the insertion of the cell
-                                      // matrix elements to the global
-                                      // matrix, which already condenses the
-                                      // hanging node constraints.
-      cell->get_dof_indices (local_dof_indices);
-
-      if (rebuild_stokes_matrix == true)
-       stokes_constraints.distribute_local_to_global (local_matrix,
-                                                      local_rhs,
-                                                      local_dof_indices,
-                                                      stokes_matrix,
-                                                      stokes_rhs);
-      else
-       stokes_constraints.distribute_local_to_global (local_rhs,
-                                                      local_dof_indices,
-                                                      stokes_rhs);
-    }
+       cell->get_dof_indices (local_dof_indices);
 
-  rebuild_stokes_matrix = false;
+       temperature_constraints.distribute_local_to_global (local_mass_matrix,
+                                                           local_dof_indices,
+                                                           temperature_mass_matrix);
+       temperature_constraints.distribute_local_to_global (local_stiffness_matrix,
+                                                           local_dof_indices,
+                                                           temperature_stiffness_matrix);
+      }
 
-  std::cout << std::endl;
-}
+    rebuild_temperature_matrices = false;
+  }
 
 
 
+                                  // @sect4{BoussinesqFlowProblem::assemble_temperature_system}
+                                  //
+                                  // This function does the second part of
+                                  // the assembly work on the temperature
+                                  // matrix, the actual addition of
+                                  // pressure mass and stiffness matrix
+                                  // (where the time step size comes into
+                                  // play), as well as the creation of the
+                                  // velocity-dependent right hand
+                                  // side. The declarations for the right
+                                  // hand side assembly in this function
+                                  // are pretty much the same as the ones
+                                  // used in the other assembly routines,
+                                  // except that we restrict ourselves to
+                                  // vectors this time. We are going to
+                                  // calculate residuals on the temperature
+                                  // system, which means that we have to
+                                  // evaluate second derivatives, specified
+                                  // by the update flag
+                                  // <code>update_hessians</code>.
+                                  //
+                                  // The temperature equation is coupled to the
+                                  // Stokes system by means of the fluid
+                                  // velocity. These two parts of the solution
+                                  // are associated with different DoFHandlers,
+                                  // so we again need to create a second
+                                  // FEValues object for the evaluation of the
+                                  // velocity at the quadrature points.
+  template <int dim>
+  void BoussinesqFlowProblem<dim>::
+  assemble_temperature_system (const double maximal_velocity)
+  {
+    const bool use_bdf2_scheme = (timestep_number != 0);
 
-                                // @sect4{BoussinesqFlowProblem::assemble_temperature_matrix}
-                                //
-                                // This function assembles the matrix in
-                                // the temperature equation. The
-                                // temperature matrix consists of two
-                                // parts, a mass matrix and the time step
-                                // size times a stiffness matrix given by
-                                // a Laplace term times the amount of
-                                // diffusion. Since the matrix depends on
-                                // the time step size (which varies from
-                                // one step to another), the temperature
-                                // matrix needs to be updated every time
-                                // step. We could simply regenerate the
-                                // matrices in every time step, but this
-                                // is not really efficient since mass and
-                                // Laplace matrix do only change when we
-                                // change the mesh. Hence, we do this
-                                // more efficiently by generating two
-                                // separate matrices in this function,
-                                // one for the mass matrix and one for
-                                // the stiffness (diffusion) matrix. We
-                                // will then sum up the matrix plus the
-                                // stiffness matrix times the time step
-                                // size once we know the actual time step.
-                                //
-                                // So the details for this first step are
-                                // very simple. In case we need to
-                                // rebuild the matrix (i.e., the mesh has
-                                // changed), we zero the data structures,
-                                // get a quadrature formula and a
-                                // FEValues object, and create local
-                                // matrices, local dof indices and
-                                // evaluation structures for the basis
-                                // functions.
-template <int dim>
-void BoussinesqFlowProblem<dim>::assemble_temperature_matrix ()
-{
-  if (rebuild_temperature_matrices == false)
-    return;
-
-  temperature_mass_matrix = 0;
-  temperature_stiffness_matrix = 0;
-
-  QGauss<dim>   quadrature_formula (temperature_degree+2);
-  FEValues<dim> temperature_fe_values (temperature_fe, quadrature_formula,
-                                      update_values    | update_gradients |
-                                      update_JxW_values);
-
-  const unsigned int   dofs_per_cell   = temperature_fe.dofs_per_cell;
-  const unsigned int   n_q_points      = quadrature_formula.size();
-
-  FullMatrix<double>   local_mass_matrix (dofs_per_cell, dofs_per_cell);
-  FullMatrix<double>   local_stiffness_matrix (dofs_per_cell, dofs_per_cell);
-
-  std::vector<unsigned int> local_dof_indices (dofs_per_cell);
-
-  std::vector<double>         phi_T       (dofs_per_cell);
-  std::vector<Tensor<1,dim> > grad_phi_T  (dofs_per_cell);
-
-                                  // Now, let's start the loop over all cells
-                                  // in the triangulation. We need to zero
-                                  // out the local matrices, update the
-                                  // finite element evaluations, and then
-                                  // loop over the rows and columns of the
-                                  // matrices on each quadrature point, where
-                                  // we then create the mass matrix and the
-                                  // stiffness matrix (Laplace terms times
-                                  // the diffusion
-                                  // <code>EquationData::kappa</code>. Finally,
-                                  // we let the constraints object insert
-                                  // these values into the global matrix, and
-                                  // directly condense the constraints into
-                                  // the matrix.
-  typename DoFHandler<dim>::active_cell_iterator
-    cell = temperature_dof_handler.begin_active(),
-    endc = temperature_dof_handler.end();
-  for (; cell!=endc; ++cell)
-    {
-      local_mass_matrix = 0;
-      local_stiffness_matrix = 0;
+    if (use_bdf2_scheme == true)
+      {
+       temperature_matrix.copy_from (temperature_mass_matrix);
+       temperature_matrix *= (2*time_step + old_time_step) /
+                             (time_step + old_time_step);
+       temperature_matrix.add (time_step, temperature_stiffness_matrix);
+      }
+    else
+      {
+       temperature_matrix.copy_from (temperature_mass_matrix);
+       temperature_matrix.add (time_step, temperature_stiffness_matrix);
+      }
 
-      temperature_fe_values.reinit (cell);
+    temperature_rhs = 0;
+
+    const QGauss<dim> quadrature_formula(temperature_degree+2);
+    FEValues<dim>     temperature_fe_values (temperature_fe, quadrature_formula,
+                                            update_values    |
+                                            update_gradients |
+                                            update_hessians  |
+                                            update_quadrature_points  |
+                                            update_JxW_values);
+    FEValues<dim>     stokes_fe_values (stokes_fe, quadrature_formula,
+                                       update_values);
+
+    const unsigned int   dofs_per_cell   = temperature_fe.dofs_per_cell;
+    const unsigned int   n_q_points      = quadrature_formula.size();
+
+    Vector<double>       local_rhs (dofs_per_cell);
+    FullMatrix<double>   local_matrix (dofs_per_cell, dofs_per_cell);
+
+    std::vector<unsigned int> local_dof_indices (dofs_per_cell);
+
+                                    // Next comes the declaration of vectors
+                                    // to hold the old and older solution
+                                    // values (as a notation for time levels
+                                    // <i>n-1</i> and <i>n-2</i>,
+                                    // respectively) and gradients at
+                                    // quadrature points of the current
+                                    // cell. We also declarate an object to
+                                    // hold the temperature right hande side
+                                    // values (<code>gamma_values</code>),
+                                    // and we again use shortcuts for the
+                                    // temperature basis
+                                    // functions. Eventually, we need to find
+                                    // the temperature extrema and the
+                                    // diameter of the computational domain
+                                    // which will be used for the definition
+                                    // of the stabilization parameter (we got
+                                    // the maximal velocity as an input to
+                                    // this function).
+    std::vector<Tensor<1,dim> > old_velocity_values (n_q_points);
+    std::vector<Tensor<1,dim> > old_old_velocity_values (n_q_points);
+    std::vector<double>         old_temperature_values (n_q_points);
+    std::vector<double>         old_old_temperature_values(n_q_points);
+    std::vector<Tensor<1,dim> > old_temperature_grads(n_q_points);
+    std::vector<Tensor<1,dim> > old_old_temperature_grads(n_q_points);
+    std::vector<double>         old_temperature_laplacians(n_q_points);
+    std::vector<double>         old_old_temperature_laplacians(n_q_points);
+
+    EquationData::TemperatureRightHandSide<dim>  temperature_right_hand_side;
+    std::vector<double> gamma_values (n_q_points);
+
+    std::vector<double>         phi_T      (dofs_per_cell);
+    std::vector<Tensor<1,dim> > grad_phi_T (dofs_per_cell);
+
+    const std::pair<double,double>
+      global_T_range = get_extrapolated_temperature_range();
+
+    const FEValuesExtractors::Vector velocities (0);
+
+                                    // Now, let's start the loop over all cells
+                                    // in the triangulation. Again, we need two
+                                    // cell iterators that walk in parallel
+                                    // through the cells of the two involved
+                                    // DoFHandler objects for the Stokes and
+                                    // temperature part. Within the loop, we
+                                    // first set the local rhs to zero, and
+                                    // then get the values and derivatives of
+                                    // the old solution functions at the
+                                    // quadrature points, since they are going
+                                    // to be needed for the definition of the
+                                    // stabilization parameters and as
+                                    // coefficients in the equation,
+                                    // respectively. Note that since the
+                                    // temperature has its own DoFHandler and
+                                    // FEValues object we get the entire
+                                    // solution at the quadrature point (which
+                                    // is the scalar temperature field only
+                                    // anyway) whereas for the Stokes part we
+                                    // restrict ourselves to extracting the
+                                    // velocity part (and ignoring the pressure
+                                    // part) by using
+                                    // <code>stokes_fe_values[velocities].get_function_values</code>.
+    typename DoFHandler<dim>::active_cell_iterator
+      cell = temperature_dof_handler.begin_active(),
+      endc = temperature_dof_handler.end();
+    typename DoFHandler<dim>::active_cell_iterator
+      stokes_cell = stokes_dof_handler.begin_active();
 
-      for (unsigned int q=0; q<n_q_points; ++q)
-       {
-         for (unsigned int k=0; k<dofs_per_cell; ++k)
-           {
-             grad_phi_T[k] = temperature_fe_values.shape_grad (k,q);
-             phi_T[k]      = temperature_fe_values.shape_value (k, q);
-           }
-
-         for (unsigned int i=0; i<dofs_per_cell; ++i)
-           for (unsigned int j=0; j<dofs_per_cell; ++j)
+    for (; cell!=endc; ++cell, ++stokes_cell)
+      {
+       local_rhs = 0;
+
+       temperature_fe_values.reinit (cell);
+       stokes_fe_values.reinit (stokes_cell);
+
+       temperature_fe_values.get_function_values (old_temperature_solution,
+                                                  old_temperature_values);
+       temperature_fe_values.get_function_values (old_old_temperature_solution,
+                                                  old_old_temperature_values);
+
+       temperature_fe_values.get_function_gradients (old_temperature_solution,
+                                                     old_temperature_grads);
+       temperature_fe_values.get_function_gradients (old_old_temperature_solution,
+                                                     old_old_temperature_grads);
+
+       temperature_fe_values.get_function_laplacians (old_temperature_solution,
+                                                      old_temperature_laplacians);
+       temperature_fe_values.get_function_laplacians (old_old_temperature_solution,
+                                                      old_old_temperature_laplacians);
+
+       temperature_right_hand_side.value_list (temperature_fe_values.get_quadrature_points(),
+                                               gamma_values);
+
+       stokes_fe_values[velocities].get_function_values (stokes_solution,
+                                                         old_velocity_values);
+       stokes_fe_values[velocities].get_function_values (old_stokes_solution,
+                                                         old_old_velocity_values);
+
+                                        // Next, we calculate the artificial
+                                        // viscosity for stabilization
+                                        // according to the discussion in the
+                                        // introduction using the dedicated
+                                        // function. With that at hand, we
+                                        // can get into the loop over
+                                        // quadrature points and local rhs
+                                        // vector components. The terms here
+                                        // are quite lenghty, but their
+                                        // definition follows the
+                                        // time-discrete system developed in
+                                        // the introduction of this
+                                        // program. The BDF-2 scheme needs
+                                        // one more term from the old time
+                                        // step (and involves more
+                                        // complicated factors) than the
+                                        // backward Euler scheme that is used
+                                        // for the first time step. When all
+                                        // this is done, we distribute the
+                                        // local vector into the global one
+                                        // (including hanging node
+                                        // constraints).
+       const double nu
+         = compute_viscosity (old_temperature_values,
+                              old_old_temperature_values,
+                              old_temperature_grads,
+                              old_old_temperature_grads,
+                              old_temperature_laplacians,
+                              old_old_temperature_laplacians,
+                              old_velocity_values,
+                              old_old_velocity_values,
+                              gamma_values,
+                              maximal_velocity,
+                              global_T_range.second - global_T_range.first,
+                              cell->diameter());
+
+       for (unsigned int q=0; q<n_q_points; ++q)
+         {
+           for (unsigned int k=0; k<dofs_per_cell; ++k)
              {
-               local_mass_matrix(i,j)
-                 += (phi_T[i] * phi_T[j]
-                     *
-                     temperature_fe_values.JxW(q));
-               local_stiffness_matrix(i,j)
-                 += (EquationData::kappa * grad_phi_T[i] * grad_phi_T[j]
-                     *
-                     temperature_fe_values.JxW(q));
+               grad_phi_T[k] = temperature_fe_values.shape_grad (k,q);
+               phi_T[k]      = temperature_fe_values.shape_value (k, q);
              }
-       }
 
-      cell->get_dof_indices (local_dof_indices);
+           const double old_Ts
+             = (use_bdf2_scheme ?
+                (old_temperature_values[q] *
+                 (time_step + old_time_step) / old_time_step
+                 -
+                 old_old_temperature_values[q] *
+                 (time_step * time_step) /
+                 (old_time_step * (time_step + old_time_step)))
+                :
+                old_temperature_values[q]);
+
+           const Tensor<1,dim> ext_grad_T
+             = (use_bdf2_scheme ?
+                (old_temperature_grads[q] *
+                 (1+time_step/old_time_step)
+                 -
+                 old_old_temperature_grads[q] *
+                 time_step / old_time_step)
+                :
+                old_temperature_grads[q]);
+
+           const Tensor<1,dim> extrapolated_u
+             = (use_bdf2_scheme ?
+                (old_velocity_values[q] * (1+time_step/old_time_step) -
+                 old_old_velocity_values[q] * time_step/old_time_step)
+                :
+                old_velocity_values[q]);
 
-      temperature_constraints.distribute_local_to_global (local_mass_matrix,
-                                                         local_dof_indices,
-                                                         temperature_mass_matrix);
-      temperature_constraints.distribute_local_to_global (local_stiffness_matrix,
-                                                         local_dof_indices,
-                                                         temperature_stiffness_matrix);
-    }
-
-  rebuild_temperature_matrices = false;
-}
+           for (unsigned int i=0; i<dofs_per_cell; ++i)
+             local_rhs(i) += (old_Ts * phi_T[i]
+                              -
+                              time_step *
+                              extrapolated_u * ext_grad_T * phi_T[i]
+                              -
+                              time_step *
+                              nu * ext_grad_T * grad_phi_T[i]
+                              +
+                              time_step *
+                              gamma_values[q] * phi_T[i])
+                             *
+                             temperature_fe_values.JxW(q);
+         }
+
+       cell->get_dof_indices (local_dof_indices);
+       temperature_constraints.distribute_local_to_global (local_rhs,
+                                                           local_dof_indices,
+                                                           temperature_rhs);
+      }
+  }
 
 
 
-                                // @sect4{BoussinesqFlowProblem::assemble_temperature_system}
-                                //
-                                // This function does the second part of
-                                // the assembly work on the temperature
-                                // matrix, the actual addition of
-                                // pressure mass and stiffness matrix
-                                // (where the time step size comes into
-                                // play), as well as the creation of the
-                                // velocity-dependent right hand
-                                // side. The declarations for the right
-                                // hand side assembly in this function
-                                // are pretty much the same as the ones
-                                // used in the other assembly routines,
-                                // except that we restrict ourselves to
-                                // vectors this time. We are going to
-                                // calculate residuals on the temperature
-                                // system, which means that we have to
-                                // evaluate second derivatives, specified
-                                // by the update flag
-                                // <code>update_hessians</code>.
-                                //
-                                // The temperature equation is coupled to the
-                                // Stokes system by means of the fluid
-                                // velocity. These two parts of the solution
-                                // are associated with different DoFHandlers,
-                                // so we again need to create a second
-                                // FEValues object for the evaluation of the
-                                // velocity at the quadrature points.
-template <int dim>
-void BoussinesqFlowProblem<dim>::
-  assemble_temperature_system (const double maximal_velocity)
-{
-  const bool use_bdf2_scheme = (timestep_number != 0);
 
-  if (use_bdf2_scheme == true)
-    {
-      temperature_matrix.copy_from (temperature_mass_matrix);
-      temperature_matrix *= (2*time_step + old_time_step) /
-                           (time_step + old_time_step);
-      temperature_matrix.add (time_step, temperature_stiffness_matrix);
-    }
-  else
-    {
-      temperature_matrix.copy_from (temperature_mass_matrix);
-      temperature_matrix.add (time_step, temperature_stiffness_matrix);
-    }
+                                  // @sect4{BoussinesqFlowProblem::solve}
+                                  //
+                                  // This function solves the linear systems
+                                  // of equations. Following the
+                                  // introduction, we start with the Stokes
+                                  // system, where we need to generate our
+                                  // block Schur preconditioner. Since all
+                                  // the relevant actions are implemented in
+                                  // the class
+                                  // <code>BlockSchurPreconditioner</code>,
+                                  // all we have to do is to initialize the
+                                  // class appropriately. What we need to
+                                  // pass down is an
+                                  // <code>InverseMatrix</code> object for
+                                  // the pressure mass matrix, which we set
+                                  // up using the respective class together
+                                  // with the IC preconditioner we already
+                                  // generated, and the AMG preconditioner
+                                  // for the velocity-velocity matrix. Note
+                                  // that both <code>Mp_preconditioner</code>
+                                  // and <code>Amg_preconditioner</code> are
+                                  // only pointers, so we use <code>*</code>
+                                  // to pass down the actual preconditioner
+                                  // objects.
+                                  //
+                                  // Once the preconditioner is ready, we
+                                  // create a GMRES solver for the block
+                                  // system. Since we are working with
+                                  // Trilinos data structures, we have to set
+                                  // the respective template argument in the
+                                  // solver. GMRES needs to internally store
+                                  // temporary vectors for each iteration
+                                  // (see the discussion in the results
+                                  // section of step-22) &ndash; the more
+                                  // vectors it can use, the better it will
+                                  // generally perform. To keep memory
+                                  // demands in check, we set the number of
+                                  // vectors to 100. This means that up to
+                                  // 100 solver iterations, every temporary
+                                  // vector can be stored. If the solver
+                                  // needs to iterate more often to get the
+                                  // specified tolerance, it will work on a
+                                  // reduced set of vectors by restarting at
+                                  // every 100 iterations.
+                                  //
+                                  // With this all set up, we solve the system
+                                  // and distribute the constraints in the
+                                  // Stokes system, i.e. hanging nodes and
+                                  // no-flux boundary condition, in order to
+                                  // have the appropriate solution values even
+                                  // at constrained dofs. Finally, we write the
+                                  // number of iterations to the screen.
+  template <int dim>
+  void BoussinesqFlowProblem<dim>::solve ()
+  {
+    std::cout << "   Solving..." << std::endl;
 
-  temperature_rhs = 0;
-
-  const QGauss<dim> quadrature_formula(temperature_degree+2);
-  FEValues<dim>     temperature_fe_values (temperature_fe, quadrature_formula,
-                                          update_values    |
-                                          update_gradients |
-                                          update_hessians  |
-                                          update_quadrature_points  |
-                                          update_JxW_values);
-  FEValues<dim>     stokes_fe_values (stokes_fe, quadrature_formula,
-                                     update_values);
-
-  const unsigned int   dofs_per_cell   = temperature_fe.dofs_per_cell;
-  const unsigned int   n_q_points      = quadrature_formula.size();
-
-  Vector<double>       local_rhs (dofs_per_cell);
-  FullMatrix<double>   local_matrix (dofs_per_cell, dofs_per_cell);
-
-  std::vector<unsigned int> local_dof_indices (dofs_per_cell);
-
-                                  // Next comes the declaration of vectors
-                                  // to hold the old and older solution
-                                  // values (as a notation for time levels
-                                  // <i>n-1</i> and <i>n-2</i>,
-                                  // respectively) and gradients at
-                                  // quadrature points of the current
-                                  // cell. We also declarate an object to
-                                  // hold the temperature right hande side
-                                  // values (<code>gamma_values</code>),
-                                  // and we again use shortcuts for the
-                                  // temperature basis
-                                  // functions. Eventually, we need to find
-                                  // the temperature extrema and the
-                                  // diameter of the computational domain
-                                  // which will be used for the definition
-                                  // of the stabilization parameter (we got
-                                  // the maximal velocity as an input to
-                                  // this function).
-  std::vector<Tensor<1,dim> > old_velocity_values (n_q_points);
-  std::vector<Tensor<1,dim> > old_old_velocity_values (n_q_points);
-  std::vector<double>         old_temperature_values (n_q_points);
-  std::vector<double>         old_old_temperature_values(n_q_points);
-  std::vector<Tensor<1,dim> > old_temperature_grads(n_q_points);
-  std::vector<Tensor<1,dim> > old_old_temperature_grads(n_q_points);
-  std::vector<double>         old_temperature_laplacians(n_q_points);
-  std::vector<double>         old_old_temperature_laplacians(n_q_points);
-
-  EquationData::TemperatureRightHandSide<dim>  temperature_right_hand_side;
-  std::vector<double> gamma_values (n_q_points);
-
-  std::vector<double>         phi_T      (dofs_per_cell);
-  std::vector<Tensor<1,dim> > grad_phi_T (dofs_per_cell);
-
-  const std::pair<double,double>
-    global_T_range = get_extrapolated_temperature_range();
-
-  const FEValuesExtractors::Vector velocities (0);
-
-                                  // Now, let's start the loop over all cells
-                                  // in the triangulation. Again, we need two
-                                  // cell iterators that walk in parallel
-                                  // through the cells of the two involved
-                                  // DoFHandler objects for the Stokes and
-                                  // temperature part. Within the loop, we
-                                  // first set the local rhs to zero, and
-                                  // then get the values and derivatives of
-                                  // the old solution functions at the
-                                  // quadrature points, since they are going
-                                  // to be needed for the definition of the
-                                  // stabilization parameters and as
-                                  // coefficients in the equation,
-                                  // respectively. Note that since the
-                                  // temperature has its own DoFHandler and
-                                  // FEValues object we get the entire
-                                  // solution at the quadrature point (which
-                                  // is the scalar temperature field only
-                                  // anyway) whereas for the Stokes part we
-                                  // restrict ourselves to extracting the
-                                  // velocity part (and ignoring the pressure
-                                  // part) by using
-                                  // <code>stokes_fe_values[velocities].get_function_values</code>.
-  typename DoFHandler<dim>::active_cell_iterator
-    cell = temperature_dof_handler.begin_active(),
-    endc = temperature_dof_handler.end();
-  typename DoFHandler<dim>::active_cell_iterator
-    stokes_cell = stokes_dof_handler.begin_active();
-
-  for (; cell!=endc; ++cell, ++stokes_cell)
     {
-      local_rhs = 0;
-
-      temperature_fe_values.reinit (cell);
-      stokes_fe_values.reinit (stokes_cell);
-
-      temperature_fe_values.get_function_values (old_temperature_solution,
-                                                old_temperature_values);
-      temperature_fe_values.get_function_values (old_old_temperature_solution,
-                                                old_old_temperature_values);
-
-      temperature_fe_values.get_function_gradients (old_temperature_solution,
-                                                   old_temperature_grads);
-      temperature_fe_values.get_function_gradients (old_old_temperature_solution,
-                                                   old_old_temperature_grads);
-
-      temperature_fe_values.get_function_laplacians (old_temperature_solution,
-                                                    old_temperature_laplacians);
-      temperature_fe_values.get_function_laplacians (old_old_temperature_solution,
-                                                  old_old_temperature_laplacians);
-
-      temperature_right_hand_side.value_list (temperature_fe_values.get_quadrature_points(),
-                                             gamma_values);
-
-      stokes_fe_values[velocities].get_function_values (stokes_solution,
-                                                       old_velocity_values);
-      stokes_fe_values[velocities].get_function_values (old_stokes_solution,
-                                                       old_old_velocity_values);
-
-                                      // Next, we calculate the artificial
-                                      // viscosity for stabilization
-                                      // according to the discussion in the
-                                      // introduction using the dedicated
-                                      // function. With that at hand, we
-                                      // can get into the loop over
-                                      // quadrature points and local rhs
-                                      // vector components. The terms here
-                                      // are quite lenghty, but their
-                                      // definition follows the
-                                      // time-discrete system developed in
-                                      // the introduction of this
-                                      // program. The BDF-2 scheme needs
-                                      // one more term from the old time
-                                      // step (and involves more
-                                      // complicated factors) than the
-                                      // backward Euler scheme that is used
-                                      // for the first time step. When all
-                                      // this is done, we distribute the
-                                      // local vector into the global one
-                                      // (including hanging node
-                                      // constraints).
-      const double nu
-       = compute_viscosity (old_temperature_values,
-                            old_old_temperature_values,
-                            old_temperature_grads,
-                            old_old_temperature_grads,
-                            old_temperature_laplacians,
-                            old_old_temperature_laplacians,
-                            old_velocity_values,
-                            old_old_velocity_values,
-                            gamma_values,
-                            maximal_velocity,
-                            global_T_range.second - global_T_range.first,
-                            cell->diameter());
-
-      for (unsigned int q=0; q<n_q_points; ++q)
-       {
-         for (unsigned int k=0; k<dofs_per_cell; ++k)
-           {
-             grad_phi_T[k] = temperature_fe_values.shape_grad (k,q);
-             phi_T[k]      = temperature_fe_values.shape_value (k, q);
-           }
-
-         const double old_Ts
-           = (use_bdf2_scheme ?
-              (old_temperature_values[q] *
-               (time_step + old_time_step) / old_time_step
-               -
-               old_old_temperature_values[q] *
-               (time_step * time_step) /
-               (old_time_step * (time_step + old_time_step)))
-              :
-              old_temperature_values[q]);
-
-         const Tensor<1,dim> ext_grad_T
-           = (use_bdf2_scheme ?
-              (old_temperature_grads[q] *
-               (1+time_step/old_time_step)
-               -
-               old_old_temperature_grads[q] *
-               time_step / old_time_step)
-              :
-              old_temperature_grads[q]);
-
-         const Tensor<1,dim> extrapolated_u
-           = (use_bdf2_scheme ?
-              (old_velocity_values[q] * (1+time_step/old_time_step) -
-               old_old_velocity_values[q] * time_step/old_time_step)
-              :
-              old_velocity_values[q]);
-
-         for (unsigned int i=0; i<dofs_per_cell; ++i)
-           local_rhs(i) += (old_Ts * phi_T[i]
-                            -
-                            time_step *
-                            extrapolated_u * ext_grad_T * phi_T[i]
-                            -
-                            time_step *
-                            nu * ext_grad_T * grad_phi_T[i]
-                            +
-                            time_step *
-                            gamma_values[q] * phi_T[i])
-                           *
-                           temperature_fe_values.JxW(q);
-       }
+      const LinearSolvers::InverseMatrix<TrilinosWrappers::SparseMatrix,
+       TrilinosWrappers::PreconditionIC>
+       mp_inverse (stokes_preconditioner_matrix.block(1,1), *Mp_preconditioner);
 
-      cell->get_dof_indices (local_dof_indices);
-      temperature_constraints.distribute_local_to_global (local_rhs,
-                                                         local_dof_indices,
-                                                         temperature_rhs);
-    }
-}
+      const LinearSolvers::BlockSchurPreconditioner<TrilinosWrappers::PreconditionAMG,
+       TrilinosWrappers::PreconditionIC>
+       preconditioner (stokes_matrix, mp_inverse, *Amg_preconditioner);
 
+      SolverControl solver_control (stokes_matrix.m(),
+                                   1e-6*stokes_rhs.l2_norm());
 
+      SolverGMRES<TrilinosWrappers::BlockVector>
+       gmres (solver_control,
+              SolverGMRES<TrilinosWrappers::BlockVector >::AdditionalData(100));
 
+      for (unsigned int i=0; i<stokes_solution.size(); ++i)
+       if (stokes_constraints.is_constrained(i))
+         stokes_solution(i) = 0;
 
-                                // @sect4{BoussinesqFlowProblem::solve}
-                                //
-                                // This function solves the linear systems
-                                // of equations. Following the
-                                // introduction, we start with the Stokes
-                                // system, where we need to generate our
-                                // block Schur preconditioner. Since all
-                                // the relevant actions are implemented in
-                                // the class
-                                // <code>BlockSchurPreconditioner</code>,
-                                // all we have to do is to initialize the
-                                // class appropriately. What we need to
-                                // pass down is an
-                                // <code>InverseMatrix</code> object for
-                                // the pressure mass matrix, which we set
-                                // up using the respective class together
-                                // with the IC preconditioner we already
-                                // generated, and the AMG preconditioner
-                                // for the velocity-velocity matrix. Note
-                                // that both <code>Mp_preconditioner</code>
-                                // and <code>Amg_preconditioner</code> are
-                                // only pointers, so we use <code>*</code>
-                                // to pass down the actual preconditioner
-                                // objects.
-                                //
-                                // Once the preconditioner is ready, we
-                                // create a GMRES solver for the block
-                                // system. Since we are working with
-                                // Trilinos data structures, we have to set
-                                // the respective template argument in the
-                                // solver. GMRES needs to internally store
-                                // temporary vectors for each iteration
-                                // (see the discussion in the results
-                                // section of step-22) &ndash; the more
-                                // vectors it can use, the better it will
-                                // generally perform. To keep memory
-                                // demands in check, we set the number of
-                                // vectors to 100. This means that up to
-                                // 100 solver iterations, every temporary
-                                // vector can be stored. If the solver
-                                // needs to iterate more often to get the
-                                // specified tolerance, it will work on a
-                                // reduced set of vectors by restarting at
-                                // every 100 iterations.
-                                //
-                                // With this all set up, we solve the system
-                                // and distribute the constraints in the
-                                // Stokes system, i.e. hanging nodes and
-                                // no-flux boundary condition, in order to
-                                // have the appropriate solution values even
-                                // at constrained dofs. Finally, we write the
-                                // number of iterations to the screen.
-template <int dim>
-void BoussinesqFlowProblem<dim>::solve ()
-{
-  std::cout << "   Solving..." << std::endl;
+      gmres.solve(stokes_matrix, stokes_solution, stokes_rhs, preconditioner);
 
-  {
-    const LinearSolvers::InverseMatrix<TrilinosWrappers::SparseMatrix,
-                                       TrilinosWrappers::PreconditionIC>
-      mp_inverse (stokes_preconditioner_matrix.block(1,1), *Mp_preconditioner);
+      stokes_constraints.distribute (stokes_solution);
 
-    const LinearSolvers::BlockSchurPreconditioner<TrilinosWrappers::PreconditionAMG,
-                                                  TrilinosWrappers::PreconditionIC>
-      preconditioner (stokes_matrix, mp_inverse, *Amg_preconditioner);
+      std::cout << "   "
+               << solver_control.last_step()
+               << " GMRES iterations for Stokes subsystem."
+               << std::endl;
+    }
 
-    SolverControl solver_control (stokes_matrix.m(),
-                                 1e-6*stokes_rhs.l2_norm());
+                                    // Once we know the Stokes solution, we can
+                                    // determine the new time step from the
+                                    // maximal velocity. We have to do this to
+                                    // satisfy the CFL condition since
+                                    // convection terms are treated explicitly
+                                    // in the temperature equation, as
+                                    // discussed in the introduction. The exact
+                                    // form of the formula used here for the
+                                    // time step is discussed in the results
+                                    // section of this program.
+                                    //
+                                    // There is a snatch here. The formula
+                                    // contains a division by the maximum value
+                                    // of the velocity. However, at the start
+                                    // of the computation, we have a constant
+                                    // temperature field (we start with a
+                                    // constant temperature, and it will be
+                                    // non-constant only after the first time
+                                    // step during which the source
+                                    // acts). Constant temperature means that
+                                    // no buoyancy acts, and so the velocity is
+                                    // zero. Dividing by it will not likely
+                                    // lead to anything good.
+                                    //
+                                    // To avoid the resulting infinite time
+                                    // step, we ask whether the maximal
+                                    // velocity is very small (in particular
+                                    // smaller than the values we encounter
+                                    // during any of the following time steps)
+                                    // and if so rather than dividing by zero
+                                    // we just divide by a small value,
+                                    // resulting in a large but finite time
+                                    // step.
+    old_time_step = time_step;
+    const double maximal_velocity = get_maximal_velocity();
+
+    if (maximal_velocity >= 0.01)
+      time_step = 1./(1.6*dim*std::sqrt(1.*dim)) /
+                 temperature_degree *
+                 GridTools::minimal_cell_diameter(triangulation) /
+                 maximal_velocity;
+    else
+      time_step = 1./(1.6*dim*std::sqrt(1.*dim)) /
+                 temperature_degree *
+                 GridTools::minimal_cell_diameter(triangulation) /
+                 .01;
+
+    std::cout << "   " << "Time step: " << time_step
+             << std::endl;
 
-    SolverGMRES<TrilinosWrappers::BlockVector>
-      gmres (solver_control,
-            SolverGMRES<TrilinosWrappers::BlockVector >::AdditionalData(100));
+    temperature_solution = old_temperature_solution;
+
+                                    // Next we set up the temperature system
+                                    // and the right hand side using the
+                                    // function
+                                    // <code>assemble_temperature_system()</code>.
+                                    // Knowing the matrix and right hand side
+                                    // of the temperature equation, we set up
+                                    // a preconditioner and a solver. The
+                                    // temperature matrix is a mass matrix
+                                    // (with eigenvalues around one) plus a
+                                    // Laplace matrix (with eigenvalues
+                                    // between zero and $ch^{-2}$) times a
+                                    // small number proportional to the time
+                                    // step $k_n$. Hence, the resulting
+                                    // symmetric and positive definite matrix
+                                    // has eigenvalues in the range
+                                    // $[1,1+k_nh^{-2}]$ (up to
+                                    // constants). This matrix is only
+                                    // moderately ill conditioned even for
+                                    // small mesh sizes and we get a
+                                    // reasonably good preconditioner by
+                                    // simple means, for example with an
+                                    // incomplete Cholesky decomposition
+                                    // preconditioner (IC) as we also use for
+                                    // preconditioning the pressure mass
+                                    // matrix solver. As a solver, we choose
+                                    // the conjugate gradient method CG. As
+                                    // before, we tell the solver to use
+                                    // Trilinos vectors via the template
+                                    // argument
+                                    // <code>TrilinosWrappers::Vector</code>.
+                                    // Finally, we solve, distribute the
+                                    // hanging node constraints and write out
+                                    // the number of iterations.
+    assemble_temperature_system (maximal_velocity);
+    {
 
-    for (unsigned int i=0; i<stokes_solution.size(); ++i)
-      if (stokes_constraints.is_constrained(i))
-       stokes_solution(i) = 0;
+      SolverControl solver_control (temperature_matrix.m(),
+                                   1e-8*temperature_rhs.l2_norm());
+      SolverCG<TrilinosWrappers::Vector> cg (solver_control);
+
+      TrilinosWrappers::PreconditionIC preconditioner;
+      preconditioner.initialize (temperature_matrix);
+
+      cg.solve (temperature_matrix, temperature_solution,
+               temperature_rhs, preconditioner);
+
+      temperature_constraints.distribute (temperature_solution);
+
+      std::cout << "   "
+               << solver_control.last_step()
+               << " CG iterations for temperature."
+               << std::endl;
+
+                                      // At the end of this function, we step
+                                      // through the vector and read out the
+                                      // maximum and minimum temperature value,
+                                      // which we also want to output. This
+                                      // will come in handy when determining
+                                      // the correct constant in the choice of
+                                      // time step as discuss in the results
+                                      // section of this program.
+      double min_temperature = temperature_solution(0),
+            max_temperature = temperature_solution(0);
+      for (unsigned int i=0; i<temperature_solution.size(); ++i)
+       {
+         min_temperature = std::min<double> (min_temperature,
+                                             temperature_solution(i));
+         max_temperature = std::max<double> (max_temperature,
+                                             temperature_solution(i));
+       }
 
-    gmres.solve(stokes_matrix, stokes_solution, stokes_rhs, preconditioner);
+      std::cout << "   Temperature range: "
+               << min_temperature << ' ' << max_temperature
+               << std::endl;
+    }
+  }
 
-    stokes_constraints.distribute (stokes_solution);
 
-    std::cout << "   "
-              << solver_control.last_step()
-              << " GMRES iterations for Stokes subsystem."
-              << std::endl;
-  }
 
-                                  // Once we know the Stokes solution, we can
-                                  // determine the new time step from the
-                                  // maximal velocity. We have to do this to
-                                  // satisfy the CFL condition since
-                                  // convection terms are treated explicitly
-                                  // in the temperature equation, as
-                                  // discussed in the introduction. The exact
-                                  // form of the formula used here for the
-                                  // time step is discussed in the results
-                                  // section of this program.
+                                  // @sect4{BoussinesqFlowProblem::output_results}
                                   //
-                                  // There is a snatch here. The formula
-                                  // contains a division by the maximum value
-                                  // of the velocity. However, at the start
-                                  // of the computation, we have a constant
-                                  // temperature field (we start with a
-                                  // constant temperature, and it will be
-                                  // non-constant only after the first time
-                                  // step during which the source
-                                  // acts). Constant temperature means that
-                                  // no buoyancy acts, and so the velocity is
-                                  // zero. Dividing by it will not likely
-                                  // lead to anything good.
+                                  // This function writes the solution to a VTK
+                                  // output file for visualization, which is
+                                  // done every tenth time step. This is
+                                  // usually quite a simple task, since the
+                                  // deal.II library provides functions that do
+                                  // almost all the job for us. In this case,
+                                  // the situation is a bit more complicated,
+                                  // since we want to visualize both the Stokes
+                                  // solution and the temperature as one data
+                                  // set, but we have done all the calculations
+                                  // based on two different DoFHandler objects,
+                                  // a situation the DataOut class usually used
+                                  // for output is not prepared to deal
+                                  // with. The way we're going to achieve this
+                                  // recombination is to create a joint
+                                  // DoFHandler that collects both components,
+                                  // the Stokes solution and the temperature
+                                  // solution. This can be nicely done by
+                                  // combining the finite elements from the two
+                                  // systems to form one FESystem, and let this
+                                  // collective system define a new DoFHandler
+                                  // object. To be sure that everything was
+                                  // done correctly, we perform a sanity check
+                                  // that ensures that we got all the dofs from
+                                  // both Stokes and temperature even in the
+                                  // combined system.
                                   //
-                                  // To avoid the resulting infinite time
-                                  // step, we ask whether the maximal
-                                  // velocity is very small (in particular
-                                  // smaller than the values we encounter
-                                  // during any of the following time steps)
-                                  // and if so rather than dividing by zero
-                                  // we just divide by a small value,
-                                  // resulting in a large but finite time
-                                  // step.
-  old_time_step = time_step;
-  const double maximal_velocity = get_maximal_velocity();
-
-  if (maximal_velocity >= 0.01)
-    time_step = 1./(1.6*dim*std::sqrt(1.*dim)) /
-               temperature_degree *
-               GridTools::minimal_cell_diameter(triangulation) /
-               maximal_velocity;
-  else
-    time_step = 1./(1.6*dim*std::sqrt(1.*dim)) /
-               temperature_degree *
-               GridTools::minimal_cell_diameter(triangulation) /
-               .01;
-
-  std::cout << "   " << "Time step: " << time_step
-           << std::endl;
-
-  temperature_solution = old_temperature_solution;
-
-                                  // Next we set up the temperature system
-                                  // and the right hand side using the
-                                  // function
-                                  // <code>assemble_temperature_system()</code>.
-                                  // Knowing the matrix and right hand side
-                                  // of the temperature equation, we set up
-                                  // a preconditioner and a solver. The
-                                  // temperature matrix is a mass matrix
-                                  // (with eigenvalues around one) plus a
-                                  // Laplace matrix (with eigenvalues
-                                  // between zero and $ch^{-2}$) times a
-                                  // small number proportional to the time
-                                  // step $k_n$. Hence, the resulting
-                                  // symmetric and positive definite matrix
-                                  // has eigenvalues in the range
-                                  // $[1,1+k_nh^{-2}]$ (up to
-                                  // constants). This matrix is only
-                                  // moderately ill conditioned even for
-                                  // small mesh sizes and we get a
-                                  // reasonably good preconditioner by
-                                  // simple means, for example with an
-                                  // incomplete Cholesky decomposition
-                                  // preconditioner (IC) as we also use for
-                                  // preconditioning the pressure mass
-                                  // matrix solver. As a solver, we choose
-                                  // the conjugate gradient method CG. As
-                                  // before, we tell the solver to use
-                                  // Trilinos vectors via the template
-                                  // argument
-                                  // <code>TrilinosWrappers::Vector</code>.
-                                  // Finally, we solve, distribute the
-                                  // hanging node constraints and write out
-                                  // the number of iterations.
-  assemble_temperature_system (maximal_velocity);
+                                  // Next, we create a vector that will collect
+                                  // the actual solution values. Since this
+                                  // vector is only going to be used for
+                                  // output, we create it as a deal.II vector
+                                  // that nicely cooperate with the data output
+                                  // classes. Remember that we used Trilinos
+                                  // vectors for assembly and solving.
+  template <int dim>
+  void BoussinesqFlowProblem<dim>::output_results ()  const
   {
+    if (timestep_number % 10 != 0)
+      return;
+
+    const FESystem<dim> joint_fe (stokes_fe, 1,
+                                 temperature_fe, 1);
+    DoFHandler<dim> joint_dof_handler (triangulation);
+    joint_dof_handler.distribute_dofs (joint_fe);
+    Assert (joint_dof_handler.n_dofs() ==
+           stokes_dof_handler.n_dofs() + temperature_dof_handler.n_dofs(),
+           ExcInternalError());
+
+    Vector<double> joint_solution (joint_dof_handler.n_dofs());
+
+                                    // Unfortunately, there is no
+                                    // straight-forward relation that tells
+                                    // us how to sort Stokes and temperature
+                                    // vector into the joint vector. The way
+                                    // we can get around this trouble is to
+                                    // rely on the information collected in
+                                    // the FESystem. For each dof in a cell,
+                                    // the joint finite element knows to
+                                    // which equation component (velocity
+                                    // component, pressure, or temperature)
+                                    // it belongs &ndash; that's the
+                                    // information we need!  So we step
+                                    // through all cells (with iterators into
+                                    // all three DoFHandlers moving in
+                                    // synch), and for each joint cell dof,
+                                    // we read out that component using the
+                                    // FiniteElement::system_to_base_index
+                                    // function (see there for a description
+                                    // of what the various parts of its
+                                    // return value contain). We also need to
+                                    // keep track whether we're on a Stokes
+                                    // dof or a temperature dof, which is
+                                    // contained in
+                                    // <code>joint_fe.system_to_base_index(i).first.first</code>.
+                                    // Eventually, the dof_indices data
+                                    // structures on either of the three
+                                    // systems tell us how the relation
+                                    // between global vector and local dofs
+                                    // looks like on the present cell, which
+                                    // concludes this tedious work.
+                                    //
+                                    // There's one thing worth remembering
+                                    // when looking at the output: In our
+                                    // algorithm, we first solve for the
+                                    // Stokes system at time level <i>n-1</i>
+                                    // in each time step and then for the
+                                    // temperature at time level <i>n</i>
+                                    // using the previously computed
+                                    // velocity. These are the two components
+                                    // we join for output, so these two parts
+                                    // of the output file are actually
+                                    // misaligned by one time step. Since we
+                                    // consider graphical output as only a
+                                    // qualititative means to understand a
+                                    // solution, we ignore this
+                                    // $\mathcal{O}(h)$ error.
+    {
+      std::vector<unsigned int> local_joint_dof_indices (joint_fe.dofs_per_cell);
+      std::vector<unsigned int> local_stokes_dof_indices (stokes_fe.dofs_per_cell);
+      std::vector<unsigned int> local_temperature_dof_indices (temperature_fe.dofs_per_cell);
 
-    SolverControl solver_control (temperature_matrix.m(),
-                                 1e-8*temperature_rhs.l2_norm());
-    SolverCG<TrilinosWrappers::Vector> cg (solver_control);
-
-    TrilinosWrappers::PreconditionIC preconditioner;
-    preconditioner.initialize (temperature_matrix);
-
-    cg.solve (temperature_matrix, temperature_solution,
-             temperature_rhs, preconditioner);
-
-    temperature_constraints.distribute (temperature_solution);
-
-    std::cout << "   "
-              << solver_control.last_step()
-              << " CG iterations for temperature."
-              << std::endl;
+      typename DoFHandler<dim>::active_cell_iterator
+       joint_cell       = joint_dof_handler.begin_active(),
+       joint_endc       = joint_dof_handler.end(),
+       stokes_cell      = stokes_dof_handler.begin_active(),
+       temperature_cell = temperature_dof_handler.begin_active();
+      for (; joint_cell!=joint_endc; ++joint_cell, ++stokes_cell, ++temperature_cell)
+       {
+         joint_cell->get_dof_indices (local_joint_dof_indices);
+         stokes_cell->get_dof_indices (local_stokes_dof_indices);
+         temperature_cell->get_dof_indices (local_temperature_dof_indices);
 
-                                    // At the end of this function, we step
-                                    // through the vector and read out the
-                                    // maximum and minimum temperature value,
-                                    // which we also want to output. This
-                                    // will come in handy when determining
-                                    // the correct constant in the choice of
-                                    // time step as discuss in the results
-                                    // section of this program.
-    double min_temperature = temperature_solution(0),
-          max_temperature = temperature_solution(0);
-    for (unsigned int i=0; i<temperature_solution.size(); ++i)
-      {
-       min_temperature = std::min<double> (min_temperature,
-                                           temperature_solution(i));
-       max_temperature = std::max<double> (max_temperature,
-                                           temperature_solution(i));
-      }
+         for (unsigned int i=0; i<joint_fe.dofs_per_cell; ++i)
+           if (joint_fe.system_to_base_index(i).first.first == 0)
+             {
+               Assert (joint_fe.system_to_base_index(i).second
+                       <
+                       local_stokes_dof_indices.size(),
+                       ExcInternalError());
+               joint_solution(local_joint_dof_indices[i])
+                 = stokes_solution(local_stokes_dof_indices[joint_fe.system_to_base_index(i).second]);
+             }
+           else
+             {
+               Assert (joint_fe.system_to_base_index(i).first.first == 1,
+                       ExcInternalError());
+               Assert (joint_fe.system_to_base_index(i).second
+                       <
+                       local_temperature_dof_indices.size(),
+                       ExcInternalError());
+               joint_solution(local_joint_dof_indices[i])
+                 = temperature_solution(local_temperature_dof_indices[joint_fe.system_to_base_index(i).second]);
+             }
+       }
+    }
 
-    std::cout << "   Temperature range: "
-             << min_temperature << ' ' << max_temperature
-             << std::endl;
+                                    // Next, we proceed as we've done in
+                                    // step-22. We create solution names
+                                    // (that are going to appear in the
+                                    // visualization program for the
+                                    // individual components), and attach the
+                                    // joint dof handler to a DataOut
+                                    // object. The first <code>dim</code>
+                                    // components are the vector velocity,
+                                    // and then we have pressure and
+                                    // temperature. This information is read
+                                    // out using the
+                                    // DataComponentInterpretation helper
+                                    // class. Next, we attach the solution
+                                    // values together with the names of its
+                                    // components to the output object, and
+                                    // build patches according to the degree
+                                    // of freedom, which are (sub-) elements
+                                    // that describe the data for
+                                    // visualization programs. Finally, we
+                                    // set a file name (that includes the
+                                    // time step number) and write the vtk
+                                    // file.
+    std::vector<std::string> joint_solution_names (dim, "velocity");
+    joint_solution_names.push_back ("p");
+    joint_solution_names.push_back ("T");
+
+    DataOut<dim> data_out;
+
+    data_out.attach_dof_handler (joint_dof_handler);
+
+    std::vector<DataComponentInterpretation::DataComponentInterpretation>
+      data_component_interpretation
+      (dim+2, DataComponentInterpretation::component_is_scalar);
+    for (unsigned int i=0; i<dim; ++i)
+      data_component_interpretation[i]
+       = DataComponentInterpretation::component_is_part_of_vector;
+
+    data_out.add_data_vector (joint_solution, joint_solution_names,
+                             DataOut<dim>::type_dof_data,
+                             data_component_interpretation);
+    data_out.build_patches (std::min(stokes_degree, temperature_degree));
+
+    std::ostringstream filename;
+    filename << "solution-" << Utilities::int_to_string(timestep_number, 4) << ".vtk";
+
+    std::ofstream output (filename.str().c_str());
+    data_out.write_vtk (output);
   }
-}
 
 
 
-                                // @sect4{BoussinesqFlowProblem::output_results}
-                                //
-                                // This function writes the solution to a VTK
-                                // output file for visualization, which is
-                                // done every tenth time step. This is
-                                // usually quite a simple task, since the
-                                // deal.II library provides functions that do
-                                // almost all the job for us. In this case,
-                                // the situation is a bit more complicated,
-                                // since we want to visualize both the Stokes
-                                // solution and the temperature as one data
-                                // set, but we have done all the calculations
-                                // based on two different DoFHandler objects,
-                                // a situation the DataOut class usually used
-                                // for output is not prepared to deal
-                                // with. The way we're going to achieve this
-                                // recombination is to create a joint
-                                // DoFHandler that collects both components,
-                                // the Stokes solution and the temperature
-                                // solution. This can be nicely done by
-                                // combining the finite elements from the two
-                                // systems to form one FESystem, and let this
-                                // collective system define a new DoFHandler
-                                // object. To be sure that everything was
-                                // done correctly, we perform a sanity check
-                                // that ensures that we got all the dofs from
-                                // both Stokes and temperature even in the
-                                // combined system.
-                                //
-                                // Next, we create a vector that will collect
-                                // the actual solution values. Since this
-                                // vector is only going to be used for
-                                // output, we create it as a deal.II vector
-                                // that nicely cooperate with the data output
-                                // classes. Remember that we used Trilinos
-                                // vectors for assembly and solving.
-template <int dim>
-void BoussinesqFlowProblem<dim>::output_results ()  const
-{
-  if (timestep_number % 10 != 0)
-    return;
-
-  const FESystem<dim> joint_fe (stokes_fe, 1,
-                               temperature_fe, 1);
-  DoFHandler<dim> joint_dof_handler (triangulation);
-  joint_dof_handler.distribute_dofs (joint_fe);
-  Assert (joint_dof_handler.n_dofs() ==
-         stokes_dof_handler.n_dofs() + temperature_dof_handler.n_dofs(),
-         ExcInternalError());
-
-  Vector<double> joint_solution (joint_dof_handler.n_dofs());
-
-                                  // Unfortunately, there is no
-                                  // straight-forward relation that tells
-                                  // us how to sort Stokes and temperature
-                                  // vector into the joint vector. The way
-                                  // we can get around this trouble is to
-                                  // rely on the information collected in
-                                  // the FESystem. For each dof in a cell,
-                                  // the joint finite element knows to
-                                  // which equation component (velocity
-                                  // component, pressure, or temperature)
-                                  // it belongs &ndash; that's the
-                                  // information we need!  So we step
-                                  // through all cells (with iterators into
-                                  // all three DoFHandlers moving in
-                                  // synch), and for each joint cell dof,
-                                  // we read out that component using the
-                                  // FiniteElement::system_to_base_index
-                                  // function (see there for a description
-                                  // of what the various parts of its
-                                  // return value contain). We also need to
-                                  // keep track whether we're on a Stokes
-                                  // dof or a temperature dof, which is
-                                  // contained in
-                                  // <code>joint_fe.system_to_base_index(i).first.first</code>.
-                                  // Eventually, the dof_indices data
-                                  // structures on either of the three
-                                  // systems tell us how the relation
-                                  // between global vector and local dofs
-                                  // looks like on the present cell, which
-                                  // concludes this tedious work.
+                                  // @sect4{BoussinesqFlowProblem::refine_mesh}
+                                  //
+                                  // This function takes care of the adaptive
+                                  // mesh refinement. The three tasks this
+                                  // function performs is to first find out
+                                  // which cells to refine/coarsen, then to
+                                  // actually do the refinement and eventually
+                                  // transfer the solution vectors between the
+                                  // two different grids. The first task is
+                                  // simply achieved by using the
+                                  // well-established Kelly error estimator on
+                                  // the temperature (it is the temperature
+                                  // we're mainly interested in for this
+                                  // program, and we need to be accurate in
+                                  // regions of high temperature gradients,
+                                  // also to not have too much numerical
+                                  // diffusion). The second task is to actually
+                                  // do the remeshing. That involves only basic
+                                  // functions as well, such as the
+                                  // <code>refine_and_coarsen_fixed_fraction</code>
+                                  // that refines those cells with the largest
+                                  // estimated error that together make up 80
+                                  // per cent of the error, and coarsens those
+                                  // cells with the smallest error that make up
+                                  // for a combined 10 per cent of the
+                                  // error.
+                                  //
+                                  // If implemented like this, we would get a
+                                  // program that will not make much progress:
+                                  // Remember that we expect temperature fields
+                                  // that are nearly discontinuous (the
+                                  // diffusivity $\kappa$ is very small after
+                                  // all) and consequently we can expect that a
+                                  // freely adapted mesh will refine further
+                                  // and further into the areas of large
+                                  // gradients. This decrease in mesh size will
+                                  // then be accompanied by a decrease in time
+                                  // step, requiring an exceedingly large
+                                  // number of time steps to solve to a given
+                                  // final time. It will also lead to meshes
+                                  // that are much better at resolving
+                                  // discontinuities after several mesh
+                                  // refinement cycles than in the beginning.
                                   //
-                                  // There's one thing worth remembering
-                                  // when looking at the output: In our
-                                  // algorithm, we first solve for the
-                                  // Stokes system at time level <i>n-1</i>
-                                  // in each time step and then for the
-                                  // temperature at time level <i>n</i>
-                                  // using the previously computed
-                                  // velocity. These are the two components
-                                  // we join for output, so these two parts
-                                  // of the output file are actually
-                                  // misaligned by one time step. Since we
-                                  // consider graphical output as only a
-                                  // qualititative means to understand a
-                                  // solution, we ignore this
-                                  // $\mathcal{O}(h)$ error.
+                                  // In particular to prevent the decrease in
+                                  // time step size and the correspondingly
+                                  // large number of time steps, we limit the
+                                  // maximal refinement depth of the mesh. To
+                                  // this end, after the refinement indicator
+                                  // has been applied to the cells, we simply
+                                  // loop over all cells on the finest level
+                                  // and unselect them from refinement if they
+                                  // would result in too high a mesh level.
+  template <int dim>
+  void BoussinesqFlowProblem<dim>::refine_mesh (const unsigned int max_grid_level)
   {
-    std::vector<unsigned int> local_joint_dof_indices (joint_fe.dofs_per_cell);
-    std::vector<unsigned int> local_stokes_dof_indices (stokes_fe.dofs_per_cell);
-    std::vector<unsigned int> local_temperature_dof_indices (temperature_fe.dofs_per_cell);
-
-    typename DoFHandler<dim>::active_cell_iterator
-      joint_cell       = joint_dof_handler.begin_active(),
-      joint_endc       = joint_dof_handler.end(),
-      stokes_cell      = stokes_dof_handler.begin_active(),
-      temperature_cell = temperature_dof_handler.begin_active();
-    for (; joint_cell!=joint_endc; ++joint_cell, ++stokes_cell, ++temperature_cell)
-      {
-       joint_cell->get_dof_indices (local_joint_dof_indices);
-       stokes_cell->get_dof_indices (local_stokes_dof_indices);
-       temperature_cell->get_dof_indices (local_temperature_dof_indices);
-
-       for (unsigned int i=0; i<joint_fe.dofs_per_cell; ++i)
-         if (joint_fe.system_to_base_index(i).first.first == 0)
-           {
-             Assert (joint_fe.system_to_base_index(i).second
-                     <
-                     local_stokes_dof_indices.size(),
-                     ExcInternalError());
-             joint_solution(local_joint_dof_indices[i])
-               = stokes_solution(local_stokes_dof_indices[joint_fe.system_to_base_index(i).second]);
-           }
-         else
-           {
-             Assert (joint_fe.system_to_base_index(i).first.first == 1,
-                     ExcInternalError());
-             Assert (joint_fe.system_to_base_index(i).second
-                     <
-                     local_temperature_dof_indices.size(),
-                     ExcInternalError());
-             joint_solution(local_joint_dof_indices[i])
-               = temperature_solution(local_temperature_dof_indices[joint_fe.system_to_base_index(i).second]);
-           }
-      }
+    Vector<float> estimated_error_per_cell (triangulation.n_active_cells());
+
+    KellyErrorEstimator<dim>::estimate (temperature_dof_handler,
+                                       QGauss<dim-1>(temperature_degree+1),
+                                       typename FunctionMap<dim>::type(),
+                                       temperature_solution,
+                                       estimated_error_per_cell);
+
+    GridRefinement::refine_and_coarsen_fixed_fraction (triangulation,
+                                                      estimated_error_per_cell,
+                                                      0.8, 0.1);
+    if (triangulation.n_levels() > max_grid_level)
+      for (typename Triangulation<dim>::active_cell_iterator
+            cell = triangulation.begin_active(max_grid_level);
+          cell != triangulation.end(); ++cell)
+       cell->clear_refine_flag ();
+
+                                    // As part of mesh refinement we need to
+                                    // transfer the solution vectors from the
+                                    // old mesh to the new one. To this end
+                                    // we use the SolutionTransfer class and
+                                    // we have to prepare the solution
+                                    // vectors that should be transfered to
+                                    // the new grid (we will lose the old
+                                    // grid once we have done the refinement
+                                    // so the transfer has to happen
+                                    // concurrently with refinement). What we
+                                    // definetely need are the current and
+                                    // the old temperature (BDF-2 time
+                                    // stepping requires two old
+                                    // solutions). Since the SolutionTransfer
+                                    // objects only support to transfer one
+                                    // object per dof handler, we need to
+                                    // collect the two temperature solutions
+                                    // in one data structure. Moreover, we
+                                    // choose to transfer the Stokes
+                                    // solution, too, since we need the
+                                    // velocity at two previous time steps,
+                                    // of which only one is calculated on the
+                                    // fly.
+                                    //
+                                    // Consequently, we initialize two
+                                    // SolutionTransfer objects for the
+                                    // Stokes and temperature DoFHandler
+                                    // objects, by attaching them to the old
+                                    // dof handlers. With this at place, we
+                                    // can prepare the triangulation and the
+                                    // data vectors for refinement (in this
+                                    // order).
+    std::vector<TrilinosWrappers::Vector> x_temperature (2);
+    x_temperature[0] = temperature_solution;
+    x_temperature[1] = old_temperature_solution;
+    TrilinosWrappers::BlockVector x_stokes = stokes_solution;
+
+    SolutionTransfer<dim,TrilinosWrappers::Vector>
+      temperature_trans(temperature_dof_handler);
+    SolutionTransfer<dim,TrilinosWrappers::BlockVector>
+      stokes_trans(stokes_dof_handler);
+
+    triangulation.prepare_coarsening_and_refinement();
+    temperature_trans.prepare_for_coarsening_and_refinement(x_temperature);
+    stokes_trans.prepare_for_coarsening_and_refinement(x_stokes);
+
+                                    // Now everything is ready, so do the
+                                    // refinement and recreate the dof
+                                    // structure on the new grid, and
+                                    // initialize the matrix structures and
+                                    // the new vectors in the
+                                    // <code>setup_dofs</code>
+                                    // function. Next, we actually perform
+                                    // the interpolation of the solutions
+                                    // between the grids. We create another
+                                    // copy of temporary vectors for
+                                    // temperature (now corresponding to the
+                                    // new grid), and let the interpolate
+                                    // function do the job. Then, the
+                                    // resulting array of vectors is written
+                                    // into the respective vector member
+                                    // variables. For the Stokes vector,
+                                    // everything is just the same &ndash;
+                                    // except that we do not need another
+                                    // temporary vector since we just
+                                    // interpolate a single vector. In the
+                                    // end, we have to tell the program that
+                                    // the matrices and preconditioners need
+                                    // to be regenerated, since the mesh has
+                                    // changed.
+    triangulation.execute_coarsening_and_refinement ();
+    setup_dofs ();
+
+    std::vector<TrilinosWrappers::Vector> tmp (2);
+    tmp[0].reinit (temperature_solution);
+    tmp[1].reinit (temperature_solution);
+    temperature_trans.interpolate(x_temperature, tmp);
+
+    temperature_solution = tmp[0];
+    old_temperature_solution = tmp[1];
+
+    stokes_trans.interpolate (x_stokes, stokes_solution);
+
+    rebuild_stokes_matrix         = true;
+    rebuild_temperature_matrices  = true;
+    rebuild_stokes_preconditioner = true;
   }
 
-                                  // Next, we proceed as we've done in
-                                  // step-22. We create solution names
-                                  // (that are going to appear in the
-                                  // visualization program for the
-                                  // individual components), and attach the
-                                  // joint dof handler to a DataOut
-                                  // object. The first <code>dim</code>
-                                  // components are the vector velocity,
-                                  // and then we have pressure and
-                                  // temperature. This information is read
-                                  // out using the
-                                  // DataComponentInterpretation helper
-                                  // class. Next, we attach the solution
-                                  // values together with the names of its
-                                  // components to the output object, and
-                                  // build patches according to the degree
-                                  // of freedom, which are (sub-) elements
-                                  // that describe the data for
-                                  // visualization programs. Finally, we
-                                  // set a file name (that includes the
-                                  // time step number) and write the vtk
-                                  // file.
-  std::vector<std::string> joint_solution_names (dim, "velocity");
-  joint_solution_names.push_back ("p");
-  joint_solution_names.push_back ("T");
-
-  DataOut<dim> data_out;
-
-  data_out.attach_dof_handler (joint_dof_handler);
-
-  std::vector<DataComponentInterpretation::DataComponentInterpretation>
-    data_component_interpretation
-    (dim+2, DataComponentInterpretation::component_is_scalar);
-  for (unsigned int i=0; i<dim; ++i)
-    data_component_interpretation[i]
-      = DataComponentInterpretation::component_is_part_of_vector;
-
-  data_out.add_data_vector (joint_solution, joint_solution_names,
-                           DataOut<dim>::type_dof_data,
-                           data_component_interpretation);
-  data_out.build_patches (std::min(stokes_degree, temperature_degree));
-
-  std::ostringstream filename;
-  filename << "solution-" << Utilities::int_to_string(timestep_number, 4) << ".vtk";
-
-  std::ofstream output (filename.str().c_str());
-  data_out.write_vtk (output);
-}
-
 
 
-                                // @sect4{BoussinesqFlowProblem::refine_mesh}
-                                //
-                                // This function takes care of the adaptive
-                                // mesh refinement. The three tasks this
-                                // function performs is to first find out
-                                // which cells to refine/coarsen, then to
-                                // actually do the refinement and eventually
-                                // transfer the solution vectors between the
-                                // two different grids. The first task is
-                                // simply achieved by using the
-                                // well-established Kelly error estimator on
-                                // the temperature (it is the temperature
-                                // we're mainly interested in for this
-                                // program, and we need to be accurate in
-                                // regions of high temperature gradients,
-                                // also to not have too much numerical
-                                // diffusion). The second task is to actually
-                                // do the remeshing. That involves only basic
-                                // functions as well, such as the
-                                // <code>refine_and_coarsen_fixed_fraction</code>
-                                // that refines those cells with the largest
-                                // estimated error that together make up 80
-                                // per cent of the error, and coarsens those
-                                // cells with the smallest error that make up
-                                // for a combined 10 per cent of the
-                                // error.
-                                //
-                                // If implemented like this, we would get a
-                                // program that will not make much progress:
-                                // Remember that we expect temperature fields
-                                // that are nearly discontinuous (the
-                                // diffusivity $\kappa$ is very small after
-                                // all) and consequently we can expect that a
-                                // freely adapted mesh will refine further
-                                // and further into the areas of large
-                                // gradients. This decrease in mesh size will
-                                // then be accompanied by a decrease in time
-                                // step, requiring an exceedingly large
-                                // number of time steps to solve to a given
-                                // final time. It will also lead to meshes
-                                // that are much better at resolving
-                                // discontinuities after several mesh
-                                // refinement cycles than in the beginning.
-                                //
-                                // In particular to prevent the decrease in
-                                // time step size and the correspondingly
-                                // large number of time steps, we limit the
-                                // maximal refinement depth of the mesh. To
-                                // this end, after the refinement indicator
-                                // has been applied to the cells, we simply
-                                // loop over all cells on the finest level
-                                // and unselect them from refinement if they
-                                // would result in too high a mesh level.
-template <int dim>
-void BoussinesqFlowProblem<dim>::refine_mesh (const unsigned int max_grid_level)
-{
-  Vector<float> estimated_error_per_cell (triangulation.n_active_cells());
-
-  KellyErrorEstimator<dim>::estimate (temperature_dof_handler,
-                                     QGauss<dim-1>(temperature_degree+1),
-                                     typename FunctionMap<dim>::type(),
-                                     temperature_solution,
-                                     estimated_error_per_cell);
-
-  GridRefinement::refine_and_coarsen_fixed_fraction (triangulation,
-                                                    estimated_error_per_cell,
-                                                    0.8, 0.1);
-  if (triangulation.n_levels() > max_grid_level)
-    for (typename Triangulation<dim>::active_cell_iterator
-          cell = triangulation.begin_active(max_grid_level);
-        cell != triangulation.end(); ++cell)
-      cell->clear_refine_flag ();
-
-                                  // As part of mesh refinement we need to
-                                  // transfer the solution vectors from the
-                                  // old mesh to the new one. To this end
-                                  // we use the SolutionTransfer class and
-                                  // we have to prepare the solution
-                                  // vectors that should be transfered to
-                                  // the new grid (we will lose the old
-                                  // grid once we have done the refinement
-                                  // so the transfer has to happen
-                                  // concurrently with refinement). What we
-                                  // definetely need are the current and
-                                  // the old temperature (BDF-2 time
-                                  // stepping requires two old
-                                  // solutions). Since the SolutionTransfer
-                                  // objects only support to transfer one
-                                  // object per dof handler, we need to
-                                  // collect the two temperature solutions
-                                  // in one data structure. Moreover, we
-                                  // choose to transfer the Stokes
-                                  // solution, too, since we need the
-                                  // velocity at two previous time steps,
-                                  // of which only one is calculated on the
-                                  // fly.
+                                  // @sect4{BoussinesqFlowProblem::run}
                                   //
-                                  // Consequently, we initialize two
-                                  // SolutionTransfer objects for the
-                                  // Stokes and temperature DoFHandler
-                                  // objects, by attaching them to the old
-                                  // dof handlers. With this at place, we
-                                  // can prepare the triangulation and the
-                                  // data vectors for refinement (in this
-                                  // order).
-  std::vector<TrilinosWrappers::Vector> x_temperature (2);
-  x_temperature[0] = temperature_solution;
-  x_temperature[1] = old_temperature_solution;
-  TrilinosWrappers::BlockVector x_stokes = stokes_solution;
-
-  SolutionTransfer<dim,TrilinosWrappers::Vector>
-    temperature_trans(temperature_dof_handler);
-  SolutionTransfer<dim,TrilinosWrappers::BlockVector>
-    stokes_trans(stokes_dof_handler);
-
-  triangulation.prepare_coarsening_and_refinement();
-  temperature_trans.prepare_for_coarsening_and_refinement(x_temperature);
-  stokes_trans.prepare_for_coarsening_and_refinement(x_stokes);
-
-                                  // Now everything is ready, so do the
-                                  // refinement and recreate the dof
-                                  // structure on the new grid, and
-                                  // initialize the matrix structures and
-                                  // the new vectors in the
-                                  // <code>setup_dofs</code>
-                                  // function. Next, we actually perform
-                                  // the interpolation of the solutions
-                                  // between the grids. We create another
-                                  // copy of temporary vectors for
-                                  // temperature (now corresponding to the
-                                  // new grid), and let the interpolate
-                                  // function do the job. Then, the
-                                  // resulting array of vectors is written
-                                  // into the respective vector member
-                                  // variables. For the Stokes vector,
-                                  // everything is just the same &ndash;
-                                  // except that we do not need another
-                                  // temporary vector since we just
-                                  // interpolate a single vector. In the
-                                  // end, we have to tell the program that
-                                  // the matrices and preconditioners need
-                                  // to be regenerated, since the mesh has
-                                  // changed.
-  triangulation.execute_coarsening_and_refinement ();
-  setup_dofs ();
-
-  std::vector<TrilinosWrappers::Vector> tmp (2);
-  tmp[0].reinit (temperature_solution);
-  tmp[1].reinit (temperature_solution);
-  temperature_trans.interpolate(x_temperature, tmp);
-
-  temperature_solution = tmp[0];
-  old_temperature_solution = tmp[1];
-
-  stokes_trans.interpolate (x_stokes, stokes_solution);
-
-  rebuild_stokes_matrix         = true;
-  rebuild_temperature_matrices  = true;
-  rebuild_stokes_preconditioner = true;
-}
-
-
-
-                                // @sect4{BoussinesqFlowProblem::run}
-                                //
-                                // This function performs all the
-                                // essential steps in the Boussinesq
-                                // program. It starts by setting up a
-                                // grid (depending on the spatial
-                                // dimension, we choose some
-                                // different level of initial
-                                // refinement and additional adaptive
-                                // refinement steps, and then create
-                                // a cube in <code>dim</code>
-                                // dimensions and set up the dofs for
-                                // the first time. Since we want to
-                                // start the time stepping already
-                                // with an adaptively refined grid,
-                                // we perform some pre-refinement
-                                // steps, consisting of all assembly,
-                                // solution and refinement, but
-                                // without actually advancing in
-                                // time. Rather, we use the vilified
-                                // <code>goto</code> statement to
-                                // jump out of the time loop right
-                                // after mesh refinement to start all
-                                // over again on the new mesh
-                                // beginning at the
-                                // <code>start_time_iteration</code>
-                                // label.
-                                //
-                                // Before we start, we project the
-                                // initial values to the grid and
-                                // obtain the first data for the
-                                // <code>old_temperature_solution</code>
-                                // vector. Then, we initialize time
-                                // step number and time step and
-                                // start the time loop.
-template <int dim>
-void BoussinesqFlowProblem<dim>::run ()
-{
-  const unsigned int initial_refinement = (dim == 2 ? 4 : 2);
-  const unsigned int n_pre_refinement_steps = (dim == 2 ? 4 : 3);
-
+                                  // This function performs all the
+                                  // essential steps in the Boussinesq
+                                  // program. It starts by setting up a
+                                  // grid (depending on the spatial
+                                  // dimension, we choose some
+                                  // different level of initial
+                                  // refinement and additional adaptive
+                                  // refinement steps, and then create
+                                  // a cube in <code>dim</code>
+                                  // dimensions and set up the dofs for
+                                  // the first time. Since we want to
+                                  // start the time stepping already
+                                  // with an adaptively refined grid,
+                                  // we perform some pre-refinement
+                                  // steps, consisting of all assembly,
+                                  // solution and refinement, but
+                                  // without actually advancing in
+                                  // time. Rather, we use the vilified
+                                  // <code>goto</code> statement to
+                                  // jump out of the time loop right
+                                  // after mesh refinement to start all
+                                  // over again on the new mesh
+                                  // beginning at the
+                                  // <code>start_time_iteration</code>
+                                  // label.
+                                  //
+                                  // Before we start, we project the
+                                  // initial values to the grid and
+                                  // obtain the first data for the
+                                  // <code>old_temperature_solution</code>
+                                  // vector. Then, we initialize time
+                                  // step number and time step and
+                                  // start the time loop.
+  template <int dim>
+  void BoussinesqFlowProblem<dim>::run ()
+  {
+    const unsigned int initial_refinement = (dim == 2 ? 4 : 2);
+    const unsigned int n_pre_refinement_steps = (dim == 2 ? 4 : 3);
 
-  GridGenerator::hyper_cube (triangulation);
-  global_Omega_diameter = GridTools::diameter (triangulation);
 
-  triangulation.refine_global (initial_refinement);
+    GridGenerator::hyper_cube (triangulation);
+    global_Omega_diameter = GridTools::diameter (triangulation);
 
-  setup_dofs();
+    triangulation.refine_global (initial_refinement);
 
-  unsigned int pre_refinement_step = 0;
+    setup_dofs();
 
-  start_time_iteration:
+    unsigned int pre_refinement_step = 0;
 
-  VectorTools::project (temperature_dof_handler,
-                       temperature_constraints,
-                       QGauss<dim>(temperature_degree+2),
-                       EquationData::TemperatureInitialValues<dim>(),
-                       old_temperature_solution);
+    start_time_iteration:
 
-  timestep_number           = 0;
-  time_step = old_time_step = 0;
+    VectorTools::project (temperature_dof_handler,
+                         temperature_constraints,
+                         QGauss<dim>(temperature_degree+2),
+                         EquationData::TemperatureInitialValues<dim>(),
+                         old_temperature_solution);
 
-  double time = 0;
+    timestep_number           = 0;
+    time_step = old_time_step = 0;
 
-  do
-    {
-      std::cout << "Timestep " << timestep_number
-               << ":  t=" << time
-                << std::endl;
+    double time = 0;
 
-                                      // The first steps in the time loop
-                                      // are all obvious &ndash; we
-                                      // assemble the Stokes system, the
-                                      // preconditioner, the temperature
-                                      // matrix (matrices and
-                                      // preconditioner do actually only
-                                      // change in case we've remeshed
-                                      // before), and then do the
-                                      // solve. Before going on
-                                      // with the next time step, we have
-                                      // to check whether we should first
-                                      // finish the pre-refinement steps or
-                                      // if we should remesh (every fifth
-                                      // time step), refining up to a level
-                                      // that is consistent with initial
-                                      // refinement and pre-refinement
-                                      // steps. Last in the loop is to
-                                      // advance the solutions, i.e. to
-                                      // copy the solutions to the next
-                                      // "older" time level.
-      assemble_stokes_system ();
-      build_stokes_preconditioner ();
-      assemble_temperature_matrix ();
-
-      solve ();
-
-      output_results ();
-
-      std::cout << std::endl;
-
-      if ((timestep_number == 0) &&
-         (pre_refinement_step < n_pre_refinement_steps))
-       {
-         refine_mesh (initial_refinement + n_pre_refinement_steps);
-         ++pre_refinement_step;
-         goto start_time_iteration;
-       }
-      else
-       if ((timestep_number > 0) && (timestep_number % 5 == 0))
-         refine_mesh (initial_refinement + n_pre_refinement_steps);
+    do
+      {
+       std::cout << "Timestep " << timestep_number
+                 << ":  t=" << time
+                 << std::endl;
+
+                                        // The first steps in the time loop
+                                        // are all obvious &ndash; we
+                                        // assemble the Stokes system, the
+                                        // preconditioner, the temperature
+                                        // matrix (matrices and
+                                        // preconditioner do actually only
+                                        // change in case we've remeshed
+                                        // before), and then do the
+                                        // solve. Before going on
+                                        // with the next time step, we have
+                                        // to check whether we should first
+                                        // finish the pre-refinement steps or
+                                        // if we should remesh (every fifth
+                                        // time step), refining up to a level
+                                        // that is consistent with initial
+                                        // refinement and pre-refinement
+                                        // steps. Last in the loop is to
+                                        // advance the solutions, i.e. to
+                                        // copy the solutions to the next
+                                        // "older" time level.
+       assemble_stokes_system ();
+       build_stokes_preconditioner ();
+       assemble_temperature_matrix ();
+
+       solve ();
+
+       output_results ();
+
+       std::cout << std::endl;
+
+       if ((timestep_number == 0) &&
+           (pre_refinement_step < n_pre_refinement_steps))
+         {
+           refine_mesh (initial_refinement + n_pre_refinement_steps);
+           ++pre_refinement_step;
+           goto start_time_iteration;
+         }
+       else
+         if ((timestep_number > 0) && (timestep_number % 5 == 0))
+           refine_mesh (initial_refinement + n_pre_refinement_steps);
 
-      time += time_step;
-      ++timestep_number;
+       time += time_step;
+       ++timestep_number;
 
-      old_stokes_solution          = stokes_solution;
-      old_old_temperature_solution = old_temperature_solution;
-      old_temperature_solution     = temperature_solution;
-    }
-                                  // Do all the above until we arrive at
-                                  // time 100.
-  while (time <= 100);
+       old_stokes_solution          = stokes_solution;
+       old_old_temperature_solution = old_temperature_solution;
+       old_temperature_solution     = temperature_solution;
+      }
+                                    // Do all the above until we arrive at
+                                    // time 100.
+    while (time <= 100);
+  }
 }
 
 
@@ -2888,6 +2891,9 @@ int main (int argc, char *argv[])
 {
   try
     {
+      using namespace dealii;
+      using namespace Step31;
+
       deallog.depth_console (0);
 
       Utilities::System::MPI_InitFinalize mpi_initialization (argc, argv);
index 2405b6d4066238df255c137226373b9fc5e9a4a5..ceba990a78a9893b5ea48fc235584d50c2bbf18c 100644 (file)
@@ -3,7 +3,7 @@
 
 /*    $Id$       */
 /*                                                                */
-/*    Copyright (C) 2007, 2008, 2009, 2010 by the deal.II authors and David Neckels */
+/*    Copyright (C) 2007, 2008, 2009, 2010, 2011 by the deal.II authors and David Neckels */
 /*                                                                */
 /*    This file is subject to QPL and may not be  distributed     */
 /*    without copyright and license information. Please refer     */
 #include <vector>
 #include <memory>
 
-                                // To end this section, introduce everythin
-                                // in the dealii library into the current
-                                // namespace:
-using namespace dealii;
-
-
-                                // @sect3{Euler equation specifics}
-
-                                // Here we define the flux function for this
-                                // particular system of conservation laws, as
-                                // well as pretty much everything else that's
-                                // specific to the Euler equations for gas
-                                // dynamics, for reasons discussed in the
-                                // introduction. We group all this into a
-                                // structure that defines everything that has
-                                // to do with the flux. All members of this
-                                // structure are static, i.e. the structure
-                                // has no actual state specified by instance
-                                // member variables. The better way to do
-                                // this, rather than a structure with all
-                                // static members would be to use a namespace
-                                // -- but namespaces can't be templatized and
-                                // we want some of the member variables of
-                                // the structure to depend on the space
-                                // dimension, which we in our usual way
-                                // introduce using a template parameter.
-template <int dim>
-struct EulerEquations
+                                // To end this section, introduce everything
+                                // in the dealii library into the namespace
+                                // into which the contents of this program
+                                // will go:
+namespace Step33
 {
-                                    // @sect4{Component description}
-
-                                    // First a few variables that
-                                    // describe the various components of our
-                                    // solution vector in a generic way. This
-                                    // includes the number of components in the
-                                    // system (Euler's equations have one entry
-                                    // for momenta in each spatial direction,
-                                    // plus the energy and density components,
-                                    // for a total of <code>dim+2</code>
-                                    // components), as well as functions that
-                                    // describe the index within the solution
-                                    // vector of the first momentum component,
-                                    // the density component, and the energy
-                                    // density component. Note that all these
-                                    // %numbers depend on the space dimension;
-                                    // defining them in a generic way (rather
-                                    // than by implicit convention) makes our
-                                    // code more flexible and makes it easier
-                                    // to later extend it, for example by
-                                    // adding more components to the equations.
-    static const unsigned int n_components             = dim + 2;
-    static const unsigned int first_momentum_component = 0;
-    static const unsigned int density_component        = dim;
-    static const unsigned int energy_component         = dim+1;
-
-                                    // When generating graphical
-                                    // output way down in this
-                                    // program, we need to specify
-                                    // the names of the solution
-                                    // variables as well as how the
-                                    // various components group into
-                                    // vector and scalar fields. We
-                                    // could describe this there, but
-                                    // in order to keep things that
-                                    // have to do with the Euler
-                                    // equation localized here and
-                                    // the rest of the program as
-                                    // generic as possible, we
-                                    // provide this sort of
-                                    // information in the following
-                                    // two functions:
-    static
-    std::vector<std::string>
-    component_names ()
-      {
-       std::vector<std::string> names (dim, "momentum");
-       names.push_back ("density");
-       names.push_back ("energy_density");
+  using namespace dealii;
+
+
+                                  // @sect3{Euler equation specifics}
+
+                                  // Here we define the flux function for this
+                                  // particular system of conservation laws, as
+                                  // well as pretty much everything else that's
+                                  // specific to the Euler equations for gas
+                                  // dynamics, for reasons discussed in the
+                                  // introduction. We group all this into a
+                                  // structure that defines everything that has
+                                  // to do with the flux. All members of this
+                                  // structure are static, i.e. the structure
+                                  // has no actual state specified by instance
+                                  // member variables. The better way to do
+                                  // this, rather than a structure with all
+                                  // static members would be to use a namespace
+                                  // -- but namespaces can't be templatized and
+                                  // we want some of the member variables of
+                                  // the structure to depend on the space
+                                  // dimension, which we in our usual way
+                                  // introduce using a template parameter.
+  template <int dim>
+  struct EulerEquations
+  {
+                                      // @sect4{Component description}
+
+                                      // First a few variables that
+                                      // describe the various components of our
+                                      // solution vector in a generic way. This
+                                      // includes the number of components in the
+                                      // system (Euler's equations have one entry
+                                      // for momenta in each spatial direction,
+                                      // plus the energy and density components,
+                                      // for a total of <code>dim+2</code>
+                                      // components), as well as functions that
+                                      // describe the index within the solution
+                                      // vector of the first momentum component,
+                                      // the density component, and the energy
+                                      // density component. Note that all these
+                                      // %numbers depend on the space dimension;
+                                      // defining them in a generic way (rather
+                                      // than by implicit convention) makes our
+                                      // code more flexible and makes it easier
+                                      // to later extend it, for example by
+                                      // adding more components to the equations.
+      static const unsigned int n_components             = dim + 2;
+      static const unsigned int first_momentum_component = 0;
+      static const unsigned int density_component        = dim;
+      static const unsigned int energy_component         = dim+1;
+
+                                      // When generating graphical
+                                      // output way down in this
+                                      // program, we need to specify
+                                      // the names of the solution
+                                      // variables as well as how the
+                                      // various components group into
+                                      // vector and scalar fields. We
+                                      // could describe this there, but
+                                      // in order to keep things that
+                                      // have to do with the Euler
+                                      // equation localized here and
+                                      // the rest of the program as
+                                      // generic as possible, we
+                                      // provide this sort of
+                                      // information in the following
+                                      // two functions:
+      static
+      std::vector<std::string>
+      component_names ()
+       {
+         std::vector<std::string> names (dim, "momentum");
+         names.push_back ("density");
+         names.push_back ("energy_density");
 
-       return names;
-      }
+         return names;
+       }
 
 
-    static
-    std::vector<DataComponentInterpretation::DataComponentInterpretation>
-    component_interpretation ()
-      {
-       std::vector<DataComponentInterpretation::DataComponentInterpretation>
+      static
+      std::vector<DataComponentInterpretation::DataComponentInterpretation>
+      component_interpretation ()
+       {
+         std::vector<DataComponentInterpretation::DataComponentInterpretation>
+           data_component_interpretation
+           (dim, DataComponentInterpretation::component_is_part_of_vector);
+         data_component_interpretation
+           .push_back (DataComponentInterpretation::component_is_scalar);
          data_component_interpretation
-         (dim, DataComponentInterpretation::component_is_part_of_vector);
-       data_component_interpretation
-         .push_back (DataComponentInterpretation::component_is_scalar);
-       data_component_interpretation
-         .push_back (DataComponentInterpretation::component_is_scalar);
+           .push_back (DataComponentInterpretation::component_is_scalar);
 
-       return data_component_interpretation;
-      }
+         return data_component_interpretation;
+       }
 
 
-                                    // @sect4{Transformations between variables}
-
-                                    // Next, we define the gas
-                                    // constant. We will set it to 1.4
-                                    // in its definition immediately
-                                    // following the declaration of
-                                    // this class (unlike integer
-                                    // variables, like the ones above,
-                                    // static const floating point
-                                    // member variables cannot be
-                                    // initialized within the class
-                                    // declaration in C++). This value
-                                    // of 1.4 is representative of a
-                                    // gas that consists of molecules
-                                    // composed of two atoms, such as
-                                    // air which consists up to small
-                                    // traces almost entirely of $N_2$
-                                    // and $O_2$.
-    static const double gas_gamma;
-
-
-                                    // In the following, we will need to
-                                    // compute the kinetic energy and the
-                                    // pressure from a vector of conserved
-                                    // variables. This we can do based on the
-                                    // energy density and the kinetic energy
-                                    // $\frac 12 \rho |\mathbf v|^2 =
-                                    // \frac{|\rho \mathbf v|^2}{2\rho}$
-                                    // (note that the independent variables
-                                    // contain the momentum components $\rho
-                                    // v_i$, not the velocities $v_i$).
-                                    //
-                                    // There is one slight problem: We will
-                                    // need to call the following functions
-                                    // with input arguments of type
-                                    // <code>std::vector@<number@></code> and
-                                    // <code>Vector@<number@></code>. The
-                                    // problem is that the former has an
-                                    // access operator
-                                    // <code>operator[]</code> whereas the
-                                    // latter, for historical reasons, has
-                                    // <code>operator()</code>. We wouldn't
-                                    // be able to write the function in a
-                                    // generic way if we were to use one or
-                                    // the other of these. Fortunately, we
-                                    // can use the following trick: instead
-                                    // of writing <code>v[i]</code> or
-                                    // <code>v(i)</code>, we can use
-                                    // <code>*(v.begin() + i)</code>, i.e. we
-                                    // generate an iterator that points to
-                                    // the <code>i</code>th element, and then
-                                    // dereference it. This works for both
-                                    // kinds of vectors -- not the prettiest
-                                    // solution, but one that works.
-    template <typename number, typename InputVector>
-    static
-    number
-    compute_kinetic_energy (const InputVector &W)
-      {
-       number kinetic_energy = 0;
-       for (unsigned int d=0; d<dim; ++d)
-         kinetic_energy += *(W.begin()+first_momentum_component+d) *
-                           *(W.begin()+first_momentum_component+d);
-       kinetic_energy *= 1./(2 * *(W.begin() + density_component));
+                                      // @sect4{Transformations between variables}
+
+                                      // Next, we define the gas
+                                      // constant. We will set it to 1.4
+                                      // in its definition immediately
+                                      // following the declaration of
+                                      // this class (unlike integer
+                                      // variables, like the ones above,
+                                      // static const floating point
+                                      // member variables cannot be
+                                      // initialized within the class
+                                      // declaration in C++). This value
+                                      // of 1.4 is representative of a
+                                      // gas that consists of molecules
+                                      // composed of two atoms, such as
+                                      // air which consists up to small
+                                      // traces almost entirely of $N_2$
+                                      // and $O_2$.
+      static const double gas_gamma;
+
+
+                                      // In the following, we will need to
+                                      // compute the kinetic energy and the
+                                      // pressure from a vector of conserved
+                                      // variables. This we can do based on the
+                                      // energy density and the kinetic energy
+                                      // $\frac 12 \rho |\mathbf v|^2 =
+                                      // \frac{|\rho \mathbf v|^2}{2\rho}$
+                                      // (note that the independent variables
+                                      // contain the momentum components $\rho
+                                      // v_i$, not the velocities $v_i$).
+                                      //
+                                      // There is one slight problem: We will
+                                      // need to call the following functions
+                                      // with input arguments of type
+                                      // <code>std::vector@<number@></code> and
+                                      // <code>Vector@<number@></code>. The
+                                      // problem is that the former has an
+                                      // access operator
+                                      // <code>operator[]</code> whereas the
+                                      // latter, for historical reasons, has
+                                      // <code>operator()</code>. We wouldn't
+                                      // be able to write the function in a
+                                      // generic way if we were to use one or
+                                      // the other of these. Fortunately, we
+                                      // can use the following trick: instead
+                                      // of writing <code>v[i]</code> or
+                                      // <code>v(i)</code>, we can use
+                                      // <code>*(v.begin() + i)</code>, i.e. we
+                                      // generate an iterator that points to
+                                      // the <code>i</code>th element, and then
+                                      // dereference it. This works for both
+                                      // kinds of vectors -- not the prettiest
+                                      // solution, but one that works.
+      template <typename number, typename InputVector>
+      static
+      number
+      compute_kinetic_energy (const InputVector &W)
+       {
+         number kinetic_energy = 0;
+         for (unsigned int d=0; d<dim; ++d)
+           kinetic_energy += *(W.begin()+first_momentum_component+d) *
+                             *(W.begin()+first_momentum_component+d);
+         kinetic_energy *= 1./(2 * *(W.begin() + density_component));
 
-       return kinetic_energy;
-      }
+         return kinetic_energy;
+       }
 
 
-    template <typename number, typename InputVector>
-    static
-    number
-    compute_pressure (const InputVector &W)
-      {
-       return ((gas_gamma-1.0) *
-               (*(W.begin() + energy_component) -
-                compute_kinetic_energy<number>(W)));
-      }
+      template <typename number, typename InputVector>
+      static
+      number
+      compute_pressure (const InputVector &W)
+       {
+         return ((gas_gamma-1.0) *
+                 (*(W.begin() + energy_component) -
+                  compute_kinetic_energy<number>(W)));
+       }
 
 
-                                    // @sect4{EulerEquations::compute_flux_matrix}
-
-                                    // We define the flux function
-                                    // $F(W)$ as one large matrix.
-                                    // Each row of this matrix
-                                    // represents a scalar
-                                    // conservation law for the
-                                    // component in that row.  The
-                                    // exact form of this matrix is
-                                    // given in the
-                                    // introduction. Note that we
-                                    // know the size of the matrix:
-                                    // it has as many rows as the
-                                    // system has components, and
-                                    // <code>dim</code> columns;
-                                    // rather than using a FullMatrix
-                                    // object for such a matrix
-                                    // (which has a variable number
-                                    // of rows and columns and must
-                                    // therefore allocate memory on
-                                    // the heap each time such a
-                                    // matrix is created), we use a
-                                    // rectangular array of numbers
-                                    // right away.
-                                    //
-                                    // We templatize the numerical type of
-                                    // the flux function so that we may use
-                                    // the automatic differentiation type
-                                    // here.  Similarly, we will call the
-                                    // function with different input vector
-                                    // data types, so we templatize on it as
-                                    // well:
-    template <typename InputVector, typename number>
-    static
-    void compute_flux_matrix (const InputVector &W,
-                             number (&flux)[n_components][dim])
-      {
-                                        // First compute the pressure that
-                                        // appears in the flux matrix, and
-                                        // then compute the first
-                                        // <code>dim</code> columns of the
-                                        // matrix that correspond to the
-                                        // momentum terms:
-       const number pressure = compute_pressure<number> (W);
+                                      // @sect4{EulerEquations::compute_flux_matrix}
+
+                                      // We define the flux function
+                                      // $F(W)$ as one large matrix.
+                                      // Each row of this matrix
+                                      // represents a scalar
+                                      // conservation law for the
+                                      // component in that row.  The
+                                      // exact form of this matrix is
+                                      // given in the
+                                      // introduction. Note that we
+                                      // know the size of the matrix:
+                                      // it has as many rows as the
+                                      // system has components, and
+                                      // <code>dim</code> columns;
+                                      // rather than using a FullMatrix
+                                      // object for such a matrix
+                                      // (which has a variable number
+                                      // of rows and columns and must
+                                      // therefore allocate memory on
+                                      // the heap each time such a
+                                      // matrix is created), we use a
+                                      // rectangular array of numbers
+                                      // right away.
+                                      //
+                                      // We templatize the numerical type of
+                                      // the flux function so that we may use
+                                      // the automatic differentiation type
+                                      // here.  Similarly, we will call the
+                                      // function with different input vector
+                                      // data types, so we templatize on it as
+                                      // well:
+      template <typename InputVector, typename number>
+      static
+      void compute_flux_matrix (const InputVector &W,
+                               number (&flux)[n_components][dim])
+       {
+                                          // First compute the pressure that
+                                          // appears in the flux matrix, and
+                                          // then compute the first
+                                          // <code>dim</code> columns of the
+                                          // matrix that correspond to the
+                                          // momentum terms:
+         const number pressure = compute_pressure<number> (W);
+
+         for (unsigned int d=0; d<dim; ++d)
+           {
+             for (unsigned int e=0; e<dim; ++e)
+               flux[first_momentum_component+d][e]
+                 = W[first_momentum_component+d] *
+                 W[first_momentum_component+e] /
+                 W[density_component];
 
-       for (unsigned int d=0; d<dim; ++d)
-         {
-           for (unsigned int e=0; e<dim; ++e)
-             flux[first_momentum_component+d][e]
-               = W[first_momentum_component+d] *
-               W[first_momentum_component+e] /
-               W[density_component];
+             flux[first_momentum_component+d][d] += pressure;
+           }
 
-           flux[first_momentum_component+d][d] += pressure;
-         }
+                                          // Then the terms for the
+                                          // density (i.e. mass
+                                          // conservation), and,
+                                          // lastly, conservation of
+                                          // energy:
+         for (unsigned int d=0; d<dim; ++d)
+           flux[density_component][d] = W[first_momentum_component+d];
+
+         for (unsigned int d=0; d<dim; ++d)
+           flux[energy_component][d] = W[first_momentum_component+d] /
+                                       W[density_component] *
+                                       (W[energy_component] + pressure);
+       }
 
-                                        // Then the terms for the
-                                        // density (i.e. mass
-                                        // conservation), and,
-                                        // lastly, conservation of
-                                        // energy:
-       for (unsigned int d=0; d<dim; ++d)
-         flux[density_component][d] = W[first_momentum_component+d];
 
-       for (unsigned int d=0; d<dim; ++d)
-         flux[energy_component][d] = W[first_momentum_component+d] /
-                                     W[density_component] *
-                                     (W[energy_component] + pressure);
-      }
+                                      // @sect4{EulerEquations::compute_normal_flux}
+
+                                      // On the boundaries of the
+                                      // domain and across hanging
+                                      // nodes we use a numerical flux
+                                      // function to enforce boundary
+                                      // conditions.  This routine is
+                                      // the basic Lax-Friedrich's flux
+                                      // with a stabilization parameter
+                                      // $\alpha$. It's form has also
+                                      // been given already in the
+                                      // introduction:
+      template <typename InputVector>
+      static
+      void numerical_normal_flux (const Point<dim>          &normal,
+                                 const InputVector         &Wplus,
+                                 const InputVector         &Wminus,
+                                 const double               alpha,
+                                 Sacado::Fad::DFad<double> (&normal_flux)[n_components])
+       {
+         Sacado::Fad::DFad<double> iflux[n_components][dim];
+         Sacado::Fad::DFad<double> oflux[n_components][dim];
 
+         compute_flux_matrix (Wplus, iflux);
+         compute_flux_matrix (Wminus, oflux);
 
-                                    // @sect4{EulerEquations::compute_normal_flux}
-
-                                    // On the boundaries of the
-                                    // domain and across hanging
-                                    // nodes we use a numerical flux
-                                    // function to enforce boundary
-                                    // conditions.  This routine is
-                                    // the basic Lax-Friedrich's flux
-                                    // with a stabilization parameter
-                                    // $\alpha$. It's form has also
-                                    // been given already in the
-                                    // introduction:
-    template <typename InputVector>
-    static
-    void numerical_normal_flux (const Point<dim>          &normal,
-                               const InputVector         &Wplus,
-                               const InputVector         &Wminus,
-                               const double               alpha,
-                               Sacado::Fad::DFad<double> (&normal_flux)[n_components])
-      {
-       Sacado::Fad::DFad<double> iflux[n_components][dim];
-       Sacado::Fad::DFad<double> oflux[n_components][dim];
+         for (unsigned int di=0; di<n_components; ++di)
+           {
+             normal_flux[di] = 0;
+             for (unsigned int d=0; d<dim; ++d)
+               normal_flux[di] += 0.5*(iflux[di][d] + oflux[di][d]) * normal[d];
 
-       compute_flux_matrix (Wplus, iflux);
-       compute_flux_matrix (Wminus, oflux);
+             normal_flux[di] += 0.5*alpha*(Wplus[di] - Wminus[di]);
+           }
+       }
 
-       for (unsigned int di=0; di<n_components; ++di)
-         {
-           normal_flux[di] = 0;
-           for (unsigned int d=0; d<dim; ++d)
-             normal_flux[di] += 0.5*(iflux[di][d] + oflux[di][d]) * normal[d];
+                                      // @sect4{EulerEquations::compute_forcing_vector}
+
+                                      // In the same way as describing the flux
+                                      // function $\mathbf F(\mathbf w)$, we
+                                      // also need to have a way to describe
+                                      // the right hand side forcing term. As
+                                      // mentioned in the introduction, we
+                                      // consider only gravity here, which
+                                      // leads to the specific form $\mathbf
+                                      // G(\mathbf w) = \left(
+                                      // g_1\rho, g_2\rho, g_3\rho, 0,
+                                      // \rho \mathbf g \cdot \mathbf v
+                                      // \right)^T$, shown here for
+                                      // the 3d case. More specifically, we
+                                      // will consider only $\mathbf
+                                      // g=(0,0,-1)^T$ in 3d, or $\mathbf
+                                      // g=(0,-1)^T$ in 2d. This naturally
+                                      // leads to the following function:
+      template <typename InputVector, typename number>
+      static
+      void compute_forcing_vector (const InputVector &W,
+                                  number (&forcing)[n_components])
+       {
+         const double gravity = -1.0;
 
-           normal_flux[di] += 0.5*alpha*(Wplus[di] - Wminus[di]);
-         }
-      }
+         for (unsigned int c=0; c<n_components; ++c)
+           switch (c)
+             {
+               case first_momentum_component+dim-1:
+                     forcing[c] = gravity * W[density_component];
+                     break;
+               case energy_component:
+                     forcing[c] = gravity *
+                                  W[density_component] *
+                                  W[first_momentum_component+dim-1];
+                     break;
+               default:
+                     forcing[c] = 0;
+             }
+       }
 
-                                    // @sect4{EulerEquations::compute_forcing_vector}
-
-                                    // In the same way as describing the flux
-                                    // function $\mathbf F(\mathbf w)$, we
-                                    // also need to have a way to describe
-                                    // the right hand side forcing term. As
-                                    // mentioned in the introduction, we
-                                    // consider only gravity here, which
-                                    // leads to the specific form $\mathbf
-                                    // G(\mathbf w) = \left(
-                                    // g_1\rho, g_2\rho, g_3\rho, 0,
-                                    // \rho \mathbf g \cdot \mathbf v
-                                    // \right)^T$, shown here for
-                                    // the 3d case. More specifically, we
-                                    // will consider only $\mathbf
-                                    // g=(0,0,-1)^T$ in 3d, or $\mathbf
-                                    // g=(0,-1)^T$ in 2d. This naturally
-                                    // leads to the following function:
-    template <typename InputVector, typename number>
-    static
-    void compute_forcing_vector (const InputVector &W,
-                                number (&forcing)[n_components])
-      {
-       const double gravity = -1.0;
 
-       for (unsigned int c=0; c<n_components; ++c)
-         switch (c)
-           {
-             case first_momentum_component+dim-1:
-                   forcing[c] = gravity * W[density_component];
-                   break;
-             case energy_component:
-                   forcing[c] = gravity *
-                                W[density_component] *
-                                W[first_momentum_component+dim-1];
-                   break;
-             default:
-                   forcing[c] = 0;
-           }
-      }
+                                      // @sect4{Dealing with boundary conditions}
 
+                                      // Another thing we have to deal with is
+                                      // boundary conditions. To this end, let
+                                      // us first define the kinds of boundary
+                                      // conditions we currently know how to
+                                      // deal with:
+      enum BoundaryKind
+      {
+           inflow_boundary,
+           outflow_boundary,
+           no_penetration_boundary,
+           pressure_boundary
+      };
 
-                                    // @sect4{Dealing with boundary conditions}
 
-                                    // Another thing we have to deal with is
-                                    // boundary conditions. To this end, let
-                                    // us first define the kinds of boundary
-                                    // conditions we currently know how to
-                                    // deal with:
-    enum BoundaryKind
-    {
-         inflow_boundary,
-         outflow_boundary,
-         no_penetration_boundary,
-         pressure_boundary
-    };
+                                      // The next part is to actually decide
+                                      // what to do at each kind of
+                                      // boundary. To this end, remember from
+                                      // the introduction that boundary
+                                      // conditions are specified by choosing a
+                                      // value $\mathbf w^-$ on the outside of
+                                      // a boundary given an inhomogeneity
+                                      // $\mathbf j$ and possibly the
+                                      // solution's value $\mathbf w^+$ on the
+                                      // inside. Both are then passed to the
+                                      // numerical flux $\mathbf
+                                      // H(\mathbf{w}^+, \mathbf{w}^-,
+                                      // \mathbf{n})$ to define boundary
+                                      // contributions to the bilinear form.
+                                      //
+                                      // Boundary conditions can in some cases
+                                      // be specified for each component of the
+                                      // solution vector independently. For
+                                      // example, if component $c$ is marked
+                                      // for inflow, then $w^-_c = j_c$. If it
+                                      // is an outflow, then $w^-_c =
+                                      // w^+_c$. These two simple cases are
+                                      // handled first in the function below.
+                                      //
+                                      // There is a little snag that makes this
+                                      // function unpleasant from a C++
+                                      // language viewpoint: The output vector
+                                      // <code>Wminus</code> will of course be
+                                      // modified, so it shouldn't be a
+                                      // <code>const</code> argument. Yet it is
+                                      // in the implementation below, and needs
+                                      // to be in order to allow the code to
+                                      // compile. The reason is that we call
+                                      // this function at a place where
+                                      // <code>Wminus</code> is of type
+                                      // <code>Table@<2,Sacado::Fad::DFad@<double@>
+                                      // @></code>, this being 2d table with
+                                      // indices representing the quadrature
+                                      // point and the vector component,
+                                      // respectively. We call this function
+                                      // with <code>Wminus[q]</code> as last
+                                      // argument; subscripting a 2d table
+                                      // yields a temporary accessor object
+                                      // representing a 1d vector, just what we
+                                      // want here. The problem is that a
+                                      // temporary accessor object can't be
+                                      // bound to a non-const reference
+                                      // argument of a function, as we would
+                                      // like here, according to the C++ 1998
+                                      // and 2003 standards (something that
+                                      // will be fixed with the next standard
+                                      // in the form of rvalue references).  We
+                                      // get away with making the output
+                                      // argument here a constant because it is
+                                      // the <i>accessor</i> object that's
+                                      // constant, not the table it points to:
+                                      // that one can still be written to. The
+                                      // hack is unpleasant nevertheless
+                                      // because it restricts the kind of data
+                                      // types that may be used as template
+                                      // argument to this function: a regular
+                                      // vector isn't going to do because that
+                                      // one can not be written to when marked
+                                      // <code>const</code>. With no good
+                                      // solution around at the moment, we'll
+                                      // go with the pragmatic, even if not
+                                      // pretty, solution shown here:
+      template <typename DataVector>
+      static
+      void
+      compute_Wminus (const BoundaryKind  (&boundary_kind)[n_components],
+                     const Point<dim>     &normal_vector,
+                     const DataVector     &Wplus,
+                     const Vector<double> &boundary_values,
+                     const DataVector     &Wminus)
+       {
+         for (unsigned int c = 0; c < n_components; c++)
+           switch (boundary_kind[c])
+             {
+               case inflow_boundary:
+               {
+                 Wminus[c] = boundary_values(c);
+                 break;
+               }
 
+               case outflow_boundary:
+               {
+                 Wminus[c] = Wplus[c];
+                 break;
+               }
 
-                                    // The next part is to actually decide
-                                    // what to do at each kind of
-                                    // boundary. To this end, remember from
-                                    // the introduction that boundary
-                                    // conditions are specified by choosing a
-                                    // value $\mathbf w^-$ on the outside of
-                                    // a boundary given an inhomogeneity
-                                    // $\mathbf j$ and possibly the
-                                    // solution's value $\mathbf w^+$ on the
-                                    // inside. Both are then passed to the
-                                    // numerical flux $\mathbf
-                                    // H(\mathbf{w}^+, \mathbf{w}^-,
-                                    // \mathbf{n})$ to define boundary
-                                    // contributions to the bilinear form.
-                                    //
-                                    // Boundary conditions can in some cases
-                                    // be specified for each component of the
-                                    // solution vector independently. For
-                                    // example, if component $c$ is marked
-                                    // for inflow, then $w^-_c = j_c$. If it
-                                    // is an outflow, then $w^-_c =
-                                    // w^+_c$. These two simple cases are
-                                    // handled first in the function below.
-                                    //
-                                    // There is a little snag that makes this
-                                    // function unpleasant from a C++
-                                    // language viewpoint: The output vector
-                                    // <code>Wminus</code> will of course be
-                                    // modified, so it shouldn't be a
-                                    // <code>const</code> argument. Yet it is
-                                    // in the implementation below, and needs
-                                    // to be in order to allow the code to
-                                    // compile. The reason is that we call
-                                    // this function at a place where
-                                    // <code>Wminus</code> is of type
-                                    // <code>Table@<2,Sacado::Fad::DFad@<double@>
-                                    // @></code>, this being 2d table with
-                                    // indices representing the quadrature
-                                    // point and the vector component,
-                                    // respectively. We call this function
-                                    // with <code>Wminus[q]</code> as last
-                                    // argument; subscripting a 2d table
-                                    // yields a temporary accessor object
-                                    // representing a 1d vector, just what we
-                                    // want here. The problem is that a
-                                    // temporary accessor object can't be
-                                    // bound to a non-const reference
-                                    // argument of a function, as we would
-                                    // like here, according to the C++ 1998
-                                    // and 2003 standards (something that
-                                    // will be fixed with the next standard
-                                    // in the form of rvalue references).  We
-                                    // get away with making the output
-                                    // argument here a constant because it is
-                                    // the <i>accessor</i> object that's
-                                    // constant, not the table it points to:
-                                    // that one can still be written to. The
-                                    // hack is unpleasant nevertheless
-                                    // because it restricts the kind of data
-                                    // types that may be used as template
-                                    // argument to this function: a regular
-                                    // vector isn't going to do because that
-                                    // one can not be written to when marked
-                                    // <code>const</code>. With no good
-                                    // solution around at the moment, we'll
-                                    // go with the pragmatic, even if not
-                                    // pretty, solution shown here:
-    template <typename DataVector>
-    static
-    void
-    compute_Wminus (const BoundaryKind  (&boundary_kind)[n_components],
-                   const Point<dim>     &normal_vector,
-                   const DataVector     &Wplus,
-                   const Vector<double> &boundary_values,
-                   const DataVector     &Wminus)
-      {
-       for (unsigned int c = 0; c < n_components; c++)
-         switch (boundary_kind[c])
-           {
-             case inflow_boundary:
-             {
-               Wminus[c] = boundary_values(c);
-               break;
-             }
+                                                // Prescribed pressure boundary
+                                                // conditions are a bit more
+                                                // complicated by the fact that
+                                                // even though the pressure is
+                                                // prescribed, we really are
+                                                // setting the energy component
+                                                // here, which will depend on
+                                                // velocity and pressure. So
+                                                // even though this seems like
+                                                // a Dirichlet type boundary
+                                                // condition, we get
+                                                // sensitivities of energy to
+                                                // velocity and density (unless
+                                                // these are also prescribed):
+               case pressure_boundary:
+               {
+                 const typename DataVector::value_type
+                   density = (boundary_kind[density_component] ==
+                              inflow_boundary
+                              ?
+                              boundary_values(density_component)
+                              :
+                              Wplus[density_component]);
 
-             case outflow_boundary:
-             {
-               Wminus[c] = Wplus[c];
-               break;
-             }
+                 typename DataVector::value_type kinetic_energy = 0;
+                 for (unsigned int d=0; d<dim; ++d)
+                   if (boundary_kind[d] == inflow_boundary)
+                     kinetic_energy += boundary_values(d)*boundary_values(d);
+                   else
+                     kinetic_energy += Wplus[d]*Wplus[d];
+                 kinetic_energy *= 1./2./density;
 
-                                              // Prescribed pressure boundary
-                                              // conditions are a bit more
-                                              // complicated by the fact that
-                                              // even though the pressure is
-                                              // prescribed, we really are
-                                              // setting the energy component
-                                              // here, which will depend on
-                                              // velocity and pressure. So
-                                              // even though this seems like
-                                              // a Dirichlet type boundary
-                                              // condition, we get
-                                              // sensitivities of energy to
-                                              // velocity and density (unless
-                                              // these are also prescribed):
-             case pressure_boundary:
-             {
-               const typename DataVector::value_type
-                 density = (boundary_kind[density_component] ==
-                            inflow_boundary
-                            ?
-                            boundary_values(density_component)
-                            :
-                            Wplus[density_component]);
-
-               typename DataVector::value_type kinetic_energy = 0;
-               for (unsigned int d=0; d<dim; ++d)
-                 if (boundary_kind[d] == inflow_boundary)
-                   kinetic_energy += boundary_values(d)*boundary_values(d);
-                 else
-                   kinetic_energy += Wplus[d]*Wplus[d];
-               kinetic_energy *= 1./2./density;
-
-               Wminus[c] = boundary_values(c) / (gas_gamma-1.0) +
-                           kinetic_energy;
+                 Wminus[c] = boundary_values(c) / (gas_gamma-1.0) +
+                             kinetic_energy;
 
-               break;
-             }
+                 break;
+               }
 
-             case no_penetration_boundary:
-             {
-                                                // We prescribe the
-                                                // velocity (we are dealing with a
-                                                // particular component here so
-                                                // that the average of the
-                                                // velocities is orthogonal to the
-                                                // surface normal.  This creates
-                                                // sensitivies of across the
-                                                // velocity components.
-               Sacado::Fad::DFad<double> vdotn = 0;
-               for (unsigned int d = 0; d < dim; d++) {
-                 vdotn += Wplus[d]*normal_vector[d];
+               case no_penetration_boundary:
+               {
+                                                  // We prescribe the
+                                                  // velocity (we are dealing with a
+                                                  // particular component here so
+                                                  // that the average of the
+                                                  // velocities is orthogonal to the
+                                                  // surface normal.  This creates
+                                                  // sensitivies of across the
+                                                  // velocity components.
+                 Sacado::Fad::DFad<double> vdotn = 0;
+                 for (unsigned int d = 0; d < dim; d++) {
+                   vdotn += Wplus[d]*normal_vector[d];
+                 }
+
+                 Wminus[c] = Wplus[c] - 2.0*vdotn*normal_vector[c];
+                 break;
                }
 
-               Wminus[c] = Wplus[c] - 2.0*vdotn*normal_vector[c];
-               break;
+               default:
+                     Assert (false, ExcNotImplemented());
              }
+       }
+
+
+                                      // @sect4{EulerEquations::compute_refinement_indicators}
+
+                                      // In this class, we also want to specify
+                                      // how to refine the mesh. The class
+                                      // <code>ConservationLaw</code> that will
+                                      // use all the information we provide
+                                      // here in the <code>EulerEquation</code>
+                                      // class is pretty agnostic about the
+                                      // particular conservation law it solves:
+                                      // as doesn't even really care how many
+                                      // components a solution vector
+                                      // has. Consequently, it can't know what
+                                      // a reasonable refinement indicator
+                                      // would be. On the other hand, here we
+                                      // do, or at least we can come up with a
+                                      // reasonable choice: we simply look at
+                                      // the gradient of the density, and
+                                      // compute
+                                      // $\eta_K=\log\left(1+|\nabla\rho(x_K)|\right)$,
+                                      // where $x_K$ is the center of cell $K$.
+                                      //
+                                      // There are certainly a number of
+                                      // equally reasonable refinement
+                                      // indicators, but this one does, and it
+                                      // is easy to compute:
+      static
+      void
+      compute_refinement_indicators (const DoFHandler<dim> &dof_handler,
+                                    const Mapping<dim>    &mapping,
+                                    const Vector<double>  &solution,
+                                    Vector<double>        &refinement_indicators)
+       {
+         const unsigned int dofs_per_cell = dof_handler.get_fe().dofs_per_cell;
+         std::vector<unsigned int> dofs (dofs_per_cell);
 
-             default:
-                   Assert (false, ExcNotImplemented());
+         const QMidpoint<dim>  quadrature_formula;
+         const UpdateFlags update_flags = update_gradients;
+         FEValues<dim> fe_v (mapping, dof_handler.get_fe(),
+                             quadrature_formula, update_flags);
+
+         std::vector<std::vector<Tensor<1,dim> > >
+           dU (1, std::vector<Tensor<1,dim> >(n_components));
+
+         typename DoFHandler<dim>::active_cell_iterator
+           cell = dof_handler.begin_active(),
+           endc = dof_handler.end();
+         for (unsigned int cell_no=0; cell!=endc; ++cell, ++cell_no)
+           {
+             fe_v.reinit(cell);
+             fe_v.get_function_grads (solution, dU);
+
+             refinement_indicators(cell_no)
+               = std::log(1+
+                          std::sqrt(dU[0][density_component] *
+                                    dU[0][density_component]));
            }
-      }
+       }
 
 
-                                    // @sect4{EulerEquations::compute_refinement_indicators}
-
-                                    // In this class, we also want to specify
-                                    // how to refine the mesh. The class
-                                    // <code>ConservationLaw</code> that will
-                                    // use all the information we provide
-                                    // here in the <code>EulerEquation</code>
-                                    // class is pretty agnostic about the
-                                    // particular conservation law it solves:
-                                    // as doesn't even really care how many
-                                    // components a solution vector
-                                    // has. Consequently, it can't know what
-                                    // a reasonable refinement indicator
-                                    // would be. On the other hand, here we
-                                    // do, or at least we can come up with a
-                                    // reasonable choice: we simply look at
-                                    // the gradient of the density, and
-                                    // compute
-                                    // $\eta_K=\log\left(1+|\nabla\rho(x_K)|\right)$,
-                                    // where $x_K$ is the center of cell $K$.
-                                    //
-                                    // There are certainly a number of
-                                    // equally reasonable refinement
-                                    // indicators, but this one does, and it
-                                    // is easy to compute:
-    static
-    void
-    compute_refinement_indicators (const DoFHandler<dim> &dof_handler,
-                                  const Mapping<dim>    &mapping,
-                                  const Vector<double>  &solution,
-                                  Vector<double>        &refinement_indicators)
+
+                                      // @sect4{EulerEquations::Postprocessor}
+
+                                      // Finally, we declare a class that
+                                      // implements a postprocessing of data
+                                      // components. The problem this class
+                                      // solves is that the variables in the
+                                      // formulation of the Euler equations we
+                                      // use are in conservative rather than
+                                      // physical form: they are momentum
+                                      // densities $\mathbf m=\rho\mathbf v$,
+                                      // density $\rho$, and energy density
+                                      // $E$. What we would like to also put
+                                      // into our output file are velocities
+                                      // $\mathbf v=\frac{\mathbf m}{\rho}$ and
+                                      // pressure $p=(\gamma-1)(E-\frac{1}{2}
+                                      // \rho |\mathbf v|^2)$.
+                                      //
+                                      // In addition, we would like to add the
+                                      // possibility to generate schlieren
+                                      // plots. Schlieren plots are a way to
+                                      // visualize shocks and other sharp
+                                      // interfaces. The word "schlieren" is a
+                                      // German word that may be translated as
+                                      // "striae" -- it may be simpler to
+                                      // explain it by an example, however:
+                                      // schlieren is what you see when you,
+                                      // for example, pour highly concentrated
+                                      // alcohol, or a transparent saline
+                                      // solution, into water; the two have the
+                                      // same color, but they have different
+                                      // refractive indices and so before they
+                                      // are fully mixed light goes through the
+                                      // mixture along bent rays that lead to
+                                      // brightness variations if you look at
+                                      // it. That's "schlieren". A similar
+                                      // effect happens in compressible flow
+                                      // because the refractive index
+                                      // depends on the pressure (and therefore
+                                      // the density) of the gas.
+                                      //
+                                      // The origin of the word refers to
+                                      // two-dimensional projections of a
+                                      // three-dimensional volume (we see a 2d
+                                      // picture of the 3d fluid). In
+                                      // computational fluid dynamics, we can
+                                      // get an idea of this effect by
+                                      // considering what causes it: density
+                                      // variations. Schlieren plots are
+                                      // therefore produced by plotting
+                                      // $s=|\nabla \rho|^2$; obviously, $s$ is
+                                      // large in shocks and at other highly
+                                      // dynamic places. If so desired by the
+                                      // user (by specifying this in the input
+                                      // file), we would like to generate these
+                                      // schlieren plots in addition to the
+                                      // other derived quantities listed above.
+                                      //
+                                      // The implementation of the algorithms
+                                      // to compute derived quantities from the
+                                      // ones that solve our problem, and to
+                                      // output them into data file, rests on
+                                      // the DataPostprocessor class. It has
+                                      // extensive documentation, and other
+                                      // uses of the class can also be found in
+                                      // step-29. We therefore refrain from
+                                      // extensive comments.
+      class Postprocessor : public DataPostprocessor<dim>
       {
-       const unsigned int dofs_per_cell = dof_handler.get_fe().dofs_per_cell;
-       std::vector<unsigned int> dofs (dofs_per_cell);
+       public:
+         Postprocessor (const bool do_schlieren_plot);
 
-       const QMidpoint<dim>  quadrature_formula;
-       const UpdateFlags update_flags = update_gradients;
-       FEValues<dim> fe_v (mapping, dof_handler.get_fe(),
-                           quadrature_formula, update_flags);
+         virtual
+         void
+         compute_derived_quantities_vector (const std::vector<Vector<double> >              &uh,
+                                            const std::vector<std::vector<Tensor<1,dim> > > &duh,
+                                            const std::vector<std::vector<Tensor<2,dim> > > &dduh,
+                                            const std::vector<Point<dim> >                  &normals,
+                                            const std::vector<Point<dim> >                  &evaluation_points,
+                                            std::vector<Vector<double> >                    &computed_quantities) const;
 
-       std::vector<std::vector<Tensor<1,dim> > >
-         dU (1, std::vector<Tensor<1,dim> >(n_components));
+         virtual std::vector<std::string> get_names () const;
 
-       typename DoFHandler<dim>::active_cell_iterator
-         cell = dof_handler.begin_active(),
-         endc = dof_handler.end();
-       for (unsigned int cell_no=0; cell!=endc; ++cell, ++cell_no)
-         {
-           fe_v.reinit(cell);
-           fe_v.get_function_grads (solution, dU);
+         virtual
+         std::vector<DataComponentInterpretation::DataComponentInterpretation>
+         get_data_component_interpretation () const;
 
-           refinement_indicators(cell_no)
-             = std::log(1+
-                        std::sqrt(dU[0][density_component] *
-                                  dU[0][density_component]));
-         }
-      }
+         virtual UpdateFlags get_needed_update_flags () const;
 
+         virtual unsigned int n_output_variables() const;
 
+       private:
+         const bool do_schlieren_plot;
+      };
+  };
 
-                                    // @sect4{EulerEquations::Postprocessor}
 
-                                    // Finally, we declare a class that
-                                    // implements a postprocessing of data
-                                    // components. The problem this class
-                                    // solves is that the variables in the
-                                    // formulation of the Euler equations we
-                                    // use are in conservative rather than
-                                    // physical form: they are momentum
-                                    // densities $\mathbf m=\rho\mathbf v$,
-                                    // density $\rho$, and energy density
-                                    // $E$. What we would like to also put
-                                    // into our output file are velocities
-                                    // $\mathbf v=\frac{\mathbf m}{\rho}$ and
-                                    // pressure $p=(\gamma-1)(E-\frac{1}{2}
-                                    // \rho |\mathbf v|^2)$.
-                                    //
-                                    // In addition, we would like to add the
-                                    // possibility to generate schlieren
-                                    // plots. Schlieren plots are a way to
-                                    // visualize shocks and other sharp
-                                    // interfaces. The word "schlieren" is a
-                                    // German word that may be translated as
-                                    // "striae" -- it may be simpler to
-                                    // explain it by an example, however:
-                                    // schlieren is what you see when you,
-                                    // for example, pour highly concentrated
-                                    // alcohol, or a transparent saline
-                                    // solution, into water; the two have the
-                                    // same color, but they have different
-                                    // refractive indices and so before they
-                                    // are fully mixed light goes through the
-                                    // mixture along bent rays that lead to
-                                    // brightness variations if you look at
-                                    // it. That's "schlieren". A similar
-                                    // effect happens in compressible flow
-                                    // because the refractive index
-                                    // depends on the pressure (and therefore
-                                    // the density) of the gas.
-                                    //
-                                    // The origin of the word refers to
-                                    // two-dimensional projections of a
-                                    // three-dimensional volume (we see a 2d
-                                    // picture of the 3d fluid). In
-                                    // computational fluid dynamics, we can
-                                    // get an idea of this effect by
-                                    // considering what causes it: density
-                                    // variations. Schlieren plots are
-                                    // therefore produced by plotting
-                                    // $s=|\nabla \rho|^2$; obviously, $s$ is
-                                    // large in shocks and at other highly
-                                    // dynamic places. If so desired by the
-                                    // user (by specifying this in the input
-                                    // file), we would like to generate these
-                                    // schlieren plots in addition to the
-                                    // other derived quantities listed above.
-                                    //
-                                    // The implementation of the algorithms
-                                    // to compute derived quantities from the
-                                    // ones that solve our problem, and to
-                                    // output them into data file, rests on
-                                    // the DataPostprocessor class. It has
-                                    // extensive documentation, and other
-                                    // uses of the class can also be found in
-                                    // step-29. We therefore refrain from
-                                    // extensive comments.
-    class Postprocessor : public DataPostprocessor<dim>
-    {
-      public:
-       Postprocessor (const bool do_schlieren_plot);
+  template <int dim>
+  const double EulerEquations<dim>::gas_gamma = 1.4;
 
-       virtual
-       void
-       compute_derived_quantities_vector (const std::vector<Vector<double> >              &uh,
-                                          const std::vector<std::vector<Tensor<1,dim> > > &duh,
-                                          const std::vector<std::vector<Tensor<2,dim> > > &dduh,
-                                          const std::vector<Point<dim> >                  &normals,
-                                          const std::vector<Point<dim> >                  &evaluation_points,
-                                          std::vector<Vector<double> >                    &computed_quantities) const;
 
-       virtual std::vector<std::string> get_names () const;
 
-       virtual
-       std::vector<DataComponentInterpretation::DataComponentInterpretation>
-       get_data_component_interpretation () const;
+  template <int dim>
+  EulerEquations<dim>::Postprocessor::
+  Postprocessor (const bool do_schlieren_plot)
+                 :
+                 do_schlieren_plot (do_schlieren_plot)
+  {}
 
-       virtual UpdateFlags get_needed_update_flags () const;
 
-       virtual unsigned int n_output_variables() const;
+                                  // This is the only function worth commenting
+                                  // on. When generating graphical output, the
+                                  // DataOut and related classes will call this
+                                  // function on each cell, with values,
+                                  // gradients, hessians, and normal vectors
+                                  // (in case we're working on faces) at each
+                                  // quadrature point. Note that the data at
+                                  // each quadrature point is itself
+                                  // vector-valued, namely the conserved
+                                  // variables. What we're going to do here is
+                                  // to compute the quantities we're interested
+                                  // in at each quadrature point. Note that for
+                                  // this we can ignore the hessians ("dduh")
+                                  // and normal vectors; to avoid compiler
+                                  // warnings about unused variables, we
+                                  // comment out their names.
+  template <int dim>
+  void
+  EulerEquations<dim>::Postprocessor::
+  compute_derived_quantities_vector (const std::vector<Vector<double> >              &uh,
+                                    const std::vector<std::vector<Tensor<1,dim> > > &duh,
+                                    const std::vector<std::vector<Tensor<2,dim> > > &/*dduh*/,
+                                    const std::vector<Point<dim> >                  &/*normals*/,
+                                    const std::vector<Point<dim> >                  &/*evaluation_points*/,
+                                    std::vector<Vector<double> >                    &computed_quantities) const
+  {
+                                    // At the beginning of the function, let us
+                                    // make sure that all variables have the
+                                    // correct sizes, so that we can access
+                                    // individual vector elements without
+                                    // having to wonder whether we might read
+                                    // or write invalid elements; we also check
+                                    // that the <code>duh</code> vector only
+                                    // contains data if we really need it (the
+                                    // system knows about this because we say
+                                    // so in the
+                                    // <code>get_needed_update_flags()</code>
+                                    // function below). For the inner vectors,
+                                    // we check that at least the first element
+                                    // of the outer vector has the correct
+                                    // inner size:
+    const unsigned int n_quadrature_points = uh.size();
+
+    if (do_schlieren_plot == true)
+      Assert (duh.size() == n_quadrature_points,
+             ExcInternalError())
+      else
+       Assert (duh.size() == 0,
+               ExcInternalError());
 
-      private:
-       const bool do_schlieren_plot;
-    };
-};
-
-
-template <int dim>
-const double EulerEquations<dim>::gas_gamma = 1.4;
-
-
-
-template <int dim>
-EulerEquations<dim>::Postprocessor::
-Postprocessor (const bool do_schlieren_plot)
-               :
-               do_schlieren_plot (do_schlieren_plot)
-{}
-
-
-                                // This is the only function worth commenting
-                                // on. When generating graphical output, the
-                                // DataOut and related classes will call this
-                                // function on each cell, with values,
-                                // gradients, hessians, and normal vectors
-                                // (in case we're working on faces) at each
-                                // quadrature point. Note that the data at
-                                // each quadrature point is itself
-                                // vector-valued, namely the conserved
-                                // variables. What we're going to do here is
-                                // to compute the quantities we're interested
-                                // in at each quadrature point. Note that for
-                                // this we can ignore the hessians ("dduh")
-                                // and normal vectors; to avoid compiler
-                                // warnings about unused variables, we
-                                // comment out their names.
-template <int dim>
-void
-EulerEquations<dim>::Postprocessor::
-compute_derived_quantities_vector (const std::vector<Vector<double> >              &uh,
-                                  const std::vector<std::vector<Tensor<1,dim> > > &duh,
-                                  const std::vector<std::vector<Tensor<2,dim> > > &/*dduh*/,
-                                  const std::vector<Point<dim> >                  &/*normals*/,
-                                  const std::vector<Point<dim> >                  &/*evaluation_points*/,
-                                  std::vector<Vector<double> >                    &computed_quantities) const
-{
-                                  // At the beginning of the function, let us
-                                  // make sure that all variables have the
-                                  // correct sizes, so that we can access
-                                  // individual vector elements without
-                                  // having to wonder whether we might read
-                                  // or write invalid elements; we also check
-                                  // that the <code>duh</code> vector only
-                                  // contains data if we really need it (the
-                                  // system knows about this because we say
-                                  // so in the
-                                  // <code>get_needed_update_flags()</code>
-                                  // function below). For the inner vectors,
-                                  // we check that at least the first element
-                                  // of the outer vector has the correct
-                                  // inner size:
-  const unsigned int n_quadrature_points = uh.size();
-
-  if (do_schlieren_plot == true)
-    Assert (duh.size() == n_quadrature_points,
-           ExcInternalError())
-                       else
-                         Assert (duh.size() == 0,
-                                 ExcInternalError());
-
-  Assert (computed_quantities.size() == n_quadrature_points,
-         ExcInternalError());
-
-  Assert (uh[0].size() == n_components,
-         ExcInternalError());
-
-  if (do_schlieren_plot == true)
-    Assert (computed_quantities[0].size() == dim+2, ExcInternalError())
-  else
-    Assert (computed_quantities[0].size() == dim+1, ExcInternalError());
-
-                                  // Then loop over all quadrature points and
-                                  // do our work there. The code should be
-                                  // pretty self-explanatory. The order of
-                                  // output variables is first
-                                  // <code>dim</code> velocities, then the
-                                  // pressure, and if so desired the
-                                  // schlieren plot. Note that we try to be
-                                  // generic about the order of variables in
-                                  // the input vector, using the
-                                  // <code>first_momentum_component</code>
-                                  // and <code>density_component</code>
-                                  // information:
-  for (unsigned int q=0; q<n_quadrature_points; ++q)
-    {
-      const double density = uh[q](density_component);
+    Assert (computed_quantities.size() == n_quadrature_points,
+           ExcInternalError());
 
-      for (unsigned int d=0; d<dim; ++d)
-       computed_quantities[q](d)
-         = uh[q](first_momentum_component+d) / density;
+    Assert (uh[0].size() == n_components,
+           ExcInternalError());
 
-      computed_quantities[q](dim) = compute_pressure<double> (uh[q]);
+    if (do_schlieren_plot == true)
+      Assert (computed_quantities[0].size() == dim+2, ExcInternalError())
+      else
+       Assert (computed_quantities[0].size() == dim+1, ExcInternalError());
+
+                                    // Then loop over all quadrature points and
+                                    // do our work there. The code should be
+                                    // pretty self-explanatory. The order of
+                                    // output variables is first
+                                    // <code>dim</code> velocities, then the
+                                    // pressure, and if so desired the
+                                    // schlieren plot. Note that we try to be
+                                    // generic about the order of variables in
+                                    // the input vector, using the
+                                    // <code>first_momentum_component</code>
+                                    // and <code>density_component</code>
+                                    // information:
+    for (unsigned int q=0; q<n_quadrature_points; ++q)
+      {
+       const double density = uh[q](density_component);
 
-      if (do_schlieren_plot == true)
-       computed_quantities[q](dim+1) = duh[q][density_component] *
-                                       duh[q][density_component];
-    }
-}
+       for (unsigned int d=0; d<dim; ++d)
+         computed_quantities[q](d)
+           = uh[q](first_momentum_component+d) / density;
 
+       computed_quantities[q](dim) = compute_pressure<double> (uh[q]);
 
-template <int dim>
-std::vector<std::string>
-EulerEquations<dim>::Postprocessor::
-get_names () const
-{
-  std::vector<std::string> names;
-  for (unsigned int d=0; d<dim; ++d)
-    names.push_back ("velocity");
-  names.push_back ("pressure");
+       if (do_schlieren_plot == true)
+         computed_quantities[q](dim+1) = duh[q][density_component] *
+                                         duh[q][density_component];
+      }
+  }
 
-  if (do_schlieren_plot == true)
-    names.push_back ("schlieren_plot");
 
-  return names;
-}
+  template <int dim>
+  std::vector<std::string>
+  EulerEquations<dim>::Postprocessor::
+  get_names () const
+  {
+    std::vector<std::string> names;
+    for (unsigned int d=0; d<dim; ++d)
+      names.push_back ("velocity");
+    names.push_back ("pressure");
 
+    if (do_schlieren_plot == true)
+      names.push_back ("schlieren_plot");
+
+    return names;
+  }
 
-template <int dim>
-std::vector<DataComponentInterpretation::DataComponentInterpretation>
-EulerEquations<dim>::Postprocessor::
-get_data_component_interpretation () const
-{
-  std::vector<DataComponentInterpretation::DataComponentInterpretation>
-    interpretation (dim,
-                   DataComponentInterpretation::component_is_part_of_vector);
 
-  interpretation.push_back (DataComponentInterpretation::
-                           component_is_scalar);
+  template <int dim>
+  std::vector<DataComponentInterpretation::DataComponentInterpretation>
+  EulerEquations<dim>::Postprocessor::
+  get_data_component_interpretation () const
+  {
+    std::vector<DataComponentInterpretation::DataComponentInterpretation>
+      interpretation (dim,
+                     DataComponentInterpretation::component_is_part_of_vector);
 
-  if (do_schlieren_plot == true)
     interpretation.push_back (DataComponentInterpretation::
                              component_is_scalar);
 
-  return interpretation;
-}
+    if (do_schlieren_plot == true)
+      interpretation.push_back (DataComponentInterpretation::
+                               component_is_scalar);
 
+    return interpretation;
+  }
 
 
-template <int dim>
-UpdateFlags
-EulerEquations<dim>::Postprocessor::
-get_needed_update_flags () const
-{
-  if (do_schlieren_plot == true)
-    return update_values | update_gradients;
-  else
-    return update_values;
-}
 
+  template <int dim>
+  UpdateFlags
+  EulerEquations<dim>::Postprocessor::
+  get_needed_update_flags () const
+  {
+    if (do_schlieren_plot == true)
+      return update_values | update_gradients;
+    else
+      return update_values;
+  }
 
 
-template <int dim>
-unsigned int
-EulerEquations<dim>::Postprocessor::
-n_output_variables () const
-{
-  if (do_schlieren_plot == true)
-    return dim+2;
-  else
-    return dim+1;
-}
 
+  template <int dim>
+  unsigned int
+  EulerEquations<dim>::Postprocessor::
+  n_output_variables () const
+  {
+    if (do_schlieren_plot == true)
+      return dim+2;
+    else
+      return dim+1;
+  }
 
-                                // @sect3{Run time parameter handling}
-
-                                // Our next job is to define a few
-                                // classes that will contain run-time
-                                // parameters (for example solver
-                                // tolerances, number of iterations,
-                                // stabilization parameter, and the
-                                // like). One could do this in the
-                                // main class, but we separate it
-                                // from that one to make the program
-                                // more modular and easier to read:
-                                // Everything that has to do with
-                                // run-time parameters will be in the
-                                // following namespace, whereas the
-                                // program logic is in the main
-                                // class.
-                                //
-                                // We will split the run-time
-                                // parameters into a few separate
-                                // structures, which we will all put
-                                // into a namespace
-                                // <code>Parameters</code>. Of these
-                                // classes, there are a few that
-                                // group the parameters for
-                                // individual groups, such as for
-                                // solvers, mesh refinement, or
-                                // output. Each of these classes have
-                                // functions
-                                // <code>declare_parameters()</code>
-                                // and
-                                // <code>parse_parameters()</code>
-                                // that declare parameter subsections
-                                // and entries in a ParameterHandler
-                                // object, and retrieve actual
-                                // parameter values from such an
-                                // object, respectively. These
-                                // classes declare all their
-                                // parameters in subsections of the
-                                // ParameterHandler.
-                                //
-                                // The final class of the following
-                                // namespace combines all the
-                                // previous classes by deriving from
-                                // them and taking care of a few more
-                                // entries at the top level of the
-                                // input file, as well as a few odd
-                                // other entries in subsections that
-                                // are too short to warrent a
-                                // structure by themselves.
-                                //
-                                // It is worth pointing out one thing here:
-                                // None of the classes below have a
-                                // constructor that would initialize the
-                                // various member variables. This isn't a
-                                // problem, however, since we will read all
-                                // variables declared in these classes from
-                                // the input file (or indirectly: a
-                                // ParameterHandler object will read it from
-                                // there, and we will get the values from
-                                // this object), and they will be initialized
-                                // this way. In case a certain variable is
-                                // not specified at all in the input file,
-                                // this isn't a problem either: The
-                                // ParameterHandler class will in this case
-                                // simply take the default value that was
-                                // specified when declaring an entry in the
-                                // <code>declare_parameters()</code>
-                                // functions of the classes below.
-namespace Parameters
-{
 
-                                  // @sect4{Parameters::Solver}
+                                  // @sect3{Run time parameter handling}
+
+                                  // Our next job is to define a few
+                                  // classes that will contain run-time
+                                  // parameters (for example solver
+                                  // tolerances, number of iterations,
+                                  // stabilization parameter, and the
+                                  // like). One could do this in the
+                                  // main class, but we separate it
+                                  // from that one to make the program
+                                  // more modular and easier to read:
+                                  // Everything that has to do with
+                                  // run-time parameters will be in the
+                                  // following namespace, whereas the
+                                  // program logic is in the main
+                                  // class.
                                   //
-                                  // The first of these classes deals
-                                  // with parameters for the linear
-                                  // inner solver. It offers
-                                  // parameters that indicate which
-                                  // solver to use (GMRES as a solver
-                                  // for general non-symmetric
-                                  // indefinite systems, or a sparse
-                                  // direct solver), the amount of
-                                  // output to be produced, as well
-                                  // as various parameters that tweak
-                                  // the thresholded incomplete LU
-                                  // decomposition (ILUT) that we use
-                                  // as a preconditioner for GMRES.
+                                  // We will split the run-time
+                                  // parameters into a few separate
+                                  // structures, which we will all put
+                                  // into a namespace
+                                  // <code>Parameters</code>. Of these
+                                  // classes, there are a few that
+                                  // group the parameters for
+                                  // individual groups, such as for
+                                  // solvers, mesh refinement, or
+                                  // output. Each of these classes have
+                                  // functions
+                                  // <code>declare_parameters()</code>
+                                  // and
+                                  // <code>parse_parameters()</code>
+                                  // that declare parameter subsections
+                                  // and entries in a ParameterHandler
+                                  // object, and retrieve actual
+                                  // parameter values from such an
+                                  // object, respectively. These
+                                  // classes declare all their
+                                  // parameters in subsections of the
+                                  // ParameterHandler.
                                   //
-                                  // In particular, the ILUT takes
-                                  // the following parameters:
-                                  // - ilut_fill: the number of extra
-                                  //   entries to add when forming the ILU
-                                  //   decomposition
-                                  // - ilut_atol, ilut_rtol: When
-                                  //   forming the preconditioner, for
-                                  //   certain problems bad conditioning
-                                  //   (or just bad luck) can cause the
-                                  //   preconditioner to be very poorly
-                                  //   conditioned.  Hence it can help to
-                                  //   add diagonal perturbations to the
-                                  //   original matrix and form the
-                                  //   preconditioner for this slightly
-                                  //   better matrix.  ATOL is an absolute
-                                  //   perturbation that is added to the
-                                  //   diagonal before forming the prec,
-                                  //   and RTOL is a scaling factor $rtol
-                                  //   \geq 1$.
-                                  // - ilut_drop: The ILUT will
-                                  //   drop any values that
-                                  //   have magnitude less than this value.
-                                  //   This is a way to manage the amount
-                                  //   of memory used by this
-                                  //   preconditioner.
+                                  // The final class of the following
+                                  // namespace combines all the
+                                  // previous classes by deriving from
+                                  // them and taking care of a few more
+                                  // entries at the top level of the
+                                  // input file, as well as a few odd
+                                  // other entries in subsections that
+                                  // are too short to warrent a
+                                  // structure by themselves.
                                   //
-                                  // The meaning of each parameter is
-                                  // also briefly described in the
-                                  // third argument of the
-                                  // ParameterHandler::declare_entry
-                                  // call in
-                                  // <code>declare_parameters()</code>.
-  struct Solver
+                                  // It is worth pointing out one thing here:
+                                  // None of the classes below have a
+                                  // constructor that would initialize the
+                                  // various member variables. This isn't a
+                                  // problem, however, since we will read all
+                                  // variables declared in these classes from
+                                  // the input file (or indirectly: a
+                                  // ParameterHandler object will read it from
+                                  // there, and we will get the values from
+                                  // this object), and they will be initialized
+                                  // this way. In case a certain variable is
+                                  // not specified at all in the input file,
+                                  // this isn't a problem either: The
+                                  // ParameterHandler class will in this case
+                                  // simply take the default value that was
+                                  // specified when declaring an entry in the
+                                  // <code>declare_parameters()</code>
+                                  // functions of the classes below.
+  namespace Parameters
   {
-      enum SolverType { gmres, direct };
-      SolverType solver;
 
-      enum  OutputType { quiet, verbose };
-      OutputType output;
+                                    // @sect4{Parameters::Solver}
+                                    //
+                                    // The first of these classes deals
+                                    // with parameters for the linear
+                                    // inner solver. It offers
+                                    // parameters that indicate which
+                                    // solver to use (GMRES as a solver
+                                    // for general non-symmetric
+                                    // indefinite systems, or a sparse
+                                    // direct solver), the amount of
+                                    // output to be produced, as well
+                                    // as various parameters that tweak
+                                    // the thresholded incomplete LU
+                                    // decomposition (ILUT) that we use
+                                    // as a preconditioner for GMRES.
+                                    //
+                                    // In particular, the ILUT takes
+                                    // the following parameters:
+                                    // - ilut_fill: the number of extra
+                                    //   entries to add when forming the ILU
+                                    //   decomposition
+                                    // - ilut_atol, ilut_rtol: When
+                                    //   forming the preconditioner, for
+                                    //   certain problems bad conditioning
+                                    //   (or just bad luck) can cause the
+                                    //   preconditioner to be very poorly
+                                    //   conditioned.  Hence it can help to
+                                    //   add diagonal perturbations to the
+                                    //   original matrix and form the
+                                    //   preconditioner for this slightly
+                                    //   better matrix.  ATOL is an absolute
+                                    //   perturbation that is added to the
+                                    //   diagonal before forming the prec,
+                                    //   and RTOL is a scaling factor $rtol
+                                    //   \geq 1$.
+                                    // - ilut_drop: The ILUT will
+                                    //   drop any values that
+                                    //   have magnitude less than this value.
+                                    //   This is a way to manage the amount
+                                    //   of memory used by this
+                                    //   preconditioner.
+                                    //
+                                    // The meaning of each parameter is
+                                    // also briefly described in the
+                                    // third argument of the
+                                    // ParameterHandler::declare_entry
+                                    // call in
+                                    // <code>declare_parameters()</code>.
+    struct Solver
+    {
+       enum SolverType { gmres, direct };
+       SolverType solver;
+
+       enum  OutputType { quiet, verbose };
+       OutputType output;
 
-      double linear_residual;
-      int max_iterations;
+       double linear_residual;
+       int max_iterations;
 
-      double ilut_fill;
-      double ilut_atol;
-      double ilut_rtol;
-      double ilut_drop;
+       double ilut_fill;
+       double ilut_atol;
+       double ilut_rtol;
+       double ilut_drop;
 
-      static void declare_parameters (ParameterHandler &prm);
-      void parse_parameters (ParameterHandler &prm);
-  };
+       static void declare_parameters (ParameterHandler &prm);
+       void parse_parameters (ParameterHandler &prm);
+    };
 
 
 
-  void Solver::declare_parameters (ParameterHandler &prm)
-  {
-    prm.enter_subsection("linear solver");
+    void Solver::declare_parameters (ParameterHandler &prm)
     {
-      prm.declare_entry("output", "quiet",
-                       Patterns::Selection("quiet|verbose"),
-                       "State whether output from solver runs should be printed. "
-                       "Choices are <quiet|verbose>.");
-      prm.declare_entry("method", "gmres",
-                       Patterns::Selection("gmres|direct"),
-                       "The kind of solver for the linear system. "
-                       "Choices are <gmres|direct>.");
-      prm.declare_entry("residual", "1e-10",
-                       Patterns::Double(),
-                       "Linear solver residual");
-      prm.declare_entry("max iters", "300",
-                       Patterns::Integer(),
-                       "Maximum solver iterations");
-      prm.declare_entry("ilut fill", "2",
-                       Patterns::Double(),
-                       "Ilut preconditioner fill");
-      prm.declare_entry("ilut absolute tolerance", "1e-9",
-                       Patterns::Double(),
-                       "Ilut preconditioner tolerance");
-      prm.declare_entry("ilut relative tolerance", "1.1",
-                       Patterns::Double(),
-                       "Ilut relative tolerance");
-      prm.declare_entry("ilut drop tolerance", "1e-10",
-                       Patterns::Double(),
-                       "Ilut drop tolerance");
+      prm.enter_subsection("linear solver");
+      {
+       prm.declare_entry("output", "quiet",
+                         Patterns::Selection("quiet|verbose"),
+                         "State whether output from solver runs should be printed. "
+                         "Choices are <quiet|verbose>.");
+       prm.declare_entry("method", "gmres",
+                         Patterns::Selection("gmres|direct"),
+                         "The kind of solver for the linear system. "
+                         "Choices are <gmres|direct>.");
+       prm.declare_entry("residual", "1e-10",
+                         Patterns::Double(),
+                         "Linear solver residual");
+       prm.declare_entry("max iters", "300",
+                         Patterns::Integer(),
+                         "Maximum solver iterations");
+       prm.declare_entry("ilut fill", "2",
+                         Patterns::Double(),
+                         "Ilut preconditioner fill");
+       prm.declare_entry("ilut absolute tolerance", "1e-9",
+                         Patterns::Double(),
+                         "Ilut preconditioner tolerance");
+       prm.declare_entry("ilut relative tolerance", "1.1",
+                         Patterns::Double(),
+                         "Ilut relative tolerance");
+       prm.declare_entry("ilut drop tolerance", "1e-10",
+                         Patterns::Double(),
+                         "Ilut drop tolerance");
+      }
+      prm.leave_subsection();
     }
-    prm.leave_subsection();
-  }
 
 
 
 
-  void Solver::parse_parameters (ParameterHandler &prm)
-  {
-    prm.enter_subsection("linear solver");
+    void Solver::parse_parameters (ParameterHandler &prm)
     {
-      const std::string op = prm.get("output");
-      if (op == "verbose")
-       output = verbose;
-      if (op == "quiet")
-       output = quiet;
-
-      const std::string sv = prm.get("method");
-      if (sv == "direct")
-       solver = direct;
-      else if (sv == "gmres")
-       solver = gmres;
-
-      linear_residual = prm.get_double("residual");
-      max_iterations  = prm.get_integer("max iters");
-      ilut_fill       = prm.get_double("ilut fill");
-      ilut_atol       = prm.get_double("ilut absolute tolerance");
-      ilut_rtol       = prm.get_double("ilut relative tolerance");
-      ilut_drop       = prm.get_double("ilut drop tolerance");
+      prm.enter_subsection("linear solver");
+      {
+       const std::string op = prm.get("output");
+       if (op == "verbose")
+         output = verbose;
+       if (op == "quiet")
+         output = quiet;
+
+       const std::string sv = prm.get("method");
+       if (sv == "direct")
+         solver = direct;
+       else if (sv == "gmres")
+         solver = gmres;
+
+       linear_residual = prm.get_double("residual");
+       max_iterations  = prm.get_integer("max iters");
+       ilut_fill       = prm.get_double("ilut fill");
+       ilut_atol       = prm.get_double("ilut absolute tolerance");
+       ilut_rtol       = prm.get_double("ilut relative tolerance");
+       ilut_drop       = prm.get_double("ilut drop tolerance");
+      }
+      prm.leave_subsection();
     }
-    prm.leave_subsection();
-  }
 
 
 
-                                  // @sect4{Parameters::Refinement}
-                                  //
-                                  // Similarly, here are a few parameters
-                                  // that determine how the mesh is to be
-                                  // refined (and if it is to be refined at
-                                  // all). For what exactly the shock
-                                  // parameters do, see the mesh refinement
-                                  // functions further down.
-  struct Refinement
-  {
-      bool do_refine;
-      double shock_val;
-      double shock_levels;
-
-      static void declare_parameters (ParameterHandler &prm);
-      void parse_parameters (ParameterHandler &prm);
-  };
+                                    // @sect4{Parameters::Refinement}
+                                    //
+                                    // Similarly, here are a few parameters
+                                    // that determine how the mesh is to be
+                                    // refined (and if it is to be refined at
+                                    // all). For what exactly the shock
+                                    // parameters do, see the mesh refinement
+                                    // functions further down.
+    struct Refinement
+    {
+       bool do_refine;
+       double shock_val;
+       double shock_levels;
 
+       static void declare_parameters (ParameterHandler &prm);
+       void parse_parameters (ParameterHandler &prm);
+    };
 
 
-  void Refinement::declare_parameters (ParameterHandler &prm)
-  {
 
-    prm.enter_subsection("refinement");
+    void Refinement::declare_parameters (ParameterHandler &prm)
     {
-      prm.declare_entry("refinement", "true",
-                       Patterns::Bool(),
-                       "Whether to perform mesh refinement or not");
-      prm.declare_entry("refinement fraction", "0.1",
-                       Patterns::Double(),
-                       "Fraction of high refinement");
-      prm.declare_entry("unrefinement fraction", "0.1",
-                       Patterns::Double(),
-                       "Fraction of low unrefinement");
-      prm.declare_entry("max elements", "1000000",
-                       Patterns::Double(),
-                       "maximum number of elements");
-      prm.declare_entry("shock value", "4.0",
-                       Patterns::Double(),
-                       "value for shock indicator");
-      prm.declare_entry("shock levels", "3.0",
-                       Patterns::Double(),
-                       "number of shock refinement levels");
+
+      prm.enter_subsection("refinement");
+      {
+       prm.declare_entry("refinement", "true",
+                         Patterns::Bool(),
+                         "Whether to perform mesh refinement or not");
+       prm.declare_entry("refinement fraction", "0.1",
+                         Patterns::Double(),
+                         "Fraction of high refinement");
+       prm.declare_entry("unrefinement fraction", "0.1",
+                         Patterns::Double(),
+                         "Fraction of low unrefinement");
+       prm.declare_entry("max elements", "1000000",
+                         Patterns::Double(),
+                         "maximum number of elements");
+       prm.declare_entry("shock value", "4.0",
+                         Patterns::Double(),
+                         "value for shock indicator");
+       prm.declare_entry("shock levels", "3.0",
+                         Patterns::Double(),
+                         "number of shock refinement levels");
+      }
+      prm.leave_subsection();
     }
-    prm.leave_subsection();
-  }
 
 
-  void Refinement::parse_parameters (ParameterHandler &prm)
-  {
-    prm.enter_subsection("refinement");
+    void Refinement::parse_parameters (ParameterHandler &prm)
     {
-      do_refine     = prm.get_bool ("refinement");
-      shock_val     = prm.get_double("shock value");
-      shock_levels  = prm.get_double("shock levels");
+      prm.enter_subsection("refinement");
+      {
+       do_refine     = prm.get_bool ("refinement");
+       shock_val     = prm.get_double("shock value");
+       shock_levels  = prm.get_double("shock levels");
+      }
+      prm.leave_subsection();
     }
-    prm.leave_subsection();
-  }
 
 
 
-                                  // @sect4{Parameters::Flux}
-                                  //
-                                  // Next a section on flux modifications to
-                                  // make it more stable. In particular, two
-                                  // options are offered to stabilize the
-                                  // Lax-Friedrichs flux: either choose
-                                  // $\mathbf{H}(\mathbf{a},\mathbf{b},\mathbf{n})
-                                  // =
-                                  // \frac{1}{2}(\mathbf{F}(\mathbf{a})\cdot
-                                  // \mathbf{n} + \mathbf{F}(\mathbf{b})\cdot
-                                  // \mathbf{n} + \alpha (\mathbf{a} -
-                                  // \mathbf{b}))$ where $\alpha$ is either a
-                                  // fixed number specified in the input
-                                  // file, or where $\alpha$ is a mesh
-                                  // dependent value. In the latter case, it
-                                  // is chosen as $\frac{h}{2\delta T}$ with
-                                  // $h$ the diameter of the face to which
-                                  // the flux is applied, and $\delta T$
-                                  // the current time step.
-  struct Flux
-  {
-      enum StabilizationKind { constant, mesh_dependent };
-      StabilizationKind stabilization_kind;
+                                    // @sect4{Parameters::Flux}
+                                    //
+                                    // Next a section on flux modifications to
+                                    // make it more stable. In particular, two
+                                    // options are offered to stabilize the
+                                    // Lax-Friedrichs flux: either choose
+                                    // $\mathbf{H}(\mathbf{a},\mathbf{b},\mathbf{n})
+                                    // =
+                                    // \frac{1}{2}(\mathbf{F}(\mathbf{a})\cdot
+                                    // \mathbf{n} + \mathbf{F}(\mathbf{b})\cdot
+                                    // \mathbf{n} + \alpha (\mathbf{a} -
+                                    // \mathbf{b}))$ where $\alpha$ is either a
+                                    // fixed number specified in the input
+                                    // file, or where $\alpha$ is a mesh
+                                    // dependent value. In the latter case, it
+                                    // is chosen as $\frac{h}{2\delta T}$ with
+                                    // $h$ the diameter of the face to which
+                                    // the flux is applied, and $\delta T$
+                                    // the current time step.
+    struct Flux
+    {
+       enum StabilizationKind { constant, mesh_dependent };
+       StabilizationKind stabilization_kind;
 
-      double stabilization_value;
+       double stabilization_value;
 
-      static void declare_parameters (ParameterHandler &prm);
-      void parse_parameters (ParameterHandler &prm);
-  };
+       static void declare_parameters (ParameterHandler &prm);
+       void parse_parameters (ParameterHandler &prm);
+    };
 
 
-  void Flux::declare_parameters (ParameterHandler &prm)
-  {
-    prm.enter_subsection("flux");
+    void Flux::declare_parameters (ParameterHandler &prm)
     {
-      prm.declare_entry("stab", "mesh",
-                       Patterns::Selection("constant|mesh"),
-                       "Whether to use a constant stabilization parameter or "
-                       "a mesh-dependent one");
-      prm.declare_entry("stab value", "1",
-                       Patterns::Double(),
-                       "alpha stabilization");
+      prm.enter_subsection("flux");
+      {
+       prm.declare_entry("stab", "mesh",
+                         Patterns::Selection("constant|mesh"),
+                         "Whether to use a constant stabilization parameter or "
+                         "a mesh-dependent one");
+       prm.declare_entry("stab value", "1",
+                         Patterns::Double(),
+                         "alpha stabilization");
+      }
+      prm.leave_subsection();
     }
-    prm.leave_subsection();
-  }
 
 
-  void Flux::parse_parameters (ParameterHandler &prm)
-  {
-    prm.enter_subsection("flux");
+    void Flux::parse_parameters (ParameterHandler &prm)
     {
-      const std::string stab = prm.get("stab");
-      if (stab == "constant")
-       stabilization_kind = constant;
-      else if (stab == "mesh")
-       stabilization_kind = mesh_dependent;
-      else
-       AssertThrow (false, ExcNotImplemented());
+      prm.enter_subsection("flux");
+      {
+       const std::string stab = prm.get("stab");
+       if (stab == "constant")
+         stabilization_kind = constant;
+       else if (stab == "mesh")
+         stabilization_kind = mesh_dependent;
+       else
+         AssertThrow (false, ExcNotImplemented());
 
-      stabilization_value = prm.get_double("stab value");
+       stabilization_value = prm.get_double("stab value");
+      }
+      prm.leave_subsection();
     }
-    prm.leave_subsection();
-  }
 
 
 
-                                  // @sect4{Parameters::Output}
-                                  //
-                                  // Then a section on output parameters. We
-                                  // offer to produce Schlieren plots (the
-                                  // squared gradient of the density, a tool
-                                  // to visualize shock fronts), and a time
-                                  // interval between graphical output in
-                                  // case we don't want an output file every
-                                  // time step.
-  struct Output
-  {
-      bool schlieren_plot;
-      double output_step;
+                                    // @sect4{Parameters::Output}
+                                    //
+                                    // Then a section on output parameters. We
+                                    // offer to produce Schlieren plots (the
+                                    // squared gradient of the density, a tool
+                                    // to visualize shock fronts), and a time
+                                    // interval between graphical output in
+                                    // case we don't want an output file every
+                                    // time step.
+    struct Output
+    {
+       bool schlieren_plot;
+       double output_step;
 
-      static void declare_parameters (ParameterHandler &prm);
-      void parse_parameters (ParameterHandler &prm);
-  };
+       static void declare_parameters (ParameterHandler &prm);
+       void parse_parameters (ParameterHandler &prm);
+    };
 
 
 
-  void Output::declare_parameters (ParameterHandler &prm)
-  {
-    prm.enter_subsection("output");
+    void Output::declare_parameters (ParameterHandler &prm)
     {
-      prm.declare_entry("schlieren plot", "true",
-                       Patterns::Bool (),
-                       "Whether or not to produce schlieren plots");
-      prm.declare_entry("step", "-1",
-                       Patterns::Double(),
-                       "Output once per this period");
+      prm.enter_subsection("output");
+      {
+       prm.declare_entry("schlieren plot", "true",
+                         Patterns::Bool (),
+                         "Whether or not to produce schlieren plots");
+       prm.declare_entry("step", "-1",
+                         Patterns::Double(),
+                         "Output once per this period");
+      }
+      prm.leave_subsection();
     }
-    prm.leave_subsection();
-  }
 
 
 
-  void Output::parse_parameters (ParameterHandler &prm)
-  {
-    prm.enter_subsection("output");
+    void Output::parse_parameters (ParameterHandler &prm)
     {
-      schlieren_plot = prm.get_bool("schlieren plot");
-      output_step = prm.get_double("step");
+      prm.enter_subsection("output");
+      {
+       schlieren_plot = prm.get_bool("schlieren plot");
+       output_step = prm.get_double("step");
+      }
+      prm.leave_subsection();
     }
-    prm.leave_subsection();
-  }
 
 
 
-                                  // @sect4{Parameters::AllParameters}
-                                  //
-                                  // Finally the class that brings it all
-                                  // together. It declares a number of
-                                  // parameters itself, mostly ones at the
-                                  // top level of the parameter file as well
-                                  // as several in section too small to
-                                  // warrant their own classes. It also
-                                  // contains everything that is actually
-                                  // space dimension dependent, like initial
-                                  // or boundary conditions.
-                                  //
-                                  // Since this class is derived from all the
-                                  // ones above, the
-                                  // <code>declare_parameters()</code> and
-                                  // <code>parse_parameters()</code>
-                                  // functions call the respective functions
-                                  // of the base classes as well.
-                                  //
-                                  // Note that this class also handles the
-                                  // declaration of initial and boundary
-                                  // conditions specified in the input
-                                  // file. To this end, in both cases,
-                                  // there are entries like "w_0 value"
-                                  // which represent an expression in terms
-                                  // of $x,y,z$ that describe the initial
-                                  // or boundary condition as a formula
-                                  // that will later be parsed by the
-                                  // FunctionParser class. Similar
-                                  // expressions exist for "w_1", "w_2",
-                                  // etc, denoting the <code>dim+2</code>
-                                  // conserved variables of the Euler
-                                  // system. Similarly, we allow up to
-                                  // <code>max_n_boundaries</code> boundary
-                                  // indicators to be used in the input
-                                  // file, and each of these boundary
-                                  // indicators can be associated with an
-                                  // inflow, outflow, or pressure boundary
-                                  // condition, with inhomogenous boundary
-                                  // conditions being specified for each
-                                  // component and each boundary indicator
-                                  // separately.
-                                  //
-                                  // The data structure used to store the
-                                  // boundary indicators is a bit
-                                  // complicated. It is an array of
-                                  // <code>max_n_boundaries</code> elements
-                                  // indicating the range of boundary
-                                  // indicators that will be accepted. For
-                                  // each entry in this array, we store a
-                                  // pair of data in the
-                                  // <code>BoundaryCondition</code>
-                                  // structure: first, an array of size
-                                  // <code>n_components</code> that for
-                                  // each component of the solution vector
-                                  // indicates whether it is an inflow,
-                                  // outflow, or other kind of boundary,
-                                  // and second a FunctionParser object
-                                  // that describes all components of the
-                                  // solution vector for this boundary id
-                                  // at once.
-                                  //
-                                  // The <code>BoundaryCondition</code>
-                                  // structure requires a constructor since
-                                  // we need to tell the function parser
-                                  // object at construction time how many
-                                  // vector components it is to
-                                  // describe. This initialization can
-                                  // therefore not wait till we actually
-                                  // set the formulas the FunctionParser
-                                  // object represents later in
-                                  // <code>AllParameters::parse_parameters()</code>
-                                  //
-                                  // For the same reason of having to tell
-                                  // Function objects their vector size at
-                                  // construction time, we have to have a
-                                  // constructor of the
-                                  // <code>AllParameters</code> class that
-                                  // at least initializes the other
-                                  // FunctionParser object, i.e. the one
-                                  // describing initial conditions.
-  template <int dim>
-  struct AllParameters : public Solver,
-                        public Refinement,
-                        public Flux,
-                        public Output
-  {
-      static const unsigned int max_n_boundaries = 10;
+                                    // @sect4{Parameters::AllParameters}
+                                    //
+                                    // Finally the class that brings it all
+                                    // together. It declares a number of
+                                    // parameters itself, mostly ones at the
+                                    // top level of the parameter file as well
+                                    // as several in section too small to
+                                    // warrant their own classes. It also
+                                    // contains everything that is actually
+                                    // space dimension dependent, like initial
+                                    // or boundary conditions.
+                                    //
+                                    // Since this class is derived from all the
+                                    // ones above, the
+                                    // <code>declare_parameters()</code> and
+                                    // <code>parse_parameters()</code>
+                                    // functions call the respective functions
+                                    // of the base classes as well.
+                                    //
+                                    // Note that this class also handles the
+                                    // declaration of initial and boundary
+                                    // conditions specified in the input
+                                    // file. To this end, in both cases,
+                                    // there are entries like "w_0 value"
+                                    // which represent an expression in terms
+                                    // of $x,y,z$ that describe the initial
+                                    // or boundary condition as a formula
+                                    // that will later be parsed by the
+                                    // FunctionParser class. Similar
+                                    // expressions exist for "w_1", "w_2",
+                                    // etc, denoting the <code>dim+2</code>
+                                    // conserved variables of the Euler
+                                    // system. Similarly, we allow up to
+                                    // <code>max_n_boundaries</code> boundary
+                                    // indicators to be used in the input
+                                    // file, and each of these boundary
+                                    // indicators can be associated with an
+                                    // inflow, outflow, or pressure boundary
+                                    // condition, with inhomogenous boundary
+                                    // conditions being specified for each
+                                    // component and each boundary indicator
+                                    // separately.
+                                    //
+                                    // The data structure used to store the
+                                    // boundary indicators is a bit
+                                    // complicated. It is an array of
+                                    // <code>max_n_boundaries</code> elements
+                                    // indicating the range of boundary
+                                    // indicators that will be accepted. For
+                                    // each entry in this array, we store a
+                                    // pair of data in the
+                                    // <code>BoundaryCondition</code>
+                                    // structure: first, an array of size
+                                    // <code>n_components</code> that for
+                                    // each component of the solution vector
+                                    // indicates whether it is an inflow,
+                                    // outflow, or other kind of boundary,
+                                    // and second a FunctionParser object
+                                    // that describes all components of the
+                                    // solution vector for this boundary id
+                                    // at once.
+                                    //
+                                    // The <code>BoundaryCondition</code>
+                                    // structure requires a constructor since
+                                    // we need to tell the function parser
+                                    // object at construction time how many
+                                    // vector components it is to
+                                    // describe. This initialization can
+                                    // therefore not wait till we actually
+                                    // set the formulas the FunctionParser
+                                    // object represents later in
+                                    // <code>AllParameters::parse_parameters()</code>
+                                    //
+                                    // For the same reason of having to tell
+                                    // Function objects their vector size at
+                                    // construction time, we have to have a
+                                    // constructor of the
+                                    // <code>AllParameters</code> class that
+                                    // at least initializes the other
+                                    // FunctionParser object, i.e. the one
+                                    // describing initial conditions.
+    template <int dim>
+    struct AllParameters : public Solver,
+                          public Refinement,
+                          public Flux,
+                          public Output
+    {
+       static const unsigned int max_n_boundaries = 10;
 
-      struct BoundaryConditions
-      {
-         typename EulerEquations<dim>::BoundaryKind
-         kind[EulerEquations<dim>::n_components];
+       struct BoundaryConditions
+       {
+           typename EulerEquations<dim>::BoundaryKind
+           kind[EulerEquations<dim>::n_components];
 
-         FunctionParser<dim> values;
+           FunctionParser<dim> values;
 
-         BoundaryConditions ();
-      };
+           BoundaryConditions ();
+       };
 
 
-      AllParameters ();
+       AllParameters ();
 
-      double diffusion_power;
+       double diffusion_power;
 
-      double time_step, final_time;
-      double theta;
-      bool is_stationary;
+       double time_step, final_time;
+       double theta;
+       bool is_stationary;
 
-      std::string mesh_filename;
+       std::string mesh_filename;
 
-      FunctionParser<dim> initial_conditions;
-      BoundaryConditions  boundary_conditions[max_n_boundaries];
+       FunctionParser<dim> initial_conditions;
+       BoundaryConditions  boundary_conditions[max_n_boundaries];
 
-      static void declare_parameters (ParameterHandler &prm);
-      void parse_parameters (ParameterHandler &prm);
-  };
+       static void declare_parameters (ParameterHandler &prm);
+       void parse_parameters (ParameterHandler &prm);
+    };
 
 
 
-  template <int dim>
-  AllParameters<dim>::BoundaryConditions::BoundaryConditions ()
-                 :
-                 values (EulerEquations<dim>::n_components)
-  {}
+    template <int dim>
+    AllParameters<dim>::BoundaryConditions::BoundaryConditions ()
+                   :
+                   values (EulerEquations<dim>::n_components)
+    {}
 
 
-  template <int dim>
-  AllParameters<dim>::AllParameters ()
-                 :
-                 initial_conditions (EulerEquations<dim>::n_components)
-  {}
+    template <int dim>
+    AllParameters<dim>::AllParameters ()
+                   :
+                   initial_conditions (EulerEquations<dim>::n_components)
+    {}
 
 
-  template <int dim>
-  void
-  AllParameters<dim>::declare_parameters (ParameterHandler &prm)
-  {
-    prm.declare_entry("mesh", "grid.inp",
-                     Patterns::Anything(),
-                     "intput file name");
-
-    prm.declare_entry("diffusion power", "2.0",
-                     Patterns::Double(),
-                     "power of mesh size for diffusion");
-
-    prm.enter_subsection("time stepping");
+    template <int dim>
+    void
+    AllParameters<dim>::declare_parameters (ParameterHandler &prm)
     {
-      prm.declare_entry("time step", "0.1",
-                       Patterns::Double(0),
-                       "simulation time step");
-      prm.declare_entry("final time", "10.0",
-                       Patterns::Double(0),
-                       "simulation end time");
-      prm.declare_entry("theta scheme value", "0.5",
-                       Patterns::Double(0,1),
-                       "value for theta that interpolated between explicit "
-                       "Euler (theta=0), Crank-Nicolson (theta=0.5), and "
-                       "implicit Euler (theta=1).");
-    }
-    prm.leave_subsection();
+      prm.declare_entry("mesh", "grid.inp",
+                       Patterns::Anything(),
+                       "intput file name");
 
+      prm.declare_entry("diffusion power", "2.0",
+                       Patterns::Double(),
+                       "power of mesh size for diffusion");
 
-    for (unsigned int b=0; b<max_n_boundaries; ++b)
+      prm.enter_subsection("time stepping");
       {
-       prm.enter_subsection("boundary_" +
-                            Utilities::int_to_string(b));
+       prm.declare_entry("time step", "0.1",
+                         Patterns::Double(0),
+                         "simulation time step");
+       prm.declare_entry("final time", "10.0",
+                         Patterns::Double(0),
+                         "simulation end time");
+       prm.declare_entry("theta scheme value", "0.5",
+                         Patterns::Double(0,1),
+                         "value for theta that interpolated between explicit "
+                         "Euler (theta=0), Crank-Nicolson (theta=0.5), and "
+                         "implicit Euler (theta=1).");
+      }
+      prm.leave_subsection();
+
+
+      for (unsigned int b=0; b<max_n_boundaries; ++b)
        {
-         prm.declare_entry("no penetration", "false",
-                           Patterns::Bool(),
-                           "whether the named boundary allows gas to "
-                           "penetrate or is a rigid wall");
+         prm.enter_subsection("boundary_" +
+                              Utilities::int_to_string(b));
+         {
+           prm.declare_entry("no penetration", "false",
+                             Patterns::Bool(),
+                             "whether the named boundary allows gas to "
+                             "penetrate or is a rigid wall");
 
-         for (unsigned int di=0; di<EulerEquations<dim>::n_components; ++di)
-           {
-             prm.declare_entry("w_" + Utilities::int_to_string(di),
-                               "outflow",
-                               Patterns::Selection("inflow|outflow|pressure"),
-                               "<inflow|outflow|pressure>");
-
-             prm.declare_entry("w_" + Utilities::int_to_string(di) +
-                               " value", "0.0",
-                               Patterns::Anything(),
-                               "expression in x,y,z");
-           }
+           for (unsigned int di=0; di<EulerEquations<dim>::n_components; ++di)
+             {
+               prm.declare_entry("w_" + Utilities::int_to_string(di),
+                                 "outflow",
+                                 Patterns::Selection("inflow|outflow|pressure"),
+                                 "<inflow|outflow|pressure>");
+
+               prm.declare_entry("w_" + Utilities::int_to_string(di) +
+                                 " value", "0.0",
+                                 Patterns::Anything(),
+                                 "expression in x,y,z");
+             }
+         }
+         prm.leave_subsection();
        }
-       prm.leave_subsection();
+
+      prm.enter_subsection("initial condition");
+      {
+       for (unsigned int di=0; di<EulerEquations<dim>::n_components; ++di)
+         prm.declare_entry("w_" + Utilities::int_to_string(di) + " value",
+                           "0.0",
+                           Patterns::Anything(),
+                           "expression in x,y,z");
       }
+      prm.leave_subsection();
 
-    prm.enter_subsection("initial condition");
-    {
-      for (unsigned int di=0; di<EulerEquations<dim>::n_components; ++di)
-       prm.declare_entry("w_" + Utilities::int_to_string(di) + " value",
-                         "0.0",
-                         Patterns::Anything(),
-                         "expression in x,y,z");
+      Parameters::Solver::declare_parameters (prm);
+      Parameters::Refinement::declare_parameters (prm);
+      Parameters::Flux::declare_parameters (prm);
+      Parameters::Output::declare_parameters (prm);
     }
-    prm.leave_subsection();
-
-    Parameters::Solver::declare_parameters (prm);
-    Parameters::Refinement::declare_parameters (prm);
-    Parameters::Flux::declare_parameters (prm);
-    Parameters::Output::declare_parameters (prm);
-  }
 
 
-  template <int dim>
-  void
-  AllParameters<dim>::parse_parameters (ParameterHandler &prm)
-  {
-    mesh_filename = prm.get("mesh");
-    diffusion_power = prm.get_double("diffusion power");
-
-    prm.enter_subsection("time stepping");
+    template <int dim>
+    void
+    AllParameters<dim>::parse_parameters (ParameterHandler &prm)
     {
-      time_step = prm.get_double("time step");
-      if (time_step == 0)
-       {
-         is_stationary = true;
-         time_step = 1.0;
-         final_time = 1.0;
-       }
-      else
-       is_stationary = false;
-
-      final_time = prm.get_double("final time");
-      theta = prm.get_double("theta scheme value");
-    }
-    prm.leave_subsection();
+      mesh_filename = prm.get("mesh");
+      diffusion_power = prm.get_double("diffusion power");
 
-    for (unsigned int boundary_id=0; boundary_id<max_n_boundaries;
-        ++boundary_id)
+      prm.enter_subsection("time stepping");
       {
-       prm.enter_subsection("boundary_" +
-                            Utilities::int_to_string(boundary_id));
+       time_step = prm.get_double("time step");
+       if (time_step == 0)
+         {
+           is_stationary = true;
+           time_step = 1.0;
+           final_time = 1.0;
+         }
+       else
+         is_stationary = false;
+
+       final_time = prm.get_double("final time");
+       theta = prm.get_double("theta scheme value");
+      }
+      prm.leave_subsection();
+
+      for (unsigned int boundary_id=0; boundary_id<max_n_boundaries;
+          ++boundary_id)
        {
-         std::vector<std::string>
-           expressions(EulerEquations<dim>::n_components, "0.0");
+         prm.enter_subsection("boundary_" +
+                              Utilities::int_to_string(boundary_id));
+         {
+           std::vector<std::string>
+             expressions(EulerEquations<dim>::n_components, "0.0");
 
-         const bool no_penetration = prm.get_bool("no penetration");
+           const bool no_penetration = prm.get_bool("no penetration");
 
-         for (unsigned int di=0; di<EulerEquations<dim>::n_components; ++di)
-           {
-             const std::string boundary_type
-               = prm.get("w_" + Utilities::int_to_string(di));
-
-             if ((di < dim) && (no_penetration == true))
-               boundary_conditions[boundary_id].kind[di]
-                 = EulerEquations<dim>::no_penetration_boundary;
-             else if (boundary_type == "inflow")
-               boundary_conditions[boundary_id].kind[di]
-                 = EulerEquations<dim>::inflow_boundary;
-             else if (boundary_type == "pressure")
-               boundary_conditions[boundary_id].kind[di]
-                 = EulerEquations<dim>::pressure_boundary;
-             else if (boundary_type == "outflow")
-               boundary_conditions[boundary_id].kind[di]
-                 = EulerEquations<dim>::outflow_boundary;
-             else
-               AssertThrow (false, ExcNotImplemented());
-
-             expressions[di] = prm.get("w_" + Utilities::int_to_string(di) +
-                                       " value");
-           }
+           for (unsigned int di=0; di<EulerEquations<dim>::n_components; ++di)
+             {
+               const std::string boundary_type
+                 = prm.get("w_" + Utilities::int_to_string(di));
+
+               if ((di < dim) && (no_penetration == true))
+                 boundary_conditions[boundary_id].kind[di]
+                   = EulerEquations<dim>::no_penetration_boundary;
+               else if (boundary_type == "inflow")
+                 boundary_conditions[boundary_id].kind[di]
+                   = EulerEquations<dim>::inflow_boundary;
+               else if (boundary_type == "pressure")
+                 boundary_conditions[boundary_id].kind[di]
+                   = EulerEquations<dim>::pressure_boundary;
+               else if (boundary_type == "outflow")
+                 boundary_conditions[boundary_id].kind[di]
+                   = EulerEquations<dim>::outflow_boundary;
+               else
+                 AssertThrow (false, ExcNotImplemented());
+
+               expressions[di] = prm.get("w_" + Utilities::int_to_string(di) +
+                                         " value");
+             }
 
-         boundary_conditions[boundary_id].values
-           .initialize (FunctionParser<dim>::default_variable_names(),
-                        expressions,
-                        std::map<std::string, double>());
+           boundary_conditions[boundary_id].values
+             .initialize (FunctionParser<dim>::default_variable_names(),
+                          expressions,
+                          std::map<std::string, double>());
+         }
+         prm.leave_subsection();
        }
-       prm.leave_subsection();
+
+      prm.enter_subsection("initial condition");
+      {
+       std::vector<std::string> expressions (EulerEquations<dim>::n_components,
+                                             "0.0");
+       for (unsigned int di = 0; di < EulerEquations<dim>::n_components; di++)
+         expressions[di] = prm.get("w_" + Utilities::int_to_string(di) +
+                                   " value");
+       initial_conditions.initialize (FunctionParser<dim>::default_variable_names(),
+                                      expressions,
+                                      std::map<std::string, double>());
       }
+      prm.leave_subsection();
 
-    prm.enter_subsection("initial condition");
-    {
-      std::vector<std::string> expressions (EulerEquations<dim>::n_components,
-                                           "0.0");
-      for (unsigned int di = 0; di < EulerEquations<dim>::n_components; di++)
-       expressions[di] = prm.get("w_" + Utilities::int_to_string(di) +
-                                 " value");
-      initial_conditions.initialize (FunctionParser<dim>::default_variable_names(),
-                                    expressions,
-                                    std::map<std::string, double>());
+      Parameters::Solver::parse_parameters (prm);
+      Parameters::Refinement::parse_parameters (prm);
+      Parameters::Flux::parse_parameters (prm);
+      Parameters::Output::parse_parameters (prm);
     }
-    prm.leave_subsection();
-
-    Parameters::Solver::parse_parameters (prm);
-    Parameters::Refinement::parse_parameters (prm);
-    Parameters::Flux::parse_parameters (prm);
-    Parameters::Output::parse_parameters (prm);
   }
-}
-
-
 
 
-                                // @sect3{Conservation law class}
-
-                                // Here finally comes the class that
-                                // actually does something with all
-                                // the Euler equation and parameter
-                                // specifics we've defined above. The
-                                // public interface is pretty much
-                                // the same as always (the
-                                // constructor now takes the name of
-                                // a file from which to read
-                                // parameters, which is passed on the
-                                // command line). The private
-                                // function interface is also pretty
-                                // similar to the usual arrangement,
-                                // with the
-                                // <code>assemble_system</code>
-                                // function split into three parts:
-                                // one that contains the main loop
-                                // over all cells and that then calls
-                                // the other two for integrals over
-                                // cells and faces, respectively.
-template <int dim>
-class ConservationLaw
-{
-  public:
-    ConservationLaw (const char *input_filename);
-    void run ();
-
-  private:
-    void setup_system ();
-
-    void assemble_system ();
-    void assemble_cell_term (const FEValues<dim>             &fe_v,
-                            const std::vector<unsigned int> &dofs);
-    void assemble_face_term (const unsigned int               face_no,
-                            const FEFaceValuesBase<dim>     &fe_v,
-                            const FEFaceValuesBase<dim>     &fe_v_neighbor,
-                            const std::vector<unsigned int> &dofs,
-                            const std::vector<unsigned int> &dofs_neighbor,
-                            const bool                       external_face,
-                            const unsigned int               boundary_id,
-                            const double                     face_diameter);
-
-    std::pair<unsigned int, double> solve (Vector<double> &solution);
-
-    void compute_refinement_indicators (Vector<double> &indicator) const;
-    void refine_grid (const Vector<double> &indicator);
-
-    void output_results () const;
-
-
-
-                                    // The first few member variables
-                                    // are also rather standard. Note
-                                    // that we define a mapping
-                                    // object to be used throughout
-                                    // the program when assembling
-                                    // terms (we will hand it to
-                                    // every FEValues and
-                                    // FEFaceValues object); the
-                                    // mapping we use is just the
-                                    // standard $Q_1$ mapping --
-                                    // nothing fancy, in other words
-                                    // -- but declaring one here and
-                                    // using it throughout the
-                                    // program will make it simpler
-                                    // later on to change it if that
-                                    // should become necessary. This
-                                    // is, in fact, rather pertinent:
-                                    // it is known that for
-                                    // transsonic simulations with
-                                    // the Euler equations,
-                                    // computations do not converge
-                                    // even as $h\rightarrow 0$ if
-                                    // the boundary approximation is
-                                    // not of sufficiently high
-                                    // order.
-    Triangulation<dim>   triangulation;
-    const MappingQ1<dim> mapping;
-
-    const FESystem<dim>  fe;
-    DoFHandler<dim>      dof_handler;
-
-    const QGauss<dim>    quadrature;
-    const QGauss<dim-1>  face_quadrature;
-
-                                     // Next come a number of data
-                                     // vectors that correspond to the
-                                     // solution of the previous time
-                                     // step
-                                     // (<code>old_solution</code>),
-                                     // the best guess of the current
-                                     // solution
-                                     // (<code>current_solution</code>;
-                                     // we say <i>guess</i> because
-                                     // the Newton iteration to
-                                     // compute it may not have
-                                     // converged yet, whereas
-                                     // <code>old_solution</code>
-                                     // refers to the fully converged
-                                     // final result of the previous
-                                     // time step), and a predictor
-                                     // for the solution at the next
-                                     // time step, computed by
-                                     // extrapolating the current and
-                                     // previous solution one time
-                                     // step into the future:
-    Vector<double>       old_solution;
-    Vector<double>       current_solution;
-    Vector<double>       predictor;
-
-    Vector<double>       right_hand_side;
-
-                                    // This final set of member variables
-                                    // (except for the object holding all
-                                    // run-time parameters at the very
-                                    // bottom and a screen output stream
-                                    // that only prints something if
-                                    // verbose output has been requested)
-                                    // deals with the inteface we have in
-                                    // this program to the Trilinos library
-                                    // that provides us with linear
-                                    // solvers. Similarly to including
-                                    // PETSc matrices in step-17,
-                                    // step-18, and step-19, all we
-                                    // need to do is to create a Trilinos
-                                    // sparse matrix instead of the
-                                    // standard deal.II class. The system
-                                    // matrix is used for the Jacobian in
-                                    // each Newton step. Since we do not
-                                    // intend to run this program in
-                                    // parallel (which wouldn't be too hard
-                                    // with Trilinos data structures,
-                                    // though), we don't have to think
-                                    // about anything else like
-                                    // distributing the degrees of freedom.
-    TrilinosWrappers::SparseMatrix system_matrix;
-
-    Parameters::AllParameters<dim>  parameters;
-    ConditionalOStream              verbose_cout;
-};
-
-
-                                // @sect4{ConservationLaw::ConservationLaw}
-                                //
-                                // There is nothing much to say about
-                                // the constructor. Essentially, it
-                                // reads the input file and fills the
-                                // parameter object with the parsed
-                                // values:
-template <int dim>
-ConservationLaw<dim>::ConservationLaw (const char *input_filename)
-               :
-               mapping (),
-                fe (FE_Q<dim>(1), EulerEquations<dim>::n_components),
-               dof_handler (triangulation),
-               quadrature (2),
-               face_quadrature (2),
-               verbose_cout (std::cout, false)
-{
-  ParameterHandler prm;
-  Parameters::AllParameters<dim>::declare_parameters (prm);
 
-  prm.read_input (input_filename);
-  parameters.parse_parameters (prm);
-
-  verbose_cout.set_condition (parameters.output == Parameters::Solver::verbose);
-}
 
+                                  // @sect3{Conservation law class}
+
+                                  // Here finally comes the class that
+                                  // actually does something with all
+                                  // the Euler equation and parameter
+                                  // specifics we've defined above. The
+                                  // public interface is pretty much
+                                  // the same as always (the
+                                  // constructor now takes the name of
+                                  // a file from which to read
+                                  // parameters, which is passed on the
+                                  // command line). The private
+                                  // function interface is also pretty
+                                  // similar to the usual arrangement,
+                                  // with the
+                                  // <code>assemble_system</code>
+                                  // function split into three parts:
+                                  // one that contains the main loop
+                                  // over all cells and that then calls
+                                  // the other two for integrals over
+                                  // cells and faces, respectively.
+  template <int dim>
+  class ConservationLaw
+  {
+    public:
+      ConservationLaw (const char *input_filename);
+      void run ();
+
+    private:
+      void setup_system ();
+
+      void assemble_system ();
+      void assemble_cell_term (const FEValues<dim>             &fe_v,
+                              const std::vector<unsigned int> &dofs);
+      void assemble_face_term (const unsigned int               face_no,
+                              const FEFaceValuesBase<dim>     &fe_v,
+                              const FEFaceValuesBase<dim>     &fe_v_neighbor,
+                              const std::vector<unsigned int> &dofs,
+                              const std::vector<unsigned int> &dofs_neighbor,
+                              const bool                       external_face,
+                              const unsigned int               boundary_id,
+                              const double                     face_diameter);
+
+      std::pair<unsigned int, double> solve (Vector<double> &solution);
+
+      void compute_refinement_indicators (Vector<double> &indicator) const;
+      void refine_grid (const Vector<double> &indicator);
+
+      void output_results () const;
+
+
+
+                                      // The first few member variables
+                                      // are also rather standard. Note
+                                      // that we define a mapping
+                                      // object to be used throughout
+                                      // the program when assembling
+                                      // terms (we will hand it to
+                                      // every FEValues and
+                                      // FEFaceValues object); the
+                                      // mapping we use is just the
+                                      // standard $Q_1$ mapping --
+                                      // nothing fancy, in other words
+                                      // -- but declaring one here and
+                                      // using it throughout the
+                                      // program will make it simpler
+                                      // later on to change it if that
+                                      // should become necessary. This
+                                      // is, in fact, rather pertinent:
+                                      // it is known that for
+                                      // transsonic simulations with
+                                      // the Euler equations,
+                                      // computations do not converge
+                                      // even as $h\rightarrow 0$ if
+                                      // the boundary approximation is
+                                      // not of sufficiently high
+                                      // order.
+      Triangulation<dim>   triangulation;
+      const MappingQ1<dim> mapping;
+
+      const FESystem<dim>  fe;
+      DoFHandler<dim>      dof_handler;
+
+      const QGauss<dim>    quadrature;
+      const QGauss<dim-1>  face_quadrature;
+
+                                      // Next come a number of data
+                                      // vectors that correspond to the
+                                      // solution of the previous time
+                                      // step
+                                      // (<code>old_solution</code>),
+                                      // the best guess of the current
+                                      // solution
+                                      // (<code>current_solution</code>;
+                                      // we say <i>guess</i> because
+                                      // the Newton iteration to
+                                      // compute it may not have
+                                      // converged yet, whereas
+                                      // <code>old_solution</code>
+                                      // refers to the fully converged
+                                      // final result of the previous
+                                      // time step), and a predictor
+                                      // for the solution at the next
+                                      // time step, computed by
+                                      // extrapolating the current and
+                                      // previous solution one time
+                                      // step into the future:
+      Vector<double>       old_solution;
+      Vector<double>       current_solution;
+      Vector<double>       predictor;
+
+      Vector<double>       right_hand_side;
+
+                                      // This final set of member variables
+                                      // (except for the object holding all
+                                      // run-time parameters at the very
+                                      // bottom and a screen output stream
+                                      // that only prints something if
+                                      // verbose output has been requested)
+                                      // deals with the inteface we have in
+                                      // this program to the Trilinos library
+                                      // that provides us with linear
+                                      // solvers. Similarly to including
+                                      // PETSc matrices in step-17,
+                                      // step-18, and step-19, all we
+                                      // need to do is to create a Trilinos
+                                      // sparse matrix instead of the
+                                      // standard deal.II class. The system
+                                      // matrix is used for the Jacobian in
+                                      // each Newton step. Since we do not
+                                      // intend to run this program in
+                                      // parallel (which wouldn't be too hard
+                                      // with Trilinos data structures,
+                                      // though), we don't have to think
+                                      // about anything else like
+                                      // distributing the degrees of freedom.
+      TrilinosWrappers::SparseMatrix system_matrix;
+
+      Parameters::AllParameters<dim>  parameters;
+      ConditionalOStream              verbose_cout;
+  };
 
 
-                                // @sect4{ConservationLaw::setup_system}
-                                //
-                                // The following (easy) function is called
-                                // each time the mesh is changed. All it
-                                // does is to resize the Trilinos matrix
-                                // according to a sparsity pattern that we
-                                // generate as in all the previous tutorial
-                                // programs.
-template <int dim>
-void ConservationLaw<dim>::setup_system ()
-{
-  CompressedSparsityPattern sparsity_pattern (dof_handler.n_dofs(),
-                                             dof_handler.n_dofs());
-  DoFTools::make_sparsity_pattern (dof_handler, sparsity_pattern);
+                                  // @sect4{ConservationLaw::ConservationLaw}
+                                  //
+                                  // There is nothing much to say about
+                                  // the constructor. Essentially, it
+                                  // reads the input file and fills the
+                                  // parameter object with the parsed
+                                  // values:
+  template <int dim>
+  ConservationLaw<dim>::ConservationLaw (const char *input_filename)
+                 :
+                 mapping (),
+                 fe (FE_Q<dim>(1), EulerEquations<dim>::n_components),
+                 dof_handler (triangulation),
+                 quadrature (2),
+                 face_quadrature (2),
+                 verbose_cout (std::cout, false)
+  {
+    ParameterHandler prm;
+    Parameters::AllParameters<dim>::declare_parameters (prm);
 
-  system_matrix.reinit (sparsity_pattern);
-}
+    prm.read_input (input_filename);
+    parameters.parse_parameters (prm);
 
+    verbose_cout.set_condition (parameters.output == Parameters::Solver::verbose);
+  }
 
-                                // @sect4{ConservationLaw::assemble_system}
-                                //
-                                 // This and the following two
-                                 // functions are the meat of this
-                                 // program: They assemble the linear
-                                 // system that results from applying
-                                 // Newton's method to the nonlinear
-                                 // system of conservation
-                                 // equations.
-                                //
-                                // This first function puts all of
-                                 // the assembly pieces together in a
-                                 // routine that dispatches the
-                                 // correct piece for each cell/face.
-                                 // The actual implementation of the
-                                 // assembly on these objects is done
-                                 // in the following functions.
-                                //
-                                // At the top of the function we do the
-                                // usual housekeeping: allocate FEValues,
-                                // FEFaceValues, and FESubfaceValues
-                                // objects necessary to do the integrations
-                                // on cells, faces, and subfaces (in case
-                                // of adjoining cells on different
-                                // refinement levels). Note that we don't
-                                // need all information (like values,
-                                // gradients, or real locations of
-                                // quadrature points) for all of these
-                                // objects, so we only let the FEValues
-                                // classes whatever is actually necessary
-                                // by specifying the minimal set of
-                                // UpdateFlags. For example, when using a
-                                // FEFaceValues object for the neighboring
-                                // cell we only need the shape values:
-                                // Given a specific face, the quadrature
-                                // points and <code>JxW</code> values are
-                                // the same as for the current cells, and
-                                // the normal vectors are known to be the
-                                // negative of the normal vectors of the
-                                // current cell.
-template <int dim>
-void ConservationLaw<dim>::assemble_system ()
-{
-  const unsigned int dofs_per_cell = dof_handler.get_fe().dofs_per_cell;
-
-  std::vector<unsigned int> dof_indices (dofs_per_cell);
-  std::vector<unsigned int> dof_indices_neighbor (dofs_per_cell);
-
-  const UpdateFlags update_flags               = update_values
-                                                | update_gradients
-                                                | update_q_points
-                                                | update_JxW_values,
-                   face_update_flags          = update_values
-                                                | update_q_points
-                                                | update_JxW_values
-                                                | update_normal_vectors,
-                   neighbor_face_update_flags = update_values;
-
-  FEValues<dim>        fe_v                  (mapping, fe, quadrature,
-                                             update_flags);
-  FEFaceValues<dim>    fe_v_face             (mapping, fe, face_quadrature,
-                                             face_update_flags);
-  FESubfaceValues<dim> fe_v_subface          (mapping, fe, face_quadrature,
-                                             face_update_flags);
-  FEFaceValues<dim>    fe_v_face_neighbor    (mapping, fe, face_quadrature,
-                                             neighbor_face_update_flags);
-  FESubfaceValues<dim> fe_v_subface_neighbor (mapping, fe, face_quadrature,
-                                             neighbor_face_update_flags);
-
-                                  // Then loop over all cells, initialize the
-                                  // FEValues object for the current cell and
-                                  // call the function that assembles the
-                                  // problem on this cell.
-  typename DoFHandler<dim>::active_cell_iterator
-    cell = dof_handler.begin_active(),
-    endc = dof_handler.end();
-  for (; cell!=endc; ++cell)
-    {
-      fe_v.reinit (cell);
-      cell->get_dof_indices (dof_indices);
-
-      assemble_cell_term(fe_v, dof_indices);
-
-                                      // Then loop over all the faces of this
-                                       // cell.  If a face is part of the
-                                       // external boundary, then assemble
-                                       // boundary conditions there (the fifth
-                                       // argument to
-                                       // <code>assemble_face_terms</code>
-                                       // indicates whether we are working on
-                                       // an external or internal face; if it
-                                       // is an external face, the fourth
-                                       // argument denoting the degrees of
-                                       // freedom indices of the neighbor is
-                                       // ignored, so we pass an empty
-                                       // vector):
-      for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell;
-          ++face_no)
-       if (cell->at_boundary(face_no))
-         {
-           fe_v_face.reinit (cell, face_no);
-           assemble_face_term (face_no, fe_v_face,
-                               fe_v_face,
-                               dof_indices,
-                               std::vector<unsigned int>(),
-                               true,
-                               cell->face(face_no)->boundary_indicator(),
-                               cell->face(face_no)->diameter());
-         }
 
-                                      // The alternative is that we are
-                                      // dealing with an internal face. There
-                                      // are two cases that we need to
-                                      // distinguish: that this is a normal
-                                      // face between two cells at the same
-                                      // refinement level, and that it is a
-                                      // face between two cells of the
-                                      // different refinement levels.
-                                      //
-                                      // In the first case, there is nothing
-                                      // we need to do: we are using a
-                                      // continuous finite element, and face
-                                      // terms do not appear in the bilinear
-                                      // form in this case. The second case
-                                      // usually does not lead to face terms
-                                      // either if we enforce hanging node
-                                      // constraints strongly (as in all
-                                      // previous tutorial programs so far
-                                      // whenever we used continuous finite
-                                      // elements -- this enforcement is done
-                                      // by the ConstraintMatrix class
-                                      // together with
-                                      // DoFTools::make_hanging_node_constraints). In
-                                      // the current program, however, we opt
-                                      // to enforce continuity weakly at
-                                      // faces between cells of different
-                                      // refinement level, for two reasons:
-                                      // (i) because we can, and more
-                                      // importantly (ii) because we would
-                                      // have to thread the automatic
-                                      // differentiation we use to compute
-                                      // the elements of the Newton matrix
-                                      // from the residual through the
-                                      // operations of the ConstraintMatrix
-                                      // class. This would be possible, but
-                                      // is not trivial, and so we choose
-                                      // this alternative approach.
-                                      //
-                                      // What needs to be decided is which
-                                      // side of an interface between two
-                                      // cells of different refinement level
-                                      // we are sitting on.
-                                      //
-                                      // Let's take the case where the
-                                      // neighbor is more refined first. We
-                                      // then have to loop over the children
-                                      // of the face of the current cell and
-                                      // integrate on each of them. We
-                                      // sprinkle a couple of assertions into
-                                      // the code to ensure that our
-                                      // reasoning trying to figure out which
-                                      // of the neighbor's children's faces
-                                      // coincides with a given subface of
-                                      // the current cell's faces is correct
-                                      // -- a bit of defensive programming
-                                      // never hurts.
-                                      //
-                                      // We then call the function that
-                                      // integrates over faces; since this is
-                                      // an internal face, the fifth argument
-                                      // is false, and the sixth one is
-                                      // ignored so we pass an invalid value
-                                      // again:
-       else
-         {
-           if (cell->neighbor(face_no)->has_children())
-             {
-               const unsigned int neighbor2=
-                 cell->neighbor_of_neighbor(face_no);
-
-               for (unsigned int subface_no=0;
-                    subface_no < cell->face(face_no)->n_children();
-                    ++subface_no)
-                 {
-                   const typename DoFHandler<dim>::active_cell_iterator
-                     neighbor_child
-                     = cell->neighbor_child_on_subface (face_no, subface_no);
-
-                   Assert (neighbor_child->face(neighbor2) ==
-                           cell->face(face_no)->child(subface_no),
-                           ExcInternalError());
-                   Assert (neighbor_child->has_children() == false,
-                           ExcInternalError());
-
-                   fe_v_subface.reinit (cell, face_no, subface_no);
-                   fe_v_face_neighbor.reinit (neighbor_child, neighbor2);
-
-                   neighbor_child->get_dof_indices (dof_indices_neighbor);
-
-                   assemble_face_term (face_no, fe_v_subface,
-                                       fe_v_face_neighbor,
-                                       dof_indices,
-                                       dof_indices_neighbor,
-                                       false,
-                                       numbers::invalid_unsigned_int,
-                                       neighbor_child->face(neighbor2)->diameter());
-                 }
-             }
 
-                                            // The other possibility we have
-                                            // to care for is if the neighbor
-                                            // is coarser than the current
-                                            // cell (in particular, because
-                                            // of the usual restriction of
-                                            // only one hanging node per
-                                            // face, the neighbor must be
-                                            // exactly one level coarser than
-                                            // the current cell, something
-                                            // that we check with an
-                                            // assertion). Again, we then
-                                            // integrate over this interface:
-           else if (cell->neighbor(face_no)->level() != cell->level())
-             {
-               const typename DoFHandler<dim>::cell_iterator
-                 neighbor = cell->neighbor(face_no);
-               Assert(neighbor->level() == cell->level()-1,
-                      ExcInternalError());
-
-               neighbor->get_dof_indices (dof_indices_neighbor);
-
-               const std::pair<unsigned int, unsigned int>
-                 faceno_subfaceno = cell->neighbor_of_coarser_neighbor(face_no);
-               const unsigned int neighbor_face_no    = faceno_subfaceno.first,
-                                  neighbor_subface_no = faceno_subfaceno.second;
-
-               Assert (neighbor->neighbor_child_on_subface (neighbor_face_no,
-                                                            neighbor_subface_no)
-                       == cell,
-                       ExcInternalError());
-
-               fe_v_face.reinit (cell, face_no);
-               fe_v_subface_neighbor.reinit (neighbor,
-                                             neighbor_face_no,
-                                             neighbor_subface_no);
-
-               assemble_face_term (face_no, fe_v_face,
-                                   fe_v_subface_neighbor,
-                                   dof_indices,
-                                   dof_indices_neighbor,
-                                   false,
-                                   numbers::invalid_unsigned_int,
-                                   cell->face(face_no)->diameter());
-             }
-         }
-    }
+                                  // @sect4{ConservationLaw::setup_system}
+                                  //
+                                  // The following (easy) function is called
+                                  // each time the mesh is changed. All it
+                                  // does is to resize the Trilinos matrix
+                                  // according to a sparsity pattern that we
+                                  // generate as in all the previous tutorial
+                                  // programs.
+  template <int dim>
+  void ConservationLaw<dim>::setup_system ()
+  {
+    CompressedSparsityPattern sparsity_pattern (dof_handler.n_dofs(),
+                                               dof_handler.n_dofs());
+    DoFTools::make_sparsity_pattern (dof_handler, sparsity_pattern);
 
-                                  // After all this assembling, notify the
-                                  // Trilinos matrix object that the matrix
-                                  // is done:
-  system_matrix.compress();
-}
+    system_matrix.reinit (sparsity_pattern);
+  }
 
 
-                                // @sect4{ConservationLaw::assemble_cell_term}
-                                //
-                                 // This function assembles the cell term by
-                                 // computing the cell part of the residual,
-                                 // adding its negative to the right hand side
-                                 // vector, and adding its derivative with
-                                 // respect to the local variables to the
-                                 // Jacobian (i.e. the Newton matrix). Recall
-                                 // that the cell contributions to the
-                                 // residual read $F_i =
-                                 // \left(\frac{\mathbf{w}_{n+1} -
-                                 // \mathbf{w}_n}{\delta
-                                 // t},\mathbf{z}_i\right)_K -
-                                 // \left(\mathbf{F}(\tilde{\mathbf{w}}),
-                                 // \nabla\mathbf{z}_i\right)_K +
-                                 // h^{\eta}(\nabla \mathbf{w} , \nabla
-                                 // \mathbf{z}_i)_K -
-                                 // (\mathbf{G}(\tilde{\mathbf w}),
-                                 // \mathbf{z}_i)_K$ where $\tilde{\mathbf w}$
-                                 // is represented by the variable
-                                 // <code>W_theta</code>, $\mathbf{z}_i$ is
-                                 // the $i$th test function, and the scalar
-                                 // product
-                                 // $\left(\mathbf{F}(\tilde{\mathbf{w}}),
-                                 // \nabla\mathbf{z}\right)_K$ is understood
-                                 // as $\int_K
-                                 // \sum_{c=1}^{\text{n\_components}}
-                                 // \sum_{d=1}^{\text{dim}}
-                                 // \mathbf{F}(\tilde{\mathbf{w}})_{cd}
-                                 // \frac{\partial z_c}{x_d}$.
-                                //
-                                // At the top of this function, we do the
-                                // usual housekeeping in terms of allocating
-                                // some local variables that we will need
-                                // later. In particular, we will allocate
-                                // variables that will hold the values of the
-                                // current solution $W_{n+1}^k$ after the
-                                // $k$th Newton iteration (variable
-                                // <code>W</code>), the previous time step's
-                                // solution $W_{n}$ (variable
-                                // <code>W_old</code>), as well as the linear
-                                // combination $\theta W_{n+1}^k +
-                                // (1-\theta)W_n$ that results from choosing
-                                // different time stepping schemes (variable
-                                // <code>W_theta</code>).
-                                //
-                                // In addition to these, we need the
-                                // gradients of the current variables.  It is
-                                // a bit of a shame that we have to compute
-                                // these; we almost don't.  The nice thing
-                                // about a simple conservation law is that
-                                // the flux doesn't generally involve any
-                                // gradients.  We do need these, however, for
-                                // the diffusion stabilization.
-                                //
-                                // The actual format in which we store these
-                                // variables requires some
-                                // explanation. First, we need values at each
-                                // quadrature point for each of the
-                                // <code>EulerEquations::n_components</code>
-                                // components of the solution vector. This
-                                // makes for a two-dimensional table for
-                                // which we use deal.II's Table class (this
-                                // is more efficient than
-                                // <code>std::vector@<std::vector@<T@>
-                                // @></code> because it only needs to
-                                // allocate memory once, rather than once for
-                                // each element of the outer
-                                // vector). Similarly, the gradient is a
-                                // three-dimensional table, which the Table
-                                // class also supports.
-                                //
-                                // Secondly, we want to use automatic
-                                // differentiation. To this end, we use the
-                                // Sacado::Fad::DFad template for everything
-                                // that is a computed from the variables with
-                                // respect to which we would like to compute
-                                // derivatives. This includes the current
-                                // solution and gradient at the quadrature
-                                // points (which are linear combinations of
-                                // the degrees of freedom) as well as
-                                // everything that is computed from them such
-                                // as the residual, but not the previous time
-                                // step's solution. These variables are all
-                                // found in the first part of the function,
-                                // along with a variable that we will use to
-                                // store the derivatives of a single
-                                // component of the residual:
-template <int dim>
-void
-ConservationLaw<dim>::
-assemble_cell_term (const FEValues<dim>             &fe_v,
-                   const std::vector<unsigned int> &dof_indices)
-{
-  const unsigned int dofs_per_cell = fe_v.dofs_per_cell;
-  const unsigned int n_q_points    = fe_v.n_quadrature_points;
-
-  Table<2,Sacado::Fad::DFad<double> >
-    W (n_q_points, EulerEquations<dim>::n_components);
-
-  Table<2,double>
-    W_old (n_q_points, EulerEquations<dim>::n_components);
-
-  Table<2,Sacado::Fad::DFad<double> >
-    W_theta (n_q_points, EulerEquations<dim>::n_components);
-
-  Table<3,Sacado::Fad::DFad<double> >
-    grad_W (n_q_points, EulerEquations<dim>::n_components, dim);
-
-  std::vector<double> residual_derivatives (dofs_per_cell);
-
-                                  // Next, we have to define the independent
-                                  // variables that we will try to determine
-                                  // by solving a Newton step. These
-                                  // independent variables are the values of
-                                  // the local degrees of freedom which we
-                                  // extract here:
-  std::vector<Sacado::Fad::DFad<double> > independent_local_dof_values(dofs_per_cell);
-  for (unsigned int i=0; i<dofs_per_cell; ++i)
-    independent_local_dof_values[i] = current_solution(dof_indices[i]);
-
-                                  // The next step incorporates all the
-                                  // magic: we declare a subset of the
-                                  // autodifferentiation variables as
-                                  // independent degrees of freedom, whereas
-                                  // all the other ones remain dependent
-                                  // functions. These are precisely the local
-                                  // degrees of freedom just extracted. All
-                                  // calculations that reference them (either
-                                  // directly or indirectly) will accumulate
-                                  // sensitivies with respect to these
-                                  // variables.
+                                  // @sect4{ConservationLaw::assemble_system}
                                   //
-                                  // In order to mark the variables as
-                                  // independent, the following does the
-                                  // trick, marking
-                                  // <code>independent_local_dof_values[i]</code>
-                                  // as the $i$th independent variable out of
-                                  // a total of <code>dofs_per_cell</code>:
-  for (unsigned int i=0; i<dofs_per_cell; ++i)
-    independent_local_dof_values[i].diff (i, dofs_per_cell);
-
-                                  // After all these declarations, let us
-                                  // actually compute something. First, the
-                                  // values of <code>W</code>,
-                                  // <code>W_old</code>,
-                                  // <code>W_theta</code>, and
-                                  // <code>grad_W</code>, which we can
-                                  // compute from the local DoF values by
-                                  // using the formula $W(x_q)=\sum_i \mathbf
-                                  // W_i \Phi_i(x_q)$, where $\mathbf W_i$ is
-                                  // the $i$th entry of the (local part of
-                                  // the) solution vector, and $\Phi_i(x_q)$
-                                  // the value of the $i$th vector-valued
-                                  // shape function evaluated at quadrature
-                                  // point $x_q$. The gradient can be
-                                  // computed in a similar way.
+                                  // This and the following two
+                                  // functions are the meat of this
+                                  // program: They assemble the linear
+                                  // system that results from applying
+                                  // Newton's method to the nonlinear
+                                  // system of conservation
+                                  // equations.
                                   //
-                                  // Ideally, we could compute this
-                                  // information using a call into something
-                                  // like FEValues::get_function_values and
-                                  // FEValues::get_function_grads, but since
-                                  // (i) we would have to extend the FEValues
-                                  // class for this, and (ii) we don't want
-                                  // to make the entire
-                                  // <code>old_solution</code> vector fad
-                                  // types, only the local cell variables, we
-                                  // explicitly code the loop above. Before
-                                  // this, we add another loop that
-                                  // initializes all the fad variables to
-                                  // zero:
-  for (unsigned int q=0; q<n_q_points; ++q)
-    for (unsigned int c=0; c<EulerEquations<dim>::n_components; ++c)
+                                  // This first function puts all of
+                                  // the assembly pieces together in a
+                                  // routine that dispatches the
+                                  // correct piece for each cell/face.
+                                  // The actual implementation of the
+                                  // assembly on these objects is done
+                                  // in the following functions.
+                                  //
+                                  // At the top of the function we do the
+                                  // usual housekeeping: allocate FEValues,
+                                  // FEFaceValues, and FESubfaceValues
+                                  // objects necessary to do the integrations
+                                  // on cells, faces, and subfaces (in case
+                                  // of adjoining cells on different
+                                  // refinement levels). Note that we don't
+                                  // need all information (like values,
+                                  // gradients, or real locations of
+                                  // quadrature points) for all of these
+                                  // objects, so we only let the FEValues
+                                  // classes whatever is actually necessary
+                                  // by specifying the minimal set of
+                                  // UpdateFlags. For example, when using a
+                                  // FEFaceValues object for the neighboring
+                                  // cell we only need the shape values:
+                                  // Given a specific face, the quadrature
+                                  // points and <code>JxW</code> values are
+                                  // the same as for the current cells, and
+                                  // the normal vectors are known to be the
+                                  // negative of the normal vectors of the
+                                  // current cell.
+  template <int dim>
+  void ConservationLaw<dim>::assemble_system ()
+  {
+    const unsigned int dofs_per_cell = dof_handler.get_fe().dofs_per_cell;
+
+    std::vector<unsigned int> dof_indices (dofs_per_cell);
+    std::vector<unsigned int> dof_indices_neighbor (dofs_per_cell);
+
+    const UpdateFlags update_flags               = update_values
+                                                  | update_gradients
+                                                  | update_q_points
+                                                  | update_JxW_values,
+                     face_update_flags          = update_values
+                                                  | update_q_points
+                                                  | update_JxW_values
+                                                  | update_normal_vectors,
+                     neighbor_face_update_flags = update_values;
+
+    FEValues<dim>        fe_v                  (mapping, fe, quadrature,
+                                               update_flags);
+    FEFaceValues<dim>    fe_v_face             (mapping, fe, face_quadrature,
+                                               face_update_flags);
+    FESubfaceValues<dim> fe_v_subface          (mapping, fe, face_quadrature,
+                                               face_update_flags);
+    FEFaceValues<dim>    fe_v_face_neighbor    (mapping, fe, face_quadrature,
+                                               neighbor_face_update_flags);
+    FESubfaceValues<dim> fe_v_subface_neighbor (mapping, fe, face_quadrature,
+                                               neighbor_face_update_flags);
+
+                                    // Then loop over all cells, initialize the
+                                    // FEValues object for the current cell and
+                                    // call the function that assembles the
+                                    // problem on this cell.
+    typename DoFHandler<dim>::active_cell_iterator
+      cell = dof_handler.begin_active(),
+      endc = dof_handler.end();
+    for (; cell!=endc; ++cell)
       {
-       W[q][c]       = 0;
-       W_old[q][c]   = 0;
-       W_theta[q][c] = 0;
-       for (unsigned int d=0; d<dim; ++d)
-         grad_W[q][c][d] = 0;
-      }
+       fe_v.reinit (cell);
+       cell->get_dof_indices (dof_indices);
+
+       assemble_cell_term(fe_v, dof_indices);
+
+                                        // Then loop over all the faces of this
+                                        // cell.  If a face is part of the
+                                        // external boundary, then assemble
+                                        // boundary conditions there (the fifth
+                                        // argument to
+                                        // <code>assemble_face_terms</code>
+                                        // indicates whether we are working on
+                                        // an external or internal face; if it
+                                        // is an external face, the fourth
+                                        // argument denoting the degrees of
+                                        // freedom indices of the neighbor is
+                                        // ignored, so we pass an empty
+                                        // vector):
+       for (unsigned int face_no=0; face_no<GeometryInfo<dim>::faces_per_cell;
+            ++face_no)
+         if (cell->at_boundary(face_no))
+           {
+             fe_v_face.reinit (cell, face_no);
+             assemble_face_term (face_no, fe_v_face,
+                                 fe_v_face,
+                                 dof_indices,
+                                 std::vector<unsigned int>(),
+                                 true,
+                                 cell->face(face_no)->boundary_indicator(),
+                                 cell->face(face_no)->diameter());
+           }
 
-  for (unsigned int q=0; q<n_q_points; ++q)
-    for (unsigned int i=0; i<dofs_per_cell; ++i)
-      {
-       const unsigned int c = fe_v.get_fe().system_to_component_index(i).first;
-
-       W[q][c] += independent_local_dof_values[i] *
-                  fe_v.shape_value_component(i, q, c);
-       W_old[q][c] += old_solution(dof_indices[i]) *
-                      fe_v.shape_value_component(i, q, c);
-       W_theta[q][c] += (parameters.theta *
-                         independent_local_dof_values[i]
-                         +
-                         (1-parameters.theta) *
-                         old_solution(dof_indices[i])) *
-                        fe_v.shape_value_component(i, q, c);
+                                        // The alternative is that we are
+                                        // dealing with an internal face. There
+                                        // are two cases that we need to
+                                        // distinguish: that this is a normal
+                                        // face between two cells at the same
+                                        // refinement level, and that it is a
+                                        // face between two cells of the
+                                        // different refinement levels.
+                                        //
+                                        // In the first case, there is nothing
+                                        // we need to do: we are using a
+                                        // continuous finite element, and face
+                                        // terms do not appear in the bilinear
+                                        // form in this case. The second case
+                                        // usually does not lead to face terms
+                                        // either if we enforce hanging node
+                                        // constraints strongly (as in all
+                                        // previous tutorial programs so far
+                                        // whenever we used continuous finite
+                                        // elements -- this enforcement is done
+                                        // by the ConstraintMatrix class
+                                        // together with
+                                        // DoFTools::make_hanging_node_constraints). In
+                                        // the current program, however, we opt
+                                        // to enforce continuity weakly at
+                                        // faces between cells of different
+                                        // refinement level, for two reasons:
+                                        // (i) because we can, and more
+                                        // importantly (ii) because we would
+                                        // have to thread the automatic
+                                        // differentiation we use to compute
+                                        // the elements of the Newton matrix
+                                        // from the residual through the
+                                        // operations of the ConstraintMatrix
+                                        // class. This would be possible, but
+                                        // is not trivial, and so we choose
+                                        // this alternative approach.
+                                        //
+                                        // What needs to be decided is which
+                                        // side of an interface between two
+                                        // cells of different refinement level
+                                        // we are sitting on.
+                                        //
+                                        // Let's take the case where the
+                                        // neighbor is more refined first. We
+                                        // then have to loop over the children
+                                        // of the face of the current cell and
+                                        // integrate on each of them. We
+                                        // sprinkle a couple of assertions into
+                                        // the code to ensure that our
+                                        // reasoning trying to figure out which
+                                        // of the neighbor's children's faces
+                                        // coincides with a given subface of
+                                        // the current cell's faces is correct
+                                        // -- a bit of defensive programming
+                                        // never hurts.
+                                        //
+                                        // We then call the function that
+                                        // integrates over faces; since this is
+                                        // an internal face, the fifth argument
+                                        // is false, and the sixth one is
+                                        // ignored so we pass an invalid value
+                                        // again:
+         else
+           {
+             if (cell->neighbor(face_no)->has_children())
+               {
+                 const unsigned int neighbor2=
+                   cell->neighbor_of_neighbor(face_no);
+
+                 for (unsigned int subface_no=0;
+                      subface_no < cell->face(face_no)->n_children();
+                      ++subface_no)
+                   {
+                     const typename DoFHandler<dim>::active_cell_iterator
+                       neighbor_child
+                       = cell->neighbor_child_on_subface (face_no, subface_no);
+
+                     Assert (neighbor_child->face(neighbor2) ==
+                             cell->face(face_no)->child(subface_no),
+                             ExcInternalError());
+                     Assert (neighbor_child->has_children() == false,
+                             ExcInternalError());
+
+                     fe_v_subface.reinit (cell, face_no, subface_no);
+                     fe_v_face_neighbor.reinit (neighbor_child, neighbor2);
+
+                     neighbor_child->get_dof_indices (dof_indices_neighbor);
+
+                     assemble_face_term (face_no, fe_v_subface,
+                                         fe_v_face_neighbor,
+                                         dof_indices,
+                                         dof_indices_neighbor,
+                                         false,
+                                         numbers::invalid_unsigned_int,
+                                         neighbor_child->face(neighbor2)->diameter());
+                   }
+               }
 
-       for (unsigned int d = 0; d < dim; d++)
-         grad_W[q][c][d] += independent_local_dof_values[i] *
-                            fe_v.shape_grad_component(i, q, c)[d];
+                                              // The other possibility we have
+                                              // to care for is if the neighbor
+                                              // is coarser than the current
+                                              // cell (in particular, because
+                                              // of the usual restriction of
+                                              // only one hanging node per
+                                              // face, the neighbor must be
+                                              // exactly one level coarser than
+                                              // the current cell, something
+                                              // that we check with an
+                                              // assertion). Again, we then
+                                              // integrate over this interface:
+             else if (cell->neighbor(face_no)->level() != cell->level())
+               {
+                 const typename DoFHandler<dim>::cell_iterator
+                   neighbor = cell->neighbor(face_no);
+                 Assert(neighbor->level() == cell->level()-1,
+                        ExcInternalError());
+
+                 neighbor->get_dof_indices (dof_indices_neighbor);
+
+                 const std::pair<unsigned int, unsigned int>
+                   faceno_subfaceno = cell->neighbor_of_coarser_neighbor(face_no);
+                 const unsigned int neighbor_face_no    = faceno_subfaceno.first,
+                                    neighbor_subface_no = faceno_subfaceno.second;
+
+                 Assert (neighbor->neighbor_child_on_subface (neighbor_face_no,
+                                                              neighbor_subface_no)
+                         == cell,
+                         ExcInternalError());
+
+                 fe_v_face.reinit (cell, face_no);
+                 fe_v_subface_neighbor.reinit (neighbor,
+                                               neighbor_face_no,
+                                               neighbor_subface_no);
+
+                 assemble_face_term (face_no, fe_v_face,
+                                     fe_v_subface_neighbor,
+                                     dof_indices,
+                                     dof_indices_neighbor,
+                                     false,
+                                     numbers::invalid_unsigned_int,
+                                     cell->face(face_no)->diameter());
+               }
+           }
       }
 
-
-                                  // Next, in order to compute the cell
-                                  // contributions, we need to evaluate
-                                  // $F(\tilde{\mathbf w})$ and
-                                  // $G(\tilde{\mathbf w})$ at all quadrature
-                                  // points. To store these, we also need to
-                                  // allocate a bit of memory. Note that we
-                                  // compute the flux matrices and right hand
-                                  // sides in terms of autodifferentiation
-                                  // variables, so that the Jacobian
-                                  // contributions can later easily be
-                                  // computed from it:
-  typedef Sacado::Fad::DFad<double> FluxMatrix[EulerEquations<dim>::n_components][dim];
-  FluxMatrix *flux = new FluxMatrix[n_q_points];
-
-  typedef Sacado::Fad::DFad<double> ForcingVector[EulerEquations<dim>::n_components];
-  ForcingVector *forcing = new ForcingVector[n_q_points];
-
-  for (unsigned int q=0; q<n_q_points; ++q)
-    {
-      EulerEquations<dim>::compute_flux_matrix (W_theta[q], flux[q]);
-      EulerEquations<dim>::compute_forcing_vector (W_theta[q], forcing[q]);
-    }
+                                    // After all this assembling, notify the
+                                    // Trilinos matrix object that the matrix
+                                    // is done:
+    system_matrix.compress();
+  }
 
 
-                                  // We now have all of the pieces in place,
-                                  // so perform the assembly.  We have an
-                                  // outer loop through the components of the
-                                  // system, and an inner loop over the
-                                  // quadrature points, where we accumulate
-                                  // contributions to the $i$th residual
-                                  // $F_i$. The general formula for this
-                                  // residual is given in the introduction
-                                  // and at the top of this function. We can,
-                                  // however, simplify it a bit taking into
-                                  // account that the $i$th (vector-valued)
-                                  // test function $\mathbf{z}_i$ has in
-                                  // reality only a single nonzero component
-                                  // (more on this topic can be found in the
-                                  // @ref vector_valued module). It will be
-                                  // represented by the variable
-                                  // <code>component_i</code> below. With
-                                  // this, the residual term can be
-                                  // re-written as $F_i =
-                                  // \left(\frac{(\mathbf{w}_{n+1} -
-                                  // \mathbf{w}_n)_{\text{component\_i}}}{\delta
-                                  // t},(\mathbf{z}_i)_{\text{component\_i}}\right)_K$
-                                  // $- \sum_{d=1}^{\text{dim}}
-                                  // \left(\mathbf{F}
-                                  // (\tilde{\mathbf{w}})_{\text{component\_i},d},
-                                  // \frac{\partial(\mathbf{z}_i)_{\text{component\_i}}}
-                                  // {\partial x_d}\right)_K$ $+
-                                  // \sum_{d=1}^{\text{dim}} h^{\eta}
-                                  // \left(\frac{\partial
-                                  // \mathbf{w}_{\text{component\_i}}}{\partial
-                                  // x_d} , \frac{\partial
-                                  // (\mathbf{z}_i)_{\text{component\_i}}}{\partial
-                                  // x_d} \right)_K$
-                                  // $-(\mathbf{G}(\tilde{\mathbf{w}}
-                                  // )_{\text{component\_i}},
-                                  // (\mathbf{z}_i)_{\text{component\_i}})_K$,
-                                  // where integrals are understood to be
-                                  // evaluated through summation over
-                                  // quadrature points.
+                                  // @sect4{ConservationLaw::assemble_cell_term}
                                   //
-                                  // We initialy sum all contributions of the
-                                  // residual in the positive sense, so that
-                                  // we don't need to negative the Jacobian
-                                  // entries.  Then, when we sum into the
-                                  // <code>right_hand_side</code> vector,
-                                  // we negate this residual.
-  for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
-    {
-      Sacado::Fad::DFad<double> F_i = 0;
-
-      const unsigned int
-       component_i = fe_v.get_fe().system_to_component_index(i).first;
-
-                                      // The residual for each row (i) will be accumulating
-                                      // into this fad variable.  At the end of the assembly
-                                      // for this row, we will query for the sensitivities
-                                      // to this variable and add them into the Jacobian.
-
-      for (unsigned int point=0; point<fe_v.n_quadrature_points; ++point)
-       {
-         if (parameters.is_stationary == false)
-           F_i += 1.0 / parameters.time_step *
-                  (W[point][component_i] - W_old[point][component_i]) *
-                  fe_v.shape_value_component(i, point, component_i) *
-                  fe_v.JxW(point);
+                                  // This function assembles the cell term by
+                                  // computing the cell part of the residual,
+                                  // adding its negative to the right hand side
+                                  // vector, and adding its derivative with
+                                  // respect to the local variables to the
+                                  // Jacobian (i.e. the Newton matrix). Recall
+                                  // that the cell contributions to the
+                                  // residual read $F_i =
+                                  // \left(\frac{\mathbf{w}_{n+1} -
+                                  // \mathbf{w}_n}{\delta
+                                  // t},\mathbf{z}_i\right)_K -
+                                  // \left(\mathbf{F}(\tilde{\mathbf{w}}),
+                                  // \nabla\mathbf{z}_i\right)_K +
+                                  // h^{\eta}(\nabla \mathbf{w} , \nabla
+                                  // \mathbf{z}_i)_K -
+                                  // (\mathbf{G}(\tilde{\mathbf w}),
+                                  // \mathbf{z}_i)_K$ where $\tilde{\mathbf w}$
+                                  // is represented by the variable
+                                  // <code>W_theta</code>, $\mathbf{z}_i$ is
+                                  // the $i$th test function, and the scalar
+                                  // product
+                                  // $\left(\mathbf{F}(\tilde{\mathbf{w}}),
+                                  // \nabla\mathbf{z}\right)_K$ is understood
+                                  // as $\int_K
+                                  // \sum_{c=1}^{\text{n\_components}}
+                                  // \sum_{d=1}^{\text{dim}}
+                                  // \mathbf{F}(\tilde{\mathbf{w}})_{cd}
+                                  // \frac{\partial z_c}{x_d}$.
+                                  //
+                                  // At the top of this function, we do the
+                                  // usual housekeeping in terms of allocating
+                                  // some local variables that we will need
+                                  // later. In particular, we will allocate
+                                  // variables that will hold the values of the
+                                  // current solution $W_{n+1}^k$ after the
+                                  // $k$th Newton iteration (variable
+                                  // <code>W</code>), the previous time step's
+                                  // solution $W_{n}$ (variable
+                                  // <code>W_old</code>), as well as the linear
+                                  // combination $\theta W_{n+1}^k +
+                                  // (1-\theta)W_n$ that results from choosing
+                                  // different time stepping schemes (variable
+                                  // <code>W_theta</code>).
+                                  //
+                                  // In addition to these, we need the
+                                  // gradients of the current variables.  It is
+                                  // a bit of a shame that we have to compute
+                                  // these; we almost don't.  The nice thing
+                                  // about a simple conservation law is that
+                                  // the flux doesn't generally involve any
+                                  // gradients.  We do need these, however, for
+                                  // the diffusion stabilization.
+                                  //
+                                  // The actual format in which we store these
+                                  // variables requires some
+                                  // explanation. First, we need values at each
+                                  // quadrature point for each of the
+                                  // <code>EulerEquations::n_components</code>
+                                  // components of the solution vector. This
+                                  // makes for a two-dimensional table for
+                                  // which we use deal.II's Table class (this
+                                  // is more efficient than
+                                  // <code>std::vector@<std::vector@<T@>
+                                  // @></code> because it only needs to
+                                  // allocate memory once, rather than once for
+                                  // each element of the outer
+                                  // vector). Similarly, the gradient is a
+                                  // three-dimensional table, which the Table
+                                  // class also supports.
+                                  //
+                                  // Secondly, we want to use automatic
+                                  // differentiation. To this end, we use the
+                                  // Sacado::Fad::DFad template for everything
+                                  // that is a computed from the variables with
+                                  // respect to which we would like to compute
+                                  // derivatives. This includes the current
+                                  // solution and gradient at the quadrature
+                                  // points (which are linear combinations of
+                                  // the degrees of freedom) as well as
+                                  // everything that is computed from them such
+                                  // as the residual, but not the previous time
+                                  // step's solution. These variables are all
+                                  // found in the first part of the function,
+                                  // along with a variable that we will use to
+                                  // store the derivatives of a single
+                                  // component of the residual:
+  template <int dim>
+  void
+  ConservationLaw<dim>::
+  assemble_cell_term (const FEValues<dim>             &fe_v,
+                     const std::vector<unsigned int> &dof_indices)
+  {
+    const unsigned int dofs_per_cell = fe_v.dofs_per_cell;
+    const unsigned int n_q_points    = fe_v.n_quadrature_points;
 
-         for (unsigned int d=0; d<dim; d++)
-           F_i -= flux[point][component_i][d] *
-                  fe_v.shape_grad_component(i, point, component_i)[d] *
-                  fe_v.JxW(point);
+    Table<2,Sacado::Fad::DFad<double> >
+      W (n_q_points, EulerEquations<dim>::n_components);
 
-         for (unsigned int d=0; d<dim; d++)
-           F_i += 1.0*std::pow(fe_v.get_cell()->diameter(),
-                               parameters.diffusion_power) *
-                  grad_W[point][component_i][d] *
-                  fe_v.shape_grad_component(i, point, component_i)[d] *
-                  fe_v.JxW(point);
+    Table<2,double>
+      W_old (n_q_points, EulerEquations<dim>::n_components);
 
-         F_i -= forcing[point][component_i] *
-                fe_v.shape_value_component(i, point, component_i) *
-                fe_v.JxW(point);
-       }
+    Table<2,Sacado::Fad::DFad<double> >
+      W_theta (n_q_points, EulerEquations<dim>::n_components);
 
-                                      // At the end of the loop, we have to
-                                      // add the sensitivities to the
-                                      // matrix and subtract the residual
-                                      // from the right hand side. Trilinos
-                                      // FAD data type gives us access to
-                                      // the derivatives using
-                                      // <code>F_i.fastAccessDx(k)</code>,
-                                      // so we store the data in a
-                                      // temporary array. This information
-                                      // about the whole row of local dofs
-                                      // is then added to the Trilinos
-                                      // matrix at once (which supports the
-                                      // data types we have chosen).
-      for (unsigned int k=0; k<dofs_per_cell; ++k)
-       residual_derivatives[k] = F_i.fastAccessDx(k);
-      system_matrix.add(dof_indices[i], dof_indices, residual_derivatives);
-      right_hand_side(dof_indices[i]) -= F_i.val();
-    }
+    Table<3,Sacado::Fad::DFad<double> >
+      grad_W (n_q_points, EulerEquations<dim>::n_components, dim);
 
-  delete[] forcing;
-  delete[] flux;
-}
+    std::vector<double> residual_derivatives (dofs_per_cell);
 
+                                    // Next, we have to define the independent
+                                    // variables that we will try to determine
+                                    // by solving a Newton step. These
+                                    // independent variables are the values of
+                                    // the local degrees of freedom which we
+                                    // extract here:
+    std::vector<Sacado::Fad::DFad<double> > independent_local_dof_values(dofs_per_cell);
+    for (unsigned int i=0; i<dofs_per_cell; ++i)
+      independent_local_dof_values[i] = current_solution(dof_indices[i]);
 
-                                // @sect4{ConservationLaw::assemble_face_term}
-                                //
-                                // Here, we do essentially the same as in the
-                                // previous function. t the top, we introduce
-                                // the independent variables. Because the
-                                // current function is also used if we are
-                                // working on an internal face between two
-                                // cells, the independent variables are not
-                                // only the degrees of freedom on the current
-                                // cell but in the case of an interior face
-                                // also the ones on the neighbor.
-template <int dim>
-void
-ConservationLaw<dim>::assemble_face_term(const unsigned int           face_no,
-                                        const FEFaceValuesBase<dim> &fe_v,
-                                        const FEFaceValuesBase<dim> &fe_v_neighbor,
-                                        const std::vector<unsigned int>   &dof_indices,
-                                        const std::vector<unsigned int>   &dof_indices_neighbor,
-                                        const bool                   external_face,
-                                        const unsigned int           boundary_id,
-                                        const double                 face_diameter)
-{
-  const unsigned int n_q_points = fe_v.n_quadrature_points;
-  const unsigned int dofs_per_cell = fe_v.dofs_per_cell;
+                                    // The next step incorporates all the
+                                    // magic: we declare a subset of the
+                                    // autodifferentiation variables as
+                                    // independent degrees of freedom, whereas
+                                    // all the other ones remain dependent
+                                    // functions. These are precisely the local
+                                    // degrees of freedom just extracted. All
+                                    // calculations that reference them (either
+                                    // directly or indirectly) will accumulate
+                                    // sensitivies with respect to these
+                                    // variables.
+                                    //
+                                    // In order to mark the variables as
+                                    // independent, the following does the
+                                    // trick, marking
+                                    // <code>independent_local_dof_values[i]</code>
+                                    // as the $i$th independent variable out of
+                                    // a total of <code>dofs_per_cell</code>:
+    for (unsigned int i=0; i<dofs_per_cell; ++i)
+      independent_local_dof_values[i].diff (i, dofs_per_cell);
+
+                                    // After all these declarations, let us
+                                    // actually compute something. First, the
+                                    // values of <code>W</code>,
+                                    // <code>W_old</code>,
+                                    // <code>W_theta</code>, and
+                                    // <code>grad_W</code>, which we can
+                                    // compute from the local DoF values by
+                                    // using the formula $W(x_q)=\sum_i \mathbf
+                                    // W_i \Phi_i(x_q)$, where $\mathbf W_i$ is
+                                    // the $i$th entry of the (local part of
+                                    // the) solution vector, and $\Phi_i(x_q)$
+                                    // the value of the $i$th vector-valued
+                                    // shape function evaluated at quadrature
+                                    // point $x_q$. The gradient can be
+                                    // computed in a similar way.
+                                    //
+                                    // Ideally, we could compute this
+                                    // information using a call into something
+                                    // like FEValues::get_function_values and
+                                    // FEValues::get_function_grads, but since
+                                    // (i) we would have to extend the FEValues
+                                    // class for this, and (ii) we don't want
+                                    // to make the entire
+                                    // <code>old_solution</code> vector fad
+                                    // types, only the local cell variables, we
+                                    // explicitly code the loop above. Before
+                                    // this, we add another loop that
+                                    // initializes all the fad variables to
+                                    // zero:
+    for (unsigned int q=0; q<n_q_points; ++q)
+      for (unsigned int c=0; c<EulerEquations<dim>::n_components; ++c)
+       {
+         W[q][c]       = 0;
+         W_old[q][c]   = 0;
+         W_theta[q][c] = 0;
+         for (unsigned int d=0; d<dim; ++d)
+           grad_W[q][c][d] = 0;
+       }
 
-  std::vector<Sacado::Fad::DFad<double> >
-    independent_local_dof_values (dofs_per_cell),
-    independent_neighbor_dof_values (external_face == false ?
-                                    dofs_per_cell :
-                                    0);
+    for (unsigned int q=0; q<n_q_points; ++q)
+      for (unsigned int i=0; i<dofs_per_cell; ++i)
+       {
+         const unsigned int c = fe_v.get_fe().system_to_component_index(i).first;
 
-  const unsigned int n_independent_variables = (external_face == false ?
-                                               2 * dofs_per_cell :
-                                               dofs_per_cell);
+         W[q][c] += independent_local_dof_values[i] *
+                    fe_v.shape_value_component(i, q, c);
+         W_old[q][c] += old_solution(dof_indices[i]) *
+                        fe_v.shape_value_component(i, q, c);
+         W_theta[q][c] += (parameters.theta *
+                           independent_local_dof_values[i]
+                           +
+                           (1-parameters.theta) *
+                           old_solution(dof_indices[i])) *
+                          fe_v.shape_value_component(i, q, c);
+
+         for (unsigned int d = 0; d < dim; d++)
+           grad_W[q][c][d] += independent_local_dof_values[i] *
+                              fe_v.shape_grad_component(i, q, c)[d];
+       }
 
-  for (unsigned int i = 0; i < dofs_per_cell; i++)
-    {
-      independent_local_dof_values[i] = current_solution(dof_indices[i]);
-      independent_local_dof_values[i].diff(i, n_independent_variables);
-    }
 
-  if (external_face == false)
-    for (unsigned int i = 0; i < dofs_per_cell; i++)
+                                    // Next, in order to compute the cell
+                                    // contributions, we need to evaluate
+                                    // $F(\tilde{\mathbf w})$ and
+                                    // $G(\tilde{\mathbf w})$ at all quadrature
+                                    // points. To store these, we also need to
+                                    // allocate a bit of memory. Note that we
+                                    // compute the flux matrices and right hand
+                                    // sides in terms of autodifferentiation
+                                    // variables, so that the Jacobian
+                                    // contributions can later easily be
+                                    // computed from it:
+    typedef Sacado::Fad::DFad<double> FluxMatrix[EulerEquations<dim>::n_components][dim];
+    FluxMatrix *flux = new FluxMatrix[n_q_points];
+
+    typedef Sacado::Fad::DFad<double> ForcingVector[EulerEquations<dim>::n_components];
+    ForcingVector *forcing = new ForcingVector[n_q_points];
+
+    for (unsigned int q=0; q<n_q_points; ++q)
       {
-       independent_neighbor_dof_values[i]
-         = current_solution(dof_indices_neighbor[i]);
-       independent_neighbor_dof_values[i]
-         .diff(i+dofs_per_cell, n_independent_variables);
+       EulerEquations<dim>::compute_flux_matrix (W_theta[q], flux[q]);
+       EulerEquations<dim>::compute_forcing_vector (W_theta[q], forcing[q]);
       }
 
 
-                                  // Next, we need to define the values of
-                                  // the conservative variables $\tilde
-                                  // {\mathbf W}$ on this side of the face
-                                  // ($\tilde {\mathbf W}^+$) and on the
-                                  // opposite side ($\tilde {\mathbf
-                                  // W}^-$). The former can be computed in
-                                  // exactly the same way as in the previous
-                                  // function, but note that the
-                                  // <code>fe_v</code> variable now is of
-                                  // type FEFaceValues or FESubfaceValues:
-  Table<2,Sacado::Fad::DFad<double> >
-    Wplus (n_q_points, EulerEquations<dim>::n_components),
-    Wminus (n_q_points, EulerEquations<dim>::n_components);
-
-  for (unsigned int q=0; q<n_q_points; ++q)
-    for (unsigned int i=0; i<dofs_per_cell; ++i)
+                                    // We now have all of the pieces in place,
+                                    // so perform the assembly.  We have an
+                                    // outer loop through the components of the
+                                    // system, and an inner loop over the
+                                    // quadrature points, where we accumulate
+                                    // contributions to the $i$th residual
+                                    // $F_i$. The general formula for this
+                                    // residual is given in the introduction
+                                    // and at the top of this function. We can,
+                                    // however, simplify it a bit taking into
+                                    // account that the $i$th (vector-valued)
+                                    // test function $\mathbf{z}_i$ has in
+                                    // reality only a single nonzero component
+                                    // (more on this topic can be found in the
+                                    // @ref vector_valued module). It will be
+                                    // represented by the variable
+                                    // <code>component_i</code> below. With
+                                    // this, the residual term can be
+                                    // re-written as $F_i =
+                                    // \left(\frac{(\mathbf{w}_{n+1} -
+                                    // \mathbf{w}_n)_{\text{component\_i}}}{\delta
+                                    // t},(\mathbf{z}_i)_{\text{component\_i}}\right)_K$
+                                    // $- \sum_{d=1}^{\text{dim}}
+                                    // \left(\mathbf{F}
+                                    // (\tilde{\mathbf{w}})_{\text{component\_i},d},
+                                    // \frac{\partial(\mathbf{z}_i)_{\text{component\_i}}}
+                                    // {\partial x_d}\right)_K$ $+
+                                    // \sum_{d=1}^{\text{dim}} h^{\eta}
+                                    // \left(\frac{\partial
+                                    // \mathbf{w}_{\text{component\_i}}}{\partial
+                                    // x_d} , \frac{\partial
+                                    // (\mathbf{z}_i)_{\text{component\_i}}}{\partial
+                                    // x_d} \right)_K$
+                                    // $-(\mathbf{G}(\tilde{\mathbf{w}}
+                                    // )_{\text{component\_i}},
+                                    // (\mathbf{z}_i)_{\text{component\_i}})_K$,
+                                    // where integrals are understood to be
+                                    // evaluated through summation over
+                                    // quadrature points.
+                                    //
+                                    // We initialy sum all contributions of the
+                                    // residual in the positive sense, so that
+                                    // we don't need to negative the Jacobian
+                                    // entries.  Then, when we sum into the
+                                    // <code>right_hand_side</code> vector,
+                                    // we negate this residual.
+    for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
       {
-       const unsigned int component_i = fe_v.get_fe().system_to_component_index(i).first;
-       Wplus[q][component_i] += (parameters.theta *
-                                 independent_local_dof_values[i]
-                                 +
-                                 (1.0-parameters.theta) *
-                                 old_solution(dof_indices[i])) *
-                                fe_v.shape_value_component(i, q, component_i);
-      }
-
-                                  // Computing $\tilde {\mathbf W}^-$ is a
-                                  // bit more complicated. If this is an
-                                  // internal face, we can compute it as
-                                  // above by simply using the independent
-                                  // variables from the neighbor:
-  if (external_face == false)
-    {
-      for (unsigned int q=0; q<n_q_points; ++q)
-       for (unsigned int i=0; i<dofs_per_cell; ++i)
-         {
-           const unsigned int component_i = fe_v_neighbor.get_fe().
-                                            system_to_component_index(i).first;
-           Wminus[q][component_i] += (parameters.theta *
-                                      independent_neighbor_dof_values[i]
-                                      +
-                                      (1.0-parameters.theta) *
-                                      old_solution(dof_indices_neighbor[i]))*
-                                     fe_v_neighbor.shape_value_component(i, q, component_i);
-         }
-    }
-                                  // On the other hand, if this is an
-                                  // external boundary face, then the values
-                                  // of $W^-$ will be either functions of
-                                  // $W^+$, or they will be prescribed,
-                                  // depending on the kind of boundary
-                                  // condition imposed here.
-                                  //
-                                  // To start the evaluation, let us ensure
-                                  // that the boundary id specified for this
-                                  // boundary is one for which we actually
-                                  // have data in the parameters
-                                  // object. Next, we evaluate the function
-                                  // object for the inhomogeneity.  This is a
-                                  // bit tricky: a given boundary might have
-                                  // both prescribed and implicit values.  If
-                                  // a particular component is not
-                                  // prescribed, the values evaluate to zero
-                                  // and are ignored below.
-                                  //
-                                  // The rest is done by a function that
-                                  // actually knows the specifics of Euler
-                                  // equation boundary conditions. Note that
-                                  // since we are using fad variables here,
-                                  // sensitivities will be updated
-                                  // appropriately, a process that would
-                                  // otherwise be tremendously complicated.
-  else
-    {
-      Assert (boundary_id < Parameters::AllParameters<dim>::max_n_boundaries,
-             ExcIndexRange (boundary_id, 0,
-                            Parameters::AllParameters<dim>::max_n_boundaries));
-
-      std::vector<Vector<double> >
-       boundary_values(n_q_points, Vector<double>(EulerEquations<dim>::n_components));
-      parameters.boundary_conditions[boundary_id]
-       .values.vector_value_list(fe_v.get_quadrature_points(),
-                                 boundary_values);
-
-      for (unsigned int q = 0; q < n_q_points; q++)
-       EulerEquations<dim>::compute_Wminus (parameters.boundary_conditions[boundary_id].kind,
-                                            fe_v.normal_vector(q),
-                                            Wplus[q],
-                                            boundary_values[q],
-                                            Wminus[q]);
-    }
-
-
-                                  // Now that we have $\mathbf w^+$ and
-                                  // $\mathbf w^-$, we can go about computing
-                                  // the numerical flux function $\mathbf
-                                  // H(\mathbf w^+,\mathbf w^-, \mathbf n)$
-                                  // for each quadrature point. Before
-                                  // calling the function that does so, we
-                                  // also need to determine the
-                                  // Lax-Friedrich's stability parameter:
-  typedef Sacado::Fad::DFad<double> NormalFlux[EulerEquations<dim>::n_components];
-  NormalFlux *normal_fluxes = new NormalFlux[n_q_points];
-
-  double alpha;
+       Sacado::Fad::DFad<double> F_i = 0;
 
-  switch(parameters.stabilization_kind)
-    {
-      case Parameters::Flux::constant:
-           alpha = parameters.stabilization_value;
-           break;
-      case Parameters::Flux::mesh_dependent:
-           alpha = face_diameter/(2.0*parameters.time_step);
-           break;
-      default:
-           Assert (false, ExcNotImplemented());
-           alpha = 1;
-    }
+       const unsigned int
+         component_i = fe_v.get_fe().system_to_component_index(i).first;
 
-  for (unsigned int q=0; q<n_q_points; ++q)
-    EulerEquations<dim>::numerical_normal_flux(fe_v.normal_vector(q),
-                                              Wplus[q], Wminus[q], alpha,
-                                              normal_fluxes[q]);
-
-                                  // Now assemble the face term in exactly
-                                  // the same way as for the cell
-                                  // contributions in the previous
-                                  // function. The only difference is that if
-                                  // this is an internal face, we also have
-                                  // to take into account the sensitivies of
-                                  // the residual contributions to the
-                                  // degrees of freedom on the neighboring
-                                  // cell:
-  std::vector<double> residual_derivatives (dofs_per_cell);
-  for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
-    if (fe_v.get_fe().has_support_on_face(i, face_no) == true)
-      {
-       Sacado::Fad::DFad<double> F_i = 0;
+                                        // The residual for each row (i) will be accumulating
+                                        // into this fad variable.  At the end of the assembly
+                                        // for this row, we will query for the sensitivities
+                                        // to this variable and add them into the Jacobian.
 
-       for (unsigned int point=0; point<n_q_points; ++point)
+       for (unsigned int point=0; point<fe_v.n_quadrature_points; ++point)
          {
-           const unsigned int
-             component_i = fe_v.get_fe().system_to_component_index(i).first;
-
-           F_i += normal_fluxes[point][component_i] *
+           if (parameters.is_stationary == false)
+             F_i += 1.0 / parameters.time_step *
+                    (W[point][component_i] - W_old[point][component_i]) *
+                    fe_v.shape_value_component(i, point, component_i) *
+                    fe_v.JxW(point);
+
+           for (unsigned int d=0; d<dim; d++)
+             F_i -= flux[point][component_i][d] *
+                    fe_v.shape_grad_component(i, point, component_i)[d] *
+                    fe_v.JxW(point);
+
+           for (unsigned int d=0; d<dim; d++)
+             F_i += 1.0*std::pow(fe_v.get_cell()->diameter(),
+                                 parameters.diffusion_power) *
+                    grad_W[point][component_i][d] *
+                    fe_v.shape_grad_component(i, point, component_i)[d] *
+                    fe_v.JxW(point);
+
+           F_i -= forcing[point][component_i] *
                   fe_v.shape_value_component(i, point, component_i) *
                   fe_v.JxW(point);
          }
 
+                                        // At the end of the loop, we have to
+                                        // add the sensitivities to the
+                                        // matrix and subtract the residual
+                                        // from the right hand side. Trilinos
+                                        // FAD data type gives us access to
+                                        // the derivatives using
+                                        // <code>F_i.fastAccessDx(k)</code>,
+                                        // so we store the data in a
+                                        // temporary array. This information
+                                        // about the whole row of local dofs
+                                        // is then added to the Trilinos
+                                        // matrix at once (which supports the
+                                        // data types we have chosen).
        for (unsigned int k=0; k<dofs_per_cell; ++k)
          residual_derivatives[k] = F_i.fastAccessDx(k);
        system_matrix.add(dof_indices[i], dof_indices, residual_derivatives);
-
-       if (external_face == false)
-         {
-           for (unsigned int k=0; k<dofs_per_cell; ++k)
-             residual_derivatives[k] = F_i.fastAccessDx(dofs_per_cell+k);
-           system_matrix.add (dof_indices[i], dof_indices_neighbor,
-                              residual_derivatives);
-         }
-
        right_hand_side(dof_indices[i]) -= F_i.val();
       }
 
-  delete[] normal_fluxes;
-}
+    delete[] forcing;
+    delete[] flux;
+  }
 
 
-                                 // @sect4{ConservationLaw::solve}
-                                 //
-                                // Here, we actually solve the linear system,
-                                 // using either of Trilinos' Aztec or Amesos
-                                 // linear solvers. The result of the
-                                 // computation will be written into the
-                                 // argument vector passed to this
-                                 // function. The result is a pair of number
-                                 // of iterations and the final linear
-                                 // residual.
-
-template <int dim>
-std::pair<unsigned int, double>
-ConservationLaw<dim>::solve (Vector<double> &newton_update)
-{
-  switch (parameters.solver)
-    {
-                                      // If the parameter file specified
-                                      // that a direct solver shall be
-                                      // used, then we'll get here. The
-                                      // process is straightforward, since
-                                      // deal.II provides a wrapper class
-                                      // to the Amesos direct solver within
-                                      // Trilinos. All we have to do is to
-                                      // create a solver control object
-                                      // (which is just a dummy object
-                                      // here, since we won't perform any
-                                      // iterations), and then create the
-                                      // direct solver object. When
-                                      // actually doing the solve, note
-                                      // that we don't pass a
-                                      // preconditioner. That wouldn't make
-                                      // much sense for a direct solver
-                                      // anyway.  At the end we return the
-                                      // solver control statistics &mdash;
-                                      // which will tell that no iterations
-                                      // have been performed and that the
-                                      // final linear residual is zero,
-                                      // absent any better information that
-                                      // may be provided here:
-      case Parameters::Solver::direct:
-      {
-       SolverControl solver_control (1,0);
-       TrilinosWrappers::SolverDirect direct (solver_control,
-                                              parameters.output ==
-                                              Parameters::Solver::verbose);
+                                  // @sect4{ConservationLaw::assemble_face_term}
+                                  //
+                                  // Here, we do essentially the same as in the
+                                  // previous function. t the top, we introduce
+                                  // the independent variables. Because the
+                                  // current function is also used if we are
+                                  // working on an internal face between two
+                                  // cells, the independent variables are not
+                                  // only the degrees of freedom on the current
+                                  // cell but in the case of an interior face
+                                  // also the ones on the neighbor.
+  template <int dim>
+  void
+  ConservationLaw<dim>::assemble_face_term(const unsigned int           face_no,
+                                          const FEFaceValuesBase<dim> &fe_v,
+                                          const FEFaceValuesBase<dim> &fe_v_neighbor,
+                                          const std::vector<unsigned int>   &dof_indices,
+                                          const std::vector<unsigned int>   &dof_indices_neighbor,
+                                          const bool                   external_face,
+                                          const unsigned int           boundary_id,
+                                          const double                 face_diameter)
+  {
+    const unsigned int n_q_points = fe_v.n_quadrature_points;
+    const unsigned int dofs_per_cell = fe_v.dofs_per_cell;
 
-       direct.solve (system_matrix, newton_update, right_hand_side);
+    std::vector<Sacado::Fad::DFad<double> >
+      independent_local_dof_values (dofs_per_cell),
+      independent_neighbor_dof_values (external_face == false ?
+                                      dofs_per_cell :
+                                      0);
 
-       return std::pair<unsigned int, double> (solver_control.last_step(),
-                                               solver_control.last_value());
-      }
+    const unsigned int n_independent_variables = (external_face == false ?
+                                                 2 * dofs_per_cell :
+                                                 dofs_per_cell);
 
-                                      // Likewise, if we are to use an
-                                      // iterative solver, we use Aztec's
-                                      // GMRES solver. We could use the
-                                      // Trilinos wrapper classes for
-                                      // iterative solvers and
-                                      // preconditioners here as well, but
-                                      // we choose to use an Aztec solver
-                                      // directly. For the given problem,
-                                      // Aztec's internal preconditioner
-                                      // implementations are superior over
-                                      // the ones deal.II has wrapper
-                                      // classes to, so we use ILU-T
-                                      // preconditioning within the AztecOO
-                                      // solver and set a bunch of options
-                                      // that can be changed from the
-                                      // parameter file.
-                                      //
-                                       // There are two more practicalities:
-                                      // Since we have built our right hand
-                                      // side and solution vector as
-                                      // deal.II Vector objects (as opposed
-                                      // to the matrix, which is a Trilinos
-                                      // object), we must hand the solvers
-                                      // Trilinos Epetra vectors.  Luckily,
-                                      // they support the concept of a
-                                      // 'view', so we just send in a
-                                      // pointer to our deal.II vectors. We
-                                      // have to provide an Epetra_Map for
-                                      // the vector that sets the parallel
-                                      // distribution, which is just a
-                                      // dummy object in serial. The
-                                      // easiest way is to ask the matrix
-                                      // for its map, and we're going to be
-                                      // ready for matrix-vector products
-                                      // with it.
-                                      //
-                                      // Secondly, the Aztec solver wants
-                                      // us to pass a Trilinos
-                                      // Epetra_CrsMatrix in, not the
-                                      // deal.II wrapper class itself. So
-                                      // we access to the actual Trilinos
-                                      // matrix in the Trilinos wrapper
-                                      // class by the command
-                                      // trilinos_matrix(). Trilinos wants
-                                      // the matrix to be non-constant, so
-                                      // we have to manually remove the
-                                      // constantness using a const_cast.
-      case Parameters::Solver::gmres:
+    for (unsigned int i = 0; i < dofs_per_cell; i++)
       {
-       Epetra_Vector x(View, system_matrix.domain_partitioner(),
-                       newton_update.begin());
-       Epetra_Vector b(View, system_matrix.range_partitioner(),
-                       right_hand_side.begin());
-
-       AztecOO solver;
-       solver.SetAztecOption(AZ_output,
-                             (parameters.output ==
-                              Parameters::Solver::quiet
-                              ?
-                              AZ_none
-                              :
-                              AZ_all));
-       solver.SetAztecOption(AZ_solver, AZ_gmres);
-       solver.SetRHS(&b);
-       solver.SetLHS(&x);
-
-       solver.SetAztecOption(AZ_precond,         AZ_dom_decomp);
-       solver.SetAztecOption(AZ_subdomain_solve, AZ_ilut);
-       solver.SetAztecOption(AZ_overlap,         0);
-       solver.SetAztecOption(AZ_reorder,         0);
+       independent_local_dof_values[i] = current_solution(dof_indices[i]);
+       independent_local_dof_values[i].diff(i, n_independent_variables);
+      }
 
-       solver.SetAztecParam(AZ_drop,      parameters.ilut_drop);
-       solver.SetAztecParam(AZ_ilut_fill, parameters.ilut_fill);
-       solver.SetAztecParam(AZ_athresh,   parameters.ilut_atol);
-       solver.SetAztecParam(AZ_rthresh,   parameters.ilut_rtol);
+    if (external_face == false)
+      for (unsigned int i = 0; i < dofs_per_cell; i++)
+       {
+         independent_neighbor_dof_values[i]
+           = current_solution(dof_indices_neighbor[i]);
+         independent_neighbor_dof_values[i]
+           .diff(i+dofs_per_cell, n_independent_variables);
+       }
 
-       solver.SetUserMatrix(const_cast<Epetra_CrsMatrix*>
-                            (&system_matrix.trilinos_matrix()));
 
-       solver.Iterate(parameters.max_iterations, parameters.linear_residual);
+                                    // Next, we need to define the values of
+                                    // the conservative variables $\tilde
+                                    // {\mathbf W}$ on this side of the face
+                                    // ($\tilde {\mathbf W}^+$) and on the
+                                    // opposite side ($\tilde {\mathbf
+                                    // W}^-$). The former can be computed in
+                                    // exactly the same way as in the previous
+                                    // function, but note that the
+                                    // <code>fe_v</code> variable now is of
+                                    // type FEFaceValues or FESubfaceValues:
+    Table<2,Sacado::Fad::DFad<double> >
+      Wplus (n_q_points, EulerEquations<dim>::n_components),
+      Wminus (n_q_points, EulerEquations<dim>::n_components);
+
+    for (unsigned int q=0; q<n_q_points; ++q)
+      for (unsigned int i=0; i<dofs_per_cell; ++i)
+       {
+         const unsigned int component_i = fe_v.get_fe().system_to_component_index(i).first;
+         Wplus[q][component_i] += (parameters.theta *
+                                   independent_local_dof_values[i]
+                                   +
+                                   (1.0-parameters.theta) *
+                                   old_solution(dof_indices[i])) *
+                                  fe_v.shape_value_component(i, q, component_i);
+       }
 
-       return std::pair<unsigned int, double> (solver.NumIters(),
-                                               solver.TrueResidual());
+                                    // Computing $\tilde {\mathbf W}^-$ is a
+                                    // bit more complicated. If this is an
+                                    // internal face, we can compute it as
+                                    // above by simply using the independent
+                                    // variables from the neighbor:
+    if (external_face == false)
+      {
+       for (unsigned int q=0; q<n_q_points; ++q)
+         for (unsigned int i=0; i<dofs_per_cell; ++i)
+           {
+             const unsigned int component_i = fe_v_neighbor.get_fe().
+                                              system_to_component_index(i).first;
+             Wminus[q][component_i] += (parameters.theta *
+                                        independent_neighbor_dof_values[i]
+                                        +
+                                        (1.0-parameters.theta) *
+                                        old_solution(dof_indices_neighbor[i]))*
+                                       fe_v_neighbor.shape_value_component(i, q, component_i);
+           }
+      }
+                                    // On the other hand, if this is an
+                                    // external boundary face, then the values
+                                    // of $W^-$ will be either functions of
+                                    // $W^+$, or they will be prescribed,
+                                    // depending on the kind of boundary
+                                    // condition imposed here.
+                                    //
+                                    // To start the evaluation, let us ensure
+                                    // that the boundary id specified for this
+                                    // boundary is one for which we actually
+                                    // have data in the parameters
+                                    // object. Next, we evaluate the function
+                                    // object for the inhomogeneity.  This is a
+                                    // bit tricky: a given boundary might have
+                                    // both prescribed and implicit values.  If
+                                    // a particular component is not
+                                    // prescribed, the values evaluate to zero
+                                    // and are ignored below.
+                                    //
+                                    // The rest is done by a function that
+                                    // actually knows the specifics of Euler
+                                    // equation boundary conditions. Note that
+                                    // since we are using fad variables here,
+                                    // sensitivities will be updated
+                                    // appropriately, a process that would
+                                    // otherwise be tremendously complicated.
+    else
+      {
+       Assert (boundary_id < Parameters::AllParameters<dim>::max_n_boundaries,
+               ExcIndexRange (boundary_id, 0,
+                              Parameters::AllParameters<dim>::max_n_boundaries));
+
+       std::vector<Vector<double> >
+         boundary_values(n_q_points, Vector<double>(EulerEquations<dim>::n_components));
+       parameters.boundary_conditions[boundary_id]
+         .values.vector_value_list(fe_v.get_quadrature_points(),
+                                   boundary_values);
+
+       for (unsigned int q = 0; q < n_q_points; q++)
+         EulerEquations<dim>::compute_Wminus (parameters.boundary_conditions[boundary_id].kind,
+                                              fe_v.normal_vector(q),
+                                              Wplus[q],
+                                              boundary_values[q],
+                                              Wminus[q]);
       }
-    }
 
-  Assert (false, ExcNotImplemented());
-  return std::pair<unsigned int, double> (0,0);
-}
 
+                                    // Now that we have $\mathbf w^+$ and
+                                    // $\mathbf w^-$, we can go about computing
+                                    // the numerical flux function $\mathbf
+                                    // H(\mathbf w^+,\mathbf w^-, \mathbf n)$
+                                    // for each quadrature point. Before
+                                    // calling the function that does so, we
+                                    // also need to determine the
+                                    // Lax-Friedrich's stability parameter:
+    typedef Sacado::Fad::DFad<double> NormalFlux[EulerEquations<dim>::n_components];
+    NormalFlux *normal_fluxes = new NormalFlux[n_q_points];
 
-                                 // @sect4{ConservationLaw::compute_refinement_indicators}
+    double alpha;
 
-                                // This function is real simple: We don't
-                                // pretend that we know here what a good
-                                // refinement indicator would be. Rather, we
-                                // assume that the <code>EulerEquation</code>
-                                // class would know about this, and so we
-                                // simply defer to the respective function
-                                // we've implemented there:
-template <int dim>
-void
-ConservationLaw<dim>::
-compute_refinement_indicators (Vector<double> &refinement_indicators) const
-{
-  EulerEquations<dim>::compute_refinement_indicators (dof_handler,
-                                                     mapping,
-                                                     predictor,
-                                                     refinement_indicators);
-}
+    switch(parameters.stabilization_kind)
+      {
+       case Parameters::Flux::constant:
+             alpha = parameters.stabilization_value;
+             break;
+       case Parameters::Flux::mesh_dependent:
+             alpha = face_diameter/(2.0*parameters.time_step);
+             break;
+       default:
+             Assert (false, ExcNotImplemented());
+             alpha = 1;
+      }
 
+    for (unsigned int q=0; q<n_q_points; ++q)
+      EulerEquations<dim>::numerical_normal_flux(fe_v.normal_vector(q),
+                                                Wplus[q], Wminus[q], alpha,
+                                                normal_fluxes[q]);
+
+                                    // Now assemble the face term in exactly
+                                    // the same way as for the cell
+                                    // contributions in the previous
+                                    // function. The only difference is that if
+                                    // this is an internal face, we also have
+                                    // to take into account the sensitivies of
+                                    // the residual contributions to the
+                                    // degrees of freedom on the neighboring
+                                    // cell:
+    std::vector<double> residual_derivatives (dofs_per_cell);
+    for (unsigned int i=0; i<fe_v.dofs_per_cell; ++i)
+      if (fe_v.get_fe().has_support_on_face(i, face_no) == true)
+       {
+         Sacado::Fad::DFad<double> F_i = 0;
 
+         for (unsigned int point=0; point<n_q_points; ++point)
+           {
+             const unsigned int
+               component_i = fe_v.get_fe().system_to_component_index(i).first;
 
-                                 // @sect4{ConservationLaw::refine_grid}
+             F_i += normal_fluxes[point][component_i] *
+                    fe_v.shape_value_component(i, point, component_i) *
+                    fe_v.JxW(point);
+           }
 
-                                // Here, we use the refinement indicators
-                                // computed before and refine the mesh. At
-                                // the beginning, we loop over all cells and
-                                // mark those that we think should be
-                                // refined:
-template <int dim>
-void
-ConservationLaw<dim>::refine_grid (const Vector<double> &refinement_indicators)
-{
-  typename DoFHandler<dim>::active_cell_iterator
-    cell = dof_handler.begin_active(),
-    endc = dof_handler.end();
+         for (unsigned int k=0; k<dofs_per_cell; ++k)
+           residual_derivatives[k] = F_i.fastAccessDx(k);
+         system_matrix.add(dof_indices[i], dof_indices, residual_derivatives);
 
-  for (unsigned int cell_no=0; cell!=endc; ++cell, ++cell_no)
-    {
-      cell->clear_coarsen_flag();
-      cell->clear_refine_flag();
+         if (external_face == false)
+           {
+             for (unsigned int k=0; k<dofs_per_cell; ++k)
+               residual_derivatives[k] = F_i.fastAccessDx(dofs_per_cell+k);
+             system_matrix.add (dof_indices[i], dof_indices_neighbor,
+                                residual_derivatives);
+           }
 
-      if ((cell->level() < parameters.shock_levels) &&
-         (std::fabs(refinement_indicators(cell_no)) > parameters.shock_val))
-       cell->set_refine_flag();
-      else
-       if ((cell->level() > 0) &&
-           (std::fabs(refinement_indicators(cell_no)) < 0.75*parameters.shock_val))
-         cell->set_coarsen_flag();
-    }
+         right_hand_side(dof_indices[i]) -= F_i.val();
+       }
 
-                                  // Then we need to transfer the
-                                  // various solution vectors from
-                                  // the old to the new grid while we
-                                  // do the refinement. The
-                                  // SolutionTransfer class is our
-                                  // friend here; it has a fairly
-                                  // extensive documentation,
-                                  // including examples, so we won't
-                                  // comment much on the following
-                                  // code. The last three lines
-                                  // simply re-set the sizes of some
-                                  // other vectors to the now correct
-                                  // size:
-  std::vector<Vector<double> > transfer_in;
-  std::vector<Vector<double> > transfer_out;
+    delete[] normal_fluxes;
+  }
 
-  transfer_in.push_back(old_solution);
-  transfer_in.push_back(predictor);
 
-  triangulation.prepare_coarsening_and_refinement();
+                                  // @sect4{ConservationLaw::solve}
+                                  //
+                                  // Here, we actually solve the linear system,
+                                  // using either of Trilinos' Aztec or Amesos
+                                  // linear solvers. The result of the
+                                  // computation will be written into the
+                                  // argument vector passed to this
+                                  // function. The result is a pair of number
+                                  // of iterations and the final linear
+                                  // residual.
 
-  SolutionTransfer<dim> soltrans(dof_handler);
-  soltrans.prepare_for_coarsening_and_refinement(transfer_in);
+  template <int dim>
+  std::pair<unsigned int, double>
+  ConservationLaw<dim>::solve (Vector<double> &newton_update)
+  {
+    switch (parameters.solver)
+      {
+                                        // If the parameter file specified
+                                        // that a direct solver shall be
+                                        // used, then we'll get here. The
+                                        // process is straightforward, since
+                                        // deal.II provides a wrapper class
+                                        // to the Amesos direct solver within
+                                        // Trilinos. All we have to do is to
+                                        // create a solver control object
+                                        // (which is just a dummy object
+                                        // here, since we won't perform any
+                                        // iterations), and then create the
+                                        // direct solver object. When
+                                        // actually doing the solve, note
+                                        // that we don't pass a
+                                        // preconditioner. That wouldn't make
+                                        // much sense for a direct solver
+                                        // anyway.  At the end we return the
+                                        // solver control statistics &mdash;
+                                        // which will tell that no iterations
+                                        // have been performed and that the
+                                        // final linear residual is zero,
+                                        // absent any better information that
+                                        // may be provided here:
+       case Parameters::Solver::direct:
+       {
+         SolverControl solver_control (1,0);
+         TrilinosWrappers::SolverDirect direct (solver_control,
+                                                parameters.output ==
+                                                Parameters::Solver::verbose);
 
-  triangulation.execute_coarsening_and_refinement ();
+         direct.solve (system_matrix, newton_update, right_hand_side);
 
-  dof_handler.clear();
-  dof_handler.distribute_dofs (fe);
+         return std::pair<unsigned int, double> (solver_control.last_step(),
+                                                 solver_control.last_value());
+       }
 
-  {
-    Vector<double> new_old_solution(1);
-    Vector<double> new_predictor(1);
+                                        // Likewise, if we are to use an
+                                        // iterative solver, we use Aztec's
+                                        // GMRES solver. We could use the
+                                        // Trilinos wrapper classes for
+                                        // iterative solvers and
+                                        // preconditioners here as well, but
+                                        // we choose to use an Aztec solver
+                                        // directly. For the given problem,
+                                        // Aztec's internal preconditioner
+                                        // implementations are superior over
+                                        // the ones deal.II has wrapper
+                                        // classes to, so we use ILU-T
+                                        // preconditioning within the AztecOO
+                                        // solver and set a bunch of options
+                                        // that can be changed from the
+                                        // parameter file.
+                                        //
+                                        // There are two more practicalities:
+                                        // Since we have built our right hand
+                                        // side and solution vector as
+                                        // deal.II Vector objects (as opposed
+                                        // to the matrix, which is a Trilinos
+                                        // object), we must hand the solvers
+                                        // Trilinos Epetra vectors.  Luckily,
+                                        // they support the concept of a
+                                        // 'view', so we just send in a
+                                        // pointer to our deal.II vectors. We
+                                        // have to provide an Epetra_Map for
+                                        // the vector that sets the parallel
+                                        // distribution, which is just a
+                                        // dummy object in serial. The
+                                        // easiest way is to ask the matrix
+                                        // for its map, and we're going to be
+                                        // ready for matrix-vector products
+                                        // with it.
+                                        //
+                                        // Secondly, the Aztec solver wants
+                                        // us to pass a Trilinos
+                                        // Epetra_CrsMatrix in, not the
+                                        // deal.II wrapper class itself. So
+                                        // we access to the actual Trilinos
+                                        // matrix in the Trilinos wrapper
+                                        // class by the command
+                                        // trilinos_matrix(). Trilinos wants
+                                        // the matrix to be non-constant, so
+                                        // we have to manually remove the
+                                        // constantness using a const_cast.
+       case Parameters::Solver::gmres:
+       {
+         Epetra_Vector x(View, system_matrix.domain_partitioner(),
+                         newton_update.begin());
+         Epetra_Vector b(View, system_matrix.range_partitioner(),
+                         right_hand_side.begin());
+
+         AztecOO solver;
+         solver.SetAztecOption(AZ_output,
+                               (parameters.output ==
+                                Parameters::Solver::quiet
+                                ?
+                                AZ_none
+                                :
+                                AZ_all));
+         solver.SetAztecOption(AZ_solver, AZ_gmres);
+         solver.SetRHS(&b);
+         solver.SetLHS(&x);
+
+         solver.SetAztecOption(AZ_precond,         AZ_dom_decomp);
+         solver.SetAztecOption(AZ_subdomain_solve, AZ_ilut);
+         solver.SetAztecOption(AZ_overlap,         0);
+         solver.SetAztecOption(AZ_reorder,         0);
+
+         solver.SetAztecParam(AZ_drop,      parameters.ilut_drop);
+         solver.SetAztecParam(AZ_ilut_fill, parameters.ilut_fill);
+         solver.SetAztecParam(AZ_athresh,   parameters.ilut_atol);
+         solver.SetAztecParam(AZ_rthresh,   parameters.ilut_rtol);
+
+         solver.SetUserMatrix(const_cast<Epetra_CrsMatrix*>
+                              (&system_matrix.trilinos_matrix()));
+
+         solver.Iterate(parameters.max_iterations, parameters.linear_residual);
+
+         return std::pair<unsigned int, double> (solver.NumIters(),
+                                                 solver.TrueResidual());
+       }
+      }
 
-    transfer_out.push_back(new_old_solution);
-    transfer_out.push_back(new_predictor);
-    transfer_out[0].reinit(dof_handler.n_dofs());
-    transfer_out[1].reinit(dof_handler.n_dofs());
+    Assert (false, ExcNotImplemented());
+    return std::pair<unsigned int, double> (0,0);
   }
 
-  soltrans.interpolate(transfer_in, transfer_out);
 
-  old_solution.reinit (transfer_out[0].size());
-  old_solution = transfer_out[0];
+                                  // @sect4{ConservationLaw::compute_refinement_indicators}
 
-  predictor.reinit (transfer_out[1].size());
-  predictor = transfer_out[1];
+                                  // This function is real simple: We don't
+                                  // pretend that we know here what a good
+                                  // refinement indicator would be. Rather, we
+                                  // assume that the <code>EulerEquation</code>
+                                  // class would know about this, and so we
+                                  // simply defer to the respective function
+                                  // we've implemented there:
+  template <int dim>
+  void
+  ConservationLaw<dim>::
+  compute_refinement_indicators (Vector<double> &refinement_indicators) const
+  {
+    EulerEquations<dim>::compute_refinement_indicators (dof_handler,
+                                                       mapping,
+                                                       predictor,
+                                                       refinement_indicators);
+  }
 
-  current_solution.reinit(dof_handler.n_dofs());
-  current_solution = old_solution;
-  right_hand_side.reinit (dof_handler.n_dofs());
-}
 
 
-                                 // @sect4{ConservationLaw::output_results}
-
-                                // This function now is rather
-                                // straightforward. All the magic, including
-                                // transforming data from conservative
-                                // variables to physical ones has been
-                                // abstracted and moved into the
-                                // EulerEquations class so that it can be
-                                // replaced in case we want to solve some
-                                // other hyperbolic conservation law.
-                                //
-                                // Note that the number of the output file is
-                                // determined by keeping a counter in the
-                                // form of a static variable that is set to
-                                // zero the first time we come to this
-                                // function and is incremented by one at the
-                                // end of each invokation.
-template <int dim>
-void ConservationLaw<dim>::output_results () const
-{
-  typename EulerEquations<dim>::Postprocessor
-    postprocessor (parameters.schlieren_plot);
+                                  // @sect4{ConservationLaw::refine_grid}
 
-  DataOut<dim> data_out;
-  data_out.attach_dof_handler (dof_handler);
+                                  // Here, we use the refinement indicators
+                                  // computed before and refine the mesh. At
+                                  // the beginning, we loop over all cells and
+                                  // mark those that we think should be
+                                  // refined:
+  template <int dim>
+  void
+  ConservationLaw<dim>::refine_grid (const Vector<double> &refinement_indicators)
+  {
+    typename DoFHandler<dim>::active_cell_iterator
+      cell = dof_handler.begin_active(),
+      endc = dof_handler.end();
 
-  data_out.add_data_vector (current_solution,
-                           EulerEquations<dim>::component_names (),
-                           DataOut<dim>::type_dof_data,
-                           EulerEquations<dim>::component_interpretation ());
+    for (unsigned int cell_no=0; cell!=endc; ++cell, ++cell_no)
+      {
+       cell->clear_coarsen_flag();
+       cell->clear_refine_flag();
 
-  data_out.add_data_vector (current_solution, postprocessor);
+       if ((cell->level() < parameters.shock_levels) &&
+           (std::fabs(refinement_indicators(cell_no)) > parameters.shock_val))
+         cell->set_refine_flag();
+       else
+         if ((cell->level() > 0) &&
+             (std::fabs(refinement_indicators(cell_no)) < 0.75*parameters.shock_val))
+           cell->set_coarsen_flag();
+      }
 
-  data_out.build_patches ();
+                                    // Then we need to transfer the
+                                    // various solution vectors from
+                                    // the old to the new grid while we
+                                    // do the refinement. The
+                                    // SolutionTransfer class is our
+                                    // friend here; it has a fairly
+                                    // extensive documentation,
+                                    // including examples, so we won't
+                                    // comment much on the following
+                                    // code. The last three lines
+                                    // simply re-set the sizes of some
+                                    // other vectors to the now correct
+                                    // size:
+    std::vector<Vector<double> > transfer_in;
+    std::vector<Vector<double> > transfer_out;
 
-  static unsigned int output_file_number = 0;
-  std::string filename = "solution-" +
-                        Utilities::int_to_string (output_file_number, 3) +
-                        ".vtk";
-  std::ofstream output (filename.c_str());
-  data_out.write_vtk (output);
+    transfer_in.push_back(old_solution);
+    transfer_in.push_back(predictor);
 
-  ++output_file_number;
-}
+    triangulation.prepare_coarsening_and_refinement();
 
+    SolutionTransfer<dim> soltrans(dof_handler);
+    soltrans.prepare_for_coarsening_and_refinement(transfer_in);
 
+    triangulation.execute_coarsening_and_refinement ();
 
+    dof_handler.clear();
+    dof_handler.distribute_dofs (fe);
 
-                                 // @sect4{ConservationLaw::run}
+    {
+      Vector<double> new_old_solution(1);
+      Vector<double> new_predictor(1);
 
-                                // This function contains the top-level logic
-                                // of this program: initialization, the time
-                                // loop, and the inner Newton iteration.
-                                //
-                                // At the beginning, we read the mesh file
-                                // specified by the parameter file, setup the
-                                // DoFHandler and various vectors, and then
-                                // interpolate the given initial conditions
-                                // on this mesh. We then perform a number of
-                                // mesh refinements, based on the initial
-                                // conditions, to obtain a mesh that is
-                                // already well adapted to the starting
-                                // solution. At the end of this process, we
-                                // output the initial solution.
-template <int dim>
-void ConservationLaw<dim>::run ()
-{
-  {
-    GridIn<dim> grid_in;
-    grid_in.attach_triangulation(triangulation);
+      transfer_out.push_back(new_old_solution);
+      transfer_out.push_back(new_predictor);
+      transfer_out[0].reinit(dof_handler.n_dofs());
+      transfer_out[1].reinit(dof_handler.n_dofs());
+    }
 
-    std::ifstream input_file(parameters.mesh_filename.c_str());
-    Assert (input_file, ExcFileNotOpen(parameters.mesh_filename.c_str()));
+    soltrans.interpolate(transfer_in, transfer_out);
 
-    grid_in.read_ucd(input_file);
-  }
+    old_solution.reinit (transfer_out[0].size());
+    old_solution = transfer_out[0];
 
-  dof_handler.clear();
-  dof_handler.distribute_dofs (fe);
+    predictor.reinit (transfer_out[1].size());
+    predictor = transfer_out[1];
 
-                                   // Size all of the fields.
-  old_solution.reinit (dof_handler.n_dofs());
-  current_solution.reinit (dof_handler.n_dofs());
-  predictor.reinit (dof_handler.n_dofs());
-  right_hand_side.reinit (dof_handler.n_dofs());
+    current_solution.reinit(dof_handler.n_dofs());
+    current_solution = old_solution;
+    right_hand_side.reinit (dof_handler.n_dofs());
+  }
 
-  setup_system();
 
-  VectorTools::interpolate(dof_handler,
-                           parameters.initial_conditions, old_solution);
-  current_solution = old_solution;
-  predictor = old_solution;
+                                  // @sect4{ConservationLaw::output_results}
 
-  if (parameters.do_refine == true)
-    for (unsigned int i=0; i<parameters.shock_levels; ++i)
-      {
-       Vector<double> refinement_indicators (triangulation.n_active_cells());
+                                  // This function now is rather
+                                  // straightforward. All the magic, including
+                                  // transforming data from conservative
+                                  // variables to physical ones has been
+                                  // abstracted and moved into the
+                                  // EulerEquations class so that it can be
+                                  // replaced in case we want to solve some
+                                  // other hyperbolic conservation law.
+                                  //
+                                  // Note that the number of the output file is
+                                  // determined by keeping a counter in the
+                                  // form of a static variable that is set to
+                                  // zero the first time we come to this
+                                  // function and is incremented by one at the
+                                  // end of each invokation.
+  template <int dim>
+  void ConservationLaw<dim>::output_results () const
+  {
+    typename EulerEquations<dim>::Postprocessor
+      postprocessor (parameters.schlieren_plot);
 
-       compute_refinement_indicators(refinement_indicators);
-       refine_grid(refinement_indicators);
+    DataOut<dim> data_out;
+    data_out.attach_dof_handler (dof_handler);
 
-       setup_system();
+    data_out.add_data_vector (current_solution,
+                             EulerEquations<dim>::component_names (),
+                             DataOut<dim>::type_dof_data,
+                             EulerEquations<dim>::component_interpretation ());
 
-       VectorTools::interpolate(dof_handler,
-                                parameters.initial_conditions, old_solution);
-       current_solution = old_solution;
-       predictor = old_solution;
-      }
+    data_out.add_data_vector (current_solution, postprocessor);
 
-  output_results ();
+    data_out.build_patches ();
 
-                                  // We then enter into the main time
-                                  // stepping loop. At the top we simply
-                                  // output some status information so one
-                                  // can keep track of where a computation
-                                  // is, as well as the header for a table
-                                  // that indicates progress of the nonlinear
-                                  // inner iteration:
-  Vector<double> newton_update (dof_handler.n_dofs());
+    static unsigned int output_file_number = 0;
+    std::string filename = "solution-" +
+                          Utilities::int_to_string (output_file_number, 3) +
+                          ".vtk";
+    std::ofstream output (filename.c_str());
+    data_out.write_vtk (output);
 
-  double time = 0;
-  double next_output = time + parameters.output_step;
+    ++output_file_number;
+  }
 
-  predictor = old_solution;
-  while (time < parameters.final_time)
-    {
-      std::cout << "T=" << time << std::endl
-               << "   Number of active cells:       "
-               << triangulation.n_active_cells()
-               << std::endl
-               << "   Number of degrees of freedom: "
-               << dof_handler.n_dofs()
-               << std::endl
-               << std::endl;
 
-      std::cout << "   NonLin Res     Lin Iter       Lin Res" << std::endl
-               << "   _____________________________________" << std::endl;
-
-                                      // Then comes the inner Newton
-                                      // iteration to solve the nonlinear
-                                      // problem in each time step. The way
-                                      // it works is to reset matrix and
-                                      // right hand side to zero, then
-                                      // assemble the linear system. If the
-                                      // norm of the right hand side is small
-                                      // enough, then we declare that the
-                                      // Newton iteration has
-                                      // converged. Otherwise, we solve the
-                                      // linear system, update the current
-                                      // solution with the Newton increment,
-                                      // and output convergence
-                                      // information. At the end, we check
-                                      // that the number of Newton iterations
-                                      // is not beyond a limit of 10 -- if it
-                                      // is, it appears likely that
-                                      // iterations are diverging and further
-                                      // iterations would do no good. If that
-                                      // happens, we throw an exception that
-                                      // will be caught in
-                                      // <code>main()</code> with status
-                                      // information being displayed before
-                                      // the program aborts.
-                                      //
-                                      // Note that the way we write the
-                                      // AssertThrow macro below is by and
-                                      // large equivalent to writing
-                                      // something like <code>if
-                                      // (!(nonlin_iter @<= 10)) throw
-                                      // ExcMessage ("No convergence in
-                                      // nonlinear solver");</code>. The only
-                                      // significant difference is that
-                                      // AssertThrow also makes sure that the
-                                      // exception being thrown carries with
-                                      // it information about the location
-                                      // (file name and line number) where it
-                                      // was generated. This is not overly
-                                      // critical here, because there is only
-                                      // a single place where this sort of
-                                      // exception can happen; however, it is
-                                      // generally a very useful tool when
-                                      // one wants to find out where an error
-                                      // occurred.
-      unsigned int nonlin_iter = 0;
-      current_solution = predictor;
-      while (true)
-       {
-         system_matrix = 0;
 
-         right_hand_side = 0;
-         assemble_system ();
 
-         const double res_norm = right_hand_side.l2_norm();
-         if (std::fabs(res_norm) < 1e-10)
-           {
-             std::printf("   %-16.3e (converged)\n\n", res_norm);
-             break;
-           }
-         else
-           {
-             newton_update = 0;
+                                  // @sect4{ConservationLaw::run}
 
-             std::pair<unsigned int, double> convergence
-               = solve (newton_update);
+                                  // This function contains the top-level logic
+                                  // of this program: initialization, the time
+                                  // loop, and the inner Newton iteration.
+                                  //
+                                  // At the beginning, we read the mesh file
+                                  // specified by the parameter file, setup the
+                                  // DoFHandler and various vectors, and then
+                                  // interpolate the given initial conditions
+                                  // on this mesh. We then perform a number of
+                                  // mesh refinements, based on the initial
+                                  // conditions, to obtain a mesh that is
+                                  // already well adapted to the starting
+                                  // solution. At the end of this process, we
+                                  // output the initial solution.
+  template <int dim>
+  void ConservationLaw<dim>::run ()
+  {
+    {
+      GridIn<dim> grid_in;
+      grid_in.attach_triangulation(triangulation);
 
-             current_solution += newton_update;
+      std::ifstream input_file(parameters.mesh_filename.c_str());
+      Assert (input_file, ExcFileNotOpen(parameters.mesh_filename.c_str()));
 
-             std::printf("   %-16.3e %04d        %-5.2e\n",
-                         res_norm, convergence.first, convergence.second);
-           }
+      grid_in.read_ucd(input_file);
+    }
 
-         ++nonlin_iter;
-         AssertThrow (nonlin_iter <= 10,
-                      ExcMessage ("No convergence in nonlinear solver"));
-       }
+    dof_handler.clear();
+    dof_handler.distribute_dofs (fe);
 
-                                      // We only get to this point if the
-                                      // Newton iteration has converged, so
-                                      // do various post convergence tasks
-                                      // here:
-                                      //
-                                      // First, we update the time
-                                      // and produce graphical output
-                                      // if so desired. Then we
-                                      // update a predictor for the
-                                      // solution at the next time
-                                      // step by approximating
-                                      // $\mathbf w^{n+1}\approx
-                                      // \mathbf w^n + \delta t
-                                      // \frac{\partial \mathbf
-                                      // w}{\partial t} \approx
-                                      // \mathbf w^n + \delta t \;
-                                      // \frac{\mathbf w^n-\mathbf
-                                      // w^{n-1}}{\delta t} = 2
-                                      // \mathbf w^n - \mathbf
-                                      // w^{n-1}$ to try and make
-                                      // adaptivity work better.  The
-                                      // idea is to try and refine
-                                      // ahead of a front, rather
-                                      // than stepping into a coarse
-                                      // set of elements and smearing
-                                      // the old_solution.  This
-                                      // simple time extrapolator
-                                      // does the job. With this, we
-                                      // then refine the mesh if so
-                                      // desired by the user, and
-                                      // finally continue on with the
-                                      // next time step:
-      time += parameters.time_step;
-
-      if (parameters.output_step < 0)
-       output_results ();
-      else if (time >= next_output)
-       {
-         output_results ();
-         next_output += parameters.output_step;
-       }
+                                    // Size all of the fields.
+    old_solution.reinit (dof_handler.n_dofs());
+    current_solution.reinit (dof_handler.n_dofs());
+    predictor.reinit (dof_handler.n_dofs());
+    right_hand_side.reinit (dof_handler.n_dofs());
 
-      predictor = current_solution;
-      predictor.sadd (2.0, -1.0, old_solution);
+    setup_system();
 
-      old_solution = current_solution;
+    VectorTools::interpolate(dof_handler,
+                            parameters.initial_conditions, old_solution);
+    current_solution = old_solution;
+    predictor = old_solution;
 
-      if (parameters.do_refine == true)
+    if (parameters.do_refine == true)
+      for (unsigned int i=0; i<parameters.shock_levels; ++i)
        {
          Vector<double> refinement_indicators (triangulation.n_active_cells());
-         compute_refinement_indicators(refinement_indicators);
 
+         compute_refinement_indicators(refinement_indicators);
          refine_grid(refinement_indicators);
+
          setup_system();
 
-         newton_update.reinit (dof_handler.n_dofs());
+         VectorTools::interpolate(dof_handler,
+                                  parameters.initial_conditions, old_solution);
+         current_solution = old_solution;
+         predictor = old_solution;
        }
-    }
+
+    output_results ();
+
+                                    // We then enter into the main time
+                                    // stepping loop. At the top we simply
+                                    // output some status information so one
+                                    // can keep track of where a computation
+                                    // is, as well as the header for a table
+                                    // that indicates progress of the nonlinear
+                                    // inner iteration:
+    Vector<double> newton_update (dof_handler.n_dofs());
+
+    double time = 0;
+    double next_output = time + parameters.output_step;
+
+    predictor = old_solution;
+    while (time < parameters.final_time)
+      {
+       std::cout << "T=" << time << std::endl
+                 << "   Number of active cells:       "
+                 << triangulation.n_active_cells()
+                 << std::endl
+                 << "   Number of degrees of freedom: "
+                 << dof_handler.n_dofs()
+                 << std::endl
+                 << std::endl;
+
+       std::cout << "   NonLin Res     Lin Iter       Lin Res" << std::endl
+                 << "   _____________________________________" << std::endl;
+
+                                        // Then comes the inner Newton
+                                        // iteration to solve the nonlinear
+                                        // problem in each time step. The way
+                                        // it works is to reset matrix and
+                                        // right hand side to zero, then
+                                        // assemble the linear system. If the
+                                        // norm of the right hand side is small
+                                        // enough, then we declare that the
+                                        // Newton iteration has
+                                        // converged. Otherwise, we solve the
+                                        // linear system, update the current
+                                        // solution with the Newton increment,
+                                        // and output convergence
+                                        // information. At the end, we check
+                                        // that the number of Newton iterations
+                                        // is not beyond a limit of 10 -- if it
+                                        // is, it appears likely that
+                                        // iterations are diverging and further
+                                        // iterations would do no good. If that
+                                        // happens, we throw an exception that
+                                        // will be caught in
+                                        // <code>main()</code> with status
+                                        // information being displayed before
+                                        // the program aborts.
+                                        //
+                                        // Note that the way we write the
+                                        // AssertThrow macro below is by and
+                                        // large equivalent to writing
+                                        // something like <code>if
+                                        // (!(nonlin_iter @<= 10)) throw
+                                        // ExcMessage ("No convergence in
+                                        // nonlinear solver");</code>. The only
+                                        // significant difference is that
+                                        // AssertThrow also makes sure that the
+                                        // exception being thrown carries with
+                                        // it information about the location
+                                        // (file name and line number) where it
+                                        // was generated. This is not overly
+                                        // critical here, because there is only
+                                        // a single place where this sort of
+                                        // exception can happen; however, it is
+                                        // generally a very useful tool when
+                                        // one wants to find out where an error
+                                        // occurred.
+       unsigned int nonlin_iter = 0;
+       current_solution = predictor;
+       while (true)
+         {
+           system_matrix = 0;
+
+           right_hand_side = 0;
+           assemble_system ();
+
+           const double res_norm = right_hand_side.l2_norm();
+           if (std::fabs(res_norm) < 1e-10)
+             {
+               std::printf("   %-16.3e (converged)\n\n", res_norm);
+               break;
+             }
+           else
+             {
+               newton_update = 0;
+
+               std::pair<unsigned int, double> convergence
+                 = solve (newton_update);
+
+               current_solution += newton_update;
+
+               std::printf("   %-16.3e %04d        %-5.2e\n",
+                           res_norm, convergence.first, convergence.second);
+             }
+
+           ++nonlin_iter;
+           AssertThrow (nonlin_iter <= 10,
+                        ExcMessage ("No convergence in nonlinear solver"));
+         }
+
+                                        // We only get to this point if the
+                                        // Newton iteration has converged, so
+                                        // do various post convergence tasks
+                                        // here:
+                                        //
+                                        // First, we update the time
+                                        // and produce graphical output
+                                        // if so desired. Then we
+                                        // update a predictor for the
+                                        // solution at the next time
+                                        // step by approximating
+                                        // $\mathbf w^{n+1}\approx
+                                        // \mathbf w^n + \delta t
+                                        // \frac{\partial \mathbf
+                                        // w}{\partial t} \approx
+                                        // \mathbf w^n + \delta t \;
+                                        // \frac{\mathbf w^n-\mathbf
+                                        // w^{n-1}}{\delta t} = 2
+                                        // \mathbf w^n - \mathbf
+                                        // w^{n-1}$ to try and make
+                                        // adaptivity work better.  The
+                                        // idea is to try and refine
+                                        // ahead of a front, rather
+                                        // than stepping into a coarse
+                                        // set of elements and smearing
+                                        // the old_solution.  This
+                                        // simple time extrapolator
+                                        // does the job. With this, we
+                                        // then refine the mesh if so
+                                        // desired by the user, and
+                                        // finally continue on with the
+                                        // next time step:
+       time += parameters.time_step;
+
+       if (parameters.output_step < 0)
+         output_results ();
+       else if (time >= next_output)
+         {
+           output_results ();
+           next_output += parameters.output_step;
+         }
+
+       predictor = current_solution;
+       predictor.sadd (2.0, -1.0, old_solution);
+
+       old_solution = current_solution;
+
+       if (parameters.do_refine == true)
+         {
+           Vector<double> refinement_indicators (triangulation.n_active_cells());
+           compute_refinement_indicators(refinement_indicators);
+
+           refine_grid(refinement_indicators);
+           setup_system();
+
+           newton_update.reinit (dof_handler.n_dofs());
+         }
+      }
+  }
 }
 
                                  // @sect3{main()}
@@ -3111,16 +3115,20 @@ void ConservationLaw<dim>::run ()
                                 // line.
 int main (int argc, char *argv[])
 {
-  deallog.depth_console(0);
-  if (argc != 2)
-    {
-      std::cout << "Usage:" << argv[0] << " input_file" << std::endl;
-      std::exit(1);
-    }
-
   try
     {
+      using namespace dealii;
+      using namespace Step33;
+
+      deallog.depth_console(0);
+      if (argc != 2)
+       {
+         std::cout << "Usage:" << argv[0] << " input_file" << std::endl;
+         std::exit(1);
+       }
+
       Utilities::System::MPI_InitFinalize mpi_initialization (argc, argv);
+
       ConservationLaw<2> cons (argv[1]);
       cons.run ();
     }
index 17e54a2782b0098c66307ff11c162896f052af4d..2090179ec2ce98009460c4cb48fe04198bc38059 100644 (file)
@@ -2,7 +2,7 @@
 //    $Id$
 //    Version: $Name$
 //
-//    Copyright (C) 2009, 2010 by the deal.II authors
+//    Copyright (C) 2009, 2010, 2011 by the deal.II authors
 //
 //    This file is subject to QPL and may not be  distributed
 //    without copyright and license information. Please refer
 
                                 // The last part of this preamble is to
                                 // import everything in the dealii namespace
-                                // into the global one for ease of use:
-using namespace dealii;
-
-
-                                // @sect3{Single and double layer operator kernels}
-
-                                // First, let us define a bit of the
-                                // boundary integral equation
-                                // machinery.
-
-                                // The following two functions are
-                                // the actual calculations of the
-                                // single and double layer potential
-                                // kernels, that is $G$ and $\nabla
-                                // G$. They are well defined only if
-                                // the vector $R =
-                                // \mathbf{y}-\mathbf{x}$ is
-                                // different from zero.
-namespace LaplaceKernel
+                                // into the one into which everything in this
+                                // program will go:
+namespace Step34
 {
-  template <int dim>
-  double single_layer(const Point<dim> &R)
-  {
-    switch(dim)
-      {
-      case 2:
-       return (-std::log(R.norm()) / (2*numbers::PI) );
-
-      case 3:
-       return (1./( R.norm()*4*numbers::PI ) );
+  using namespace dealii;
 
-      default:
-       Assert(false, ExcInternalError());
-       return 0.;
-      }
-  }
 
+                                  // @sect3{Single and double layer operator kernels}
 
+                                  // First, let us define a bit of the
+                                  // boundary integral equation
+                                  // machinery.
 
-  template <int dim>
-  Point<dim> double_layer(const Point<dim> &R)
+                                  // The following two functions are
+                                  // the actual calculations of the
+                                  // single and double layer potential
+                                  // kernels, that is $G$ and $\nabla
+                                  // G$. They are well defined only if
+                                  // the vector $R =
+                                  // \mathbf{y}-\mathbf{x}$ is
+                                  // different from zero.
+  namespace LaplaceKernel
   {
-    switch(dim)
-      {
-      case 2:
-       return R / ( -2*numbers::PI * R.square());
-      case 3:
-       return R / ( -4*numbers::PI * R.square() * R.norm() );
-
-      default:
-       Assert(false, ExcInternalError());
-       return Point<dim>();
-      }
-  }
-}
+    template <int dim>
+    double single_layer(const Point<dim> &R)
+    {
+      switch(dim)
+       {
+         case 2:
+               return (-std::log(R.norm()) / (2*numbers::PI) );
 
+         case 3:
+               return (1./( R.norm()*4*numbers::PI ) );
 
-                                // @sect3{The BEMProblem class}
-
-                                // The structure of a boundary
-                                // element method code is very
-                                // similar to the structure of a
-                                // finite element code, and so the
-                                // member functions of this class are
-                                // like those of most of the other
-                                // tutorial programs. In particular,
-                                // by now you should be familiar with
-                                // reading parameters from an
-                                // external file, and with the
-                                // splitting of the different tasks
-                                // into different modules. The same
-                                // applies to boundary element
-                                // methods, and we won't comment too
-                                // much on them, except on the
-                                // differences.
-template <int dim>
-class BEMProblem
-{
-  public:
-    BEMProblem(const unsigned int fe_degree = 1,
-              const unsigned int mapping_degree = 1);
-
-    void run();
+         default:
+               Assert(false, ExcInternalError());
+               return 0.;
+       }
+    }
 
-  private:
 
-    void read_parameters (const std::string &filename);
 
-    void read_domain();
+    template <int dim>
+    Point<dim> double_layer(const Point<dim> &R)
+    {
+      switch(dim)
+       {
+         case 2:
+               return R / ( -2*numbers::PI * R.square());
+         case 3:
+               return R / ( -4*numbers::PI * R.square() * R.norm() );
+
+         default:
+               Assert(false, ExcInternalError());
+               return Point<dim>();
+       }
+    }
+  }
 
-    void refine_and_resize();
 
-                                    // The only really different
-                                    // function that we find here is
-                                    // the assembly routine. We wrote
-                                    // this function in the most
-                                    // possible general way, in order
-                                    // to allow for easy
-                                    // generalization to higher order
-                                    // methods and to different
-                                    // fundamental solutions (e.g.,
-                                    // Stokes or Maxwell).
-                                    //
-                                    // The most noticeable difference
-                                    // is the fact that the final
-                                    // matrix is full, and that we
-                                    // have a nested loop inside the
-                                    // usual loop on cells that
-                                    // visits all support points of
-                                    // the degrees of freedom.
-                                    // Moreover, when the support
-                                    // point lies inside the cell
-                                    // which we are visiting, then
-                                    // the integral we perform
-                                    // becomes singular.
-                                    //
-                                    // The practical consequence is
-                                    // that we have two sets of
-                                    // quadrature formulas, finite
-                                    // element values and temporary
-                                    // storage, one for standard
-                                    // integration and one for the
-                                    // singular integration, which
-                                    // are used where necessary.
-    void assemble_system();
-
-                                    // There are two options for the
-                                    // solution of this problem. The
-                                    // first is to use a direct
-                                    // solver, and the second is to
-                                    // use an iterative solver. We
-                                    // opt for the second option.
-                                    //
-                                    // The matrix that we assemble is
-                                    // not symmetric, and we opt to
-                                    // use the GMRES method; however
-                                    // the construction of an
-                                    // efficient preconditioner for
-                                    // boundary element methods is
-                                    // not a trivial issue. Here we
-                                    // use a non preconditioned GMRES
-                                    // solver. The options for the
-                                    // iterative solver, such as the
-                                    // tolerance, the maximum number
-                                    // of iterations, are selected
-                                    // through the parameter file.
-    void solve_system();
-
-                                    // Once we obtained the solution,
-                                    // we compute the $L^2$ error of
-                                    // the computed potential as well
-                                    // as the $L^\infty$ error of the
-                                    // approximation of the solid
-                                    // angle. The mesh we are using
-                                    // is an approximation of a
-                                    // smooth curve, therefore the
-                                    // computed diagonal matrix of
-                                    // fraction of angles or solid
-                                    // angles $\alpha(\mathbf{x})$
-                                    // should be constantly equal to
-                                    // $\frac 12$. In this routine we
-                                    // output the error on the
-                                    // potential and the error in the
-                                    // approximation of the computed
-                                    // angle. Notice that the latter
-                                    // error is actually not the
-                                    // error in the computation of
-                                    // the angle, but a measure of
-                                    // how well we are approximating
-                                    // the sphere and the circle.
-                                    //
-                                    // Experimenting a little with
-                                    // the computation of the angles
-                                    // gives very accurate results
-                                    // for simpler geometries. To
-                                    // verify this you can comment
-                                    // out, in the read_domain()
-                                    // method, the
-                                    // tria.set_boundary(1, boundary)
-                                    // line, and check the alpha that
-                                    // is generated by the
-                                    // program. By removing this
-                                    // call, whenever the mesh is
-                                    // refined new nodes will be
-                                    // placed along the straight
-                                    // lines that made up the coarse
-                                    // mesh, rather than be pulled
-                                    // onto the surface that we
-                                    // really want to approximate. In
-                                    // the three dimensional case,
-                                    // the coarse grid of the sphere
-                                    // is obtained starting from a
-                                    // cube, and the obtained values
-                                    // of alphas are exactly $\frac
-                                    // 12$ on the nodes of the faces,
-                                    // $\frac 34$ on the nodes of the
-                                    // edges and $\frac 78$ on the 8
-                                    // nodes of the vertices.
-    void compute_errors(const unsigned int cycle);
-
-                                    // Once we obtained a solution on
-                                    // the codimension one domain, we
-                                    // want to interpolate it to the
-                                    // rest of the space. This is
-                                    // done by performing again the
-                                    // convolution of the solution
-                                    // with the kernel in the
-                                    // compute_exterior_solution()
-                                    // function.
-                                    //
-                                    // We would like to plot the
-                                    // velocity variable which is the
-                                    // gradient of the potential
-                                    // solution. The potential
-                                    // solution is only known on the
-                                    // boundary, but we use the
-                                    // convolution with the
-                                    // fundamental solution to
-                                    // interpolate it on a standard
-                                    // dim dimensional continuous
-                                    // finite element space. The plot
-                                    // of the gradient of the
-                                    // extrapolated solution will
-                                    // give us the velocity we want.
-                                    //
-                                    // In addition to the solution on
-                                    // the exterior domain, we also
-                                    // output the solution on the
-                                    // domain's boundary in the
-                                    // output_results() function, of
-                                    // course.
-    void compute_exterior_solution();
-
-    void output_results(const unsigned int cycle);
-
-                                    // To allow for dimension
-                                    // independent programming, we
-                                    // specialize this single
-                                    // function to extract the
-                                    // singular quadrature formula
-                                    // needed to integrate the
-                                    // singular kernels in the
-                                    // interior of the cells.
-    const Quadrature<dim-1> & get_singular_quadrature(
-      const typename DoFHandler<dim-1, dim>::active_cell_iterator &cell,
-      const unsigned int index) const;
-
-
-                                    // The usual deal.II classes can
-                                    // be used for boundary element
-                                    // methods by specifying the
-                                    // "codimension" of the
-                                    // problem. This is done by
-                                    // setting the optional second
-                                    // template arguments to
-                                    // Triangulation, FiniteElement
-                                    // and DoFHandler to the
-                                    // dimension of the embedding
-                                    // space. In our case we generate
-                                    // either 1 or 2 dimensional
-                                    // meshes embedded in 2 or 3
-                                    // dimensional spaces.
-                                    //
-                                    // The optional argument by
-                                    // default is equal to the first
-                                    // argument, and produces the
-                                    // usual finite element classes
-                                    // that we saw in all previous
-                                    // examples.
-                                    //
-                                    // The class is constructed in a
-                                    // way to allow for arbitrary
-                                    // order of approximation of both
-                                    // the domain (through high order
-                                    // mapping) and the finite
-                                    // element space. The order of
-                                    // the finite element space and
-                                    // of the mapping can be selected
-                                    // in the constructor of the class.
-
-    Triangulation<dim-1, dim>   tria;
-    FE_Q<dim-1,dim>             fe;
-    DoFHandler<dim-1,dim>       dh;
-    MappingQ<dim-1, dim>       mapping;
-
-                                    // In BEM methods, the matrix
-                                    // that is generated is
-                                    // dense. Depending on the size
-                                    // of the problem, the final
-                                    // system might be solved by
-                                    // direct LU decomposition, or by
-                                    // iterative methods. In this
-                                    // example we use an
-                                    // unpreconditioned GMRES
-                                    // method. Building a
-                                    // preconditioner for BEM method
-                                    // is non trivial, and we don't
-                                    // treat this subject here.
-
-    FullMatrix<double>    system_matrix;
-    Vector<double>        system_rhs;
-
-                                    // The next two variables will
-                                    // denote the solution $\phi$ as
-                                    // well as a vector that will
-                                    // hold the values of
-                                    // $\alpha(\mathbf x)$ (the
-                                    // fraction of $\Omega$ visible
-                                    // from a point $\mathbf x$) at
-                                    // the support points of our
-                                    // shape functions.
-
-    Vector<double>              phi;
-    Vector<double>              alpha;
-
-                                    // The convergence table is used
-                                    // to output errors in the exact
-                                    // solution and in the computed
-                                    // alphas.
-
-    ConvergenceTable   convergence_table;
-
-                                    // The following variables are
-                                    // the ones that we fill through
-                                    // a parameter file.  The new
-                                    // objects that we use in this
-                                    // example are the
-                                    // Functions::ParsedFunction
-                                    // object and the
-                                    // QuadratureSelector object.
-                                    //
-                                    // The Functions::ParsedFunction
-                                    // class allows us to easily and
-                                    // quickly define new function
-                                    // objects via parameter files,
-                                    // with custom definitions which
-                                    // can be very complex (see the
-                                    // documentation of that class
-                                    // for all the available
-                                    // options).
-                                    //
-                                    // We will allocate the
-                                    // quadrature object using the
-                                    // QuadratureSelector class that
-                                    // allows us to generate
-                                    // quadrature formulas based on
-                                    // an identifying string and on
-                                    // the possible degree of the
-                                    // formula itself. We used this
-                                    // to allow custom selection of
-                                    // the quadrature formulas for
-                                    // the standard integration, and
-                                    // to define the order of the
-                                    // singular quadrature rule.
-                                    //
-                                    // We also define a couple of
-                                    // parameters which are used in
-                                    // case we wanted to extend the
-                                    // solution to the entire domain.
-
-    Functions::ParsedFunction<dim> wind;
-    Functions::ParsedFunction<dim> exact_solution;
-
-    unsigned int singular_quadrature_order;
-    std_cxx1x::shared_ptr<Quadrature<dim-1> > quadrature;
-
-    SolverControl solver_control;
-
-    unsigned int n_cycles;
-    unsigned int external_refinement;
-
-    bool run_in_this_dimension;
-    bool extend_solution;
-};
-
-
-                                // @sect4{BEMProblem::BEMProblem and BEMProblem::read_parameters}
-
-                                // The constructor initializes the
-                                // variuous object in much the same
-                                // way as done in the finite element
-                                // programs such as step-4 or
-                                // step-6. The only new ingredient
-                                // here is the ParsedFunction object,
-                                // which needs, at construction time,
-                                // the specification of the number of
-                                // components.
-                                //
-                                // For the exact solution the number
-                                // of vector components is one, and
-                                // no action is required since one is
-                                // the default value for a
-                                // ParsedFunction object. The wind,
-                                // however, requires dim components
-                                // to be specified. Notice that when
-                                // declaring entries in a parameter
-                                // file for the expression of the
-                                // Functions::ParsedFunction, we need
-                                // to specify the number of
-                                // components explicitly, since the
-                                // function
-                                // Functions::ParsedFunction::declare_parameters
-                                // is static, and has no knowledge of
-                                // the number of components.
-template <int dim>
-BEMProblem<dim>::BEMProblem(const unsigned int fe_degree,
-                           const unsigned int mapping_degree)
-               :
-               fe(fe_degree),
-               dh(tria),
-               mapping(mapping_degree, true),
-               wind(dim)
-{}
-
-
-template <int dim>
-void BEMProblem<dim>::read_parameters (const std::string &filename)
-{
-  deallog << std::endl << "Parsing parameter file " << filename << std::endl
-         << "for a " << dim << " dimensional simulation. " << std::endl;
-
-  ParameterHandler prm;
-
-  prm.declare_entry("Number of cycles", "4",
-                   Patterns::Integer());
-  prm.declare_entry("External refinement", "5",
-                   Patterns::Integer());
-  prm.declare_entry("Extend solution on the -2,2 box", "true",
-                   Patterns::Bool());
-  prm.declare_entry("Run 2d simulation", "true",
-                   Patterns::Bool());
-  prm.declare_entry("Run 3d simulation", "true",
-                   Patterns::Bool());
-
-  prm.enter_subsection("Quadrature rules");
+                                  // @sect3{The BEMProblem class}
+
+                                  // The structure of a boundary
+                                  // element method code is very
+                                  // similar to the structure of a
+                                  // finite element code, and so the
+                                  // member functions of this class are
+                                  // like those of most of the other
+                                  // tutorial programs. In particular,
+                                  // by now you should be familiar with
+                                  // reading parameters from an
+                                  // external file, and with the
+                                  // splitting of the different tasks
+                                  // into different modules. The same
+                                  // applies to boundary element
+                                  // methods, and we won't comment too
+                                  // much on them, except on the
+                                  // differences.
+  template <int dim>
+  class BEMProblem
   {
-    prm.declare_entry("Quadrature type", "gauss",
-                     Patterns::Selection(QuadratureSelector<(dim-1)>::get_quadrature_names()));
-    prm.declare_entry("Quadrature order", "4", Patterns::Integer());
-    prm.declare_entry("Singular quadrature order", "5", Patterns::Integer());
-  }
-  prm.leave_subsection();
-
-                                  // For both two and three
-                                  // dimensions, we set the default
-                                  // input data to be such that the
-                                  // solution is $x+y$ or
-                                  // $x+y+z$. The actually computed
-                                  // solution will have value zero at
-                                  // infinity. In this case, this
-                                  // coincide with the exact
-                                  // solution, and no additional
-                                  // corrections are needed, but you
-                                  // should be aware of the fact that
-                                  // we arbitrarily set
-                                  // $\phi_\infty$, and the exact
-                                  // solution we pass to the program
-                                  // needs to have the same value at
-                                  // infinity for the error to be
-                                  // computed correctly.
+    public:
+      BEMProblem(const unsigned int fe_degree = 1,
+                const unsigned int mapping_degree = 1);
+
+      void run();
+
+    private:
+
+      void read_parameters (const std::string &filename);
+
+      void read_domain();
+
+      void refine_and_resize();
+
+                                      // The only really different
+                                      // function that we find here is
+                                      // the assembly routine. We wrote
+                                      // this function in the most
+                                      // possible general way, in order
+                                      // to allow for easy
+                                      // generalization to higher order
+                                      // methods and to different
+                                      // fundamental solutions (e.g.,
+                                      // Stokes or Maxwell).
+                                      //
+                                      // The most noticeable difference
+                                      // is the fact that the final
+                                      // matrix is full, and that we
+                                      // have a nested loop inside the
+                                      // usual loop on cells that
+                                      // visits all support points of
+                                      // the degrees of freedom.
+                                      // Moreover, when the support
+                                      // point lies inside the cell
+                                      // which we are visiting, then
+                                      // the integral we perform
+                                      // becomes singular.
+                                      //
+                                      // The practical consequence is
+                                      // that we have two sets of
+                                      // quadrature formulas, finite
+                                      // element values and temporary
+                                      // storage, one for standard
+                                      // integration and one for the
+                                      // singular integration, which
+                                      // are used where necessary.
+      void assemble_system();
+
+                                      // There are two options for the
+                                      // solution of this problem. The
+                                      // first is to use a direct
+                                      // solver, and the second is to
+                                      // use an iterative solver. We
+                                      // opt for the second option.
+                                      //
+                                      // The matrix that we assemble is
+                                      // not symmetric, and we opt to
+                                      // use the GMRES method; however
+                                      // the construction of an
+                                      // efficient preconditioner for
+                                      // boundary element methods is
+                                      // not a trivial issue. Here we
+                                      // use a non preconditioned GMRES
+                                      // solver. The options for the
+                                      // iterative solver, such as the
+                                      // tolerance, the maximum number
+                                      // of iterations, are selected
+                                      // through the parameter file.
+      void solve_system();
+
+                                      // Once we obtained the solution,
+                                      // we compute the $L^2$ error of
+                                      // the computed potential as well
+                                      // as the $L^\infty$ error of the
+                                      // approximation of the solid
+                                      // angle. The mesh we are using
+                                      // is an approximation of a
+                                      // smooth curve, therefore the
+                                      // computed diagonal matrix of
+                                      // fraction of angles or solid
+                                      // angles $\alpha(\mathbf{x})$
+                                      // should be constantly equal to
+                                      // $\frac 12$. In this routine we
+                                      // output the error on the
+                                      // potential and the error in the
+                                      // approximation of the computed
+                                      // angle. Notice that the latter
+                                      // error is actually not the
+                                      // error in the computation of
+                                      // the angle, but a measure of
+                                      // how well we are approximating
+                                      // the sphere and the circle.
+                                      //
+                                      // Experimenting a little with
+                                      // the computation of the angles
+                                      // gives very accurate results
+                                      // for simpler geometries. To
+                                      // verify this you can comment
+                                      // out, in the read_domain()
+                                      // method, the
+                                      // tria.set_boundary(1, boundary)
+                                      // line, and check the alpha that
+                                      // is generated by the
+                                      // program. By removing this
+                                      // call, whenever the mesh is
+                                      // refined new nodes will be
+                                      // placed along the straight
+                                      // lines that made up the coarse
+                                      // mesh, rather than be pulled
+                                      // onto the surface that we
+                                      // really want to approximate. In
+                                      // the three dimensional case,
+                                      // the coarse grid of the sphere
+                                      // is obtained starting from a
+                                      // cube, and the obtained values
+                                      // of alphas are exactly $\frac
+                                      // 12$ on the nodes of the faces,
+                                      // $\frac 34$ on the nodes of the
+                                      // edges and $\frac 78$ on the 8
+                                      // nodes of the vertices.
+      void compute_errors(const unsigned int cycle);
+
+                                      // Once we obtained a solution on
+                                      // the codimension one domain, we
+                                      // want to interpolate it to the
+                                      // rest of the space. This is
+                                      // done by performing again the
+                                      // convolution of the solution
+                                      // with the kernel in the
+                                      // compute_exterior_solution()
+                                      // function.
+                                      //
+                                      // We would like to plot the
+                                      // velocity variable which is the
+                                      // gradient of the potential
+                                      // solution. The potential
+                                      // solution is only known on the
+                                      // boundary, but we use the
+                                      // convolution with the
+                                      // fundamental solution to
+                                      // interpolate it on a standard
+                                      // dim dimensional continuous
+                                      // finite element space. The plot
+                                      // of the gradient of the
+                                      // extrapolated solution will
+                                      // give us the velocity we want.
+                                      //
+                                      // In addition to the solution on
+                                      // the exterior domain, we also
+                                      // output the solution on the
+                                      // domain's boundary in the
+                                      // output_results() function, of
+                                      // course.
+      void compute_exterior_solution();
+
+      void output_results(const unsigned int cycle);
+
+                                      // To allow for dimension
+                                      // independent programming, we
+                                      // specialize this single
+                                      // function to extract the
+                                      // singular quadrature formula
+                                      // needed to integrate the
+                                      // singular kernels in the
+                                      // interior of the cells.
+      const Quadrature<dim-1> & get_singular_quadrature(
+       const typename DoFHandler<dim-1, dim>::active_cell_iterator &cell,
+       const unsigned int index) const;
+
+
+                                      // The usual deal.II classes can
+                                      // be used for boundary element
+                                      // methods by specifying the
+                                      // "codimension" of the
+                                      // problem. This is done by
+                                      // setting the optional second
+                                      // template arguments to
+                                      // Triangulation, FiniteElement
+                                      // and DoFHandler to the
+                                      // dimension of the embedding
+                                      // space. In our case we generate
+                                      // either 1 or 2 dimensional
+                                      // meshes embedded in 2 or 3
+                                      // dimensional spaces.
+                                      //
+                                      // The optional argument by
+                                      // default is equal to the first
+                                      // argument, and produces the
+                                      // usual finite element classes
+                                      // that we saw in all previous
+                                      // examples.
+                                      //
+                                      // The class is constructed in a
+                                      // way to allow for arbitrary
+                                      // order of approximation of both
+                                      // the domain (through high order
+                                      // mapping) and the finite
+                                      // element space. The order of
+                                      // the finite element space and
+                                      // of the mapping can be selected
+                                      // in the constructor of the class.
+
+      Triangulation<dim-1, dim>   tria;
+      FE_Q<dim-1,dim>             fe;
+      DoFHandler<dim-1,dim>       dh;
+      MappingQ<dim-1, dim>     mapping;
+
+                                      // In BEM methods, the matrix
+                                      // that is generated is
+                                      // dense. Depending on the size
+                                      // of the problem, the final
+                                      // system might be solved by
+                                      // direct LU decomposition, or by
+                                      // iterative methods. In this
+                                      // example we use an
+                                      // unpreconditioned GMRES
+                                      // method. Building a
+                                      // preconditioner for BEM method
+                                      // is non trivial, and we don't
+                                      // treat this subject here.
+
+      FullMatrix<double>    system_matrix;
+      Vector<double>        system_rhs;
+
+                                      // The next two variables will
+                                      // denote the solution $\phi$ as
+                                      // well as a vector that will
+                                      // hold the values of
+                                      // $\alpha(\mathbf x)$ (the
+                                      // fraction of $\Omega$ visible
+                                      // from a point $\mathbf x$) at
+                                      // the support points of our
+                                      // shape functions.
+
+      Vector<double>              phi;
+      Vector<double>              alpha;
+
+                                      // The convergence table is used
+                                      // to output errors in the exact
+                                      // solution and in the computed
+                                      // alphas.
+
+      ConvergenceTable convergence_table;
+
+                                      // The following variables are
+                                      // the ones that we fill through
+                                      // a parameter file.  The new
+                                      // objects that we use in this
+                                      // example are the
+                                      // Functions::ParsedFunction
+                                      // object and the
+                                      // QuadratureSelector object.
+                                      //
+                                      // The Functions::ParsedFunction
+                                      // class allows us to easily and
+                                      // quickly define new function
+                                      // objects via parameter files,
+                                      // with custom definitions which
+                                      // can be very complex (see the
+                                      // documentation of that class
+                                      // for all the available
+                                      // options).
+                                      //
+                                      // We will allocate the
+                                      // quadrature object using the
+                                      // QuadratureSelector class that
+                                      // allows us to generate
+                                      // quadrature formulas based on
+                                      // an identifying string and on
+                                      // the possible degree of the
+                                      // formula itself. We used this
+                                      // to allow custom selection of
+                                      // the quadrature formulas for
+                                      // the standard integration, and
+                                      // to define the order of the
+                                      // singular quadrature rule.
+                                      //
+                                      // We also define a couple of
+                                      // parameters which are used in
+                                      // case we wanted to extend the
+                                      // solution to the entire domain.
+
+      Functions::ParsedFunction<dim> wind;
+      Functions::ParsedFunction<dim> exact_solution;
+
+      unsigned int singular_quadrature_order;
+      std_cxx1x::shared_ptr<Quadrature<dim-1> > quadrature;
+
+      SolverControl solver_control;
+
+      unsigned int n_cycles;
+      unsigned int external_refinement;
+
+      bool run_in_this_dimension;
+      bool extend_solution;
+  };
+
+
+                                  // @sect4{BEMProblem::BEMProblem and BEMProblem::read_parameters}
+
+                                  // The constructor initializes the
+                                  // variuous object in much the same
+                                  // way as done in the finite element
+                                  // programs such as step-4 or
+                                  // step-6. The only new ingredient
+                                  // here is the ParsedFunction object,
+                                  // which needs, at construction time,
+                                  // the specification of the number of
+                                  // components.
                                   //
-                                  // The use of the
-                                  // Functions::ParsedFunction object
-                                  // is pretty straight forward. The
+                                  // For the exact solution the number
+                                  // of vector components is one, and
+                                  // no action is required since one is
+                                  // the default value for a
+                                  // ParsedFunction object. The wind,
+                                  // however, requires dim components
+                                  // to be specified. Notice that when
+                                  // declaring entries in a parameter
+                                  // file for the expression of the
+                                  // Functions::ParsedFunction, we need
+                                  // to specify the number of
+                                  // components explicitly, since the
+                                  // function
                                   // Functions::ParsedFunction::declare_parameters
-                                  // function takes an additional
-                                  // integer argument that specifies
-                                  // the number of components of the
-                                  // given function. Its default
-                                  // value is one. When the
-                                  // corresponding
-                                  // Functions::ParsedFunction::parse_parameters
-                                  // method is called, the calling
-                                  // object has to have the same
-                                  // number of components defined
-                                  // here, otherwise an exception is
-                                  // thrown.
-                                  //
-                                  // When declaring entries, we
-                                  // declare both 2 and three
-                                  // dimensional functions. However
-                                  // only the dim-dimensional one is
-                                  // ultimately parsed. This allows
-                                  // us to have only one parameter
-                                  // file for both 2 and 3
-                                  // dimensional problems.
-                                  //
-                                  // Notice that from a mathematical
-                                  // point of view, the wind function
-                                  // on the boundary should satisfy
-                                  // the condition
-                                  // $\int_{\partial\Omega}
-                                  // \mathbf{v}\cdot \mathbf{n} d
-                                  // \Gamma = 0$, for the problem to
-                                  // have a solution. If this
-                                  // condition is not satisfied, then
-                                  // no solution can be found, and
-                                  // the solver will not converge.
-  prm.enter_subsection("Wind function 2d");
-  {
-    Functions::ParsedFunction<2>::declare_parameters(prm, 2);
-    prm.set("Function expression", "1; 1");
-  }
-  prm.leave_subsection();
-
-  prm.enter_subsection("Wind function 3d");
-  {
-    Functions::ParsedFunction<3>::declare_parameters(prm, 3);
-    prm.set("Function expression", "1; 1; 1");
-  }
-  prm.leave_subsection();
+                                  // is static, and has no knowledge of
+                                  // the number of components.
+  template <int dim>
+  BEMProblem<dim>::BEMProblem(const unsigned int fe_degree,
+                             const unsigned int mapping_degree)
+                 :
+                 fe(fe_degree),
+                 dh(tria),
+                 mapping(mapping_degree, true),
+                 wind(dim)
+  {}
 
-  prm.enter_subsection("Exact solution 2d");
-  {
-    Functions::ParsedFunction<2>::declare_parameters(prm);
-    prm.set("Function expression", "x+y");
-  }
-  prm.leave_subsection();
 
-  prm.enter_subsection("Exact solution 3d");
-  {
-    Functions::ParsedFunction<3>::declare_parameters(prm);
-    prm.set("Function expression", "x+y+z");
-  }
-  prm.leave_subsection();
-
-
-                                  // In the solver section, we set
-                                  // all SolverControl
-                                  // parameters. The object will then
-                                  // be fed to the GMRES solver in
-                                  // the solve_system() function.
-  prm.enter_subsection("Solver");
-  SolverControl::declare_parameters(prm);
-  prm.leave_subsection();
-
-                                  // After declaring all these
-                                  // parameters to the
-                                  // ParameterHandler object, let's
-                                  // read an input file that will
-                                  // give the parameters their
-                                  // values. We then proceed to
-                                  // extract these values from the
-                                  // ParameterHandler object:
-  prm.read_input(filename);
-
-  n_cycles = prm.get_integer("Number of cycles");
-  external_refinement = prm.get_integer("External refinement");
-  extend_solution = prm.get_bool("Extend solution on the -2,2 box");
-
-  prm.enter_subsection("Quadrature rules");
+  template <int dim>
+  void BEMProblem<dim>::read_parameters (const std::string &filename)
   {
-    quadrature =
-      std_cxx1x::shared_ptr<Quadrature<dim-1> >
-      (new QuadratureSelector<dim-1> (prm.get("Quadrature type"),
-                                     prm.get_integer("Quadrature order")));
-    singular_quadrature_order = prm.get_integer("Singular quadrature order");
-  }
-  prm.leave_subsection();
+    deallog << std::endl << "Parsing parameter file " << filename << std::endl
+           << "for a " << dim << " dimensional simulation. " << std::endl;
+
+    ParameterHandler prm;
+
+    prm.declare_entry("Number of cycles", "4",
+                     Patterns::Integer());
+    prm.declare_entry("External refinement", "5",
+                     Patterns::Integer());
+    prm.declare_entry("Extend solution on the -2,2 box", "true",
+                     Patterns::Bool());
+    prm.declare_entry("Run 2d simulation", "true",
+                     Patterns::Bool());
+    prm.declare_entry("Run 3d simulation", "true",
+                     Patterns::Bool());
+
+    prm.enter_subsection("Quadrature rules");
+    {
+      prm.declare_entry("Quadrature type", "gauss",
+                       Patterns::Selection(QuadratureSelector<(dim-1)>::get_quadrature_names()));
+      prm.declare_entry("Quadrature order", "4", Patterns::Integer());
+      prm.declare_entry("Singular quadrature order", "5", Patterns::Integer());
+    }
+    prm.leave_subsection();
+
+                                    // For both two and three
+                                    // dimensions, we set the default
+                                    // input data to be such that the
+                                    // solution is $x+y$ or
+                                    // $x+y+z$. The actually computed
+                                    // solution will have value zero at
+                                    // infinity. In this case, this
+                                    // coincide with the exact
+                                    // solution, and no additional
+                                    // corrections are needed, but you
+                                    // should be aware of the fact that
+                                    // we arbitrarily set
+                                    // $\phi_\infty$, and the exact
+                                    // solution we pass to the program
+                                    // needs to have the same value at
+                                    // infinity for the error to be
+                                    // computed correctly.
+                                    //
+                                    // The use of the
+                                    // Functions::ParsedFunction object
+                                    // is pretty straight forward. The
+                                    // Functions::ParsedFunction::declare_parameters
+                                    // function takes an additional
+                                    // integer argument that specifies
+                                    // the number of components of the
+                                    // given function. Its default
+                                    // value is one. When the
+                                    // corresponding
+                                    // Functions::ParsedFunction::parse_parameters
+                                    // method is called, the calling
+                                    // object has to have the same
+                                    // number of components defined
+                                    // here, otherwise an exception is
+                                    // thrown.
+                                    //
+                                    // When declaring entries, we
+                                    // declare both 2 and three
+                                    // dimensional functions. However
+                                    // only the dim-dimensional one is
+                                    // ultimately parsed. This allows
+                                    // us to have only one parameter
+                                    // file for both 2 and 3
+                                    // dimensional problems.
+                                    //
+                                    // Notice that from a mathematical
+                                    // point of view, the wind function
+                                    // on the boundary should satisfy
+                                    // the condition
+                                    // $\int_{\partial\Omega}
+                                    // \mathbf{v}\cdot \mathbf{n} d
+                                    // \Gamma = 0$, for the problem to
+                                    // have a solution. If this
+                                    // condition is not satisfied, then
+                                    // no solution can be found, and
+                                    // the solver will not converge.
+    prm.enter_subsection("Wind function 2d");
+    {
+      Functions::ParsedFunction<2>::declare_parameters(prm, 2);
+      prm.set("Function expression", "1; 1");
+    }
+    prm.leave_subsection();
 
-  prm.enter_subsection(std::string("Wind function ")+
-                      Utilities::int_to_string(dim)+std::string("d"));
-  {
-    wind.parse_parameters(prm);
-  }
-  prm.leave_subsection();
+    prm.enter_subsection("Wind function 3d");
+    {
+      Functions::ParsedFunction<3>::declare_parameters(prm, 3);
+      prm.set("Function expression", "1; 1; 1");
+    }
+    prm.leave_subsection();
 
-  prm.enter_subsection(std::string("Exact solution ")+
-                      Utilities::int_to_string(dim)+std::string("d"));
-  {
-    exact_solution.parse_parameters(prm);
-  }
-  prm.leave_subsection();
-
-  prm.enter_subsection("Solver");
-  solver_control.parse_parameters(prm);
-  prm.leave_subsection();
-
-
-                                  // Finally, here's another example
-                                  // of how to use parameter files in
-                                  // dimension independent
-                                  // programming.  If we wanted to
-                                  // switch off one of the two
-                                  // simulations, we could do this by
-                                  // setting the corresponding "Run
-                                  // 2d simulation" or "Run 3d
-                                  // simulation" flag to false:
-  run_in_this_dimension = prm.get_bool("Run " +
-                                      Utilities::int_to_string(dim) +
-                                      "d simulation");
-}
+    prm.enter_subsection("Exact solution 2d");
+    {
+      Functions::ParsedFunction<2>::declare_parameters(prm);
+      prm.set("Function expression", "x+y");
+    }
+    prm.leave_subsection();
 
+    prm.enter_subsection("Exact solution 3d");
+    {
+      Functions::ParsedFunction<3>::declare_parameters(prm);
+      prm.set("Function expression", "x+y+z");
+    }
+    prm.leave_subsection();
+
+
+                                    // In the solver section, we set
+                                    // all SolverControl
+                                    // parameters. The object will then
+                                    // be fed to the GMRES solver in
+                                    // the solve_system() function.
+    prm.enter_subsection("Solver");
+    SolverControl::declare_parameters(prm);
+    prm.leave_subsection();
+
+                                    // After declaring all these
+                                    // parameters to the
+                                    // ParameterHandler object, let's
+                                    // read an input file that will
+                                    // give the parameters their
+                                    // values. We then proceed to
+                                    // extract these values from the
+                                    // ParameterHandler object:
+    prm.read_input(filename);
+
+    n_cycles = prm.get_integer("Number of cycles");
+    external_refinement = prm.get_integer("External refinement");
+    extend_solution = prm.get_bool("Extend solution on the -2,2 box");
+
+    prm.enter_subsection("Quadrature rules");
+    {
+      quadrature =
+       std_cxx1x::shared_ptr<Quadrature<dim-1> >
+       (new QuadratureSelector<dim-1> (prm.get("Quadrature type"),
+                                       prm.get_integer("Quadrature order")));
+      singular_quadrature_order = prm.get_integer("Singular quadrature order");
+    }
+    prm.leave_subsection();
 
-                                // @sect4{BEMProblem::read_domain}
-
-                                // A boundary element method
-                                // triangulation is basically the
-                                // same as a (dim-1) dimensional
-                                // triangulation, with the difference
-                                // that the vertices belong to a
-                                // (dim) dimensional space.
-                                //
-                                // Some of the mesh formats supported
-                                // in deal.II use by default three
-                                // dimensional points to describe
-                                // meshes. These are the formats
-                                // which are compatible with the
-                                // boundary element method
-                                // capabilities of deal.II. In
-                                // particular we can use either UCD
-                                // or GMSH formats. In both cases, we
-                                // have to be particularly careful
-                                // with the orientation of the mesh,
-                                // because, unlike in the standard
-                                // finite element case, no reordering
-                                // or compatibility check is
-                                // performed here.  All meshes are
-                                // considered as oriented, because
-                                // they are embedded in a higher
-                                // dimensional space. (See the
-                                // documentation of the GridIn and of
-                                // the Triangulation for further
-                                // details on orientation of cells in
-                                // a triangulation.) In our case, the
-                                // normals to the mesh are external
-                                // to both the circle in 2d or the
-                                // sphere in 3d.
-                                //
-                                // The other detail that is required
-                                // for appropriate refinement of the
-                                // boundary element mesh, is an
-                                // accurate description of the
-                                // manifold that the mesh is
-                                // approximating. We already saw this
-                                // several times for the boundary of
-                                // standard finite element meshes
-                                // (for example in step-5 and
-                                // step-6), and here the principle
-                                // and usage is the same, except that
-                                // the HyperBallBoundary class takes
-                                // an additional template parameter
-                                // that specifies the embedding space
-                                // dimension. The function object
-                                // still has to be static to live at
-                                // least as long as the triangulation
-                                // object to which it is attached.
-
-template <int dim>
-void BEMProblem<dim>::read_domain()
-{
-  static const Point<dim> center = Point<dim>();
-  static const HyperBallBoundary<dim-1, dim> boundary(center,1.);
+    prm.enter_subsection(std::string("Wind function ")+
+                        Utilities::int_to_string(dim)+std::string("d"));
+    {
+      wind.parse_parameters(prm);
+    }
+    prm.leave_subsection();
 
-  std::ifstream in;
-  switch (dim)
+    prm.enter_subsection(std::string("Exact solution ")+
+                        Utilities::int_to_string(dim)+std::string("d"));
     {
-      case 2:
-           in.open ("coarse_circle.inp");
-           break;
+      exact_solution.parse_parameters(prm);
+    }
+    prm.leave_subsection();
+
+    prm.enter_subsection("Solver");
+    solver_control.parse_parameters(prm);
+    prm.leave_subsection();
+
+
+                                    // Finally, here's another example
+                                    // of how to use parameter files in
+                                    // dimension independent
+                                    // programming.  If we wanted to
+                                    // switch off one of the two
+                                    // simulations, we could do this by
+                                    // setting the corresponding "Run
+                                    // 2d simulation" or "Run 3d
+                                    // simulation" flag to false:
+    run_in_this_dimension = prm.get_bool("Run " +
+                                        Utilities::int_to_string(dim) +
+                                        "d simulation");
+  }
 
-      case 3:
-           in.open ("coarse_sphere.inp");
-           break;
 
-      default:
-           Assert (false, ExcNotImplemented());
-    }
+                                  // @sect4{BEMProblem::read_domain}
 
-  GridIn<dim-1, dim> gi;
-  gi.attach_triangulation (tria);
-  gi.read_ucd (in);
+                                  // A boundary element method
+                                  // triangulation is basically the
+                                  // same as a (dim-1) dimensional
+                                  // triangulation, with the difference
+                                  // that the vertices belong to a
+                                  // (dim) dimensional space.
+                                  //
+                                  // Some of the mesh formats supported
+                                  // in deal.II use by default three
+                                  // dimensional points to describe
+                                  // meshes. These are the formats
+                                  // which are compatible with the
+                                  // boundary element method
+                                  // capabilities of deal.II. In
+                                  // particular we can use either UCD
+                                  // or GMSH formats. In both cases, we
+                                  // have to be particularly careful
+                                  // with the orientation of the mesh,
+                                  // because, unlike in the standard
+                                  // finite element case, no reordering
+                                  // or compatibility check is
+                                  // performed here.  All meshes are
+                                  // considered as oriented, because
+                                  // they are embedded in a higher
+                                  // dimensional space. (See the
+                                  // documentation of the GridIn and of
+                                  // the Triangulation for further
+                                  // details on orientation of cells in
+                                  // a triangulation.) In our case, the
+                                  // normals to the mesh are external
+                                  // to both the circle in 2d or the
+                                  // sphere in 3d.
+                                  //
+                                  // The other detail that is required
+                                  // for appropriate refinement of the
+                                  // boundary element mesh, is an
+                                  // accurate description of the
+                                  // manifold that the mesh is
+                                  // approximating. We already saw this
+                                  // several times for the boundary of
+                                  // standard finite element meshes
+                                  // (for example in step-5 and
+                                  // step-6), and here the principle
+                                  // and usage is the same, except that
+                                  // the HyperBallBoundary class takes
+                                  // an additional template parameter
+                                  // that specifies the embedding space
+                                  // dimension. The function object
+                                  // still has to be static to live at
+                                  // least as long as the triangulation
+                                  // object to which it is attached.
 
-  tria.set_boundary(1, boundary);
-}
+  template <int dim>
+  void BEMProblem<dim>::read_domain()
+  {
+    static const Point<dim> center = Point<dim>();
+    static const HyperBallBoundary<dim-1, dim> boundary(center,1.);
 
+    std::ifstream in;
+    switch (dim)
+      {
+       case 2:
+             in.open ("coarse_circle.inp");
+             break;
 
-                                // @sect4{BEMProblem::refine_and_resize}
+       case 3:
+             in.open ("coarse_sphere.inp");
+             break;
 
-                                // This function globally refines the
-                                // mesh, distributes degrees of
-                                // freedom, and resizes matrices and
-                                // vectors.
+       default:
+             Assert (false, ExcNotImplemented());
+      }
 
-template <int dim>
-void BEMProblem<dim>::refine_and_resize()
-{
-  tria.refine_global(1);
+    GridIn<dim-1, dim> gi;
+    gi.attach_triangulation (tria);
+    gi.read_ucd (in);
 
-  dh.distribute_dofs(fe);
+    tria.set_boundary(1, boundary);
+  }
 
-  const unsigned int n_dofs =  dh.n_dofs();
 
-  system_matrix.reinit(n_dofs, n_dofs);
+                                  // @sect4{BEMProblem::refine_and_resize}
 
-  system_rhs.reinit(n_dofs);
-  phi.reinit(n_dofs);
-  alpha.reinit(n_dofs);
-}
+                                  // This function globally refines the
+                                  // mesh, distributes degrees of
+                                  // freedom, and resizes matrices and
+                                  // vectors.
+
+  template <int dim>
+  void BEMProblem<dim>::refine_and_resize()
+  {
+    tria.refine_global(1);
 
+    dh.distribute_dofs(fe);
 
-                                // @sect4{BEMProblem::assemble_system}
+    const unsigned int n_dofs =  dh.n_dofs();
 
-                                // The following is the main function
-                                // of this program, assembling the
-                                // matrix that corresponds to the
-                                // boundary integral equation.
-template <int dim>
-void BEMProblem<dim>::assemble_system()
-{
+    system_matrix.reinit(n_dofs, n_dofs);
 
-                                  // First we initialize an FEValues
-                                  // object with the quadrature
-                                  // formula for the integration of
-                                  // the kernel in non singular
-                                  // cells. This quadrature is
-                                  // selected with the parameter
-                                  // file, and needs to be quite
-                                  // precise, since the functions we
-                                  // are integrating are not
-                                  // polynomial functions.
-  FEValues<dim-1,dim> fe_v(mapping, fe, *quadrature,
-                          update_values |
-                          update_cell_normal_vectors |
-                          update_quadrature_points |
-                          update_JxW_values);
-
-  const unsigned int n_q_points = fe_v.n_quadrature_points;
-
-  std::vector<unsigned int> local_dof_indices(fe.dofs_per_cell);
-
-  std::vector<Vector<double> > cell_wind(n_q_points, Vector<double>(dim) );
-  double normal_wind;
-
-                                  // Unlike in finite element
-                                  // methods, if we use a collocation
-                                  // boundary element method, then in
-                                  // each assembly loop we only
-                                  // assemble the information that
-                                  // refers to the coupling between
-                                  // one degree of freedom (the
-                                  // degree associated with support
-                                  // point $i$) and the current
-                                  // cell. This is done using a
-                                  // vector of fe.dofs_per_cell
-                                  // elements, which will then be
-                                  // distributed to the matrix in the
-                                  // global row $i$. The following
-                                  // object will hold this
-                                  // information:
-  Vector<double>      local_matrix_row_i(fe.dofs_per_cell);
-
-                                  // The index $i$ runs on the
-                                  // collocation points, which are
-                                  // the support points of the $i$th
-                                  // basis function, while $j$ runs
-                                  // on inner integration points.
-
-                                  // We construct a vector
-                                  // of support points which will be
-                                  // used in the local integrations:
-  std::vector<Point<dim> > support_points(dh.n_dofs());
-  DoFTools::map_dofs_to_support_points<dim-1, dim>( mapping, dh, support_points);
-
-
-                                  // After doing so, we can start the
-                                  // integration loop over all cells,
-                                  // where we first initialize the
-                                  // FEValues object and get the
-                                  // values of $\mathbf{\tilde v}$ at
-                                  // the quadrature points (this
-                                  // vector field should be constant,
-                                  // but it doesn't hurt to be more
-                                  // general):
-  typename DoFHandler<dim-1,dim>::active_cell_iterator
-    cell = dh.begin_active(),
-    endc = dh.end();
-
-  for(cell = dh.begin_active(); cell != endc; ++cell)
-    {
-      fe_v.reinit(cell);
-      cell->get_dof_indices(local_dof_indices);
-
-      const std::vector<Point<dim> > &q_points = fe_v.get_quadrature_points();
-      const std::vector<Point<dim> > &normals = fe_v.get_cell_normal_vectors();
-      wind.vector_value_list(q_points, cell_wind);
-
-                                      // We then form the integral over
-                                      // the current cell for all
-                                      // degrees of freedom (note that
-                                      // this includes degrees of
-                                      // freedom not located on the
-                                      // current cell, a deviation from
-                                      // the usual finite element
-                                      // integrals). The integral that
-                                      // we need to perform is singular
-                                      // if one of the local degrees of
-                                      // freedom is the same as the
-                                      // support point $i$. A the
-                                      // beginning of the loop we
-                                      // therefore check wether this is
-                                      // the case, and we store which
-                                      // one is the singular index:
-      for(unsigned int i=0; i<dh.n_dofs() ; ++i)
-       {
+    system_rhs.reinit(n_dofs);
+    phi.reinit(n_dofs);
+    alpha.reinit(n_dofs);
+  }
 
-         local_matrix_row_i = 0;
 
-         bool is_singular = false;
-         unsigned int singular_index = numbers::invalid_unsigned_int;
+                                  // @sect4{BEMProblem::assemble_system}
 
-         for(unsigned int j=0; j<fe.dofs_per_cell; ++j)
-           if(local_dof_indices[j] == i)
-             {
-               singular_index = j;
-               is_singular = true;
-               break;
-             }
-
-                                          // We then perform the
-                                          // integral. If the index $i$
-                                          // is not one of the local
-                                          // degrees of freedom, we
-                                          // simply have to add the
-                                          // single layer terms to the
-                                          // right hand side, and the
-                                          // double layer terms to the
-                                          // matrix:
-         if(is_singular == false)
-           {
-             for(unsigned int q=0; q<n_q_points; ++q)
-               {
-                 normal_wind = 0;
-                 for(unsigned int d=0; d<dim; ++d)
-                   normal_wind += normals[q][d]*cell_wind[q](d);
+                                  // The following is the main function
+                                  // of this program, assembling the
+                                  // matrix that corresponds to the
+                                  // boundary integral equation.
+  template <int dim>
+  void BEMProblem<dim>::assemble_system()
+  {
 
-                 const Point<dim> R = q_points[q] - support_points[i];
+                                    // First we initialize an FEValues
+                                    // object with the quadrature
+                                    // formula for the integration of
+                                    // the kernel in non singular
+                                    // cells. This quadrature is
+                                    // selected with the parameter
+                                    // file, and needs to be quite
+                                    // precise, since the functions we
+                                    // are integrating are not
+                                    // polynomial functions.
+    FEValues<dim-1,dim> fe_v(mapping, fe, *quadrature,
+                            update_values |
+                            update_cell_normal_vectors |
+                            update_quadrature_points |
+                            update_JxW_values);
+
+    const unsigned int n_q_points = fe_v.n_quadrature_points;
+
+    std::vector<unsigned int> local_dof_indices(fe.dofs_per_cell);
+
+    std::vector<Vector<double> > cell_wind(n_q_points, Vector<double>(dim) );
+    double normal_wind;
+
+                                    // Unlike in finite element
+                                    // methods, if we use a collocation
+                                    // boundary element method, then in
+                                    // each assembly loop we only
+                                    // assemble the information that
+                                    // refers to the coupling between
+                                    // one degree of freedom (the
+                                    // degree associated with support
+                                    // point $i$) and the current
+                                    // cell. This is done using a
+                                    // vector of fe.dofs_per_cell
+                                    // elements, which will then be
+                                    // distributed to the matrix in the
+                                    // global row $i$. The following
+                                    // object will hold this
+                                    // information:
+    Vector<double>      local_matrix_row_i(fe.dofs_per_cell);
+
+                                    // The index $i$ runs on the
+                                    // collocation points, which are
+                                    // the support points of the $i$th
+                                    // basis function, while $j$ runs
+                                    // on inner integration points.
+
+                                    // We construct a vector
+                                    // of support points which will be
+                                    // used in the local integrations:
+    std::vector<Point<dim> > support_points(dh.n_dofs());
+    DoFTools::map_dofs_to_support_points<dim-1, dim>( mapping, dh, support_points);
+
+
+                                    // After doing so, we can start the
+                                    // integration loop over all cells,
+                                    // where we first initialize the
+                                    // FEValues object and get the
+                                    // values of $\mathbf{\tilde v}$ at
+                                    // the quadrature points (this
+                                    // vector field should be constant,
+                                    // but it doesn't hurt to be more
+                                    // general):
+    typename DoFHandler<dim-1,dim>::active_cell_iterator
+      cell = dh.begin_active(),
+      endc = dh.end();
+
+    for (cell = dh.begin_active(); cell != endc; ++cell)
+      {
+       fe_v.reinit(cell);
+       cell->get_dof_indices(local_dof_indices);
+
+       const std::vector<Point<dim> > &q_points = fe_v.get_quadrature_points();
+       const std::vector<Point<dim> > &normals = fe_v.get_cell_normal_vectors();
+       wind.vector_value_list(q_points, cell_wind);
+
+                                        // We then form the integral over
+                                        // the current cell for all
+                                        // degrees of freedom (note that
+                                        // this includes degrees of
+                                        // freedom not located on the
+                                        // current cell, a deviation from
+                                        // the usual finite element
+                                        // integrals). The integral that
+                                        // we need to perform is singular
+                                        // if one of the local degrees of
+                                        // freedom is the same as the
+                                        // support point $i$. A the
+                                        // beginning of the loop we
+                                        // therefore check wether this is
+                                        // the case, and we store which
+                                        // one is the singular index:
+       for (unsigned int i=0; i<dh.n_dofs() ; ++i)
+         {
 
-                 system_rhs(i) += ( LaplaceKernel::single_layer(R)   *
-                                    normal_wind                      *
-                                    fe_v.JxW(q) );
+           local_matrix_row_i = 0;
 
-                 for(unsigned int j=0; j<fe.dofs_per_cell; ++j)
+           bool is_singular = false;
+           unsigned int singular_index = numbers::invalid_unsigned_int;
 
-                   local_matrix_row_i(j) -= ( ( LaplaceKernel::double_layer(R)     *
-                                                normals[q] )            *
-                                              fe_v.shape_value(j,q)     *
-                                              fe_v.JxW(q)       );
+           for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
+             if (local_dof_indices[j] == i)
+               {
+                 singular_index = j;
+                 is_singular = true;
+                 break;
                }
-           } else {
-                                            // Now we treat the more
-                                            // delicate case. If we
-                                            // are here, this means
-                                            // that the cell that
-                                            // runs on the $j$ index
-                                            // contains
-                                            // support_point[i]. In
-                                            // this case both the
-                                            // single and the double
-                                            // layer potential are
-                                            // singular, and they
-                                            // require special
-                                            // treatment.
-                                            //
-                                            // Whenever the
-                                            // integration is
-                                            // performed with the
-                                            // singularity inside the
-                                            // given cell, then a
-                                            // special quadrature
-                                            // formula is used that
-                                            // allows one to
-                                            // integrate arbitrary
-                                            // functions against a
-                                            // singular weight on the
-                                            // reference cell.
-                                            //
-                                            // The correct quadrature
-                                            // formula is selected by
-                                            // the
-                                            // get_singular_quadrature
-                                            // function, which is
-                                            // explained in detail below.
-           Assert(singular_index != numbers::invalid_unsigned_int,
-                  ExcInternalError());
-
-           const Quadrature<dim-1> & singular_quadrature =
-             get_singular_quadrature(cell, singular_index);
-
-           FEValues<dim-1,dim> fe_v_singular (mapping, fe, singular_quadrature,
-                                              update_jacobians |
-                                              update_values |
-                                              update_cell_normal_vectors |
-                                              update_quadrature_points );
-
-           fe_v_singular.reinit(cell);
-
-           std::vector<Vector<double> > singular_cell_wind( singular_quadrature.size(),
-                                                            Vector<double>(dim) );
-
-           const std::vector<Point<dim> > &singular_normals = fe_v_singular.get_cell_normal_vectors();
-           const std::vector<Point<dim> > &singular_q_points = fe_v_singular.get_quadrature_points();
-
-           wind.vector_value_list(singular_q_points, singular_cell_wind);
-
-           for(unsigned int q=0; q<singular_quadrature.size(); ++q)
+
+                                            // We then perform the
+                                            // integral. If the index $i$
+                                            // is not one of the local
+                                            // degrees of freedom, we
+                                            // simply have to add the
+                                            // single layer terms to the
+                                            // right hand side, and the
+                                            // double layer terms to the
+                                            // matrix:
+           if (is_singular == false)
              {
-               const Point<dim> R = singular_q_points[q] - support_points[i];
-               double normal_wind = 0;
-               for(unsigned int d=0; d<dim; ++d)
-                 normal_wind += (singular_cell_wind[q](d)*
-                                 singular_normals[q][d]);
+               for (unsigned int q=0; q<n_q_points; ++q)
+                 {
+                   normal_wind = 0;
+                   for (unsigned int d=0; d<dim; ++d)
+                     normal_wind += normals[q][d]*cell_wind[q](d);
+
+                   const Point<dim> R = q_points[q] - support_points[i];
+
+                   system_rhs(i) += ( LaplaceKernel::single_layer(R)   *
+                                      normal_wind                      *
+                                      fe_v.JxW(q) );
+
+                   for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
+
+                     local_matrix_row_i(j) -= ( ( LaplaceKernel::double_layer(R)     *
+                                                  normals[q] )            *
+                                                fe_v.shape_value(j,q)     *
+                                                fe_v.JxW(q)       );
+                 }
+             } else {
+                                              // Now we treat the more
+                                              // delicate case. If we
+                                              // are here, this means
+                                              // that the cell that
+                                              // runs on the $j$ index
+                                              // contains
+                                              // support_point[i]. In
+                                              // this case both the
+                                              // single and the double
+                                              // layer potential are
+                                              // singular, and they
+                                              // require special
+                                              // treatment.
+                                              //
+                                              // Whenever the
+                                              // integration is
+                                              // performed with the
+                                              // singularity inside the
+                                              // given cell, then a
+                                              // special quadrature
+                                              // formula is used that
+                                              // allows one to
+                                              // integrate arbitrary
+                                              // functions against a
+                                              // singular weight on the
+                                              // reference cell.
+                                              //
+                                              // The correct quadrature
+                                              // formula is selected by
+                                              // the
+                                              // get_singular_quadrature
+                                              // function, which is
+                                              // explained in detail below.
+             Assert(singular_index != numbers::invalid_unsigned_int,
+                    ExcInternalError());
+
+             const Quadrature<dim-1> & singular_quadrature =
+               get_singular_quadrature(cell, singular_index);
+
+             FEValues<dim-1,dim> fe_v_singular (mapping, fe, singular_quadrature,
+                                                update_jacobians |
+                                                update_values |
+                                                update_cell_normal_vectors |
+                                                update_quadrature_points );
+
+             fe_v_singular.reinit(cell);
+
+             std::vector<Vector<double> > singular_cell_wind( singular_quadrature.size(),
+                                                              Vector<double>(dim) );
+
+             const std::vector<Point<dim> > &singular_normals = fe_v_singular.get_cell_normal_vectors();
+             const std::vector<Point<dim> > &singular_q_points = fe_v_singular.get_quadrature_points();
+
+             wind.vector_value_list(singular_q_points, singular_cell_wind);
+
+             for (unsigned int q=0; q<singular_quadrature.size(); ++q)
+               {
+                 const Point<dim> R = singular_q_points[q] - support_points[i];
+                 double normal_wind = 0;
+                 for (unsigned int d=0; d<dim; ++d)
+                   normal_wind += (singular_cell_wind[q](d)*
+                                   singular_normals[q][d]);
 
-               system_rhs(i) += ( LaplaceKernel::single_layer(R) *
-                                  normal_wind                         *
-                                  fe_v_singular.JxW(q) );
+                 system_rhs(i) += ( LaplaceKernel::single_layer(R) *
+                                    normal_wind                         *
+                                    fe_v_singular.JxW(q) );
 
-               for(unsigned int j=0; j<fe.dofs_per_cell; ++j) {
+                 for (unsigned int j=0; j<fe.dofs_per_cell; ++j) {
                    local_matrix_row_i(j) -= (( LaplaceKernel::double_layer(R) *
                                                singular_normals[q])                *
                                              fe_v_singular.shape_value(j,q)        *
                                              fe_v_singular.JxW(q)       );
+                 }
                }
-             }
-         }
+           }
 
-                                          // Finally, we need to add
-                                          // the contributions of the
-                                          // current cell to the
-                                          // global matrix.
-         for(unsigned int j=0; j<fe.dofs_per_cell; ++j)
+                                            // Finally, we need to add
+                                            // the contributions of the
+                                            // current cell to the
+                                            // global matrix.
+           for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
              system_matrix(i,local_dof_indices[j])
-                 += local_matrix_row_i(j);
-       }
-    }
+               += local_matrix_row_i(j);
+         }
+      }
 
-                                  // The second part of the integral
-                                  // operator is the term
-                                  // $\alpha(\mathbf{x}_i)
-                                  // \phi_j(\mathbf{x}_i)$. Since we
-                                  // use a collocation scheme,
-                                  // $\phi_j(\mathbf{x}_i)=\delta_{ij}$
-                                  // and the corresponding matrix is
-                                  // a diagonal one with entries
-                                  // equal to $\alpha(\mathbf{x}_i)$.
-
-                                  // One quick way to compute this
-                                  // diagonal matrix of the solid
-                                  // angles, is to use the Neumann
-                                  // matrix itself. It is enough to
-                                  // multiply the matrix with a
-                                  // vector of elements all equal to
-                                  // -1, to get the diagonal matrix
-                                  // of the alpha angles, or solid
-                                  // angles (see the formula in the
-                                  // introduction for this). The
-                                  // result is then added back onto
-                                  // the system matrix object to
-                                  // yield the final form of the
-                                  // matrix:
-  Vector<double> ones(dh.n_dofs());
-  ones.add(-1.);
-
-  system_matrix.vmult(alpha, ones);
-  alpha.add(1);
-  for(unsigned int i = 0; i<dh.n_dofs(); ++i)
+                                    // The second part of the integral
+                                    // operator is the term
+                                    // $\alpha(\mathbf{x}_i)
+                                    // \phi_j(\mathbf{x}_i)$. Since we
+                                    // use a collocation scheme,
+                                    // $\phi_j(\mathbf{x}_i)=\delta_{ij}$
+                                    // and the corresponding matrix is
+                                    // a diagonal one with entries
+                                    // equal to $\alpha(\mathbf{x}_i)$.
+
+                                    // One quick way to compute this
+                                    // diagonal matrix of the solid
+                                    // angles, is to use the Neumann
+                                    // matrix itself. It is enough to
+                                    // multiply the matrix with a
+                                    // vector of elements all equal to
+                                    // -1, to get the diagonal matrix
+                                    // of the alpha angles, or solid
+                                    // angles (see the formula in the
+                                    // introduction for this). The
+                                    // result is then added back onto
+                                    // the system matrix object to
+                                    // yield the final form of the
+                                    // matrix:
+    Vector<double> ones(dh.n_dofs());
+    ones.add(-1.);
+
+    system_matrix.vmult(alpha, ones);
+    alpha.add(1);
+    for (unsigned int i = 0; i<dh.n_dofs(); ++i)
       system_matrix(i,i) +=  alpha(i);
-}
+  }
 
 
-                                // @sect4{BEMProblem::solve_system}
+                                  // @sect4{BEMProblem::solve_system}
 
-                                // The next function simply solves
-                                // the linear system.
-template <int dim>
-void BEMProblem<dim>::solve_system()
-{
+                                  // The next function simply solves
+                                  // the linear system.
+  template <int dim>
+  void BEMProblem<dim>::solve_system()
+  {
     SolverGMRES<Vector<double> > solver (solver_control);
     solver.solve (system_matrix, phi, system_rhs, PreconditionIdentity());
-}
+  }
 
 
-                                // @sect4{BEMProblem::compute_errors}
+                                  // @sect4{BEMProblem::compute_errors}
 
-                                // The computation of the errors is
-                                // exactly the same in all other
-                                // example programs, and we won't
-                                // comment too much. Notice how the
-                                // same methods that are used in the
-                                // finite element methods can be used
-                                // here.
-template <int dim>
-void BEMProblem<dim>::compute_errors(const unsigned int cycle)
-{
-  Vector<float> difference_per_cell (tria.n_active_cells());
-  VectorTools::integrate_difference (mapping, dh, phi,
-                                    exact_solution,
-                                    difference_per_cell,
-                                    QGauss<(dim-1)>(2*fe.degree+1),
-                                    VectorTools::L2_norm);
-  const double L2_error = difference_per_cell.l2_norm();
-
-
-                                  // The error in the alpha vector
-                                  // can be computed directly using
-                                  // the Vector::linfty_norm()
-                                  // function, since on each node,
-                                  // the value should be $\frac
-                                  // 12$. All errors are then output
-                                  // and appended to our
-                                  // ConvergenceTable object for
-                                  // later computation of convergence
-                                  // rates:
-  Vector<double> difference_per_node(alpha);
-  difference_per_node.add(-.5);
-
-  const double alpha_error = difference_per_node.linfty_norm();
-  const unsigned int n_active_cells=tria.n_active_cells();
-  const unsigned int n_dofs=dh.n_dofs();
-
-  deallog << "Cycle " << cycle << ':'
-         << std::endl
-         << "   Number of active cells:       "
-         << n_active_cells
-         << std::endl
-         << "   Number of degrees of freedom: "
-         << n_dofs
-         << std::endl;
-
-  convergence_table.add_value("cycle", cycle);
-  convergence_table.add_value("cells", n_active_cells);
-  convergence_table.add_value("dofs", n_dofs);
-  convergence_table.add_value("L2(phi)", L2_error);
-  convergence_table.add_value("Linfty(alpha)", alpha_error);
-}
+                                  // The computation of the errors is
+                                  // exactly the same in all other
+                                  // example programs, and we won't
+                                  // comment too much. Notice how the
+                                  // same methods that are used in the
+                                  // finite element methods can be used
+                                  // here.
+  template <int dim>
+  void BEMProblem<dim>::compute_errors(const unsigned int cycle)
+  {
+    Vector<float> difference_per_cell (tria.n_active_cells());
+    VectorTools::integrate_difference (mapping, dh, phi,
+                                      exact_solution,
+                                      difference_per_cell,
+                                      QGauss<(dim-1)>(2*fe.degree+1),
+                                      VectorTools::L2_norm);
+    const double L2_error = difference_per_cell.l2_norm();
+
+
+                                    // The error in the alpha vector
+                                    // can be computed directly using
+                                    // the Vector::linfty_norm()
+                                    // function, since on each node,
+                                    // the value should be $\frac
+                                    // 12$. All errors are then output
+                                    // and appended to our
+                                    // ConvergenceTable object for
+                                    // later computation of convergence
+                                    // rates:
+    Vector<double> difference_per_node(alpha);
+    difference_per_node.add(-.5);
+
+    const double alpha_error = difference_per_node.linfty_norm();
+    const unsigned int n_active_cells=tria.n_active_cells();
+    const unsigned int n_dofs=dh.n_dofs();
+
+    deallog << "Cycle " << cycle << ':'
+           << std::endl
+           << "   Number of active cells:       "
+           << n_active_cells
+           << std::endl
+           << "   Number of degrees of freedom: "
+           << n_dofs
+           << std::endl;
+
+    convergence_table.add_value("cycle", cycle);
+    convergence_table.add_value("cells", n_active_cells);
+    convergence_table.add_value("dofs", n_dofs);
+    convergence_table.add_value("L2(phi)", L2_error);
+    convergence_table.add_value("Linfty(alpha)", alpha_error);
+  }
 
 
-                                // Singular integration requires a
-                                // careful selection of the
-                                // quadrature rules. In particular
-                                // the deal.II library provides
-                                // quadrature rules which are
-                                // taylored for logarithmic
-                                // singularities (QGaussLog,
-                                // QGaussLogR), as well as for 1/R
-                                // singularities (QGaussOneOverR).
-                                //
-                                // Singular integration is typically
-                                // obtained by constructing weighted
-                                // quadrature formulas with singular
-                                // weights, so that it is possible to
-                                // write
-                                //
-                                // \f[
-                                //   \int_K f(x) s(x) dx = \sum_{i=1}^N w_i f(q_i)
-                                // \f]
-                                //
-                                // where $s(x)$ is a given
-                                // singularity, and the weights and
-                                // quadrature points $w_i,q_i$ are
-                                // carefully selected to make the
-                                // formula above an equality for a
-                                // certain class of functions $f(x)$.
-                                //
-                                // In all the finite element examples
-                                // we have seen so far, the weight of
-                                // the quadrature itself (namely, the
-                                // function $s(x)$), was always
-                                // constantly equal to 1.  For
-                                // singular integration, we have two
-                                // choices: we can use the definition
-                                // above, factoring out the
-                                // singularity from the integrand
-                                // (i.e., integrating $f(x)$ with the
-                                // special quadrature rule), or we
-                                // can ask the quadrature rule to
-                                // "normalize" the weights $w_i$ with
-                                // $s(q_i)$:
-                                //
-                                // \f[
-                                //   \int_K f(x) s(x) dx =
-                                //   \int_K g(x) dx = \sum_{i=1}^N \frac{w_i}{s(q_i)} g(q_i)
-                                // \f]
-                                //
-                                // We use this second option, through
-                                // the @p factor_out_singularity
-                                // parameter of both QGaussLogR and
-                                // QGaussOneOverR.
-                                //
-                                // These integrals are somewhat
-                                // delicate, especially in two
-                                // dimensions, due to the
-                                // transformation from the real to
-                                // the reference cell, where the
-                                // variable of integration is scaled
-                                // with the determinant of the
-                                // transformation.
-                                //
-                                // In two dimensions this process
-                                // does not result only in a factor
-                                // appearing as a constant factor on
-                                // the entire integral, but also on
-                                // an additional integral alltogether
-                                // that needs to be evaluated:
-                                //
-                                // \f[
-                                //  \int_0^1 f(x)\ln(x/\alpha) dx =
-                                //  \int_0^1 f(x)\ln(x) dx - \int_0^1 f(x) \ln(\alpha) dx.
-                                // \f]
-                                //
-                                // This process is taken care of by
-                                // the constructor of the QGaussLogR
-                                // class, which adds additional
-                                // quadrature points and weights to
-                                // take into consideration also the
-                                // second part of the integral.
-                                //
-                                // A similar reasoning should be done
-                                // in the three dimensional case,
-                                // since the singular quadrature is
-                                // taylored on the inverse of the
-                                // radius $r$ in the reference cell,
-                                // while our singular function lives
-                                // in real space, however in the
-                                // three dimensional case everything
-                                // is simpler because the singularity
-                                // scales linearly with the
-                                // determinant of the
-                                // transformation. This allows us to
-                                // build the singular two dimensional
-                                // quadrature rules only once and,
-                                // reuse them over all cells.
-                                //
-                                // In the one dimensional singular
-                                // integration this is not possible,
-                                // since we need to know the scaling
-                                // parameter for the quadrature,
-                                // which is not known a priori. Here,
-                                // the quadrature rule itself depends
-                                // also on the size of the current
-                                // cell. For this reason, it is
-                                // necessary to create a new
-                                // quadrature for each singular
-                                // integration.
-                                //
-                                // The different quadrature rules are
-                                // built inside the
-                                // get_singular_quadrature, which is
-                                // specialized for dim=2 and dim=3,
-                                // and they are retrieved inside the
-                                // assemble_system function. The
-                                // index given as an argument is the
-                                // index of the unit support point
-                                // where the singularity is located.
-
-template<>
-const Quadrature<2> & BEMProblem<3>::get_singular_quadrature(
-  const DoFHandler<2,3>::active_cell_iterator &,
-  const unsigned int index) const
-{
-  Assert(index < fe.dofs_per_cell,
-        ExcIndexRange(0, fe.dofs_per_cell, index));
-
-  static std::vector<QGaussOneOverR<2> > quadratures;
-  if(quadratures.size() == 0)
-    for(unsigned int i=0; i<fe.dofs_per_cell; ++i)
-      quadratures.push_back(QGaussOneOverR<2>(singular_quadrature_order,
-                                             fe.get_unit_support_points()[i],
-                                             true));
-  return quadratures[index];
-}
+                                  // Singular integration requires a
+                                  // careful selection of the
+                                  // quadrature rules. In particular
+                                  // the deal.II library provides
+                                  // quadrature rules which are
+                                  // taylored for logarithmic
+                                  // singularities (QGaussLog,
+                                  // QGaussLogR), as well as for 1/R
+                                  // singularities (QGaussOneOverR).
+                                  //
+                                  // Singular integration is typically
+                                  // obtained by constructing weighted
+                                  // quadrature formulas with singular
+                                  // weights, so that it is possible to
+                                  // write
+                                  //
+                                  // \f[
+                                  //   \int_K f(x) s(x) dx = \sum_{i=1}^N w_i f(q_i)
+                                  // \f]
+                                  //
+                                  // where $s(x)$ is a given
+                                  // singularity, and the weights and
+                                  // quadrature points $w_i,q_i$ are
+                                  // carefully selected to make the
+                                  // formula above an equality for a
+                                  // certain class of functions $f(x)$.
+                                  //
+                                  // In all the finite element examples
+                                  // we have seen so far, the weight of
+                                  // the quadrature itself (namely, the
+                                  // function $s(x)$), was always
+                                  // constantly equal to 1.  For
+                                  // singular integration, we have two
+                                  // choices: we can use the definition
+                                  // above, factoring out the
+                                  // singularity from the integrand
+                                  // (i.e., integrating $f(x)$ with the
+                                  // special quadrature rule), or we
+                                  // can ask the quadrature rule to
+                                  // "normalize" the weights $w_i$ with
+                                  // $s(q_i)$:
+                                  //
+                                  // \f[
+                                  //   \int_K f(x) s(x) dx =
+                                  //   \int_K g(x) dx = \sum_{i=1}^N \frac{w_i}{s(q_i)} g(q_i)
+                                  // \f]
+                                  //
+                                  // We use this second option, through
+                                  // the @p factor_out_singularity
+                                  // parameter of both QGaussLogR and
+                                  // QGaussOneOverR.
+                                  //
+                                  // These integrals are somewhat
+                                  // delicate, especially in two
+                                  // dimensions, due to the
+                                  // transformation from the real to
+                                  // the reference cell, where the
+                                  // variable of integration is scaled
+                                  // with the determinant of the
+                                  // transformation.
+                                  //
+                                  // In two dimensions this process
+                                  // does not result only in a factor
+                                  // appearing as a constant factor on
+                                  // the entire integral, but also on
+                                  // an additional integral alltogether
+                                  // that needs to be evaluated:
+                                  //
+                                  // \f[
+                                  //  \int_0^1 f(x)\ln(x/\alpha) dx =
+                                  //  \int_0^1 f(x)\ln(x) dx - \int_0^1 f(x) \ln(\alpha) dx.
+                                  // \f]
+                                  //
+                                  // This process is taken care of by
+                                  // the constructor of the QGaussLogR
+                                  // class, which adds additional
+                                  // quadrature points and weights to
+                                  // take into consideration also the
+                                  // second part of the integral.
+                                  //
+                                  // A similar reasoning should be done
+                                  // in the three dimensional case,
+                                  // since the singular quadrature is
+                                  // taylored on the inverse of the
+                                  // radius $r$ in the reference cell,
+                                  // while our singular function lives
+                                  // in real space, however in the
+                                  // three dimensional case everything
+                                  // is simpler because the singularity
+                                  // scales linearly with the
+                                  // determinant of the
+                                  // transformation. This allows us to
+                                  // build the singular two dimensional
+                                  // quadrature rules only once and,
+                                  // reuse them over all cells.
+                                  //
+                                  // In the one dimensional singular
+                                  // integration this is not possible,
+                                  // since we need to know the scaling
+                                  // parameter for the quadrature,
+                                  // which is not known a priori. Here,
+                                  // the quadrature rule itself depends
+                                  // also on the size of the current
+                                  // cell. For this reason, it is
+                                  // necessary to create a new
+                                  // quadrature for each singular
+                                  // integration.
+                                  //
+                                  // The different quadrature rules are
+                                  // built inside the
+                                  // get_singular_quadrature, which is
+                                  // specialized for dim=2 and dim=3,
+                                  // and they are retrieved inside the
+                                  // assemble_system function. The
+                                  // index given as an argument is the
+                                  // index of the unit support point
+                                  // where the singularity is located.
+
+  template<>
+  const Quadrature<2> & BEMProblem<3>::get_singular_quadrature(
+    const DoFHandler<2,3>::active_cell_iterator &,
+    const unsigned int index) const
+  {
+    Assert(index < fe.dofs_per_cell,
+          ExcIndexRange(0, fe.dofs_per_cell, index));
+
+    static std::vector<QGaussOneOverR<2> > quadratures;
+    if (quadratures.size() == 0)
+      for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+       quadratures.push_back(QGaussOneOverR<2>(singular_quadrature_order,
+                                               fe.get_unit_support_points()[i],
+                                               true));
+    return quadratures[index];
+  }
 
 
-template<>
-const Quadrature<1> & BEMProblem<2>::get_singular_quadrature(
-  const DoFHandler<1,2>::active_cell_iterator &cell,
-  const unsigned int index) const
-{
-  Assert(index < fe.dofs_per_cell,
-        ExcIndexRange(0, fe.dofs_per_cell, index));
+  template<>
+  const Quadrature<1> & BEMProblem<2>::get_singular_quadrature(
+    const DoFHandler<1,2>::active_cell_iterator &cell,
+    const unsigned int index) const
+  {
+    Assert(index < fe.dofs_per_cell,
+          ExcIndexRange(0, fe.dofs_per_cell, index));
 
-  static Quadrature<1> * q_pointer = NULL;
-  if(q_pointer) delete q_pointer;
+    static Quadrature<1> * q_pointer = NULL;
+    if (q_pointer) delete q_pointer;
 
-  q_pointer = new QGaussLogR<1>(singular_quadrature_order,
-                               fe.get_unit_support_points()[index],
-                               1./cell->measure(), true);
-  return (*q_pointer);
-}
+    q_pointer = new QGaussLogR<1>(singular_quadrature_order,
+                                 fe.get_unit_support_points()[index],
+                                 1./cell->measure(), true);
+    return (*q_pointer);
+  }
 
 
 
-                                // @sect4{BEMProblem::compute_exterior_solution}
-
-                                // We'd like to also know something
-                                // about the value of the potential
-                                // $\phi$ in the exterior domain:
-                                // after all our motivation to
-                                // consider the boundary integral
-                                // problem was that we wanted to know
-                                // the velocity in the exterior
-                                // domain!
-                                //
-                                // To this end, let us assume here
-                                // that the boundary element domain
-                                // is contained in the box
-                                // $[-2,2]^{\text{dim}}$, and we
-                                // extrapolate the actual solution
-                                // inside this box using the
-                                // convolution with the fundamental
-                                // solution. The formula for this is
-                                // given in the introduction.
-                                //
-                                // The reconstruction of the solution
-                                // in the entire space is done on a
-                                // continuous finite element grid of
-                                // dimension dim. These are the usual
-                                // ones, and we don't comment any
-                                // further on them. At the end of the
-                                // function, we output this exterior
-                                // solution in, again, much the usual
-                                // way.
-template <int dim>
-void BEMProblem<dim>::compute_exterior_solution()
-{
-  Triangulation<dim>  external_tria;
-  GridGenerator::hyper_cube(external_tria, -2, 2);
+                                  // @sect4{BEMProblem::compute_exterior_solution}
 
-  FE_Q<dim>           external_fe(1);
-  DoFHandler<dim>     external_dh (external_tria);
-  Vector<double>      external_phi;
+                                  // We'd like to also know something
+                                  // about the value of the potential
+                                  // $\phi$ in the exterior domain:
+                                  // after all our motivation to
+                                  // consider the boundary integral
+                                  // problem was that we wanted to know
+                                  // the velocity in the exterior
+                                  // domain!
+                                  //
+                                  // To this end, let us assume here
+                                  // that the boundary element domain
+                                  // is contained in the box
+                                  // $[-2,2]^{\text{dim}}$, and we
+                                  // extrapolate the actual solution
+                                  // inside this box using the
+                                  // convolution with the fundamental
+                                  // solution. The formula for this is
+                                  // given in the introduction.
+                                  //
+                                  // The reconstruction of the solution
+                                  // in the entire space is done on a
+                                  // continuous finite element grid of
+                                  // dimension dim. These are the usual
+                                  // ones, and we don't comment any
+                                  // further on them. At the end of the
+                                  // function, we output this exterior
+                                  // solution in, again, much the usual
+                                  // way.
+  template <int dim>
+  void BEMProblem<dim>::compute_exterior_solution()
+  {
+    Triangulation<dim>  external_tria;
+    GridGenerator::hyper_cube(external_tria, -2, 2);
 
-  external_tria.refine_global(external_refinement);
-  external_dh.distribute_dofs(external_fe);
-  external_phi.reinit(external_dh.n_dofs());
+    FE_Q<dim>           external_fe(1);
+    DoFHandler<dim>     external_dh (external_tria);
+    Vector<double>      external_phi;
 
-  typename DoFHandler<dim-1,dim>::active_cell_iterator
-    cell = dh.begin_active(),
-    endc = dh.end();
+    external_tria.refine_global(external_refinement);
+    external_dh.distribute_dofs(external_fe);
+    external_phi.reinit(external_dh.n_dofs());
 
+    typename DoFHandler<dim-1,dim>::active_cell_iterator
+      cell = dh.begin_active(),
+      endc = dh.end();
 
-  FEValues<dim-1,dim> fe_v(mapping, fe, *quadrature,
-                          update_values |
-                          update_cell_normal_vectors |
-                          update_quadrature_points |
-                          update_JxW_values);
 
-  const unsigned int n_q_points = fe_v.n_quadrature_points;
+    FEValues<dim-1,dim> fe_v(mapping, fe, *quadrature,
+                            update_values |
+                            update_cell_normal_vectors |
+                            update_quadrature_points |
+                            update_JxW_values);
 
-  std::vector<unsigned int> dofs(fe.dofs_per_cell);
+    const unsigned int n_q_points = fe_v.n_quadrature_points;
 
-  std::vector<double> local_phi(n_q_points);
-  std::vector<double> normal_wind(n_q_points);
-  std::vector<Vector<double> > local_wind(n_q_points, Vector<double>(dim) );
+    std::vector<unsigned int> dofs(fe.dofs_per_cell);
 
-  std::vector<Point<dim> > external_support_points(external_dh.n_dofs());
-  DoFTools::map_dofs_to_support_points<dim>(StaticMappingQ1<dim>::mapping,
-                                           external_dh, external_support_points);
+    std::vector<double> local_phi(n_q_points);
+    std::vector<double> normal_wind(n_q_points);
+    std::vector<Vector<double> > local_wind(n_q_points, Vector<double>(dim) );
 
-  for(cell = dh.begin_active(); cell != endc; ++cell)
-    {
-      fe_v.reinit(cell);
+    std::vector<Point<dim> > external_support_points(external_dh.n_dofs());
+    DoFTools::map_dofs_to_support_points<dim>(StaticMappingQ1<dim>::mapping,
+                                             external_dh, external_support_points);
 
-      const std::vector<Point<dim> > &q_points = fe_v.get_quadrature_points();
-      const std::vector<Point<dim> > &normals = fe_v.get_cell_normal_vectors();
+    for (cell = dh.begin_active(); cell != endc; ++cell)
+      {
+       fe_v.reinit(cell);
 
-      cell->get_dof_indices(dofs);
-      fe_v.get_function_values(phi, local_phi);
+       const std::vector<Point<dim> > &q_points = fe_v.get_quadrature_points();
+       const std::vector<Point<dim> > &normals = fe_v.get_cell_normal_vectors();
 
-      wind.vector_value_list(q_points, local_wind);
+       cell->get_dof_indices(dofs);
+       fe_v.get_function_values(phi, local_phi);
 
-      for(unsigned int q=0; q<n_q_points; ++q){
-       normal_wind[q] = 0;
-       for(unsigned int d=0; d<dim; ++d)
-         normal_wind[q] += normals[q][d]*local_wind[q](d);
-      }
+       wind.vector_value_list(q_points, local_wind);
 
-      for(unsigned int i=0; i<external_dh.n_dofs(); ++i)
-       for(unsigned int q=0; q<n_q_points; ++q)
-         {
+       for (unsigned int q=0; q<n_q_points; ++q){
+         normal_wind[q] = 0;
+         for (unsigned int d=0; d<dim; ++d)
+           normal_wind[q] += normals[q][d]*local_wind[q](d);
+       }
 
-           const Point<dim> R =  q_points[q] - external_support_points[i];
+       for (unsigned int i=0; i<external_dh.n_dofs(); ++i)
+         for (unsigned int q=0; q<n_q_points; ++q)
+           {
 
-           external_phi(i) += ( ( LaplaceKernel::single_layer(R) *
-                                  normal_wind[q]
-                                  +
-                                  (LaplaceKernel::double_layer(R) *
-                                   normals[q] )            *
-                                  local_phi[q] )           *
-                                fe_v.JxW(q) );
-         }
-    }
+             const Point<dim> R =  q_points[q] - external_support_points[i];
 
-  DataOut<dim> data_out;
+             external_phi(i) += ( ( LaplaceKernel::single_layer(R) *
+                                    normal_wind[q]
+                                    +
+                                    (LaplaceKernel::double_layer(R) *
+                                     normals[q] )            *
+                                    local_phi[q] )           *
+                                  fe_v.JxW(q) );
+           }
+      }
 
-  data_out.attach_dof_handler(external_dh);
-  data_out.add_data_vector(external_phi, "external_phi");
-  data_out.build_patches();
+    DataOut<dim> data_out;
 
-  const std::string
-    filename = Utilities::int_to_string(dim) + "d_external.vtk";
-  std::ofstream file(filename.c_str());
+    data_out.attach_dof_handler(external_dh);
+    data_out.add_data_vector(external_phi, "external_phi");
+    data_out.build_patches();
 
-  data_out.write_vtk(file);
-}
+    const std::string
+      filename = Utilities::int_to_string(dim) + "d_external.vtk";
+    std::ofstream file(filename.c_str());
+
+    data_out.write_vtk(file);
+  }
 
 
-                                // @sect4{BEMProblem::output_results}
+                                  // @sect4{BEMProblem::output_results}
 
-                                // Outputting the results of our
-                                // computations is a rather
-                                // mechanical tasks. All the
-                                // components of this function have
-                                // been discussed before.
-template <int dim>
-void BEMProblem<dim>::output_results(const unsigned int cycle)
-{
-  DataOut<dim-1, DoFHandler<dim-1, dim> > dataout;
+                                  // Outputting the results of our
+                                  // computations is a rather
+                                  // mechanical tasks. All the
+                                  // components of this function have
+                                  // been discussed before.
+  template <int dim>
+  void BEMProblem<dim>::output_results(const unsigned int cycle)
+  {
+    DataOut<dim-1, DoFHandler<dim-1, dim> > dataout;
 
-  dataout.attach_dof_handler(dh);
-  dataout.add_data_vector(phi, "phi");
-  dataout.add_data_vector(alpha, "alpha");
-  dataout.build_patches(mapping,
-                       mapping.get_degree(),
-                       DataOut<dim-1, DoFHandler<dim-1, dim> >::curved_inner_cells);
+    dataout.attach_dof_handler(dh);
+    dataout.add_data_vector(phi, "phi");
+    dataout.add_data_vector(alpha, "alpha");
+    dataout.build_patches(mapping,
+                         mapping.get_degree(),
+                         DataOut<dim-1, DoFHandler<dim-1, dim> >::curved_inner_cells);
 
-  std::string filename = ( Utilities::int_to_string(dim) +
-                          "d_boundary_solution_" +
-                          Utilities::int_to_string(cycle) +
-                          ".vtk" );
-  std::ofstream file(filename.c_str());
+    std::string filename = ( Utilities::int_to_string(dim) +
+                            "d_boundary_solution_" +
+                            Utilities::int_to_string(cycle) +
+                            ".vtk" );
+    std::ofstream file(filename.c_str());
 
-  dataout.write_vtk(file);
+    dataout.write_vtk(file);
 
-  if(cycle == n_cycles-1)
-    {
-      convergence_table.set_precision("L2(phi)", 3);
-      convergence_table.set_precision("Linfty(alpha)", 3);
-
-      convergence_table.set_scientific("L2(phi)", true);
-      convergence_table.set_scientific("Linfty(alpha)", true);
-
-      convergence_table
-       .evaluate_convergence_rates("L2(phi)", ConvergenceTable::reduction_rate_log2);
-      convergence_table
-       .evaluate_convergence_rates("Linfty(alpha)", ConvergenceTable::reduction_rate_log2);
-      deallog << std::endl;
-      convergence_table.write_text(std::cout);
-    }
-}
+    if (cycle == n_cycles-1)
+      {
+       convergence_table.set_precision("L2(phi)", 3);
+       convergence_table.set_precision("Linfty(alpha)", 3);
+
+       convergence_table.set_scientific("L2(phi)", true);
+       convergence_table.set_scientific("Linfty(alpha)", true);
+
+       convergence_table
+         .evaluate_convergence_rates("L2(phi)", ConvergenceTable::reduction_rate_log2);
+       convergence_table
+         .evaluate_convergence_rates("Linfty(alpha)", ConvergenceTable::reduction_rate_log2);
+       deallog << std::endl;
+       convergence_table.write_text(std::cout);
+      }
+  }
 
 
-                                // @sect4{BEMProblem::run}
+                                  // @sect4{BEMProblem::run}
 
-                                // This is the main function. It
-                                // should be self explanatory in its
-                                // briefness:
-template <int dim>
-void BEMProblem<dim>::run()
-{
+                                  // This is the main function. It
+                                  // should be self explanatory in its
+                                  // briefness:
+  template <int dim>
+  void BEMProblem<dim>::run()
+  {
 
-  read_parameters("parameters.prm");
+    read_parameters("parameters.prm");
 
-  if(run_in_this_dimension == false)
-    {
-      deallog << "Run in dimension " << dim
-             << " explicitly disabled in parameter file. "
-             << std::endl;
-      return;
-    }
+    if (run_in_this_dimension == false)
+      {
+       deallog << "Run in dimension " << dim
+               << " explicitly disabled in parameter file. "
+               << std::endl;
+       return;
+      }
 
-  read_domain();
+    read_domain();
 
-  for(unsigned int cycle=0; cycle<n_cycles; ++cycle)
-    {
-      refine_and_resize();
-      assemble_system();
-      solve_system();
-      compute_errors(cycle);
-      output_results(cycle);
-    }
+    for (unsigned int cycle=0; cycle<n_cycles; ++cycle)
+      {
+       refine_and_resize();
+       assemble_system();
+       solve_system();
+       compute_errors(cycle);
+       output_results(cycle);
+      }
 
-  if(extend_solution == true)
-    compute_exterior_solution();
+    if (extend_solution == true)
+      compute_exterior_solution();
+  }
 }
 
 
@@ -1458,8 +1462,11 @@ int main ()
 {
   try
     {
-      unsigned int degree = 1;
-      unsigned int mapping_degree = 1;
+      using namespace dealii;
+      using namespace Step34;
+
+      const unsigned int degree = 1;
+      const unsigned int mapping_degree = 1;
 
       deallog.depth_console (3);
       BEMProblem<2> laplace_problem_2d(degree, mapping_degree);
index 6a1c0b70c69abf9181dc1761a6d5aedae66bbc1d..4402ddd0835f189843dee96b38b6e6582199e681 100644 (file)
@@ -1,7 +1,7 @@
 /* $Id$ */
 /* Version: $Name:  $ */
 /*      */
-/*    Copyright (C) 2007, 2008, 2009, 2010 by the deal.II authors */
+/*    Copyright (C) 2007, 2008, 2009, 2010, 2011 by the deal.II authors */
 /*    Author: Abner Salgado, Texas A&M University 2009 */
 /*                                                                */
 /*    This file is subject to QPL and may not be  distributed     */
 #include <cmath>
 #include <iostream>
 
-                                // Finally we import all the deal.II
-                                // names to the global namespace
-using namespace dealii;
-
-
-
-                                // @sect3{Run time parameters}
-                                //
-                                // Since our method has several
-                                // parameters that can be fine-tuned
-                                // we put them into an external file,
-                                // so that they can be determined at
-                                // run-time.
-                                //
-                                // This includes, in particular, the
-                                // formulation of the equation for
-                                // the auxiliary variable $\phi$, for
-                                // which we declare an
-                                // <code>enum</code>.  Next, we
-                                // declare a class that is going to
-                                // read and store all the parameters
-                                // that our program needs to run.
-namespace RunTimeParameters
+                                // Finally this is as in all previous
+                                // programs:
+namespace Step35
 {
-  enum MethodFormulation
+  using namespace dealii;
+
+
+
+                                  // @sect3{Run time parameters}
+                                  //
+                                  // Since our method has several
+                                  // parameters that can be fine-tuned
+                                  // we put them into an external file,
+                                  // so that they can be determined at
+                                  // run-time.
+                                  //
+                                  // This includes, in particular, the
+                                  // formulation of the equation for
+                                  // the auxiliary variable $\phi$, for
+                                  // which we declare an
+                                  // <code>enum</code>.  Next, we
+                                  // declare a class that is going to
+                                  // read and store all the parameters
+                                  // that our program needs to run.
+  namespace RunTimeParameters
   {
-       METHOD_STANDARD,
-       METHOD_ROTATIONAL
-  };
-
-  class Data_Storage
-  {
-    public:
-      Data_Storage();
-      ~Data_Storage();
-      void read_data (const char *filename);
-      MethodFormulation form;
-      double initial_time,
-      final_time,
-      Reynolds;
-      double dt;
-      unsigned int n_global_refines,
-      pressure_degree;
-      unsigned int vel_max_iterations,
-      vel_Krylov_size,
-      vel_off_diagonals,
-      vel_update_prec;
-      double vel_eps,
-      vel_diag_strength;
-      bool verbose;
-      unsigned int output_interval;
-    protected:
-      ParameterHandler prm;
-  };
-
-                                  // In the constructor of this class
-                                  // we declare all the
-                                  // parameters. The details of how
-                                  // this works have been discussed
-                                  // elsewhere, for example in
-                                  // step-19 and step-29.
-  Data_Storage::Data_Storage()
-  {
-    prm.declare_entry ("Method_Form", "rotational",
-                      Patterns::Selection ("rotational|standard"),
-                      " Used to select the type of method that we are going "
-                      "to use. ");
-    prm.enter_subsection ("Physical data");
+    enum MethodFormulation
     {
-      prm.declare_entry ("initial_time", "0.",
-                        Patterns::Double (0.),
-                        " The initial time of the simulation. ");
-      prm.declare_entry ("final_time", "1.",
-                        Patterns::Double (0.),
-                        " The final time of the simulation. ");
-      prm.declare_entry ("Reynolds", "1.",
-                        Patterns::Double (0.),
-                        " The Reynolds number. ");
-    }
-    prm.leave_subsection();
+         METHOD_STANDARD,
+         METHOD_ROTATIONAL
+    };
 
-    prm.enter_subsection ("Time step data");
+    class Data_Storage
     {
-      prm.declare_entry ("dt", "5e-4",
-                        Patterns::Double (0.),
-                        " The time step size. ");
-    }
-    prm.leave_subsection();
+      public:
+       Data_Storage();
+       ~Data_Storage();
+       void read_data (const char *filename);
+       MethodFormulation form;
+       double initial_time,
+       final_time,
+       Reynolds;
+       double dt;
+       unsigned int n_global_refines,
+       pressure_degree;
+       unsigned int vel_max_iterations,
+       vel_Krylov_size,
+       vel_off_diagonals,
+       vel_update_prec;
+       double vel_eps,
+       vel_diag_strength;
+       bool verbose;
+       unsigned int output_interval;
+      protected:
+       ParameterHandler prm;
+    };
 
-    prm.enter_subsection ("Space discretization");
+                                    // In the constructor of this class
+                                    // we declare all the
+                                    // parameters. The details of how
+                                    // this works have been discussed
+                                    // elsewhere, for example in
+                                    // step-19 and step-29.
+    Data_Storage::Data_Storage()
     {
-      prm.declare_entry ("n_of_refines", "0",
-                        Patterns::Integer (0, 15),
-                         " The number of global refines we do on the mesh. ");
-      prm.declare_entry ("pressure_fe_degree", "1",
-                        Patterns::Integer (1, 5),
-                         " The polynomial degree for the pressure space. ");
-    }
-    prm.leave_subsection();
+      prm.declare_entry ("Method_Form", "rotational",
+                        Patterns::Selection ("rotational|standard"),
+                        " Used to select the type of method that we are going "
+                        "to use. ");
+      prm.enter_subsection ("Physical data");
+      {
+       prm.declare_entry ("initial_time", "0.",
+                          Patterns::Double (0.),
+                          " The initial time of the simulation. ");
+       prm.declare_entry ("final_time", "1.",
+                          Patterns::Double (0.),
+                          " The final time of the simulation. ");
+       prm.declare_entry ("Reynolds", "1.",
+                          Patterns::Double (0.),
+                          " The Reynolds number. ");
+      }
+      prm.leave_subsection();
 
-    prm.enter_subsection ("Data solve velocity");
-    {
-      prm.declare_entry ("max_iterations", "1000",
-                        Patterns::Integer (1, 1000),
-                         " The maximal number of iterations GMRES must make. ");
-      prm.declare_entry ("eps", "1e-12",
-                        Patterns::Double (0.),
-                        " The stopping criterion. ");
-      prm.declare_entry ("Krylov_size", "30",
-                        Patterns::Integer(1),
-                        " The size of the Krylov subspace to be used. ");
-      prm.declare_entry ("off_diagonals", "60",
-                        Patterns::Integer(0),
-                         " The number of off-diagonal elements ILU must "
-                        "compute. ");
-      prm.declare_entry ("diag_strength", "0.01",
-                        Patterns::Double (0.),
-                        " Diagonal strengthening coefficient. ");
-      prm.declare_entry ("update_prec", "15",
+      prm.enter_subsection ("Time step data");
+      {
+       prm.declare_entry ("dt", "5e-4",
+                          Patterns::Double (0.),
+                          " The time step size. ");
+      }
+      prm.leave_subsection();
+
+      prm.enter_subsection ("Space discretization");
+      {
+       prm.declare_entry ("n_of_refines", "0",
+                          Patterns::Integer (0, 15),
+                          " The number of global refines we do on the mesh. ");
+       prm.declare_entry ("pressure_fe_degree", "1",
+                          Patterns::Integer (1, 5),
+                          " The polynomial degree for the pressure space. ");
+      }
+      prm.leave_subsection();
+
+      prm.enter_subsection ("Data solve velocity");
+      {
+       prm.declare_entry ("max_iterations", "1000",
+                          Patterns::Integer (1, 1000),
+                          " The maximal number of iterations GMRES must make. ");
+       prm.declare_entry ("eps", "1e-12",
+                          Patterns::Double (0.),
+                          " The stopping criterion. ");
+       prm.declare_entry ("Krylov_size", "30",
+                          Patterns::Integer(1),
+                          " The size of the Krylov subspace to be used. ");
+       prm.declare_entry ("off_diagonals", "60",
+                          Patterns::Integer(0),
+                          " The number of off-diagonal elements ILU must "
+                          "compute. ");
+       prm.declare_entry ("diag_strength", "0.01",
+                          Patterns::Double (0.),
+                          " Diagonal strengthening coefficient. ");
+       prm.declare_entry ("update_prec", "15",
+                          Patterns::Integer(1),
+                          " This number indicates how often we need to "
+                          "update the preconditioner");
+      }
+      prm.leave_subsection();
+
+      prm.declare_entry ("verbose", "true",
+                        Patterns::Bool(),
+                        " This indicates whether the output of the solution "
+                        "process should be verbose. ");
+
+      prm.declare_entry ("output_interval", "1",
                         Patterns::Integer(1),
-                         " This number indicates how often we need to "
-                        "update the preconditioner");
+                        " This indicates between how many time steps we print "
+                        "the solution. ");
     }
-    prm.leave_subsection();
 
-    prm.declare_entry ("verbose", "true",
-                      Patterns::Bool(),
-                       " This indicates whether the output of the solution "
-                      "process should be verbose. ");
 
-    prm.declare_entry ("output_interval", "1",
-                      Patterns::Integer(1),
-                       " This indicates between how many time steps we print "
-                      "the solution. ");
-  }
 
+    Data_Storage::~Data_Storage()
+    {}
 
 
-  Data_Storage::~Data_Storage()
-  {}
 
+    void Data_Storage::read_data (const char *filename)
+    {
+      std::ifstream file (filename);
+      AssertThrow (file, ExcFileNotOpen (filename));
 
+      prm.read_input (file);
 
-  void Data_Storage::read_data (const char *filename)
-  {
-    std::ifstream file (filename);
-    AssertThrow (file, ExcFileNotOpen (filename));
+      if (prm.get ("Method_Form") == std::string ("rotational"))
+       form = METHOD_ROTATIONAL;
+      else
+       form = METHOD_STANDARD;
 
-    prm.read_input (file);
+      prm.enter_subsection ("Physical data");
+      {
+       initial_time = prm.get_double ("initial_time");
+       final_time   = prm.get_double ("final_time");
+       Reynolds     = prm.get_double ("Reynolds");
+      }
+      prm.leave_subsection();
 
-    if (prm.get ("Method_Form") == std::string ("rotational"))
-      form = METHOD_ROTATIONAL;
-    else
-      form = METHOD_STANDARD;
+      prm.enter_subsection ("Time step data");
+      {
+       dt = prm.get_double ("dt");
+      }
+      prm.leave_subsection();
 
-    prm.enter_subsection ("Physical data");
-    {
-      initial_time = prm.get_double ("initial_time");
-      final_time   = prm.get_double ("final_time");
-      Reynolds     = prm.get_double ("Reynolds");
-    }
-    prm.leave_subsection();
+      prm.enter_subsection ("Space discretization");
+      {
+       n_global_refines = prm.get_integer ("n_of_refines");
+       pressure_degree     = prm.get_integer ("pressure_fe_degree");
+      }
+      prm.leave_subsection();
 
-    prm.enter_subsection ("Time step data");
-    {
-      dt = prm.get_double ("dt");
+      prm.enter_subsection ("Data solve velocity");
+      {
+       vel_max_iterations = prm.get_integer ("max_iterations");
+       vel_eps            = prm.get_double ("eps");
+       vel_Krylov_size    = prm.get_integer ("Krylov_size");
+       vel_off_diagonals  = prm.get_integer ("off_diagonals");
+       vel_diag_strength  = prm.get_double ("diag_strength");
+       vel_update_prec    = prm.get_integer ("update_prec");
+      }
+      prm.leave_subsection();
+
+      verbose = prm.get_bool ("verbose");
+
+      output_interval = prm.get_integer ("output_interval");
     }
-    prm.leave_subsection();
+  }
+
 
-    prm.enter_subsection ("Space discretization");
+
+                                  // @sect3{Equation data}
+
+                                  // In the next namespace, we declare
+                                  // the initial and boundary
+                                  // conditions:
+  namespace EquationData
+  {
+                                    // As we have chosen a completely
+                                    // decoupled formulation, we will
+                                    // not take advantage of deal.II's
+                                    // capabilities to handle vector
+                                    // valued problems. We do, however,
+                                    // want to use an interface for the
+                                    // equation data that is somehow
+                                    // dimension independent. To be
+                                    // able to do that, our functions
+                                    // should be able to know on which
+                                    // spatial component we are
+                                    // currently working, and we should
+                                    // be able to have a common
+                                    // interface to do that. The
+                                    // following class is an attempt in
+                                    // that direction.
+    template <int dim>
+    class MultiComponentFunction: public Function<dim>
     {
-      n_global_refines = prm.get_integer ("n_of_refines");
-      pressure_degree     = prm.get_integer ("pressure_fe_degree");
-    }
-    prm.leave_subsection();
+      public:
+       MultiComponentFunction (const double initial_time = 0.);
+       void set_component (const unsigned int d);
+      protected:
+       unsigned int comp;
+    };
 
-    prm.enter_subsection ("Data solve velocity");
+    template <int dim>
+    MultiComponentFunction<dim>::
+    MultiComponentFunction (const double initial_time)
+                   :
+                   Function<dim> (1, initial_time), comp(0)
+    {}
+
+
+    template <int dim>
+    void MultiComponentFunction<dim>::set_component(const unsigned int d)
     {
-      vel_max_iterations = prm.get_integer ("max_iterations");
-      vel_eps            = prm.get_double ("eps");
-      vel_Krylov_size    = prm.get_integer ("Krylov_size");
-      vel_off_diagonals  = prm.get_integer ("off_diagonals");
-      vel_diag_strength  = prm.get_double ("diag_strength");
-      vel_update_prec    = prm.get_integer ("update_prec");
+      Assert (d<dim, ExcIndexRange (d, 0, dim));
+      comp = d;
     }
-    prm.leave_subsection();
 
-    verbose = prm.get_bool ("verbose");
 
-    output_interval = prm.get_integer ("output_interval");
-  }
-}
+                                    // With this class defined, we
+                                    // declare classes that describe
+                                    // the boundary conditions for
+                                    // velocity and pressure:
+    template <int dim>
+    class Velocity : public MultiComponentFunction<dim>
+    {
+      public:
+       Velocity (const double initial_time = 0.0);
 
+       virtual double value (const Point<dim> &p,
+                             const unsigned int component = 0) const;
 
+       virtual void value_list (const std::vector< Point<dim> > &points,
+                                std::vector<double> &values,
+                                const unsigned int component = 0) const;
+    };
 
-                                // @sect3{Equation data}
 
-                                // In the next namespace, we declare
-                                // the initial and boundary
-                                // conditions:
-namespace EquationData
-{
-                                  // As we have chosen a completely
-                                  // decoupled formulation, we will
-                                  // not take advantage of deal.II's
-                                  // capabilities to handle vector
-                                  // valued problems. We do, however,
-                                  // want to use an interface for the
-                                  // equation data that is somehow
-                                  // dimension independent. To be
-                                  // able to do that, our functions
-                                  // should be able to know on which
-                                  // spatial component we are
-                                  // currently working, and we should
-                                  // be able to have a common
-                                  // interface to do that. The
-                                  // following class is an attempt in
-                                  // that direction.
-  template <int dim>
-  class MultiComponentFunction: public Function<dim>
-  {
-    public:
-      MultiComponentFunction (const double initial_time = 0.);
-      void set_component (const unsigned int d);
-    protected:
-      unsigned int comp;
-  };
+    template <int dim>
+    Velocity<dim>::Velocity (const double initial_time)
+                   :
+                   MultiComponentFunction<dim> (initial_time)
+    {}
 
-  template <int dim>
-  MultiComponentFunction<dim>::
-  MultiComponentFunction (const double initial_time)
-                 :
-                 Function<dim> (1, initial_time), comp(0)
-  {}
 
+    template <int dim>
+    void Velocity<dim>::value_list (const std::vector<Point<dim> > &points,
+                                   std::vector<double> &values,
+                                   const unsigned int) const
+    {
+      const unsigned int n_points = points.size();
+      Assert (values.size() == n_points,
+             ExcDimensionMismatch (values.size(), n_points));
+      for (unsigned int i=0; i<n_points; ++i)
+       values[i] = Velocity<dim>::value (points[i]);
+    }
 
-  template <int dim>
-  void MultiComponentFunction<dim>::set_component(const unsigned int d)
-  {
-    Assert (d<dim, ExcIndexRange (d, 0, dim));
-    comp = d;
-  }
 
+    template <int dim>
+    double Velocity<dim>::value (const Point<dim> &p,
+                                const unsigned int) const
+    {
+      if (this->comp == 0)
+       {
+         const double Um = 1.5;
+         const double H  = 4.1;
+         return 4.*Um*p(1)*(H - p(1))/(H*H);
+       }
+      else
+       return 0.;
+    }
 
-                                  // With this class defined, we
-                                  // declare classes that describe
-                                  // the boundary conditions for
-                                  // velocity and pressure:
-  template <int dim>
-  class Velocity : public MultiComponentFunction<dim>
-  {
-    public:
-      Velocity (const double initial_time = 0.0);
 
-      virtual double value (const Point<dim> &p,
-                           const unsigned int component = 0) const;
 
-      virtual void value_list (const std::vector< Point<dim> > &points,
-                              std::vector<double> &values,
-                              const unsigned int component = 0) const;
-  };
+    template <int dim>
+    class Pressure: public Function<dim>
+    {
+      public:
+       Pressure (const double initial_time = 0.0);
 
+       virtual double value (const Point<dim> &p,
+                             const unsigned int component = 0) const;
 
-  template <int dim>
-  Velocity<dim>::Velocity (const double initial_time)
-                 :
-                 MultiComponentFunction<dim> (initial_time)
-  {}
+       virtual void value_list (const std::vector< Point<dim> > &points,
+                                std::vector<double> &values,
+                                const unsigned int component = 0) const;
+    };
 
+    template <int dim>
+    Pressure<dim>::Pressure (const double initial_time)
+                   :
+                   Function<dim> (1, initial_time)
+    {}
 
-  template <int dim>
-  void Velocity<dim>::value_list (const std::vector<Point<dim> > &points,
-                                 std::vector<double> &values,
-                                 const unsigned int) const
-  {
-    const unsigned int n_points = points.size();
-    Assert (values.size() == n_points,
-           ExcDimensionMismatch (values.size(), n_points));
-    for (unsigned int i=0; i<n_points; ++i)
-      values[i] = Velocity<dim>::value (points[i]);
-  }
 
+    template <int dim>
+    double Pressure<dim>::value (const Point<dim> &p,
+                                const unsigned int) const
+    {
+      return 25.-p(0);
+    }
 
-  template <int dim>
-  double Velocity<dim>::value (const Point<dim> &p,
-                              const unsigned int) const
-  {
-    if (this->comp == 0)
-      {
-       const double Um = 1.5;
-       const double H  = 4.1;
-       return 4.*Um*p(1)*(H - p(1))/(H*H);
-      }
-    else
-      return 0.;
+    template <int dim>
+    void Pressure<dim>::value_list (const std::vector<Point<dim> > &points,
+                                   std::vector<double> &values,
+                                   const unsigned int) const
+    {
+      const unsigned int n_points = points.size();
+      Assert (values.size() == n_points, ExcDimensionMismatch (values.size(), n_points));
+      for (unsigned int i=0; i<n_points; ++i)
+       values[i] = Pressure<dim>::value (points[i]);
+    }
   }
 
 
 
+                                  // @sect3{The <code>NavierStokesProjection</code> class}
+
+                                  // Now for the main class of the program. It
+                                  // implements the various versions of the
+                                  // projection method for Navier-Stokes
+                                  // equations.  The names for all the methods
+                                  // and member variables should be
+                                  // self-explanatory, taking into account the
+                                  // implementation details given in the
+                                  // introduction.
   template <int dim>
-  class Pressure: public Function<dim>
+  class NavierStokesProjection
   {
     public:
-      Pressure (const double initial_time = 0.0);
-
-      virtual double value (const Point<dim> &p,
-                           const unsigned int component = 0) const;
+      NavierStokesProjection (const RunTimeParameters::Data_Storage &data);
 
-      virtual void value_list (const std::vector< Point<dim> > &points,
-                              std::vector<double> &values,
-                              const unsigned int component = 0) const;
+      void run (const bool         verbose    = false,
+               const unsigned int n_plots = 10);
+    protected:
+      RunTimeParameters::MethodFormulation type;
+
+      const unsigned int deg;
+      const double       dt;
+      const double       t_0, T, Re;
+
+      EquationData::Velocity<dim>    vel_exact;
+      std::map<unsigned int, double> boundary_values;
+      std::vector<unsigned char>     boundary_indicators;
+
+      Triangulation<dim> triangulation;
+
+      FE_Q<dim>          fe_velocity;
+      FE_Q<dim>          fe_pressure;
+
+      DoFHandler<dim>    dof_handler_velocity;
+      DoFHandler<dim>    dof_handler_pressure;
+
+      QGauss<dim>        quadrature_pressure;
+      QGauss<dim>        quadrature_velocity;
+
+      SparsityPattern    sparsity_pattern_velocity;
+      SparsityPattern    sparsity_pattern_pressure;
+      SparsityPattern    sparsity_pattern_pres_vel;
+
+      SparseMatrix<double> vel_Laplace_plus_Mass;
+      SparseMatrix<double> vel_it_matrix[dim];
+      SparseMatrix<double> vel_Mass;
+      SparseMatrix<double> vel_Laplace;
+      SparseMatrix<double> vel_Advection;
+      SparseMatrix<double> pres_Laplace;
+      SparseMatrix<double> pres_Mass;
+      SparseMatrix<double> pres_Diff[dim];
+      SparseMatrix<double> pres_iterative;
+
+      Vector<double> pres_n;
+      Vector<double> pres_n_minus_1;
+      Vector<double> phi_n;
+      Vector<double> phi_n_minus_1;
+      Vector<double> u_n[dim];
+      Vector<double> u_n_minus_1[dim];
+      Vector<double> u_star[dim];
+      Vector<double> force[dim];
+      Vector<double> v_tmp;
+      Vector<double> pres_tmp;
+      Vector<double> rot_u;
+
+      SparseILU<double> prec_velocity[dim];
+      SparseILU<double> prec_pres_Laplace;
+      SparseDirectUMFPACK prec_mass;
+      SparseDirectUMFPACK prec_vel_mass;
+
+      DeclException2 (ExcInvalidTimeStep,
+                     double, double,
+                     << " The time step " << arg1 << " is out of range."
+                     << std::endl
+                     << " The permitted range is (0," << arg2 << "]");
+
+      void create_triangulation_and_dofs (const unsigned int n_refines);
+
+      void initialize();
+
+      void interpolate_velocity ();
+
+      void diffusion_step (const bool reinit_prec);
+
+      void projection_step (const bool reinit_prec);
+
+      void update_pressure (const bool reinit_prec);
+
+    private:
+      unsigned int vel_max_its;
+      unsigned int vel_Krylov_size;
+      unsigned int vel_off_diagonals;
+      unsigned int vel_update_prec;
+      double       vel_eps;
+      double       vel_diag_strength;
+
+      void initialize_velocity_matrices();
+
+      void initialize_pressure_matrices();
+
+                                      // The next few structures and functions
+                                      // are for doing various things in
+                                      // parallel. They follow the scheme laid
+                                      // out in @ref threads, using the
+                                      // WorkStream class. As explained there,
+                                      // this requires us to declare two
+                                      // structures for each of the assemblers,
+                                      // a per-task data and a scratch data
+                                      // structure. These are then handed over
+                                      // to functions that assemble local
+                                      // contributions and that copy these
+                                      // local contributions to the global
+                                      // objects.
+                                      //
+                                      // One of the things that are specific to
+                                      // this program is that we don't just
+                                      // have a single DoFHandler object that
+                                      // represents both the velocities and the
+                                      // pressure, but we use individual
+                                      // DoFHandler objects for these two kinds
+                                      // of variables. We pay for this
+                                      // optimization when we want to assemble
+                                      // terms that involve both variables,
+                                      // such as the divergence of the velocity
+                                      // and the gradient of the pressure,
+                                      // times the respective test
+                                      // functions. When doing so, we can't
+                                      // just anymore use a single FEValues
+                                      // object, but rather we need two, and
+                                      // they need to be initialized with cell
+                                      // iterators that point to the same cell
+                                      // in the triangulation but different
+                                      // DoFHandlers.
+                                      //
+                                      // To do this in practice, we declare a
+                                      // "synchronous" iterator -- an object
+                                      // that internally consists of several
+                                      // (in our case two) iterators, and each
+                                      // time the synchronous iteration is
+                                      // moved up one step, each of the
+                                      // iterators stored internally is moved
+                                      // up one step as well, thereby always
+                                      // staying in sync. As it so happens,
+                                      // there is a deal.II class that
+                                      // facilitates this sort of thing.
+      typedef std_cxx1x::tuple< typename DoFHandler<dim>::active_cell_iterator,
+                               typename DoFHandler<dim>::active_cell_iterator
+                               > IteratorTuple;
+
+      typedef SynchronousIterators<IteratorTuple> IteratorPair;
+
+      void initialize_gradient_operator();
+
+      struct InitGradPerTaskData
+      {
+         unsigned int              d;
+         unsigned int              vel_dpc;
+         unsigned int              pres_dpc;
+         FullMatrix<double>        local_grad;
+         std::vector<unsigned int> vel_local_dof_indices;
+         std::vector<unsigned int> pres_local_dof_indices;
+
+         InitGradPerTaskData (const unsigned int dd,
+                              const unsigned int vdpc,
+                              const unsigned int pdpc)
+                         :
+                         d(dd),
+                         vel_dpc (vdpc),
+                         pres_dpc (pdpc),
+                         local_grad (vdpc, pdpc),
+                         vel_local_dof_indices (vdpc),
+                         pres_local_dof_indices (pdpc)
+           {}
+      };
+
+      struct InitGradScratchData
+      {
+         unsigned int  nqp;
+         FEValues<dim> fe_val_vel;
+         FEValues<dim> fe_val_pres;
+         InitGradScratchData (const FE_Q<dim> &fe_v,
+                              const FE_Q<dim> &fe_p,
+                              const QGauss<dim> &quad,
+                              const UpdateFlags flags_v,
+                              const UpdateFlags flags_p)
+                         :
+                         nqp (quad.size()),
+                         fe_val_vel (fe_v, quad, flags_v),
+                         fe_val_pres (fe_p, quad, flags_p)
+           {}
+         InitGradScratchData (const InitGradScratchData &data)
+                         :
+                         nqp (data.nqp),
+                         fe_val_vel (data.fe_val_vel.get_fe(),
+                                     data.fe_val_vel.get_quadrature(),
+                                     data.fe_val_vel.get_update_flags()),
+                         fe_val_pres (data.fe_val_pres.get_fe(),
+                                      data.fe_val_pres.get_quadrature(),
+                                      data.fe_val_pres.get_update_flags())
+           {}
+      };
+
+      void assemble_one_cell_of_gradient (const IteratorPair  &SI,
+                                         InitGradScratchData &scratch,
+                                         InitGradPerTaskData &data);
+
+      void copy_gradient_local_to_global (const InitGradPerTaskData &data);
+
+                                      // The same general layout also applies
+                                      // to the following classes and functions
+                                      // implementing the assembly of the
+                                      // advection term:
+      void assemble_advection_term();
+
+      struct AdvectionPerTaskData
+      {
+         FullMatrix<double>        local_advection;
+         std::vector<unsigned int> local_dof_indices;
+         AdvectionPerTaskData (const unsigned int dpc)
+                         :
+                         local_advection (dpc, dpc),
+                         local_dof_indices (dpc)
+           {}
+      };
+
+      struct AdvectionScratchData
+      {
+         unsigned int                 nqp;
+         unsigned int                 dpc;
+         std::vector< Point<dim> >    u_star_local;
+         std::vector< Tensor<1,dim> > grad_u_star;
+         std::vector<double>          u_star_tmp;
+         FEValues<dim>                fe_val;
+         AdvectionScratchData (const FE_Q<dim> &fe,
+                               const QGauss<dim> &quad,
+                               const UpdateFlags flags)
+                         :
+                         nqp (quad.size()),
+                         dpc (fe.dofs_per_cell),
+                         u_star_local (nqp),
+                         grad_u_star (nqp),
+                         u_star_tmp (nqp),
+                         fe_val (fe, quad, flags)
+           {}
+
+         AdvectionScratchData (const AdvectionScratchData &data)
+                         :
+                         nqp (data.nqp),
+                         dpc (data.dpc),
+                         u_star_local (nqp),
+                         grad_u_star (nqp),
+                         u_star_tmp (nqp),
+                         fe_val (data.fe_val.get_fe(),
+                                 data.fe_val.get_quadrature(),
+                                 data.fe_val.get_update_flags())
+           {}
+      };
+
+      void assemble_one_cell_of_advection (const typename DoFHandler<dim>::active_cell_iterator &cell,
+                                          AdvectionScratchData &scratch,
+                                          AdvectionPerTaskData &data);
+
+      void copy_advection_local_to_global (const AdvectionPerTaskData &data);
+
+                                      // The final few functions implement the
+                                      // diffusion solve as well as
+                                      // postprocessing the output, including
+                                      // computing the curl of the velocity:
+      void diffusion_component_solve (const unsigned int d);
+
+      void output_results (const unsigned int step);
+
+      void assemble_vorticity (const bool reinit_prec);
   };
 
-  template <int dim>
-  Pressure<dim>::Pressure (const double initial_time)
-                 :
-                 Function<dim> (1, initial_time)
-  {}
 
 
-  template <int dim>
-  double Pressure<dim>::value (const Point<dim> &p,
-                              const unsigned int) const
-  {
-    return 25.-p(0);
-  }
+                                  // @sect4{ <code>NavierStokesProjection::NavierStokesProjection</code> }
 
+                                  // In the constructor, we just read
+                                  // all the data from the
+                                  // <code>Data_Storage</code> object
+                                  // that is passed as an argument,
+                                  // verify that the data we read is
+                                  // reasonable and, finally, create
+                                  // the triangulation and load the
+                                  // initial data.
   template <int dim>
-  void Pressure<dim>::value_list (const std::vector<Point<dim> > &points,
-                                 std::vector<double> &values,
-                                 const unsigned int) const
+  NavierStokesProjection<dim>::NavierStokesProjection(const RunTimeParameters::Data_Storage &data)
+                 :
+                 type (data.form),
+                 deg (data.pressure_degree),
+                 dt (data.dt),
+                 t_0 (data.initial_time),
+                 T (data.final_time),
+                 Re (data.Reynolds),
+                 vel_exact (data.initial_time),
+                 fe_velocity (deg+1),
+                 fe_pressure (deg),
+                 dof_handler_velocity (triangulation),
+                 dof_handler_pressure (triangulation),
+                 quadrature_pressure (deg+1),
+                 quadrature_velocity (deg+2),
+                 vel_max_its (data.vel_max_iterations),
+                 vel_Krylov_size (data.vel_Krylov_size),
+                 vel_off_diagonals (data.vel_off_diagonals),
+                 vel_update_prec (data.vel_update_prec),
+                 vel_eps (data.vel_eps),
+                 vel_diag_strength (data.vel_diag_strength)
   {
-    const unsigned int n_points = points.size();
-    Assert (values.size() == n_points, ExcDimensionMismatch (values.size(), n_points));
-    for (unsigned int i=0; i<n_points; ++i)
-      values[i] = Pressure<dim>::value (points[i]);
+    if(deg < 1)
+      std::cout << " WARNING: The chosen pair of finite element spaces is not stable."
+               << std::endl
+               << " The obtained results will be nonsense"
+               << std::endl;
+
+    AssertThrow (!  ( (dt <= 0.) || (dt > .5*T)), ExcInvalidTimeStep (dt, .5*T));
+
+    create_triangulation_and_dofs (data.n_global_refines);
+    initialize();
   }
-}
 
 
+                                  // @sect4{ <code>NavierStokesProjection::create_triangulation_and_dofs</code> }
 
-                                // @sect3{The <code>NavierStokesProjection</code> class}
+                                  // The method that creates the
+                                  // triangulation and refines it the
+                                  // needed number of times.  After
+                                  // creating the triangulation, it
+                                  // creates the mesh dependent data,
+                                  // i.e. it distributes degrees of
+                                  // freedom and renumbers them, and
+                                  // initializes the matrices and
+                                  // vectors that we will use.
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::
+  create_triangulation_and_dofs (const unsigned int n_refines)
+  {
+    GridIn<dim> grid_in;
+    grid_in.attach_triangulation (triangulation);
 
-                                // Now for the main class of the program. It
-                                // implements the various versions of the
-                                // projection method for Navier-Stokes
-                                // equations.  The names for all the methods
-                                // and member variables should be
-                                // self-explanatory, taking into account the
-                                // implementation details given in the
-                                // introduction.
-template <int dim>
-class NavierStokesProjection
-{
-  public:
-    NavierStokesProjection (const RunTimeParameters::Data_Storage &data);
-
-    void run (const bool         verbose    = false,
-             const unsigned int n_plots = 10);
-  protected:
-    RunTimeParameters::MethodFormulation type;
-
-    const unsigned int deg;
-    const double       dt;
-    const double       t_0, T, Re;
-
-    EquationData::Velocity<dim>    vel_exact;
-    std::map<unsigned int, double> boundary_values;
-    std::vector<unsigned char>     boundary_indicators;
-
-    Triangulation<dim> triangulation;
-
-    FE_Q<dim>          fe_velocity;
-    FE_Q<dim>          fe_pressure;
-
-    DoFHandler<dim>    dof_handler_velocity;
-    DoFHandler<dim>    dof_handler_pressure;
-
-    QGauss<dim>        quadrature_pressure;
-    QGauss<dim>        quadrature_velocity;
-
-    SparsityPattern    sparsity_pattern_velocity;
-    SparsityPattern    sparsity_pattern_pressure;
-    SparsityPattern    sparsity_pattern_pres_vel;
-
-    SparseMatrix<double> vel_Laplace_plus_Mass;
-    SparseMatrix<double> vel_it_matrix[dim];
-    SparseMatrix<double> vel_Mass;
-    SparseMatrix<double> vel_Laplace;
-    SparseMatrix<double> vel_Advection;
-    SparseMatrix<double> pres_Laplace;
-    SparseMatrix<double> pres_Mass;
-    SparseMatrix<double> pres_Diff[dim];
-    SparseMatrix<double> pres_iterative;
-
-    Vector<double> pres_n;
-    Vector<double> pres_n_minus_1;
-    Vector<double> phi_n;
-    Vector<double> phi_n_minus_1;
-    Vector<double> u_n[dim];
-    Vector<double> u_n_minus_1[dim];
-    Vector<double> u_star[dim];
-    Vector<double> force[dim];
-    Vector<double> v_tmp;
-    Vector<double> pres_tmp;
-    Vector<double> rot_u;
-
-    SparseILU<double> prec_velocity[dim];
-    SparseILU<double> prec_pres_Laplace;
-    SparseDirectUMFPACK prec_mass;
-    SparseDirectUMFPACK prec_vel_mass;
-
-    DeclException2 (ExcInvalidTimeStep,
-                   double, double,
-                   << " The time step " << arg1 << " is out of range."
-                   << std::endl
-                   << " The permitted range is (0," << arg2 << "]");
-
-    void create_triangulation_and_dofs (const unsigned int n_refines);
-
-    void initialize();
-
-    void interpolate_velocity ();
-
-    void diffusion_step (const bool reinit_prec);
-
-    void projection_step (const bool reinit_prec);
-
-    void update_pressure (const bool reinit_prec);
-
-  private:
-    unsigned int vel_max_its;
-    unsigned int vel_Krylov_size;
-    unsigned int vel_off_diagonals;
-    unsigned int vel_update_prec;
-    double       vel_eps;
-    double       vel_diag_strength;
-
-    void initialize_velocity_matrices();
-
-    void initialize_pressure_matrices();
-
-                                    // The next few structures and functions
-                                    // are for doing various things in
-                                    // parallel. They follow the scheme laid
-                                    // out in @ref threads, using the
-                                    // WorkStream class. As explained there,
-                                    // this requires us to declare two
-                                    // structures for each of the assemblers,
-                                    // a per-task data and a scratch data
-                                    // structure. These are then handed over
-                                    // to functions that assemble local
-                                    // contributions and that copy these
-                                    // local contributions to the global
-                                    // objects.
-                                    //
-                                    // One of the things that are specific to
-                                    // this program is that we don't just
-                                    // have a single DoFHandler object that
-                                    // represents both the velocities and the
-                                    // pressure, but we use individual
-                                    // DoFHandler objects for these two kinds
-                                    // of variables. We pay for this
-                                    // optimization when we want to assemble
-                                    // terms that involve both variables,
-                                    // such as the divergence of the velocity
-                                    // and the gradient of the pressure,
-                                    // times the respective test
-                                    // functions. When doing so, we can't
-                                    // just anymore use a single FEValues
-                                    // object, but rather we need two, and
-                                    // they need to be initialized with cell
-                                    // iterators that point to the same cell
-                                    // in the triangulation but different
-                                    // DoFHandlers.
-                                    //
-                                    // To do this in practice, we declare a
-                                    // "synchronous" iterator -- an object
-                                    // that internally consists of several
-                                    // (in our case two) iterators, and each
-                                    // time the synchronous iteration is
-                                    // moved up one step, each of the
-                                    // iterators stored internally is moved
-                                    // up one step as well, thereby always
-                                    // staying in sync. As it so happens,
-                                    // there is a deal.II class that
-                                    // facilitates this sort of thing.
-    typedef std_cxx1x::tuple< typename DoFHandler<dim>::active_cell_iterator,
-                             typename DoFHandler<dim>::active_cell_iterator
-                             > IteratorTuple;
-
-    typedef SynchronousIterators<IteratorTuple> IteratorPair;
-
-    void initialize_gradient_operator();
-
-    struct InitGradPerTaskData
     {
-       unsigned int              d;
-       unsigned int              vel_dpc;
-       unsigned int              pres_dpc;
-       FullMatrix<double>        local_grad;
-       std::vector<unsigned int> vel_local_dof_indices;
-       std::vector<unsigned int> pres_local_dof_indices;
-
-       InitGradPerTaskData (const unsigned int dd,
-                            const unsigned int vdpc,
-                            const unsigned int pdpc)
-                       :
-                       d(dd),
-                       vel_dpc (vdpc),
-                       pres_dpc (pdpc),
-                       local_grad (vdpc, pdpc),
-                       vel_local_dof_indices (vdpc),
-                       pres_local_dof_indices (pdpc)
-         {}
-    };
+      std::string filename = "nsbench2.inp";
+      std::ifstream file (filename.c_str());
+      Assert (file, ExcFileNotOpen (filename.c_str()));
+      grid_in.read_ucd (file);
+    }
 
-    struct InitGradScratchData
-    {
-       unsigned int  nqp;
-       FEValues<dim> fe_val_vel;
-       FEValues<dim> fe_val_pres;
-       InitGradScratchData (const FE_Q<dim> &fe_v,
-                            const FE_Q<dim> &fe_p,
-                            const QGauss<dim> &quad,
-                            const UpdateFlags flags_v,
-                            const UpdateFlags flags_p)
-                       :
-                       nqp (quad.size()),
-                       fe_val_vel (fe_v, quad, flags_v),
-                       fe_val_pres (fe_p, quad, flags_p)
-         {}
-       InitGradScratchData (const InitGradScratchData &data)
-                       :
-                       nqp (data.nqp),
-                       fe_val_vel (data.fe_val_vel.get_fe(),
-                                   data.fe_val_vel.get_quadrature(),
-                                   data.fe_val_vel.get_update_flags()),
-                       fe_val_pres (data.fe_val_pres.get_fe(),
-                                    data.fe_val_pres.get_quadrature(),
-                                    data.fe_val_pres.get_update_flags())
-         {}
-    };
+    std::cout << "Number of refines = " << n_refines
+             << std::endl;
+    triangulation.refine_global (n_refines);
+    std::cout << "Number of active cells: " << triangulation.n_active_cells()
+             << std::endl;
 
-    void assemble_one_cell_of_gradient (const IteratorPair  &SI,
-                                       InitGradScratchData &scratch,
-                                       InitGradPerTaskData &data);
+    boundary_indicators = triangulation.get_boundary_indicators();
 
-    void copy_gradient_local_to_global (const InitGradPerTaskData &data);
+    dof_handler_velocity.distribute_dofs (fe_velocity);
+    DoFRenumbering::boost::Cuthill_McKee (dof_handler_velocity);
+    dof_handler_pressure.distribute_dofs (fe_pressure);
+    DoFRenumbering::boost::Cuthill_McKee (dof_handler_pressure);
 
-                                    // The same general layout also applies
-                                    // to the following classes and functions
-                                    // implementing the assembly of the
-                                    // advection term:
-    void assemble_advection_term();
+    initialize_velocity_matrices();
+    initialize_pressure_matrices();
+    initialize_gradient_operator();
 
-    struct AdvectionPerTaskData
-    {
-       FullMatrix<double>        local_advection;
-       std::vector<unsigned int> local_dof_indices;
-       AdvectionPerTaskData (const unsigned int dpc)
-                       :
-                       local_advection (dpc, dpc),
-                       local_dof_indices (dpc)
-         {}
-    };
-
-    struct AdvectionScratchData
-    {
-       unsigned int                 nqp;
-       unsigned int                 dpc;
-       std::vector< Point<dim> >    u_star_local;
-       std::vector< Tensor<1,dim> > grad_u_star;
-       std::vector<double>          u_star_tmp;
-       FEValues<dim>                fe_val;
-       AdvectionScratchData (const FE_Q<dim> &fe,
-                             const QGauss<dim> &quad,
-                             const UpdateFlags flags)
-                       :
-                       nqp (quad.size()),
-                       dpc (fe.dofs_per_cell),
-                       u_star_local (nqp),
-                       grad_u_star (nqp),
-                       u_star_tmp (nqp),
-                       fe_val (fe, quad, flags)
-         {}
-
-       AdvectionScratchData (const AdvectionScratchData &data)
-                       :
-                       nqp (data.nqp),
-                       dpc (data.dpc),
-                       u_star_local (nqp),
-                       grad_u_star (nqp),
-                       u_star_tmp (nqp),
-                       fe_val (data.fe_val.get_fe(),
-                               data.fe_val.get_quadrature(),
-                               data.fe_val.get_update_flags())
-         {}
-    };
+    pres_n.reinit (dof_handler_pressure.n_dofs());
+    pres_n_minus_1.reinit (dof_handler_pressure.n_dofs());
+    phi_n.reinit (dof_handler_pressure.n_dofs());
+    phi_n_minus_1.reinit (dof_handler_pressure.n_dofs());
+    pres_tmp.reinit (dof_handler_pressure.n_dofs());
+    for(unsigned int d=0; d<dim; ++d)
+      {
+       u_n[d].reinit (dof_handler_velocity.n_dofs());
+       u_n_minus_1[d].reinit (dof_handler_velocity.n_dofs());
+       u_star[d].reinit (dof_handler_velocity.n_dofs());
+       force[d].reinit (dof_handler_velocity.n_dofs());
+      }
+    v_tmp.reinit (dof_handler_velocity.n_dofs());
+    rot_u.reinit (dof_handler_velocity.n_dofs());
 
-    void assemble_one_cell_of_advection (const typename DoFHandler<dim>::active_cell_iterator &cell,
-                                        AdvectionScratchData &scratch,
-                                        AdvectionPerTaskData &data);
-
-    void copy_advection_local_to_global (const AdvectionPerTaskData &data);
-
-                                    // The final few functions implement the
-                                    // diffusion solve as well as
-                                    // postprocessing the output, including
-                                    // computing the curl of the velocity:
-    void diffusion_component_solve (const unsigned int d);
-
-    void output_results (const unsigned int step);
-
-    void assemble_vorticity (const bool reinit_prec);
-};
-
-
-
-                                // @sect4{ <code>NavierStokesProjection::NavierStokesProjection</code> }
-
-                                // In the constructor, we just read
-                                // all the data from the
-                                // <code>Data_Storage</code> object
-                                // that is passed as an argument,
-                                // verify that the data we read is
-                                // reasonable and, finally, create
-                                // the triangulation and load the
-                                // initial data.
-template <int dim>
-NavierStokesProjection<dim>::NavierStokesProjection(const RunTimeParameters::Data_Storage &data)
-               :
-               type (data.form),
-               deg (data.pressure_degree),
-               dt (data.dt),
-               t_0 (data.initial_time),
-               T (data.final_time),
-               Re (data.Reynolds),
-               vel_exact (data.initial_time),
-               fe_velocity (deg+1),
-               fe_pressure (deg),
-               dof_handler_velocity (triangulation),
-               dof_handler_pressure (triangulation),
-               quadrature_pressure (deg+1),
-               quadrature_velocity (deg+2),
-               vel_max_its (data.vel_max_iterations),
-               vel_Krylov_size (data.vel_Krylov_size),
-               vel_off_diagonals (data.vel_off_diagonals),
-               vel_update_prec (data.vel_update_prec),
-               vel_eps (data.vel_eps),
-               vel_diag_strength (data.vel_diag_strength)
-{
-  if(deg < 1)
-    std::cout << " WARNING: The chosen pair of finite element spaces is not stable."
+    std::cout << "dim (X_h) = " << (dof_handler_velocity.n_dofs()*dim)
+             << std::endl
+             << "dim (M_h) = " << dof_handler_pressure.n_dofs()
+             << std::endl
+             << "Re        = " << Re
              << std::endl
-             << " The obtained results will be nonsense"
              << std::endl;
+  }
 
-  AssertThrow (!  ( (dt <= 0.) || (dt > .5*T)), ExcInvalidTimeStep (dt, .5*T));
-
-  create_triangulation_and_dofs (data.n_global_refines);
-  initialize();
-}
 
+                                  // @sect4{ <code>NavierStokesProjection::initialize</code> }
 
-                                // @sect4{ <code>NavierStokesProjection::create_triangulation_and_dofs</code> }
-
-                                // The method that creates the
-                                // triangulation and refines it the
-                                // needed number of times.  After
-                                // creating the triangulation, it
-                                // creates the mesh dependent data,
-                                // i.e. it distributes degrees of
-                                // freedom and renumbers them, and
-                                // initializes the matrices and
-                                // vectors that we will use.
-template <int dim>
-void
-NavierStokesProjection<dim>::
-create_triangulation_and_dofs (const unsigned int n_refines)
-{
-  GridIn<dim> grid_in;
-  grid_in.attach_triangulation (triangulation);
-
+                                  // This method creates the constant
+                                  // matrices and loads the initial
+                                  // data
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::initialize()
   {
-    std::string filename = "nsbench2.inp";
-    std::ifstream file (filename.c_str());
-    Assert (file, ExcFileNotOpen (filename.c_str()));
-    grid_in.read_ucd (file);
+    vel_Laplace_plus_Mass = 0.;
+    vel_Laplace_plus_Mass.add (1./Re, vel_Laplace);
+    vel_Laplace_plus_Mass.add (1.5/dt, vel_Mass);
+
+    EquationData::Pressure<dim> pres (t_0);
+    VectorTools::interpolate (dof_handler_pressure, pres, pres_n_minus_1);
+    pres.advance_time (dt);
+    VectorTools::interpolate (dof_handler_pressure, pres, pres_n);
+    phi_n = 0.;
+    phi_n_minus_1 = 0.;
+    for(unsigned int d=0; d<dim; ++d)
+      {
+       vel_exact.set_time (t_0);
+       vel_exact.set_component(d);
+       VectorTools::interpolate (dof_handler_velocity, ZeroFunction<dim>(), u_n_minus_1[d]);
+       vel_exact.advance_time (dt);
+       VectorTools::interpolate (dof_handler_velocity, ZeroFunction<dim>(), u_n[d]);
+      }
   }
 
-  std::cout << "Number of refines = " << n_refines
-           << std::endl;
-  triangulation.refine_global (n_refines);
-  std::cout << "Number of active cells: " << triangulation.n_active_cells()
-           << std::endl;
-
-  boundary_indicators = triangulation.get_boundary_indicators();
-
-  dof_handler_velocity.distribute_dofs (fe_velocity);
-  DoFRenumbering::boost::Cuthill_McKee (dof_handler_velocity);
-  dof_handler_pressure.distribute_dofs (fe_pressure);
-  DoFRenumbering::boost::Cuthill_McKee (dof_handler_pressure);
-
-  initialize_velocity_matrices();
-  initialize_pressure_matrices();
-  initialize_gradient_operator();
-
-  pres_n.reinit (dof_handler_pressure.n_dofs());
-  pres_n_minus_1.reinit (dof_handler_pressure.n_dofs());
-  phi_n.reinit (dof_handler_pressure.n_dofs());
-  phi_n_minus_1.reinit (dof_handler_pressure.n_dofs());
-  pres_tmp.reinit (dof_handler_pressure.n_dofs());
-  for(unsigned int d=0; d<dim; ++d)
-    {
-      u_n[d].reinit (dof_handler_velocity.n_dofs());
-      u_n_minus_1[d].reinit (dof_handler_velocity.n_dofs());
-      u_star[d].reinit (dof_handler_velocity.n_dofs());
-      force[d].reinit (dof_handler_velocity.n_dofs());
-    }
-  v_tmp.reinit (dof_handler_velocity.n_dofs());
-  rot_u.reinit (dof_handler_velocity.n_dofs());
 
-  std::cout << "dim (X_h) = " << (dof_handler_velocity.n_dofs()*dim)
-           << std::endl
-           << "dim (M_h) = " << dof_handler_pressure.n_dofs()
-           << std::endl
-           << "Re        = " << Re
-           << std::endl
-           << std::endl;
-}
-
-
-                                // @sect4{ <code>NavierStokesProjection::initialize</code> }
-
-                                // This method creates the constant
-                                // matrices and loads the initial
-                                // data
-template <int dim>
-void
-NavierStokesProjection<dim>::initialize()
-{
-  vel_Laplace_plus_Mass = 0.;
-  vel_Laplace_plus_Mass.add (1./Re, vel_Laplace);
-  vel_Laplace_plus_Mass.add (1.5/dt, vel_Mass);
-
-  EquationData::Pressure<dim> pres (t_0);
-  VectorTools::interpolate (dof_handler_pressure, pres, pres_n_minus_1);
-  pres.advance_time (dt);
-  VectorTools::interpolate (dof_handler_pressure, pres, pres_n);
-  phi_n = 0.;
-  phi_n_minus_1 = 0.;
-  for(unsigned int d=0; d<dim; ++d)
-    {
-      vel_exact.set_time (t_0);
-      vel_exact.set_component(d);
-      VectorTools::interpolate (dof_handler_velocity, ZeroFunction<dim>(), u_n_minus_1[d]);
-      vel_exact.advance_time (dt);
-      VectorTools::interpolate (dof_handler_velocity, ZeroFunction<dim>(), u_n[d]);
-    }
-}
-
-
-                                // @sect4{ The <code>NavierStokesProjection::initialize_*_matrices</code> methods }
-
-                                // In this set of methods we initialize the
-                                // sparsity patterns, the constraints (if
-                                // any) and assemble the matrices that do not
-                                // depend on the timestep
-                                // <code>dt</code>. Note that for the Laplace
-                                // and mass matrices, we can use functions in
-                                // the library that do this. Because the
-                                // expensive operations of this function --
-                                // creating the two matrices -- are entirely
-                                // independent, we could in principle mark
-                                // them as tasks that can be worked on in
-                                // %parallel using the Threads::new_task
-                                // functions. We won't do that here since
-                                // these functions internally already are
-                                // parallelized, and in particular because
-                                // the current function is only called once
-                                // per program run and so does not incur a
-                                // cost in each time step. The necessary
-                                // modifications would be quite
-                                // straightforward, however.
-template <int dim>
-void
-NavierStokesProjection<dim>::initialize_velocity_matrices()
-{
-  sparsity_pattern_velocity.reinit (dof_handler_velocity.n_dofs(),
-                                   dof_handler_velocity.n_dofs(),
-                                   dof_handler_velocity.max_couplings_between_dofs());
-  DoFTools::make_sparsity_pattern (dof_handler_velocity,
-                                  sparsity_pattern_velocity);
-  sparsity_pattern_velocity.compress();
-
-  vel_Laplace_plus_Mass.reinit (sparsity_pattern_velocity);
-  for (unsigned int d=0; d<dim; ++d)
-    vel_it_matrix[d].reinit (sparsity_pattern_velocity);
-  vel_Mass.reinit (sparsity_pattern_velocity);
-  vel_Laplace.reinit (sparsity_pattern_velocity);
-  vel_Advection.reinit (sparsity_pattern_velocity);
-
-  MatrixCreator::create_mass_matrix (dof_handler_velocity,
-                                    quadrature_velocity,
-                                    vel_Mass);
-  MatrixCreator::create_laplace_matrix (dof_handler_velocity,
-                                       quadrature_velocity,
-                                       vel_Laplace);
-}
+                                  // @sect4{ The <code>NavierStokesProjection::initialize_*_matrices</code> methods }
+
+                                  // In this set of methods we initialize the
+                                  // sparsity patterns, the constraints (if
+                                  // any) and assemble the matrices that do not
+                                  // depend on the timestep
+                                  // <code>dt</code>. Note that for the Laplace
+                                  // and mass matrices, we can use functions in
+                                  // the library that do this. Because the
+                                  // expensive operations of this function --
+                                  // creating the two matrices -- are entirely
+                                  // independent, we could in principle mark
+                                  // them as tasks that can be worked on in
+                                  // %parallel using the Threads::new_task
+                                  // functions. We won't do that here since
+                                  // these functions internally already are
+                                  // parallelized, and in particular because
+                                  // the current function is only called once
+                                  // per program run and so does not incur a
+                                  // cost in each time step. The necessary
+                                  // modifications would be quite
+                                  // straightforward, however.
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::initialize_velocity_matrices()
+  {
+    sparsity_pattern_velocity.reinit (dof_handler_velocity.n_dofs(),
+                                     dof_handler_velocity.n_dofs(),
+                                     dof_handler_velocity.max_couplings_between_dofs());
+    DoFTools::make_sparsity_pattern (dof_handler_velocity,
+                                    sparsity_pattern_velocity);
+    sparsity_pattern_velocity.compress();
+
+    vel_Laplace_plus_Mass.reinit (sparsity_pattern_velocity);
+    for (unsigned int d=0; d<dim; ++d)
+      vel_it_matrix[d].reinit (sparsity_pattern_velocity);
+    vel_Mass.reinit (sparsity_pattern_velocity);
+    vel_Laplace.reinit (sparsity_pattern_velocity);
+    vel_Advection.reinit (sparsity_pattern_velocity);
+
+    MatrixCreator::create_mass_matrix (dof_handler_velocity,
+                                      quadrature_velocity,
+                                      vel_Mass);
+    MatrixCreator::create_laplace_matrix (dof_handler_velocity,
+                                         quadrature_velocity,
+                                         vel_Laplace);
+  }
 
-                                // The initialization of the matrices
-                                // that act on the pressure space is similar
-         // to the ones that act on the velocity space.
-template <int dim>
-void
-NavierStokesProjection<dim>::initialize_pressure_matrices()
-{
-  sparsity_pattern_pressure.reinit (dof_handler_pressure.n_dofs(), dof_handler_pressure.n_dofs(),
-                                   dof_handler_pressure.max_couplings_between_dofs());
-  DoFTools::make_sparsity_pattern (dof_handler_pressure, sparsity_pattern_pressure);
-
-  sparsity_pattern_pressure.compress();
-
-  pres_Laplace.reinit (sparsity_pattern_pressure);
-  pres_iterative.reinit (sparsity_pattern_pressure);
-  pres_Mass.reinit (sparsity_pattern_pressure);
-
-  MatrixCreator::create_laplace_matrix (dof_handler_pressure,
-                                       quadrature_pressure,
-                                       pres_Laplace);
-  MatrixCreator::create_mass_matrix (dof_handler_pressure,
-                                    quadrature_pressure,
-                                    pres_Mass);
-}
+                                  // The initialization of the matrices
+                                  // that act on the pressure space is similar
+                                  // to the ones that act on the velocity space.
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::initialize_pressure_matrices()
+  {
+    sparsity_pattern_pressure.reinit (dof_handler_pressure.n_dofs(), dof_handler_pressure.n_dofs(),
+                                     dof_handler_pressure.max_couplings_between_dofs());
+    DoFTools::make_sparsity_pattern (dof_handler_pressure, sparsity_pattern_pressure);
+
+    sparsity_pattern_pressure.compress();
+
+    pres_Laplace.reinit (sparsity_pattern_pressure);
+    pres_iterative.reinit (sparsity_pattern_pressure);
+    pres_Mass.reinit (sparsity_pattern_pressure);
+
+    MatrixCreator::create_laplace_matrix (dof_handler_pressure,
+                                         quadrature_pressure,
+                                         pres_Laplace);
+    MatrixCreator::create_mass_matrix (dof_handler_pressure,
+                                      quadrature_pressure,
+                                      pres_Mass);
+  }
 
 
-                                // For the gradient operator, we
-                                // start by initializing the sparsity
-                                // pattern and compressing it.  It is
-                                // important to notice here that the
-                                // gradient operator acts from the
-                                // pressure space into the velocity
-                                // space, so we have to deal with two
-                                // different finite element
-                                // spaces. To keep the loops
-                                // synchronized, we use the
-                                // <code>typedef</code>'s that we
-                                // have defined before, namely
-                                // <code>PairedIterators</code> and
-                                // <code>IteratorPair</code>.
-template <int dim>
-void
-NavierStokesProjection<dim>::initialize_gradient_operator()
-{
-  sparsity_pattern_pres_vel.reinit (dof_handler_velocity.n_dofs(),
-                                   dof_handler_pressure.n_dofs(),
-                                   dof_handler_velocity.max_couplings_between_dofs());
-  DoFTools::make_sparsity_pattern (dof_handler_velocity,
-                                  dof_handler_pressure,
-                                  sparsity_pattern_pres_vel);
-  sparsity_pattern_pres_vel.compress();
-
-  InitGradPerTaskData per_task_data (0, fe_velocity.dofs_per_cell,
-                                    fe_pressure.dofs_per_cell);
-  InitGradScratchData scratch_data (fe_velocity,
-                                   fe_pressure,
-                                   quadrature_velocity,
-                                    update_gradients | update_JxW_values,
-                                   update_values);
-
-  for (unsigned int d=0; d<dim; ++d)
-    {
-      pres_Diff[d].reinit (sparsity_pattern_pres_vel);
-      per_task_data.d = d;
-      WorkStream::run (IteratorPair (IteratorTuple (dof_handler_velocity.begin_active(),
-                                                   dof_handler_pressure.begin_active()
-                                    )
-                      ),
-                      IteratorPair (IteratorTuple (dof_handler_velocity.end(),
-                                                   dof_handler_pressure.end()
-                                    )
-                      ),
-                      *this,
-                      &NavierStokesProjection<dim>::assemble_one_cell_of_gradient,
-                      &NavierStokesProjection<dim>::copy_gradient_local_to_global,
-                      scratch_data,
-                      per_task_data
-      );
-    }
-}
+                                  // For the gradient operator, we
+                                  // start by initializing the sparsity
+                                  // pattern and compressing it.  It is
+                                  // important to notice here that the
+                                  // gradient operator acts from the
+                                  // pressure space into the velocity
+                                  // space, so we have to deal with two
+                                  // different finite element
+                                  // spaces. To keep the loops
+                                  // synchronized, we use the
+                                  // <code>typedef</code>'s that we
+                                  // have defined before, namely
+                                  // <code>PairedIterators</code> and
+                                  // <code>IteratorPair</code>.
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::initialize_gradient_operator()
+  {
+    sparsity_pattern_pres_vel.reinit (dof_handler_velocity.n_dofs(),
+                                     dof_handler_pressure.n_dofs(),
+                                     dof_handler_velocity.max_couplings_between_dofs());
+    DoFTools::make_sparsity_pattern (dof_handler_velocity,
+                                    dof_handler_pressure,
+                                    sparsity_pattern_pres_vel);
+    sparsity_pattern_pres_vel.compress();
+
+    InitGradPerTaskData per_task_data (0, fe_velocity.dofs_per_cell,
+                                      fe_pressure.dofs_per_cell);
+    InitGradScratchData scratch_data (fe_velocity,
+                                     fe_pressure,
+                                     quadrature_velocity,
+                                     update_gradients | update_JxW_values,
+                                     update_values);
+
+    for (unsigned int d=0; d<dim; ++d)
+      {
+       pres_Diff[d].reinit (sparsity_pattern_pres_vel);
+       per_task_data.d = d;
+       WorkStream::run (IteratorPair (IteratorTuple (dof_handler_velocity.begin_active(),
+                                                     dof_handler_pressure.begin_active()
+                                      )
+                        ),
+                        IteratorPair (IteratorTuple (dof_handler_velocity.end(),
+                                                     dof_handler_pressure.end()
+                                      )
+                        ),
+                        *this,
+                        &NavierStokesProjection<dim>::assemble_one_cell_of_gradient,
+                        &NavierStokesProjection<dim>::copy_gradient_local_to_global,
+                        scratch_data,
+                        per_task_data
+       );
+      }
+  }
 
-template <int dim>
-void
-NavierStokesProjection<dim>::
-assemble_one_cell_of_gradient (const IteratorPair  &SI,
-                              InitGradScratchData &scratch,
-                              InitGradPerTaskData &data)
-{
-  scratch.fe_val_vel.reinit (std_cxx1x::get<0> (SI.iterators));
-  scratch.fe_val_pres.reinit (std_cxx1x::get<1> (SI.iterators));
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::
+  assemble_one_cell_of_gradient (const IteratorPair  &SI,
+                                InitGradScratchData &scratch,
+                                InitGradPerTaskData &data)
+  {
+    scratch.fe_val_vel.reinit (std_cxx1x::get<0> (SI.iterators));
+    scratch.fe_val_pres.reinit (std_cxx1x::get<1> (SI.iterators));
 
-  std_cxx1x::get<0> (SI.iterators)->get_dof_indices (data.vel_local_dof_indices);
-  std_cxx1x::get<1> (SI.iterators)->get_dof_indices (data.pres_local_dof_indices);
+    std_cxx1x::get<0> (SI.iterators)->get_dof_indices (data.vel_local_dof_indices);
+    std_cxx1x::get<1> (SI.iterators)->get_dof_indices (data.pres_local_dof_indices);
 
-  data.local_grad = 0.;
-  for (unsigned int q=0; q<scratch.nqp; ++q)
-    {
-      for (unsigned int i=0; i<data.vel_dpc; ++i)
-       for (unsigned int j=0; j<data.pres_dpc; ++j)
-         data.local_grad (i, j) += -scratch.fe_val_vel.JxW(q) *
-                                   scratch.fe_val_vel.shape_grad (i, q)[data.d] *
-                                   scratch.fe_val_pres.shape_value (j, q);
-    }
-}
+    data.local_grad = 0.;
+    for (unsigned int q=0; q<scratch.nqp; ++q)
+      {
+       for (unsigned int i=0; i<data.vel_dpc; ++i)
+         for (unsigned int j=0; j<data.pres_dpc; ++j)
+           data.local_grad (i, j) += -scratch.fe_val_vel.JxW(q) *
+                                     scratch.fe_val_vel.shape_grad (i, q)[data.d] *
+                                     scratch.fe_val_pres.shape_value (j, q);
+      }
+  }
 
 
-template <int dim>
-void
-NavierStokesProjection<dim>::
-copy_gradient_local_to_global(const InitGradPerTaskData &data)
-{
-  for (unsigned int i=0; i<data.vel_dpc; ++i)
-    for (unsigned int j=0; j<data.pres_dpc; ++j)
-      pres_Diff[data.d].add (data.vel_local_dof_indices[i], data.pres_local_dof_indices[j],
-                             data.local_grad (i, j) );
-}
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::
+  copy_gradient_local_to_global(const InitGradPerTaskData &data)
+  {
+    for (unsigned int i=0; i<data.vel_dpc; ++i)
+      for (unsigned int j=0; j<data.pres_dpc; ++j)
+       pres_Diff[data.d].add (data.vel_local_dof_indices[i], data.pres_local_dof_indices[j],
+                              data.local_grad (i, j) );
+  }
 
 
-                                // @sect4{ <code>NavierStokesProjection::run</code> }
-
-                                // This is the time marching
-                                // function, which starting at
-                                // <code>t_0</code> advances in time
-                                // using the projection method with
-                                // time step <code>dt</code> until
-                                // <code>T</code>.
-                                //
-                                // Its second parameter, <code>verbose</code>
-                                // indicates whether the function should
-                                // output information what it is doing at any
-                                // given moment: for example, it will say
-                                // whether we are working on the diffusion,
-                                // projection substep; updating
-                                // preconditioners etc. Rather than
-                                // implementing this output using code like
-                                // @code
-                                //   if (verbose)
-                                //     std::cout << "something";
-                                // @endcode
-                                // we use the ConditionalOStream class to
-                                // do that for us. That class takes an
-                                // output stream and a condition that
-                                // indicates whether the things you pass
-                                // to it should be passed through to the
-                                // given output stream, or should just
-                                // be ignored. This way, above code
-                                // simply becomes
-                                // @code
-                                //   verbose_cout << "something";
-                                // @endcode
-                                // and does the right thing in either
-                                // case.
-template <int dim>
-void
-NavierStokesProjection<dim>::run (const bool verbose,
-                                 const unsigned int output_interval)
-{
-  ConditionalOStream verbose_cout (std::cout, verbose);
+                                  // @sect4{ <code>NavierStokesProjection::run</code> }
+
+                                  // This is the time marching
+                                  // function, which starting at
+                                  // <code>t_0</code> advances in time
+                                  // using the projection method with
+                                  // time step <code>dt</code> until
+                                  // <code>T</code>.
+                                  //
+                                  // Its second parameter, <code>verbose</code>
+                                  // indicates whether the function should
+                                  // output information what it is doing at any
+                                  // given moment: for example, it will say
+                                  // whether we are working on the diffusion,
+                                  // projection substep; updating
+                                  // preconditioners etc. Rather than
+                                  // implementing this output using code like
+                                  // @code
+                                  //   if (verbose)
+                                  //     std::cout << "something";
+                                  // @endcode
+                                  // we use the ConditionalOStream class to
+                                  // do that for us. That class takes an
+                                  // output stream and a condition that
+                                  // indicates whether the things you pass
+                                  // to it should be passed through to the
+                                  // given output stream, or should just
+                                  // be ignored. This way, above code
+                                  // simply becomes
+                                  // @code
+                                  //   verbose_cout << "something";
+                                  // @endcode
+                                  // and does the right thing in either
+                                  // case.
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::run (const bool verbose,
+                                   const unsigned int output_interval)
+  {
+    ConditionalOStream verbose_cout (std::cout, verbose);
 
-  const unsigned int n_steps =  static_cast<unsigned int>((T - t_0)/dt);
-  vel_exact.set_time (2.*dt);
-  output_results(1);
-  for (unsigned int n = 2; n<=n_steps; ++n)
-    {
-      if (n % output_interval == 0)
-       {
-         verbose_cout << "Plotting Solution" << std::endl;
-         output_results(n);
-       }
-      std::cout << "Step = " << n << " Time = " << (n*dt) << std::endl;
-      verbose_cout << "  Interpolating the velocity " << std::endl;
-
-      interpolate_velocity();
-      verbose_cout << "  Diffusion Step" << std::endl;
-      if (n % vel_update_prec == 0)
-       verbose_cout << "    With reinitialization of the preconditioner"
-                    << std::endl;
-      diffusion_step ((n%vel_update_prec == 0) || (n == 2));
-      verbose_cout << "  Projection Step" << std::endl;
-      projection_step ( (n == 2));
-      verbose_cout << "  Updating the Pressure" << std::endl;
-      update_pressure ( (n == 2));
-      vel_exact.advance_time(dt);
-    }
-  output_results (n_steps);
-}
+    const unsigned int n_steps =  static_cast<unsigned int>((T - t_0)/dt);
+    vel_exact.set_time (2.*dt);
+    output_results(1);
+    for (unsigned int n = 2; n<=n_steps; ++n)
+      {
+       if (n % output_interval == 0)
+         {
+           verbose_cout << "Plotting Solution" << std::endl;
+           output_results(n);
+         }
+       std::cout << "Step = " << n << " Time = " << (n*dt) << std::endl;
+       verbose_cout << "  Interpolating the velocity " << std::endl;
+
+       interpolate_velocity();
+       verbose_cout << "  Diffusion Step" << std::endl;
+       if (n % vel_update_prec == 0)
+         verbose_cout << "    With reinitialization of the preconditioner"
+                      << std::endl;
+       diffusion_step ((n%vel_update_prec == 0) || (n == 2));
+       verbose_cout << "  Projection Step" << std::endl;
+       projection_step ( (n == 2));
+       verbose_cout << "  Updating the Pressure" << std::endl;
+       update_pressure ( (n == 2));
+       vel_exact.advance_time(dt);
+      }
+    output_results (n_steps);
+  }
 
 
 
-template <int dim>
-void
-NavierStokesProjection<dim>::interpolate_velocity()
-{
-  for (unsigned int d=0; d<dim; ++d)
-    u_star[d].equ (2., u_n[d], -1, u_n_minus_1[d]);
-}
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::interpolate_velocity()
+  {
+    for (unsigned int d=0; d<dim; ++d)
+      u_star[d].equ (2., u_n[d], -1, u_n_minus_1[d]);
+  }
 
 
-                                // @sect4{<code>NavierStokesProjection::diffusion_step</code>}
-
-                                // The implementation of a diffusion
-                                // step. Note that the expensive operation is
-                                // the diffusion solve at the end of the
-                                // function, which we have to do once for
-                                // each velocity component. To accellerate
-                                // things a bit, we allow to do this in
-                                // %parallel, using the Threads::new_task
-                                // function which makes sure that the
-                                // <code>dim</code> solves are all taken care
-                                // of and are scheduled to available
-                                // processors: if your machine has more than
-                                // one processor core and no other parts of
-                                // this program are using resources
-                                // currently, then the diffusion solves will
-                                // run in %parallel. On the other hand, if
-                                // your system has only one processor core
-                                // then running things in %parallel would be
-                                // inefficient (since it leads, for example,
-                                // to cache congestion) and things will be
-                                // executed sequentially.
-template <int dim>
-void
-NavierStokesProjection<dim>::diffusion_step (const bool reinit_prec)
-{
-  pres_tmp.equ (-1., pres_n, -4./3., phi_n, 1./3., phi_n_minus_1);
+                                  // @sect4{<code>NavierStokesProjection::diffusion_step</code>}
+
+                                  // The implementation of a diffusion
+                                  // step. Note that the expensive operation is
+                                  // the diffusion solve at the end of the
+                                  // function, which we have to do once for
+                                  // each velocity component. To accellerate
+                                  // things a bit, we allow to do this in
+                                  // %parallel, using the Threads::new_task
+                                  // function which makes sure that the
+                                  // <code>dim</code> solves are all taken care
+                                  // of and are scheduled to available
+                                  // processors: if your machine has more than
+                                  // one processor core and no other parts of
+                                  // this program are using resources
+                                  // currently, then the diffusion solves will
+                                  // run in %parallel. On the other hand, if
+                                  // your system has only one processor core
+                                  // then running things in %parallel would be
+                                  // inefficient (since it leads, for example,
+                                  // to cache congestion) and things will be
+                                  // executed sequentially.
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::diffusion_step (const bool reinit_prec)
+  {
+    pres_tmp.equ (-1., pres_n, -4./3., phi_n, 1./3., phi_n_minus_1);
 
-  assemble_advection_term();
+    assemble_advection_term();
 
-  for (unsigned int d=0; d<dim; ++d)
-    {
-      force[d] = 0.;
-      v_tmp.equ (2./dt,u_n[d],-.5/dt,u_n_minus_1[d]);
-      vel_Mass.vmult_add (force[d], v_tmp);
-
-      pres_Diff[d].vmult_add (force[d], pres_tmp);
-      u_n_minus_1[d] = u_n[d];
-
-      vel_it_matrix[d].copy_from (vel_Laplace_plus_Mass);
-      vel_it_matrix[d].add (1., vel_Advection);
-
-      vel_exact.set_component(d);
-      boundary_values.clear();
-      for (std::vector<unsigned char>::const_iterator
-            boundaries = boundary_indicators.begin();
-          boundaries != boundary_indicators.end();
-          ++boundaries)
-       {
-         switch (*boundaries)
-           {
-             case 1:
-                   VectorTools::
-                     interpolate_boundary_values (dof_handler_velocity,
-                                                  *boundaries,
-                                                  ZeroFunction<dim>(),
-                                                  boundary_values);
-                   break;
-             case 2:
-                   VectorTools::
-                     interpolate_boundary_values (dof_handler_velocity,
-                                                  *boundaries,
-                                                  vel_exact,
-                                                  boundary_values);
-                   break;
-             case 3:
-                   if (d != 0)
+    for (unsigned int d=0; d<dim; ++d)
+      {
+       force[d] = 0.;
+       v_tmp.equ (2./dt,u_n[d],-.5/dt,u_n_minus_1[d]);
+       vel_Mass.vmult_add (force[d], v_tmp);
+
+       pres_Diff[d].vmult_add (force[d], pres_tmp);
+       u_n_minus_1[d] = u_n[d];
+
+       vel_it_matrix[d].copy_from (vel_Laplace_plus_Mass);
+       vel_it_matrix[d].add (1., vel_Advection);
+
+       vel_exact.set_component(d);
+       boundary_values.clear();
+       for (std::vector<unsigned char>::const_iterator
+              boundaries = boundary_indicators.begin();
+            boundaries != boundary_indicators.end();
+            ++boundaries)
+         {
+           switch (*boundaries)
+             {
+               case 1:
                      VectorTools::
                        interpolate_boundary_values (dof_handler_velocity,
                                                     *boundaries,
                                                     ZeroFunction<dim>(),
                                                     boundary_values);
-                   break;
-             case 4:
-                   VectorTools::
-                     interpolate_boundary_values (dof_handler_velocity,
-                                                  *boundaries,
-                                                  ZeroFunction<dim>(),
-                                                  boundary_values);
-                   break;
-             default:
-                   Assert (false, ExcNotImplemented());
-           }
-       }
-      MatrixTools::apply_boundary_values (boundary_values,
-                                         vel_it_matrix[d],
-                                         u_n[d],
-                                         force[d]);
-    }
+                     break;
+               case 2:
+                     VectorTools::
+                       interpolate_boundary_values (dof_handler_velocity,
+                                                    *boundaries,
+                                                    vel_exact,
+                                                    boundary_values);
+                     break;
+               case 3:
+                     if (d != 0)
+                       VectorTools::
+                         interpolate_boundary_values (dof_handler_velocity,
+                                                      *boundaries,
+                                                      ZeroFunction<dim>(),
+                                                      boundary_values);
+                     break;
+               case 4:
+                     VectorTools::
+                       interpolate_boundary_values (dof_handler_velocity,
+                                                    *boundaries,
+                                                    ZeroFunction<dim>(),
+                                                    boundary_values);
+                     break;
+               default:
+                     Assert (false, ExcNotImplemented());
+             }
+         }
+       MatrixTools::apply_boundary_values (boundary_values,
+                                           vel_it_matrix[d],
+                                           u_n[d],
+                                           force[d]);
+      }
 
 
-  Threads::TaskGroup<void> tasks;
-  for(unsigned int d=0; d<dim; ++d)
-    {
-      if (reinit_prec)
-       prec_velocity[d].initialize (vel_it_matrix[d],
-                                    SparseILU<double>::
-                                    AdditionalData (vel_diag_strength,
-                                                    vel_off_diagonals));
-      tasks += Threads::new_task (&NavierStokesProjection<dim>::
-                                 diffusion_component_solve,
-                                 *this, d);
-    }
-  tasks.join_all();
-}
+    Threads::TaskGroup<void> tasks;
+    for(unsigned int d=0; d<dim; ++d)
+      {
+       if (reinit_prec)
+         prec_velocity[d].initialize (vel_it_matrix[d],
+                                      SparseILU<double>::
+                                      AdditionalData (vel_diag_strength,
+                                                      vel_off_diagonals));
+       tasks += Threads::new_task (&NavierStokesProjection<dim>::
+                                   diffusion_component_solve,
+                                   *this, d);
+      }
+    tasks.join_all();
+  }
 
 
 
-template <int dim>
-void
-NavierStokesProjection<dim>::diffusion_component_solve (const unsigned int d)
-{
-  SolverControl solver_control (vel_max_its, vel_eps*force[d].l2_norm());
-  SolverGMRES<> gmres (solver_control,
-                      SolverGMRES<>::AdditionalData (vel_Krylov_size));
-  gmres.solve (vel_it_matrix[d], u_n[d], force[d], prec_velocity[d]);
-}
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::diffusion_component_solve (const unsigned int d)
+  {
+    SolverControl solver_control (vel_max_its, vel_eps*force[d].l2_norm());
+    SolverGMRES<> gmres (solver_control,
+                        SolverGMRES<>::AdditionalData (vel_Krylov_size));
+    gmres.solve (vel_it_matrix[d], u_n[d], force[d], prec_velocity[d]);
+  }
 
 
-                                // @sect4{ The <code>NavierStokesProjection::assemble_advection_term</code> method and related}
+                                  // @sect4{ The <code>NavierStokesProjection::assemble_advection_term</code> method and related}
 
-                                // The following few functions deal with
-                                // assembling the advection terms, which is the part of the
-         // system matrix for the diffusion step that changes
-         // at every time step. As mentioned above, we
-                                // will run the assembly loop over all cells
-                                // in %parallel, using the WorkStream class
-                                // and other facilities as described in the
-                                // documentation module on @ref threads.
-template <int dim>
-void
-NavierStokesProjection<dim>::assemble_advection_term()
-{
-  vel_Advection = 0.;
-  AdvectionPerTaskData data (fe_velocity.dofs_per_cell);
-  AdvectionScratchData scratch (fe_velocity, quadrature_velocity,
-                                update_values |
-                               update_JxW_values |
-                               update_gradients);
-  WorkStream::run (dof_handler_velocity.begin_active(),
-                  dof_handler_velocity.end(), *this,
-                   &NavierStokesProjection<dim>::assemble_one_cell_of_advection,
-                   &NavierStokesProjection<dim>::copy_advection_local_to_global,
-                  scratch,
-                  data);
-}
+                                  // The following few functions deal with
+                                  // assembling the advection terms, which is the part of the
+                                  // system matrix for the diffusion step that changes
+                                  // at every time step. As mentioned above, we
+                                  // will run the assembly loop over all cells
+                                  // in %parallel, using the WorkStream class
+                                  // and other facilities as described in the
+                                  // documentation module on @ref threads.
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::assemble_advection_term()
+  {
+    vel_Advection = 0.;
+    AdvectionPerTaskData data (fe_velocity.dofs_per_cell);
+    AdvectionScratchData scratch (fe_velocity, quadrature_velocity,
+                                 update_values |
+                                 update_JxW_values |
+                                 update_gradients);
+    WorkStream::run (dof_handler_velocity.begin_active(),
+                    dof_handler_velocity.end(), *this,
+                    &NavierStokesProjection<dim>::assemble_one_cell_of_advection,
+                    &NavierStokesProjection<dim>::copy_advection_local_to_global,
+                    scratch,
+                    data);
+  }
 
 
 
-template <int dim>
-void
-NavierStokesProjection<dim>::
-assemble_one_cell_of_advection(const typename DoFHandler<dim>::active_cell_iterator &cell,
-                              AdvectionScratchData &scratch,
-                              AdvectionPerTaskData &data)
-{
-  scratch.fe_val.reinit(cell);
-  cell->get_dof_indices (data.local_dof_indices);
-  for (unsigned int d=0; d<dim; ++d)
-    {
-      scratch.fe_val.get_function_values (u_star[d], scratch.u_star_tmp);
-      for (unsigned int q=0; q<scratch.nqp; ++q)
-       scratch.u_star_local[q](d) = scratch.u_star_tmp[q];
-    }
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::
+  assemble_one_cell_of_advection(const typename DoFHandler<dim>::active_cell_iterator &cell,
+                                AdvectionScratchData &scratch,
+                                AdvectionPerTaskData &data)
+  {
+    scratch.fe_val.reinit(cell);
+    cell->get_dof_indices (data.local_dof_indices);
+    for (unsigned int d=0; d<dim; ++d)
+      {
+       scratch.fe_val.get_function_values (u_star[d], scratch.u_star_tmp);
+       for (unsigned int q=0; q<scratch.nqp; ++q)
+         scratch.u_star_local[q](d) = scratch.u_star_tmp[q];
+      }
 
-  for (unsigned int d=0; d<dim; ++d)
-    {
-      scratch.fe_val.get_function_gradients (u_star[d], scratch.grad_u_star);
-      for (unsigned int q=0; q<scratch.nqp; ++q)
-       {
-         if (d==0)
-           scratch.u_star_tmp[q] = 0.;
-         scratch.u_star_tmp[q] += scratch.grad_u_star[q][d];
-       }
-    }
+    for (unsigned int d=0; d<dim; ++d)
+      {
+       scratch.fe_val.get_function_gradients (u_star[d], scratch.grad_u_star);
+       for (unsigned int q=0; q<scratch.nqp; ++q)
+         {
+           if (d==0)
+             scratch.u_star_tmp[q] = 0.;
+           scratch.u_star_tmp[q] += scratch.grad_u_star[q][d];
+         }
+      }
 
-  data.local_advection = 0.;
-  for (unsigned int q=0; q<scratch.nqp; ++q)
-    for (unsigned int i=0; i<scratch.dpc; ++i)
-      for (unsigned int j=0; j<scratch.dpc; ++j)
-        data.local_advection(i,j) += (scratch.u_star_local[q] *
-                                     scratch.fe_val.shape_grad (j, q) *
-                                     scratch.fe_val.shape_value (i, q)
-                                     +
-                                     0.5 *
-                                     scratch.u_star_tmp[q] *
-                                     scratch.fe_val.shape_value (i, q) *
-                                     scratch.fe_val.shape_value (j, q))
-                                    *
-                                    scratch.fe_val.JxW(q) ;
-}
+    data.local_advection = 0.;
+    for (unsigned int q=0; q<scratch.nqp; ++q)
+      for (unsigned int i=0; i<scratch.dpc; ++i)
+       for (unsigned int j=0; j<scratch.dpc; ++j)
+         data.local_advection(i,j) += (scratch.u_star_local[q] *
+                                       scratch.fe_val.shape_grad (j, q) *
+                                       scratch.fe_val.shape_value (i, q)
+                                       +
+                                       0.5 *
+                                       scratch.u_star_tmp[q] *
+                                       scratch.fe_val.shape_value (i, q) *
+                                       scratch.fe_val.shape_value (j, q))
+                                      *
+                                      scratch.fe_val.JxW(q) ;
+  }
 
 
 
-template <int dim>
-void
-NavierStokesProjection<dim>::
-copy_advection_local_to_global(const AdvectionPerTaskData &data)
-{
-  for (unsigned int i=0; i<fe_velocity.dofs_per_cell; ++i)
-    for (unsigned int j=0; j<fe_velocity.dofs_per_cell; ++j)
-      vel_Advection.add (data.local_dof_indices[i],
-                        data.local_dof_indices[j],
-                        data.local_advection(i,j));
-}
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::
+  copy_advection_local_to_global(const AdvectionPerTaskData &data)
+  {
+    for (unsigned int i=0; i<fe_velocity.dofs_per_cell; ++i)
+      for (unsigned int j=0; j<fe_velocity.dofs_per_cell; ++j)
+       vel_Advection.add (data.local_dof_indices[i],
+                          data.local_dof_indices[j],
+                          data.local_advection(i,j));
+  }
 
 
 
-                                // @sect4{<code>NavierStokesProjection::projection_step</code>}
+                                  // @sect4{<code>NavierStokesProjection::projection_step</code>}
 
-                                // This implements the projection step:
-template <int dim>
-void
-NavierStokesProjection<dim>::projection_step (const bool reinit_prec)
-{
-  pres_iterative.copy_from (pres_Laplace);
+                                  // This implements the projection step:
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::projection_step (const bool reinit_prec)
+  {
+    pres_iterative.copy_from (pres_Laplace);
 
-  pres_tmp = 0.;
-  for (unsigned d=0; d<dim; ++d)
-    pres_Diff[d].Tvmult_add (pres_tmp, u_n[d]);
+    pres_tmp = 0.;
+    for (unsigned d=0; d<dim; ++d)
+      pres_Diff[d].Tvmult_add (pres_tmp, u_n[d]);
 
-  phi_n_minus_1 = phi_n;
+    phi_n_minus_1 = phi_n;
 
-  static std::map<unsigned int, double> bval;
-  if (reinit_prec)
-    VectorTools::interpolate_boundary_values (dof_handler_pressure, 3,
-                                             ZeroFunction<dim>(), bval);
+    static std::map<unsigned int, double> bval;
+    if (reinit_prec)
+      VectorTools::interpolate_boundary_values (dof_handler_pressure, 3,
+                                               ZeroFunction<dim>(), bval);
 
-  MatrixTools::apply_boundary_values (bval, pres_iterative, phi_n, pres_tmp);
+    MatrixTools::apply_boundary_values (bval, pres_iterative, phi_n, pres_tmp);
 
-  if (reinit_prec)
-    prec_pres_Laplace.initialize(pres_iterative,
-        SparseILU<double>::AdditionalData (vel_diag_strength,
-                                          vel_off_diagonals) );
+    if (reinit_prec)
+      prec_pres_Laplace.initialize(pres_iterative,
+                                  SparseILU<double>::AdditionalData (vel_diag_strength,
+                                                                     vel_off_diagonals) );
 
-  SolverControl solvercontrol (vel_max_its, vel_eps*pres_tmp.l2_norm());
-  SolverCG<> cg (solvercontrol);
-  cg.solve (pres_iterative, phi_n, pres_tmp, prec_pres_Laplace);
+    SolverControl solvercontrol (vel_max_its, vel_eps*pres_tmp.l2_norm());
+    SolverCG<> cg (solvercontrol);
+    cg.solve (pres_iterative, phi_n, pres_tmp, prec_pres_Laplace);
 
-  phi_n *= 1.5/dt;
-}
+    phi_n *= 1.5/dt;
+  }
 
 
-                                // @sect4{ <code>NavierStokesProjection::update_pressure</code> }
-
-                                // This is the pressure update step
-                                // of the projection method. It
-                                // implements the standard
-                                // formulation of the method, that is
-                                // @f[
-                                //      p^{n+1} = p^n + \phi^{n+1},
-                                // @f]
-                                // or the rotational form, which is
-                                // @f[
-                                //      p^{n+1} = p^n + \phi^{n+1} - \frac{1}{Re} \nabla\cdot u^{n+1}.
-                                // @f]
-template <int dim>
-void
-NavierStokesProjection<dim>::update_pressure (const bool reinit_prec)
-{
-  pres_n_minus_1 = pres_n;
-  switch (type)
-    {
-      case RunTimeParameters::METHOD_STANDARD:
-           pres_n += phi_n;
-           break;
-      case RunTimeParameters::METHOD_ROTATIONAL:
-           if (reinit_prec)
-             prec_mass.initialize (pres_Mass);
-           pres_n = pres_tmp;
-           prec_mass.solve (pres_n);
-           pres_n.sadd(1./Re, 1., pres_n_minus_1, 1., phi_n);
-           break;
-      default:
-           Assert (false, ExcNotImplemented());
-    };
-}
+                                  // @sect4{ <code>NavierStokesProjection::update_pressure</code> }
 
+                                  // This is the pressure update step
+                                  // of the projection method. It
+                                  // implements the standard
+                                  // formulation of the method, that is
+                                  // @f[
+                                  //      p^{n+1} = p^n + \phi^{n+1},
+                                  // @f]
+                                  // or the rotational form, which is
+                                  // @f[
+                                  //      p^{n+1} = p^n + \phi^{n+1} - \frac{1}{Re} \nabla\cdot u^{n+1}.
+                                  // @f]
+  template <int dim>
+  void
+  NavierStokesProjection<dim>::update_pressure (const bool reinit_prec)
+  {
+    pres_n_minus_1 = pres_n;
+    switch (type)
+      {
+       case RunTimeParameters::METHOD_STANDARD:
+             pres_n += phi_n;
+             break;
+       case RunTimeParameters::METHOD_ROTATIONAL:
+             if (reinit_prec)
+               prec_mass.initialize (pres_Mass);
+             pres_n = pres_tmp;
+             prec_mass.solve (pres_n);
+             pres_n.sadd(1./Re, 1., pres_n_minus_1, 1., phi_n);
+             break;
+       default:
+             Assert (false, ExcNotImplemented());
+      };
+  }
 
-                                // @sect4{ <code>NavierStokesProjection::output_results</code> }
-
-                                // This method plots the current
-                                // solution. The main difficulty is that we
-                                // want to create a single output file that
-                                // contains the data for all velocity
-                                // components, the pressure, and also the
-                                // vorticity of the flow. On the other hand,
-                                // velocities and the pressure live on
-                                // separate DoFHandler objects, and so can't
-                                // be written to the same file using a single
-                                // DataOut object. As a consequence, we have
-                                // to work a bit harder to get the various
-                                // pieces of data into a single DoFHandler
-                                // object, and then use that to drive
-                                // graphical output.
-                                //
-                                // We will not elaborate on this process
-                                // here, but rather refer to step-31 and
-                                // step-32, where a similar procedure is used
-                                // (and is documented) to create a joint
-                                // DoFHandler object for all variables.
-                                //
-                                // Let us also note that we here compute the
-                                // vorticity as a scalar quantity in a
-                                // separate function, using the $L^2$
-                                // projection of the quantity $\text{curl} u$
-                                // onto the finite element space used for the
-                                // components of the velocity. In principle,
-                                // however, we could also have computed as a
-                                // pointwise quantity from the velocity, and
-                                // do so through the DataPostprocessor
-                                // mechanism discussed in step-29 and
-                                // step-33.
-template <int dim>
-void NavierStokesProjection<dim>::output_results (const unsigned int step)
-{
-  assemble_vorticity ( (step == 1));
-  const FESystem<dim> joint_fe (fe_velocity, dim,
-                               fe_pressure, 1,
-                               fe_velocity, 1);
-  DoFHandler<dim> joint_dof_handler (triangulation);
-  joint_dof_handler.distribute_dofs (joint_fe);
-  Assert (joint_dof_handler.n_dofs() ==
-         ((dim + 1)*dof_handler_velocity.n_dofs() +
-          dof_handler_pressure.n_dofs()),
-          ExcInternalError());
-  static Vector<double> joint_solution (joint_dof_handler.n_dofs());
-  std::vector<unsigned int> loc_joint_dof_indices (joint_fe.dofs_per_cell),
-    loc_vel_dof_indices (fe_velocity.dofs_per_cell),
-    loc_pres_dof_indices (fe_pressure.dofs_per_cell);
-  typename DoFHandler<dim>::active_cell_iterator
-    joint_cell = joint_dof_handler.begin_active(),
-    joint_endc = joint_dof_handler.end(),
-    vel_cell   = dof_handler_velocity.begin_active(),
-    pres_cell  = dof_handler_pressure.begin_active();
-  for (; joint_cell != joint_endc; ++joint_cell, ++vel_cell, ++pres_cell)
-    {
-      joint_cell->get_dof_indices (loc_joint_dof_indices);
-      vel_cell->get_dof_indices (loc_vel_dof_indices),
-       pres_cell->get_dof_indices (loc_pres_dof_indices);
-      for (unsigned int i=0; i<joint_fe.dofs_per_cell; ++i)
-       switch (joint_fe.system_to_base_index(i).first.first)
-         {
-           case 0:
-                 Assert (joint_fe.system_to_base_index(i).first.second < dim,
-                         ExcInternalError());
-                 joint_solution (loc_joint_dof_indices[i]) =
-                   u_n[ joint_fe.system_to_base_index(i).first.second ]
-                   (loc_vel_dof_indices[ joint_fe.system_to_base_index(i).second ]);
-                 break;
-           case 1:
-                 Assert (joint_fe.system_to_base_index(i).first.second == 0,
-                         ExcInternalError());
-                 joint_solution (loc_joint_dof_indices[i]) =
-                   pres_n (loc_pres_dof_indices[ joint_fe.system_to_base_index(i).second ]);
-                 break;
-           case 2:
-                 Assert (joint_fe.system_to_base_index(i).first.second == 0,
-                         ExcInternalError());
-                 joint_solution (loc_joint_dof_indices[i]) =
-                   rot_u (loc_vel_dof_indices[ joint_fe.system_to_base_index(i).second ]);
-                 break;
-           default:
-                 Assert (false, ExcInternalError());
-         }
-    }
-  std::vector<std::string> joint_solution_names (dim, "v");
-  joint_solution_names.push_back ("p");
-  joint_solution_names.push_back ("rot_u");
-  DataOut<dim> data_out;
-  data_out.attach_dof_handler (joint_dof_handler);
-  std::vector< DataComponentInterpretation::DataComponentInterpretation >
-    component_interpretation (dim+2,
-                             DataComponentInterpretation::component_is_part_of_vector);
-  component_interpretation[dim]
-    = DataComponentInterpretation::component_is_scalar;
-  component_interpretation[dim+1]
-    = DataComponentInterpretation::component_is_scalar;
-  data_out.add_data_vector (joint_solution,
-                           joint_solution_names,
-                           DataOut<dim>::type_dof_data,
-                            component_interpretation);
-  data_out.build_patches (deg + 1);
-  std::ofstream output (("solution-" +
-                        Utilities::int_to_string (step, 5) +
-                        ".vtk").c_str());
-  data_out.write_vtk (output);
-}
 
+                                  // @sect4{ <code>NavierStokesProjection::output_results</code> }
+
+                                  // This method plots the current
+                                  // solution. The main difficulty is that we
+                                  // want to create a single output file that
+                                  // contains the data for all velocity
+                                  // components, the pressure, and also the
+                                  // vorticity of the flow. On the other hand,
+                                  // velocities and the pressure live on
+                                  // separate DoFHandler objects, and so can't
+                                  // be written to the same file using a single
+                                  // DataOut object. As a consequence, we have
+                                  // to work a bit harder to get the various
+                                  // pieces of data into a single DoFHandler
+                                  // object, and then use that to drive
+                                  // graphical output.
+                                  //
+                                  // We will not elaborate on this process
+                                  // here, but rather refer to step-31 and
+                                  // step-32, where a similar procedure is used
+                                  // (and is documented) to create a joint
+                                  // DoFHandler object for all variables.
+                                  //
+                                  // Let us also note that we here compute the
+                                  // vorticity as a scalar quantity in a
+                                  // separate function, using the $L^2$
+                                  // projection of the quantity $\text{curl} u$
+                                  // onto the finite element space used for the
+                                  // components of the velocity. In principle,
+                                  // however, we could also have computed as a
+                                  // pointwise quantity from the velocity, and
+                                  // do so through the DataPostprocessor
+                                  // mechanism discussed in step-29 and
+                                  // step-33.
+  template <int dim>
+  void NavierStokesProjection<dim>::output_results (const unsigned int step)
+  {
+    assemble_vorticity ( (step == 1));
+    const FESystem<dim> joint_fe (fe_velocity, dim,
+                                 fe_pressure, 1,
+                                 fe_velocity, 1);
+    DoFHandler<dim> joint_dof_handler (triangulation);
+    joint_dof_handler.distribute_dofs (joint_fe);
+    Assert (joint_dof_handler.n_dofs() ==
+           ((dim + 1)*dof_handler_velocity.n_dofs() +
+            dof_handler_pressure.n_dofs()),
+           ExcInternalError());
+    static Vector<double> joint_solution (joint_dof_handler.n_dofs());
+    std::vector<unsigned int> loc_joint_dof_indices (joint_fe.dofs_per_cell),
+      loc_vel_dof_indices (fe_velocity.dofs_per_cell),
+      loc_pres_dof_indices (fe_pressure.dofs_per_cell);
+    typename DoFHandler<dim>::active_cell_iterator
+      joint_cell = joint_dof_handler.begin_active(),
+      joint_endc = joint_dof_handler.end(),
+      vel_cell   = dof_handler_velocity.begin_active(),
+      pres_cell  = dof_handler_pressure.begin_active();
+    for (; joint_cell != joint_endc; ++joint_cell, ++vel_cell, ++pres_cell)
+      {
+       joint_cell->get_dof_indices (loc_joint_dof_indices);
+       vel_cell->get_dof_indices (loc_vel_dof_indices),
+         pres_cell->get_dof_indices (loc_pres_dof_indices);
+       for (unsigned int i=0; i<joint_fe.dofs_per_cell; ++i)
+         switch (joint_fe.system_to_base_index(i).first.first)
+           {
+             case 0:
+                   Assert (joint_fe.system_to_base_index(i).first.second < dim,
+                           ExcInternalError());
+                   joint_solution (loc_joint_dof_indices[i]) =
+                     u_n[ joint_fe.system_to_base_index(i).first.second ]
+                     (loc_vel_dof_indices[ joint_fe.system_to_base_index(i).second ]);
+                   break;
+             case 1:
+                   Assert (joint_fe.system_to_base_index(i).first.second == 0,
+                           ExcInternalError());
+                   joint_solution (loc_joint_dof_indices[i]) =
+                     pres_n (loc_pres_dof_indices[ joint_fe.system_to_base_index(i).second ]);
+                   break;
+             case 2:
+                   Assert (joint_fe.system_to_base_index(i).first.second == 0,
+                           ExcInternalError());
+                   joint_solution (loc_joint_dof_indices[i]) =
+                     rot_u (loc_vel_dof_indices[ joint_fe.system_to_base_index(i).second ]);
+                   break;
+             default:
+                   Assert (false, ExcInternalError());
+           }
+      }
+    std::vector<std::string> joint_solution_names (dim, "v");
+    joint_solution_names.push_back ("p");
+    joint_solution_names.push_back ("rot_u");
+    DataOut<dim> data_out;
+    data_out.attach_dof_handler (joint_dof_handler);
+    std::vector< DataComponentInterpretation::DataComponentInterpretation >
+      component_interpretation (dim+2,
+                               DataComponentInterpretation::component_is_part_of_vector);
+    component_interpretation[dim]
+      = DataComponentInterpretation::component_is_scalar;
+    component_interpretation[dim+1]
+      = DataComponentInterpretation::component_is_scalar;
+    data_out.add_data_vector (joint_solution,
+                             joint_solution_names,
+                             DataOut<dim>::type_dof_data,
+                             component_interpretation);
+    data_out.build_patches (deg + 1);
+    std::ofstream output (("solution-" +
+                          Utilities::int_to_string (step, 5) +
+                          ".vtk").c_str());
+    data_out.write_vtk (output);
+  }
 
 
-                                // Following is the helper function that
-                                // computes the vorticity by projecting the
-                                // term $\text{curl} u$ onto the finite
-                                // element space used for the components of
-                                // the velocity. The function is only called
-                                // whenever we generate graphical output, so
-                                // not very often, and as a consequence we
-                                // didn't bother parallelizing it using the
-                                // WorkStream concept as we do for the other
-                                // assembly functions. That should not be
-                                // overly complicated, however, if
-                                // needed. Moreover, the implementation that
-                                // we have here only works for 2d, so we bail
-                                // if that is not the case.
-template <int dim>
-void NavierStokesProjection<dim>::assemble_vorticity (const bool reinit_prec)
-{
-  Assert (dim == 2, ExcNotImplemented());
-  if (reinit_prec)
-    prec_vel_mass.initialize (vel_Mass);
-
-  typename DoFHandler<dim>::active_cell_iterator
-    cell = dof_handler_velocity.begin_active(),
-    end  = dof_handler_velocity.end();
-  FEValues<dim> fe_val_vel (fe_velocity, quadrature_velocity,
-                            update_gradients |
-                           update_JxW_values |
-                           update_values);
-  const unsigned int dpc = fe_velocity.dofs_per_cell,
-                     nqp = quadrature_velocity.size();
-  std::vector<unsigned int> ldi (dpc);
-  Vector<double> loc_rot (dpc);
-
-  std::vector< Tensor<1,dim> > grad_u1 (nqp), grad_u2 (nqp);
-  rot_u = 0.;
-  for (; cell != end; ++cell)
-    {
-      fe_val_vel.reinit (cell);
-      cell->get_dof_indices (ldi);
-      fe_val_vel.get_function_gradients (u_n[0], grad_u1);
-      fe_val_vel.get_function_gradients (u_n[1], grad_u2);
-      loc_rot = 0.;
-      for (unsigned int q=0; q<nqp; ++q)
-       for (unsigned int i=0; i<dpc; ++i)
-         loc_rot(i) += (grad_u2[q][0] - grad_u1[q][1]) *
-                       fe_val_vel.shape_value (i, q) *
-                       fe_val_vel.JxW(q);
 
-      for (unsigned int i=0; i<dpc; ++i)
-       rot_u (ldi[i]) += loc_rot(i);
-    }
+                                  // Following is the helper function that
+                                  // computes the vorticity by projecting the
+                                  // term $\text{curl} u$ onto the finite
+                                  // element space used for the components of
+                                  // the velocity. The function is only called
+                                  // whenever we generate graphical output, so
+                                  // not very often, and as a consequence we
+                                  // didn't bother parallelizing it using the
+                                  // WorkStream concept as we do for the other
+                                  // assembly functions. That should not be
+                                  // overly complicated, however, if
+                                  // needed. Moreover, the implementation that
+                                  // we have here only works for 2d, so we bail
+                                  // if that is not the case.
+  template <int dim>
+  void NavierStokesProjection<dim>::assemble_vorticity (const bool reinit_prec)
+  {
+    Assert (dim == 2, ExcNotImplemented());
+    if (reinit_prec)
+      prec_vel_mass.initialize (vel_Mass);
+
+    FEValues<dim> fe_val_vel (fe_velocity, quadrature_velocity,
+                             update_gradients |
+                             update_JxW_values |
+                             update_values);
+    const unsigned int dpc = fe_velocity.dofs_per_cell,
+                      nqp = quadrature_velocity.size();
+    std::vector<unsigned int> ldi (dpc);
+    Vector<double> loc_rot (dpc);
+
+    std::vector< Tensor<1,dim> > grad_u1 (nqp), grad_u2 (nqp);
+    rot_u = 0.;
+
+    typename DoFHandler<dim>::active_cell_iterator
+      cell = dof_handler_velocity.begin_active(),
+      end  = dof_handler_velocity.end();
+    for (; cell != end; ++cell)
+      {
+       fe_val_vel.reinit (cell);
+       cell->get_dof_indices (ldi);
+       fe_val_vel.get_function_gradients (u_n[0], grad_u1);
+       fe_val_vel.get_function_gradients (u_n[1], grad_u2);
+       loc_rot = 0.;
+       for (unsigned int q=0; q<nqp; ++q)
+         for (unsigned int i=0; i<dpc; ++i)
+           loc_rot(i) += (grad_u2[q][0] - grad_u1[q][1]) *
+                         fe_val_vel.shape_value (i, q) *
+                         fe_val_vel.JxW(q);
+
+       for (unsigned int i=0; i<dpc; ++i)
+         rot_u (ldi[i]) += loc_rot(i);
+      }
 
-  prec_vel_mass.solve (rot_u);
+    prec_vel_mass.solve (rot_u);
+  }
 }
 
 
@@ -1528,9 +1532,14 @@ int main()
 {
   try
     {
+      using namespace dealii;
+      using namespace Step35;
+
       RunTimeParameters::Data_Storage data;
       data.read_data ("parameter-file.prm");
+
       deallog.depth_console (data.verbose ? 2 : 0);
+
       NavierStokesProjection<2> test (data);
       test.run (data.verbose, data.output_interval);
     }
index dbb614860b49e0ee345e838478a26f74530eeee9..989ec262de0b37a93e306a049da78cb2fb043de8 100644 (file)
@@ -3,7 +3,7 @@
 /*         Wolfgang Bangerth, Texas A&M University                */
 /*    $Id$*/
 /*                                                                */
-/*    Copyright (C) 2009 by the deal.II authors */
+/*    Copyright (C) 2009, 2011 by the deal.II authors */
 /*                                                                */
 /*    This file is subject to QPL and may not be  distributed     */
 /*    without copyright and license information. Please refer     */
 #include <fstream>
 #include <iostream>
 
-                                // Finally, as in previous programs,
-                                // we import all the deal.II class
-                                // and function names into the global
-                                // namespace:
-using namespace dealii;
-
-                                // @sect3{The <code>EigenvalueProblem</code> class template}
-
-                                // Following is the class declaration
-                                // for the main class template. It
-                                // looks pretty much exactly like
-                                // what has already been shown in
-                                // step-4:
-template <int dim>
-class EigenvalueProblem 
+                                // Finally, as in previous programs, we
+                                // import all the deal.II class and function
+                                // names into the namespace into which
+                                // everything in this program will go:
+namespace Step36
 {
-  public:
-    EigenvalueProblem (const std::string &prm_file);
-    void run ();
-  
-  private:
-    void make_grid_and_dofs ();
-    void assemble_system ();
-    void solve ();
-    void output_results () const;
-  
-    Triangulation<dim> triangulation;
-    FE_Q<dim>          fe;
-    DoFHandler<dim>    dof_handler;
-
-                                    // With these exceptions: For our
-                                    // eigenvalue problem, we need
-                                    // both a stiffness matrix for
-                                    // the left hand side as well as
-                                    // a mass matrix for the right
-                                    // hand side. We also need not
-                                    // just one solution function,
-                                    // but a whole set of these for
-                                    // the eigenfunctions we want to
-                                    // compute, along with the
-                                    // corresponding eigenvalues:
-    PETScWrappers::SparseMatrix        stiffness_matrix, mass_matrix;
-    std::vector<PETScWrappers::Vector> eigenfunctions;
-    std::vector<double>                eigenvalues;   
-
-                                    // And then we need an object
-                                    // that will store several
-                                    // run-time parameters that we
-                                    // will specify in an input file:
-    ParameterHandler parameters;
-
-                                    // Finally, we will have an
-                                    // object that contains
-                                    // "constraints" on our degrees
-                                    // of freedom. This could include
-                                    // hanging node constraints if we
-                                    // had adaptively refined meshes
-                                    // (which we don't have in the
-                                    // current program). Here, we
-                                    // will store the constraints for
-                                    // boundary nodes $U_i=0$.
-    ConstraintMatrix constraints;
-};
-
-                                // @sect3{Implementation of the <code>EigenvalueProblem</code> class}
-
-                                // @sect4{EigenvalueProblem::EigenvalueProblem}
-
-                                // First up, the constructor. The
-                                // main new part is handling the
-                                // run-time input parameters. We need
-                                // to declare their existence first,
-                                // and then read their values from
-                                // the input file whose name is
-                                // specified as an argument to this
-                                // function:
-template <int dim>
-EigenvalueProblem<dim>::EigenvalueProblem (const std::string &prm_file)
-               :
-               fe (1),
-               dof_handler (triangulation)
-{
-  parameters.declare_entry ("Global mesh refinement steps", "5",
-                           Patterns::Integer (0, 20),
-                           "The number of times the 1-cell coarse mesh should "
-                           "be refined globally for our computations.");
-  parameters.declare_entry ("Number of eigenvalues/eigenfunctions", "5",
-                           Patterns::Integer (0, 100),
-                           "The number of eigenvalues/eigenfunctions "
-                           "to be computed.");
-  parameters.declare_entry ("Potential", "0",
-                           Patterns::Anything(),
-                           "A functional description of the potential.");
-  
-  parameters.read_input (prm_file);
-}
+  using namespace dealii;
 
+                                  // @sect3{The <code>EigenvalueProblem</code> class template}
 
-                                // @sect4{EigenvalueProblem::make_grid_and_dofs}
-
-                                // The next function creates a mesh
-                                // on the domain $[-1,1]^d$, refines
-                                // it as many times as the input file
-                                // calls for, and then attaches a
-                                // DoFHandler to it and initializes
-                                // the matrices and vectors to their
-                                // correct sizes. We also build the
-                                // constraints that correspond to the
-                                // boundary values
-                                // $u|_{\partial\Omega}=0$.
-                                //
-                                // For the matrices, we use the PETSc
-                                // wrappers. These have the ability
-                                // to allocate memory as necessary as
-                                // non-zero entries are added. This
-                                // seems inefficient: we could as
-                                // well first compute the sparsity
-                                // pattern, initialize the matrices
-                                // with it, and as we then insert
-                                // entries we can be sure that we do
-                                // not need to re-allocate memory and
-                                // free the one used previously. One
-                                // way to do that would be to use
-                                // code like this:
-                                // @code
-                                //   CompressedSimpleSparsityPattern
-                                //      csp (dof_handler.n_dofs(),
-                                //           dof_handler.n_dofs());
-                                //   DoFTools::make_sparsity_pattern (dof_handler, csp);
-                                //   csp.compress ();
-                                //   stiffness_matrix.reinit (csp);
-                                //   mass_matrix.reinit (csp);
-                                // @endcode
-                                // instead of the two
-                                // <code>reinit()</code> calls for
-                                // the stiffness and mass matrices
-                                // below.
-                                //
-                                // This doesn't quite work,
-                                // unfortunately. The code above may
-                                // lead to a few entries in the
-                                // non-zero pattern to which we only
-                                // ever write zero entries; most
-                                // notably, this holds true for
-                                // off-diagonal entries for those
-                                // rows and columns that belong to
-                                // boundary nodes. This shouldn't be
-                                // a problem, but for whatever
-                                // reason, PETSc's ILU
-                                // preconditioner, which we use to
-                                // solve linear systems in the
-                                // eigenvalue solver, doesn't like
-                                // these extra entries and aborts
-                                // with an error message.
-                                //
-                                // In the absense of any obvious way
-                                // to avoid this, we simply settle
-                                // for the second best option, which
-                                // is have PETSc allocate memory as
-                                // necessary. That said, since this
-                                // is not a time critical part, this
-                                // whole affair is of no further
-                                // importance.
-template <int dim>
-void EigenvalueProblem<dim>::make_grid_and_dofs ()
-{
-  GridGenerator::hyper_cube (triangulation, -1, 1);
-  triangulation.refine_global (parameters.get_integer ("Global mesh refinement steps"));
-  dof_handler.distribute_dofs (fe);
-
-  DoFTools::make_zero_boundary_constraints (dof_handler, constraints);
-  constraints.close ();
-  
-  stiffness_matrix.reinit (dof_handler.n_dofs(),
-                          dof_handler.n_dofs(),
-                          dof_handler.max_couplings_between_dofs());
-  mass_matrix.reinit (dof_handler.n_dofs(),
-                     dof_handler.n_dofs(),
-                     dof_handler.max_couplings_between_dofs());
-
-                                  // The next step is to take care of
-                                  // the eigenspectrum. In this case,
-                                  // the outputs are eigenvalues and
-                                  // eigenfunctions, so we set the
-                                  // size of the list of
-                                  // eigenfunctions and eigenvalues
-                                  // to be as large as we asked for
-                                  // in the input file:
-  eigenfunctions
-    .resize (parameters.get_integer ("Number of eigenvalues/eigenfunctions"));
-  for (unsigned int i=0; i<eigenfunctions.size (); ++i)
-    eigenfunctions[i].reinit (dof_handler.n_dofs ());
-
-  eigenvalues.resize (eigenfunctions.size ());
-}
+                                  // Following is the class declaration
+                                  // for the main class template. It
+                                  // looks pretty much exactly like
+                                  // what has already been shown in
+                                  // step-4:
+  template <int dim>
+  class EigenvalueProblem
+  {
+    public:
+      EigenvalueProblem (const std::string &prm_file);
+      void run ();
+
+    private:
+      void make_grid_and_dofs ();
+      void assemble_system ();
+      void solve ();
+      void output_results () const;
+
+      Triangulation<dim> triangulation;
+      FE_Q<dim>          fe;
+      DoFHandler<dim>    dof_handler;
+
+                                      // With these exceptions: For our
+                                      // eigenvalue problem, we need
+                                      // both a stiffness matrix for
+                                      // the left hand side as well as
+                                      // a mass matrix for the right
+                                      // hand side. We also need not
+                                      // just one solution function,
+                                      // but a whole set of these for
+                                      // the eigenfunctions we want to
+                                      // compute, along with the
+                                      // corresponding eigenvalues:
+      PETScWrappers::SparseMatrix        stiffness_matrix, mass_matrix;
+      std::vector<PETScWrappers::Vector> eigenfunctions;
+      std::vector<double>                eigenvalues;
+
+                                      // And then we need an object
+                                      // that will store several
+                                      // run-time parameters that we
+                                      // will specify in an input file:
+      ParameterHandler parameters;
+
+                                      // Finally, we will have an
+                                      // object that contains
+                                      // "constraints" on our degrees
+                                      // of freedom. This could include
+                                      // hanging node constraints if we
+                                      // had adaptively refined meshes
+                                      // (which we don't have in the
+                                      // current program). Here, we
+                                      // will store the constraints for
+                                      // boundary nodes $U_i=0$.
+      ConstraintMatrix constraints;
+  };
+
+                                  // @sect3{Implementation of the <code>EigenvalueProblem</code> class}
+
+                                  // @sect4{EigenvalueProblem::EigenvalueProblem}
+
+                                  // First up, the constructor. The
+                                  // main new part is handling the
+                                  // run-time input parameters. We need
+                                  // to declare their existence first,
+                                  // and then read their values from
+                                  // the input file whose name is
+                                  // specified as an argument to this
+                                  // function:
+  template <int dim>
+  EigenvalueProblem<dim>::EigenvalueProblem (const std::string &prm_file)
+                 :
+                 fe (1),
+                 dof_handler (triangulation)
+  {
+    parameters.declare_entry ("Global mesh refinement steps", "5",
+                             Patterns::Integer (0, 20),
+                             "The number of times the 1-cell coarse mesh should "
+                             "be refined globally for our computations.");
+    parameters.declare_entry ("Number of eigenvalues/eigenfunctions", "5",
+                             Patterns::Integer (0, 100),
+                             "The number of eigenvalues/eigenfunctions "
+                             "to be computed.");
+    parameters.declare_entry ("Potential", "0",
+                             Patterns::Anything(),
+                             "A functional description of the potential.");
+
+    parameters.read_input (prm_file);
+  }
 
 
-                                // @sect4{EigenvalueProblem::assemble_system}
-
-                                // Here, we assemble the global
-                                // stiffness and mass matrices from
-                                // local contributions $A^K_{ij} =
-                                // \int_K \nabla\varphi_i(\mathbf x)
-                                // \cdot \nabla\varphi_j(\mathbf x) +
-                                // V(\mathbf x)\varphi_i(\mathbf
-                                // x)\varphi_j(\mathbf x)$ and
-                                // $M^K_{ij} = \int_K
-                                // \varphi_i(\mathbf
-                                // x)\varphi_j(\mathbf x)$
-                                // respectively. This function should
-                                // be immediately familiar if you've
-                                // seen previous tutorial
-                                // programs. The only thing new would
-                                // be setting up an object that
-                                // described the potential $V(\mathbf
-                                // x)$ using the expression that we
-                                // got from the input file. We then
-                                // need to evaluate this object at
-                                // the quadrature points on each
-                                // cell. If you've seen how to
-                                // evaluate function objects (see,
-                                // for example the coefficient in
-                                // step-5), the code here will also
-                                // look rather familiar.
-template <int dim>
-void EigenvalueProblem<dim>::assemble_system () 
-{  
-  QGauss<dim>   quadrature_formula(2);
-  
-  FEValues<dim> fe_values (fe, quadrature_formula, 
-                          update_values | update_gradients |
-                           update_quadrature_points | update_JxW_values);
-  
-  const unsigned int dofs_per_cell = fe.dofs_per_cell;
-  const unsigned int n_q_points    = quadrature_formula.size();
-  
-  FullMatrix<double> cell_stiffness_matrix (dofs_per_cell, dofs_per_cell);
-  FullMatrix<double> cell_mass_matrix (dofs_per_cell, dofs_per_cell);
-  
-  std::vector<unsigned int> local_dof_indices (dofs_per_cell);
-  
-  FunctionParser<dim> potential;
-  potential.initialize (FunctionParser<dim>::default_variable_names (),
-                       parameters.get ("Potential"),
-                       typename FunctionParser<dim>::ConstMap());
-  
-  std::vector<double> potential_values (n_q_points);
-  
-  
-  typename DoFHandler<dim>::active_cell_iterator
-    cell = dof_handler.begin_active (),
-    endc = dof_handler.end ();
-  for (; cell!=endc; ++cell)
-    {
-      fe_values.reinit (cell);
-      cell_stiffness_matrix = 0;
-      cell_mass_matrix      = 0;
-      
-      potential.value_list (fe_values.get_quadrature_points(),
-                           potential_values);
-      
-      for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
-       for (unsigned int i=0; i<dofs_per_cell; ++i)
-         for (unsigned int j=0; j<dofs_per_cell; ++j)
-           {
-             cell_stiffness_matrix (i, j)
-               += (fe_values.shape_grad (i, q_point) *
-                   fe_values.shape_grad (j, q_point) 
-                   + 
-                   potential_values[q_point] *
-                   fe_values.shape_value (i, q_point) *
-                   fe_values.shape_value (j, q_point)
-               ) * fe_values.JxW (q_point);
-             
-             cell_mass_matrix (i, j)
-               += (fe_values.shape_value (i, q_point) *
-                   fe_values.shape_value (j, q_point) 
-               ) * fe_values.JxW (q_point);
-           }
-
-                                      // Now that we have the local
-                                      // matrix contributions, we
-                                      // transfer them into the
-                                      // global objects and take care
-                                      // of zero boundary
-                                      // constraints:
-      cell->get_dof_indices (local_dof_indices);
-      
-      constraints
-       .distribute_local_to_global (cell_stiffness_matrix,
-                                    local_dof_indices,
-                                    stiffness_matrix);
-      constraints
-       .distribute_local_to_global (cell_mass_matrix,
-                                    local_dof_indices,
-                                    mass_matrix);
-    }
+                                  // @sect4{EigenvalueProblem::make_grid_and_dofs}
 
-                                  // At the end of the function, we
-                                  // tell PETSc that the matrices
-                                  // have now been fully assembled
-                                  // and that the sparse matrix
-                                  // representation can now be
-                                  // compressed as no more entries
-                                  // will be added:
-  stiffness_matrix.compress ();
-  mass_matrix.compress ();
-}
+                                  // The next function creates a mesh
+                                  // on the domain $[-1,1]^d$, refines
+                                  // it as many times as the input file
+                                  // calls for, and then attaches a
+                                  // DoFHandler to it and initializes
+                                  // the matrices and vectors to their
+                                  // correct sizes. We also build the
+                                  // constraints that correspond to the
+                                  // boundary values
+                                  // $u|_{\partial\Omega}=0$.
+                                  //
+                                  // For the matrices, we use the PETSc
+                                  // wrappers. These have the ability
+                                  // to allocate memory as necessary as
+                                  // non-zero entries are added. This
+                                  // seems inefficient: we could as
+                                  // well first compute the sparsity
+                                  // pattern, initialize the matrices
+                                  // with it, and as we then insert
+                                  // entries we can be sure that we do
+                                  // not need to re-allocate memory and
+                                  // free the one used previously. One
+                                  // way to do that would be to use
+                                  // code like this:
+                                  // @code
+                                  //   CompressedSimpleSparsityPattern
+                                  //      csp (dof_handler.n_dofs(),
+                                  //           dof_handler.n_dofs());
+                                  //   DoFTools::make_sparsity_pattern (dof_handler, csp);
+                                  //   csp.compress ();
+                                  //   stiffness_matrix.reinit (csp);
+                                  //   mass_matrix.reinit (csp);
+                                  // @endcode
+                                  // instead of the two
+                                  // <code>reinit()</code> calls for
+                                  // the stiffness and mass matrices
+                                  // below.
+                                  //
+                                  // This doesn't quite work,
+                                  // unfortunately. The code above may
+                                  // lead to a few entries in the
+                                  // non-zero pattern to which we only
+                                  // ever write zero entries; most
+                                  // notably, this holds true for
+                                  // off-diagonal entries for those
+                                  // rows and columns that belong to
+                                  // boundary nodes. This shouldn't be
+                                  // a problem, but for whatever
+                                  // reason, PETSc's ILU
+                                  // preconditioner, which we use to
+                                  // solve linear systems in the
+                                  // eigenvalue solver, doesn't like
+                                  // these extra entries and aborts
+                                  // with an error message.
+                                  //
+                                  // In the absense of any obvious way
+                                  // to avoid this, we simply settle
+                                  // for the second best option, which
+                                  // is have PETSc allocate memory as
+                                  // necessary. That said, since this
+                                  // is not a time critical part, this
+                                  // whole affair is of no further
+                                  // importance.
+  template <int dim>
+  void EigenvalueProblem<dim>::make_grid_and_dofs ()
+  {
+    GridGenerator::hyper_cube (triangulation, -1, 1);
+    triangulation.refine_global (parameters.get_integer ("Global mesh refinement steps"));
+    dof_handler.distribute_dofs (fe);
+
+    DoFTools::make_zero_boundary_constraints (dof_handler, constraints);
+    constraints.close ();
+
+    stiffness_matrix.reinit (dof_handler.n_dofs(),
+                            dof_handler.n_dofs(),
+                            dof_handler.max_couplings_between_dofs());
+    mass_matrix.reinit (dof_handler.n_dofs(),
+                       dof_handler.n_dofs(),
+                       dof_handler.max_couplings_between_dofs());
+
+                                    // The next step is to take care of
+                                    // the eigenspectrum. In this case,
+                                    // the outputs are eigenvalues and
+                                    // eigenfunctions, so we set the
+                                    // size of the list of
+                                    // eigenfunctions and eigenvalues
+                                    // to be as large as we asked for
+                                    // in the input file:
+    eigenfunctions
+      .resize (parameters.get_integer ("Number of eigenvalues/eigenfunctions"));
+    for (unsigned int i=0; i<eigenfunctions.size (); ++i)
+      eigenfunctions[i].reinit (dof_handler.n_dofs ());
+
+    eigenvalues.resize (eigenfunctions.size ());
+  }
 
 
-                                // @sect4{EigenvalueProblem::solve}
-
-                                // This is the key new functionality
-                                // of the program. Now that the
-                                // system is set up, here is a good
-                                // time to actually solve the
-                                // problem: As with other examples
-                                // this is done using a "solve"
-                                // routine. Essentially, it works as
-                                // in other programs: you set up a
-                                // SolverControl object that
-                                // describes the accuracy to which we
-                                // want to solve the linear systems,
-                                // and then we select the kind of
-                                // solver we want. Here we choose the
-                                // Krylov-Schur solver of SLEPc, a
-                                // pretty fast and robust choice for
-                                // this kind of problem:
-template <int dim>
-void EigenvalueProblem<dim>::solve () 
-{
+                                  // @sect4{EigenvalueProblem::assemble_system}
+
+                                  // Here, we assemble the global
+                                  // stiffness and mass matrices from
+                                  // local contributions $A^K_{ij} =
+                                  // \int_K \nabla\varphi_i(\mathbf x)
+                                  // \cdot \nabla\varphi_j(\mathbf x) +
+                                  // V(\mathbf x)\varphi_i(\mathbf
+                                  // x)\varphi_j(\mathbf x)$ and
+                                  // $M^K_{ij} = \int_K
+                                  // \varphi_i(\mathbf
+                                  // x)\varphi_j(\mathbf x)$
+                                  // respectively. This function should
+                                  // be immediately familiar if you've
+                                  // seen previous tutorial
+                                  // programs. The only thing new would
+                                  // be setting up an object that
+                                  // described the potential $V(\mathbf
+                                  // x)$ using the expression that we
+                                  // got from the input file. We then
+                                  // need to evaluate this object at
+                                  // the quadrature points on each
+                                  // cell. If you've seen how to
+                                  // evaluate function objects (see,
+                                  // for example the coefficient in
+                                  // step-5), the code here will also
+                                  // look rather familiar.
+  template <int dim>
+  void EigenvalueProblem<dim>::assemble_system ()
+  {
+    QGauss<dim>   quadrature_formula(2);
 
-                                 // We start here, as we normally do,
-                                 // by assigning convergence control
-                                 // we want:
-  SolverControl solver_control (dof_handler.n_dofs(), 1e-9);
-  SLEPcWrappers::SolverKrylovSchur eigensolver (solver_control);
-
-                                  // Before we actually solve for the
-                                  // eigenfunctions and -values, we
-                                  // have to also select which set of
-                                  // eigenvalues to solve for. Lets
-                                  // select those eigenvalues and
-                                  // corresponding eigenfunctions
-                                  // with the smallest real part (in
-                                  // fact, the problem we solve here
-                                  // is symmetric and so the
-                                  // eigenvalues are purely
-                                  // real). After that, we can
-                                  // actually let SLEPc do its work:
-  eigensolver.set_which_eigenpairs (EPS_SMALLEST_REAL);
-
-  eigensolver.solve (stiffness_matrix, mass_matrix, 
-                    eigenvalues, eigenfunctions, 
-                    eigenfunctions.size());
-
-                                  // The output of the call above is
-                                  // a set of vectors and values. In
-                                  // eigenvalue problems, the
-                                  // eigenfunctions are only
-                                  // determined up to a constant that
-                                  // can be fixed pretty
-                                  // arbitrarily. Knowing nothing
-                                  // about the origin of the
-                                  // eigenvalue problem, SLEPc has no
-                                  // other choice than to normalize
-                                  // the eigenvectors to one in the
-                                  // $l_2$ (vector)
-                                  // norm. Unfortunately this norm
-                                  // has little to do with any norm
-                                  // we may be interested from a
-                                  // eigenfunction perspective: the
-                                  // $L_2(\Omega)$ norm, or maybe the
-                                  // $L_\infty(\Omega)$ norm.
-                                  //
-                                  // Let us choose the latter and
-                                  // rescale eigenfunctions so that
-                                  // they have $\|\phi_i(\mathbf
-                                  // x)\|_{L^\infty(\Omega)}=1$
-                                  // instead of $\|\Phi\|_{l_2}=1$
-                                  // (where $\phi_i$ is the $i$th
-                                  // eigen<i>function</i> and
-                                  // $\Phi_i$ the corresponding
-                                  // vector of nodal values). For the
-                                  // $Q_1$ elements chosen here, we
-                                  // know that the maximum of the
-                                  // function $\phi_i(\mathbf x)$ is
-                                  // attained at one of the nodes, so
-                                  // $\max_{\mathbf x}\phi_i(\mathbf
-                                  // x)=\max_j (\Phi_i)_j$, making
-                                  // the normalization in the
-                                  // $L_\infty$ norm trivial. Note
-                                  // that this doesn't work as easily
-                                  // if we had chosen $Q_k$ elements
-                                  // with $k>1$: there, the maximum
-                                  // of a function does not
-                                  // necessarily have to be attained
-                                  // at a node, and so $\max_{\mathbf
-                                  // x}\phi_i(\mathbf x)\ge\max_j
-                                  // (\Phi_i)_j$ (although the
-                                  // equality is usually nearly
-                                  // true).
-  for (unsigned int i=0; i<eigenfunctions.size(); ++i)
-    eigenfunctions[i] /= eigenfunctions[i].linfty_norm ();
-}
+    FEValues<dim> fe_values (fe, quadrature_formula,
+                            update_values | update_gradients |
+                            update_quadrature_points | update_JxW_values);
 
+    const unsigned int dofs_per_cell = fe.dofs_per_cell;
+    const unsigned int n_q_points    = quadrature_formula.size();
+
+    FullMatrix<double> cell_stiffness_matrix (dofs_per_cell, dofs_per_cell);
+    FullMatrix<double> cell_mass_matrix (dofs_per_cell, dofs_per_cell);
+
+    std::vector<unsigned int> local_dof_indices (dofs_per_cell);
 
-                                // @sect4{EigenvalueProblem::output_results}
-
-                                // This is the last significant
-                                // function of this program. It uses
-                                // the DataOut class to generate
-                                // graphical output from the
-                                // eigenfunctions for later
-                                // visualization. It works as in many
-                                // of the other tutorial programs.
-                                //
-                                // The whole collection of functions
-                                // is then output as a single VTK
-                                // file.
-template <int dim>
-void EigenvalueProblem<dim>::output_results () const
-{
-  DataOut<dim> data_out;
-
-  data_out.attach_dof_handler (dof_handler);
-
-  for (unsigned int i=0; i<eigenfunctions.size(); ++i)
-    data_out.add_data_vector (eigenfunctions[i],
-                             std::string("eigenfunction_") +
-                             Utilities::int_to_string(i));
-
-                                // The only thing worth discussing
-                                // may be that because the potential
-                                // is specified as a function
-                                // expression in the input file, it
-                                // would be nice to also have it as a
-                                // graphical representation along
-                                // with the eigenfunctions. The
-                                // process to achieve this is
-                                // relatively straightforward: we
-                                // build an object that represents
-                                // $V(\mathbf x)$ and then we
-                                // interpolate this continuous
-                                // function onto the finite element
-                                // space. The result we also attach
-                                // to the DataOut object for
-                                // visualization.
-  Vector<double> projected_potential (dof_handler.n_dofs());
-  {
     FunctionParser<dim> potential;
     potential.initialize (FunctionParser<dim>::default_variable_names (),
                          parameters.get ("Potential"),
                          typename FunctionParser<dim>::ConstMap());
-    VectorTools::interpolate (dof_handler, potential, projected_potential);
+
+    std::vector<double> potential_values (n_q_points);
+
+
+    typename DoFHandler<dim>::active_cell_iterator
+      cell = dof_handler.begin_active (),
+      endc = dof_handler.end ();
+    for (; cell!=endc; ++cell)
+      {
+       fe_values.reinit (cell);
+       cell_stiffness_matrix = 0;
+       cell_mass_matrix      = 0;
+
+       potential.value_list (fe_values.get_quadrature_points(),
+                             potential_values);
+
+       for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
+         for (unsigned int i=0; i<dofs_per_cell; ++i)
+           for (unsigned int j=0; j<dofs_per_cell; ++j)
+             {
+               cell_stiffness_matrix (i, j)
+                 += (fe_values.shape_grad (i, q_point) *
+                     fe_values.shape_grad (j, q_point)
+                     +
+                     potential_values[q_point] *
+                     fe_values.shape_value (i, q_point) *
+                     fe_values.shape_value (j, q_point)
+                 ) * fe_values.JxW (q_point);
+
+               cell_mass_matrix (i, j)
+                 += (fe_values.shape_value (i, q_point) *
+                     fe_values.shape_value (j, q_point)
+                 ) * fe_values.JxW (q_point);
+             }
+
+                                        // Now that we have the local
+                                        // matrix contributions, we
+                                        // transfer them into the
+                                        // global objects and take care
+                                        // of zero boundary
+                                        // constraints:
+       cell->get_dof_indices (local_dof_indices);
+
+       constraints
+         .distribute_local_to_global (cell_stiffness_matrix,
+                                      local_dof_indices,
+                                      stiffness_matrix);
+       constraints
+         .distribute_local_to_global (cell_mass_matrix,
+                                      local_dof_indices,
+                                      mass_matrix);
+      }
+
+                                    // At the end of the function, we
+                                    // tell PETSc that the matrices
+                                    // have now been fully assembled
+                                    // and that the sparse matrix
+                                    // representation can now be
+                                    // compressed as no more entries
+                                    // will be added:
+    stiffness_matrix.compress ();
+    mass_matrix.compress ();
   }
-  data_out.add_data_vector (projected_potential, "interpolated_potential");
-  
-  data_out.build_patches ();
 
-  std::ofstream output ("eigenvectors.vtk");
-  data_out.write_vtk (output);
-}
 
+                                  // @sect4{EigenvalueProblem::solve}
+
+                                  // This is the key new functionality
+                                  // of the program. Now that the
+                                  // system is set up, here is a good
+                                  // time to actually solve the
+                                  // problem: As with other examples
+                                  // this is done using a "solve"
+                                  // routine. Essentially, it works as
+                                  // in other programs: you set up a
+                                  // SolverControl object that
+                                  // describes the accuracy to which we
+                                  // want to solve the linear systems,
+                                  // and then we select the kind of
+                                  // solver we want. Here we choose the
+                                  // Krylov-Schur solver of SLEPc, a
+                                  // pretty fast and robust choice for
+                                  // this kind of problem:
+  template <int dim>
+  void EigenvalueProblem<dim>::solve ()
+  {
 
-                                 // @sect4{EigenvalueProblem::run}
+                                    // We start here, as we normally do,
+                                    // by assigning convergence control
+                                    // we want:
+    SolverControl solver_control (dof_handler.n_dofs(), 1e-9);
+    SLEPcWrappers::SolverKrylovSchur eigensolver (solver_control);
+
+                                    // Before we actually solve for the
+                                    // eigenfunctions and -values, we
+                                    // have to also select which set of
+                                    // eigenvalues to solve for. Lets
+                                    // select those eigenvalues and
+                                    // corresponding eigenfunctions
+                                    // with the smallest real part (in
+                                    // fact, the problem we solve here
+                                    // is symmetric and so the
+                                    // eigenvalues are purely
+                                    // real). After that, we can
+                                    // actually let SLEPc do its work:
+    eigensolver.set_which_eigenpairs (EPS_SMALLEST_REAL);
+
+    eigensolver.solve (stiffness_matrix, mass_matrix,
+                      eigenvalues, eigenfunctions,
+                      eigenfunctions.size());
+
+                                    // The output of the call above is
+                                    // a set of vectors and values. In
+                                    // eigenvalue problems, the
+                                    // eigenfunctions are only
+                                    // determined up to a constant that
+                                    // can be fixed pretty
+                                    // arbitrarily. Knowing nothing
+                                    // about the origin of the
+                                    // eigenvalue problem, SLEPc has no
+                                    // other choice than to normalize
+                                    // the eigenvectors to one in the
+                                    // $l_2$ (vector)
+                                    // norm. Unfortunately this norm
+                                    // has little to do with any norm
+                                    // we may be interested from a
+                                    // eigenfunction perspective: the
+                                    // $L_2(\Omega)$ norm, or maybe the
+                                    // $L_\infty(\Omega)$ norm.
+                                    //
+                                    // Let us choose the latter and
+                                    // rescale eigenfunctions so that
+                                    // they have $\|\phi_i(\mathbf
+                                    // x)\|_{L^\infty(\Omega)}=1$
+                                    // instead of $\|\Phi\|_{l_2}=1$
+                                    // (where $\phi_i$ is the $i$th
+                                    // eigen<i>function</i> and
+                                    // $\Phi_i$ the corresponding
+                                    // vector of nodal values). For the
+                                    // $Q_1$ elements chosen here, we
+                                    // know that the maximum of the
+                                    // function $\phi_i(\mathbf x)$ is
+                                    // attained at one of the nodes, so
+                                    // $\max_{\mathbf x}\phi_i(\mathbf
+                                    // x)=\max_j (\Phi_i)_j$, making
+                                    // the normalization in the
+                                    // $L_\infty$ norm trivial. Note
+                                    // that this doesn't work as easily
+                                    // if we had chosen $Q_k$ elements
+                                    // with $k>1$: there, the maximum
+                                    // of a function does not
+                                    // necessarily have to be attained
+                                    // at a node, and so $\max_{\mathbf
+                                    // x}\phi_i(\mathbf x)\ge\max_j
+                                    // (\Phi_i)_j$ (although the
+                                    // equality is usually nearly
+                                    // true).
+    for (unsigned int i=0; i<eigenfunctions.size(); ++i)
+      eigenfunctions[i] /= eigenfunctions[i].linfty_norm ();
+  }
 
-                                 // This is the function which has the
-                                // top-level control over
-                                // everything. It is almost exactly
-                                // the same as in step-4:
-template <int dim>
-void EigenvalueProblem<dim>::run () 
-{
-  make_grid_and_dofs ();
-
-  std::cout << "   Number of active cells:       "
-           << triangulation.n_active_cells ()
-           << std::endl
-           << "   Number of degrees of freedom: "
-           << dof_handler.n_dofs ()
-           << std::endl
-           << std::endl;
-  
-  assemble_system ();
-  solve ();
-  output_results ();
-
-  for (unsigned int i=0; i<eigenvalues.size(); ++i)
-    std::cout << "   Eigenvalue " << i 
-             << " : " << eigenvalues[i]
+
+                                  // @sect4{EigenvalueProblem::output_results}
+
+                                  // This is the last significant
+                                  // function of this program. It uses
+                                  // the DataOut class to generate
+                                  // graphical output from the
+                                  // eigenfunctions for later
+                                  // visualization. It works as in many
+                                  // of the other tutorial programs.
+                                  //
+                                  // The whole collection of functions
+                                  // is then output as a single VTK
+                                  // file.
+  template <int dim>
+  void EigenvalueProblem<dim>::output_results () const
+  {
+    DataOut<dim> data_out;
+
+    data_out.attach_dof_handler (dof_handler);
+
+    for (unsigned int i=0; i<eigenfunctions.size(); ++i)
+      data_out.add_data_vector (eigenfunctions[i],
+                               std::string("eigenfunction_") +
+                               Utilities::int_to_string(i));
+
+                                    // The only thing worth discussing
+                                    // may be that because the potential
+                                    // is specified as a function
+                                    // expression in the input file, it
+                                    // would be nice to also have it as a
+                                    // graphical representation along
+                                    // with the eigenfunctions. The
+                                    // process to achieve this is
+                                    // relatively straightforward: we
+                                    // build an object that represents
+                                    // $V(\mathbf x)$ and then we
+                                    // interpolate this continuous
+                                    // function onto the finite element
+                                    // space. The result we also attach
+                                    // to the DataOut object for
+                                    // visualization.
+    Vector<double> projected_potential (dof_handler.n_dofs());
+    {
+      FunctionParser<dim> potential;
+      potential.initialize (FunctionParser<dim>::default_variable_names (),
+                           parameters.get ("Potential"),
+                           typename FunctionParser<dim>::ConstMap());
+      VectorTools::interpolate (dof_handler, potential, projected_potential);
+    }
+    data_out.add_data_vector (projected_potential, "interpolated_potential");
+
+    data_out.build_patches ();
+
+    std::ofstream output ("eigenvectors.vtk");
+    data_out.write_vtk (output);
+  }
+
+
+                                  // @sect4{EigenvalueProblem::run}
+
+                                  // This is the function which has the
+                                  // top-level control over
+                                  // everything. It is almost exactly
+                                  // the same as in step-4:
+  template <int dim>
+  void EigenvalueProblem<dim>::run ()
+  {
+    make_grid_and_dofs ();
+
+    std::cout << "   Number of active cells:       "
+             << triangulation.n_active_cells ()
+             << std::endl
+             << "   Number of degrees of freedom: "
+             << dof_handler.n_dofs ()
+             << std::endl
              << std::endl;
-}
 
+    assemble_system ();
+    solve ();
+    output_results ();
+
+    for (unsigned int i=0; i<eigenvalues.size(); ++i)
+      std::cout << "   Eigenvalue " << i
+               << " : " << eigenvalues[i]
+               << std::endl;
+  }
+}
 
                                  // @sect3{The <code>main</code> function}
-int main (int argc, char **argv) 
+int main (int argc, char **argv)
 {
   try
     {
@@ -566,8 +568,11 @@ int main (int argc, char **argv)
       SlepcInitialize (&argc, &argv, 0, 0);
 
       {
+       using namespace dealii;
+       using namespace Step36;
+
        deallog.depth_console (0);
-       
+
        EigenvalueProblem<2> problem ("step-36.prm");
        problem.run ();
       }
@@ -592,7 +597,7 @@ int main (int argc, char **argv)
 
       return 1;
     }
-  catch (...) 
+  catch (...)
     {
       std::cerr << std::endl << std::endl
                << "----------------------------------------------------"
@@ -603,13 +608,13 @@ int main (int argc, char **argv)
                << std::endl;
       return 1;
     }
-  
+
                                   // If no exceptions are thrown,
                                   // then we tell the program to stop
                                   // monkeying around and exit
                                   // nicely:
-  std::cout << std::endl 
-           << "Job done." 
+  std::cout << std::endl
+           << "Job done."
            << std::endl;
 
   return 0;
index dfd540321a3bed2bb3535da41f870a952d428ab0..61a32d7b4b87850d9c8a9e034fc6a381768a57f0 100644 (file)
 #include <fstream>
 #include <iostream>
 
-using namespace dealii;
-
-                                // @sect3{The <code>LaplaceBeltramiProblem</code> class template}
-
-                                // This class is almost exactly similar to
-                                // the <code>LaplaceProblem</code> class in
-                                // step-4.
-
-                                // The essential differences are these:
-                                //
-                                // - The template parameter now denotes the
-                                //   dimensionality of the embedding space,
-                                //   which is no longer the same as the
-                                //   dimensionality of the domain and the
-                                //   triangulation on which we compute. We
-                                //   indicate this by calling the parameter
-                                //   @p spacedim , and introducing a constant
-                                //   @p dim equal to the dimensionality of
-                                //   the domain -- here equal to
-                                //   <code>spacedim-1</code>.
-                                // - All member variables that have geometric
-                                //   aspects now need to know about both
-                                //   their own dimensionality as well as that
-                                //   of the embedding space. Consequently, we
-                                //   need to specify both of their template
-                                //   parameters one for the dimension of the
-                                //   mesh @p dim, and the other for the
-                                //   dimension of the embedding space,
-                                //   @p spacedim. This is exactly what we
-                                //   did in step-34, take a look there for
-                                //   a deeper explanation.
-
-                                // - We need an object that describes which
-                                //   kind of mapping to use from the
-                                //   reference cell to the cells that the
-                                //   triangulation is composed of. The
-                                //   classes derived from the Mapping base
-                                //   class do exactly this. Throughout most
-                                //   of deal.II, if you don't do anything at
-                                //   all, the library assumes that you want
-                                //   an object of kind MappingQ1 that uses a
-                                //   (bi-, tri-)linear mapping. In many
-                                //   cases, this is quite sufficient, which
-                                //   is why the use of these objects is
-                                //   mostly optional: for example, if you
-                                //   have a polygonal two-dimensional domain
-                                //   in two-dimensional space, a bilinear
-                                //   mapping of the reference cell to the
-                                //   cells of the triangulation yields an
-                                //   exact representation of the domain. If
-                                //   you have a curved domain, one may want
-                                //   to use a higher order mapping for those
-                                //   cells that lie at the boundary of the
-                                //   domain -- this is what we did in
-                                //   step-11, for example. However, here we
-                                //   have a curved domain, not just a curved
-                                //   boundary, and while we can approximate
-                                //   it with bilinearly mapped cells, it is
-                                //   really only prodent to use a higher
-                                //   order mapping for all
-                                //   cells. Consequently, this class has a
-                                //   member variable of type MappingQ; we
-                                //   will choose the polynomial degree of the
-                                //   mapping equal to the polynomial degree
-                                //   of the finite element used in the
-                                //   computations to ensure optimal approximation, though this
-                                //   iso-parametricity is not required.
-template <int spacedim>
-class LaplaceBeltramiProblem
-{
-  public:
-    LaplaceBeltramiProblem (const unsigned degree = 2);
-    void run ();
-
-  private:
-    static const unsigned int dim = spacedim-1;
-
-    void make_grid_and_dofs ();
-    void assemble_system ();
-    void solve ();
-    void output_results () const;
-    void compute_error () const;
-
-
-    Triangulation<dim,spacedim>   triangulation;
-    FE_Q<dim,spacedim>            fe;
-    DoFHandler<dim,spacedim>      dof_handler;
-    MappingQ<dim, spacedim>       mapping;
-
-    SparsityPattern               sparsity_pattern;
-    SparseMatrix<double>          system_matrix;
-
-    Vector<double>                solution;
-    Vector<double>                system_rhs;
-};
-
-
-                                // @sect3{Equation data}
-
-                                 // Next, let us define the classes that
-                                 // describe the exact solution and the right
-                                 // hand sides of the problem. This is in
-                                 // analogy to step-4 and step-7 where we also
-                                 // defined such objects. Given the discussion
-                                 // in the introduction, the actual formulas
-                                 // should be self-explanatory. A point of
-                                 // interest may be how we define the value
-                                 // and gradient functions for the 2d and 3d
-                                 // cases separately, using explicit
-                                 // specializations of the general
-                                 // template. An alternative to doing it this
-                                 // way might have been to define the general
-                                 // template and have a <code>switch</code>
-                                 // statement (or a sequence of
-                                 // <code>if</code>s) for each possible value
-                                 // of the spatial dimension.
-template <int dim>
-class Solution  : public Function<dim>
-{
-  public:
-    Solution () : Function<dim>() {}
 
-    virtual double value (const Point<dim>   &p,
-                         const unsigned int  component = 0) const;
+namespace Step38
+{
+  using namespace dealii;
+
+                                  // @sect3{The <code>LaplaceBeltramiProblem</code> class template}
+
+                                  // This class is almost exactly similar to
+                                  // the <code>LaplaceProblem</code> class in
+                                  // step-4.
+
+                                  // The essential differences are these:
+                                  //
+                                  // - The template parameter now denotes the
+                                  //   dimensionality of the embedding space,
+                                  //   which is no longer the same as the
+                                  //   dimensionality of the domain and the
+                                  //   triangulation on which we compute. We
+                                  //   indicate this by calling the parameter
+                                  //   @p spacedim , and introducing a constant
+                                  //   @p dim equal to the dimensionality of
+                                  //   the domain -- here equal to
+                                  //   <code>spacedim-1</code>.
+                                  // - All member variables that have geometric
+                                  //   aspects now need to know about both
+                                  //   their own dimensionality as well as that
+                                  //   of the embedding space. Consequently, we
+                                  //   need to specify both of their template
+                                  //   parameters one for the dimension of the
+                                  //   mesh @p dim, and the other for the
+                                  //   dimension of the embedding space,
+                                  //   @p spacedim. This is exactly what we
+                                  //   did in step-34, take a look there for
+                                  //   a deeper explanation.
+
+                                  // - We need an object that describes which
+                                  //   kind of mapping to use from the
+                                  //   reference cell to the cells that the
+                                  //   triangulation is composed of. The
+                                  //   classes derived from the Mapping base
+                                  //   class do exactly this. Throughout most
+                                  //   of deal.II, if you don't do anything at
+                                  //   all, the library assumes that you want
+                                  //   an object of kind MappingQ1 that uses a
+                                  //   (bi-, tri-)linear mapping. In many
+                                  //   cases, this is quite sufficient, which
+                                  //   is why the use of these objects is
+                                  //   mostly optional: for example, if you
+                                  //   have a polygonal two-dimensional domain
+                                  //   in two-dimensional space, a bilinear
+                                  //   mapping of the reference cell to the
+                                  //   cells of the triangulation yields an
+                                  //   exact representation of the domain. If
+                                  //   you have a curved domain, one may want
+                                  //   to use a higher order mapping for those
+                                  //   cells that lie at the boundary of the
+                                  //   domain -- this is what we did in
+                                  //   step-11, for example. However, here we
+                                  //   have a curved domain, not just a curved
+                                  //   boundary, and while we can approximate
+                                  //   it with bilinearly mapped cells, it is
+                                  //   really only prodent to use a higher
+                                  //   order mapping for all
+                                  //   cells. Consequently, this class has a
+                                  //   member variable of type MappingQ; we
+                                  //   will choose the polynomial degree of the
+                                  //   mapping equal to the polynomial degree
+                                  //   of the finite element used in the
+                                  //   computations to ensure optimal approximation, though this
+                                  //   iso-parametricity is not required.
+  template <int spacedim>
+  class LaplaceBeltramiProblem
+  {
+    public:
+      LaplaceBeltramiProblem (const unsigned degree = 2);
+      void run ();
+
+    private:
+      static const unsigned int dim = spacedim-1;
+
+      void make_grid_and_dofs ();
+      void assemble_system ();
+      void solve ();
+      void output_results () const;
+      void compute_error () const;
+
+
+      Triangulation<dim,spacedim>   triangulation;
+      FE_Q<dim,spacedim>            fe;
+      DoFHandler<dim,spacedim>      dof_handler;
+      MappingQ<dim, spacedim>       mapping;
+
+      SparsityPattern               sparsity_pattern;
+      SparseMatrix<double>          system_matrix;
+
+      Vector<double>                solution;
+      Vector<double>                system_rhs;
+  };
+
+
+                                  // @sect3{Equation data}
+
+                                  // Next, let us define the classes that
+                                  // describe the exact solution and the right
+                                  // hand sides of the problem. This is in
+                                  // analogy to step-4 and step-7 where we also
+                                  // defined such objects. Given the discussion
+                                  // in the introduction, the actual formulas
+                                  // should be self-explanatory. A point of
+                                  // interest may be how we define the value
+                                  // and gradient functions for the 2d and 3d
+                                  // cases separately, using explicit
+                                  // specializations of the general
+                                  // template. An alternative to doing it this
+                                  // way might have been to define the general
+                                  // template and have a <code>switch</code>
+                                  // statement (or a sequence of
+                                  // <code>if</code>s) for each possible value
+                                  // of the spatial dimension.
+  template <int dim>
+  class Solution  : public Function<dim>
+  {
+    public:
+      Solution () : Function<dim>() {}
 
-    virtual Tensor<1,dim> gradient (const Point<dim>   &p,
-                                   const unsigned int  component = 0) const;
+      virtual double value (const Point<dim>   &p,
+                           const unsigned int  component = 0) const;
 
-};
+      virtual Tensor<1,dim> gradient (const Point<dim>   &p,
+                                     const unsigned int  component = 0) const;
 
+  };
 
-template <>
-double
-Solution<2>::value (const Point<2> &p,
-                   const unsigned int) const
-{
-  return ( -2. * p(0) * p(1) );
-}
 
+  template <>
+  double
+  Solution<2>::value (const Point<2> &p,
+                     const unsigned int) const
+  {
+    return ( -2. * p(0) * p(1) );
+  }
 
-template <>
-Tensor<1,2>
-Solution<2>::gradient (const Point<2>   &p,
-                      const unsigned int) const
-{
-  Tensor<1,2> return_value;
-  return_value[0] = -2. * p(1) * (1 - 2. * p(0) * p(0));
-  return_value[1] = -2. * p(0) * (1 - 2. * p(1) * p(1));
 
-  return return_value;
-}
+  template <>
+  Tensor<1,2>
+  Solution<2>::gradient (const Point<2>   &p,
+                        const unsigned int) const
+  {
+    Tensor<1,2> return_value;
+    return_value[0] = -2. * p(1) * (1 - 2. * p(0) * p(0));
+    return_value[1] = -2. * p(0) * (1 - 2. * p(1) * p(1));
 
+    return return_value;
+  }
 
-template <>
-double
-Solution<3>::value (const Point<3> &p,
-                   const unsigned int) const
-{
-  return (std::sin(numbers::PI * p(0)) *
-         std::cos(numbers::PI * p(1))*exp(p(2)));
-}
 
+  template <>
+  double
+  Solution<3>::value (const Point<3> &p,
+                     const unsigned int) const
+  {
+    return (std::sin(numbers::PI * p(0)) *
+           std::cos(numbers::PI * p(1))*exp(p(2)));
+  }
 
-template <>
-Tensor<1,3>
-Solution<3>::gradient (const Point<3>   &p,
-                      const unsigned int) const
-{
-  using numbers::PI;
 
-  Tensor<1,3> return_value;
+  template <>
+  Tensor<1,3>
+  Solution<3>::gradient (const Point<3>   &p,
+                        const unsigned int) const
+  {
+    using numbers::PI;
 
-  return_value[0] = PI *cos(PI * p(0))*cos(PI * p(1))*exp(p(2));
-  return_value[1] = -PI *sin(PI * p(0))*sin(PI * p(1))*exp(p(2));
-  return_value[2] = sin(PI * p(0))*cos(PI * p(1))*exp(p(2));
+    Tensor<1,3> return_value;
 
-  return return_value;
-}
+    return_value[0] = PI *cos(PI * p(0))*cos(PI * p(1))*exp(p(2));
+    return_value[1] = -PI *sin(PI * p(0))*sin(PI * p(1))*exp(p(2));
+    return_value[2] = sin(PI * p(0))*cos(PI * p(1))*exp(p(2));
 
+    return return_value;
+  }
 
 
-template <int dim>
-class RightHandSide : public Function<dim>
-{
-  public:
-    RightHandSide () : Function<dim>() {}
 
-    virtual double value (const Point<dim>   &p,
-                         const unsigned int  component = 0) const;
-};
+  template <int dim>
+  class RightHandSide : public Function<dim>
+  {
+    public:
+      RightHandSide () : Function<dim>() {}
 
-template <>
-double
-RightHandSide<2>::value (const Point<2> &p,
-                        const unsigned int /*component*/) const
-{
-  return ( -8. * p(0) * p(1) );
-}
+      virtual double value (const Point<dim>   &p,
+                           const unsigned int  component = 0) const;
+  };
 
+  template <>
+  double
+  RightHandSide<2>::value (const Point<2> &p,
+                          const unsigned int /*component*/) const
+  {
+    return ( -8. * p(0) * p(1) );
+  }
 
-template <>
-double
-RightHandSide<3>::value (const Point<3> &p,
-                        const unsigned int /*component*/) const
-{
-  using numbers::PI;
 
-  Tensor<2,3> hessian;
+  template <>
+  double
+  RightHandSide<3>::value (const Point<3> &p,
+                          const unsigned int /*component*/) const
+  {
+    using numbers::PI;
 
-  hessian[0][0] = -PI*PI*sin(PI*p(0))*cos(PI*p(1))*exp(p(2));
-  hessian[1][1] = -PI*PI*sin(PI*p(0))*cos(PI*p(1))*exp(p(2));
-  hessian[2][2] = sin(PI*p(0))*cos(PI*p(1))*exp(p(2));
+    Tensor<2,3> hessian;
 
-  hessian[0][1] = -PI*PI*cos(PI*p(0))*sin(PI*p(1))*exp(p(2));
-  hessian[1][0] = -PI*PI*cos(PI*p(0))*sin(PI*p(1))*exp(p(2));
+    hessian[0][0] = -PI*PI*sin(PI*p(0))*cos(PI*p(1))*exp(p(2));
+    hessian[1][1] = -PI*PI*sin(PI*p(0))*cos(PI*p(1))*exp(p(2));
+    hessian[2][2] = sin(PI*p(0))*cos(PI*p(1))*exp(p(2));
 
-  hessian[0][2] = PI*cos(PI*p(0))*cos(PI*p(1))*exp(p(2));
-  hessian[2][0] = PI*cos(PI*p(0))*cos(PI*p(1))*exp(p(2));
+    hessian[0][1] = -PI*PI*cos(PI*p(0))*sin(PI*p(1))*exp(p(2));
+    hessian[1][0] = -PI*PI*cos(PI*p(0))*sin(PI*p(1))*exp(p(2));
 
-  hessian[1][2] = -PI*sin(PI*p(0))*sin(PI*p(1))*exp(p(2));
-  hessian[2][1] = -PI*sin(PI*p(0))*sin(PI*p(1))*exp(p(2));
+    hessian[0][2] = PI*cos(PI*p(0))*cos(PI*p(1))*exp(p(2));
+    hessian[2][0] = PI*cos(PI*p(0))*cos(PI*p(1))*exp(p(2));
 
-  Tensor<1,3> gradient;
-  gradient[0] = PI * cos(PI*p(0))*cos(PI*p(1))*exp(p(2));
-  gradient[1] = - PI * sin(PI*p(0))*sin(PI*p(1))*exp(p(2));
-  gradient[2] = sin(PI*p(0))*cos(PI*p(1))*exp(p(2));
+    hessian[1][2] = -PI*sin(PI*p(0))*sin(PI*p(1))*exp(p(2));
+    hessian[2][1] = -PI*sin(PI*p(0))*sin(PI*p(1))*exp(p(2));
 
-  Point<3> normal = p;
-  normal /= p.norm();
+    Tensor<1,3> gradient;
+    gradient[0] = PI * cos(PI*p(0))*cos(PI*p(1))*exp(p(2));
+    gradient[1] = - PI * sin(PI*p(0))*sin(PI*p(1))*exp(p(2));
+    gradient[2] = sin(PI*p(0))*cos(PI*p(1))*exp(p(2));
 
-  return (- trace(hessian)
-         + 2 * (gradient * normal)
-         + (hessian * normal) * normal);
-}
+    Point<3> normal = p;
+    normal /= p.norm();
 
+    return (- trace(hessian)
+           + 2 * (gradient * normal)
+           + (hessian * normal) * normal);
+  }
 
-                                 // @sect3{Implementation of the <code>LaplaceBeltramiProblem</code> class}
-
-                                // The rest of the program is actually quite
-                                // unspectacular if you know step-4. Our
-                                // first step is to define the constructor,
-                                // setting the polynomial degree of the
-                                // finite element and mapping, and
-                                // associating the DoF handler to the
-                                // triangulation:
-template <int spacedim>
-LaplaceBeltramiProblem<spacedim>::
-LaplaceBeltramiProblem (const unsigned degree)
-               :
-               fe (degree),
-               dof_handler(triangulation),
-               mapping (degree)
-{}
-
-
-                                 // @sect4{LaplaceBeltramiProblem::make_grid_and_dofs}
-
-                                // The next step is to create the mesh,
-                                // distribute degrees of freedom, and set up
-                                // the various variables that describe the
-                                // linear system. All of these steps are
-                                // standard with the exception of how to
-                                // create a mesh that describes a surface. We
-                                // could generate a mesh for the domain we
-                                // are interested in, generate a
-                                // triangulation using a mesh generator, and
-                                // read it in using the GridIn class. Or, as
-                                // we do here, we generate the mesh using the
-                                // facilities in the GridGenerator namespace.
-                                //
-                                // In particular, what we're going to do is
-                                // this (enclosed between the set of braces
-                                // below): we generate a
-                                // <code>spacedim</code> dimensional mesh for
-                                // the half disk (in 2d) or half ball (in
-                                // 3d), using the
-                                // GridGenerator::half_hyper_ball
-                                // function. This function sets the boundary
-                                // indicators of all faces on the outside of
-                                // the boundary to zero for the ones located
-                                // on the perimeter of the disk/ball, and one
-                                // on the straight part that splits the full
-                                // disk/ball into two halves. The next step
-                                // is the main point: The
-                                // GridTools::extract_boundary_mesh function
-                                // creates a mesh that consists of those
-                                // cells that are the faces of the previous
-                                // mesh, i.e. it describes the <i>surface</i>
-                                // cells of the original (volume)
-                                // mesh. However, we do not want all faces:
-                                // only those on the perimeter of the disk or
-                                // ball which carry boundary indicator zero;
-                                // we can select these cells using a set of
-                                // boundary indicators that we pass to
-                                // GridTools::extract_boundary_mesh.
-                                //
-                                // There is one point that needs to be
-                                // mentioned. In order to refine a surface
-                                // mesh appropriately if the manifold is
-                                // curved (similarly to refining the faces of
-                                // cells that are adjacent to a curved
-                                // boundary), the triangulation has to have
-                                // an object attached to it that described
-                                // where new vertices should be located. If
-                                // you don't attach such a boundary object,
-                                // they will be located halfway between
-                                // existing vertices; this is appropriate if
-                                // you have a domain with straight boundaries
-                                // (e.g. a polygon) but not when, as here,
-                                // the manifold has curvature. So for things
-                                // to work properly, we need to attach a
-                                // manifold object to our (surface)
-                                // triangulation. We create such an object
-                                // (with indefinite, <code>static</code>,
-                                // lifetime) at the top of the function and
-                                // attach it to the triangulation for all
-                                // cells with boundary indicator zero that
-                                // will be created henceforth.
-                                //
-                                // The final step in creating the mesh is to
-                                // refine it a number of times. The rest of
-                                // the function is the same as in previous
-                                // tutorial programs.
-template <int spacedim>
-void LaplaceBeltramiProblem<spacedim>::make_grid_and_dofs ()
-{
-  static HyperBallBoundary<dim,spacedim> surface_description;
-  triangulation.set_boundary (0, surface_description);
 
+                                  // @sect3{Implementation of the <code>LaplaceBeltramiProblem</code> class}
+
+                                  // The rest of the program is actually quite
+                                  // unspectacular if you know step-4. Our
+                                  // first step is to define the constructor,
+                                  // setting the polynomial degree of the
+                                  // finite element and mapping, and
+                                  // associating the DoF handler to the
+                                  // triangulation:
+  template <int spacedim>
+  LaplaceBeltramiProblem<spacedim>::
+  LaplaceBeltramiProblem (const unsigned degree)
+                 :
+                 fe (degree),
+                 dof_handler(triangulation),
+                 mapping (degree)
+  {}
+
+
+                                  // @sect4{LaplaceBeltramiProblem::make_grid_and_dofs}
+
+                                  // The next step is to create the mesh,
+                                  // distribute degrees of freedom, and set up
+                                  // the various variables that describe the
+                                  // linear system. All of these steps are
+                                  // standard with the exception of how to
+                                  // create a mesh that describes a surface. We
+                                  // could generate a mesh for the domain we
+                                  // are interested in, generate a
+                                  // triangulation using a mesh generator, and
+                                  // read it in using the GridIn class. Or, as
+                                  // we do here, we generate the mesh using the
+                                  // facilities in the GridGenerator namespace.
+                                  //
+                                  // In particular, what we're going to do is
+                                  // this (enclosed between the set of braces
+                                  // below): we generate a
+                                  // <code>spacedim</code> dimensional mesh for
+                                  // the half disk (in 2d) or half ball (in
+                                  // 3d), using the
+                                  // GridGenerator::half_hyper_ball
+                                  // function. This function sets the boundary
+                                  // indicators of all faces on the outside of
+                                  // the boundary to zero for the ones located
+                                  // on the perimeter of the disk/ball, and one
+                                  // on the straight part that splits the full
+                                  // disk/ball into two halves. The next step
+                                  // is the main point: The
+                                  // GridTools::extract_boundary_mesh function
+                                  // creates a mesh that consists of those
+                                  // cells that are the faces of the previous
+                                  // mesh, i.e. it describes the <i>surface</i>
+                                  // cells of the original (volume)
+                                  // mesh. However, we do not want all faces:
+                                  // only those on the perimeter of the disk or
+                                  // ball which carry boundary indicator zero;
+                                  // we can select these cells using a set of
+                                  // boundary indicators that we pass to
+                                  // GridTools::extract_boundary_mesh.
+                                  //
+                                  // There is one point that needs to be
+                                  // mentioned. In order to refine a surface
+                                  // mesh appropriately if the manifold is
+                                  // curved (similarly to refining the faces of
+                                  // cells that are adjacent to a curved
+                                  // boundary), the triangulation has to have
+                                  // an object attached to it that described
+                                  // where new vertices should be located. If
+                                  // you don't attach such a boundary object,
+                                  // they will be located halfway between
+                                  // existing vertices; this is appropriate if
+                                  // you have a domain with straight boundaries
+                                  // (e.g. a polygon) but not when, as here,
+                                  // the manifold has curvature. So for things
+                                  // to work properly, we need to attach a
+                                  // manifold object to our (surface)
+                                  // triangulation. We create such an object
+                                  // (with indefinite, <code>static</code>,
+                                  // lifetime) at the top of the function and
+                                  // attach it to the triangulation for all
+                                  // cells with boundary indicator zero that
+                                  // will be created henceforth.
+                                  //
+                                  // The final step in creating the mesh is to
+                                  // refine it a number of times. The rest of
+                                  // the function is the same as in previous
+                                  // tutorial programs.
+  template <int spacedim>
+  void LaplaceBeltramiProblem<spacedim>::make_grid_and_dofs ()
   {
-    Triangulation<spacedim> volume_mesh;
-    GridGenerator::half_hyper_ball(volume_mesh);
+    static HyperBallBoundary<dim,spacedim> surface_description;
+    triangulation.set_boundary (0, surface_description);
 
-    std::set<unsigned char> boundary_ids;
-    boundary_ids.insert (0);
+    {
+      Triangulation<spacedim> volume_mesh;
+      GridGenerator::half_hyper_ball(volume_mesh);
 
-    GridTools::extract_boundary_mesh (volume_mesh, triangulation,
-                                     boundary_ids);
-  }
-  triangulation.refine_global(4);
+      std::set<unsigned char> boundary_ids;
+      boundary_ids.insert (0);
 
-  std::cout << "Surface mesh has " << triangulation.n_active_cells()
-           << " cells."
-           << std::endl;
+      GridTools::extract_boundary_mesh (volume_mesh, triangulation,
+                                       boundary_ids);
+    }
+    triangulation.refine_global(4);
 
-  dof_handler.distribute_dofs (fe);
+    std::cout << "Surface mesh has " << triangulation.n_active_cells()
+             << " cells."
+             << std::endl;
 
-  std::cout << "Surface mesh has " << dof_handler.n_dofs()
-           << " degrees of freedom."
-           << std::endl;
+    dof_handler.distribute_dofs (fe);
 
-  CompressedSparsityPattern csp (dof_handler.n_dofs(), dof_handler.n_dofs());
-  DoFTools::make_sparsity_pattern (dof_handler, csp);
-  sparsity_pattern.copy_from (csp);
+    std::cout << "Surface mesh has " << dof_handler.n_dofs()
+             << " degrees of freedom."
+             << std::endl;
 
-  system_matrix.reinit (sparsity_pattern);
+    CompressedSparsityPattern csp (dof_handler.n_dofs(), dof_handler.n_dofs());
+    DoFTools::make_sparsity_pattern (dof_handler, csp);
+    sparsity_pattern.copy_from (csp);
 
-  solution.reinit (dof_handler.n_dofs());
-  system_rhs.reinit (dof_handler.n_dofs());
-}
+    system_matrix.reinit (sparsity_pattern);
 
+    solution.reinit (dof_handler.n_dofs());
+    system_rhs.reinit (dof_handler.n_dofs());
+  }
 
-                                 // @sect4{LaplaceBeltramiProblem::assemble_system}
-
-                                // The following is the central function of
-                                // this program, assembling the matrix that
-                                // corresponds to the surface Laplacian
-                                // (Laplace-Beltrami operator). Maybe
-                                // surprisingly, it actually looks exactly
-                                // the same as for the regular Laplace
-                                // operator discussed in, for example,
-                                // step-4. The key is that the
-                                // FEValues::shape_gradient function does the
-                                // magic: It returns the surface gradient
-                                // $\nabla_K \phi_i(x_q)$ of the $i$th shape
-                                // function at the $q$th quadrature
-                                // point. The rest then does not need any
-                                // changes either:
-template <int spacedim>
-void LaplaceBeltramiProblem<spacedim>::assemble_system ()
-{
-  system_matrix = 0;
-  system_rhs = 0;
 
-  const QGauss<dim>  quadrature_formula(2*fe.degree);
-  FEValues<dim,spacedim> fe_values (mapping, fe, quadrature_formula,
-                                   update_values              |
-                                   update_gradients           |
-                                   update_quadrature_points   |
-                                   update_JxW_values);
+                                  // @sect4{LaplaceBeltramiProblem::assemble_system}
+
+                                  // The following is the central function of
+                                  // this program, assembling the matrix that
+                                  // corresponds to the surface Laplacian
+                                  // (Laplace-Beltrami operator). Maybe
+                                  // surprisingly, it actually looks exactly
+                                  // the same as for the regular Laplace
+                                  // operator discussed in, for example,
+                                  // step-4. The key is that the
+                                  // FEValues::shape_gradient function does the
+                                  // magic: It returns the surface gradient
+                                  // $\nabla_K \phi_i(x_q)$ of the $i$th shape
+                                  // function at the $q$th quadrature
+                                  // point. The rest then does not need any
+                                  // changes either:
+  template <int spacedim>
+  void LaplaceBeltramiProblem<spacedim>::assemble_system ()
+  {
+    system_matrix = 0;
+    system_rhs = 0;
 
-  const unsigned int        dofs_per_cell = fe.dofs_per_cell;
-  const unsigned int        n_q_points    = quadrature_formula.size();
+    const QGauss<dim>  quadrature_formula(2*fe.degree);
+    FEValues<dim,spacedim> fe_values (mapping, fe, quadrature_formula,
+                                     update_values              |
+                                     update_gradients           |
+                                     update_quadrature_points   |
+                                     update_JxW_values);
 
-  FullMatrix<double>        cell_matrix (dofs_per_cell, dofs_per_cell);
-  Vector<double>            cell_rhs (dofs_per_cell);
+    const unsigned int        dofs_per_cell = fe.dofs_per_cell;
+    const unsigned int        n_q_points    = quadrature_formula.size();
 
-  std::vector<double>       rhs_values(n_q_points);
-  std::vector<unsigned int> local_dof_indices (dofs_per_cell);
+    FullMatrix<double>        cell_matrix (dofs_per_cell, dofs_per_cell);
+    Vector<double>            cell_rhs (dofs_per_cell);
 
-  const RightHandSide<spacedim> rhs;
+    std::vector<double>       rhs_values(n_q_points);
+    std::vector<unsigned int> local_dof_indices (dofs_per_cell);
 
-  for (typename DoFHandler<dim,spacedim>::active_cell_iterator
-        cell = dof_handler.begin_active(),
-        endc = dof_handler.end();
-       cell!=endc; ++cell)
-    {
-      cell_matrix = 0;
-      cell_rhs = 0;
+    const RightHandSide<spacedim> rhs;
 
-      fe_values.reinit (cell);
+    for (typename DoFHandler<dim,spacedim>::active_cell_iterator
+          cell = dof_handler.begin_active(),
+          endc = dof_handler.end();
+        cell!=endc; ++cell)
+      {
+       cell_matrix = 0;
+       cell_rhs = 0;
 
-      rhs.value_list (fe_values.get_quadrature_points(), rhs_values);
+       fe_values.reinit (cell);
 
-      for (unsigned int i=0; i<dofs_per_cell; ++i)
-       for (unsigned int j=0; j<dofs_per_cell; ++j)
-         for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
-           cell_matrix(i,j) += fe_values.shape_grad(i,q_point) *
-                               fe_values.shape_grad(j,q_point) *
-                               fe_values.JxW(q_point);
-
-      for (unsigned int i=0; i<dofs_per_cell; ++i)
-       for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
-         cell_rhs(i) += fe_values.shape_value(i,q_point) *
-                        rhs_values[q_point]*
-                        fe_values.JxW(q_point);
-
-      cell->get_dof_indices (local_dof_indices);
-      for (unsigned int i=0; i<dofs_per_cell; ++i)
-       {
-         for (unsigned int j=0; j<dofs_per_cell; ++j)
-           system_matrix.add (local_dof_indices[i],
-                              local_dof_indices[j],
-                              cell_matrix(i,j));
+       rhs.value_list (fe_values.get_quadrature_points(), rhs_values);
 
-         system_rhs(local_dof_indices[i]) += cell_rhs(i);
-       }
-    }
+       for (unsigned int i=0; i<dofs_per_cell; ++i)
+         for (unsigned int j=0; j<dofs_per_cell; ++j)
+           for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
+             cell_matrix(i,j) += fe_values.shape_grad(i,q_point) *
+                                 fe_values.shape_grad(j,q_point) *
+                                 fe_values.JxW(q_point);
 
-  std::map<unsigned int,double> boundary_values;
-  VectorTools::interpolate_boundary_values (mapping,
-                                           dof_handler,
-                                           0,
-                                           Solution<spacedim>(),
-                                           boundary_values);
-
-  MatrixTools::apply_boundary_values (boundary_values,
-                                     system_matrix,
-                                     solution,
-                                     system_rhs,false);
-}
+       for (unsigned int i=0; i<dofs_per_cell; ++i)
+         for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
+           cell_rhs(i) += fe_values.shape_value(i,q_point) *
+                          rhs_values[q_point]*
+                          fe_values.JxW(q_point);
+
+       cell->get_dof_indices (local_dof_indices);
+       for (unsigned int i=0; i<dofs_per_cell; ++i)
+         {
+           for (unsigned int j=0; j<dofs_per_cell; ++j)
+             system_matrix.add (local_dof_indices[i],
+                                local_dof_indices[j],
+                                cell_matrix(i,j));
+
+           system_rhs(local_dof_indices[i]) += cell_rhs(i);
+         }
+      }
+
+    std::map<unsigned int,double> boundary_values;
+    VectorTools::interpolate_boundary_values (mapping,
+                                             dof_handler,
+                                             0,
+                                             Solution<spacedim>(),
+                                             boundary_values);
+
+    MatrixTools::apply_boundary_values (boundary_values,
+                                       system_matrix,
+                                       solution,
+                                       system_rhs,false);
+  }
 
 
 
-                                 // @sect4{LaplaceBeltramiProblem::solve}
+                                  // @sect4{LaplaceBeltramiProblem::solve}
 
-                                // The next function is the one that solves
-                                // the linear system. Here, too, no changes
-                                // are necessary:
-template <int spacedim>
-void LaplaceBeltramiProblem<spacedim>::solve ()
-{
-  SolverControl solver_control (solution.size(),
-                               1e-7 * system_rhs.l2_norm());
-  SolverCG<>    cg (solver_control);
+                                  // The next function is the one that solves
+                                  // the linear system. Here, too, no changes
+                                  // are necessary:
+  template <int spacedim>
+  void LaplaceBeltramiProblem<spacedim>::solve ()
+  {
+    SolverControl solver_control (solution.size(),
+                                 1e-7 * system_rhs.l2_norm());
+    SolverCG<>    cg (solver_control);
 
-  PreconditionSSOR<> preconditioner;
-  preconditioner.initialize(system_matrix, 1.2);
+    PreconditionSSOR<> preconditioner;
+    preconditioner.initialize(system_matrix, 1.2);
 
-  cg.solve (system_matrix, solution, system_rhs,
-           preconditioner);
-}
+    cg.solve (system_matrix, solution, system_rhs,
+             preconditioner);
+  }
 
 
 
-                                 // @sect4{LaplaceBeltramiProblem::output_result}
-
-                                // This is the function that generates
-                                // graphical output from the solution. Most
-                                // of it is boilerplate code, but there are
-                                // two points worth pointing out:
-                                //
-                                // - The DataOut::add_data_vector function
-                                //   can take two kinds of vectors: Either
-                                //   vectors that have one value per degree
-                                //   of freedom defined by the DoFHandler
-                                //   object previously attached via
-                                //   DataOut::attach_dof_handler; and vectors
-                                //   that have one value for each cell of the
-                                //   triangulation, for example to output
-                                //   estimated errors for each
-                                //   cell. Typically, the DataOut class knows
-                                //   to tell these two kinds of vectors
-                                //   apart: there are almost always more
-                                //   degrees of freedom than cells, so we can
-                                //   differentiate by the two kinds looking
-                                //   at the length of a vector. We could do
-                                //   the same here, but only because we got
-                                //   lucky: we use a half sphere. If we had
-                                //   used the whole sphere as domain and
-                                //   $Q_1$ elements, we would have the same
-                                //   number of cells as vertices and
-                                //   consequently the two kinds of vectors
-                                //   would have the same number of
-                                //   elements. To avoid the resulting
-                                //   confusion, we have to tell the
-                                //   DataOut::add_data_vector function which
-                                //   kind of vector we have: DoF data. This
-                                //   is what the third argument to the
-                                //   function does.
-                                // - The DataOut::build_patches function can
-                                //   generate output that subdivides each
-                                //   cell so that visualization programs can
-                                //   resolve curved manifolds or higher
-                                //   polynomial degree shape functions
-                                //   better. We here subdivide each element
-                                //   in each coordinate direction as many
-                                //   times as the polynomial degree of the
-                                //   finite element in use.
-template <int spacedim>
-void LaplaceBeltramiProblem<spacedim>::output_results () const
-{
-  DataOut<dim,DoFHandler<dim,spacedim> > data_out;
-  data_out.attach_dof_handler (dof_handler);
-  data_out.add_data_vector (solution,
-                           "solution",
-                           DataOut<dim,DoFHandler<dim,spacedim> >::type_dof_data);
-  data_out.build_patches (mapping,
-                         mapping.get_degree());
-
-  std::string filename ("solution-");
-  filename += ('0'+spacedim);filename += "d.vtk";
-  std::ofstream output (filename.c_str());
-  data_out.write_vtk (output);
-}
+                                  // @sect4{LaplaceBeltramiProblem::output_result}
+
+                                  // This is the function that generates
+                                  // graphical output from the solution. Most
+                                  // of it is boilerplate code, but there are
+                                  // two points worth pointing out:
+                                  //
+                                  // - The DataOut::add_data_vector function
+                                  //   can take two kinds of vectors: Either
+                                  //   vectors that have one value per degree
+                                  //   of freedom defined by the DoFHandler
+                                  //   object previously attached via
+                                  //   DataOut::attach_dof_handler; and vectors
+                                  //   that have one value for each cell of the
+                                  //   triangulation, for example to output
+                                  //   estimated errors for each
+                                  //   cell. Typically, the DataOut class knows
+                                  //   to tell these two kinds of vectors
+                                  //   apart: there are almost always more
+                                  //   degrees of freedom than cells, so we can
+                                  //   differentiate by the two kinds looking
+                                  //   at the length of a vector. We could do
+                                  //   the same here, but only because we got
+                                  //   lucky: we use a half sphere. If we had
+                                  //   used the whole sphere as domain and
+                                  //   $Q_1$ elements, we would have the same
+                                  //   number of cells as vertices and
+                                  //   consequently the two kinds of vectors
+                                  //   would have the same number of
+                                  //   elements. To avoid the resulting
+                                  //   confusion, we have to tell the
+                                  //   DataOut::add_data_vector function which
+                                  //   kind of vector we have: DoF data. This
+                                  //   is what the third argument to the
+                                  //   function does.
+                                  // - The DataOut::build_patches function can
+                                  //   generate output that subdivides each
+                                  //   cell so that visualization programs can
+                                  //   resolve curved manifolds or higher
+                                  //   polynomial degree shape functions
+                                  //   better. We here subdivide each element
+                                  //   in each coordinate direction as many
+                                  //   times as the polynomial degree of the
+                                  //   finite element in use.
+  template <int spacedim>
+  void LaplaceBeltramiProblem<spacedim>::output_results () const
+  {
+    DataOut<dim,DoFHandler<dim,spacedim> > data_out;
+    data_out.attach_dof_handler (dof_handler);
+    data_out.add_data_vector (solution,
+                             "solution",
+                             DataOut<dim,DoFHandler<dim,spacedim> >::type_dof_data);
+    data_out.build_patches (mapping,
+                           mapping.get_degree());
+
+    std::string filename ("solution-");
+    filename += ('0'+spacedim);filename += "d.vtk";
+    std::ofstream output (filename.c_str());
+    data_out.write_vtk (output);
+  }
 
 
 
-                                 // @sect4{LaplaceBeltramiProblem::compute_error}
+                                  // @sect4{LaplaceBeltramiProblem::compute_error}
 
-                                // This is the last piece of functionality:
-                                // we want to compute the error in the
-                                // numerical solution. It is a verbatim copy
-                                // of the code previously shown and discussed
-                                // in step-7. As mentioned in the
-                                // introduction, the <code>Solution</code>
-                                // class provides the (tangential) gradient
-                                // of the solution. To avoid evaluating the
-                                // error only a superconvergence points, we
-                                // choose a quadrature rule of sufficiently
-                                // high order.
-template <int spacedim>
-void LaplaceBeltramiProblem<spacedim>::compute_error () const
-{
-  Vector<float> difference_per_cell (triangulation.n_active_cells());
-  VectorTools::integrate_difference (mapping, dof_handler, solution,
-                                    Solution<spacedim>(),
-                                    difference_per_cell,
-                                    QGauss<dim>(2*fe.degree+1),
-                                    VectorTools::H1_norm);
-
-  std::cout << "H1 error = "
-           << difference_per_cell.l2_norm()
-           << std::endl;
-}
+                                  // This is the last piece of functionality:
+                                  // we want to compute the error in the
+                                  // numerical solution. It is a verbatim copy
+                                  // of the code previously shown and discussed
+                                  // in step-7. As mentioned in the
+                                  // introduction, the <code>Solution</code>
+                                  // class provides the (tangential) gradient
+                                  // of the solution. To avoid evaluating the
+                                  // error only a superconvergence points, we
+                                  // choose a quadrature rule of sufficiently
+                                  // high order.
+  template <int spacedim>
+  void LaplaceBeltramiProblem<spacedim>::compute_error () const
+  {
+    Vector<float> difference_per_cell (triangulation.n_active_cells());
+    VectorTools::integrate_difference (mapping, dof_handler, solution,
+                                      Solution<spacedim>(),
+                                      difference_per_cell,
+                                      QGauss<dim>(2*fe.degree+1),
+                                      VectorTools::H1_norm);
+
+    std::cout << "H1 error = "
+             << difference_per_cell.l2_norm()
+             << std::endl;
+  }
 
 
 
-                                 // @sect4{LaplaceBeltramiProblem::run}
+                                  // @sect4{LaplaceBeltramiProblem::run}
 
-                                // The last function provides the top-level
-                                // logic. Its contents are self-explanatory:
-template <int spacedim>
-void LaplaceBeltramiProblem<spacedim>::run ()
-{
-  make_grid_and_dofs();
-  assemble_system ();
-  solve ();
-  output_results ();
-  compute_error ();
+                                  // The last function provides the top-level
+                                  // logic. Its contents are self-explanatory:
+  template <int spacedim>
+  void LaplaceBeltramiProblem<spacedim>::run ()
+  {
+    make_grid_and_dofs();
+    assemble_system ();
+    solve ();
+    output_results ();
+    compute_error ();
+  }
 }
 
 
@@ -637,6 +641,9 @@ int main ()
 {
   try
     {
+      using namespace dealii;
+      using namespace Step38;
+
       deallog.depth_console (0);
 
       LaplaceBeltramiProblem<3> laplace_beltrami;
index 330385f37949a0883c7c8bef55f174262555c2d8..687e11fb83867c25cb1df5742efd029adc2ca616 100644 (file)
                                 // order to save typing, we tell the
                                 // compiler to search names in there
                                 // as well.
-using namespace dealii;
-
-                                // This is the function we use to set
-                                // the boundary values and also the
-                                // exact solution we compare to.
-Functions::SlitSingularityFunction<2> exact_solution;
-
-                                // @sect3{The local integrators}
-
-                                // MeshWorker separates local
-                                // integration from the loops over
-                                // cells and faces. Thus, we have to
-                                // write local integration classes
-                                // for generating matrices, the right
-                                // hand side and the error
-                                // estimator.
-
-                                // All these classes have the same
-                                // three functions for integrating
-                                // over cells, boundary faces and
-                                // interior faces, respectively. All
-                                // the information needed for the
-                                // local integration is provided by
-                                // MeshWorker::IntegrationInfo<dim>. Note
-                                // that the signature of the functions cannot
-                                // be changed, because it is expected
-                                // by MeshWorker::integration_loop().
-
-                                // The first class defining local
-                                // integrators is responsible for
-                                // computing cell and face
-                                // matrices. It is used to assemble
-                                // the global matrix as well as the
-                                // level matrices.
-template <int dim>
-class MatrixIntegrator : public Subscriptor
-{
-  public:
-    static void cell(MeshWorker::DoFInfo<dim>& dinfo,
-                    typename MeshWorker::IntegrationInfo<dim>& info);
-    static void boundary(MeshWorker::DoFInfo<dim>& dinfo,
-                    typename MeshWorker::IntegrationInfo<dim>& info);
-    static void face(MeshWorker::DoFInfo<dim>& dinfo1,
-                    MeshWorker::DoFInfo<dim>& dinfo2,
-                    typename MeshWorker::IntegrationInfo<dim>& info1,
-                    typename MeshWorker::IntegrationInfo<dim>& info2);
-};
-
-
-                                // On each cell, we integrate the
-                                // Dirichlet form. We use the library
-                                // of ready made integrals in
-                                // LocalIntegrators to avoid writing
-                                // these loops ourselves. Similarly,
-                                // we implement Nitsche boundary
-                                // conditions and the interior
-                                // penalty fluxes between cells.
-                                //
-                                // The boundary und flux terms need a
-                                // penalty parameter, which should be
-                                // adjusted to the cell size and the
-                                // polynomial degree. A safe choice
-                                // of this parameter for constant
-                                // coefficients can be found in
-                                // LocalIntegrators::Laplace::compute_penalty()
-                                // and we use this below.
-template <int dim>
-void MatrixIntegrator<dim>::cell(
-  MeshWorker::DoFInfo<dim>& dinfo,
-  typename MeshWorker::IntegrationInfo<dim>& info)
-{
-  LocalIntegrators::Laplace::cell_matrix(dinfo.matrix(0,false).matrix, info.fe_values());
-}
-
-
-template <int dim>
-void MatrixIntegrator<dim>::boundary(
-  MeshWorker::DoFInfo<dim>& dinfo,
-  typename MeshWorker::IntegrationInfo<dim>& info)
-{
-  const unsigned int deg = info.fe_values(0).get_fe().tensor_degree();
-  LocalIntegrators::Laplace::nitsche_matrix(
-    dinfo.matrix(0,false).matrix, info.fe_values(0),
-    LocalIntegrators::Laplace::compute_penalty(dinfo, dinfo, deg, deg));
-}
-
-                                // Interior faces use the interior
-                                // penalty method
-template <int dim>
-void MatrixIntegrator<dim>::face(
-  MeshWorker::DoFInfo<dim>& dinfo1,
-  MeshWorker::DoFInfo<dim>& dinfo2,
-  typename MeshWorker::IntegrationInfo<dim>& info1,
-  typename MeshWorker::IntegrationInfo<dim>& info2)
-{
-  const unsigned int deg = info1.fe_values(0).get_fe().tensor_degree();
-  LocalIntegrators::Laplace::ip_matrix(
-    dinfo1.matrix(0,false).matrix, dinfo1.matrix(0,true).matrix, 
-    dinfo2.matrix(0,true).matrix, dinfo2.matrix(0,false).matrix,
-    info1.fe_values(0), info2.fe_values(0),
-    LocalIntegrators::Laplace::compute_penalty(dinfo1, dinfo2, deg, deg));
-}
-
-                                // The second local integrator builds
-                                // the right hand side. In our
-                                // example, the right hand side
-                                // function is zero, such that only
-                                // the boundary condition is set here
-                                // in weak form.
-template <int dim>
-class RHSIntegrator : public Subscriptor
-{
-  public:
-    static void cell(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
-    static void boundary(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
-    static void face(MeshWorker::DoFInfo<dim>& dinfo1,
-                    MeshWorker::DoFInfo<dim>& dinfo2,
-                    typename MeshWorker::IntegrationInfo<dim>& info1,
-                    typename MeshWorker::IntegrationInfo<dim>& info2);
-};
-
-
-template <int dim>
-void RHSIntegrator<dim>::cell(MeshWorker::DoFInfo<dim>&, typename MeshWorker::IntegrationInfo<dim>&)
-{}
-
-
-template <int dim>
-void RHSIntegrator<dim>::boundary(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info)
-{
-  const FEValuesBase<dim>& fe = info.fe_values();
-  Vector<double>& local_vector = dinfo.vector(0).block(0);
-  
-  std::vector<double> boundary_values(fe.n_quadrature_points);
-  exact_solution.value_list(fe.get_quadrature_points(), boundary_values);
-  
-  const unsigned int deg = fe.get_fe().tensor_degree();
-  const double penalty = 2. * deg * (deg+1) * dinfo.face->measure() / dinfo.cell->measure();
-  
-  for (unsigned k=0;k<fe.n_quadrature_points;++k)
-    for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
-      local_vector(i) += (- fe.shape_value(i,k) * penalty * boundary_values[k]
-                         + (fe.normal_vector(k) * fe.shape_grad(i,k)) * boundary_values[k])
-                        * fe.JxW(k);
-}
-
-
-template <int dim>
-void RHSIntegrator<dim>::face(MeshWorker::DoFInfo<dim>&,
-                             MeshWorker::DoFInfo<dim>&,
-                             typename MeshWorker::IntegrationInfo<dim>&,
-                             typename MeshWorker::IntegrationInfo<dim>&)
-{}
-
-
-                                // The third local integrator is
-                                // responsible for the contributions
-                                // to the error estimate. This is the
-                                // standard energy estimator due to
-                                // Karakashian and Pascal (2003).
-template <int dim>
-class Estimator : public Subscriptor
-{
-  public:
-    static void cell(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
-    static void boundary(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
-    static void face(MeshWorker::DoFInfo<dim>& dinfo1,
-                    MeshWorker::DoFInfo<dim>& dinfo2,
-                    typename MeshWorker::IntegrationInfo<dim>& info1,
-                    typename MeshWorker::IntegrationInfo<dim>& info2);
-};
-
-
-                                // The cell contribution is the
-                                // Laplacian of the discrete
-                                // solution, since the right hand
-                                // side is zero.
-template <int dim>
-void Estimator<dim>::cell(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info)
-{
-  const FEValuesBase<dim>& fe = info.fe_values();
-  
-  const std::vector<Tensor<2,dim> >& DDuh = info.hessians[0][0];
-  for (unsigned k=0;k<fe.n_quadrature_points;++k)
-    {
-      const double t = dinfo.cell->diameter() * trace(DDuh[k]);
-      dinfo.value(0) +=  t*t * fe.JxW(k);
-    }
-  dinfo.value(0) = std::sqrt(dinfo.value(0));
-}
-
-                                // At the boundary, we use simply a
-                                // weighted form of the boundary
-                                // residual, namely the norm of the
-                                // difference between the finite
-                                // element solution and the correct
-                                // boundary condition.
-template <int dim>
-void Estimator<dim>::boundary(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info)
-{
-  const FEValuesBase<dim>& fe = info.fe_values();
-  
-  std::vector<double> boundary_values(fe.n_quadrature_points);
-  exact_solution.value_list(fe.get_quadrature_points(), boundary_values);
-  
-  const std::vector<double>& uh = info.values[0][0];
-  
-  const unsigned int deg = fe.get_fe().tensor_degree();
-  const double penalty = 2. * deg * (deg+1) * dinfo.face->measure() / dinfo.cell->measure();
-  
-  for (unsigned k=0;k<fe.n_quadrature_points;++k)
-    dinfo.value(0) += penalty * (boundary_values[k] - uh[k]) * (boundary_values[k] - uh[k])
-                     * fe.JxW(k);
-  dinfo.value(0) = std::sqrt(dinfo.value(0));  
-}
-
-
-                                // Finally, on interior faces, the
-                                // estimator consists of the jumps of
-                                // the solution and its normal
-                                // derivative, weighted appropriately.
-template <int dim>
-void Estimator<dim>::face(MeshWorker::DoFInfo<dim>& dinfo1,
-                         MeshWorker::DoFInfo<dim>& dinfo2,
-                         typename MeshWorker::IntegrationInfo<dim>& info1,
-                         typename MeshWorker::IntegrationInfo<dim>& info2)
-{
-  const FEValuesBase<dim>& fe = info1.fe_values();
-  const std::vector<double>& uh1 = info1.values[0][0];
-  const std::vector<double>& uh2 = info2.values[0][0];
-  const std::vector<Tensor<1,dim> >& Duh1 = info1.gradients[0][0];
-  const std::vector<Tensor<1,dim> >& Duh2 = info2.gradients[0][0];
-  
-  const unsigned int deg = fe.get_fe().tensor_degree();
-  const double penalty1 = deg * (deg+1) * dinfo1.face->measure() / dinfo1.cell->measure();
-  const double penalty2 = deg * (deg+1) * dinfo2.face->measure() / dinfo2.cell->measure();
-  const double penalty = penalty1 + penalty2;
-  const double h = dinfo1.face->measure();
-  
-  for (unsigned k=0;k<fe.n_quadrature_points;++k)
-    {
-      double diff1 = uh1[k] - uh2[k];
-      double diff2 = fe.normal_vector(k) * Duh1[k] - fe.normal_vector(k) * Duh2[k];
-      dinfo1.value(0) += (penalty * diff1*diff1 + h * diff2*diff2)
-                   * fe.JxW(k);
-    }
-  dinfo1.value(0) = std::sqrt(dinfo1.value(0));
-  dinfo2.value(0) = dinfo1.value(0);
-}
-
-                                // Finally we have an integrator for
-                                // the error. Since the energy norm
-                                // for discontinuous Galerkin
-                                // problems not only involves the
-                                // difference of the gradient inside
-                                // the cells, but also the jump terms
-                                // across faces and at the boundary,
-                                // we cannot just use
-                                // VectorTools::integrate_difference().
-                                // Instead, we use the MeshWorker
-                                // interface to compute the error
-                                // ourselves.
-
-                                // There are several different ways
-                                // to define this energy norm, but
-                                // all of them are equivalent to each
-                                // other uniformly with mesh size
-                                // (some not uniformly with
-                                // polynomial degree). Here, we
-                                // choose
-                                // @f[
-                                // \|u\|_{1,h} = \sum_{K\in \mathbb
-                                // T_h} \|\nabla u\|_K^2
-                                // + \sum_{F \in F_h^i}
-                                // 4\sigma_F\|\{\!\{ u \mathbf
-                                // n\}\!\}\|^2_F
-                                // + \sum_{F \in F_h^b} 2\sigma_F\|u\|^2_F
-                                // @f]
-
-template <int dim>
-class ErrorIntegrator : public Subscriptor
-{
-  public:
-    static void cell(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
-    static void boundary(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
-    static void face(MeshWorker::DoFInfo<dim>& dinfo1,
-                    MeshWorker::DoFInfo<dim>& dinfo2,
-                    typename MeshWorker::IntegrationInfo<dim>& info1,
-                    typename MeshWorker::IntegrationInfo<dim>& info2);
-};
-
-                                // Here we have the integration on
-                                // cells. There is currently no good
-                                // interfce in MeshWorker that would
-                                // allow us to access values of
-                                // regular functions in the
-                                // quadrature points. Thus, we have
-                                // to create the vectors for the
-                                // exact function's values and
-                                // gradients inside the cell
-                                // integrator. After that, everything
-                                // is as before and we just add up
-                                // the squares of the differences.
-
-                                // Additionally to computing the error
-                                // in the energy norm, we use the
-                                // capability of the mesh worker to
-                                // compute two functionals at the
-                                // same time and compute the
-                                // <i>L<sup>2</sup></i>-error in the
-                                // same loop. Obviously, this one
-                                // does not have any jump terms and
-                                // only appears in the integration on
-                                // cells.
-template <int dim>
-void ErrorIntegrator<dim>::cell(
-  MeshWorker::DoFInfo<dim>& dinfo,
-  typename MeshWorker::IntegrationInfo<dim>& info)
-{
-  const FEValuesBase<dim>& fe = info.fe_values();
-  std::vector<Tensor<1,dim> > exact_gradients(fe.n_quadrature_points);
-  std::vector<double> exact_values(fe.n_quadrature_points);
-  
-  exact_solution.gradient_list(fe.get_quadrature_points(), exact_gradients);
-  exact_solution.value_list(fe.get_quadrature_points(), exact_values);
-  
-  const std::vector<Tensor<1,dim> >& Duh = info.gradients[0][0];
-  const std::vector<double>& uh = info.values[0][0];
-
-  for (unsigned k=0;k<fe.n_quadrature_points;++k)
-    {
-      double sum = 0;
-      for (unsigned int d=0;d<dim;++d)
-       {
-         const double diff = exact_gradients[k][d] - Duh[k][d];
-         sum += diff*diff;
-       }
-      const double diff = exact_values[k] - uh[k];
-      dinfo.value(0) +=  sum * fe.JxW(k);
-      dinfo.value(1) +=  diff*diff * fe.JxW(k);
-    }
-  dinfo.value(0) = std::sqrt(dinfo.value(0));
-  dinfo.value(1) = std::sqrt(dinfo.value(1));
-}
-
-
-template <int dim>
-void ErrorIntegrator<dim>::boundary(
-  MeshWorker::DoFInfo<dim>& dinfo,
-  typename MeshWorker::IntegrationInfo<dim>& info)
-{
-  const FEValuesBase<dim>& fe = info.fe_values();
-  
-  std::vector<double> exact_values(fe.n_quadrature_points);
-  exact_solution.value_list(fe.get_quadrature_points(), exact_values);
-  
-  const std::vector<double>& uh = info.values[0][0];
-  
-  const unsigned int deg = fe.get_fe().tensor_degree();
-  const double penalty = 2. * deg * (deg+1) * dinfo.face->measure() / dinfo.cell->measure();
-  
-  for (unsigned k=0;k<fe.n_quadrature_points;++k)
-    {
-      const double diff = exact_values[k] - uh[k];
-      dinfo.value(0) += penalty * diff * diff * fe.JxW(k);
-    }
-  dinfo.value(0) = std::sqrt(dinfo.value(0));  
-}
-
-
-template <int dim>
-void ErrorIntegrator<dim>::face(
-  MeshWorker::DoFInfo<dim>& dinfo1,
-  MeshWorker::DoFInfo<dim>& dinfo2,
-  typename MeshWorker::IntegrationInfo<dim>& info1,
-  typename MeshWorker::IntegrationInfo<dim>& info2)
-{
-  const FEValuesBase<dim>& fe = info1.fe_values();
-  const std::vector<double>& uh1 = info1.values[0][0];
-  const std::vector<double>& uh2 = info2.values[0][0];
-  
-  const unsigned int deg = fe.get_fe().tensor_degree();
-  const double penalty1 = deg * (deg+1) * dinfo1.face->measure() / dinfo1.cell->measure();
-  const double penalty2 = deg * (deg+1) * dinfo2.face->measure() / dinfo2.cell->measure();
-  const double penalty = penalty1 + penalty2;
-  
-  for (unsigned k=0;k<fe.n_quadrature_points;++k)
-    {
-      double diff = uh1[k] - uh2[k];
-      dinfo1.value(0) += (penalty * diff*diff)
-                        * fe.JxW(k);
-    }
-  dinfo1.value(0) = std::sqrt(dinfo1.value(0));
-  dinfo2.value(0) = dinfo1.value(0);
-}
-
-
-
-                                // @sect3{The main class}
-
-                                // This class does the main job, like
-                                // in previous examples. For a
-                                // description of the functions
-                                // declared here, please refer to
-                                // the implementation below.
-template <int dim>
-class Step39
-{
-  public:
-    typedef MeshWorker::IntegrationInfo<dim> CellInfo;
-    
-    Step39(const FiniteElement<dim>& fe);
-
-    void run(unsigned int n_steps);
-    
-  private:
-    void setup_system ();
-    void assemble_matrix ();
-    void assemble_mg_matrix ();
-    void assemble_right_hand_side ();
-    void error ();
-    double estimate ();
-    void solve ();
-    void output_results (const unsigned int cycle) const;
-
-                                    // The member objects related to
-                                    // the discretization are here.
-    Triangulation<dim>        triangulation;
-    const MappingQ1<dim>      mapping;
-    const FiniteElement<dim>& fe;
-    MGDoFHandler<dim>         mg_dof_handler;
-    DoFHandler<dim>&          dof_handler;
-
-                                    // Then, we have the matrices and
-                                    // vectors related to the global
-                                    // discrete system.
-    SparsityPattern      sparsity;
-    SparseMatrix<double> matrix;
-    Vector<double>       solution;
-    Vector<double>       right_hand_side;
-    BlockVector<double>  estimates;
-
-                                    // Finally, we have a group of
-                                    // sparsity patterns and sparse
-                                    // matrices related to the
-                                    // multilevel preconditioner.
-                                    // First, we have a level matrix
-                                    // and its sparsity pattern.
-    MGLevelObject<SparsityPattern> mg_sparsity;
-    MGLevelObject<SparseMatrix<double> > mg_matrix;
-    
-                                    // When we perform multigrid with
-                                    // local smoothing on locally
-                                    // refined meshes, additional
-                                    // matrices are required; see
-                                    // Kanschat (2004). Here is the
-                                    // sparsity pattern for these
-                                    // edge matrices. We only need
-                                    // one, because the pattern of
-                                    // the up matrix is the
-                                    // transpose of that of the down
-                                    // matrix. Actually, we do not
-                                    // care too much about these
-                                    // details, since the MeshWorker
-                                    // is filling these matrices.
-    MGLevelObject<SparsityPattern> mg_sparsity_dg_interface;
-                                    // The flux matrix at the
-                                    // refinement edge, coupling fine
-                                    // level degrees of freedom to
-                                    // coarse level.
-    MGLevelObject<SparseMatrix<double> > mg_matrix_dg_down;
-                                    // The transpose of the flux
-                                    // matrix at the refinement edge,
-                                    // coupling coarse level degrees
-                                    // of freedom to fine level.
-    MGLevelObject<SparseMatrix<double> > mg_matrix_dg_up;
-};
-
-
-                                // The constructor simply sets up the
-                                // coarse grid and the
-                                // DoFHandler. The FiniteElement is
-                                // provided as a parameter to allow
-                                // flexibility.
-template <int dim>
-Step39<dim>::Step39(const FiniteElement<dim>& fe)
-               :
-                mapping(),
-               fe(fe),
-               mg_dof_handler(triangulation),
-               dof_handler(mg_dof_handler),
-               estimates(1)
+namespace Step39
 {
-  GridGenerator::hyper_cube_slit(triangulation, -1, 1);
-}
-
-
-                                // In this function, we set up the
-                                // dimension of the linear system and
-                                // the sparsity patterns for the
-                                // global matrix as well as the level
-                                // matrices.
-template <int dim>
-void
-Step39<dim>::setup_system()
-{
-                                  // First, we use the finite element
-                                  // to distribute degrees of
-                                  // freedom over the mesh and number
-                                  // them.
-  dof_handler.distribute_dofs(fe);
-  unsigned int n_dofs = dof_handler.n_dofs();
-                                  // Then, we already know the size
-                                  // of the vectors representing
-                                  // finite element functions.
-  solution.reinit(n_dofs);
-  right_hand_side.reinit(n_dofs);
-
-                                  // Next, we set up the sparsity
-                                  // pattern for the global
-                                  // matrix. Since we do not know the
-                                  // row sizes in advance, we first
-                                  // fill a temporary
-                                  // CompressedSparsityPattern object
-                                  // and copy it to the regular
-                                  // SparsityPattern once it is
-                                  // complete.
-  CompressedSparsityPattern c_sparsity(n_dofs);
-  DoFTools::make_flux_sparsity_pattern(dof_handler, c_sparsity);
-  sparsity.copy_from(c_sparsity);
-  matrix.reinit(sparsity);
-
-  const unsigned int n_levels = triangulation.n_levels();
-                                  // The global system is set up, now
-                                  // we attend to the level
-                                  // matrices. We resize all matrix
-                                  // objects to hold one matrix per level.
-  mg_matrix.resize(0, n_levels-1);
-  mg_matrix.clear();
-  mg_matrix_dg_up.resize(0, n_levels-1);
-  mg_matrix_dg_up.clear();
-  mg_matrix_dg_down.resize(0, n_levels-1);
-  mg_matrix_dg_down.clear();
-                                  // It is important to update the
-                                  // sparsity patterns after
-                                  // <tt>clear()</tt> was called for
-                                  // the level matrices, since the
-                                  // matrices lock the sparsity
-                                  // pattern through the Smartpointer
-                                  // ans Subscriptor mechanism.
-  mg_sparsity.resize(0, n_levels-1);
-  mg_sparsity_dg_interface.resize(0, n_levels-1);
-
-                                  // Now all objects are prepared to
-                                  // hold one sparsity pattern or
-                                  // matrix per level. What's left is
-                                  // setting up the sparsity patterns
-                                  // on each level.
-  for (unsigned int level=mg_sparsity.get_minlevel();
-       level<=mg_sparsity.get_maxlevel();++level)
-    {
-                                      // These are roughly the same
-                                      // lines as above for the
-                                      // global matrix, now for each
-                                      // level.
-      CompressedSparsityPattern c_sparsity(mg_dof_handler.n_dofs(level));      
-      MGTools::make_flux_sparsity_pattern(mg_dof_handler, c_sparsity, level);
-      mg_sparsity[level].copy_from(c_sparsity);
-      mg_matrix[level].reinit(mg_sparsity[level]);
-
-                                      // Additionally, we need to
-                                      // initialize the transfer
-                                      // matrices at the refinement
-                                      // edge between levels. They
-                                      // are stored at the index
-                                      // referring to the finer of
-                                      // the two indices, thus there
-                                      // is no such object on level
-                                      // 0.
-      if (level>0)
-       {
-         CompressedSparsityPattern ci_sparsity;
-         ci_sparsity.reinit(mg_dof_handler.n_dofs(level-1), mg_dof_handler.n_dofs(level));
-         MGTools::make_flux_sparsity_pattern_edge(mg_dof_handler, ci_sparsity, level);
-         mg_sparsity_dg_interface[level].copy_from(ci_sparsity);
-         mg_matrix_dg_up[level].reinit(mg_sparsity_dg_interface[level]);
-         mg_matrix_dg_down[level].reinit(mg_sparsity_dg_interface[level]);
-       }
-    }
-}
-
-
-                                // In this function, we assemble the
-                                // global system matrix, where by
-                                // global we indicate that this is
-                                // the matrix of the discrete system
-                                // we solve and it is covering the
-                                // whole mesh.
-template <int dim>
-void
-Step39<dim>::assemble_matrix()
-{
-                                  // First, we need t set up the
-                                  // object providing the values we
-                                  // integrate. This object contains
-                                  // all FEValues and FEFaceValues
-                                  // objects needed and also
-                                  // maintains them automatically
-                                  // such that they always point to
-                                  // the current cell. To this end,
-                                  // we need to tell it first, where
-                                  // and what to compute. Since we
-                                  // are not doing anything fancy, we
-                                  // can rely on their standard
-                                  // choice for quadrature rules.
+  using namespace dealii;
+
+                                  // This is the function we use to set
+                                  // the boundary values and also the
+                                  // exact solution we compare to.
+  Functions::SlitSingularityFunction<2> exact_solution;
+
+                                  // @sect3{The local integrators}
+
+                                  // MeshWorker separates local
+                                  // integration from the loops over
+                                  // cells and faces. Thus, we have to
+                                  // write local integration classes
+                                  // for generating matrices, the right
+                                  // hand side and the error
+                                  // estimator.
+
+                                  // All these classes have the same
+                                  // three functions for integrating
+                                  // over cells, boundary faces and
+                                  // interior faces, respectively. All
+                                  // the information needed for the
+                                  // local integration is provided by
+                                  // MeshWorker::IntegrationInfo<dim>. Note
+                                  // that the signature of the functions cannot
+                                  // be changed, because it is expected
+                                  // by MeshWorker::integration_loop().
+
+                                  // The first class defining local
+                                  // integrators is responsible for
+                                  // computing cell and face
+                                  // matrices. It is used to assemble
+                                  // the global matrix as well as the
+                                  // level matrices.
+  template <int dim>
+  class MatrixIntegrator : public Subscriptor
+  {
+    public:
+      static void cell(MeshWorker::DoFInfo<dim>& dinfo,
+                      typename MeshWorker::IntegrationInfo<dim>& info);
+      static void boundary(MeshWorker::DoFInfo<dim>& dinfo,
+                          typename MeshWorker::IntegrationInfo<dim>& info);
+      static void face(MeshWorker::DoFInfo<dim>& dinfo1,
+                      MeshWorker::DoFInfo<dim>& dinfo2,
+                      typename MeshWorker::IntegrationInfo<dim>& info1,
+                      typename MeshWorker::IntegrationInfo<dim>& info2);
+  };
+
+
+                                  // On each cell, we integrate the
+                                  // Dirichlet form. We use the library
+                                  // of ready made integrals in
+                                  // LocalIntegrators to avoid writing
+                                  // these loops ourselves. Similarly,
+                                  // we implement Nitsche boundary
+                                  // conditions and the interior
+                                  // penalty fluxes between cells.
                                   //
-                                  // Since their default update flags
-                                  // are minimal, we add what we need
-                                  // additionally, namely the values
-                                  // and gradients of shape functions
-                                  // on all objects (cells, boundary
-                                  // and interior faces). Afterwards,
-                                  // we are ready to initialize the
-                                  // container, which will create all
-                                  // necessary FEValuesBase objects
-                                  // for integration.
-  MeshWorker::IntegrationInfoBox<dim> info_box;
-  UpdateFlags update_flags = update_values | update_gradients;
-  info_box.add_update_flags_all(update_flags);
-  info_box.initialize(fe, mapping);
-
-                                  // This is the object into which we
-                                  // integrate local data. It is
-                                  // filled by the local integration
-                                  // routines in MatrixIntegrator and
-                                  // then used by the assembler to
-                                  // distribute the information into
-                                  // the global matrix.
-  MeshWorker::DoFInfo<dim> dof_info(dof_handler);
-
-                                  // Finally, we need an object that
-                                  // assembles the local matrix into
-                                  // the global matrix.
-  MeshWorker::Assembler::MatrixSimple<SparseMatrix<double> > assembler;
-  assembler.initialize(matrix);
-
-                                  // Now, we throw everything into a
-                                  // MeshWorker::loop(), which here
-                                  // traverses all active cells of
-                                  // the mesh, computes cell and face
-                                  // matrices and assembles them into
-                                  // the global matrix. We use the
-                                  // variable <tt>dof_handler</tt>
-                                  // here in order to use the global
-                                  // numbering of degrees of freedom.
-  MeshWorker::integration_loop<dim, dim>(
-    dof_handler.begin_active(), dof_handler.end(),
-    dof_info, info_box,
-    &MatrixIntegrator<dim>::cell,
-    &MatrixIntegrator<dim>::boundary,
-    &MatrixIntegrator<dim>::face,
-    assembler);
-}
-
-
-                                // Now, we do the same for the level
-                                // matrices. Not too surprisingly,
-                                // this function looks like a twin of
-                                // the previous one. Indeed, there
-                                // are only two minor differences.
-template <int dim>
-void
-Step39<dim>::assemble_mg_matrix()
-{
-  MeshWorker::IntegrationInfoBox<dim> info_box;
-  UpdateFlags update_flags = update_values | update_gradients;
-  info_box.add_update_flags_all(update_flags);
-  info_box.initialize(fe, mapping);
-
-  MeshWorker::DoFInfo<dim> dof_info(mg_dof_handler);
-
-                                  // Obviously, the assembler needs
-                                  // to be replaced by one filling
-                                  // level matrices. Note that it
-                                  // automatically fills the edge
-                                  // matrices as well.
-  MeshWorker::Assembler::MGMatrixSimple<SparseMatrix<double> > assembler;
-  assembler.initialize(mg_matrix);
-  assembler.initialize_fluxes(mg_matrix_dg_up, mg_matrix_dg_down);
-
-                                  // Here is the other difference to
-                                  // the previous function: we run
-                                  // over all cells, not only the
-                                  // active ones. And we use
-                                  // <tt>mg_dof_handler</tt>, since
-                                  // we need the degrees of freedom
-                                  // on each level, not the global
-                                  // numbering.
-  MeshWorker::integration_loop<dim, dim> (
-    mg_dof_handler.begin(), mg_dof_handler.end(),
-    dof_info, info_box,
-    &MatrixIntegrator<dim>::cell,
-    &MatrixIntegrator<dim>::boundary,
-    &MatrixIntegrator<dim>::face,
-    assembler);
-}
-
-
-                                // Here we have another clone of the
-                                // assemble function. The difference
-                                // to assembling the system matrix
-                                // consists in that we assemble a
-                                // vector here.
-template <int dim>
-void
-Step39<dim>::assemble_right_hand_side()
-{
-  MeshWorker::IntegrationInfoBox<dim> info_box;
-  UpdateFlags update_flags = update_quadrature_points | update_values | update_gradients;
-  info_box.add_update_flags_all(update_flags);
-  info_box.initialize(fe, mapping);
-  
-  MeshWorker::DoFInfo<dim> dof_info(dof_handler);
-
-                                  // Since this assembler alows us to
-                                  // fill several vectors, the
-                                  // interface is a little more
-                                  // complicated as above. The
-                                  // pointers to the vectors have to
-                                  // be stored in a NamedData
-                                  // object. While this seems to
-                                  // cause two extra lines of code
-                                  // here, it actually comes handy in
-                                  // more complex applications.
-  MeshWorker::Assembler::ResidualSimple<Vector<double> > assembler;  
-  NamedData<Vector<double>* > data;
-  Vector<double>* rhs = &right_hand_side;
-  data.add(rhs, "RHS");
-  assembler.initialize(data);
-  
-  MeshWorker::integration_loop<dim, dim>(
-    dof_handler.begin_active(), dof_handler.end(),
-    dof_info, info_box,
-    &RHSIntegrator<dim>::cell,
-    &RHSIntegrator<dim>::boundary,
-    &RHSIntegrator<dim>::face,
-    assembler);
-  
-  right_hand_side *= -1.;
-}
-
-
-                                // Now that we have coded all
-                                // functions building the discrete
-                                // linear system, it is about time
-                                // that we actually solve it.
-template <int dim>
-void
-Step39<dim>::solve()
-{
-                                  // The solver of choice is
-                                  // conjugate gradient.
-  SolverControl control(1000, 1.e-12);
-  SolverCG<Vector<double> > solver(control);
-
-                                  // Now we are setting up the
-                                  // components of the multilevel
-                                  // preconditioner. First, we need
-                                  // transfer between grid
-                                  // levels. The object we are using
-                                  // here generates sparse matrices
-                                  // for these transfers.
-  MGTransferPrebuilt<Vector<double> > mg_transfer;
-  mg_transfer.build_matrices(mg_dof_handler);
-
-                                  // Then, we need an exact solver
-                                  // for the matrix on the coarsest
-                                  // level.
-  FullMatrix<double> coarse_matrix;
-  coarse_matrix.copy_from (mg_matrix[0]);
-  MGCoarseGridHouseholder<double, Vector<double> > mg_coarse;
-  mg_coarse.initialize(coarse_matrix);
-
-                                  // While transfer and coarse grid
-                                  // solver are pretty much generic,
-                                  // more flexibility is offered for
-                                  // the smoother. First, we choose
-                                  // Gauss-Seidel as our smoothing
-                                  // method.
-  GrowingVectorMemory<Vector<double> > mem;
-  typedef PreconditionSOR<SparseMatrix<double> > RELAXATION;
-  MGSmootherRelaxation<SparseMatrix<double>, RELAXATION, Vector<double> >
-    mg_smoother(mem);
-  RELAXATION::AdditionalData smoother_data(1.);
-  mg_smoother.initialize(mg_matrix, smoother_data);
-  
-                                  // Do two smoothing steps on each
-                                  // level.
-  mg_smoother.set_steps(2);
-                                  // Since the SOR method is not
-                                  // symmetric, but we use conjugate
-                                  // gradient iteration below, here
-                                  // is a trick to make the
-                                  // multilevel preconditioner a
-                                  // symmetric operator even for
-                                  // nonsymmetric smoothers.
-  mg_smoother.set_symmetric(true);
-                                  // The smoother class optionally
-                                  // implements the variable V-cycle,
-                                  // which we do not want here.
-  mg_smoother.set_variable(false);
-
-                                  // Finally, we must wrap our
-                                  // matrices in an object having the
-                                  // required multiplication
-                                  // functions.
-  MGMatrix<SparseMatrix<double>, Vector<double> > mgmatrix(&mg_matrix);
-  MGMatrix<SparseMatrix<double>, Vector<double> > mgdown(&mg_matrix_dg_down);
-  MGMatrix<SparseMatrix<double>, Vector<double> > mgup(&mg_matrix_dg_up);
-  
-                                  // Now, we are ready to set up the
-                                  // V-cycle operator and the
-                                  // multilevel preconditioner.
-  Multigrid<Vector<double> > mg(mg_dof_handler, mgmatrix,
-                               mg_coarse, mg_transfer,
-                               mg_smoother, mg_smoother);
-                                  // Let us not forget the edge
-                                  // matrices needed because of the
-                                  // adaptive refinement.
-  mg.set_edge_flux_matrices(mgdown, mgup);
-
-                                  // After all preparations, wrap the
-                                  // Multigrid object into another
-                                  // object, which can be used as a
-                                  // regular preconditioner,
-  PreconditionMG<dim, Vector<double>,
-    MGTransferPrebuilt<Vector<double> > >
+                                  // The boundary und flux terms need a
+                                  // penalty parameter, which should be
+                                  // adjusted to the cell size and the
+                                  // polynomial degree. A safe choice
+                                  // of this parameter for constant
+                                  // coefficients can be found in
+                                  // LocalIntegrators::Laplace::compute_penalty()
+                                  // and we use this below.
+  template <int dim>
+  void MatrixIntegrator<dim>::cell(
+    MeshWorker::DoFInfo<dim>& dinfo,
+    typename MeshWorker::IntegrationInfo<dim>& info)
+  {
+    LocalIntegrators::Laplace::cell_matrix(dinfo.matrix(0,false).matrix, info.fe_values());
+  }
+
+
+  template <int dim>
+  void MatrixIntegrator<dim>::boundary(
+    MeshWorker::DoFInfo<dim>& dinfo,
+    typename MeshWorker::IntegrationInfo<dim>& info)
+  {
+    const unsigned int deg = info.fe_values(0).get_fe().tensor_degree();
+    LocalIntegrators::Laplace::nitsche_matrix(
+      dinfo.matrix(0,false).matrix, info.fe_values(0),
+      LocalIntegrators::Laplace::compute_penalty(dinfo, dinfo, deg, deg));
+  }
+
+                                  // Interior faces use the interior
+                                  // penalty method
+  template <int dim>
+  void MatrixIntegrator<dim>::face(
+    MeshWorker::DoFInfo<dim>& dinfo1,
+    MeshWorker::DoFInfo<dim>& dinfo2,
+    typename MeshWorker::IntegrationInfo<dim>& info1,
+    typename MeshWorker::IntegrationInfo<dim>& info2)
+  {
+    const unsigned int deg = info1.fe_values(0).get_fe().tensor_degree();
+    LocalIntegrators::Laplace::ip_matrix(
+      dinfo1.matrix(0,false).matrix, dinfo1.matrix(0,true).matrix,
+      dinfo2.matrix(0,true).matrix, dinfo2.matrix(0,false).matrix,
+      info1.fe_values(0), info2.fe_values(0),
+      LocalIntegrators::Laplace::compute_penalty(dinfo1, dinfo2, deg, deg));
+  }
+
+                                  // The second local integrator builds
+                                  // the right hand side. In our
+                                  // example, the right hand side
+                                  // function is zero, such that only
+                                  // the boundary condition is set here
+                                  // in weak form.
+  template <int dim>
+  class RHSIntegrator : public Subscriptor
+  {
+    public:
+      static void cell(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
+      static void boundary(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
+      static void face(MeshWorker::DoFInfo<dim>& dinfo1,
+                      MeshWorker::DoFInfo<dim>& dinfo2,
+                      typename MeshWorker::IntegrationInfo<dim>& info1,
+                      typename MeshWorker::IntegrationInfo<dim>& info2);
+  };
+
+
+  template <int dim>
+  void RHSIntegrator<dim>::cell(MeshWorker::DoFInfo<dim>&, typename MeshWorker::IntegrationInfo<dim>&)
+  {}
+
+
+  template <int dim>
+  void RHSIntegrator<dim>::boundary(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info)
+  {
+    const FEValuesBase<dim>& fe = info.fe_values();
+    Vector<double>& local_vector = dinfo.vector(0).block(0);
+
+    std::vector<double> boundary_values(fe.n_quadrature_points);
+    exact_solution.value_list(fe.get_quadrature_points(), boundary_values);
+
+    const unsigned int deg = fe.get_fe().tensor_degree();
+    const double penalty = 2. * deg * (deg+1) * dinfo.face->measure() / dinfo.cell->measure();
+
+    for (unsigned k=0;k<fe.n_quadrature_points;++k)
+      for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
+       local_vector(i) += (- fe.shape_value(i,k) * penalty * boundary_values[k]
+                           + (fe.normal_vector(k) * fe.shape_grad(i,k)) * boundary_values[k])
+                          * fe.JxW(k);
+  }
+
+
+  template <int dim>
+  void RHSIntegrator<dim>::face(MeshWorker::DoFInfo<dim>&,
+                               MeshWorker::DoFInfo<dim>&,
+                               typename MeshWorker::IntegrationInfo<dim>&,
+                               typename MeshWorker::IntegrationInfo<dim>&)
+  {}
+
+
+                                  // The third local integrator is
+                                  // responsible for the contributions
+                                  // to the error estimate. This is the
+                                  // standard energy estimator due to
+                                  // Karakashian and Pascal (2003).
+  template <int dim>
+  class Estimator : public Subscriptor
+  {
+    public:
+      static void cell(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
+      static void boundary(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
+      static void face(MeshWorker::DoFInfo<dim>& dinfo1,
+                      MeshWorker::DoFInfo<dim>& dinfo2,
+                      typename MeshWorker::IntegrationInfo<dim>& info1,
+                      typename MeshWorker::IntegrationInfo<dim>& info2);
+  };
+
+
+                                  // The cell contribution is the
+                                  // Laplacian of the discrete
+                                  // solution, since the right hand
+                                  // side is zero.
+  template <int dim>
+  void Estimator<dim>::cell(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info)
+  {
+    const FEValuesBase<dim>& fe = info.fe_values();
+
+    const std::vector<Tensor<2,dim> >& DDuh = info.hessians[0][0];
+    for (unsigned k=0;k<fe.n_quadrature_points;++k)
+      {
+       const double t = dinfo.cell->diameter() * trace(DDuh[k]);
+       dinfo.value(0) +=  t*t * fe.JxW(k);
+      }
+    dinfo.value(0) = std::sqrt(dinfo.value(0));
+  }
+
+                                  // At the boundary, we use simply a
+                                  // weighted form of the boundary
+                                  // residual, namely the norm of the
+                                  // difference between the finite
+                                  // element solution and the correct
+                                  // boundary condition.
+  template <int dim>
+  void Estimator<dim>::boundary(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info)
+  {
+    const FEValuesBase<dim>& fe = info.fe_values();
+
+    std::vector<double> boundary_values(fe.n_quadrature_points);
+    exact_solution.value_list(fe.get_quadrature_points(), boundary_values);
+
+    const std::vector<double>& uh = info.values[0][0];
+
+    const unsigned int deg = fe.get_fe().tensor_degree();
+    const double penalty = 2. * deg * (deg+1) * dinfo.face->measure() / dinfo.cell->measure();
+
+    for (unsigned k=0;k<fe.n_quadrature_points;++k)
+      dinfo.value(0) += penalty * (boundary_values[k] - uh[k]) * (boundary_values[k] - uh[k])
+                       * fe.JxW(k);
+    dinfo.value(0) = std::sqrt(dinfo.value(0));
+  }
+
+
+                                  // Finally, on interior faces, the
+                                  // estimator consists of the jumps of
+                                  // the solution and its normal
+                                  // derivative, weighted appropriately.
+  template <int dim>
+  void Estimator<dim>::face(MeshWorker::DoFInfo<dim>& dinfo1,
+                           MeshWorker::DoFInfo<dim>& dinfo2,
+                           typename MeshWorker::IntegrationInfo<dim>& info1,
+                           typename MeshWorker::IntegrationInfo<dim>& info2)
+  {
+    const FEValuesBase<dim>& fe = info1.fe_values();
+    const std::vector<double>& uh1 = info1.values[0][0];
+    const std::vector<double>& uh2 = info2.values[0][0];
+    const std::vector<Tensor<1,dim> >& Duh1 = info1.gradients[0][0];
+    const std::vector<Tensor<1,dim> >& Duh2 = info2.gradients[0][0];
+
+    const unsigned int deg = fe.get_fe().tensor_degree();
+    const double penalty1 = deg * (deg+1) * dinfo1.face->measure() / dinfo1.cell->measure();
+    const double penalty2 = deg * (deg+1) * dinfo2.face->measure() / dinfo2.cell->measure();
+    const double penalty = penalty1 + penalty2;
+    const double h = dinfo1.face->measure();
+
+    for (unsigned k=0;k<fe.n_quadrature_points;++k)
+      {
+       double diff1 = uh1[k] - uh2[k];
+       double diff2 = fe.normal_vector(k) * Duh1[k] - fe.normal_vector(k) * Duh2[k];
+       dinfo1.value(0) += (penalty * diff1*diff1 + h * diff2*diff2)
+                          * fe.JxW(k);
+      }
+    dinfo1.value(0) = std::sqrt(dinfo1.value(0));
+    dinfo2.value(0) = dinfo1.value(0);
+  }
+
+                                  // Finally we have an integrator for
+                                  // the error. Since the energy norm
+                                  // for discontinuous Galerkin
+                                  // problems not only involves the
+                                  // difference of the gradient inside
+                                  // the cells, but also the jump terms
+                                  // across faces and at the boundary,
+                                  // we cannot just use
+                                  // VectorTools::integrate_difference().
+                                  // Instead, we use the MeshWorker
+                                  // interface to compute the error
+                                  // ourselves.
+
+                                  // There are several different ways
+                                  // to define this energy norm, but
+                                  // all of them are equivalent to each
+                                  // other uniformly with mesh size
+                                  // (some not uniformly with
+                                  // polynomial degree). Here, we
+                                  // choose
+                                  // @f[
+                                  // \|u\|_{1,h} = \sum_{K\in \mathbb
+                                  // T_h} \|\nabla u\|_K^2
+                                  // + \sum_{F \in F_h^i}
+                                  // 4\sigma_F\|\{\!\{ u \mathbf
+                                  // n\}\!\}\|^2_F
+                                  // + \sum_{F \in F_h^b} 2\sigma_F\|u\|^2_F
+                                  // @f]
+
+  template <int dim>
+  class ErrorIntegrator : public Subscriptor
+  {
+    public:
+      static void cell(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
+      static void boundary(MeshWorker::DoFInfo<dim>& dinfo, typename MeshWorker::IntegrationInfo<dim>& info);
+      static void face(MeshWorker::DoFInfo<dim>& dinfo1,
+                      MeshWorker::DoFInfo<dim>& dinfo2,
+                      typename MeshWorker::IntegrationInfo<dim>& info1,
+                      typename MeshWorker::IntegrationInfo<dim>& info2);
+  };
+
+                                  // Here we have the integration on
+                                  // cells. There is currently no good
+                                  // interfce in MeshWorker that would
+                                  // allow us to access values of
+                                  // regular functions in the
+                                  // quadrature points. Thus, we have
+                                  // to create the vectors for the
+                                  // exact function's values and
+                                  // gradients inside the cell
+                                  // integrator. After that, everything
+                                  // is as before and we just add up
+                                  // the squares of the differences.
+
+                                  // Additionally to computing the error
+                                  // in the energy norm, we use the
+                                  // capability of the mesh worker to
+                                  // compute two functionals at the
+                                  // same time and compute the
+                                  // <i>L<sup>2</sup></i>-error in the
+                                  // same loop. Obviously, this one
+                                  // does not have any jump terms and
+                                  // only appears in the integration on
+                                  // cells.
+  template <int dim>
+  void ErrorIntegrator<dim>::cell(
+    MeshWorker::DoFInfo<dim>& dinfo,
+    typename MeshWorker::IntegrationInfo<dim>& info)
+  {
+    const FEValuesBase<dim>& fe = info.fe_values();
+    std::vector<Tensor<1,dim> > exact_gradients(fe.n_quadrature_points);
+    std::vector<double> exact_values(fe.n_quadrature_points);
+
+    exact_solution.gradient_list(fe.get_quadrature_points(), exact_gradients);
+    exact_solution.value_list(fe.get_quadrature_points(), exact_values);
+
+    const std::vector<Tensor<1,dim> >& Duh = info.gradients[0][0];
+    const std::vector<double>& uh = info.values[0][0];
+
+    for (unsigned k=0;k<fe.n_quadrature_points;++k)
+      {
+       double sum = 0;
+       for (unsigned int d=0;d<dim;++d)
+         {
+           const double diff = exact_gradients[k][d] - Duh[k][d];
+           sum += diff*diff;
+         }
+       const double diff = exact_values[k] - uh[k];
+       dinfo.value(0) +=  sum * fe.JxW(k);
+       dinfo.value(1) +=  diff*diff * fe.JxW(k);
+      }
+    dinfo.value(0) = std::sqrt(dinfo.value(0));
+    dinfo.value(1) = std::sqrt(dinfo.value(1));
+  }
+
+
+  template <int dim>
+  void ErrorIntegrator<dim>::boundary(
+    MeshWorker::DoFInfo<dim>& dinfo,
+    typename MeshWorker::IntegrationInfo<dim>& info)
+  {
+    const FEValuesBase<dim>& fe = info.fe_values();
+
+    std::vector<double> exact_values(fe.n_quadrature_points);
+    exact_solution.value_list(fe.get_quadrature_points(), exact_values);
+
+    const std::vector<double>& uh = info.values[0][0];
+
+    const unsigned int deg = fe.get_fe().tensor_degree();
+    const double penalty = 2. * deg * (deg+1) * dinfo.face->measure() / dinfo.cell->measure();
+
+    for (unsigned k=0;k<fe.n_quadrature_points;++k)
+      {
+       const double diff = exact_values[k] - uh[k];
+       dinfo.value(0) += penalty * diff * diff * fe.JxW(k);
+      }
+    dinfo.value(0) = std::sqrt(dinfo.value(0));
+  }
+
+
+  template <int dim>
+  void ErrorIntegrator<dim>::face(
+    MeshWorker::DoFInfo<dim>& dinfo1,
+    MeshWorker::DoFInfo<dim>& dinfo2,
+    typename MeshWorker::IntegrationInfo<dim>& info1,
+    typename MeshWorker::IntegrationInfo<dim>& info2)
+  {
+    const FEValuesBase<dim>& fe = info1.fe_values();
+    const std::vector<double>& uh1 = info1.values[0][0];
+    const std::vector<double>& uh2 = info2.values[0][0];
+
+    const unsigned int deg = fe.get_fe().tensor_degree();
+    const double penalty1 = deg * (deg+1) * dinfo1.face->measure() / dinfo1.cell->measure();
+    const double penalty2 = deg * (deg+1) * dinfo2.face->measure() / dinfo2.cell->measure();
+    const double penalty = penalty1 + penalty2;
+
+    for (unsigned k=0;k<fe.n_quadrature_points;++k)
+      {
+       double diff = uh1[k] - uh2[k];
+       dinfo1.value(0) += (penalty * diff*diff)
+                          * fe.JxW(k);
+      }
+    dinfo1.value(0) = std::sqrt(dinfo1.value(0));
+    dinfo2.value(0) = dinfo1.value(0);
+  }
+
+
+
+                                  // @sect3{The main class}
+
+                                  // This class does the main job, like
+                                  // in previous examples. For a
+                                  // description of the functions
+                                  // declared here, please refer to
+                                  // the implementation below.
+  template <int dim>
+  class InteriorPenaltyProblem
+  {
+    public:
+      typedef MeshWorker::IntegrationInfo<dim> CellInfo;
+
+      InteriorPenaltyProblem(const FiniteElement<dim>& fe);
+
+      void run(unsigned int n_steps);
+
+    private:
+      void setup_system ();
+      void assemble_matrix ();
+      void assemble_mg_matrix ();
+      void assemble_right_hand_side ();
+      void error ();
+      double estimate ();
+      void solve ();
+      void output_results (const unsigned int cycle) const;
+
+                                      // The member objects related to
+                                      // the discretization are here.
+      Triangulation<dim>        triangulation;
+      const MappingQ1<dim>      mapping;
+      const FiniteElement<dim>& fe;
+      MGDoFHandler<dim>         mg_dof_handler;
+      DoFHandler<dim>&          dof_handler;
+
+                                      // Then, we have the matrices and
+                                      // vectors related to the global
+                                      // discrete system.
+      SparsityPattern      sparsity;
+      SparseMatrix<double> matrix;
+      Vector<double>       solution;
+      Vector<double>       right_hand_side;
+      BlockVector<double>  estimates;
+
+                                      // Finally, we have a group of
+                                      // sparsity patterns and sparse
+                                      // matrices related to the
+                                      // multilevel preconditioner.
+                                      // First, we have a level matrix
+                                      // and its sparsity pattern.
+      MGLevelObject<SparsityPattern> mg_sparsity;
+      MGLevelObject<SparseMatrix<double> > mg_matrix;
+
+                                      // When we perform multigrid with
+                                      // local smoothing on locally
+                                      // refined meshes, additional
+                                      // matrices are required; see
+                                      // Kanschat (2004). Here is the
+                                      // sparsity pattern for these
+                                      // edge matrices. We only need
+                                      // one, because the pattern of
+                                      // the up matrix is the
+                                      // transpose of that of the down
+                                      // matrix. Actually, we do not
+                                      // care too much about these
+                                      // details, since the MeshWorker
+                                      // is filling these matrices.
+      MGLevelObject<SparsityPattern> mg_sparsity_dg_interface;
+                                      // The flux matrix at the
+                                      // refinement edge, coupling fine
+                                      // level degrees of freedom to
+                                      // coarse level.
+      MGLevelObject<SparseMatrix<double> > mg_matrix_dg_down;
+                                      // The transpose of the flux
+                                      // matrix at the refinement edge,
+                                      // coupling coarse level degrees
+                                      // of freedom to fine level.
+      MGLevelObject<SparseMatrix<double> > mg_matrix_dg_up;
+  };
+
+
+                                  // The constructor simply sets up the
+                                  // coarse grid and the
+                                  // DoFHandler. The FiniteElement is
+                                  // provided as a parameter to allow
+                                  // flexibility.
+  template <int dim>
+  InteriorPenaltyProblem<dim>::InteriorPenaltyProblem(const FiniteElement<dim>& fe)
+                 :
+                 mapping(),
+                 fe(fe),
+                 mg_dof_handler(triangulation),
+                 dof_handler(mg_dof_handler),
+                 estimates(1)
+  {
+    GridGenerator::hyper_cube_slit(triangulation, -1, 1);
+  }
+
+
+                                  // In this function, we set up the
+                                  // dimension of the linear system and
+                                  // the sparsity patterns for the
+                                  // global matrix as well as the level
+                                  // matrices.
+  template <int dim>
+  void
+  InteriorPenaltyProblem<dim>::setup_system()
+  {
+                                    // First, we use the finite element
+                                    // to distribute degrees of
+                                    // freedom over the mesh and number
+                                    // them.
+    dof_handler.distribute_dofs(fe);
+    unsigned int n_dofs = dof_handler.n_dofs();
+                                    // Then, we already know the size
+                                    // of the vectors representing
+                                    // finite element functions.
+    solution.reinit(n_dofs);
+    right_hand_side.reinit(n_dofs);
+
+                                    // Next, we set up the sparsity
+                                    // pattern for the global
+                                    // matrix. Since we do not know the
+                                    // row sizes in advance, we first
+                                    // fill a temporary
+                                    // CompressedSparsityPattern object
+                                    // and copy it to the regular
+                                    // SparsityPattern once it is
+                                    // complete.
+    CompressedSparsityPattern c_sparsity(n_dofs);
+    DoFTools::make_flux_sparsity_pattern(dof_handler, c_sparsity);
+    sparsity.copy_from(c_sparsity);
+    matrix.reinit(sparsity);
+
+    const unsigned int n_levels = triangulation.n_levels();
+                                    // The global system is set up, now
+                                    // we attend to the level
+                                    // matrices. We resize all matrix
+                                    // objects to hold one matrix per level.
+    mg_matrix.resize(0, n_levels-1);
+    mg_matrix.clear();
+    mg_matrix_dg_up.resize(0, n_levels-1);
+    mg_matrix_dg_up.clear();
+    mg_matrix_dg_down.resize(0, n_levels-1);
+    mg_matrix_dg_down.clear();
+                                    // It is important to update the
+                                    // sparsity patterns after
+                                    // <tt>clear()</tt> was called for
+                                    // the level matrices, since the
+                                    // matrices lock the sparsity
+                                    // pattern through the Smartpointer
+                                    // ans Subscriptor mechanism.
+    mg_sparsity.resize(0, n_levels-1);
+    mg_sparsity_dg_interface.resize(0, n_levels-1);
+
+                                    // Now all objects are prepared to
+                                    // hold one sparsity pattern or
+                                    // matrix per level. What's left is
+                                    // setting up the sparsity patterns
+                                    // on each level.
+    for (unsigned int level=mg_sparsity.get_minlevel();
+        level<=mg_sparsity.get_maxlevel();++level)
+      {
+                                        // These are roughly the same
+                                        // lines as above for the
+                                        // global matrix, now for each
+                                        // level.
+       CompressedSparsityPattern c_sparsity(mg_dof_handler.n_dofs(level));
+       MGTools::make_flux_sparsity_pattern(mg_dof_handler, c_sparsity, level);
+       mg_sparsity[level].copy_from(c_sparsity);
+       mg_matrix[level].reinit(mg_sparsity[level]);
+
+                                        // Additionally, we need to
+                                        // initialize the transfer
+                                        // matrices at the refinement
+                                        // edge between levels. They
+                                        // are stored at the index
+                                        // referring to the finer of
+                                        // the two indices, thus there
+                                        // is no such object on level
+                                        // 0.
+       if (level>0)
+         {
+           CompressedSparsityPattern ci_sparsity;
+           ci_sparsity.reinit(mg_dof_handler.n_dofs(level-1), mg_dof_handler.n_dofs(level));
+           MGTools::make_flux_sparsity_pattern_edge(mg_dof_handler, ci_sparsity, level);
+           mg_sparsity_dg_interface[level].copy_from(ci_sparsity);
+           mg_matrix_dg_up[level].reinit(mg_sparsity_dg_interface[level]);
+           mg_matrix_dg_down[level].reinit(mg_sparsity_dg_interface[level]);
+         }
+      }
+  }
+
+
+                                  // In this function, we assemble the
+                                  // global system matrix, where by
+                                  // global we indicate that this is
+                                  // the matrix of the discrete system
+                                  // we solve and it is covering the
+                                  // whole mesh.
+  template <int dim>
+  void
+  InteriorPenaltyProblem<dim>::assemble_matrix()
+  {
+                                    // First, we need t set up the
+                                    // object providing the values we
+                                    // integrate. This object contains
+                                    // all FEValues and FEFaceValues
+                                    // objects needed and also
+                                    // maintains them automatically
+                                    // such that they always point to
+                                    // the current cell. To this end,
+                                    // we need to tell it first, where
+                                    // and what to compute. Since we
+                                    // are not doing anything fancy, we
+                                    // can rely on their standard
+                                    // choice for quadrature rules.
+                                    //
+                                    // Since their default update flags
+                                    // are minimal, we add what we need
+                                    // additionally, namely the values
+                                    // and gradients of shape functions
+                                    // on all objects (cells, boundary
+                                    // and interior faces). Afterwards,
+                                    // we are ready to initialize the
+                                    // container, which will create all
+                                    // necessary FEValuesBase objects
+                                    // for integration.
+    MeshWorker::IntegrationInfoBox<dim> info_box;
+    UpdateFlags update_flags = update_values | update_gradients;
+    info_box.add_update_flags_all(update_flags);
+    info_box.initialize(fe, mapping);
+
+                                    // This is the object into which we
+                                    // integrate local data. It is
+                                    // filled by the local integration
+                                    // routines in MatrixIntegrator and
+                                    // then used by the assembler to
+                                    // distribute the information into
+                                    // the global matrix.
+    MeshWorker::DoFInfo<dim> dof_info(dof_handler);
+
+                                    // Finally, we need an object that
+                                    // assembles the local matrix into
+                                    // the global matrix.
+    MeshWorker::Assembler::MatrixSimple<SparseMatrix<double> > assembler;
+    assembler.initialize(matrix);
+
+                                    // Now, we throw everything into a
+                                    // MeshWorker::loop(), which here
+                                    // traverses all active cells of
+                                    // the mesh, computes cell and face
+                                    // matrices and assembles them into
+                                    // the global matrix. We use the
+                                    // variable <tt>dof_handler</tt>
+                                    // here in order to use the global
+                                    // numbering of degrees of freedom.
+    MeshWorker::integration_loop<dim, dim>(
+      dof_handler.begin_active(), dof_handler.end(),
+      dof_info, info_box,
+      &MatrixIntegrator<dim>::cell,
+      &MatrixIntegrator<dim>::boundary,
+      &MatrixIntegrator<dim>::face,
+      assembler);
+  }
+
+
+                                  // Now, we do the same for the level
+                                  // matrices. Not too surprisingly,
+                                  // this function looks like a twin of
+                                  // the previous one. Indeed, there
+                                  // are only two minor differences.
+  template <int dim>
+  void
+  InteriorPenaltyProblem<dim>::assemble_mg_matrix()
+  {
+    MeshWorker::IntegrationInfoBox<dim> info_box;
+    UpdateFlags update_flags = update_values | update_gradients;
+    info_box.add_update_flags_all(update_flags);
+    info_box.initialize(fe, mapping);
+
+    MeshWorker::DoFInfo<dim> dof_info(mg_dof_handler);
+
+                                    // Obviously, the assembler needs
+                                    // to be replaced by one filling
+                                    // level matrices. Note that it
+                                    // automatically fills the edge
+                                    // matrices as well.
+    MeshWorker::Assembler::MGMatrixSimple<SparseMatrix<double> > assembler;
+    assembler.initialize(mg_matrix);
+    assembler.initialize_fluxes(mg_matrix_dg_up, mg_matrix_dg_down);
+
+                                    // Here is the other difference to
+                                    // the previous function: we run
+                                    // over all cells, not only the
+                                    // active ones. And we use
+                                    // <tt>mg_dof_handler</tt>, since
+                                    // we need the degrees of freedom
+                                    // on each level, not the global
+                                    // numbering.
+    MeshWorker::integration_loop<dim, dim> (
+      mg_dof_handler.begin(), mg_dof_handler.end(),
+      dof_info, info_box,
+      &MatrixIntegrator<dim>::cell,
+      &MatrixIntegrator<dim>::boundary,
+      &MatrixIntegrator<dim>::face,
+      assembler);
+  }
+
+
+                                  // Here we have another clone of the
+                                  // assemble function. The difference
+                                  // to assembling the system matrix
+                                  // consists in that we assemble a
+                                  // vector here.
+  template <int dim>
+  void
+  InteriorPenaltyProblem<dim>::assemble_right_hand_side()
+  {
+    MeshWorker::IntegrationInfoBox<dim> info_box;
+    UpdateFlags update_flags = update_quadrature_points | update_values | update_gradients;
+    info_box.add_update_flags_all(update_flags);
+    info_box.initialize(fe, mapping);
+
+    MeshWorker::DoFInfo<dim> dof_info(dof_handler);
+
+                                    // Since this assembler alows us to
+                                    // fill several vectors, the
+                                    // interface is a little more
+                                    // complicated as above. The
+                                    // pointers to the vectors have to
+                                    // be stored in a NamedData
+                                    // object. While this seems to
+                                    // cause two extra lines of code
+                                    // here, it actually comes handy in
+                                    // more complex applications.
+    MeshWorker::Assembler::ResidualSimple<Vector<double> > assembler;
+    NamedData<Vector<double>* > data;
+    Vector<double>* rhs = &right_hand_side;
+    data.add(rhs, "RHS");
+    assembler.initialize(data);
+
+    MeshWorker::integration_loop<dim, dim>(
+      dof_handler.begin_active(), dof_handler.end(),
+      dof_info, info_box,
+      &RHSIntegrator<dim>::cell,
+      &RHSIntegrator<dim>::boundary,
+      &RHSIntegrator<dim>::face,
+      assembler);
+
+    right_hand_side *= -1.;
+  }
+
+
+                                  // Now that we have coded all
+                                  // functions building the discrete
+                                  // linear system, it is about time
+                                  // that we actually solve it.
+  template <int dim>
+  void
+  InteriorPenaltyProblem<dim>::solve()
+  {
+                                    // The solver of choice is
+                                    // conjugate gradient.
+    SolverControl control(1000, 1.e-12);
+    SolverCG<Vector<double> > solver(control);
+
+                                    // Now we are setting up the
+                                    // components of the multilevel
+                                    // preconditioner. First, we need
+                                    // transfer between grid
+                                    // levels. The object we are using
+                                    // here generates sparse matrices
+                                    // for these transfers.
+    MGTransferPrebuilt<Vector<double> > mg_transfer;
+    mg_transfer.build_matrices(mg_dof_handler);
+
+                                    // Then, we need an exact solver
+                                    // for the matrix on the coarsest
+                                    // level.
+    FullMatrix<double> coarse_matrix;
+    coarse_matrix.copy_from (mg_matrix[0]);
+    MGCoarseGridHouseholder<double, Vector<double> > mg_coarse;
+    mg_coarse.initialize(coarse_matrix);
+
+                                    // While transfer and coarse grid
+                                    // solver are pretty much generic,
+                                    // more flexibility is offered for
+                                    // the smoother. First, we choose
+                                    // Gauss-Seidel as our smoothing
+                                    // method.
+    GrowingVectorMemory<Vector<double> > mem;
+    typedef PreconditionSOR<SparseMatrix<double> > RELAXATION;
+    MGSmootherRelaxation<SparseMatrix<double>, RELAXATION, Vector<double> >
+      mg_smoother(mem);
+    RELAXATION::AdditionalData smoother_data(1.);
+    mg_smoother.initialize(mg_matrix, smoother_data);
+
+                                    // Do two smoothing steps on each
+                                    // level.
+    mg_smoother.set_steps(2);
+                                    // Since the SOR method is not
+                                    // symmetric, but we use conjugate
+                                    // gradient iteration below, here
+                                    // is a trick to make the
+                                    // multilevel preconditioner a
+                                    // symmetric operator even for
+                                    // nonsymmetric smoothers.
+    mg_smoother.set_symmetric(true);
+                                    // The smoother class optionally
+                                    // implements the variable V-cycle,
+                                    // which we do not want here.
+    mg_smoother.set_variable(false);
+
+                                    // Finally, we must wrap our
+                                    // matrices in an object having the
+                                    // required multiplication
+                                    // functions.
+    MGMatrix<SparseMatrix<double>, Vector<double> > mgmatrix(&mg_matrix);
+    MGMatrix<SparseMatrix<double>, Vector<double> > mgdown(&mg_matrix_dg_down);
+    MGMatrix<SparseMatrix<double>, Vector<double> > mgup(&mg_matrix_dg_up);
+
+                                    // Now, we are ready to set up the
+                                    // V-cycle operator and the
+                                    // multilevel preconditioner.
+    Multigrid<Vector<double> > mg(mg_dof_handler, mgmatrix,
+                                 mg_coarse, mg_transfer,
+                                 mg_smoother, mg_smoother);
+                                    // Let us not forget the edge
+                                    // matrices needed because of the
+                                    // adaptive refinement.
+    mg.set_edge_flux_matrices(mgdown, mgup);
+
+                                    // After all preparations, wrap the
+                                    // Multigrid object into another
+                                    // object, which can be used as a
+                                    // regular preconditioner,
+    PreconditionMG<dim, Vector<double>,
+                  MGTransferPrebuilt<Vector<double> > >
     preconditioner(mg_dof_handler, mg, mg_transfer);
                                   // and use it to solve the system.
   solver.solve(matrix, solution, right_hand_side, preconditioner);
@@ -920,7 +922,7 @@ Step39<dim>::solve()
                                 // also have an input vector.
 template <int dim>
 double
-Step39<dim>::estimate()
+InteriorPenaltyProblem<dim>::estimate()
 {
                                   // The results of the estimator are
                                   // stored in a vector with one
@@ -936,7 +938,7 @@ Step39<dim>::estimate()
                                   // tampering with them.
   std::vector<unsigned int> old_user_indices;
   triangulation.save_user_indices(old_user_indices);
-  
+
   estimates.block(0).reinit(triangulation.n_active_cells());
   unsigned int i=0;
   for (typename Triangulation<dim>::active_cell_iterator cell = triangulation.begin_active();
@@ -957,7 +959,7 @@ Step39<dim>::estimate()
                                   // solution we just computed.
   NamedData<Vector<double>* > solution_data;
   solution_data.add(&solution, "solution");
-  
+
                                   // Then, we tell the Meshworker::VectorSelector
                                   // for cells, that we need the
                                   // second derivatives of this
@@ -983,19 +985,19 @@ Step39<dim>::estimate()
                                   // derivatives we requested above.
   info_box.add_update_flags_boundary(update_quadrature_points);
   info_box.initialize(fe, mapping, solution_data);
-  
+
   MeshWorker::DoFInfo<dim> dof_info(dof_handler);
 
                                   // The assembler stores one number
                                   // per cell, but else this is the
                                   // same as in the computation of
                                   // the right hand side.
-  MeshWorker::Assembler::CellsAndFaces<double> assembler;  
+  MeshWorker::Assembler::CellsAndFaces<double> assembler;
   NamedData<BlockVector<double>* > out_data;
   BlockVector<double>* est = &estimates;
   out_data.add(est, "cells");
   assembler.initialize(out_data, false);
-  
+
   MeshWorker::integration_loop<dim, dim> (
     dof_handler.begin_active(), dof_handler.end(),
     dof_info, info_box,
@@ -1026,7 +1028,7 @@ Step39<dim>::estimate()
                                 // needs two blocks here.
 template <int dim>
 void
-Step39<dim>::error()
+InteriorPenaltyProblem<dim>::error()
 {
   BlockVector<double> errors(2);
   errors.block(0).reinit(triangulation.n_active_cells());
@@ -1042,23 +1044,23 @@ Step39<dim>::error()
 
   NamedData<Vector<double>* > solution_data;
   solution_data.add(&solution, "solution");
-  
+
   info_box.cell_selector.add("solution", true, true, false);
   info_box.boundary_selector.add("solution", true, false, false);
   info_box.face_selector.add("solution", true, false, false);
-  
+
   info_box.add_update_flags_cell(update_quadrature_points);
   info_box.add_update_flags_boundary(update_quadrature_points);
   info_box.initialize(fe, mapping, solution_data);
-  
+
   MeshWorker::DoFInfo<dim> dof_info(dof_handler);
-  
-  MeshWorker::Assembler::CellsAndFaces<double> assembler;  
+
+  MeshWorker::Assembler::CellsAndFaces<double> assembler;
   NamedData<BlockVector<double>* > out_data;
   BlockVector<double>* est = &errors;
   out_data.add(est, "cells");
   assembler.initialize(out_data, false);
-  
+
   MeshWorker::integration_loop<dim, dim> (
     dof_handler.begin_active(), dof_handler.end(),
     dof_info, info_box,
@@ -1074,7 +1076,7 @@ Step39<dim>::error()
 
                                 // Some graphical output
 template <int dim>
-void Step39<dim>::output_results (const unsigned int cycle) const
+void InteriorPenaltyProblem<dim>::output_results (const unsigned int cycle) const
 {
                                   // Output of the solution in
                                   // gnuplot format.
@@ -1086,14 +1088,14 @@ void Step39<dim>::output_results (const unsigned int cycle) const
   deallog << "Writing solution to <" << filename << ">..."
          << std::endl << std::endl;
   std::ofstream gnuplot_output (filename.c_str());
-  
+
   DataOut<dim> data_out;
   data_out.attach_dof_handler (dof_handler);
   data_out.add_data_vector (solution, "u");
   data_out.add_data_vector (estimates.block(0), "est");
 
   data_out.build_patches ();
-  
+
   data_out.write_gnuplot(gnuplot_output);
 }
 
@@ -1102,7 +1104,7 @@ void Step39<dim>::output_results (const unsigned int cycle) const
                                 // examples.
 template <int dim>
 void
-Step39<dim>::run(unsigned int n_steps)
+InteriorPenaltyProblem<dim>::run(unsigned int n_steps)
 {
   deallog << "Element: " << fe.get_name() << std::endl;
   for (unsigned int s=0;s<n_steps;++s)
@@ -1117,11 +1119,11 @@ Step39<dim>::run(unsigned int n_steps)
                                                             0.5, 0.0);
          triangulation.execute_coarsening_and_refinement ();
        }
-      
+
       deallog << "Triangulation "
              << triangulation.n_active_cells() << " cells, "
              << triangulation.n_levels() << " levels" << std::endl;
-      
+
       setup_system();
       deallog << "DoFHandler " << dof_handler.n_dofs() << " dofs, level dofs";
       for (unsigned int l=0;l<triangulation.n_levels();++l)
@@ -1141,13 +1143,18 @@ Step39<dim>::run(unsigned int n_steps)
       output_results(s);
     }
 }
+}
+
 
 
 int main()
 {
+  using namespace dealii;
+  using namespace Step39;
+
   std::ofstream logfile("deallog");
   deallog.attach(logfile);
   FE_DGQ<2> fe1(3);
-  Step39<2> test1(fe1);
+  InteriorPenaltyProblem<2> test1(fe1);
   test1.run(12);
 }

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.