/* $Id: step-1.cc 27657 2012-11-21 13:19:08Z bangerth $
 *
 * Copyright (C) 1999-2003, 2005-2007, 2009, 2011-2012 by the deal.II authors
 *
 * This file is subject to QPL and may not be  distributed
 * without copyright and license information. Please refer
 * to the file deal.II/doc/license.html for the  text  and
 * further information on this license.
 */

// @sect3{Include files}

// The most fundamental class in the library is the Triangulation class, which
// is declared here:
#include <deal.II/grid/tria.h>
// We need the following two includes for loops over cells and/or faces:
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
// Here are some functions to generate standard grids:
#include <deal.II/grid/grid_generator.h>
// We would like to use boundaries which are not straight lines, so we import
// some classes which predefine some boundary descriptions:
#include <deal.II/grid/tria_boundary_lib.h>
// Output of grids in various graphics formats:
#include <deal.II/grid/grid_out.h>

// This is needed for C++ output:
#include <fstream>
// And this for the declarations of the `sqrt' and `fabs' functions:
#include <cmath>

// The final step in importing deal.II is this: All deal.II functions and
// classes are in a namespace dealii, to make sure they don't
// clash with symbols from other libraries you may want to use in conjunction
// with deal.II. One could use these functions and classes by prefixing every
// use of these names by dealii::, but that would quickly become
// cumbersome and annoying. Rather, we simply import the entire deal.II
// namespace for general use:
using namespace dealii;

// @sect3{Creating the first mesh}

// In the following, first function, we simply use the unit square as domain
// and produce a globally refined grid from it.
void first_grid ()
{
  // The first thing to do is to define an object for a triangulation of a
  // two-dimensional domain:
  Triangulation<2> triangulation;
  // Here and in many following cases, the string "<2>" after a class name
  // indicates that this is an object that shall work in two space
  // dimensions. Likewise, there are versions of the triangulation class that
  // are working in one ("<1>") and three ("<3>") space dimensions. The way
  // this works is through some template magic that we will investigate in
  // some more detail in later example programs; there, we will also see how
  // to write programs in an essentially dimension independent way.

  // Next, we want to fill the triangulation with a single cell for a square
  // domain. The triangulation is the refined four times, to yield 4^4=256
  // cells in total:
  GridGenerator::hyper_cube (triangulation);
  triangulation.refine_global (4);

  // Now we want to write a graphical representation of the mesh to an output
  // file. The GridOut class of deal.II can do that in a number of different
  // output formats; here, we choose encapsulated postscript (eps) format:
  std::ofstream out ("grid-1.eps");
  GridOut grid_out;
  grid_out.write_eps (triangulation, out);
}

// @sect3{Creating the second mesh}

// The grid in the following, second function is slightly more complicated in
// that we use a ring domain and refine the result once globally.
void second_grid ()
{
  // We start again by defining an object for a triangulation of a
  // two-dimensional domain:
  Triangulation<2> triangulation;

  // We then fill it with a ring domain. The center of the ring shall be the
  // point (1,0), and inner and outer radius shall be 0.5 and 1. The number of
  // circumferential cells could be adjusted automatically by this function,
  // but we choose to set it explicitely to 10 as the last argument:
  const Point<2> center (1,0);
  const double inner_radius = 0.5,
               outer_radius = 1.0;
  GridGenerator::hyper_shell (triangulation,
                              center, inner_radius, outer_radius,
                              10);
  // By default, the triangulation assumes that all boundaries are straight
  // and given by the cells of the coarse grid (which we just created). It
  // uses this information when cells at the boundary are refined and new
  // points need to be introduced on the boundary; if the boundary is assumed
  // to be straight, then new points will simply be in the middle of the
  // surrounding ones.
  //
  // Here, however, we would like to have a curved boundary. Fortunately, some
  // good soul implemented an object which describes the boundary of a ring
  // domain; it only needs the center of the ring and automatically figures
  // out the inner and outer radius when needed. Note that we associate this
  // boundary object with that part of the boundary that has the "boundary
  // indicator" zero. By default (at least in 2d and 3d, the 1d case is
  // slightly different), all boundary parts have this number, but you can
  // change this number for some parts of the boundary. In that case, the
  // curved boundary thus associated with number zero will not apply on those
  // parts with a non-zero boundary indicator, but other boundary description
  // objects can be associated with those non-zero indicators. If no boundary
  // description is associated with a particular boundary indicator, a
  // straight boundary is implied.
  const HyperShellBoundary<2> boundary_description(center);
  triangulation.set_boundary (0, boundary_description);

  // In order to demonstrate how to write a loop over all cells, we will
  // refine the grid in five steps towards the inner circle of the domain:
  for (unsigned int step=0; step<5; ++step)
    {
      // Next, we need an iterator which points to a cell and which we will
      // move over all active cells one by one (active cells are those that
      // are not further refined, and the only ones that can be marked for
      // further refinement, obviously). By convention, we almost always use
      // the names cell and endc for the iterator
      // pointing to the present cell and to the one-past-the-end
      // iterator:
      Triangulation<2>::active_cell_iterator
      cell = triangulation.begin_active(),
      endc = triangulation.end();

      // The loop over all cells is then rather trivial, and looks like any
      // loop involving pointers instead of iterators:
      for (; cell!=endc; ++cell)
        // Next, we want to loop over all vertices of the cells. Since we are
        // in 2d, we know that each cell has exactly four vertices. However,
        // instead of penning down a 4 in the loop bound, we make a first
        // attempt at writing it in a dimension-independent way by which we
        // find out about the number of vertices of a cell. Using the
        // GeometryInfo class, we will later have an easier time getting the
        // program to also run in 3d: we only have to change all occurrences
        // of <2> to <3>, and do not
        // have to audit our code for the hidden appearance of magic numbers
        // like a 4 that needs to be replaced by an 8:
        for (unsigned int v=0;
             v < GeometryInfo<2>::vertices_per_cell;
             ++v)
          {
            // If this cell is at the inner boundary, then at least one of its
            // vertices must sit on the inner ring and therefore have a radial
            // distance from the center of exactly 0.5, up to floating point
            // accuracy. Compute this distance, and if we have found a vertex
            // with this property flag this cell for later refinement. We can
            // then also break the loop over all vertices and move on to the
            // next cell.
            const double distance_from_center
              = center.distance (cell->vertex(v));

            if (std::fabs(distance_from_center - inner_radius) < 1e-10)
              {
                cell->set_refine_flag ();
                break;
              }
          }

      // Now that we have marked all the cells that we want refined, we let
      // the triangulation actually do this refinement. The function that does
      // so owes its long name to the fact that one can also mark cells for
      // coarsening, and the function does coarsening and refinement all at
      // once:
      triangulation.execute_coarsening_and_refinement ();
    }

  // Finally, after these five iterations of refinement, we want to again
  // write the resulting mesh to a file, again in eps format. This works just
  // as above:
  std::ofstream out ("grid-2.eps");
  GridOut grid_out;
  grid_out.write_eps (triangulation, out);

  // At this point, all objects created in this function will be destroyed in
  // reverse order. Unfortunately, we defined the boundary object after the
  // triangulation, which still has a pointer to it and the library will
  // produce an error if the boundary object is destroyed before the
  // triangulation. We therefore have to release it, which can be done as
  // follows. Note that this sets the boundary object used for part "0" of the
  // boundary back to a default object, over which the triangulation has full
  // control.
  triangulation.set_boundary (0);
  // An alternative to doing so, and one that is frequently more convenient,
  // would have been to declare the boundary object before the triangulation
  // object. In that case, the triangulation would have let lose of the
  // boundary object upon its destruction, and everything would have been
  // fine.
}

// @sect3{The main function}

// Finally, the main function. There isn't much to do here, only to call the
// two subfunctions, which produce the two grids.
int main ()
{
  first_grid ();
  second_grid ();
}


/* ---------------------------------------------------------------------
 *
 * Copyright (C) 2009 - 2021 by the deal.II authors
 *
 * This file is part of the deal.II library.
 *
 * The deal.II library is free software; you can use it, redistribute
 * it, and/or modify it under the terms of the GNU Lesser General
 * Public License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * The full text of the license can be found in the file LICENSE.md at
 * the top level directory of deal.II.
 *
 * ---------------------------------------------------------------------
 *
 * Author: Wolfgang Bangerth, Texas A&M University, 2009, 2010
 *         Timo Heister, University of Goettingen, 2009, 2010
 */

// @sect3{Include files}

// 我们在这个程序中需要的大部分包含文件已经在以前的程序中讨论过了。特别是，以下所有的文件都应该已经是熟悉的朋友了。

#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/function.h>
#include <deal.II/base/timer.h>

#include <deal.II/lac/generic_linear_algebra.h>

// 这个程序可以使用PETSc或Trilinos来满足其并行代数的需要。默认情况下，如果deal.II已经被配置为PETSc，它将使用PETSc。否则，下面几行将检查deal.II是否已被配置为Trilinos，并采用它。

// 但是在某些情况下，即使deal.II也被配置为PETSc，你还是想使用Trilinos，例如，比较这两个库的性能。要做到这一点，请在源代码中添加以下的\#define。
// @code
//  #define FORCE_USE_OF_TRILINOS
//  @endcode

// 使用这个逻辑，下面几行将导入PETSc或Trilinos包装器到命名空间`LA`（代表 "线性代数"）。在前一种情况下，我们还要定义宏 `USE_PETSC_LA`，这样我们就可以检测到我们是否在使用PETSc（参见solve()中需要用到的例子）。

namespace LA
{
#if defined(DEAL_II_WITH_PETSC) && !defined(DEAL_II_PETSC_WITH_COMPLEX) && \
  !(defined(DEAL_II_WITH_TRILINOS) && defined(FORCE_USE_OF_TRILINOS))
  using namespace dealii::LinearAlgebraPETSc;
#  define USE_PETSC_LA
#elif defined(DEAL_II_WITH_TRILINOS)
  using namespace dealii::LinearAlgebraTrilinos;
#else
#  error DEAL_II_WITH_PETSC or DEAL_II_WITH_TRILINOS required
#endif
} // namespace LA

#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/affine_constraints.h>
#include <deal.II/lac/dynamic_sparsity_pattern.h>

#include <deal.II/grid/grid_generator.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/numerics/vector_tools.h>
#include <deal.II/numerics/data_out.h>
#include <deal.II/numerics/error_estimator.h>

// 然而，下面这些将是新的，或在新的角色中使用。让我们来看看它们。其中第一个将提供 Utilities::System 命名空间的工具，我们将用它来查询诸如与当前MPI宇宙相关的处理器数量，或者这个作业运行的处理器在这个宇宙中的编号。

#include <deal.II/base/utilities.h>

// 下一个提供了一个类，ConditionOStream，它允许我们编写代码，将东西输出到一个流中（例如在每个处理器上的 std::cout ，但在除了一个处理器以外的所有处理器上都将文本扔掉。我们可以通过简单地在每个可能产生输出的地方前面放一个 if 语句来实现同样的目的，但这并不能使代码更漂亮。此外，这个处理器是否应该向屏幕输出的条件每次都是一样的--因此，把它放在产生输出的语句中应该是很简单的。

#include <deal.II/base/conditional_ostream.h>

// 在这些预演之后，这里变得更加有趣。正如在 @ref distributed 模块中提到的，在大量处理器上解决问题的一个基本事实是，任何处理器都不可能存储所有的东西（例如，关于网格中所有单元的信息，所有的自由度，或者解向量中所有元素的值）。相反，每个处理器都会own其中的几个，如果有必要，还可能know另外几个，例如，位于与该处理器自己拥有的单元相邻的那些单元。我们通常称后者为ghost cells、ghost nodes或ghost elements of a vector。这里讨论的重点是，我们需要有一种方法来表明一个特定的处理器拥有或需要知道哪些元素。这就是IndexSet类的领域：如果总共有 $N$ 个单元、自由度或向量元素，与（非负）积分指数 $[0,N)$ 相关，那么当前处理器拥有的元素集以及它需要了解的（可能更大）指数集都是集合 $[0,N)$ 的子集。IndexSet是一个类，它以一种有效的格式存储这个集合的子集。

#include <deal.II/base/index_set.h>

// 下一个头文件是一个单一的函数所必需的，  SparsityTools::distribute_sparsity_pattern.  这个函数的作用将在下面解释。

#include <deal.II/lac/sparsity_tools.h>

// 最后两个新的头文件提供了类 parallel::distributed::Triangulation ，它提供了分布在可能非常多的处理器上的网格，而第二个文件提供了命名空间 parallel::distributed::GridRefinement ，它提供了可以自适应细化这种分布式网格的函数。

#include <deal.II/distributed/tria.h>
#include <deal.II/distributed/grid_refinement.h>

#include <fstream>
#include <iostream>

namespace Step40
{
  using namespace dealii;
// @sect3{The LaplaceProblem class template}

// 接下来我们来声明这个程序的主类。它的结构几乎与 step-6 的教程程序一模一样。唯一显著的区别是。

// --  mpi_communicator 变量，它描述了我们希望这段代码运行在哪一组处理器上。在实践中，这将是MPI_COMM_WORLD，即批处理调度系统分配给这个特定作业的所有处理器。

// - ConditionOStream类型的 pcout 变量的存在。

// - 明显使用 parallel::distributed::Triangulation 而不是Triangulation。

// - 两个IndexSet对象的存在，表示我们在当前处理器上拥有哪些自由度集（以及解和右手向量的相关元素），以及我们需要哪些（作为幽灵元素）来使本程序中的算法工作。

// - 现在所有的矩阵和向量都是分布式的。我们使用PETSc或Trilinos包装类，这样我们就可以使用Hypre（使用PETSc）或ML（使用Trilinos）提供的复杂的预处理器之一。请注意，作为这个类的一部分，我们存储的解向量不仅包含当前处理器拥有的自由度，还包括（作为鬼魂元素）所有对应于 "本地相关 "自由度的向量元素（即所有生活在本地拥有的单元或围绕它的鬼魂单元层的自由度）。

  template <int dim>
  class LaplaceProblem
  {
  public:
    LaplaceProblem();

    void run();

  private:
    void setup_system();
    void assemble_system();
    void solve();
    void refine_grid();
    void output_results(const unsigned int cycle) const;

    MPI_Comm mpi_communicator;

    parallel::distributed::Triangulation<dim> triangulation;

    FE_Q<dim>       fe;
    DoFHandler<dim> dof_handler;

    IndexSet locally_owned_dofs;
    IndexSet locally_relevant_dofs;

    AffineConstraints<double> constraints;

    LA::MPI::SparseMatrix system_matrix;
    LA::MPI::Vector       locally_relevant_solution;
    LA::MPI::Vector       system_rhs;

    ConditionalOStream pcout;
    TimerOutput        computing_timer;
  };
// @sect3{The LaplaceProblem class implementation}
// @sect4{Constructor}

// 构造函数和析构函数是相当微不足道的。除了我们在 step-6 中所做的，我们将我们想要工作的处理器集合设置为所有可用的机器（MPI_COMM_WORLD）；要求三角化以确保网格保持平滑并自由精炼岛屿，例如；并初始化 pcout 变量，只允许处理器0输出任何东西。最后一块是初始化一个定时器，我们用它来决定程序的不同部分需要多少计算时间。

  template <int dim>
  LaplaceProblem<dim>::LaplaceProblem()
    : mpi_communicator(MPI_COMM_WORLD)
    , triangulation(mpi_communicator,
                    typename Triangulation<dim>::MeshSmoothing(
                      Triangulation<dim>::smoothing_on_refinement |
                      Triangulation<dim>::smoothing_on_coarsening))
    , fe(2)
    , dof_handler(triangulation)
    , pcout(std::cout,
            (Utilities::MPI::this_mpi_process(mpi_communicator) == 0))
    , computing_timer(mpi_communicator,
                      pcout,
                      TimerOutput::summary,
                      TimerOutput::wall_times)
  {}

//  @sect4{LaplaceProblem::setup_system}

// 下面这个函数可以说是整个程序中最有趣的一个，因为它涉及到了%并行  step-40  和顺序  step-6  的核心区别。

// 在顶部我们做了我们一直在做的事情：告诉DoFHandler对象来分配自由度。由于我们在这里使用的三角测量是分布式的，DoFHandler对象足够聪明，它认识到在每个处理器上只能在它所拥有的单元上分配自由度；接下来是一个交换步骤，处理器互相告诉对方关于ghost单元的自由度。结果是DoFHandler知道本地拥有的单元和幽灵单元（即与本地拥有的单元相邻的单元）的自由度，但对更远的单元则一无所知，这与分布式计算的基本理念一致，即没有处理器可以知道所有的事情。

  template <int dim>
  void LaplaceProblem<dim>::setup_system()
  {
    TimerOutput::Scope t(computing_timer, "setup");

    dof_handler.distribute_dofs(fe);

// 接下来的两行提取了一些我们以后需要的信息，即两个索引集，提供了关于哪些自由度为当前处理器所拥有的信息（这些信息将被用来初始化解和右手向量以及系统矩阵，表明哪些元素要存储在当前处理器上，哪些要期望存储在其他地方）；以及一个索引集，表明哪些自由度是本地相关的（即生活在当前处理器所拥有的单元上或本地所拥有的单元周围的鬼魂单元上；我们将把这些自由度存储在当前处理器上。 例如，生活在当前处理器拥有的单元上或本地拥有的单元周围的幽灵单元层上；例如，我们需要所有这些自由度来估计本地单元的误差）。)

    locally_owned_dofs = dof_handler.locally_owned_dofs();
    DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant_dofs);

// 接下来，让我们初始化解和右手边的向量。如上所述，我们寻求的解向量不仅存储了我们自己的元素，还存储了幽灵条目；另一方面，右手向量只需要有当前处理器拥有的条目，因为我们所做的只是向其中写入，而不是从其中读取本地拥有的单元（当然，线性求解器会从其中读取，但它们并不关心自由度的几何位置）。

    locally_relevant_solution.reinit(locally_owned_dofs,
                                     locally_relevant_dofs,
                                     mpi_communicator);
    system_rhs.reinit(locally_owned_dofs, mpi_communicator);

// 下一步是计算悬挂节点和边界值约束，我们将其合并为一个存储所有约束的对象。

// 就像在%parallel中的所有其他事情一样，口头禅必须是：没有一个处理器可以存储整个宇宙的所有信息。因此，我们需要告诉AffineConstraints对象哪些自由度可以存储约束条件，哪些可以不期望存储任何信息。在我们的例子中，正如 @ref distributed 模块所解释的，我们需要在每个处理器上关心的自由度是本地相关的自由度，所以我们把这个传递给 AffineConstraints::reinit 函数。顺便提一下，如果你忘记传递这个参数，AffineConstraints类将分配一个长度等于它目前看到的最大自由度索引的数组。对于MPI进程数很高的处理器来说，这可能是非常大的 -- 也许是数十亿的数量级。然后，程序将为这个单一的数组分配比其他所有操作加起来还要多的内存。

    constraints.clear();
    constraints.reinit(locally_relevant_dofs);
    DoFTools::make_hanging_node_constraints(dof_handler, constraints);
    VectorTools::interpolate_boundary_values(dof_handler,
                                             0,
                                             Functions::ZeroFunction<dim>(),
                                             constraints);
    constraints.close();

// 这个函数的最后一部分涉及到用伴随的稀疏模式初始化矩阵。和以前的教程程序一样，我们使用DynamicSparsityPattern作为一个中介，然后用它来初始化系统矩阵。为了做到这一点，我们必须告诉稀疏模式它的大小，但如上所述，所产生的对象不可能为每个全局自由度存储哪怕一个指针；我们最好的希望是它能存储每个局部相关自由度的信息，即所有我们在组装矩阵的过程中可能接触到的自由度（ @ref distributed_paper "分布式计算论文 "有很长的讨论，为什么我们真的需要局部相关自由度，而不是在此背景下的小的局部活动自由度集）。

// 所以我们告诉稀疏模式它的大小和要存储什么自由度，然后要求 DoFTools::make_sparsity_pattern 来填充它（这个函数忽略了所有不属于本地的单元，模仿我们下面在装配过程中的做法）。在这之后，我们调用一个函数，在处理器之间交换这些稀疏模式的条目，以便最后每个处理器真正知道它将拥有的那部分有限元矩阵中的所有条目。最后一步是用稀疏模式初始化矩阵。

    DynamicSparsityPattern dsp(locally_relevant_dofs);

    DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints, false);
    SparsityTools::distribute_sparsity_pattern(dsp,
                                               dof_handler.locally_owned_dofs(),
                                               mpi_communicator,
                                               locally_relevant_dofs);

    system_matrix.reinit(locally_owned_dofs,
                         locally_owned_dofs,
                         dsp,
                         mpi_communicator);
  }

//  @sect4{LaplaceProblem::assemble_system}

// 然后组装线性系统的函数相对来说比较无聊，几乎和我们之前看到的一模一样。需要注意的地方是。

// - 装配必须只在本地拥有的单元上循环。有多种方法来测试；例如，我们可以将一个单元的subdomain_id与三角形的信息进行比较，如cell->subdomain_id() == triangulation.local_owned_subdomain()，或者跳过所有条件cell->is_ghost() || cell->is_artificial()为真的单元。然而，最简单的方法是简单地询问单元格是否为本地处理器所拥有。

// - 将本地贡献复制到全局矩阵中必须包括分配约束和边界值。换句话说，我们不能（就像我们在 step-6 中所做的那样）首先将每个本地贡献复制到全局矩阵中，然后在后面的步骤中才处理悬挂节点的约束和边界值。原因是，正如在 step-17 中所讨论的那样，一旦矩阵中的任意元素被组装到矩阵中，并行矢量类就不能提供对这些元素的访问--部分原因是它们可能不再存在于当前的处理器中，而是被运到了不同的机器上。

// - 我们计算右手边的方式（考虑到介绍中的公式）可能不是最优雅的，但对于重点在某个完全不同的地方的程序来说是可以的。

  template <int dim>
  void LaplaceProblem<dim>::assemble_system()
  {
    TimerOutput::Scope t(computing_timer, "assembly");

    const QGauss<dim> quadrature_formula(fe.degree + 1);

    FEValues<dim> fe_values(fe,
                            quadrature_formula,
                            update_values | update_gradients |
                              update_quadrature_points | update_JxW_values);

    const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
    const unsigned int n_q_points    = quadrature_formula.size();

    FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
    Vector<double>     cell_rhs(dofs_per_cell);

    std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);

    for (const auto &cell : dof_handler.active_cell_iterators())
      if (cell->is_locally_owned())
        {
          cell_matrix = 0.;
          cell_rhs    = 0.;

          fe_values.reinit(cell);

          for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
            {
              const double rhs_value =
                (fe_values.quadrature_point(q_point)[1] >
                     0.5 +
                       0.25 * std::sin(4.0 * numbers::PI *
                                       fe_values.quadrature_point(q_point)[0]) ?
                   1. :
                   -1.);

              for (unsigned int i = 0; i < dofs_per_cell; ++i)
                {
                  for (unsigned int j = 0; j < dofs_per_cell; ++j)
                    cell_matrix(i, j) += fe_values.shape_grad(i, q_point) *
                                         fe_values.shape_grad(j, q_point) *
                                         fe_values.JxW(q_point);

                  cell_rhs(i) += rhs_value *                         //
                                 fe_values.shape_value(i, q_point) * //
                                 fe_values.JxW(q_point);
                }
            }

          cell->get_dof_indices(local_dof_indices);
          constraints.distribute_local_to_global(cell_matrix,
                                                 cell_rhs,
                                                 local_dof_indices,
                                                 system_matrix,
                                                 system_rhs);
        }

// 注意，上面的装配只是一个局部操作。因此，为了形成 "全局 "线性系统，需要在所有处理器之间进行同步。这可以通过调用函数compress()来实现。参见 @ref GlossCompress "压缩分布式对象"，以了解更多关于compress()的设计目的的信息。

    system_matrix.compress(VectorOperation::add);
    system_rhs.compress(VectorOperation::add);
  }

//  @sect4{LaplaceProblem::solve}

// 尽管在可能是数以万计的处理器上求解线性系统到目前为止并不是一项微不足道的工作，但完成这项工作的函数--至少在外表上--相对简单。大部分的部分你都见过了。真正值得一提的只有两件事。

// - 解算器和预处理器是建立在PETSc和Trilinos功能的deal.II包装上的。众所周知，大规模并行线性求解器的主要瓶颈实际上不是处理器之间的通信，而是很难产生能够很好地扩展到大量处理器的预处理程序。在21世纪前十年的后半段，代数多网格（AMG）方法在这种情况下显然是非常有效的，我们将使用其中的一种方法--要么是可以通过PETSc接口的Hypre软件包的BoomerAMG实现，要么是由ML提供的预处理程序，它是Trilinos的一部分--用于当前的程序。解算器本身的其余部分是模板，之前已经展示过了。由于线性系统是对称和正定的，我们可以使用CG方法作为外解器。

// - 最终，我们想要一个向量，它不仅存储了当前处理器拥有的自由度的解的元素，而且还存储了所有其他本地相关的自由度。另一方面，求解器本身需要一个在处理器之间唯一分割的向量，没有任何重叠。因此，我们在这个函数的开头创建一个具有这些特性的向量，用它来求解线性系统，并在最后才把它分配给我们想要的向量。这最后一步确保所有的鬼魂元素也在必要时被复制。

  template <int dim>
  void LaplaceProblem<dim>::solve()
  {
    TimerOutput::Scope t(computing_timer, "solve");
    LA::MPI::Vector    completely_distributed_solution(locally_owned_dofs,
                                                    mpi_communicator);

    SolverControl solver_control(dof_handler.n_dofs(), 1e-12);

#ifdef USE_PETSC_LA
    LA::SolverCG solver(solver_control, mpi_communicator);
#else
    LA::SolverCG solver(solver_control);
#endif

    LA::MPI::PreconditionAMG preconditioner;

    LA::MPI::PreconditionAMG::AdditionalData data;

#ifdef USE_PETSC_LA
    data.symmetric_operator = true;
#else
/* Trilinos的默认值是好的  */
#endif
    preconditioner.initialize(system_matrix, data);

    solver.solve(system_matrix,
                 completely_distributed_solution,
                 system_rhs,
                 preconditioner);

    pcout << "   Solved in " << solver_control.last_step() << " iterations."
          << std::endl;

    constraints.distribute(completely_distributed_solution);

    locally_relevant_solution = completely_distributed_solution;
  }

//  @sect4{LaplaceProblem::refine_grid}

// 估计误差和细化网格的函数又与  step-6  中的函数几乎完全一样。唯一不同的是，标志着要细化的单元格的函数现在在命名空间  parallel::distributed::GridRefinement  中 -- 这个命名空间的函数可以在所有参与的处理器之间进行通信，并确定全局阈值，用于决定哪些单元格要细化，哪些要粗化。

// 注意，我们不需要对KellyErrorEstimator类做任何特殊处理：我们只是给它一个向量，其元素数量与本地三角形的单元（本地拥有的单元、幽灵单元和人工单元）一样多，但它只填入那些对应于本地拥有的单元的条目。

  template <int dim>
  void LaplaceProblem<dim>::refine_grid()
  {
    TimerOutput::Scope t(computing_timer, "refine");

    Vector<float> estimated_error_per_cell(triangulation.n_active_cells());
    KellyErrorEstimator<dim>::estimate(
      dof_handler,
      QGauss<dim - 1>(fe.degree + 1),
      std::map<types::boundary_id, const Function<dim> *>(),
      locally_relevant_solution,
      estimated_error_per_cell);
    parallel::distributed::GridRefinement::refine_and_coarsen_fixed_number(
      triangulation, estimated_error_per_cell, 0.3, 0.03);
    triangulation.execute_coarsening_and_refinement();
  }

//  @sect4{LaplaceProblem::output_results}

// 与 step-6 中的相应函数相比，这里的函数要复杂一点。有两个原因：第一个原因是，我们不只是想输出解决方案，还想输出每个单元的处理器（即它在哪个 "子域"）。其次，正如在 step-17 和 step-18 中详细讨论的那样，生成图形数据可能是并行化的一个瓶颈。在 step-18 中，我们将这一步骤从实际计算中移出，而是将其转移到一个单独的程序中，随后将各个处理器的输出合并到一个文件中。但这并不具规模：如果处理器的数量很大，这可能意味着在单个处理器上合并数据的步骤后来成为程序中运行时间最长的部分，或者它可能产生一个大到无法再可视化的文件。我们在这里遵循一个更合理的方法，即为每个MPI进程创建单独的文件，并将其留给可视化程序来理解。

// 首先，函数的顶部看起来和平时一样。除了附加解决方案向量（包含所有本地相关元素的条目，而不仅仅是本地拥有的元素）外，我们还附加一个数据向量，为每个单元存储该单元所属的子域。这稍微有点棘手，因为当然不是每个处理器都知道每个单元。因此，我们附加的向量有一个当前处理器在其网格中拥有的每个单元的条目（本地拥有的单元、幽灵单元和人造单元），但DataOut类将忽略所有对应于不属于当前处理器的单元的条目。因此，我们在这些向量条目中写入什么值实际上并不重要：我们只需用当前MPI进程的编号（即当前进程的子域_id）来填充整个向量；这就正确地设置了我们关心的值，即对应于本地拥有的单元的条目，而为所有其他元素提供了错误的值--但无论如何这些都会被忽略。

  template <int dim>
  void LaplaceProblem<dim>::output_results(const unsigned int cycle) const
  {
    DataOut<dim> data_out;
    data_out.attach_dof_handler(dof_handler);
    data_out.add_data_vector(locally_relevant_solution, "u");

    Vector<float> subdomain(triangulation.n_active_cells());
    for (unsigned int i = 0; i < subdomain.size(); ++i)
      subdomain(i) = triangulation.locally_owned_subdomain();
    data_out.add_data_vector(subdomain, "subdomain");

    data_out.build_patches();

// 下一步是把这些数据写到磁盘上。在MPI-IO的帮助下，我们最多可以并行写入8个VTU文件。此外，还产生了一个PVTU记录，它将写入的VTU文件分组。

    data_out.write_vtu_with_pvtu_record(
      "./", "solution", cycle, mpi_communicator, 2, 8);
  }

//  @sect4{LaplaceProblem::run}

// 控制程序整体行为的函数又和  step-6  中的一样。小的区别是使用 pcout instead of std::cout 来输出到控制台（也见 step-17 ），而且我们只在最多涉及32个处理器的情况下产生图形输出。如果没有这个限制，人们很容易在没有阅读这个程序的情况下粗心大意地运行这个程序，从而导致集群互连中断，并填满任何可用的文件系统 :-)

// 与 step-6 的一个功能上的区别是使用了一个正方形域，并且我们从一个稍细的网格开始（5个全局细化周期）--在4个单元上开始显示一个大规模的%并行程序没有什么意义（尽管承认在1024单元上开始显示的意义只是稍强）。

  template <int dim>
  void LaplaceProblem<dim>::run()
  {
    pcout << "Running with "
#ifdef USE_PETSC_LA
          << "PETSc"
#else
          << "Trilinos"
#endif
          << " on " << Utilities::MPI::n_mpi_processes(mpi_communicator)
          << " MPI rank(s)..." << std::endl;

    const unsigned int n_cycles = 8;
    for (unsigned int cycle = 0; cycle < n_cycles; ++cycle)
      {
        pcout << "Cycle " << cycle << ':' << std::endl;

        if (cycle == 0)
          {
            GridGenerator::hyper_cube(triangulation);
            triangulation.refine_global(5);
          }
        else
          refine_grid();

        setup_system();

        pcout << "   Number of active cells:       "
              << triangulation.n_global_active_cells() << std::endl
              << "   Number of degrees of freedom: " << dof_handler.n_dofs()
              << std::endl;

        assemble_system();
        solve();

        if (Utilities::MPI::n_mpi_processes(mpi_communicator) <= 32)
          {
            TimerOutput::Scope t(computing_timer, "output");
            output_results(cycle);
          }

        computing_timer.print_summary();
        computing_timer.reset();

        pcout << std::endl;
      }
  }
} // namespace Step40

//  @sect4{main()}

// 最后一个函数，  main()  ，同样具有与所有其他程序相同的结构，特别是  step-6  。像其他使用MPI的程序一样，我们必须初始化和最终确定MPI，这是用辅助对象  Utilities::MPI::MPI_InitFinalize.  完成的。该类的构造函数也初始化了依赖MPI的库，如p4est、PETSc、SLEPc和Zoltan（尽管最后两个在本教程中没有使用）。这里的顺序很重要：在这些库被初始化之前，我们不能使用它们，所以在创建  Utilities::MPI::MPI_InitFinalize.  的实例之前做任何事情都没有意义。

// 在求解器完成后，LaplaceProblem解构器将运行，然后是 Utilities::MPI::MPI_InitFinalize::~MPI_InitFinalize().  这个顺序也很重要： Utilities::MPI::MPI_InitFinalize::~MPI_InitFinalize() 调用 PetscFinalize （以及其他库的最终确定函数），这将删除任何正在使用的PETSc对象。这必须在我们解构拉普拉斯求解器之后进行，以避免双重删除错误。幸运的是，由于C++的析构器调用顺序规则，我们不需要担心这些：一切都以正确的顺序发生（即，与构造顺序相反）。由 Utilities::MPI::MPI_InitFinalize::~MPI_InitFinalize() 调用的最后一个函数是 MPI_Finalize ：也就是说，一旦这个对象被析构，程序应该退出，因为MPI将不再可用。

int main(int argc, char *argv[])
{
  try
    {
      using namespace dealii;
      using namespace Step40;

      Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);

      LaplaceProblem<2> laplace_problem_2d;
      laplace_problem_2d.run();
    }
  catch (std::exception &exc)
    {
      std::cerr << std::endl
                << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Exception on processing: " << std::endl
                << exc.what() << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;

      return 1;
    }
  catch (...)
    {
      std::cerr << std::endl
                << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Unknown exception!" << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;
      return 1;
    }

  return 0;
}


/* $Id: step-15.cc 27656 2012-11-21 13:12:20Z bangerth $ */
/* Author: Sven Wetterauer, University of Heidelberg, 2012 */

/*    $Id: step-15.cc 27656 2012-11-21 13:12:20Z bangerth $       */
/*                                                                */
/*    Copyright (C) 2012 by the deal.II authors */
/*                                                                */
/*    This file is subject to QPL and may not be  distributed     */
/*    without copyright and license information. Please refer     */
/*    to the file deal.II/doc/license.html for the  text  and     */
/*    further information on this license.                        */

// @sect3{Include files}

// The first few files have already been covered in previous examples and will
// thus not be further commented on.
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/function.h>
#include <deal.II/base/logstream.h>
#include <deal.II/base/utilities.h>

#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/sparse_matrix.h>
#include <deal.II/lac/compressed_sparsity_pattern.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/precondition.h>
#include <deal.II/lac/constraint_matrix.h>

#include <deal.II/grid/tria.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
#include <deal.II/grid/tria_boundary_lib.h>
#include <deal.II/grid/grid_refinement.h>

#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/dofs/dof_tools.h>

#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/fe_q.h>

#include <deal.II/numerics/vector_tools.h>
#include <deal.II/numerics/matrix_tools.h>
#include <deal.II/numerics/data_out.h>
#include <deal.II/numerics/error_estimator.h>

#include <fstream>
#include <iostream>

// We will use adaptive mesh refinement between Newton interations. To do so,
// we need to be able to work with a solution on the new mesh, although it was
// computed on the old one. The SolutionTransfer class transfers the solution
// from the old to the new mesh:

#include <deal.II/numerics/solution_transfer.h>

// We then open a namepsace for this program and import everything from the
// dealii namespace into it, as in previous programs:
namespace Step15
{
  using namespace dealii;

  // @sect3{The MinimalSurfaceProblem class template}

  // The class template is basically the same as in step-6.  Three additions
  // are made:
  // - There are two solution vectors, one for the Newton update
  //   $\delta u^n$, and one for the current iterate $u^n$.
  // - The setup_system function takes an argument that denotes whether
  //   this is the first time it is called or not. The difference is that the
  //   first time around we need to distributed degrees of freedom and set the
  //   solution vector for $u^n$ to the correct size. The following times, the
  //   function is called after we have already done these steps as part of
  //   refining the mesh in refine_mesh.
  // - We then also need new functions: set_boundary_values()
  //   takes care of setting the boundary values on the solution vector
  //   correctly, as discussed at the end of the
  //   introduction. compute_residual() is a function that computes
  //   the norm of the nonlinear (discrete) residual. We use this function to
  //   monitor convergence of the Newton iteration. The function takes a step
  //   length $\alpha^n$ as argument to compute the residual of $u^n + \alpha^n
  //   \; \delta u^n$. This is something one typically needs for step length
  //   control, although we will not use this feature here. Finally,
  //   determine_step_length() computes the step length $\alpha^n$
  //   in each Newton iteration. As discussed in the introduction, we here use a
  //   fixed step length and leave implementing a better strategy as an
  //   exercise.

  template <int dim>
  class MinimalSurfaceProblem
  {
  public:
    MinimalSurfaceProblem ();
    ~MinimalSurfaceProblem ();

    void run ();

  private:
    void setup_system (const bool initial_step);
    void assemble_system ();
    void solve ();
    void refine_mesh ();
    void set_boundary_values ();
    double compute_residual (const double alpha) const;
    double determine_step_length () const;

    Triangulation<dim>   triangulation;

    DoFHandler<dim>      dof_handler;
    FE_Q<dim>            fe;

    ConstraintMatrix     hanging_node_constraints;

    SparsityPattern      sparsity_pattern;
    SparseMatrix<double> system_matrix;

    Vector<double>       present_solution;
    Vector<double>       newton_update;
    Vector<double>       system_rhs;
  };

  // @sect3{Boundary condition}

  // The boundary condition is implemented just like in step-4.  It is chosen
  // as $g(x,y)=\sin(2 \pi (x+y))$:

  template <int dim>
  class BoundaryValues : public Function<dim>
  {
  public:
    BoundaryValues () : Function<dim>() {}

    virtual double value (const Point<dim>   &p,
                          const unsigned int  component = 0) const;
  };

  template <int dim>
  double BoundaryValues<dim>::value (const Point<dim> &p,
                                     const unsigned int /*component*/) const
  {
    return std::sin(2 * numbers::PI * (p[0]+p[1]));
  }

  // @sect3{The MinimalSurfaceProblem class implementation}

  // @sect4{MinimalSurfaceProblem::MinimalSurfaceProblem}

  // The constructor and destructor of the class are the same as in the first
  // few tutorials.

  template <int dim>
  MinimalSurfaceProblem<dim>::MinimalSurfaceProblem ()
    :
    dof_handler (triangulation),
    fe (2)
  {}

  template <int dim>
  MinimalSurfaceProblem<dim>::~MinimalSurfaceProblem ()
  {
    dof_handler.clear ();
  }

  // @sect4{MinimalSurfaceProblem::setup_system}

  // As always in the setup-system function, we setup the variables of the
  // finite element method. There are same differences to step-6, because
  // there we start solving the PDE from scratch in every refinement cycle
  // whereas here we need to take the solution from the previous mesh onto the
  // current mesh. Consequently, we can't just reset solution vectors. The
  // argument passed to this function thus indicates whether we can
  // distributed degrees of freedom (plus compute constraints) and set the
  // solution vector to zero or whether this has happened elsewhere already
  // (specifically, in refine_mesh()).

  template <int dim>
  void MinimalSurfaceProblem<dim>::setup_system (const bool initial_step)
  {
    if (initial_step)
      {
        dof_handler.distribute_dofs (fe);
        present_solution.reinit (dof_handler.n_dofs());

        hanging_node_constraints.clear ();
        DoFTools::make_hanging_node_constraints (dof_handler,
                                                 hanging_node_constraints);
        hanging_node_constraints.close ();
      }

    // The remaining parts of the function are the same as in step-6.

    newton_update.reinit (dof_handler.n_dofs());
    system_rhs.reinit (dof_handler.n_dofs());

    CompressedSparsityPattern c_sparsity(dof_handler.n_dofs());
    DoFTools::make_sparsity_pattern (dof_handler, c_sparsity);

    hanging_node_constraints.condense (c_sparsity);

    sparsity_pattern.copy_from(c_sparsity);
    system_matrix.reinit (sparsity_pattern);
  }

  // @sect4{MinimalSurfaceProblem::assemble_system}

  // This function does the same as in the previous tutorials except that now,
  // of course, the matrix and right hand side functions depend on the
  // previous iteration's solution. As discussed in the introduction, we need
  // to use zero boundary values for the Newton updates; we compute them at
  // the end of this function.
  //
  // The top of the function contains the usual boilerplate code, setting up
  // the objects that allow us to evaluate shape functions at quadrature
  // points and temporary storage locations for the local matrices and
  // vectors, as well as for the gradients of the previous solution at the
  // quadrature points. We then start the loop over all cells:
  template <int dim>
  void MinimalSurfaceProblem<dim>::assemble_system ()
  {
    const QGauss<dim>  quadrature_formula(3);

    system_matrix = 0;
    system_rhs = 0;

    FEValues<dim> fe_values (fe, quadrature_formula,
                             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_matrix (dofs_per_cell, dofs_per_cell);
    Vector<double>               cell_rhs (dofs_per_cell);

    std::vector<Tensor<1, dim> > old_solution_gradients(n_q_points);

    std::vector<unsigned int>    local_dof_indices (dofs_per_cell);

    typename DoFHandler<dim>::active_cell_iterator
    cell = dof_handler.begin_active(),
    endc = dof_handler.end();
    for (; cell!=endc; ++cell)
      {
        cell_matrix = 0;
        cell_rhs = 0;

        fe_values.reinit (cell);

        // For the assembly of the linear system, we have to obtain the values
        // of the previous solution's gradients at the quadrature
        // points. There is a standard way of doing this: the
        // FEValues::get_function function takes a vector that represents a
        // finite element field defined on a DoFHandler, and evaluates the
        // gradients of this field at the quadrature points of the cell with
        // which the FEValues object has last been reinitialized. The values
        // of the gradients at all quadrature points are then written into the
        // second argument:
        fe_values.get_function_gradients(present_solution,
                                         old_solution_gradients);

        // With this, we can then do the integration loop over all quadrature
        // points and shape functions.  Having just computed the gradients of
        // the old solution in the quadrature points, we are able to compute
        // the coefficients $a_{n}$ in these points.  The assembly of the
        // system itself then looks similar to what we always do with the
        // exception of the nonlinear terms, as does copying the results from
        // the local objects into the global ones:
        for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
          {
            const double coeff
              = 1.0 / std::sqrt(1 +
                                old_solution_gradients[q_point] *
                                old_solution_gradients[q_point]);

            for (unsigned int i=0; i<dofs_per_cell; ++i)
              {
                for (unsigned int j=0; j<dofs_per_cell; ++j)
                  {
                    cell_matrix(i, j) += (fe_values.shape_grad(i, q_point)
                                          * coeff
                                          * (fe_values.shape_grad(j, q_point)
                                             -
                                             coeff * coeff
                                             * (fe_values.shape_grad(j, q_point)
                                                *
                                                old_solution_gradients[q_point])
                                             * old_solution_gradients[q_point]
                                            )
                                          * fe_values.JxW(q_point));
                  }

                cell_rhs(i) -= (fe_values.shape_grad(i, q_point)
                                * coeff
                                * old_solution_gradients[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);
          }
      }

    // Finally, we remove hanging nodes from the system and apply zero
    // boundary values to the linear system that defines the Newton updates
    // $\delta u^n$:
    hanging_node_constraints.condense (system_matrix);
    hanging_node_constraints.condense (system_rhs);

    std::map<unsigned int,double> boundary_values;
    VectorTools::interpolate_boundary_values (dof_handler,
                                              0,
                                              ZeroFunction<dim>(),
                                              boundary_values);
    MatrixTools::apply_boundary_values (boundary_values,
                                        system_matrix,
                                        newton_update,
                                        system_rhs);
  }

  // @sect4{MinimalSurfaceProblem::solve}

  // The solve function is the same as always. At the end of the solution
  // process we update the current solution by setting
  // $u^{n+1}=u^n+\alpha^n\;\delta u^n$.
  template <int dim>
  void MinimalSurfaceProblem<dim>::solve ()
  {
    SolverControl solver_control (system_rhs.size(),
                                  system_rhs.l2_norm()*1e-6);
    SolverCG<>    solver (solver_control);

    PreconditionSSOR<> preconditioner;
    preconditioner.initialize(system_matrix, 1.2);

    solver.solve (system_matrix, newton_update, system_rhs,
                  preconditioner);

    hanging_node_constraints.distribute (newton_update);

    const double alpha = determine_step_length();
    present_solution.add (alpha, newton_update);
  }

  // @sect4{MinimalSurfaceProblem::refine_mesh}

  // The first part of this function is the same as in step-6... However,
  // after refining the mesh we have to transfer the old solution to the new
  // one which we do with the help of the SolutionTransfer class. The process
  // is slightly convoluted, so let us describe it in detail:
  template <int dim>
  void MinimalSurfaceProblem<dim>::refine_mesh ()
  {
    Vector<float> estimated_error_per_cell (triangulation.n_active_cells());

    KellyErrorEstimator<dim>::estimate (dof_handler,
                                        QGauss<dim-1>(3),
                                        typename FunctionMap<dim>::type(),
                                        present_solution,
                                        estimated_error_per_cell);

    GridRefinement::refine_and_coarsen_fixed_number (triangulation,
                                                     estimated_error_per_cell,
                                                     0.3, 0.03);

    // Then we need an additional step: if, for example, you flag a cell that
    // is once more refined than its neighbor, and that neighbor is not
    // flagged for refinement, we would end up with a jump of two refinement
    // levels across a cell interface.  To avoid these situations, the library
    // will silently also have to refine the neighbor cell once. It does so by
    // calling the Triangulation::prepare_coarsening_and_refinement function
    // before actually doing the refinement and coarsening.  This function
    // flags a set of additional cells for refinement or coarsening, to
    // enforce rules like the one-hanging-node rule.  The cells that are
    // flagged for refinement and coarsening after calling this function are
    // exactly the ones that will actually be refined or coarsened. Usually,
    // you don't have to do this by hand
    // (Triangulation::execute_coarsening_and_refinement does this for
    // you). However, we need to initialize the SolutionTransfer class and it
    // needs to know the final set of cells that will be coarsened or refined
    // in order to store the data from the old mesh and transfer to the new
    // one. Thus, we call the function by hand:
    triangulation.prepare_coarsening_and_refinement ();

    // With this out of the way, we initialize a SolutionTransfer object with
    // the present DoFHandler and attach the solution vector to it, followed
    // by doing the actual refinement and distribution of degrees of freedom
    // on the new mesh
    SolutionTransfer<dim> solution_transfer(dof_handler);
    solution_transfer.prepare_for_coarsening_and_refinement(present_solution);

    triangulation.execute_coarsening_and_refinement();

    dof_handler.distribute_dofs(fe);

    // Finally, we retrieve the old solution interpolated to the new
    // mesh. Since the SolutionTransfer function does not actually store the
    // values of the old solution, but rather indices, we need to preserve the
    // old solution vector until we have gotten the new interpolated
    // values. Thus, we have the new values written into a temporary vector,
    // and only afterwards write them into the solution vector object. Once we
    // have this solution we have to make sure that the $u^n$ we now have
    // actually has the correct boundary values. As explained at the end of
    // the introduction, this is not automatically the case even if the
    // solution before refinement had the correct boundary values, and so we
    // have to explicitly make sure that it now has:
    Vector<double> tmp(dof_handler.n_dofs());
    solution_transfer.interpolate(present_solution, tmp);
    present_solution = tmp;

    set_boundary_values ();

    // On the new mesh, there are different hanging nodes, which we have to
    // compute again. To ensure there are no hanging nodes of the old mesh in
    // the object, it's first cleared.  To be on the safe side, we then also
    // make sure that the current solution's vector entries satisfy the
    // hanging node constraints:

    hanging_node_constraints.clear();

    DoFTools::make_hanging_node_constraints(dof_handler,
                                            hanging_node_constraints);
    hanging_node_constraints.close();

    hanging_node_constraints.distribute (present_solution);

    // We end the function by updating all the remaining data structures,
    // indicating to setup_dofs() that this is not the first
    // go-around and that it needs to preserve the content of the solution
    // vector:
    setup_system (false);
  }

  // @sect4{MinimalSurfaceProblem::set_boundary_values}

  // The next function ensures that the solution vector's entries respect the
  // boundary values for our problem.  Having refined the mesh (or just
  // started computations), there might be new nodal points on the
  // boundary. These have values that are simply interpolated from the
  // previous mesh (or are just zero), instead of the correct boundary
  // values. This is fixed up by setting all boundary nodes explicit to the
  // right value:
  template <int dim>
  void MinimalSurfaceProblem<dim>::set_boundary_values ()
  {
    std::map<unsigned int, double> boundary_values;
    VectorTools::interpolate_boundary_values (dof_handler,
                                              0,
                                              BoundaryValues<dim>(),
                                              boundary_values);
    for (std::map<unsigned int, double>::const_iterator
         p = boundary_values.begin();
         p != boundary_values.end(); ++p)
      present_solution(p->first) = p->second;
  }

  // @sect4{MinimalSurfaceProblem::compute_residual}

  // In order to monitor convergence, we need a way to compute the norm of the
  // (discrete) residual, i.e., the norm of the vector
  // $\left<F(u^n),\varphi_i\right>$ with $F(u)=-\nabla \cdot \left(
  // \frac{1}{\sqrt{1+|\nabla u|^{2}}}\nabla u \right)$ as discussed in the
  // introduction. It turns out that (although we don't use this feature in
  // the current version of the program) one needs to compute the residual
  // $\left<F(u^n+\alpha^n\;\delta u^n),\varphi_i\right>$ when determining
  // optimal step lengths, and so this is what we implement here: the function
  // takes the step length $\alpha^n$ as an argument. The original
  // functionality is of course obtained by passing a zero as argument.
  //
  // In the function below, we first set up a vector for the residual, and
  // then a vector for the evaluation point $u^n+\alpha^n\;\delta u^n$. This
  // is followed by the same boilerplate code we use for all integration
  // operations:
  template <int dim>
  double MinimalSurfaceProblem<dim>::compute_residual (const double alpha) const
  {
    Vector<double> residual (dof_handler.n_dofs());

    Vector<double> evaluation_point (dof_handler.n_dofs());
    evaluation_point = present_solution;
    evaluation_point.add (alpha, newton_update);

    const QGauss<dim>  quadrature_formula(3);
    FEValues<dim> fe_values (fe, quadrature_formula,
                             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();

    Vector<double>               cell_rhs (dofs_per_cell);
    std::vector<Tensor<1, dim> > gradients(n_q_points);

    std::vector<unsigned int>    local_dof_indices (dofs_per_cell);

    typename DoFHandler<dim>::active_cell_iterator
    cell = dof_handler.begin_active(),
    endc = dof_handler.end();
    for (; cell!=endc; ++cell)
      {
        cell_rhs = 0;
        fe_values.reinit (cell);

        // The actual computation is much as in
        // assemble_system(). We first evaluate the gradients of
        // $u^n+\alpha^n\,\delta u^n$ at the quadrature points, then compute
        // the coefficient $a_n$, and then plug it all into the formula for
        // the residual:
        fe_values.get_function_gradients (evaluation_point,
                                          gradients);

        for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
          {
            const double coeff = 1/std::sqrt(1 +
                                             gradients[q_point] *
                                             gradients[q_point]);

            for (unsigned int i = 0; i < dofs_per_cell; ++i)
              cell_rhs(i) -= (fe_values.shape_grad(i, q_point)
                              * coeff
                              * gradients[q_point]
                              * fe_values.JxW(q_point));
          }

        cell->get_dof_indices (local_dof_indices);
        for (unsigned int i=0; i<dofs_per_cell; ++i)
          residual(local_dof_indices[i]) += cell_rhs(i);
      }

    // At the end of this function we also have to deal with the hanging node
    // constraints and with the issue of boundary values. With regard to the
    // latter, we have to set to zero the elements of the residual vector for
    // all entries that correspond to degrees of freedom that sit at the
    // boundary. The reason is that because the value of the solution there is
    // fixed, they are of course no "real" degrees of freedom and so, strictly
    // speaking, we shouldn't have assembled entries in the residual vector
    // for them. However, as we always do, we want to do exactly the same
    // thing on every cell and so we didn't not want to deal with the question
    // of whether a particular degree of freedom sits at the boundary in the
    // integration above. Rather, we will simply set to zero these entries
    // after the fact. To this end, we first need to determine which degrees
    // of freedom do in fact belong to the boundary and then loop over all of
    // those and set the residual entry to zero. This happens in the following
    // lines which we have already seen used in step-11:
    hanging_node_constraints.condense (residual);

    std::vector<bool> boundary_dofs (dof_handler.n_dofs());
    DoFTools::extract_boundary_dofs (dof_handler,
                                     ComponentMask(),
                                     boundary_dofs);
    for (unsigned int i=0; i<dof_handler.n_dofs(); ++i)
      if (boundary_dofs[i] == true)
        residual(i) = 0;

    // At the end of the function, we return the norm of the residual:
    return residual.l2_norm();
  }

  // @sect4{MinimalSurfaceProblem::determine_step_length}

  // As discussed in the introduction, Newton's method frequently does not
  // converge if we always take full steps, i.e., compute $u^{n+1}=u^n+\delta
  // u^n$. Rather, one needs a damping parameter (step length) $\alpha^n$ and
  // set $u^{n+1}=u^n+\alpha^n\; delta u^n$. This function is the one called
  // to compute $\alpha^n$.
  //
  // Here, we simply always return 0.1. This is of course a sub-optimal
  // choice: ideally, what one wants is that the step size goes to one as we
  // get closer to the solution, so that we get to enjoy the rapid quadratic
  // convergence of Newton's method. We will discuss better strategies below
  // in the results section.
  template <int dim>
  double MinimalSurfaceProblem<dim>::determine_step_length() const
  {
    return 0.1;
  }

  // @sect4{MinimalSurfaceProblem::run}

  // In the run function, we build the first grid and then have the top-level
  // logic for the Newton iteration. The function has two variables, one that
  // indicates whether this is the first time we solve for a Newton update and
  // one that indicates the refinement level of the mesh:
  template <int dim>
  void MinimalSurfaceProblem<dim>::run ()
  {
    unsigned int refinement = 0;
    bool         first_step = true;

    // As described in the introduction, the domain is the unit disk around
    // the origin, created in the same way as shown in step-6. The mesh is
    // globally refined twice followed later on by several adaptive cycles:
    GridGenerator::hyper_ball (triangulation);
    static const HyperBallBoundary<dim> boundary;
    triangulation.set_boundary (0, boundary);
    triangulation.refine_global(2);

    // The Newton iteration starts next. During the first step we do not have
    // information about the residual prior to this step and so we continue
    // the Newton iteration until we have reached at least one iteration and
    // until residual is less than $10^{-3}$.
    //
    // At the beginning of the loop, we do a bit of setup work. In the first
    // go around, we compute the solution on the twice globally refined mesh
    // after setting up the basic data structures. In all following mesh
    // refinement loops, the mesh will be refined adaptively.
    double previous_res = 0;
    while (first_step || (previous_res>1e-3))
      {
        if (first_step == true)
          {
            std::cout << "******** Initial mesh "
                      << " ********"
                      << std::endl;

            setup_system (true);
            set_boundary_values ();
          }
        else
          {
            ++refinement;
            std::cout << "******** Refined mesh " << refinement
                      << " ********"
                      << std::endl;

            refine_mesh();
          }

        // On every mesh we do exactly five Newton steps. We print the initial
        // residual here and then start the iterations on this mesh.
        //
        // In every Newton step the system matrix and the right hand side have
        // to be computed first, after which we store the norm of the right
        // hand side as the residual to check against when deciding whether to
        // stop the iterations. We then solve the linear system (the function
        // also updates $u^{n+1}=u^n+\alpha^n\;\delta u^n$) and output the
        // residual at the end of this Newton step:
        std::cout << "  Initial residual: "
                  << compute_residual(0)
                  << std::endl;

        for (unsigned int inner_iteration=0; inner_iteration<5; ++inner_iteration)
          {
            assemble_system ();
            previous_res = system_rhs.l2_norm();

            solve ();

            first_step = false;
            std::cout << "  Residual: "
                      << compute_residual(0)
                      << std::endl;
          }

        // Every fifth iteration, i.e., just before we refine the mesh again,
        // we output the solution as well as the Newton update. This happens
        // as in all programs before:
        DataOut<dim> data_out;

        data_out.attach_dof_handler (dof_handler);
        data_out.add_data_vector (present_solution, "solution");
        data_out.add_data_vector (newton_update, "update");
        data_out.build_patches ();
        const std::string filename = "solution-" +
                                     Utilities::int_to_string (refinement, 2) +
                                     ".vtk";
        std::ofstream output (filename.c_str());
        data_out.write_vtk (output);

      }
  }
}

// @sect4{The main function}

// Finally the main function. This follows the scheme of all other main
// functions:
int main ()
{
  try
    {
      using namespace dealii;
      using namespace Step15;

      deallog.depth_console (0);

      MinimalSurfaceProblem<2> laplace_problem_2d;
      laplace_problem_2d.run ();
    }
  catch (std::exception &exc)
    {
      std::cerr << std::endl << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Exception on processing: " << std::endl
                << exc.what() << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;

      return 1;
    }
  catch (...)
    {
      std::cerr << std::endl << std::endl
                << "----------------------------------------------------"
                << std::endl;
      std::cerr << "Unknown exception!" << std::endl
                << "Aborting!" << std::endl
                << "----------------------------------------------------"
                << std::endl;
      return 1;
    }
  return 0;
}


//  Copyright John Maddock 2007.
//  Copyright Paul A. Bristow 2010

//  Use, modification and distribution are subject to the
//  Boost Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

// Note that this file contains quickbook mark-up as well as code
// and comments, don't change any of the special comment mark-ups!

#include <iostream>
using std::cout;  using std::endl;
#include <cerrno> // for ::errno

//[policy_eg_4

/*`
Suppose we want `C::foo()` to behave in a C-compatible way and set
`::errno` on error rather than throwing any exceptions.

We'll begin by including the needed header for our function:
*/

#include <boost/math/special_functions.hpp>
//using boost::math::tgamma; // Not needed because using C::tgamma.

/*`
Open up the "C" namespace that we'll use for our functions, and
define the policy type we want: in this case a C-style one that sets
::errno and returns a standard value, rather than throwing exceptions.

Any policies we don't specify here will inherit the defaults.
*/

namespace C
{ // To hold our C-style policy.
  //using namespace boost::math::policies; or explicitly:
  using boost::math::policies::policy;

  using boost::math::policies::domain_error;
  using boost::math::policies::pole_error;
  using boost::math::policies::overflow_error;
  using boost::math::policies::evaluation_error;
  using boost::math::policies::errno_on_error;

  typedef policy<
     domain_error<errno_on_error>,
     pole_error<errno_on_error>,
     overflow_error<errno_on_error>,
     evaluation_error<errno_on_error>
  > c_policy;

/*`
All we need do now is invoke the BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS
macro passing our policy type c_policy as the single argument:
*/

BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(c_policy)

} // close namespace C

/*`
We now have a set of forwarding functions defined in namespace C
that all look something like this:

``
template <class RealType>
inline typename boost::math::tools::promote_args<RT>::type
   tgamma(RT z)
{
   return boost::math::tgamma(z, c_policy());
}
``

So that when we call `C::tgamma(z)`, we really end up calling
`boost::math::tgamma(z, C::c_policy())`:
*/

int main()
{
   errno = 0;
   cout << "Result of tgamma(30000) is: "
      << C::tgamma(30000) << endl; // Note using C::tgamma
   cout << "errno = " << errno << endl; // errno = 34
   cout << "Result of tgamma(-10) is: "
      << C::tgamma(-10) << endl;
   cout << "errno = " << errno << endl; // errno = 33, overwriting previous value of 34.
}

/*`

Which outputs:

[pre
Result of C::tgamma(30000) is: 1.#INF
errno = 34
Result of C::tgamma(-10) is: 1.#QNAN
errno = 33
]

This mechanism is particularly useful when we want to define a project-wide policy,
and don't want to modify the Boost source,
or to set project wide build macros (possibly fragile and easy to forget).

*/
//] //[/policy_eg_4]


// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)

// Copyright Paul A. Bristow 2015.
// Copyright Christopher Kormanyos 2015.
// Copyright Nikhar Agrawal 2015.

// This file is written to be included from a Quickbook .qbk document.
// It can be compiled by the C++ compiler, and run. Any output can
// also be added here as comment or included or pasted in elsewhere.
// Caution: this file contains Quickbook markup as well as code
// and comments: don't change any of the special comment markups!

// This file also includes Doxygen-style documentation about the function of the code.
// See http://www.doxygen.org for details.

//! \file

// Below are snippets of code that can be included into a Quickbook file.

#include <iostream>
#include <iomanip>
#include <exception>
#include <typeinfo>
#include <limits>

#include <boost/cstdint.hpp>

//[fixed_point_include_1
#include <boost/fixed_point/fixed_point.hpp>
//] [/fixed_point_include_1]

/*
! Show numeric_limits values for a type.
\tparam T floating-point, fixed-point type.
\param os std::ostream, default @c std::cout
*/

// static int Functions to access template parameters for fixed_point
// that are missing for fundamental integral and floating-point types.
// Version selected on whether is not arithmetic, is floating_point or is integral.

template <typename NumericalType,
          typename EnableType = void>
struct numerical_details
{
  static int get_range     () { return 0; }
  static int get_resolution() { return 0; }
};

/*! Deduce fixed-point if @c std::is_class (so exclude @c bool, @c int...) and not arithmetic (exclude @c float, @c double...).
*/
template <typename NumericalType>
struct numerical_details<NumericalType,
                         typename std::enable_if<   (std::is_arithmetic<NumericalType>::value == false)
                                                 && (std::is_class<NumericalType>::value      == true)>::type>
{
  static int get_range     () { return NumericalType::range; }
  static int get_resolution() { return NumericalType::resolution; }
};

/*! Deduce fundamental floating-point type @c float, @c double or @c long double.
*/

template <typename NumericalType>
struct numerical_details<NumericalType,
                         typename std::enable_if<std::is_floating_point<NumericalType>::value>::type>
{
  static int get_range     () { return 0; }
  static int get_resolution() { return std::numeric_limits<NumericalType>::digits; }
};

/*! Deduce fundamental integral type.
*/
template <typename NumericalType>
struct numerical_details<NumericalType,
                         typename std::enable_if<std::is_integral<NumericalType>::value>::type>
{
  static int get_range     () { return std::numeric_limits<NumericalType>::digits; }
  static int get_resolution() { return 0; }
};

template <typename T>
void show_fixed_point(std::ostream& os = std::cout)
{
  using boost::fixed_point::negatable;

  os.precision(std::numeric_limits<T>::max_digits10);

  os << "Numeric_limits of type: "
     << typeid(T).name()
     << "\n range        = " << numerical_details<T>::get_range() //
     << "\n resolution   = " << numerical_details<T>::get_resolution()
     << "\n radix        = " << std::numeric_limits<T>::radix  // Always 2 for fixed-point.
     << "\n digits       = " << std::numeric_limits<T>::digits; // Does not include any sign bit.

  if (std::is_signed<T>::value == true)
  {
    os << "\n signed "
       << "\n total bits =   " << std::numeric_limits<T>::digits + 1; // DOES include sign bit.
  }

  if (std::numeric_limits<T>::is_exact == false)
  { // epsilon has meaning.
    os << "\n epsilon      = " << std::numeric_limits<T>::epsilon();
  }
  else
  {
    os << "\n exact        = "  << std::numeric_limits<T>::is_exact;
  }

  // Avoid char values showing as a character or squiggle.
  BOOST_CONSTEXPR_OR_CONST bool is_any_character_type = (   std::is_same<T, signed char>::value
                                                         || std::is_same<T, unsigned char>::value
                                                         || std::is_same<T, char16_t>::value
                                                         || std::is_same<T, char32_t>::value);

  os << "\n lowest       = ";
  if(is_any_character_type)
  {
    os << static_cast<boost::int32_t>(std::numeric_limits<T>::lowest());
  }
  else
  {
    os << std::numeric_limits<T>::lowest();
  }

  BOOST_CONSTEXPR_OR_CONST bool is_8bit_character_type = (   std::is_same<T, signed char>::value
                                                          || std::is_same<T, unsigned char>::value);

  os << "\n min          = ";
  if(is_8bit_character_type)
  {
    os << static_cast<boost::int32_t>((std::numeric_limits<T>::min)());
  }
  else
  {
    os << (std::numeric_limits<T>::min)();
  }

  os << "\n max          = ";
  if(is_8bit_character_type)
  {
    os << static_cast<boost::int32_t>((std::numeric_limits<T>::max)());
  }
  else
  {
    os << (std::numeric_limits<T>::max)();
  }

  os << "\n max_exponent = " << std::numeric_limits<T>::max_exponent
     << "\n min_exponent = " << std::numeric_limits<T>::min_exponent
     << "\n digits10     = " << std::numeric_limits<T>::digits10
     << "\n max_digits10 = " << std::numeric_limits<T>::max_digits10
     << "\n"
     << std::endl;
} // template <typename T> void show_fixed_point

int main()
{
  using boost::fixed_point::negatable;

  typedef negatable<15,  -16> fixed_point_type_15m16;
  typedef negatable<11,  -20> fixed_point_type_11m20;
  typedef negatable< 0,  -31> fixed_point_type_0m31;
  typedef negatable<29,   -2> fixed_point_type_29m2;
  typedef negatable<0,  -168> fixed_point_type_0m168;
  typedef negatable<20, -148> fixed_point_type_20m148;

  try
  {
    std::cout.setf(std::ios_base::boolalpha | std::ios_base::showpoint); // Show any trailing zeros.
    std::cout << std::endl;

//[fixed_example_1

    // Show all the significant digits for this particular type.

    // Fundamental (built-in) integral types.
    show_fixed_point<bool>              ();
    show_fixed_point<signed char>       ();
    show_fixed_point<unsigned char>     ();
    show_fixed_point<char16_t>          (); // Shows as type unsigned short.
    show_fixed_point<char32_t>          (); // Shows as type unsigned int.
    show_fixed_point<short int>         ();
    show_fixed_point<unsigned short int>();
    show_fixed_point<int>               ();
    show_fixed_point<unsigned int>      ();

   // Fundamental (built-in) floating-point types.
    show_fixed_point<float>();
    // digits 24 (leaving 8 for decimal exponent).
    // epsilon 1.2e-7.

    show_fixed_point<double>();
    // digits 53 (leaving 10 for decimal exponent).
    // epsilon 2.2e-16.
    show_fixed_point<long double>();
    // Varies with compiler
    // Using MSVC double == long double

//] [/fixed_example_1]

// Some fixed_point types using only a single 8-bit byte (signed char).

//[fixed_point_15m16

    // Some fixed_point types using 32 bits, and more.
    show_fixed_point<fixed_point_type_15m16> (); // Even split bits between range and resolution.
    show_fixed_point<fixed_point_type_11m20> (); // More resolution than range.
    show_fixed_point<fixed_point_type_0m31>  (); // All bits used for resolution.
    show_fixed_point<fixed_point_type_29m2>  (); // Most bits used for range.
    show_fixed_point<fixed_point_type_0m168> ();
    show_fixed_point<fixed_point_type_20m148>();

    //std::cout << "fixed_point_type(123) / 100 = "
    //  << x // 1.22999573 is the nearest representation of decimal digit string 1.23.
    //  << std::endl;
  }
  catch (std::exception ex)
  {
    std::cout << ex.what() << std::endl;
  }
}

/*
//[fixed_point_type_examples_output_1

//] [/fixed_point_type_examples_output_1]
*/