/* Author: Wolfgang Bangerth, University of Texas at Austin, 2000, 2004 */

/*    $Id: step-17.cc 28351 2013-02-12 23:23:18Z heister $       */
/*                                                                */
/*    Copyright (C) 2000, 2004-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.                        */

// First the usual assortment of header files we have already used in previous
// example programs:
#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/function.h>
#include <deal.II/base/logstream.h>
#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.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/grid_refinement.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/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_system.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>

// And here come the things that we need particularly for this example program
// and that weren't in step-8. First, we replace the standard output
// std::cout by a new stream pcout which is used in
// %parallel computations for generating output only on one of the MPI
// processes.
#include <deal.II/base/conditional_ostream.h>
// We are going to query the number of processes and the number of the present
// process by calling the respective functions in the Utilities::MPI
// namespace.
#include <deal.II/base/utilities.h>
// Then, we are going to replace all linear algebra components that involve
// the (global) linear system by classes that wrap interfaces similar to our
// own linear algebra classes around what PETSc offers (PETSc is a library
// written in C, and deal.II comes with wrapper classes that provide the PETSc
// functionality with an interface that is similar to the interface we already
// had for our own linear algebra classes). In particular, we need vectors and
// matrices that are distributed across several processes in MPI programs (and
// simply map to sequential, local vectors and matrices if there is only a
// single process, i.e. if you are running on only one machine, and without
// MPI support):
#include <deal.II/lac/petsc_vector.h>
#include <deal.II/lac/petsc_parallel_vector.h>
#include <deal.II/lac/petsc_parallel_sparse_matrix.h>
// Then we also need interfaces for solvers and preconditioners that PETSc
// provides:
#include <deal.II/lac/petsc_solver.h>
#include <deal.II/lac/petsc_precondition.h>
// And in addition, we need some algorithms for partitioning our meshes so
// that they can be efficiently distributed across an MPI network. The
// partitioning algorithm is implemented in the GridTools class,
// and we need an additional include file for a function in
// DoFRenumbering that allows to sort the indices associated with
// degrees of freedom so that they are numbered according to the subdomain
// they are associated with:
#include <deal.II/grid/grid_tools.h>
#include <deal.II/dofs/dof_renumbering.h>

// And this is simply C++ again:
#include <fstream>
#include <iostream>
#include <sstream>

// The last step is as in all previous programs:
namespace Step17
{
  using namespace dealii;

  // Now, here comes the declaration of the main class and of various other
  // things below it. As mentioned in the introduction, almost all of this has
  // been copied verbatim from step-8, so we only comment on the few things
  // that are different. There is one (cosmetic) change in that we let
  // solve return a value, namely the number of iterations it
  // took to converge, so that we can output this to the screen at the
  // appropriate place. In addition, we introduce a stream-like variable
  // pcout, explained below:
  template <int dim>
  class ElasticProblem
  {
  public:
    ElasticProblem ();
    ~ElasticProblem ();
    void run ();

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

    // The first variable is basically only for convenience: in %parallel
    // program, if each process outputs status information, then there quickly
    // is a lot of clutter. Rather, we would want to only have one process
    // output everything once, for example the one with process number
    // zero. ConditionalOStream does exactly this: it acts as if
    // it were a stream, but only forwards to a real, underlying stream if a
    // flag is set. By setting this condition to
    // this_mpi_process==0, we make sure that output is only
    // generated from the first process and that we don't get the same lines
    // of output over and over again, once per process.
    //
    // With this simple trick, we make sure that we don't have to guard each
    // and every write to std::cout by a prefixed
    // if(this_mpi_process==0).
    ConditionalOStream pcout;

    // The next few variables are taken verbatim from step-8:
    Triangulation<dim>   triangulation;
    DoFHandler<dim>      dof_handler;

    FESystem<dim>        fe;

    ConstraintMatrix     hanging_node_constraints;

    // In step-8, this would have been the place where we would have declared
    // the member variables for the sparsity pattern, the system matrix, right
    // hand, and solution vector. We change these declarations to use
    // %parallel PETSc objects instead (note that the fact that we use the
    // %parallel versions is denoted the fact that we use the classes from the
    // PETScWrappers::MPI namespace; sequential versions of these
    // classes are in the PETScWrappers namespace, i.e. without
    // the MPI part). Note also that we do not use a separate
    // sparsity pattern, since PETSc manages that as part of its matrix data
    // structures.
    PETScWrappers::MPI::SparseMatrix system_matrix;

    PETScWrappers::MPI::Vector       solution;
    PETScWrappers::MPI::Vector       system_rhs;

    // The next change is that we have to declare a variable that indicates
    // the MPI communicator over which we are supposed to distribute our
    // computations. Note that if this is a sequential job without support by
    // MPI, then PETSc provides some dummy type for MPI_Comm, so
    // we do not have to care here whether the job is really a %parallel one:
    MPI_Comm mpi_communicator;

    // Then we have two variables that tell us where in the %parallel world we
    // are. The first of the following variables, n_mpi_processes
    // tells us how many MPI processes there exist in total, while the second
    // one, this_mpi_process, indicates which is the number of
    // the present process within this space of processes. The latter variable
    // will have a unique value for each process between zero and (less than)
    // n_mpi_processes. If this program is run on a single
    // machine without MPI support, then their values are 1 and
    // 0, respectively.
    const unsigned int n_mpi_processes;
    const unsigned int this_mpi_process;
  };

  // The following is again taken from step-8 without change:
  template <int dim>
  class RightHandSide :  public Function<dim>
  {
  public:
    RightHandSide ();

    virtual void vector_value (const Point<dim> &p,
                               Vector<double>   &values) const;

    virtual void vector_value_list (const std::vector<Point<dim> > &points,
                                    std::vector<Vector<double> >   &value_list) const;
  };

  template <int dim>
  RightHandSide<dim>::RightHandSide () :
    Function<dim> (dim)
  {}

  template <int dim>
  inline
  void RightHandSide<dim>::vector_value (const Point<dim> &p,
                                         Vector<double>   &values) const
  {
    Assert (values.size() == dim,
            ExcDimensionMismatch (values.size(), dim));
    Assert (dim >= 2, ExcInternalError());

    Point<dim> point_1, point_2;
    point_1(0) = 0.5;
    point_2(0) = -0.5;

    if (((p-point_1).square() < 0.2*0.2) ||
        ((p-point_2).square() < 0.2*0.2))
      values(0) = 1;
    else
      values(0) = 0;

    if (p.square() < 0.2*0.2)
      values(1) = 1;
    else
      values(1) = 0;
  }

  template <int dim>
  void RightHandSide<dim>::vector_value_list (const std::vector<Point<dim> > &points,
                                              std::vector<Vector<double> >   &value_list) const
  {
    const unsigned int n_points = points.size();

    Assert (value_list.size() == n_points,
            ExcDimensionMismatch (value_list.size(), n_points));

    for (unsigned int p=0; p<n_points; ++p)
      RightHandSide<dim>::vector_value (points[p],
                                        value_list[p]);
  }

  // The first step in the actual implementation of things is the constructor
  // of the main class. Apart from initializing the same member variables that
  // we already had in step-8, we here initialize the MPI communicator
  // variable we shall use with the global MPI communicator linking all
  // processes together (in more complex applications, one could here use a
  // communicator object that only links a subset of all processes), and call
  // the Utilities helper functions to determine the number of processes and
  // where the present one fits into this picture. In addition, we make sure
  // that output is only generated by the (globally) first process. As,
  // this_mpi_process is determined after creation of pcout, we cannot set the
  // condition through the constructor, i.e. by pcout(std::cout,
  // this_mpi_process==0), but set the condition separately.
  template <int dim>
  ElasticProblem<dim>::ElasticProblem ()
    :
    pcout (std::cout),
    dof_handler (triangulation),
    fe (FE_Q<dim>(1), dim),
    mpi_communicator (MPI_COMM_WORLD),
    n_mpi_processes (Utilities::MPI::n_mpi_processes(mpi_communicator)),
    this_mpi_process (Utilities::MPI::this_mpi_process(mpi_communicator))
  {
    pcout.set_condition(this_mpi_process == 0);
  }

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

  // The second step is the function in which we set up the various variables
  // for the global linear system to be solved.
  template <int dim>
  void ElasticProblem<dim>::setup_system ()
  {
    // Before we even start out setting up the system, there is one thing to
    // do for a %parallel program: we need to assign cells to each of the
    // processes. We do this by splitting (partitioning) the mesh
    // cells into as many chunks (subdomains) as there are
    // processes in this MPI job (if this is a sequential job, then there is
    // only one job and all cells will get a zero as subdomain
    // indicator). This is done using an interface to the METIS library that
    // does this in a very efficient way, trying to minimize the number of
    // nodes on the interfaces between subdomains. All this is hidden behind
    // the following call to a deal.II library function:
    GridTools::partition_triangulation (n_mpi_processes, triangulation);

    // As for the linear system: First, we need to generate an enumeration for
    // the degrees of freedom in our problem. Further below, we will show how
    // we assign each cell to one of the MPI processes before we even get
    // here. What we then need to do is to enumerate the degrees of freedom in
    // a way so that all degrees of freedom associated with cells in subdomain
    // zero (which resides on process zero) come before all DoFs associated
    // with cells on subdomain one, before those on cells on process two, and
    // so on. We need this since we have to split the global vectors for right
    // hand side and solution, as well as the matrix into contiguous chunks of
    // rows that live on each of the processors, and we will want to do this
    // in a way that requires minimal communication. This is done using the
    // following two functions, which first generates an initial ordering of
    // all degrees of freedom, and then re-sort them according to above
    // criterion:
    dof_handler.distribute_dofs (fe);
    DoFRenumbering::subdomain_wise (dof_handler);

    // While we're at it, let us also count how many degrees of freedom there
    // exist on the present process:
    const unsigned int n_local_dofs
      = DoFTools::count_dofs_with_subdomain_association (dof_handler,
                                                         this_mpi_process);

    // Then we initialize the system matrix, solution, and right hand side
    // vectors. Since they all need to work in %parallel, we have to pass them
    // an MPI communication object, as well as their global sizes (both
    // dimensions are equal to the number of degrees of freedom), and also how
    // many rows out of this global size are to be stored locally
    // (n_local_dofs). In addition, PETSc needs to know how to
    // partition the columns in the chunk of the matrix that is stored
    // locally; for square matrices, the columns should be partitioned in the
    // same way as the rows (indicated by the second n_local_dofs
    // in the call) but in the case of rectangular matrices one has to
    // partition the columns in the same way as vectors are partitioned with
    // which the matrix is multiplied, while rows have to partitioned in the
    // same way as destination vectors of matrix-vector multiplications:
    system_matrix.reinit (mpi_communicator,
                          dof_handler.n_dofs(),
                          dof_handler.n_dofs(),
                          n_local_dofs,
                          n_local_dofs,
                          dof_handler.max_couplings_between_dofs());

    solution.reinit (mpi_communicator, dof_handler.n_dofs(), n_local_dofs);
    system_rhs.reinit (mpi_communicator, dof_handler.n_dofs(), n_local_dofs);

    // Finally, we need to initialize the objects denoting hanging node
    // constraints for the present grid. Note that since PETSc handles the
    // sparsity pattern internally to the matrix, there is no need to set up
    // an independent sparsity pattern here, and to condense it for
    // constraints, as we have done in all other example programs.
    hanging_node_constraints.clear ();
    DoFTools::make_hanging_node_constraints (dof_handler,
                                             hanging_node_constraints);
    hanging_node_constraints.close ();
  }

  // The third step is to actually assemble the matrix and right hand side of
  // the problem. There are some things worth mentioning before we go into
  // detail. First, we will be assembling the system in %parallel, i.e. each
  // process will be responsible for assembling on cells that belong to this
  // particular processor. Note that the degrees of freedom are split in a way
  // such that all DoFs in the interior of cells and between cells belonging
  // to the same subdomain belong to the process that owns the
  // cell. However, even then we sometimes need to assemble on a cell with a
  // neighbor that belongs to a different process, and in these cases when we
  // write the local contributions into the global matrix or right hand side
  // vector, we actually have to transfer these entries to the other
  // process. Fortunately, we don't have to do this by hand, PETSc does all
  // this for us by caching these elements locally, and sending them to the
  // other processes as necessary when we call the compress()
  // functions on the matrix and vector at the end of this function.
  //
  // The second point is that once we have handed over matrix and vector
  // contributions to PETSc, it is a) hard, and b) very inefficient to get
  // them back for modifications. This is not only the fault of PETSc, it is
  // also a consequence of the distributed nature of this program: if an entry
  // resides on another processor, then it is necessarily expensive to get
  // it. The consequence of this is that where we previously first assembled
  // the matrix and right hand side as if there were no hanging node
  // constraints and boundary values, and then eliminated these in a second
  // step, we should now try to do that while still assembling the local
  // systems, and before handing these entries over to PETSc. At least as far
  // as eliminating hanging nodes is concerned, this is actually possible,
  // though removing boundary nodes isn't that simple. deal.II provides
  // functions to do this first part: instead of copying elements by hand into
  // the global matrix, we use the distribute_local_to_global
  // functions below to take care of hanging nodes at the same time. The
  // second step, elimination of boundary nodes, is then done in exactly the
  // same way as in all previous example programs.
  //
  // So, here is the actual implementation:
  template <int dim>
  void ElasticProblem<dim>::assemble_system ()
  {
    // The infrastructure to assemble linear systems is the same as in all the
    // other programs, and in particular unchanged from step-8. Note that we
    // still use the deal.II full matrix and vector types for the local
    // systems.
    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_matrix (dofs_per_cell, dofs_per_cell);
    Vector<double>       cell_rhs (dofs_per_cell);

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

    std::vector<double>     lambda_values (n_q_points);
    std::vector<double>     mu_values (n_q_points);

    ConstantFunction<dim> lambda(1.), mu(1.);

    RightHandSide<dim>      right_hand_side;
    std::vector<Vector<double> > rhs_values (n_q_points,
                                             Vector<double>(dim));

    // The next thing is the loop over all elements. Note that we do not have
    // to do all the work: our job here is only to assemble the system on
    // cells that actually belong to this MPI process, all other cells will be
    // taken care of by other processes. This is what the if-clause
    // immediately after the for-loop takes care of: it queries the subdomain
    // identifier of each cell, which is a number associated with each cell
    // that tells which process handles it. In more generality, the subdomain
    // id is used to split a domain into several parts (we do this above, at
    // the beginning of setup_system), and which allows to
    // identify which subdomain a cell is living on. In this application, we
    // have each process handle exactly one subdomain, so we identify the
    // terms subdomain and MPI process with each
    // other.
    //
    // Apart from this, assembling the local system is relatively uneventful
    // if you have understood how this is done in step-8, and only becomes
    // interesting again once we start distributing it into the global matrix
    // and right hand sides.
    typename DoFHandler<dim>::active_cell_iterator
    cell = dof_handler.begin_active(),
    endc = dof_handler.end();
    for (; cell!=endc; ++cell)
      if (cell->subdomain_id() == this_mpi_process)
        {
          cell_matrix = 0;
          cell_rhs = 0;

          fe_values.reinit (cell);

          lambda.value_list (fe_values.get_quadrature_points(), lambda_values);
          mu.value_list     (fe_values.get_quadrature_points(), mu_values);

          for (unsigned int i=0; i<dofs_per_cell; ++i)
            {
              const unsigned int
              component_i = fe.system_to_component_index(i).first;

              for (unsigned int j=0; j<dofs_per_cell; ++j)
                {
                  const unsigned int
                  component_j = fe.system_to_component_index(j).first;

                  for (unsigned int q_point=0; q_point<n_q_points;
                       ++q_point)
                    {
//TODO investigate really small values here
                      cell_matrix(i,j)
                      +=
                        (
                          (fe_values.shape_grad(i,q_point)[component_i] *
                           fe_values.shape_grad(j,q_point)[component_j] *
                           lambda_values[q_point])
                          +
                          (fe_values.shape_grad(i,q_point)[component_j] *
                           fe_values.shape_grad(j,q_point)[component_i] *
                           mu_values[q_point])
                          +
                          ((component_i == component_j) ?
                           (fe_values.shape_grad(i,q_point) *
                            fe_values.shape_grad(j,q_point) *
                            mu_values[q_point])  :
                           0)
                        )
                        *
                        fe_values.JxW(q_point);
                    }
                }
            }

          right_hand_side.vector_value_list (fe_values.get_quadrature_points(),
                                             rhs_values);
          for (unsigned int i=0; i<dofs_per_cell; ++i)
            {
              const unsigned int
              component_i = fe.system_to_component_index(i).first;

              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](component_i) *
                               fe_values.JxW(q_point);
            }

          // Now we have the local system, and need to transfer it into the
          // global objects. However, as described in the introduction to this
          // function, we want to avoid any operations to matrix and vector
          // entries after handing them off to PETSc (i.e. after distributing
          // to the global objects). Therefore, we will take care of hanging
          // node constraints already here. This is not quite trivial since
          // the rows and columns of constrained nodes have to be distributed
          // to the rows and columns of those nodes to which they are
          // constrained. This can't be done on a purely local basis (because
          // the degrees of freedom to which hanging nodes are constrained may
          // not be associated with the cell we are presently treating, and
          // are therefore not represented in the local matrix and vector),
          // but it can be done while distributing the local system to the
          // global one. This is what the following call does, i.e. we
          // distribute to the global objects and at the same time make sure
          // that hanging node constraints are taken care of:
          cell->get_dof_indices (local_dof_indices);
          hanging_node_constraints
          .distribute_local_to_global(cell_matrix, cell_rhs,
                                       local_dof_indices,
                                       system_matrix, system_rhs);
        }

    // Now compress the vector and the system matrix:
    system_matrix.compress();
    system_rhs.compress(VectorOperation::add);

    // The global matrix and right hand side vectors have now been
    // formed. Note that since we took care of this already above, we do not
    // have to condense away hanging node constraints any more.
    //
    // However, we still have to apply boundary values, in the same way as we
    // always do:
    std::map<unsigned int,double> boundary_values;
    VectorTools::interpolate_boundary_values (dof_handler,
                                              0,
                                              ZeroFunction<dim>(dim),
                                              boundary_values);
    MatrixTools::apply_boundary_values (boundary_values,
                                        system_matrix, solution,
                                        system_rhs, false);
    // The last argument to the call just performed allows for some
    // optimizations. It controls whether we should also delete the column
    // corresponding to a boundary node, or keep it (and passing
    // true as above means: yes, do eliminate the column). If we
    // do, then the resulting matrix will be symmetric again if it was before;
    // if we don't, then it won't. The solution of the resulting system should
    // be the same, though. The only reason why we may want to make the system
    // symmetric again is that we would like to use the CG method, which only
    // works with symmetric matrices.  Experience tells that CG also works
    // (and works almost as well) if we don't remove the columns associated
    // with boundary nodes, which can be easily explained by the special
    // structure of the non-symmetry. Since eliminating columns from dense
    // matrices is not expensive, though, we let the function do it; not doing
    // so is more important if the linear system is either non-symmetric
    // anyway, or we are using the non-local version of this function (as in
    // all the other example programs before) and want to save a few cycles
    // during this operation.
  }

  // The fourth step is to solve the linear system, with its distributed
  // matrix and vector objects. Fortunately, PETSc offers a variety of
  // sequential and %parallel solvers, for which we have written wrappers that
  // have almost the same interface as is used for the deal.II solvers used in
  // all previous example programs.
  template <int dim>
  unsigned int ElasticProblem<dim>::solve ()
  {
    // First, we have to set up a convergence monitor, and assign it the
    // accuracy to which we would like to solve the linear system. Next, an
    // actual solver object using PETSc's CG solver which also works with
    // %parallel (distributed) vectors and matrices. And finally a
    // preconditioner; we choose to use a block Jacobi preconditioner which
    // works by computing an incomplete LU decomposition on each block
    // (i.e. the chunk of matrix that is stored on each MPI process). That
    // means that if you run the program with only one process, then you will
    // use an ILU(0) as a preconditioner, while if it is run on many
    // processes, then we will have a number of blocks on the diagonal and the
    // preconditioner is the ILU(0) of each of these blocks.
    SolverControl           solver_control (solution.size(),
                                            1e-8*system_rhs.l2_norm());
    PETScWrappers::SolverCG cg (solver_control,
                                mpi_communicator);

    PETScWrappers::PreconditionBlockJacobi preconditioner(system_matrix);

    // Then solve the system:
    cg.solve (system_matrix, solution, system_rhs,
              preconditioner);

    // The next step is to distribute hanging node constraints. This is a
    // little tricky, since to fill in the value of a constrained node you
    // need access to the values of the nodes to which it is constrained (for
    // example, for a Q1 element in 2d, we need access to the two nodes on the
    // big side of a hanging node face, to compute the value of the
    // constrained node in the middle). Since PETSc (and, for that matter, the
    // MPI model on which it is built) does not allow to query the value of
    // another node in a simple way if we should need it, what we do here is
    // to get a copy of the distributed vector where we keep all elements
    // locally. This is simple, since the deal.II wrappers have a conversion
    // constructor for the non-MPI vector class:
    PETScWrappers::Vector localized_solution (solution);

    // Then we distribute hanging node constraints on this local copy, i.e. we
    // compute the values of all constrained nodes:
    hanging_node_constraints.distribute (localized_solution);

    // Then transfer everything back into the global vector. The following
    // operation copies those elements of the localized solution that we store
    // locally in the distributed solution, and does not touch the other
    // ones. Since we do the same operation on all processors, we end up with
    // a distributed vector that has all the constrained nodes fixed.
    solution = localized_solution;

    // Finally return the number of iterations it took to converge, to allow
    // for some output:
    return solver_control.last_step();
  }

  // Step five is to output the results we computed in this iteration. This is
  // actually the same as done in step-8 before, with two small
  // differences. First, all processes call this function, but not all of them
  // need to do the work associated with generating output. In fact, they
  // shouldn't, since we would try to write to the same file multiple times at
  // once. So we let only the first job do this, and all the other ones idle
  // around during this time (or start their work for the next iteration, or
  // simply yield their CPUs to other jobs that happen to run at the same
  // time). The second thing is that we not only output the solution vector,
  // but also a vector that indicates which subdomain each cell belongs
  // to. This will make for some nice pictures of partitioned domains.
  //
  // In practice, the present implementation of the output function is a major
  // bottleneck of this program, since generating graphical output is
  // expensive and doing so only on one process does, of course, not scale if
  // we significantly increase the number of processes. In effect, this
  // function will consume most of the run-time if you go to very large
  // numbers of unknowns and processes, and real applications should limit the
  // number of times they generate output through this function.
  //
  // The solution to this is to have each process generate output data only
  // for it's own local cells, and write them to separate files, one file per
  // process. This would distribute the work of generating the output to all
  // processes equally. In a second step, separate from running this program,
  // we would then take all the output files for a given cycle and merge these
  // parts into one single output file. This has to be done sequentially, but
  // can be done on a different machine, and should be relatively
  // cheap. However, the necessary functionality for this is not yet
  // implemented in the library, and since we are too close to the next
  // release, we do not want to do such major destabilizing changes any
  // more. This has been fixed in the meantime, though, and a better way to do
  // things is explained in the step-18 example program.
  template <int dim>
  void ElasticProblem<dim>::output_results (const unsigned int cycle) const
  {
    // One point to realize is that when we want to generate output on process
    // zero only, we need to have access to all elements of the solution
    // vector. So we need to get a local copy of the distributed vector, which
    // is in fact simple:
    const PETScWrappers::Vector localized_solution (solution);
    // The thing to notice, however, is that we do this localization operation
    // on all processes, not only the one that actually needs the data. This
    // can't be avoided, however, with the communication model of MPI: MPI
    // does not have a way to query data on another process, both sides have
    // to initiate a communication at the same time. So even though most of
    // the processes do not need the localized solution, we have to place the
    // call here so that all processes execute it.
    //
    // (In reality, part of this work can in fact be avoided. What we do is
    // send the local parts of all processes to all other processes. What we
    // would really need to do is to initiate an operation on all processes
    // where each process simply sends its local chunk of data to process
    // zero, since this is the only one that actually needs it, i.e. we need
    // something like a gather operation. PETSc can do this, but for
    // simplicity's sake we don't attempt to make use of this here. We don't,
    // since what we do is not very expensive in the grand scheme of things:
    // it is one vector communication among all processes , which has to be
    // compared to the number of communications we have to do when solving the
    // linear system, setting up the block-ILU for the preconditioner, and
    // other operations.)

    // This being done, process zero goes ahead with setting up the output
    // file as in step-8, and attaching the (localized) solution vector to the
    // output object:. (The code to generate the output file name is stolen
    // and slightly modified from step-5, since we expect that we can do a
    // number of cycles greater than 10, which is the maximum of what the code
    // in step-8 could handle.)
    if (this_mpi_process == 0)
      {
        std::ostringstream filename;
        filename << "solution-" << cycle << ".gmv";

        std::ofstream output (filename.str().c_str());

        DataOut<dim> data_out;
        data_out.attach_dof_handler (dof_handler);

        std::vector<std::string> solution_names;
        switch (dim)
          {
          case 1:
            solution_names.push_back ("displacement");
            break;
          case 2:
            solution_names.push_back ("x_displacement");
            solution_names.push_back ("y_displacement");
            break;
          case 3:
            solution_names.push_back ("x_displacement");
            solution_names.push_back ("y_displacement");
            solution_names.push_back ("z_displacement");
            break;
          default:
            Assert (false, ExcInternalError());
          }

        data_out.add_data_vector (localized_solution, solution_names);

        // The only thing we do here additionally is that we also output one
        // value per cell indicating which subdomain (i.e. MPI process) it
        // belongs to. This requires some conversion work, since the data the
        // library provides us with is not the one the output class expects,
        // but this is not difficult. First, set up a vector of integers, one
        // per cell, that is then filled by the number of subdomain each cell
        // is in:
        std::vector<unsigned int> partition_int (triangulation.n_active_cells());
        GridTools::get_subdomain_association (triangulation, partition_int);

        // Then convert this integer vector into a floating point vector just
        // as the output functions want to see:
        const Vector<double> partitioning(partition_int.begin(),
                                          partition_int.end());

        // And finally add this vector as well:
        data_out.add_data_vector (partitioning, "partitioning");

        // This all being done, generate the intermediate format and write it
        // out in GMV output format:
        data_out.build_patches ();
        data_out.write_gmv (output);
      }
  }

  // The sixth step is to take the solution just computed, and evaluate some
  // kind of refinement indicator to refine the mesh. The problem is basically
  // the same as with distributing hanging node constraints: in order to
  // compute the error indicator, we need access to all elements of the
  // solution vector. We then compute the indicators for the cells that belong
  // to the present process, but then we need to distribute the refinement
  // indicators into a distributed vector so that all processes have the
  // values of the refinement indicator for all cells. But then, in order for
  // each process to refine its copy of the mesh, they need to have acces to
  // all refinement indicators locally, so they have to copy the global vector
  // back into a local one. That's a little convoluted, but thinking about it
  // quite straightforward nevertheless. So here's how we do it:
  template <int dim>
  void ElasticProblem<dim>::refine_grid ()
  {
    // So, first part: get a local copy of the distributed solution
    // vector. This is necessary since the error estimator needs to get at the
    // value of neighboring cells even if they do not belong to the subdomain
    // associated with the present MPI process:
    const PETScWrappers::Vector localized_solution (solution);

    // Second part: set up a vector of error indicators for all cells and let
    // the Kelly class compute refinement indicators for all cells belonging
    // to the present subdomain/process. Note that the last argument of the
    // call indicates which subdomain we are interested in. The three
    // arguments before it are various other default arguments that one
    // usually doesn't need (and doesn't state values for, but rather uses the
    // defaults), but which we have to state here explicitly since we want to
    // modify the value of a following argument (i.e. the one indicating the
    // subdomain):
    Vector<float> local_error_per_cell (triangulation.n_active_cells());
    KellyErrorEstimator<dim>::estimate (dof_handler,
                                        QGauss<dim-1>(2),
                                        typename FunctionMap<dim>::type(),
                                        localized_solution,
                                        local_error_per_cell,
                                        ComponentMask(),
                                        0,
                                        multithread_info.n_default_threads,
                                        this_mpi_process);

    // Now all processes have computed error indicators for their own cells
    // and stored them in the respective elements of the
    // local_error_per_cell vector. The elements of this vector
    // for cells not on the present process are zero. However, since all
    // processes have a copy of a copy of the entire triangulation and need to
    // keep these copies in synch, they need the values of refinement
    // indicators for all cells of the triangulation. Thus, we need to
    // distribute our results. We do this by creating a distributed vector
    // where each process has its share, and sets the elements it has
    // computed. We will then later generate a local sequential copy of this
    // distributed vector to allow each process to access all elements of this
    // vector.
    //
    // So in the first step, we need to set up a %parallel vector. For
    // simplicity, every process will own a chunk with as many elements as
    // this process owns cells, so that the first chunk of elements is stored
    // with process zero, the next chunk with process one, and so on. It is
    // important to remark, however, that these elements are not necessarily
    // the ones we will write to. This is so, since the order in which cells
    // are arranged, i.e. the order in which the elements of the vector
    // correspond to cells, is not ordered according to the subdomain these
    // cells belong to. In other words, if on this process we compute
    // indicators for cells of a certain subdomain, we may write the results
    // to more or less random elements if the distributed vector, that do not
    // necessarily lie within the chunk of vector we own on the present
    // process. They will subsequently have to be copied into another
    // process's memory space then, an operation that PETSc does for us when
    // we call the compress function. This inefficiency could be
    // avoided with some more code, but we refrain from it since it is not a
    // major factor in the program's total runtime.
    //
    // So here's how we do it: count how many cells belong to this process,
    // set up a distributed vector with that many elements to be stored
    // locally, and copy over the elements we computed locally, then compress
    // the result. In fact, we really only copy the elements that are nonzero,
    // so we may miss a few that we computed to zero, but this won't hurt
    // since the original values of the vector is zero anyway.
    const unsigned int n_local_cells
      = GridTools::count_cells_with_subdomain_association (triangulation,
                                                           this_mpi_process);
    PETScWrappers::MPI::Vector
    distributed_all_errors (mpi_communicator,
                            triangulation.n_active_cells(),
                            n_local_cells);

    for (unsigned int i=0; i<local_error_per_cell.size(); ++i)
      if (local_error_per_cell(i) != 0)
        distributed_all_errors(i) = local_error_per_cell(i);
    distributed_all_errors.compress (VectorOperation::insert);

    // So now we have this distributed vector out there that contains the
    // refinement indicators for all cells. To use it, we need to obtain a
    // local copy...
    const Vector<float> localized_all_errors (distributed_all_errors);

    // ...which we can the subsequently use to finally refine the grid:
    GridRefinement::refine_and_coarsen_fixed_number (triangulation,
                                                     localized_all_errors,
                                                     0.3, 0.03);
    triangulation.execute_coarsening_and_refinement ();
  }

  // Lastly, here is the driver function. It is almost unchanged from step-8,
  // with the exception that we replace std::cout by the
  // pcout stream. Apart from this, the only other cosmetic
  // change is that we output how many degrees of freedom there are per
  // process, and how many iterations it took for the linear solver to
  // converge:
  template <int dim>
  void ElasticProblem<dim>::run ()
  {
    for (unsigned int cycle=0; cycle<10; ++cycle)
      {
        pcout << "Cycle " << cycle << ':' << std::endl;

        if (cycle == 0)
          {
            GridGenerator::hyper_cube (triangulation, -1, 1);
            triangulation.refine_global (3);
          }
        else
          refine_grid ();

        pcout << "   Number of active cells:       "
              << triangulation.n_active_cells()
              << std::endl;

        setup_system ();

        pcout << "   Number of degrees of freedom: "
              << dof_handler.n_dofs()
              << " (by partition:";
        for (unsigned int p=0; p<n_mpi_processes; ++p)
          pcout << (p==0 ? ' ' : '+')
                << (DoFTools::
                    count_dofs_with_subdomain_association (dof_handler,
                                                           p));
        pcout << ")" << std::endl;

        assemble_system ();
        const unsigned int n_iterations = solve ();

        pcout << "   Solver converged in " << n_iterations
              << " iterations." << std::endl;

        output_results (cycle);
      }
  }
}

// So that's it, almost. main() works the same way as most of the
// main functions in the other example programs, i.e. it delegates work to the
// run function of a master object, and only wraps everything
// into some code to catch exceptions:
int main (int argc, char **argv)
{
  try
    {
      using namespace dealii;
      using namespace Step17;

      // Here is the only real difference: PETSc requires that we initialize
      // it at the beginning of the program, and un-initialize it at the
      // end. The class MPI_InitFinalize takes care of that. The original code
      // sits in between, enclosed in braces to make sure that the
      // elastic_problem variable goes out of scope (and is
      // destroyed) before PETSc is closed with
      // PetscFinalize. (If we wouldn't use braces, the
      // destructor of elastic_problem would run after
      // PetscFinalize; since the destructor involves calls to
      // PETSc functions, we would get strange error messages from PETSc.)
      Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv);

      {
        deallog.depth_console (0);

        ElasticProblem<2> elastic_problem;
        elastic_problem.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;
}


/**
 * @file    Format.cc
 * @brief   Implementation of double formatting strings
 * @author  [Yi-Mu "Enoch" Chen](https://github.com/yimuchen)
 */

#ifdef CMSSW_GIT_HASH
#include "UserUtils/Common/interface/Format.hpp"
#include "UserUtils/Common/interface/Maths.hpp"
#include "UserUtils/Common/interface/STLUtils/StringUtils.hpp"
#else
#include "UserUtils/Common/Format.hpp"
#include "UserUtils/Common/Maths.hpp"
#include "UserUtils/Common/STLUtils/StringUtils.hpp"
#endif

#include <boost/algorithm/string.hpp>
#include <cmath>
#include <regex>
#include <string>

namespace usr {

namespace fmt {

namespace base {

/*-----------------------------------------------------------------------------
 *  Default settings control variables
   --------------------------------------------------------------------------*/

/**
 * @details default precision is set such that loss of precision due to IO would
 * not be of too much concern, while avoiding artifacts in decimal--binary
 * conversions (ex. 1.7=1.6999999999999999556 )
 */
int precision_default = 8;

/**
 * @details spacing between digits should be universal (i.e. three digits), but
 * can be changed if publishing to journal using another number system.
 */
unsigned spacesep_default = 3;

/**
 * @details Defaults to none, as it is easier on the eyes when testing code with
 * screen I/O, but you might want to set it to the latex "\," string when
 * mass producing numbers for publication.
 */
std::string spacestr_default = "";

/**
 * @details library specifically doesn't allow more digits then 27 to be
 * printed after the decimal point. This is pretty close to the recommended
 * precision limit of doubles anyway.
 */
const unsigned max_precision = 27;

/**
 * @brief generating string to represent double as a string in decimal.
 */
std::string
decimal::str() const
{
  const unsigned op_precision = std::min( abs( _precision ), abs( max_precision ) );
  std::string retstr          = usr::fstr( usr::fstr( "%%.%df", op_precision ), _input );

  // stripping trailing zero after decimal point
  if( _precision < 0 && retstr.find( '.' ) != std::string::npos ){
    boost::trim_right_if( retstr, boost::is_any_of( "0" ) );
    boost::trim_right_if( retstr, boost::is_any_of( "." ) );
  }

  // Adding spacing string every _spacesep digits away from decimal point
  // Largest double is around e308
  if( _spacesep != 0 && _spacestr != "" ){
    int space = ( ( (int)( retstr.length()/_spacesep ) ) + 1 ) * _spacesep;

    while( space > 0 ){
      if( retstr.find( '.' ) != std::string::npos ){
        // If decimal point exists, expand around decimal point
        const std::regex before( usr::fstr( "(.*\\d)(\\d{%d}\\..*)", space ) );
        const std::regex after(  usr::fstr( "(.*\\.\\d{%d})(\\d.*)", space ) );
        retstr = std::regex_replace( retstr, before, "$1"+_spacestr+"$2" );
        retstr = std::regex_replace( retstr, after,  "$1"+_spacestr+"$2" );
      } else {
        // If decimal point doesn't exist, expand around right most side
        const std::regex beforedec(  usr::fstr( "(.*\\d)(\\d{%d})", space ) );
        retstr = std::regex_replace( retstr, beforedec, "$1"+_spacestr+"$2" );
      }
      space -= _spacesep;
    }
  }
  return retstr;
}

/**
 * @brief Requires explicit specification of precision (cannot be negative)
 */
scientific::scientific( const double x, const unsigned p )
{
  precision( p );
  _mant = x;
  _exp  = ReduceToMant( _mant );
}

/**
 * @brief Generating string to represent double as string in scientific
 *  notations.
 */
std::string
scientific::str() const
{
  const std::string base = decimal( _mant, _precision ).dupsetting( *this ).str();
  // largest exponent should be around ~300
  // no need of additional formatting.
  const std::string ans
    = ( _exp == 0 ) ?  base : usr::fstr( "%s \\times 10^{%d}", base, _exp );
  return ans;
}

}/* base */

}/* fmt */

}/* usr */


// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_GRAPH_CLIQUE_HPP
#define BOOST_GRAPH_CLIQUE_HPP

#include <vector>
#include <deque>
#include <boost/config.hpp>

#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/lookup_edge.hpp>

#include <boost/concept/detail/concept_def.hpp>
namespace boost {
    namespace concepts {
        BOOST_concept(CliqueVisitor,(Visitor)(Clique)(Graph))
        {
            BOOST_CONCEPT_USAGE(CliqueVisitor)
            {
                vis.clique(k, g);
            }
        private:
            Visitor vis;
            Graph g;
            Clique k;
        };
    } /* namespace concepts */
using concepts::CliqueVisitorConcept;
} /* namespace boost */
#include <boost/concept/detail/concept_undef.hpp>

namespace boost
{
// The algorithm implemented in this paper is based on the so-called
// Algorithm 457, published as:
//
//     @article{362367,
//         author = {Coen Bron and Joep Kerbosch},
//         title = {Algorithm 457: finding all cliques of an undirected graph},
//         journal = {Communications of the ACM},
//         volume = {16},
//         number = {9},
//         year = {1973},
//         issn = {0001-0782},
//         pages = {575--577},
//         doi = {http://doi.acm.org/10.1145/362342.362367},
//             publisher = {ACM Press},
//             address = {New York, NY, USA},
//         }
//
// Sort of. This implementation is adapted from the 1st version of the
// algorithm and does not implement the candidate selection optimization
// described as published - it could, it just doesn't yet.
//
// The algorithm is given as proportional to (3.14)^(n/3) power. This is
// not the same as O(...), but based on time measures and approximation.
//
// Unfortunately, this implementation may be less efficient on non-
// AdjacencyMatrix modeled graphs due to the non-constant implementation
// of the edge(u,v,g) functions.
//
// TODO: It might be worthwhile to provide functionality for passing
// a connectivity matrix to improve the efficiency of those lookups
// when needed. This could simply be passed as a BooleanMatrix
// s.t. edge(u,v,B) returns true or false. This could easily be
// abstracted for adjacency matricies.
//
// The following paper is interesting for a number of reasons. First,
// it lists a number of other such algorithms and second, it describes
// a new algorithm (that does not appear to require the edge(u,v,g)
// function and appears fairly efficient. It is probably worth investigating.
//
//      @article{DBLP:journals/tcs/TomitaTT06,
//          author = {Etsuji Tomita and Akira Tanaka and Haruhisa Takahashi},
//          title = {The worst-case time complexity for generating all maximal cliques and computational experiments},
//          journal = {Theor. Comput. Sci.},
//          volume = {363},
//          number = {1},
//          year = {2006},
//          pages = {28-42}
//          ee = {http://dx.doi.org/10.1016/j.tcs.2006.06.015}
//      }

/**
 * The default clique_visitor supplies an empty visitation function.
 */
struct clique_visitor
{
    template <typename VertexSet, typename Graph>
    void clique(const VertexSet&, Graph&)
    { }
};

/**
 * The max_clique_visitor records the size of the maximum clique (but not the
 * clique itself).
 */
struct max_clique_visitor
{
    max_clique_visitor(std::size_t& max)
        : maximum(max)
    { }

    template <typename Clique, typename Graph>
    inline void clique(const Clique& p, const Graph& g)
    {
        BOOST_USING_STD_MAX();
        maximum = max BOOST_PREVENT_MACRO_SUBSTITUTION (maximum, p.size());
    }
    std::size_t& maximum;
};

inline max_clique_visitor find_max_clique(std::size_t& max)
{ return max_clique_visitor(max); }

namespace detail
{
    template <typename Graph>
    inline bool
    is_connected_to_clique(const Graph& g,
                            typename graph_traits<Graph>::vertex_descriptor u,
                            typename graph_traits<Graph>::vertex_descriptor v,
                            typename graph_traits<Graph>::undirected_category)
    {
        return lookup_edge(u, v, g).second;
    }

    template <typename Graph>
    inline bool
    is_connected_to_clique(const Graph& g,
                            typename graph_traits<Graph>::vertex_descriptor u,
                            typename graph_traits<Graph>::vertex_descriptor v,
                            typename graph_traits<Graph>::directed_category)
    {
        // Note that this could alternate between using an || to determine
        // full connectivity. I believe that this should produce strongly
        // connected components. Note that using && instead of || will
        // change the results to a fully connected subgraph (i.e., symmetric
        // edges between all vertices s.t., if a->b, then b->a.
        return lookup_edge(u, v, g).second && lookup_edge(v, u, g).second;
    }

    template <typename Graph, typename Container>
    inline void
    filter_unconnected_vertices(const Graph& g,
                                typename graph_traits<Graph>::vertex_descriptor v,
                                const Container& in,
                                Container& out)
    {
        function_requires< GraphConcept<Graph> >();

        typename graph_traits<Graph>::directed_category cat;
        typename Container::const_iterator i, end = in.end();
        for(i = in.begin(); i != end; ++i) {
            if(is_connected_to_clique(g, v, *i, cat)) {
                out.push_back(*i);
            }
        }
    }

    template <
        typename Graph,
        typename Clique,        // compsub type
        typename Container,     // candidates/not type
        typename Visitor>
    void extend_clique(const Graph& g,
                        Clique& clique,
                        Container& cands,
                        Container& nots,
                        Visitor vis,
                        std::size_t min)
    {
        function_requires< GraphConcept<Graph> >();
        function_requires< CliqueVisitorConcept<Visitor,Clique,Graph> >();
        typedef typename graph_traits<Graph>::vertex_descriptor Vertex;

        // Is there vertex in nots that is connected to all vertices
        // in the candidate set? If so, no clique can ever be found.
        // This could be broken out into a separate function.
        {
            typename Container::iterator ni, nend = nots.end();
            typename Container::iterator ci, cend = cands.end();
            for(ni = nots.begin(); ni != nend; ++ni) {
                for(ci = cands.begin(); ci != cend; ++ci) {
                    // if we don't find an edge, then we're okay.
                    if(!lookup_edge(*ni, *ci, g).second) break;
                }
                // if we iterated all the way to the end, then *ni
                // is connected to all *ci
                if(ci == cend) break;
            }
            // if we broke early, we found *ni connected to all *ci
            if(ni != nend) return;
        }

        // TODO: the original algorithm 457 describes an alternative
        // (albeit really complicated) mechanism for selecting candidates.
        // The given optimizaiton seeks to bring about the above
        // condition sooner (i.e., there is a vertex in the not set
        // that is connected to all candidates). unfortunately, the
        // method they give for doing this is fairly unclear.

        // basically, for every vertex in not, we should know how many
        // vertices it is disconnected from in the candidate set. if
        // we fix some vertex in the not set, then we want to keep
        // choosing vertices that are not connected to that fixed vertex.
        // apparently, by selecting fix point with the minimum number
        // of disconnections (i.e., the maximum number of connections
        // within the candidate set), then the previous condition wil
        // be reached sooner.

        // there's some other stuff about using the number of disconnects
        // as a counter, but i'm jot really sure i followed it.

        // TODO: If we min-sized cliques to visit, then theoretically, we
        // should be able to stop recursing if the clique falls below that
        // size - maybe?

        // otherwise, iterate over candidates and and test
        // for maxmimal cliquiness.
        typename Container::iterator i, j, end = cands.end();
        for(i = cands.begin(); i != cands.end(); ) {
            Vertex candidate = *i;

            // add the candidate to the clique (keeping the iterator!)
            // typename Clique::iterator ci = clique.insert(clique.end(), candidate);
            clique.push_back(candidate);

            // remove it from the candidate set
            i = cands.erase(i);

            // build new candidate and not sets by removing all vertices
            // that are not connected to the current candidate vertex.
            // these actually invert the operation, adding them to the new
            // sets if the vertices are connected. its semantically the same.
            Container new_cands, new_nots;
            filter_unconnected_vertices(g, candidate, cands, new_cands);
            filter_unconnected_vertices(g, candidate, nots, new_nots);

            if(new_cands.empty() && new_nots.empty()) {
                // our current clique is maximal since there's nothing
                // that's connected that we haven't already visited. If
                // the clique is below our radar, then we won't visit it.
                if(clique.size() >= min) {
                    vis.clique(clique, g);
                }
            }
            else {
                // recurse to explore the new candidates
                extend_clique(g, clique, new_cands, new_nots, vis, min);
            }

            // we're done with this vertex, so we need to move it
            // to the nots, and remove the candidate from the clique.
            nots.push_back(candidate);
            clique.pop_back();
        }
    }
} /* namespace detail */

template <typename Graph, typename Visitor>
inline void
bron_kerbosch_all_cliques(const Graph& g, Visitor vis, std::size_t min)
{
    function_requires< IncidenceGraphConcept<Graph> >();
    function_requires< VertexListGraphConcept<Graph> >();
    function_requires< VertexIndexGraphConcept<Graph> >();
    function_requires< AdjacencyMatrixConcept<Graph> >(); // Structural requirement only
    typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
    typedef typename graph_traits<Graph>::vertex_iterator VertexIterator;
    typedef std::vector<Vertex> VertexSet;
    typedef std::deque<Vertex> Clique;
    function_requires< CliqueVisitorConcept<Visitor,Clique,Graph> >();

    // NOTE: We're using a deque to implement the clique, because it provides
    // constant inserts and removals at the end and also a constant size.

    VertexIterator i, end;
    tie(i, end) = vertices(g);
    VertexSet cands(i, end);    // start with all vertices as candidates
    VertexSet nots;             // start with no vertices visited

    Clique clique;              // the first clique is an empty vertex set
    detail::extend_clique(g, clique, cands, nots, vis, min);
}

// NOTE: By default the minimum number of vertices per clique is set at 2
// because singleton cliques aren't really very interesting.
template <typename Graph, typename Visitor>
inline void
bron_kerbosch_all_cliques(const Graph& g, Visitor vis)
{ bron_kerbosch_all_cliques(g, vis, 2); }

template <typename Graph>
inline std::size_t
bron_kerbosch_clique_number(const Graph& g)
{
    std::size_t ret = 0;
    bron_kerbosch_all_cliques(g, find_max_clique(ret));
    return ret;
}

} /* namespace boost */

#endif


/* ---------------------------------------------------------------------
 *
 * Copyright (C) 2013 - 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: Timo Heister, Texas A&M University, 2013
 */

// 这个教程程序很奇怪，与其他大多数步骤不同，介绍中已经提供了关于如何使用各种策略来生成网格的大部分信息。因此，这里没有什么需要评论的，我们在代码中穿插了相对较少的文字。从本质上讲，这里的代码只是提供了一个在介绍中已经描述过的内容的参考实现。

//  @sect3{Include files}
#include <deal.II/grid/tria.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_tools.h>
#include <deal.II/grid/manifold_lib.h>
#include <deal.II/grid/grid_out.h>
#include <deal.II/grid/grid_in.h>

#include <iostream>
#include <fstream>

#include <map>

using namespace dealii;
// @sect3{Generating output for a given mesh}

// 下面的函数为我们将在本程序的剩余部分中生成的任何网格生成一些输出。特别是，它生成了以下信息。

// - 一些关于这个网格所处的空间维数和它的单元数的一般信息。

// - 使用每个边界指标的边界面的数量，这样就可以和我们预期的情况进行比较。

// 最后，该函数将网格输出为VTU格式，可以方便地在Paraview或VisIt中进行可视化。

template <int dim>
void print_mesh_info(const Triangulation<dim> &triangulation,
                     const std::string &       filename)
{
  std::cout << "Mesh info:" << std::endl
            << " dimension: " << dim << std::endl
            << " no. of cells: " << triangulation.n_active_cells() << std::endl;

// 接下来循环所有单元格的所有面，找出每个边界指标的使用频率（请记住，如果你访问一个不存在的 std::map 对象的元素，它将被隐式创建并默认初始化--在当前情况下为零--然后我们再将其增加）。

  {
    std::map<types::boundary_id, unsigned int> boundary_count;
    for (const auto &face : triangulation.active_face_iterators())
      if (face->at_boundary())
        boundary_count[face->boundary_id()]++;

    std::cout << " boundary indicators: ";
    for (const std::pair<const types::boundary_id, unsigned int> &pair :
         boundary_count)
      {
        std::cout << pair.first << "(" << pair.second << " times) ";
      }
    std::cout << std::endl;
  }

// 最后，产生一个网格的图形表示到一个输出文件。

  std::ofstream out(filename);
  GridOut       grid_out;
  grid_out.write_vtu(triangulation, out);
  std::cout << " written to " << filename << std::endl << std::endl;
}
// @sect3{Main routines}
// @sect4{grid_1: Loading a mesh generated by gmsh}

// 在这第一个例子中，我们展示了如何加载我们在介绍中讨论过的如何生成的网格。这与 step-5 中加载网格的模式相同，尽管那里是以不同的文件格式（UCD而不是MSH）编写。

void grid_1()
{
  Triangulation<2> triangulation;

  GridIn<2> gridin;
  gridin.attach_triangulation(triangulation);
  std::ifstream f("example.msh");
  gridin.read_msh(f);

  print_mesh_info(triangulation, "grid-1.vtu");
}
// @sect4{grid_2: Merging triangulations}

// 在这里，我们首先创建两个三角形，然后将它们合并成一个。 正如介绍中所讨论的，必须确保共同界面的顶点位于相同的坐标上。

void grid_2()
{
  Triangulation<2> tria1;
  GridGenerator::hyper_cube_with_cylindrical_hole(tria1, 0.25, 1.0);

  Triangulation<2>          tria2;
  std::vector<unsigned int> repetitions(2);
  repetitions[0] = 3;
  repetitions[1] = 2;
  GridGenerator::subdivided_hyper_rectangle(tria2,
                                            repetitions,
                                            Point<2>(1.0, -1.0),
                                            Point<2>(4.0, 1.0));

  Triangulation<2> triangulation;
  GridGenerator::merge_triangulations(tria1, tria2, triangulation);

  print_mesh_info(triangulation, "grid-2.vtu");
}
// @sect4{grid_3: Moving vertices}

// 在这个函数中，我们移动一个网格的顶点。这比人们通常想象的要简单：如果你用 cell-@>vertex(i) 询问一个单元格的 i 的顶点的坐标，它不只是提供这个顶点的位置，实际上是对存储这些坐标的位置的引用。然后我们可以修改存储在那里的值。

// 所以这就是我们在这个函数的第一部分所做的。我们创建一个几何形状为 $[-1,1]^2$ 的正方形，在原点处有一个半径为0.25的圆孔。然后我们在所有单元格和所有顶点上循环，如果一个顶点的 $y$ 坐标等于1，我们就把它向上移动0.5。

// 注意，这种程序通常不是这样工作的，因为通常会多次遇到相同的顶点，并且可能会多次移动它们。它在这里起作用是因为我们根据顶点的几何位置来选择要使用的顶点，而移动过一次的顶点在未来将无法通过这个测试。解决这个问题的一个更普遍的方法是保留一个 std::set ，即那些我们已经移动过的顶点索引（我们可以用 cell-@>vertex_index(i) 获得，并且只移动那些索引还不在这个集合中的顶点。

void grid_3()
{
  Triangulation<2> triangulation;
  GridGenerator::hyper_cube_with_cylindrical_hole(triangulation, 0.25, 1.0);

  for (const auto &cell : triangulation.active_cell_iterators())
    {
      for (const auto i : cell->vertex_indices())
        {
          Point<2> &v = cell->vertex(i);
          if (std::abs(v(1) - 1.0) < 1e-5)
            v(1) += 0.5;
        }
    }

// 在第二步，我们将对网格进行两次细化。为了正确做到这一点，我们应该沿着以原点为中心的圆的表面在内部边界上放置新的点。幸运的是， GridGenerator::hyper_cube_with_cylindrical_hole 已经在内部边界上附加了一个Manifold对象，所以我们不需要做任何事情，只需要细化网格（参见results section中一个完全可行的例子，我们  做  附加一个Manifold对象）。

  triangulation.refine_global(2);
  print_mesh_info(triangulation, "grid-3.vtu");
}

// 如上图所示，做事有一个障碍。如果像这里所示的那样移动边界上的节点，由于内部的节点没有被移动，所以经常会出现内部的单元被严重扭曲的情况。在目前的情况下，这并不是一个很大的问题，因为当节点被移动时，网格并不包含任何内部节点--它是粗略的网格，而且恰好所有的顶点都在边界上。还有一种情况是，我们在这里的移动，与平均单元的大小相比，并没有太大影响。然而，有时我们确实想把顶点移动一段距离，在这种情况下，我们也需要移动内部节点。一个自动完成的方法是调用函数 GridTools::laplace_transform ，该函数接收一组转换后的顶点坐标并移动所有其他的顶点，使产生的网格在某种意义上有一个小的变形。

//  @sect4{grid_4: Demonstrating extrude_triangulation}

// 这个例子从前面的函数中获取初始网格，并简单地将其挤压到第三空间维度。

void grid_4()
{
  Triangulation<2> triangulation;
  Triangulation<3> out;
  GridGenerator::hyper_cube_with_cylindrical_hole(triangulation, 0.25, 1.0);

  GridGenerator::extrude_triangulation(triangulation, 3, 2.0, out);
  print_mesh_info(out, "grid-4.vtu");
}
// @sect4{grid_5: Demonstrating GridTools::transform, part 1}

// 这个例子和下一个例子首先创建一个网格，然后根据一个函数移动网格的每个节点，这个函数接收一个点并返回一个映射的点。在这个例子中，我们转换  $(x,y) \mapsto (x,y+\sin(\pi x/5))$  。

//  GridTools::transform()  需要一个三角形和一个参数，这个参数可以像一个函数一样被调用，接收一个点并返回一个点。有不同的方式来提供这样一个参数。它可以是一个函数的指针；它可以是一个具有`operator()`的类的对象；它可以是一个lambda函数；或者它可以是任何通过 std::function@<Point@<2@>(const Point@<2@>)@> 对象描述的东西。

// 更现代的方法是使用一个接受一个点并返回一个点的lambda函数，这就是我们在下面所做的。

void grid_5()
{
  Triangulation<2>          triangulation;
  std::vector<unsigned int> repetitions(2);
  repetitions[0] = 14;
  repetitions[1] = 2;
  GridGenerator::subdivided_hyper_rectangle(triangulation,
                                            repetitions,
                                            Point<2>(0.0, 0.0),
                                            Point<2>(10.0, 1.0));

  GridTools::transform(
    [](const Point<2> &in) {
      return Point<2>(in[0], in[1] + std::sin(numbers::PI * in[0] / 5.0));
    },
    triangulation);
  print_mesh_info(triangulation, "grid-5.vtu");
}

//  @sect4{grid_6: Demonstrating GridTools::transform, part 2}

// 在第二个例子中，我们将使用映射  $(x,y) \mapsto (x,\tanh(2y)/\tanh(2))$  将原始网格中的点转换为新的网格。为了使事情更有趣，而不是像前面的例子那样在一个单一的函数中完成，我们在这里创建一个具有  operator()  的对象，这个对象将被  GridTools::transform.  所调用。当然，这个对象实际上可能要复杂得多：这个对象可能有成员变量，在计算顶点的新位置时起作用。

struct Grid6Func
{
  double trans(const double y) const
  {
    return std::tanh(2 * y) / tanh(2);
  }

  Point<2> operator()(const Point<2> &in) const
  {
    return {in(0), trans(in(1))};
  }
};

void grid_6()
{
  Triangulation<2>          triangulation;
  std::vector<unsigned int> repetitions(2);
  repetitions[0] = repetitions[1] = 40;
  GridGenerator::subdivided_hyper_rectangle(triangulation,
                                            repetitions,
                                            Point<2>(0.0, 0.0),
                                            Point<2>(1.0, 1.0));

  GridTools::transform(Grid6Func(), triangulation);
  print_mesh_info(triangulation, "grid-6.vtu");
}
// @sect4{grid_7: Demonstrating distort_random}

// 在这最后一个例子中，我们创建了一个网格，然后通过随机扰动使其（内部）顶点变形。这不是你想在生产计算中做的事情（因为在具有 "良好形状 "单元的网格上的结果通常比在 GridTools::distort_random()), 产生的变形单元上的结果要好，但这是一个有用的工具，可以测试离散化和代码，确保它们不会因为网格恰好是均匀结构和支持超级收敛特性而意外地工作。

void grid_7()
{
  Triangulation<2>          triangulation;
  std::vector<unsigned int> repetitions(2);
  repetitions[0] = repetitions[1] = 16;
  GridGenerator::subdivided_hyper_rectangle(triangulation,
                                            repetitions,
                                            Point<2>(0.0, 0.0),
                                            Point<2>(1.0, 1.0));

  GridTools::distort_random(0.3, triangulation, true);
  print_mesh_info(triangulation, "grid-7.vtu");
}
// @sect3{The main function}

// 最后是主函数。这里没有什么可做的，只是调用我们上面写的所有各种函数。

int main()
{
  try
    {
      grid_1();
      grid_2();
      grid_3();
      grid_4();
      grid_5();
      grid_6();
      grid_7();
    }
  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;
    }
}


/**
 * \file dcs/disjoint_sets.hpp
 *
 * \brief Implementation of the disjoint-sets (union-find) data structure.
 *
 * \author Marco Guazzone (marco.guazzone@gmail.com)
 *
 * <hr/>
 *
 * Copyright 2009 Marco Guazzone (marco.guazzone@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef DCS_DISJOINT_SETS_HPP
#define DCS_DISJOINT_SETS_HPP

#include <boost/function.hpp>
#include <cstddef>
#include <map>
#include <vector>

namespace dcs {

namespace detail { namespace /*<unnamed>*/ {

template <typename T,typename ValueT>
struct identity_hasher
{
	ValueT operator()(T const& t) { return t; }
}; // identity

template <class ParentPA, class Vertex>
Vertex find_representative_with_path_halving(ParentPA p, Vertex v)
{
  Vertex parent = p[v];
  Vertex grandparent = p[parent];
  while (parent != grandparent) {
    p[v] = grandparent;
    v =  grandparent;
    parent = p[v];
    grandparent = p[parent];
  }
  return parent;
}

template <class ParentPA, class Vertex>
Vertex find_representative_with_full_compression(ParentPA parent, Vertex v)
{
  Vertex old = v;
  Vertex ancestor = parent[v];
  while (ancestor != v) {
    v = ancestor;
    ancestor = parent[v];
  }
  v = parent[old];
  while (ancestor != v) {
    parent[old] = ancestor;
    old = v;
    v = parent[old];
  }
  return ancestor;
}

}} // Namespace detail::<unnamed>

struct find_with_path_halving
{
	template <class ParentPA, class Vertex>
	Vertex operator()(ParentPA p, Vertex v) const
	{
		return detail::find_representative_with_path_halving(p, v);
	}
};

struct find_with_full_path_compression
{
	template <class ParentPA, class Vertex>
	Vertex operator()(ParentPA p, Vertex v) const
	{
		return detail::find_representative_with_full_compression(p, v);
	}
};

template <typename ElementT, typename FinderT = find_with_full_path_compression>
class disjoint_sets
{
	public: typedef ElementT element_type;
	public: typedef ::std::size_t size_type;
	public: typedef size_type (*hash_function_type)(element_type const&);
	public: typedef FinderT finder_type;

	public: disjoint_sets()
	: hash_(detail::identity_hasher<element_type,size_type>())
	{
	}

	public: void make_set(element_type const& e)
	{
		size_type sid(id_map_.size());
		id_map_[hash_(e)] = sid;
		inv_id_map_[sid] = e;
		ranks_.push_back(0);
		parents_.push_back(sid);

	}

	public: size_type find_set(element_type const& e) const
	{
		return finder_(parents_, id_map_.at(hash_(e)));
	}

	public: void link_sets(element_type const& e1, element_type const& e2)
	{
		size_type sid1 = find_set(e1);
		size_type sid2 = find_set(e2);
		if (sid1 == sid2)
		{
			return;
		}

		// e1 and e1 are not already in same set. Merge them.
		if (ranks_[sid1] > ranks_[sid2])
		{
			parents_[sid2] = sid1;
		}
		else
		{
			parents_[sid1] = sid2;
			if (ranks_[sid1] == ranks_[sid2])
			{
				ranks_[sid2] += 1;
			}
		}
	}

	public: void union_sets(element_type const& e1, element_type const& e2)
	{
		link_sets(find_set(e1), find_set(e2));
	}

	private: ::std::vector<size_type> ranks_;
	private: ::std::vector<size_type> parents_;
	private: ::std::map<size_type,size_type> id_map_;
	private: ::std::map<size_type,element_type> inv_id_map_;
	private: ::boost::function<size_type(element_type const&)> hash_;
	private: finder_type finder_;
}; // disjoint_sets

} // Namespace dcs

#endif // DCS_DISJOINT_SETS_HPP


// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_GRAPH_CYCLE_HPP
#define BOOST_GRAPH_CYCLE_HPP

#include <vector>

#include <boost/config.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/properties.hpp>

#include <boost/concept/detail/concept_def.hpp>
namespace boost {
    namespace concepts {
        BOOST_concept(CycleVisitor,(Visitor)(Path)(Graph))
        {
            BOOST_CONCEPT_USAGE(CycleVisitor)
            {
                vis.cycle(p, g);
            }
        private:
            Visitor vis;
            Graph g;
            Path p;
        };
    } /* namespace concepts */
using concepts::CycleVisitorConcept;
} /* namespace boost */
#include <boost/concept/detail/concept_undef.hpp>

namespace boost
{

// The implementation of this algorithm is a reproduction of the Teirnan
// approach for directed graphs: bibtex follows
//
//     @article{362819,
//         author = {James C. Tiernan},
//         title = {An efficient search algorithm to find the elementary circuits of a graph},
//         journal = {Commun. ACM},
//         volume = {13},
//         number = {12},
//         year = {1970},
//         issn = {0001-0782},
//         pages = {722--726},
//         doi = {http://doi.acm.org/10.1145/362814.362819},
//             publisher = {ACM Press},
//             address = {New York, NY, USA},
//         }
//
// It should be pointed out that the author does not provide a complete analysis for
// either time or space. This is in part, due to the fact that it's a fairly input
// sensitive problem related to the density and construction of the graph, not just
// its size.
//
// I've also taken some liberties with the interpretation of the algorithm - I've
// basically modernized it to use real data structures (no more arrays and matrices).
// Oh... and there's explicit control structures - not just gotos.
//
// The problem is definitely NP-complete, an an unbounded implementation of this
// will probably run for quite a while on a large graph. The conclusions
// of this paper also reference a Paton algorithm for undirected graphs as being
// much more efficient (apparently based on spanning trees). Although not implemented,
// it can be found here:
//
//     @article{363232,
//         author = {Keith Paton},
//         title = {An algorithm for finding a fundamental set of cycles of a graph},
//         journal = {Commun. ACM},
//         volume = {12},
//         number = {9},
//         year = {1969},
//         issn = {0001-0782},
//         pages = {514--518},
//         doi = {http://doi.acm.org/10.1145/363219.363232},
//             publisher = {ACM Press},
//             address = {New York, NY, USA},
//         }

/**
 * The default cycle visitor providse an empty visit function for cycle
 * visitors.
 */
struct cycle_visitor
{
    template <typename Path, typename Graph>
    inline void cycle(const Path& p, const Graph& g)
    { }
};

/**
 * The min_max_cycle_visitor simultaneously records the minimum and maximum
 * cycles in a graph.
 */
struct min_max_cycle_visitor
{
    min_max_cycle_visitor(std::size_t& min_, std::size_t& max_)
        : minimum(min_), maximum(max_)
    { }

    template <typename Path, typename Graph>
    inline void cycle(const Path& p, const Graph& g)
    {
        BOOST_USING_STD_MIN();
        BOOST_USING_STD_MAX();
        std::size_t len = p.size();
        minimum = min BOOST_PREVENT_MACRO_SUBSTITUTION (minimum, len);
        maximum = max BOOST_PREVENT_MACRO_SUBSTITUTION (maximum, len);
    }
    std::size_t& minimum;
    std::size_t& maximum;
};

inline min_max_cycle_visitor
find_min_max_cycle(std::size_t& min_, std::size_t& max_)
{ return min_max_cycle_visitor(min_, max_); }

namespace detail
{
    template <typename Graph, typename Path>
    inline bool
    is_vertex_in_path(const Graph&,
                        typename graph_traits<Graph>::vertex_descriptor v,
                        const Path& p)
    {
        return (std::find(p.begin(), p.end(), v) != p.end());
    }

    template <typename Graph, typename ClosedMatrix>
    inline bool
    is_path_closed(const Graph& g,
                    typename graph_traits<Graph>::vertex_descriptor u,
                    typename graph_traits<Graph>::vertex_descriptor v,
                    const ClosedMatrix& closed)
    {
        // the path from u to v is closed if v can be found in the list
        // of closed vertices associated with u.
        typedef typename ClosedMatrix::const_reference Row;
        Row r = closed[get(vertex_index, g, u)];
        if(find(r.begin(), r.end(), v) != r.end()) {
            return true;
        }
        return false;
    }

    template <typename Graph, typename Path, typename ClosedMatrix>
    inline bool
    can_extend_path(const Graph& g,
                    typename graph_traits<Graph>::edge_descriptor e,
                    const Path& p,
                    const ClosedMatrix& m)
    {
        function_requires< IncidenceGraphConcept<Graph> >();
        function_requires< VertexIndexGraphConcept<Graph> >();
        typedef typename graph_traits<Graph>::vertex_descriptor Vertex;

        // get the vertices in question
        Vertex
            u = source(e, g),
            v = target(e, g);

        // conditions for allowing a traversal along this edge are:
        // 1. the index of v must be greater than that at which the
        //    the path is rooted (p.front()).
        // 2. the vertex v cannot already be in the path
        // 3. the vertex v cannot be closed to the vertex u

        bool indices = get(vertex_index, g, p.front()) < get(vertex_index, g, v);
        bool path = !is_vertex_in_path(g, v, p);
        bool closed = !is_path_closed(g, u, v, m);
        return indices && path && closed;
    }

    template <typename Graph, typename Path>
    inline bool
    can_wrap_path(const Graph& g, const Path& p)
    {
        function_requires< IncidenceGraphConcept<Graph> >();
        typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
        typedef typename graph_traits<Graph>::out_edge_iterator OutIterator;

        // iterate over the out-edges of the back, looking for the
        // front of the path. also, we can't travel along the same
        // edge that we did on the way here, but we don't quite have the
        // stringent requirements that we do in can_extend_path().
        Vertex
            u = p.back(),
            v = p.front();
        OutIterator i, end;
        for(boost::tie(i, end) = out_edges(u, g); i != end; ++i) {
            if((target(*i, g) == v)) {
                return true;
            }
        }
        return false;
    }

    template <typename Graph,
        typename Path,
        typename ClosedMatrix>
    inline typename graph_traits<Graph>::vertex_descriptor
    extend_path(const Graph& g,
                Path& p,
                ClosedMatrix& closed)
    {
        function_requires< IncidenceGraphConcept<Graph> >();
        typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
        typedef typename graph_traits<Graph>::edge_descriptor Edge;
        typedef typename graph_traits<Graph>::out_edge_iterator OutIterator;

        // get the current vertex
        Vertex u = p.back();
        Vertex ret = graph_traits<Graph>::null_vertex();

        // AdjacencyIterator i, end;
        OutIterator i, end;
        for(boost::tie(i, end) = out_edges(u, g); i != end; ++i) {
            Vertex v = target(*i, g);

            // if we can actually extend along this edge,
            // then that's what we want to do
            if(can_extend_path(g, *i, p, closed)) {
                p.push_back(v);         // add the vertex to the path
                ret = v;
                break;
            }
        }
        return ret;
    }

    template <typename Graph, typename Path, typename ClosedMatrix>
    inline bool
    exhaust_paths(const Graph& g, Path& p, ClosedMatrix& closed)
    {
        function_requires< GraphConcept<Graph> >();
        typedef typename graph_traits<Graph>::vertex_descriptor Vertex;

        // if there's more than one vertex in the path, this closes
        // of some possible routes and returns true. otherwise, if there's
        // only one vertex left, the vertex has been used up
        if(p.size() > 1) {
            // get the last and second to last vertices, popping the last
            // vertex off the path
            Vertex last, prev;
            last = p.back();
            p.pop_back();
            prev = p.back();

            // reset the closure for the last vertex of the path and
            // indicate that the last vertex in p is now closed to
            // the next-to-last vertex in p
            closed[get(vertex_index, g, last)].clear();
            closed[get(vertex_index, g, prev)].push_back(last);
            return true;
        }
        else {
            return false;
        }
    }

    template <typename Graph, typename Visitor>
    inline void
    all_cycles_from_vertex(const Graph& g,
                            typename graph_traits<Graph>::vertex_descriptor v,
                            Visitor vis,
                            std::size_t minlen,
                            std::size_t maxlen)
    {
        function_requires< VertexListGraphConcept<Graph> >();
        typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
        typedef std::vector<Vertex> Path;
        function_requires< CycleVisitorConcept<Visitor,Path,Graph> >();
        typedef std::vector<Vertex> VertexList;
        typedef std::vector<VertexList> ClosedMatrix;

        Path p;
        ClosedMatrix closed(num_vertices(g), VertexList());
        Vertex null = graph_traits<Graph>::null_vertex();

        // each path investigation starts at the ith vertex
        p.push_back(v);

        while(1) {
            // extend the path until we've reached the end or the
            // maxlen-sized cycle
            Vertex j = null;
            while(((j = detail::extend_path(g, p, closed)) != null)
                    && (p.size() < maxlen))
                ; // empty loop

            // if we're done extending the path and there's an edge
            // connecting the back to the front, then we should have
            // a cycle.
            if(detail::can_wrap_path(g, p) && p.size() >= minlen) {
                vis.cycle(p, g);
            }

            if(!detail::exhaust_paths(g, p, closed)) {
                break;
            }
        }
    }

    // Select the minimum allowable length of a cycle based on the directedness
    // of the graph - 2 for directed, 3 for undirected.
    template <typename D> struct min_cycles { enum { value = 2 }; };
    template <> struct min_cycles<undirected_tag> { enum { value = 3 }; };
} /* namespace detail */

template <typename Graph, typename Visitor>
inline void
tiernan_all_cycles(const Graph& g,
                    Visitor vis,
                    std::size_t minlen,
                    std::size_t maxlen)
{
    function_requires< VertexListGraphConcept<Graph> >();
    typedef typename graph_traits<Graph>::vertex_iterator VertexIterator;

    VertexIterator i, end;
    for(boost::tie(i, end) = vertices(g); i != end; ++i) {
        detail::all_cycles_from_vertex(g, *i, vis, minlen, maxlen);
    }
}

template <typename Graph, typename Visitor>
inline void
tiernan_all_cycles(const Graph& g, Visitor vis, std::size_t maxlen)
{
    typedef typename graph_traits<Graph>::directed_category Dir;
    tiernan_all_cycles(g, vis, detail::min_cycles<Dir>::value, maxlen);
}

template <typename Graph, typename Visitor>
inline void
tiernan_all_cycles(const Graph& g, Visitor vis)
{
    typedef typename graph_traits<Graph>::directed_category Dir;
    tiernan_all_cycles(g, vis, detail::min_cycles<Dir>::value,
                       (std::numeric_limits<std::size_t>::max)());
}

template <typename Graph>
inline std::pair<std::size_t, std::size_t>
tiernan_girth_and_circumference(const Graph& g)
{
    std::size_t
        min_ = (std::numeric_limits<std::size_t>::max)(),
        max_ = 0;
    tiernan_all_cycles(g, find_min_max_cycle(min_, max_));

    // if this is the case, the graph is acyclic...
    if(max_ == 0) max_ = min_;

    return std::make_pair(min_, max_);
}

template <typename Graph>
inline std::size_t
tiernan_girth(const Graph& g)
{ return tiernan_girth_and_circumference(g).first; }

template <typename Graph>
inline std::size_t
tiernan_circumference(const Graph& g)
{ return tiernan_girth_and_circumference(g).second; }

} /* namespace boost */

#endif


//  Copyright John Maddock 2006.
//  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)

// distributions.hpp provides definitions of the concept of a distribution
// and non-member accessor functions that must be implemented by all distributions.
// This is used to verify that
// all the features of a distributions have been fully implemented.

#ifndef BOOST_MATH_DISTRIBUTION_CONCEPT_HPP
#define BOOST_MATH_DISTRIBUTION_CONCEPT_HPP

#include <boost/math/distributions/complement.hpp>
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable: 4100)
#pragma warning(disable: 4510)
#pragma warning(disable: 4610)
#endif
#include <boost/concept_check.hpp>
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#include <utility>

namespace boost{
namespace math{

namespace concepts
{
// Begin by defining a concept archetype
// for a distribution class:
//
template <class RealType>
class distribution_archetype
{
public:
   typedef RealType value_type;

   distribution_archetype(const distribution_archetype&); // Copy constructible.
   distribution_archetype& operator=(const distribution_archetype&); // Assignable.

   // There is no default constructor,
   // but we need a way to instantiate the archetype:
   static distribution_archetype& get_object()
   {
      // will never get caled:
      return *reinterpret_cast<distribution_archetype*>(0);
   }
}; // template <class RealType>class distribution_archetype

// Non-member accessor functions:
// (This list defines the functions that must be implemented by all distributions).

template <class RealType>
RealType pdf(const distribution_archetype<RealType>& dist, const RealType& x);

template <class RealType>
RealType cdf(const distribution_archetype<RealType>& dist, const RealType& x);

template <class RealType>
RealType quantile(const distribution_archetype<RealType>& dist, const RealType& p);

template <class RealType>
RealType cdf(const complemented2_type<distribution_archetype<RealType>, RealType>& c);

template <class RealType>
RealType quantile(const complemented2_type<distribution_archetype<RealType>, RealType>& c);

template <class RealType>
RealType mean(const distribution_archetype<RealType>& dist);

template <class RealType>
RealType standard_deviation(const distribution_archetype<RealType>& dist);

template <class RealType>
RealType variance(const distribution_archetype<RealType>& dist);

template <class RealType>
RealType hazard(const distribution_archetype<RealType>& dist);

template <class RealType>
RealType chf(const distribution_archetype<RealType>& dist);
// http://en.wikipedia.org/wiki/Characteristic_function_%28probability_theory%29

template <class RealType>
RealType coefficient_of_variation(const distribution_archetype<RealType>& dist);

template <class RealType>
RealType mode(const distribution_archetype<RealType>& dist);

template <class RealType>
RealType skewness(const distribution_archetype<RealType>& dist);

template <class RealType>
RealType kurtosis_excess(const distribution_archetype<RealType>& dist);

template <class RealType>
RealType kurtosis(const distribution_archetype<RealType>& dist);

template <class RealType>
RealType median(const distribution_archetype<RealType>& dist);

template <class RealType>
std::pair<RealType, RealType> range(const distribution_archetype<RealType>& dist);

template <class RealType>
std::pair<RealType, RealType> support(const distribution_archetype<RealType>& dist);

//
// Next comes the concept checks for verifying that a class
// fullfils the requirements of a Distribution:
//
template <class Distribution>
struct DistributionConcept
{
   void constraints()
   {
      function_requires<CopyConstructibleConcept<Distribution> >();
      function_requires<AssignableConcept<Distribution> >();

      typedef typename Distribution::value_type value_type;

      const Distribution& dist = DistributionConcept<Distribution>::get_object();

      value_type x = 0;
       // The result values are ignored in all these checks.
       value_type v = cdf(dist, x);
      v = cdf(complement(dist, x));
      v = pdf(dist, x);
      v = quantile(dist, x);
      v = quantile(complement(dist, x));
      v = mean(dist);
      v = mode(dist);
      v = standard_deviation(dist);
      v = variance(dist);
      v = hazard(dist, x);
      v = chf(dist, x);
      v = coefficient_of_variation(dist);
      v = skewness(dist);
      v = kurtosis(dist);
      v = kurtosis_excess(dist);
      v = median(dist);
      std::pair<value_type, value_type> pv;
      pv = range(dist);
      pv = support(dist);

      float f = 1;
      v = cdf(dist, f);
      v = cdf(complement(dist, f));
      v = pdf(dist, f);
      v = quantile(dist, f);
      v = quantile(complement(dist, f));
      v = hazard(dist, f);
      v = chf(dist, f);
      double d = 1;
      v = cdf(dist, d);
      v = cdf(complement(dist, d));
      v = pdf(dist, d);
      v = quantile(dist, d);
      v = quantile(complement(dist, d));
      v = hazard(dist, d);
      v = chf(dist, d);
#ifndef TEST_MPFR
      long double ld = 1;
      v = cdf(dist, ld);
      v = cdf(complement(dist, ld));
      v = pdf(dist, ld);
      v = quantile(dist, ld);
      v = quantile(complement(dist, ld));
      v = hazard(dist, ld);
      v = chf(dist, ld);
#endif
      int i = 1;
      v = cdf(dist, i);
      v = cdf(complement(dist, i));
      v = pdf(dist, i);
      v = quantile(dist, i);
      v = quantile(complement(dist, i));
      v = hazard(dist, i);
      v = chf(dist, i);
      unsigned long li = 1;
      v = cdf(dist, li);
      v = cdf(complement(dist, li));
      v = pdf(dist, li);
      v = quantile(dist, li);
      v = quantile(complement(dist, li));
      v = hazard(dist, li);
      v = chf(dist, li);
   }
private:
   static Distribution& get_object()
   {
      // will never get called:
      static char buf[sizeof(Distribution)];
      return * reinterpret_cast<Distribution*>(buf);
   }
}; // struct DistributionConcept

} // namespace concepts
} // namespace math
} // namespace boost

#endif // BOOST_MATH_DISTRIBUTION_CONCEPT_HPP


/*
//@HEADER
// ************************************************************************
//
// tutorial1.cc
//                     		  Pressio
//                             Copyright 2019
//    National Technology & Engineering Solutions of Sandia, LLC (NTESS)
//
// Under the terms of Contract DE-NA0003525 with NTESS, the
// U.S. Government retains certain rights in this software.
//
// Pressio is licensed under BSD-3-Clause terms of use:
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
// IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Francesco Rizzi (fnrizzi@sandia.gov)
//
// ************************************************************************
//@HEADER
*/

#include "pressio_containers.hpp"
#include <Eigen/Core>

int main(int argc, char *argv[])
{
  std::cout << "Running tutorial 1\n";

  /*
    Pressio makes use of container wrappers to wrap arbitrary data types.
    These wrappers are thin layers.

    Pressio has predefined knowledge about data structures
    from specific libraries, e.g. Trilinos, Eigen, Kokkos.
    Over time, this support will be extended.
    If your application uses vector/matrix/multivector classes of one
    of these libraries, you can easily use pressio as follows.

    Suppose that you have an application that is based on Eigen.
    Therefore, a (dynamic) vector object "a" in your application looks like:

    Eigen::VectorXd a;

    Now, suppose now that you need to use some functionality in pressio.
    To do so, you need to wrap your object with a pressio container.
    e.g. ::pressio::containers::Vector<Eigen::VectorXd> aW(a);

    If the type you are wrapping is one of the already supported by pressio,
    then you have seamless access to all pressio functionalities, since pressio
    behind the scenes knows how to do algebra with these objects and in fact
    leverages the native algebra functionalities of the target library.
    If the type you are wrapping is NOT already known to pressio,
    then you can still wrap it, but in order to instantiate and use pressio
    functionalities you need to provide functionalities to tell pressio
    how to do operations with your data types.
    See tutorials{3,5} for examples showing using arbitrary types.
  */

  // this is dynamic double array in Eigen
  Eigen::VectorXd a(5);
  a.setConstant(2.2);

  // the corresponding pressio wrapper can be created as follows
  // Note that here pressio makes a deep copy of the object.
  // This is because the target ROM algorithms are all implemented
  // such that pressio owns the data and queries the full-order application
  // to computed things.
  ::pressio::containers::Vector<Eigen::VectorXd> aW(a);

  // we can verify that a deep copy is made
  for (auto i=0; i<aW.extent(0); ++i)
    std::cout << "aW(i) = " << aW(i)
	      << " expected = " << 2.2
	      << std::endl;

  // note that above we used the "extent" method
  // extent(k) works for all pressio container wrappers
  // - extent(k1) for 1d objects,
  // - extent(k1,k2) for 2d objects

  return 0;
}