/* ---------------------------------------------------------------------
 *
 * Copyright (C) 2016 - 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, Clemson University, 2016
 */

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

// 下面这块出场代码与 step-40 相同，可以在PETSc和Trilinos之间切换。

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

/* #define FORCE_USE_OF_TRILINOS */

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

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

#include <deal.II/lac/petsc_sparse_matrix.h>
#include <deal.II/lac/petsc_vector.h>
#include <deal.II/lac/petsc_solver.h>
#include <deal.II/lac/petsc_precondition.h>

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

#include <deal.II/base/utilities.h>
#include <deal.II/base/conditional_ostream.h>
#include <deal.II/base/index_set.h>
#include <deal.II/lac/sparsity_tools.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/distributed/grid_refinement.h>

#include <cmath>
#include <fstream>
#include <iostream>

namespace Step55
{
  using namespace dealii;
// @sect3{Linear solvers and preconditioners}

// 我们需要一些辅助类来表示我们在介绍中描述的求解器策略。

  namespace LinearSolvers
  {

// 这个类暴露了通过函数 InverseMatrix::vmult(). 应用给定矩阵的逆的动作，在内部，逆不是显式形成的。相反，一个带有CG的线性求解器被执行。这个类扩展了 step-22 中的InverseMatrix类，增加了一个指定预处理程序的选项，并允许在vmult函数中使用不同的矢量类型。

    template <class Matrix, class Preconditioner>
    class InverseMatrix : public Subscriptor
    {
    public:
      InverseMatrix(const Matrix &m, const Preconditioner &preconditioner);

      template <typename VectorType>
      void vmult(VectorType &dst, const VectorType &src) const;

    private:
      const SmartPointer<const Matrix> matrix;
      const Preconditioner &           preconditioner;
    };

    template <class Matrix, class Preconditioner>
    InverseMatrix<Matrix, Preconditioner>::InverseMatrix(
      const Matrix &        m,
      const Preconditioner &preconditioner)
      : matrix(&m)
      , preconditioner(preconditioner)
    {}

    template <class Matrix, class Preconditioner>
    template <typename VectorType>
    void
    InverseMatrix<Matrix, Preconditioner>::vmult(VectorType &      dst,
                                                 const VectorType &src) const
    {
      SolverControl solver_control(src.size(), 1e-8 * src.l2_norm());
      SolverCG<LA::MPI::Vector> cg(solver_control);
      dst = 0;

      try
        {
          cg.solve(*matrix, dst, src, preconditioner);
        }
      catch (std::exception &e)
        {
          Assert(false, ExcMessage(e.what()));
        }
    }

// 该类是一个简单的2x2矩阵的块状对角线预处理器的模板类。

    template <class PreconditionerA, class PreconditionerS>
    class BlockDiagonalPreconditioner : public Subscriptor
    {
    public:
      BlockDiagonalPreconditioner(const PreconditionerA &preconditioner_A,
                                  const PreconditionerS &preconditioner_S);

      void vmult(LA::MPI::BlockVector &      dst,
                 const LA::MPI::BlockVector &src) const;

    private:
      const PreconditionerA &preconditioner_A;
      const PreconditionerS &preconditioner_S;
    };

    template <class PreconditionerA, class PreconditionerS>
    BlockDiagonalPreconditioner<PreconditionerA, PreconditionerS>::
      BlockDiagonalPreconditioner(const PreconditionerA &preconditioner_A,
                                  const PreconditionerS &preconditioner_S)
      : preconditioner_A(preconditioner_A)
      , preconditioner_S(preconditioner_S)
    {}

    template <class PreconditionerA, class PreconditionerS>
    void BlockDiagonalPreconditioner<PreconditionerA, PreconditionerS>::vmult(
      LA::MPI::BlockVector &      dst,
      const LA::MPI::BlockVector &src) const
    {
      preconditioner_A.vmult(dst.block(0), src.block(0));
      preconditioner_S.vmult(dst.block(1), src.block(1));
    }

// @sect3{Problem setup}

// 下面的类代表测试问题的右手边和精确解。

  template <int dim>
  class RightHandSide : public Function<dim>
  {
  public:
    RightHandSide()
      : Function<dim>(dim + 1)
    {}

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

  template <int dim>
  void RightHandSide<dim>::vector_value(const Point<dim> &p,
                                        Vector<double> &  values) const
  {
    const double R_x = p[0];
    const double R_y = p[1];

    const double pi  = numbers::PI;
    const double pi2 = pi * pi;
    values[0] =
      -1.0L / 2.0L * (-2 * sqrt(25.0 + 4 * pi2) + 10.0) *
        exp(R_x * (-2 * sqrt(25.0 + 4 * pi2) + 10.0)) -
      0.4 * pi2 * exp(R_x * (-sqrt(25.0 + 4 * pi2) + 5.0)) * cos(2 * R_y * pi) +
      0.1 * pow(-sqrt(25.0 + 4 * pi2) + 5.0, 2) *
        exp(R_x * (-sqrt(25.0 + 4 * pi2) + 5.0)) * cos(2 * R_y * pi);
    values[1] = 0.2 * pi * (-sqrt(25.0 + 4 * pi2) + 5.0) *
                  exp(R_x * (-sqrt(25.0 + 4 * pi2) + 5.0)) * sin(2 * R_y * pi) -
                0.05 * pow(-sqrt(25.0 + 4 * pi2) + 5.0, 3) *
                  exp(R_x * (-sqrt(25.0 + 4 * pi2) + 5.0)) * sin(2 * R_y * pi) /
                  pi;
    values[2] = 0;
  }

  template <int dim>
  class ExactSolution : public Function<dim>
  {
  public:
    ExactSolution()
      : Function<dim>(dim + 1)
    {}

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

  template <int dim>
  void ExactSolution<dim>::vector_value(const Point<dim> &p,
                                        Vector<double> &  values) const
  {
    const double R_x = p[0];
    const double R_y = p[1];

    const double pi  = numbers::PI;
    const double pi2 = pi * pi;
    values[0] =
      -exp(R_x * (-sqrt(25.0 + 4 * pi2) + 5.0)) * cos(2 * R_y * pi) + 1;
    values[1] = (1.0L / 2.0L) * (-sqrt(25.0 + 4 * pi2) + 5.0) *
                exp(R_x * (-sqrt(25.0 + 4 * pi2) + 5.0)) * sin(2 * R_y * pi) /
                pi;
    values[2] =
      -1.0L / 2.0L * exp(R_x * (-2 * sqrt(25.0 + 4 * pi2) + 10.0)) -
      2.0 *
        (-6538034.74494422 +
         0.0134758939981709 * exp(4 * sqrt(25.0 + 4 * pi2))) /
        (-80.0 * exp(3 * sqrt(25.0 + 4 * pi2)) +
         16.0 * sqrt(25.0 + 4 * pi2) * exp(3 * sqrt(25.0 + 4 * pi2))) -
      1634508.68623606 * exp(-3.0 * sqrt(25.0 + 4 * pi2)) /
        (-10.0 + 2.0 * sqrt(25.0 + 4 * pi2)) +
      (-0.00673794699908547 * exp(sqrt(25.0 + 4 * pi2)) +
       3269017.37247211 * exp(-3 * sqrt(25.0 + 4 * pi2))) /
        (-8 * sqrt(25.0 + 4 * pi2) + 40.0) +
      0.00336897349954273 * exp(1.0 * sqrt(25.0 + 4 * pi2)) /
        (-10.0 + 2.0 * sqrt(25.0 + 4 * pi2));
  }

//  @sect3{The main program}

// 主类与  step-40  非常相似，只是矩阵和向量现在是块状的，而且我们为拥有的和相关的DoF存储一个  std::vector<IndexSet>  ，而不是一个IndexSet。我们正好有两个IndexSets，一个用于所有速度未知数，一个用于所有压力未知数。

  template <int dim>
  class StokesProblem
  {
  public:
    StokesProblem(unsigned int velocity_degree);

    void run();

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

    unsigned int velocity_degree;
    double       viscosity;
    MPI_Comm     mpi_communicator;

    FESystem<dim>                             fe;
    parallel::distributed::Triangulation<dim> triangulation;
    DoFHandler<dim>                           dof_handler;

    std::vector<IndexSet> owned_partitioning;
    std::vector<IndexSet> relevant_partitioning;

    AffineConstraints<double> constraints;

    LA::MPI::BlockSparseMatrix system_matrix;
    LA::MPI::BlockSparseMatrix preconditioner_matrix;
    LA::MPI::BlockVector       locally_relevant_solution;
    LA::MPI::BlockVector       system_rhs;

    ConditionalOStream pcout;
    TimerOutput        computing_timer;
  };

  template <int dim>
  StokesProblem<dim>::StokesProblem(unsigned int velocity_degree)
    : velocity_degree(velocity_degree)
    , viscosity(0.1)
    , mpi_communicator(MPI_COMM_WORLD)
    , fe(FE_Q<dim>(velocity_degree), dim, FE_Q<dim>(velocity_degree - 1), 1)
    , triangulation(mpi_communicator,
                    typename Triangulation<dim>::MeshSmoothing(
                      Triangulation<dim>::smoothing_on_refinement |
                      Triangulation<dim>::smoothing_on_coarsening))
    , dof_handler(triangulation)
    , pcout(std::cout,
            (Utilities::MPI::this_mpi_process(mpi_communicator) == 0))
    , computing_timer(mpi_communicator,
                      pcout,
                      TimerOutput::summary,
                      TimerOutput::wall_times)
  {}

// Kovasnay流定义在域[-0.5, 1.5]^2上，我们通过将最小和最大值传递给 GridGenerator::hyper_cube. 来创建这个域。
  template <int dim>
  void StokesProblem<dim>::make_grid()
  {
    GridGenerator::hyper_cube(triangulation, -0.5, 1.5);
    triangulation.refine_global(3);
  }
// @sect3{System Setup}

// 与 step-40 相比，块矩阵和向量的构造是新的，与 step-22 这样的串行代码相比也是不同的，因为我们需要提供属于我们处理器的行的集合。

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

    dof_handler.distribute_dofs(fe);

// 将所有的昏暗速度放入0区块，压力放入1区块，然后按区块重新排列未知数。最后计算每块有多少个未知数。

    std::vector<unsigned int> stokes_sub_blocks(dim + 1, 0);
    stokes_sub_blocks[dim] = 1;
    DoFRenumbering::component_wise(dof_handler, stokes_sub_blocks);

    const std::vector<types::global_dof_index> dofs_per_block =
      DoFTools::count_dofs_per_fe_block(dof_handler, stokes_sub_blocks);

    const unsigned int n_u = dofs_per_block[0];
    const unsigned int n_p = dofs_per_block[1];

    pcout << "   Number of degrees of freedom: " << dof_handler.n_dofs() << " ("
          << n_u << '+' << n_p << ')' << std::endl;

// 我们根据我们想要创建块状矩阵和向量的方式，将本地拥有的和本地相关的DoF的IndexSet分割成两个IndexSets。

    owned_partitioning.resize(2);
    owned_partitioning[0] = dof_handler.locally_owned_dofs().get_view(0, n_u);
    owned_partitioning[1] =
      dof_handler.locally_owned_dofs().get_view(n_u, n_u + n_p);

    IndexSet locally_relevant_dofs;
    DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant_dofs);
    relevant_partitioning.resize(2);
    relevant_partitioning[0] = locally_relevant_dofs.get_view(0, n_u);
    relevant_partitioning[1] = locally_relevant_dofs.get_view(n_u, n_u + n_p);

// 设置边界条件和悬挂节点的约束与  step-40  相同。尽管我们没有任何悬空节点，因为我们只进行全局细化，但把这个函数调用放进去仍然是个好主意，以备以后引入自适应细化。

    {
      constraints.reinit(locally_relevant_dofs);

      FEValuesExtractors::Vector velocities(0);
      DoFTools::make_hanging_node_constraints(dof_handler, constraints);
      VectorTools::interpolate_boundary_values(dof_handler,
                                               0,
                                               ExactSolution<dim>(),
                                               constraints,
                                               fe.component_mask(velocities));
      constraints.close();
    }

// 现在我们根据BlockDynamicSparsityPattern来创建系统矩阵。我们知道我们不会有不同速度分量之间的耦合（因为我们使用的是拉普拉斯而不是变形张量），也不会有压力与其测试函数之间的耦合，所以我们使用一个表来将这个耦合信息传达给  DoFTools::make_sparsity_pattern.  。
    {
      system_matrix.clear();

      Table<2, DoFTools::Coupling> coupling(dim + 1, dim + 1);
      for (unsigned int c = 0; c < dim + 1; ++c)
        for (unsigned int d = 0; d < dim + 1; ++d)
          if (c == dim && d == dim)
            coupling[c][d] = DoFTools::none;
          else if (c == dim || d == dim || c == d)
            coupling[c][d] = DoFTools::always;
          else
            coupling[c][d] = DoFTools::none;

      BlockDynamicSparsityPattern dsp(dofs_per_block, dofs_per_block);

      DoFTools::make_sparsity_pattern(
        dof_handler, coupling, dsp, constraints, false);

      SparsityTools::distribute_sparsity_pattern(
        dsp,
        dof_handler.locally_owned_dofs(),
        mpi_communicator,
        locally_relevant_dofs);

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

// 先决条件矩阵有不同的耦合（我们只在1,1块中填入质量矩阵），否则这段代码与上面的system_matrix的构造是相同的。

    {
      preconditioner_matrix.clear();

      Table<2, DoFTools::Coupling> coupling(dim + 1, dim + 1);
      for (unsigned int c = 0; c < dim + 1; ++c)
        for (unsigned int d = 0; d < dim + 1; ++d)
          if (c == dim && d == dim)
            coupling[c][d] = DoFTools::always;
          else
            coupling[c][d] = DoFTools::none;

      BlockDynamicSparsityPattern dsp(dofs_per_block, dofs_per_block);

      DoFTools::make_sparsity_pattern(
        dof_handler, coupling, dsp, constraints, false);
      SparsityTools::distribute_sparsity_pattern(
        dsp,
        Utilities::MPI::all_gather(mpi_communicator,
                                   dof_handler.locally_owned_dofs()),
        mpi_communicator,
        locally_relevant_dofs);
      preconditioner_matrix.reinit(owned_partitioning,

// owned_partitioning。

                                   dsp,
                                   mpi_communicator);
    }

// 最后，我们以正确的尺寸构建块状向量。带有两个 std::vector<IndexSet> 的函数调用将创建一个重影向量。

    locally_relevant_solution.reinit(owned_partitioning,
                                     relevant_partitioning,
                                     mpi_communicator);
    system_rhs.reinit(owned_partitioning, mpi_communicator);
  }

//  @sect3{Assembly}

// 这个函数将系统矩阵、预处理矩阵和右手边集合起来。其代码非常标准。

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

    system_matrix         = 0;
    preconditioner_matrix = 0;
    system_rhs            = 0;

    const QGauss<dim> quadrature_formula(velocity_degree + 1);

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

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

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

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

    std::vector<Tensor<2, dim>> grad_phi_u(dofs_per_cell);
    std::vector<double>         div_phi_u(dofs_per_cell);
    std::vector<double>         phi_p(dofs_per_cell);

    std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
    const FEValuesExtractors::Vector     velocities(0);
    const FEValuesExtractors::Scalar     pressure(dim);

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

          fe_values.reinit(cell);
          right_hand_side.vector_value_list(fe_values.get_quadrature_points(),
                                            rhs_values);
          for (unsigned int q = 0; q < n_q_points; ++q)
            {
              for (unsigned int k = 0; k < dofs_per_cell; ++k)
                {
                  grad_phi_u[k] = fe_values[velocities].gradient(k, q);
                  div_phi_u[k]  = fe_values[velocities].divergence(k, q);
                  phi_p[k]      = fe_values[pressure].value(k, q);
                }

              for (unsigned int i = 0; i < dofs_per_cell; ++i)
                {
                  for (unsigned int j = 0; j < dofs_per_cell; ++j)
                    {
                      cell_matrix(i, j) +=
                        (viscosity *
                           scalar_product(grad_phi_u[i], grad_phi_u[j]) -
                         div_phi_u[i] * phi_p[j] - phi_p[i] * div_phi_u[j]) *
                        fe_values.JxW(q);

                      cell_matrix2(i, j) += 1.0 / viscosity * phi_p[i] *
                                            phi_p[j] * fe_values.JxW(q);
                    }

                  const unsigned int component_i =
                    fe.system_to_component_index(i).first;
                  cell_rhs(i) += fe_values.shape_value(i, q) *
                                 rhs_values[q](component_i) * fe_values.JxW(q);
                }
            }

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

          constraints.distribute_local_to_global(cell_matrix2,
                                                 local_dof_indices,
                                                 preconditioner_matrix);
        }

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

//  @sect3{Solving}

// 这个函数用MINRES求解线性系统，如介绍中所述，对两个对角线块使用块状对角线预处理和AMG。预处理程序对0,0块应用v循环，对1,1块应用质量矩阵的CG（Schur补充）。

  template <int dim>
  void StokesProblem<dim>::solve()
  {
    TimerOutput::Scope t(computing_timer, "solve");

    LA::MPI::PreconditionAMG prec_A;
    {
      LA::MPI::PreconditionAMG::AdditionalData data;

#ifdef USE_PETSC_LA
      data.symmetric_operator = true;
#endif
      prec_A.initialize(system_matrix.block(0, 0), data);
    }

    LA::MPI::PreconditionAMG prec_S;
    {
      LA::MPI::PreconditionAMG::AdditionalData data;

#ifdef USE_PETSC_LA
      data.symmetric_operator = true;
#endif
      prec_S.initialize(preconditioner_matrix.block(1, 1), data);
    }

// InverseMatrix用于解决质量矩阵的问题。

    using mp_inverse_t = LinearSolvers::InverseMatrix<LA::MPI::SparseMatrix,
                                                      LA::MPI::PreconditionAMG>;
    const mp_inverse_t mp_inverse(preconditioner_matrix.block(1, 1), prec_S);

// 这是在上面定义的各个块的预处理的基础上构造的块预处理。

    const LinearSolvers::BlockDiagonalPreconditioner<LA::MPI::PreconditionAMG,
                                                     mp_inverse_t>
      preconditioner(prec_A, mp_inverse);

// 有了这些，我们终于可以设置线性求解器并求解该系统。

    SolverControl solver_control(system_matrix.m(),
                                 1e-10 * system_rhs.l2_norm());

    SolverMinRes<LA::MPI::BlockVector> solver(solver_control);

    LA::MPI::BlockVector distributed_solution(owned_partitioning,
                                              mpi_communicator);

    constraints.set_zero(distributed_solution);

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

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

    constraints.distribute(distributed_solution);

// 像在  step-56  中一样，我们减去平均压力，以便与我们的参考解决方案进行误差计算，该解决方案的平均值为零。

    locally_relevant_solution = distributed_solution;
    const double mean_pressure =
      VectorTools::compute_mean_value(dof_handler,
                                      QGauss<dim>(velocity_degree + 2),
                                      locally_relevant_solution,
                                      dim);
    distributed_solution.block(1).add(-mean_pressure);
    locally_relevant_solution.block(1) = distributed_solution.block(1);
  }

//  @sect3{The rest}

// 其余处理网格细化、输出和主循环的代码非常标准。

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

    triangulation.refine_global();
  }

  template <int dim>
  void StokesProblem<dim>::output_results(const unsigned int cycle) const
  {
    {
      const ComponentSelectFunction<dim> pressure_mask(dim, dim + 1);
      const ComponentSelectFunction<dim> velocity_mask(std::make_pair(0, dim),
                                                       dim + 1);

      Vector<double> cellwise_errors(triangulation.n_active_cells());
      QGauss<dim>    quadrature(velocity_degree + 2);

      VectorTools::integrate_difference(dof_handler,
                                        locally_relevant_solution,
                                        ExactSolution<dim>(),
                                        cellwise_errors,
                                        quadrature,
                                        VectorTools::L2_norm,
                                        &velocity_mask);

      const double error_u_l2 =
        VectorTools::compute_global_error(triangulation,
                                          cellwise_errors,
                                          VectorTools::L2_norm);

      VectorTools::integrate_difference(dof_handler,
                                        locally_relevant_solution,
                                        ExactSolution<dim>(),
                                        cellwise_errors,
                                        quadrature,
                                        VectorTools::L2_norm,
                                        &pressure_mask);

      const double error_p_l2 =
        VectorTools::compute_global_error(triangulation,
                                          cellwise_errors,
                                          VectorTools::L2_norm);

      pcout << "error: u_0: " << error_u_l2 << " p_0: " << error_p_l2
            << std::endl;
    }

    std::vector<std::string> solution_names(dim, "velocity");
    solution_names.emplace_back("pressure");
    std::vector<DataComponentInterpretation::DataComponentInterpretation>
      data_component_interpretation(
        dim, DataComponentInterpretation::component_is_part_of_vector);
    data_component_interpretation.push_back(
      DataComponentInterpretation::component_is_scalar);

    DataOut<dim> data_out;
    data_out.attach_dof_handler(dof_handler);
    data_out.add_data_vector(locally_relevant_solution,
                             solution_names,
                             DataOut<dim>::type_dof_data,
                             data_component_interpretation);

    LA::MPI::BlockVector interpolated;
    interpolated.reinit(owned_partitioning, MPI_COMM_WORLD);
    VectorTools::interpolate(dof_handler, ExactSolution<dim>(), interpolated);

    LA::MPI::BlockVector interpolated_relevant(owned_partitioning,
                                               relevant_partitioning,
                                               MPI_COMM_WORLD);
    interpolated_relevant = interpolated;
    {
      std::vector<std::string> solution_names(dim, "ref_u");
      solution_names.emplace_back("ref_p");
      data_out.add_data_vector(interpolated_relevant,
                               solution_names,
                               DataOut<dim>::type_dof_data,
                               data_component_interpretation);
    }

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

    data_out.build_patches();

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

  template <int dim>
  void StokesProblem<dim>::run()
  {
#ifdef USE_PETSC_LA
    pcout << "Running using PETSc." << std::endl;
#else
    pcout << "Running using Trilinos." << std::endl;
#endif
    const unsigned int n_cycles = 5;
    for (unsigned int cycle = 0; cycle < n_cycles; ++cycle)
      {
        pcout << "Cycle " << cycle << ':' << std::endl;

        if (cycle == 0)
          make_grid();
        else
          refine_grid();

        setup_system();

        assemble_system();
        solve();

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

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

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

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

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

      StokesProblem<2> problem(2);
      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;
}


/*
 * Copyright 2017 Mahdi Khanalizadeh
 *
 * 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 HEADER_EXT_VECTOR3_HPP_INCLUDED
#define HEADER_EXT_VECTOR3_HPP_INCLUDED

#include <cmath>

#include <boost/operators.hpp>

namespace ext
{

	template <typename T>
	class Vector3 :
		boost::equality_comparable<Vector3<T>,
		boost::additive<Vector3<T>,
		boost::multiplicative<Vector3<T>, T
		>>>
	{
	public:
		using Type = T;

		Type x;
		Type y;
		Type z;

		Vector3() : x{0}, y{0}, z{0} {}
		Vector3(Type x_, Type y_, Type z_) : x{x_}, y{y_}, z{z_} {}
		template <typename U>
		Vector3(Vector3<U> const& v) : x{v.x}, y{v.y}, z{v.z} {}
	};

	using Vector3f = Vector3<float>;
	using Vector3d = Vector3<double>;
	using Vector3ld = Vector3<long double>;

	template <typename T>
	bool operator==(Vector3<T> const& v1, Vector3<T> const& v2)
	{
		return v1.x == v2.x && v1.y == v2.y && v1.z == v2.z;
	}

	template <typename T>
	Vector3<T>& operator+=(Vector3<T>& v1, Vector3<T> const& v2)
	{
		v1.x += v2.x;
		v1.y += v2.y;
		v1.z += v2.z;
		return v1;
	}

	template <typename T>
	Vector3<T>& operator-=(Vector3<T>& v1, Vector3<T> const& v2)
	{
		v1.x -= v2.x;
		v1.y -= v2.y;
		v1.z -= v2.z;
		return v1;
	}

	template <typename T>
	Vector3<T>& operator*=(Vector3<T>& v, T t)
	{
		v.x *= t;
		v.y *= t;
		v.z *= t;
		return v;
	}

	template <typename T>
	Vector3<T>& operator/=(Vector3<T>& v, T t)
	{
		v.x /= t;
		v.y /= t;
		v.z /= t;
		return v;
	}

	template <typename T>
	Vector3<T> operator+(Vector3<T> const& v)
	{
		return v;
	}

	template <typename T>
	Vector3<T> operator-(Vector3<T> const& v)
	{
		return {-v.x, -v.y, -v.z};
	}

	template <typename T>
	T dot(Vector3<T> const& v1, Vector3<T> const& v2)
	{
		return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
	}

	template <typename T>
	T norm(Vector3<T> const& v)
	{
		return std::sqrt(dot(v, v));
	}

	template <typename T>
	Vector3<T> normalize(Vector3<T> const& v)
	{
		return v / norm(v);
	}

} // namespace ext

#endif // !HEADER_EXT_VECTOR3_HPP_INCLUDED


// system includes -----------------------------------------------
#include <boost/math/constants/constants.hpp>
#include <boost/program_options.hpp>
#include <iostream>
// own includes --------------------------------------------------
#include <base/eigen2hdf.hpp>
#include <base/init.hpp>
#include <base/timer.hpp>
#include <fft/fft2.hpp>
#include <ridgelet/ridgelet_frame.hpp>
#include <ridgelet/rt.hpp>

using namespace std;

const char* fname = "test_rt.h5";

// typedef FFTr2c<PlannerR2COD> fft_t;
typedef FFT fft_t;
typedef RT<std::complex<double>, RidgeletFrame, fft_t> RT_t;
typedef RT_t::array_t array_t;
typedef RT_t::complex_array_t complex_array_t;
typedef RT_t::rt_coeff_t rt_coeff_t;

void dump_frc(const std::vector<rt_coeff_t>& f_rc, const RidgeletFrame& rt)
{
  const char* fname = "f_rc.h5";
  hid_t file = H5Fcreate(fname, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
  for (unsigned int i = 0; i < f_rc.size(); ++i) {
    stringstream ss;
    ss << rt.lambdas()[i];
    string slam = ss.str();
    eigen2hdf::save(file, slam, f_rc[i]);
  }
  H5Fclose(file);
  cout << "Written f(lambda, t) to " << fname << "\n";
}

int main(int argc, char* argv[])
{
  SOURCE_INFO();

  namespace po = boost::program_options;

  unsigned int Jx, Jy, rho_x, rho_y;

  po::options_description options("options");
  options.add_options()
      ("help", "produce help message")
      ("Jx,i", po::value<unsigned int>(&Jx)->default_value(3), "Jx")
      ("Jy,j", po::value<unsigned int>(&Jy)->default_value(3), "Jy")
      ("rx,x", po::value<unsigned int>(&rho_x)->default_value(1), "rho_x")
      ("ry,y", po::value<unsigned int>(&rho_y)->default_value(1), "rho_x")
      ("save", "save coefficients");
  po::variables_map vm;
  po::store(po::parse_command_line(argc, argv, options), vm);
  po::notify(vm);

  if (vm.count("help")) {
    std::cout << options << "\n";
    return 0;
  }

  cout << setw(20) << "Jx: " << Jx << "\n"
       << setw(20) << "Jy: " << Jy << "\n"
       << setw(20) << "rho_x: " << rho_x << "\n"
       << setw(20) << "rho_y: " << rho_y << "\n"
       << setw(20) << "Nx: " << std::pow(2, Jx + 2) * rho_x << "\n"
       << setw(20) << "Ny: " << std::pow(2, Jy + 2) * rho_y << "\n";
  RDTSCTimer timer;

  timer.start();
  RidgeletFrame frame(Jx, Jy, rho_x, rho_y);
  double time_frame_constructor = timer.stop();
  timer.print(cout, time_frame_constructor, "RidgeletFrame init");

  const unsigned int ncols = frame.Nx();  // #cols
  const unsigned int nrows = frame.Ny();  // #rows

  RT_t rt(frame);
  array_t F(nrows / 2, ncols / 2);
  {
    double pi = boost::math::constants::pi<double>();
    Eigen::ArrayXd x = pi * Eigen::ArrayXd::LinSpaced(ncols / 2, 0, 1);
    Eigen::ArrayXd y = pi * Eigen::ArrayXd::LinSpaced(nrows / 2, 0, 1);
    F = y.replicate(1, x.rows()).sin() * x.transpose().replicate(y.rows(), 1).sin();

    Eigen::MatrixXd tmp = F;
    tmp = tmp.triangularView<Eigen::Lower>();
    F = tmp.array();
  }

  fft_t fft;
  // debug
  complex_array_t Fhh(nrows / 2, ncols / 2);
  fft.ft(Fhh, F, false);
  hid_t file;
  if (vm.count("save")) {
    file = H5Fcreate(fname, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
    eigen2hdf::save(file, "Fhh", Fhh);  // debug
  }
  // ----------------------------------------
  complex_array_t Fh(nrows, ncols);
  Fh.setZero();
  ftcut(Fh, nrows / 2, ncols / 2) = Fhh;
  std::vector<rt_coeff_t> rt_coeffs(frame.size());
  timer.start();
  cout << "rt.rt(...)"
       << "\n";
  rt.rt(rt_coeffs, Fh);

  int ncoeffs = 0;
  for (unsigned int i = 0; i < rt_coeffs.size(); ++i) {
    ncoeffs += rt_coeffs[i].rows() * rt_coeffs[i].cols();
  }
  cout << "dim(rt_coeffs): " << ncoeffs << "\n";
  auto time_rt = timer.stop();
  timer.print(cout, time_rt, "rt.rt");

  // -------------------- Inverse transform --------------------
  complex_array_t Fh2(nrows, ncols);
  timer.start();
  cout << "rt.irt(...)"
       << "\n";
  rt.irt(Fh2, rt_coeffs);
  auto time_irt = timer.stop();
  timer.print(cout, time_irt, "rt.irt");

  array_t F2(nrows / 2, ncols / 2);
  complex_array_t Fh2_cut(nrows / 2, ncols / 2);
  Fh2_cut.setZero();
  Fh2_cut = ftcut(Fh2, nrows / 2, ncols / 2);
  fft.ift(F2, Fh2_cut);
  auto diff = (F - F2).abs();
  cout << "(F-F2).abs().sum(): " << diff.sum() << "\n";

  if (vm.count("save")) {
    eigen2hdf::save(file, "Fhl", Fhh);
    eigen2hdf::save(file, "Fh", Fh);
    eigen2hdf::save(file, "R", F);
    eigen2hdf::save(file, "Fh2", Fh2);
    eigen2hdf::save(file, "R2", F2);
    H5Fclose(file);
    cout << "written results to " << fname << "\n";
  }

  return 0;
}


#include "Geometry.h"

#include "Eigen/Core"
#include "Eigen/Dense"
//#include <Eigen/SVD>

#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/matrix_access.hpp"

#include <iostream>
#include <limits>

#define MIN_VAL -FLT_MAX
#define MAX_VAL FLT_MAX

using namespace Eigen;

void ComputeSpatialProperties(std::vector<float>* verts) {
	const int numVerts = ((int)verts->size()) / 3;
	glm::vec3 minPoint(MIN_VAL, MIN_VAL, MIN_VAL);
	glm::vec3 maxPoint(MAX_VAL, MAX_VAL, MAX_VAL);
	glm::vec3 centroid(0.0f);

	MatrixXf A(numVerts, 3);

	for (int i = 0; i < numVerts; i++) {

		float x = (*verts)[i * 3];
		float y = (*verts)[i * 3 + 1];
		float z = (*verts)[i * 3 + 2];
		if (x > minPoint.x) { minPoint.x = x; }
		if (y > minPoint.y) { minPoint.y = y; }
		if (z > minPoint.z) { minPoint.z = z; }

		centroid.x += x;
		centroid.y += y;
		centroid.z += z;

		A.row(i) << x, y, z;
	}

	//https://stats.stackexchange.com/questions/134282/relationship-between-svd-and-pca-how-to-use-svd-to-perform-pca
	//std::cout << A << std::endl;

	JacobiSVD<MatrixXf> svd(A, ComputeThinV);
	std::cout << "Its singular values are:" << std::endl << svd.singularValues() << std::endl;
	std::cout << "Its right singular vectors are the columns of the thin V matrix:" << std::endl << svd.matrixV() << std::endl;
	int ti = 1;

}


//
// OpenTissue, A toolbox for physical based simulation and animation.
// Copyright (C) 2007 Department of Computer Science, University of Copenhagen
//
#include <OpenTissue/configuration.h>

#include <OpenTissue/core/math/math_random.h>
#include <OpenTissue/core/math/big/big_types.h>
#include <OpenTissue/core/math/optimization/optimization_compute_generalized_minimal_map.h>
#include <OpenTissue/core/math/optimization/optimization_compute_natural_merit.h>

#define BOOST_AUTO_TEST_MAIN
#include <OpenTissue/utility/utility_push_boost_filter.h>
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/test_tools.hpp>
#include <OpenTissue/utility/utility_pop_boost_filter.h>

template <typename T>
class BoundFunction
{
public:

  T    m_value;

public:

  BoundFunction(T const & value)
    : m_value(value)
  {}

  template<typename vector_type>
  T operator()(vector_type const & x, size_t const & i) const  {    return m_value;  }

};

BOOST_AUTO_TEST_SUITE(opentissue_math_big_compute_generalized_minimal_map);

BOOST_AUTO_TEST_CASE(test_case)
{

  ublas::vector<double> x;
  ublas::vector<double> y;
  ublas::vector<double> H;

  x.resize(10,false);
  y.resize(10,false);
  H.resize(10,false);

  OpenTissue::math::Random<double> value(0.0,1.0);

  x(0) = value();
  x(1) = value();
  x(2) = value();
  x(3) = value();
  x(4) = value();
  x(5) = value();
  x(6) = value();
  x(7) = value();
  x(8) = value();
  x(9) = value();

  y(0) = value();
  y(1) = value();
  y(2) = value();
  y(3) = value();
  y(4) = value();
  y(5) = value();
  y(6) = value();
  y(7) = value();
  y(8) = value();
  y(9) = value();

  BoundFunction<double> l(-value());
  BoundFunction<double> u( value());

  OpenTissue::math::optimization::compute_generalized_minimal_map(y,l,u,x, H );

  double theta = OpenTissue::math::optimization::compute_natural_merit( H );
  BOOST_CHECK ( theta >= 0.0 );

}

BOOST_AUTO_TEST_SUITE_END();


//****************************************************************************
// (c) 2008, 2009 by the openOR Team
//****************************************************************************
// The contents of this file are available under the GPL v2.0 license
// or under the openOR comercial license. see
//   /Doc/openOR_free_license.txt or
//   /Doc/openOR_comercial_license.txt
// for Details.
//****************************************************************************
//! OPENOR_INTERFACE_FILE(openOR_core)
//****************************************************************************
/**
 * @file
 * @author Christian Winne
 * @ingroup openOR_core
 */

#ifndef openOR_core_vectorfunctions_hpp
#define openOR_core_vectorfunctions_hpp

#include <functional>

#include <boost/mpl/bool.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/equal_to.hpp>

#include <openOR/Utility/conceptcheck.hpp>
#include <openOR/Math/traits.hpp>
#include <openOR/Math/vector.hpp>
#include <openOR/Math/constants.hpp>

namespace openOR {
   namespace Math {

      /**
       * @brief
       * @ingroup openOR_core
       */
      template <class Type>
      inline
      OPENOR_CONCEPT_REQUIRES(
         ((Concept::ConstVector<Type>)),
         (typename VectorTraits<Type>::ValueType))
      squaredNorm(const Type& vec) {
         return dot(vec, vec);
      }

      namespace Impl {

        template <class V, int I>
        struct VectorAccess {
           typename VectorTraits<V>::ValueType operator()(const V& vec) const { return get<I>(vec); }
        };

        template<class _Type>
        struct Min : public std::binary_function<_Type, _Type, _Type> {
           _Type operator()(const _Type& left, const _Type& right) const {
              return std::min<_Type>(left, right);
           }
        };

        template<class _Type>
        struct Max : public std::binary_function<_Type, _Type, _Type> {
           _Type operator()(const _Type& left, const _Type& right) const {
              return std::max<_Type>(left, right);
           }
        };

      }

      /**
       * @brief Returns the minimal element of a vector.
       * @ingroup openOR_core
       */
      template <class Type>
      inline
      OPENOR_CONCEPT_REQUIRES(
        ((Concept::ConstVector<Type>)),
        (typename VectorTraits<Type>::ValueType))
      minimalElement(const Type& vec)
      {
         typedef typename VectorTraits<Type>::ValueType ValueType;
         return Impl::VectorCompileTimeIterator<Type>().template reduce<Impl::VectorAccess, ValueType, Impl::Min>(vec);
      }

      /**
       * @brief
       * @ingroup openOR_core
       */
      template <class Type>
      inline
      OPENOR_CONCEPT_REQUIRES(
        ((Concept::ConstVector<Type>)),
        (typename VectorTraits<Type>::ValueType))
      maximalElement(const Type& vec)
      {
        typedef typename VectorTraits<Type>::ValueType ValueType;
        return Impl::VectorCompileTimeIterator<Type>().template reduce<Impl::VectorAccess, ValueType, Impl::Max>(vec);
      }

      /**
       * @brief
       * @ingroup openOR_core
       */
      template <class Type>
      inline
      OPENOR_CONCEPT_REQUIRES(
        ((Concept::ConstVector<Type>)),
        (typename VectorTraits<Type>::ValueType))
      summarizedElements(const Type& vec)
      {
        typedef typename VectorTraits<Type>::ValueType ValueType;
        return Impl::VectorCompileTimeIterator<Type>().template reduce<Impl::VectorAccess, ValueType, std::plus>(vec);
      }

      /**
       * @brief
       * @ingroup openOR_core
       */
      template <class Type>
      inline
      OPENOR_CONCEPT_REQUIRES(
        ((Concept::ConstVector<Type>)),
        (typename VectorTraits<Type>::ValueType))
      multipliedElements(const Type& vec)
      {
        typedef typename VectorTraits<Type>::ValueType ValueType;
        return Impl::VectorCompileTimeIterator<Type>().template reduce<Impl::VectorAccess, ValueType, std::multiplies>(vec);
      }

      /**
       * @brief
       * @ingroup openOR_core
       */
      template <class Type>
      inline
      OPENOR_CONCEPT_REQUIRES(
         ((Concept::Vector<Type>)),
         (Type&))
      normalize(Type& vec) {
         BOOST_MPL_ASSERT((boost::is_floating_point<typename VectorTraits<Type>::ValueType>));
         typedef typename ScalarTraits<typename VectorTraits<Type>::ValueType>::RealType RealType;
         RealType invNorm = (RealType) 1.0 / norm(vec);
         vec *= invNorm;
         return vec;
      }

      namespace Impl
      {
         template <class Vec, class Vec2, class Vec3, int I>
         struct ElementwiseMult {
            inline void operator()(Vec& p1, const Vec2& p2 , const Vec3& p3) const
            {
               typedef typename VectorTraits<Vec>::ValueType ValueType;
               ValueType v2 = static_cast<ValueType>(get<I>(p2));
               ValueType v3 = static_cast<ValueType>(get<I>(p3));
               get<I>(p1) = v2 * v3;
            }
         };
      }

      /**
      * @brief
      * @ingroup openOR_core
      */
      template <class Type, class Type2, class Type3>
      inline
         OPENOR_CONCEPT_REQUIRES(
         ((Concept::Vector<Type>))
         ((Concept::ConstVector<Type2))
         ((Concept::ConstVector<Type3)),
         (Type))
         elementProd(const Type2& left, const Type3& right)
      {
         Type result;
         Impl::VectorCompileTimeIterator<Type>().template apply<Impl::ElementwiseMult, Type2, Type3>(result, left, right);
         return result;
      }

      template<class Type>
      inline Type fromString(const std::string& str) {
            Type retval;

            std::stringstream in;
            in.str(str);
            in >> retval;

            return retval;
      }

      ///**
      // * @brief
      // * @ingroup openOR_core_math
      // */
      //template <class Type>
      //inline
      //OPENOR_CONCEPT_REQUIRES(
      //                        ((Concept::Vector<Type>)),
      //                        (Type&))
      //normalize(const Type& vec) {
      //   BOOST_MPL_ASSERT((boost::is_floating_point<typename VectorTraits<Type>::ValueType>));
      //   typename ScalarTraits<typename VectorTraits<Type>::ValueType>::RealType invNorm = 1.0 / norm(vec);
      //   Type res = vec * invNorm;
      //   return res;
      //}

      /**
       * @brief
       * @ingroup openOR_core
       */
      template <class Type>
      inline
      OPENOR_CONCEPT_REQUIRES(
         ((Concept::ConstVector<Type>)),
         (typename VectorTraits<Type>::RealVectorType))
      normalized(const Type& vec) {
         typename VectorTraits<Type>::RealVectorType v(vec);
         normalize(v);
         return v;
      }

      namespace Impl {

         template <int I, class Type, class Type2>
         struct Cross {
            typedef invalid_type ResultType;
         };

         template<class Type, class Type2>
         struct Cross<2, Type, Type2> {
            typedef typename VectorTraits<Type>::ValueType ResultType;

            ResultType operator()(const Type& left, const Type2& right) const {
               return get<0>(left) * get<1>(right) - get<1>(left) * get<0>(right);
            }
         };

         template <class Type, class Type2>
         struct Cross<3, Type, Type2> {
            typedef typename VectorTraits<Type>::Vector3Type ResultType;

            ResultType operator()(const Type& left, const Type2& right) const {
               BOOST_MPL_ASSERT((boost::mpl::equal_to<typename VectorTraits<typename VectorTraits<Type>::Vector3Type>::Dimension, boost::mpl::int_<3> >));
               ResultType vec;
               get<0>(vec) = get<1>(left) * get<2>(right) - get<2>(left) * get<1>(right);
               get<1>(vec) = get<2>(left) * get<0>(right) - get<0>(left) * get<2>(right);
               get<2>(vec) = get<0>(left) * get<1>(right) - get<1>(left) * get<0>(right);
               return vec;
            }
         };

      }

       /**
       * @brief
       * @ingroup openOR_core
       */
      template <class Type, class Type2>
      inline
      OPENOR_CONCEPT_REQUIRES(
         ((Concept::ConstVector<Type>))
         ((Concept::ConstVector<Type2>))
         ((Concept::Vector<typename VectorTraits<Type>::Vector3Type>)),
         (typename Impl::Cross<VectorTraits<Type>::Dimension::value, Type, Type2>::ResultType))
      cross(const Type& left, const Type2& right) {
         BOOST_MPL_ASSERT((boost::mpl::equal_to<typename VectorTraits<typename VectorTraits<Type>::Vector3Type>::Dimension, boost::mpl::int_<3> >));
         return typename Impl::Cross<VectorTraits<Type>::Dimension::value, Type, Type2>()(left, right);
      }

      /**
       * @brief
       * @ingroup openOR_core
       */
      template <class Type>
      inline
      OPENOR_CONCEPT_REQUIRES(
                              ((Concept::ConstVector<Type>)),
                              (Type))
      rotate3(const Type& vec, const Type& vecAxis, const typename ScalarTraits<typename VectorTraits<Type>::ValueType>::RealType angle) {

         typedef typename VectorTraits<Type>::RealVectorType RealVectorType;
         typedef typename ScalarTraits<typename VectorTraits<Type>::ValueType>::RealType RealType;
         RealVectorType vecReal(vec);
         RealVectorType vecAxisReal(vecAxis);
         normalize(vecAxisReal);
         vecAxisReal *= static_cast<RealType>(dot(vec, vecAxis));

         // first radius vector
         RealVectorType vecRad1(vecReal - vecAxisReal);
         RealType length = norm(vecRad1);
         if (length < 0.0001) return vec;

         // second radius vector
         RealVectorType vecRad2 = cross(RealVectorType(vecAxis), vecRad1);
         normalize(vecRad1);
         normalize(vecRad2);

         RealType factor1 = length * cos(angle);
         RealType factor2 = length * sin(angle);

         RealVectorType result = vecAxisReal + vecRad1 * factor1 + vecRad2 * factor2;
         return Type(result);
      }

   }
}

#endif


/*
this file should cover the following functions in hmm.h
- hmm_vec2 HMM_DivideVec2(hmm_vec2 Left, hmm_vec2 Right);
- hmm_vec2 HMM_DivideVec2f(hmm_vec2 Left, float Right);
- hmm_vec3 HMM_DivideVec3(hmm_vec3 Left, hmm_vec3 Right);
- hmm_vec3 HMM_DivideVec3f(hmm_vec3 Left, float Right);
- hmm_vec4 HMM_DivideVec4(hmm_vec4 Left, hmm_vec4 Right);
- hmm_vec4 HMM_DivideVec4f(hmm_vec4 Left, float Right);
- hmm_mat4 HMM_DivideMat4f(hmm_mat4 Matrix, float Scalar);
take care of operator overloading also for these functions:
- hmm_vec2 operator/(hmm_vec2 Left, hmm_vec2 Right);
- hmm_vec3 operator/(hmm_vec3 Left, hmm_vec3 Right);
- hmm_vec4 operator/(hmm_vec4 Left, hmm_vec4 Right);
- hmm_vec2 operator/(hmm_vec2 Left, float Right);
- hmm_vec3 operator/(hmm_vec3 Left, float Right);
- hmm_vec4 operator/(hmm_vec4 Left, float Right);
- hmm_mat4 operator/(hmm_mat4 Left, float Right);
- hmm_vec2 &operator/=(hmm_vec2 &Left, hmm_vec2 Right);
- hmm_vec3 &operator/=(hmm_vec3 &Left, hmm_vec3 Right);
- hmm_vec4 &operator/=(hmm_vec4 &Left, hmm_vec4 Right);
- hmm_vec2 &operator/=(hmm_vec2 &Left, float Right);
- hmm_vec3 &operator/=(hmm_vec3 &Left, float Right);
- hmm_vec4 &operator/=(hmm_vec4 &Left, float Right);
- hmm_mat4 &operator/=(hmm_mat4 &Left, float Right);
*/
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include "HMM.h"
#include "test_helpers.h"
namespace utf = boost::unit_test;

BOOST_AUTO_TEST_SUITE(division_test_suite)

BOOST_AUTO_TEST_SUITE(division_vec2_by_int)

BOOST_AUTO_TEST_CASE(test_HMM_DivideVec2_int_BothVecsZeros, *utf::tolerance(0.00001)) {
    //Arrange
    auto zeros = HMM_Vec2i(0, 0);
    //Act
    auto res = HMM_DivideVec2(zeros, zeros);
    //Assert
    BOOST_TEST(isnan(res.Elements[0]));
    BOOST_TEST(isnan(res.Elements[1]));
}

BOOST_AUTO_TEST_CASE(test_HMM_DivideVec2_int_V1_zeros, *utf::tolerance(0.00001)) {
    //Arrange
    auto zeros = HMM_Vec2i(0, 0);
    auto right = HMM_Vec2i(5, -10);
    //Act
    auto res = HMM_DivideVec2(zeros, right);
    //Assert
    float expectedRes[2] = {0, 0};
    BOOST_TEST(res.Elements == expectedRes);
}

BOOST_AUTO_TEST_CASE(test_HMM_DivideVec2_int_postives, *utf::tolerance(0.00001)) {
    //Arrange
    auto left = HMM_Vec2i(1, 5);
    auto right = HMM_Vec2i(3, 4);
    //Act
    auto res = HMM_DivideVec2(left, right);
    //Assert
    float expectedRes[2] = {left.Elements[0] / right.Elements[0], left.Elements[1] / right.Elements[1]};
    BOOST_TEST(res.Elements == expectedRes);
}

BOOST_AUTO_TEST_CASE(test_HMM_DivideVec2_int_pos_neg, *utf::tolerance(0.00001)) {
    //Arrange
    auto left = HMM_Vec2i(1, 5);
    auto right = HMM_Vec2i(-3, -4);
    //Act
    auto res = HMM_DivideVec2(left, right);
    //Assert
    BOOST_TEST(vector<float>(res.Elements, res.Elements + 2) == vector<float>({left.Elements[0] / right.Elements[0], left.Elements[1] / right.Elements[1]}));
}

BOOST_AUTO_TEST_CASE(test_HMM_DivideVec2_float_pos_neg, *utf::tolerance(0.00001)) {
    //Arrange
    auto left = HMM_Vec2(10., 1.);
    auto right = HMM_Vec2(-2, -5.);
    //Act
    auto res = HMM_DivideVec2(left, right);
    //Assert
    BOOST_TEST(vector<float>(res.Elements, res.Elements + 2) == vector<float>({left.Elements[0] / right.Elements[0], left.Elements[1] / right.Elements[1]}));
}

BOOST_AUTO_TEST_SUITE_END()

//--------------------------------------------------------------

BOOST_AUTO_TEST_SUITE(division_vec2_by_float)

BOOST_AUTO_TEST_CASE(test_HMM_DivideVec2f_vec_x_posfloat, *utf::tolerance(0.00001)) {
    //Arrange
    auto left = HMM_Vec2(.5, .2);
    float right = 10.;
    //Act
    auto res = HMM_DivideVec2f(left, right);
    //Assert
    BOOST_TEST(vector<float>(res.Elements, res.Elements + 2) == vector<float>({left.Elements[0] / right, left.Elements[1] / right}));
}

BOOST_AUTO_TEST_SUITE_END()
//--------------------------------------------------------------
BOOST_AUTO_TEST_SUITE(division_vec2_using_operators)

BOOST_AUTO_TEST_CASE(test_division_vec2_by_vec2_using_division_operator, *utf::tolerance(0.00001)) {
    //Arrange
    auto left = HMM_Vec2(10., 1.);
    auto right = HMM_Vec2(-2, -5.);
    //Act
    auto res = left / right;
    //Assert
    BOOST_TEST(vector<float>(res.Elements, res.Elements + 2) == vector<float>({left.Elements[0] / right.Elements[0], left.Elements[1] / right.Elements[1]}));
}

BOOST_AUTO_TEST_CASE(test_division_vec2_by_float_using_division_operator, *utf::tolerance(0.00001)) {
    //Arrange
    auto left = HMM_Vec2(.5, .2);
    float right = 10.;
    //Act
    auto res = left / right;
    //Assert
    BOOST_TEST(vector<float>(res.Elements, res.Elements + 2) == vector<float>({left.Elements[0] / right, left.Elements[1] / right}));
}

BOOST_AUTO_TEST_CASE(test_division_vec2_by_vec2_using_division_equal_operator, *utf::tolerance(0.00001)) {
    //Arrange
    auto left = HMM_Vec2(.5, .2);
    auto right = HMM_Vec2(-2, -5.);
    //Act
    auto res = left;
    res /= right;
    //Assert
    BOOST_TEST(vector<float>(res.Elements, res.Elements + 2) == vector<float>({left.Elements[0] / right.Elements[0], left.Elements[1] / right.Elements[1]}));
}

BOOST_AUTO_TEST_CASE(test_division_vec2_by_float_using_division_equal_operator, *utf::tolerance(0.00001)) {
    //Arrange
    auto left = HMM_Vec2(.5, .2);
    float right = 10.;
    //Act
    auto res = left;
    res /= right;
    //Assert
    float expectedRes[2] = {left.Elements[0] / right, left.Elements[1] / right};
    BOOST_TEST(res.Elements == expectedRes);
}

BOOST_AUTO_TEST_SUITE_END()

//-----------------------
BOOST_AUTO_TEST_SUITE(division_mat4_by_floatscalar)

BOOST_AUTO_TEST_CASE(test_HMM_DivideMat4f, *utf::tolerance(0.00001)) {
    //Arrange
    auto left = hmm_mat4();
    float arr[4][4] = {{1, 2, 3, 4},
                       {5, -6, 7, 8},
                       {9, 10, 11, 12},
                       {0, 15, 0, 0}};
    copy(&arr[0][0], &arr[0][0] + 4 * 4, &left.Elements[0][0]);

    float right = .5;
    //Act
    hmm_mat4 res = HMM_DivideMat4f(left, right);

    //Assert
    float expMat[4][4] = {{arr[0][0] / right, arr[0][1] / right, arr[0][2] / right, arr[0][3] / right},
                          {arr[1][0] / right, arr[1][1] / right, arr[1][2] / right, arr[1][3] / right},
                          {arr[2][0] / right, arr[2][1] / right, arr[2][2] / right, arr[2][3] / right},
                          {arr[3][0] / right, arr[3][1] / right, arr[3][2] / right, arr[3][3] / right}};

    BOOST_TEST(res.Elements == expMat);
}

BOOST_AUTO_TEST_SUITE_END()

//-----------------------
BOOST_AUTO_TEST_SUITE(division_mat4_using_operators)

BOOST_AUTO_TEST_CASE(test_HMM_DivideMat4f, *utf::tolerance(0.00001)) {
    //Arrange
    auto left = hmm_mat4();
    float arr[4][4] = {{1, 2, 3, 4},
                       {5, -6, 7, 8},
                       {9, 10, 11, 12},
                       {0, 15, 0, 0}};
    copy(&arr[0][0], &arr[0][0] + 4 * 4, &left.Elements[0][0]);

    float right = .5;
    //Act
    hmm_mat4 res = HMM_DivideMat4f(left, right);

    //Assert
    float expMat[4][4] = {{arr[0][0] / right, arr[0][1] / right, arr[0][2] / right, arr[0][3] / right},
                          {arr[1][0] / right, arr[1][1] / right, arr[1][2] / right, arr[1][3] / right},
                          {arr[2][0] / right, arr[2][1] / right, arr[2][2] / right, arr[2][3] / right},
                          {arr[3][0] / right, arr[3][1] / right, arr[3][2] / right, arr[3][3] / right}};

    BOOST_TEST(res.Elements == expMat);
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()


/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2013-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* Distributed under 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)
*
*****************************************************************************/

#include <rokko/rokko.hpp>
#include <rokko/utility/frank_matrix.hpp>
#include <boost/foreach.hpp>
#define BOOST_TEST_MODULE test_generator
#ifndef BOOST_TEST_DYN_LINK
#include <boost/test/included/unit_test.hpp>
#else
#include <boost/test/unit_test.hpp>
#endif

template<typename T, typename MATRIX_MAJOR>
void test(int dim) {
  rokko::localized_matrix<T, MATRIX_MAJOR> mat(dim, dim);
  rokko::frank_matrix::generate(mat);
  BOOST_CHECK_CLOSE(mat.trace(), dim * (dim+1) * 0.5, 10e-5);
}

BOOST_AUTO_TEST_CASE(test_generator) {
  const int dim = 100;
  std::cout << "dimension = " << dim << std::endl;

  std::cout << "  test for row major" << std::endl;
  test<double, rokko::matrix_row_major>(dim);
  std::cout << "  test for column major" << std::endl;
  test<double, rokko::matrix_col_major>(dim);
}


/*
@copyright Louis Dionne 2015
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#include <boost/hana/ext/std/ratio.hpp>

#include <boost/hana/assert.hpp>
#include <boost/hana/tuple.hpp>

#include <laws/comparable.hpp>
#include <laws/euclidean_ring.hpp>
#include <laws/group.hpp>
#include <laws/monoid.hpp>
#include <laws/orderable.hpp>
#include <laws/ring.hpp>
#include <test/cnumeric.hpp>

#include <ratio>
using namespace boost::hana;

int main() {
    auto ratios = make<tuple_tag>(
          std::ratio<0>{}
        , std::ratio<1, 3>{}
        , std::ratio<1, 2>{}
        , std::ratio<2, 6>{}
        , std::ratio<3, 1>{}
        , std::ratio<7, 8>{}
        , std::ratio<3, 5>{}
        , std::ratio<2, 1>{}
    );
    (void)ratios;

#if BOOST_HANA_TEST_PART == 1
    //////////////////////////////////////////////////////////////////////////
    // Conversions
    //////////////////////////////////////////////////////////////////////////
    {
        // Constant -> Ratio
        {
            BOOST_HANA_CONSTANT_CHECK(equal(
                to<ext::std::ratio_tag>(test::cnumeric<int, 0>),
                std::ratio<0>{}
            ));

            BOOST_HANA_CONSTANT_CHECK(equal(
                to<ext::std::ratio_tag>(test::cnumeric<int, 1>),
                std::ratio<1>{}
            ));

            BOOST_HANA_CONSTANT_CHECK(equal(
                to<ext::std::ratio_tag>(test::cnumeric<int, 3>),
                std::ratio<3>{}
            ));
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Comparable
    //////////////////////////////////////////////////////////////////////////
    {
        // equal
        {
            BOOST_HANA_CONSTANT_CHECK(equal(
                std::ratio<0>{},
                std::ratio<0>{}
            ));

            BOOST_HANA_CONSTANT_CHECK(equal(
                std::ratio<3, 5>{},
                std::ratio<6, 10>{}
            ));

            BOOST_HANA_CONSTANT_CHECK(not_(equal(
                std::ratio<4, 5>{},
                std::ratio<6, 10>{}
            )));
        }

        // laws
        test::TestComparable<ext::std::ratio_tag>{ratios};
    }

#elif BOOST_HANA_TEST_PART == 2
    //////////////////////////////////////////////////////////////////////////
    // Orderable
    //////////////////////////////////////////////////////////////////////////
    {
        // less
        {
            BOOST_HANA_CONSTANT_CHECK(less(
                std::ratio<1>{},
                std::ratio<3>{}
            ));

            BOOST_HANA_CONSTANT_CHECK(less(
                std::ratio<4, 10>{},
                std::ratio<3, 5>{}
            ));

            BOOST_HANA_CONSTANT_CHECK(not_(less(
                std::ratio<3, 5>{},
                std::ratio<4, 10>{}
            )));
        }

        // laws
        auto ratios = make<tuple_tag>(
              std::ratio<0>{}
            , std::ratio<1, 3>{}
            , std::ratio<1, 2>{}
            , std::ratio<2, 6>{}
            , std::ratio<7, 8>{}
            , std::ratio<3, 5>{}
        );

        test::TestOrderable<ext::std::ratio_tag>{ratios};
    }

#elif BOOST_HANA_TEST_PART == 3
    //////////////////////////////////////////////////////////////////////////
    // Monoid
    //////////////////////////////////////////////////////////////////////////
    {
        // plus
        {
            BOOST_HANA_CONSTANT_CHECK(equal(
                plus(std::ratio<3, 4>{}, std::ratio<5, 10>{}),
                std::ratio<3*10 + 5*4, 4*10>{}
            ));
        }

        // zero
        {
            BOOST_HANA_CONSTANT_CHECK(equal(
                zero<ext::std::ratio_tag>(),
                std::ratio<0, 1>{}
            ));

            BOOST_HANA_CONSTANT_CHECK(equal(
                zero<ext::std::ratio_tag>(),
                std::ratio<0, 2>{}
            ));
        }

        // laws
        test::TestMonoid<ext::std::ratio_tag>{ratios};
    }

    //////////////////////////////////////////////////////////////////////////
    // Group
    //////////////////////////////////////////////////////////////////////////
    {
        // minus
        {
            BOOST_HANA_CONSTANT_CHECK(equal(
                minus(std::ratio<3, 4>{}, std::ratio<5, 10>{}),
                std::ratio<3*10 - 5*4, 4*10>{}
            ));
        }

        // laws
        test::TestGroup<ext::std::ratio_tag>{ratios};
    }

#elif BOOST_HANA_TEST_PART == 4
    //////////////////////////////////////////////////////////////////////////
    // Ring
    //////////////////////////////////////////////////////////////////////////
    {
        // mult
        {
            BOOST_HANA_CONSTANT_CHECK(equal(
                mult(std::ratio<3, 4>{}, std::ratio<5, 10>{}),
                std::ratio<3*5, 4*10>{}
            ));
        }

        // one
        {
            BOOST_HANA_CONSTANT_CHECK(equal(
                one<ext::std::ratio_tag>(),
                std::ratio<1, 1>{}
            ));

            BOOST_HANA_CONSTANT_CHECK(equal(
                one<ext::std::ratio_tag>(),
                std::ratio<2, 2>{}
            ));
        }

        // laws
        test::TestRing<ext::std::ratio_tag>{ratios};
    }

#elif BOOST_HANA_TEST_PART == 5
    //////////////////////////////////////////////////////////////////////////
    // EuclideanRing
    //////////////////////////////////////////////////////////////////////////
    {
        // div
        {
            using boost::hana::div; // hide ::div
            BOOST_HANA_CONSTANT_CHECK(equal(
                div(std::ratio<6>{}, std::ratio<4>{}),
                std::ratio<6, 4>{}
            ));

            BOOST_HANA_CONSTANT_CHECK(equal(
                div(std::ratio<3, 4>{}, std::ratio<5, 10>{}),
                std::ratio<3*10, 4*5>{}
            ));
        }

        // mod
        {
            BOOST_HANA_CONSTANT_CHECK(equal(
                mod(std::ratio<6>{}, std::ratio<4>{}),
                std::ratio<0>{}
            ));

            BOOST_HANA_CONSTANT_CHECK(equal(
                mod(std::ratio<3, 4>{}, std::ratio<5, 10>{}),
                std::ratio<0>{}
            ));
        }

        // laws
        test::TestEuclideanRing<ext::std::ratio_tag>{ratios};
    }
#endif
}


///////////////////////////////////////////////////////////////////////////////
// calculator.hpp
//
//  Copyright 2008 Eric Niebler. Distributed under 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)

#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
#include <boost/test/unit_test.hpp>

using namespace boost;

struct placeholder {};
proto::terminal<placeholder>::type const _1 = {{}};

struct calculator : proto::callable_context<calculator const>
{
    typedef int result_type;

    calculator(int i)
      : i_(i)
    {}

    int operator ()(proto::tag::terminal, placeholder) const
    {
        return this->i_;
    }

    int operator ()(proto::tag::terminal, int j) const
    {
        return j;
    }

    template<typename Left, typename Right>
    int operator ()(proto::tag::plus, Left const &left, Right const &right) const
    {
        return proto::eval(left, *this) + proto::eval(right, *this);
    }

    template<typename Left, typename Right>
    int operator ()(proto::tag::minus, Left const &left, Right const &right) const
    {
        return proto::eval(left, *this) - proto::eval(right, *this);
    }

    template<typename Left, typename Right>
    int operator ()(proto::tag::multiplies, Left const &left, Right const &right) const
    {
        return proto::eval(left, *this) * proto::eval(right, *this);
    }

    template<typename Left, typename Right>
    int operator ()(proto::tag::divides, Left const &left, Right const &right) const
    {
        return proto::eval(left, *this) / proto::eval(right, *this);
    }

private:
    int i_;
};

template<typename Fun, typename Expr>
struct functional
{
    typedef typename proto::result_of::eval<Expr, Fun>::type result_type;

    functional(Expr const &expr)
      : expr_(expr)
    {}

    template<typename T>
    result_type operator ()(T const &t) const
    {
        Fun fun(t);
        return proto::eval(this->expr_, fun);
    }

private:
    Expr const &expr_;
};

template<typename Fun, typename Expr>
functional<Fun, Expr> as(Expr const &expr)
{
    return functional<Fun, Expr>(expr);
}

void test_calculator()
{
    BOOST_CHECK_EQUAL(10, proto::eval(((_1 + 42)-3)/4, calculator(1)));
    BOOST_CHECK_EQUAL(11, proto::eval(((_1 + 42)-3)/4, calculator(5)));

    BOOST_CHECK_EQUAL(10, as<calculator>(((_1 + 42)-3)/4)(1));
    BOOST_CHECK_EQUAL(11, as<calculator>(((_1 + 42)-3)/4)(5));
}

using namespace unit_test;
///////////////////////////////////////////////////////////////////////////////
// init_unit_test_suite
//
test_suite* init_unit_test_suite( int argc, char* argv[] )
{
    test_suite *test = BOOST_TEST_SUITE("test immediate evaluation of proto parse trees");

    test->add(BOOST_TEST_CASE(&test_calculator));

    return test;
}


/**
 * @file finitevolumerobin_main.cc
 * @brief NPDE homework FiniteVolumeRobin code
 * @author Philippe Peter
 * @date February 2020
 * @copyright Developed at ETH Zurich
 */

#include <lf/assemble/assemble.h>
#include <lf/io/io.h>
#include <lf/mesh/hybrid2d/hybrid2d.h>
#include <lf/mesh/utils/utils.h>
#include <lf/uscalfe/uscalfe.h>

#include <Eigen/Core>
#include <Eigen/SparseCore>
#include <Eigen/SparseLU>
#include <iostream>
#include <memory>
#include <string>
#include <utility>

#include "finitevolumerobin.h"

int main() {
  // coefficient functions
  auto g = [](const Eigen::Vector2d & /*x*/) { return 1.0; };
  auto gamma = [](const Eigen::Vector2d &x) { return 1.0 + x(0) * x(0); };

  // The equation is solved on  the four test meshes
  // disk1.msh, disk2.msh, disk3.msh and disk4.msh
  for (int i = 1; i <= 4; ++i) {
    // read mesh
    auto mesh_factory = std::make_unique<lf::mesh::hybrid2d::MeshFactory>(2);
    lf::io::GmshReader reader(
        std::move(mesh_factory),
        CURRENT_SOURCE_DIR "/../meshes/disk" + std::to_string(i) + ".msh");
    auto mesh_p = reader.mesh();

    // Construct dofhanlder for linear finite elements on the current mesh.
    auto fe_space =
        std::make_shared<lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);
    const lf::assemble::DofHandler &dofh{fe_space->LocGlobMap()};

    // Create a dataset of boolean flags indicating edges on the boundary of the
    // mesh
    auto bd_flags{lf::mesh::utils::flagEntitiesOnBoundary(mesh_p, 1)};

    // ASSEMBLE GALERKIN MATRIX
    // Matrix in triplet format holding Galerkin matrix, zero initially.
    lf::assemble::COOMatrix<double> A(dofh.NumDofs(), dofh.NumDofs());

    // First the part corresponding to piecewise Lagrangian finite elements
    lf::uscalfe::LinearFELaplaceElementMatrix elmat_provider;
    lf::assemble::AssembleMatrixLocally(0, dofh, dofh, elmat_provider, A);

    // Next the part corresponding to the modifications of the Galerkin matrix
    // on the boundary.
    FiniteVolumeRobin::EdgeMatrixProvider edmat_provider(gamma, bd_flags);
    lf::assemble::AssembleMatrixLocally(1, dofh, dofh, edmat_provider, A);

    // RIGHT-HAND SIDE VECTOR
    Eigen::VectorXd phi(dofh.NumDofs());
    phi.setZero();

    // Contributions on the boundary to the rhs vector
    FiniteVolumeRobin::EdgeVectorProvider edvec_provider(g, bd_flags);
    lf::assemble::AssembleVectorLocally(1, dofh, edvec_provider, phi);

    // SOLVE LINEAR SYSTEM
    Eigen::SparseMatrix<double> A_crs = A.makeSparse();
    Eigen::SparseLU<Eigen::SparseMatrix<double>> solver;
    solver.compute(A_crs);
    Eigen::VectorXd sol_vec = solver.solve(phi);

    // OUTPUT RESULTS TO VTK FILE
    // construct mesh function representing the finite element solution
    lf::uscalfe::MeshFunctionFE mf_sol(fe_space, sol_vec);
    // construct vtk writer
    lf::io::VtkWriter vtk_writer(mesh_p, CURRENT_BINARY_DIR
                                             "/finite_volume_robin_solution_" +
                                             std::to_string(i) + ".vtk");
    // output data
    vtk_writer.WritePointData(
        "finite_volume_robin_solution_" + std::to_string(i), mf_sol);
  }
  return 0;
}


#pragma once

#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>

namespace taiton {

namespace mp = boost::multiprecision;
using cint = mp::cpp_int;
using lfloat = mp::number<mp::cpp_dec_float<30>>;

}


#include <iostream>
#include <boost/graph/adjacency_list.hpp>
using namespace boost;
using namespace std;
typedef property<edge_weight_t, int> EdgeWeightProperty;
typedef property<edge_weight_t, int> EdgeWeightProperty;
typedef boost::adjacency_list < listS, vecS, undirectedS, no_property, EdgeWeightProperty> mygraph;
int main()
{
    mygraph g;
    add_edge (0, 1, 8, g);
    add_edge (0, 3, 18, g);
    add_edge (1, 2, 20, g);
    add_edge (2, 3, 2, g);
    add_edge (3, 1, 1, g);
    add_edge (1, 3, 7, g);
    cout << "Number of edges: " << num_edges(g) << "\n";
    cout << "Number of vertices: " << num_vertices(g) << "\n";
    mygraph::vertex_iterator vertexIt, vertexEnd;
    tie(vertexIt, vertexEnd) = vertices(g);
    for (; vertexIt != vertexEnd; ++vertexIt)
    {
        std::cout << "in-degree for " << *vertexIt << ": "<< in_degree(*vertexIt, g) << "\n";
        std::cout << "out-degree for " << *vertexIt << ": "<< out_degree(*vertexIt, g) << "\n";
    }
    mygraph::edge_iterator edgeIt, edgeEnd;
    tie(edgeIt, edgeEnd) = edges(g);
    for (; edgeIt!= edgeEnd; ++edgeIt)
    {
        std::cout << "edge " << source(*edgeIt, g) << "-->"<< target(*edgeIt, g) << "\n";
    }
}


#include <Eigen/Dense>
#include <iostream>
#include <math.h>
#include "plane3d.hpp"

using namespace Eigen;
using namespace std;

Plane3d::Plane3d(int _id, double alpha, double theta, Vector3d _target){
    id = _id;
    Vector3d u0(1, 0, 0);
    Vector3d v0(0, cos(alpha), sin(alpha));
    Vector3d w0(0, -sin(alpha), cos(alpha));

    Matrix3f rotationX;
    rotationX << u0[0], u0[1], u0[2],
		 v0[0], v0[1], v0[2],
		 w0[0], w0[1], w0[2];

    Vector3d u1(cos(theta), 0, sin(theta));
    Vector3d v1(0, 1, 0);
    Vector3d w1(-sin(theta), 0, cos(theta));

    Matrix3f rotationY;
    rotationY << u1[0], u1[1], u1[2],
		 v1[0], v1[1], v1[2],
		 w1[0], w1[1], w1[2];

    Matrix3f rotation = rotationX * rotationY;

    axisX = Vector3d(rotation.row(0)[0], rotation.row(0)[1], rotation.row(0)[2]);
    axisY = Vector3d(rotation.row(1)[0], rotation.row(1)[1], rotation.row(1)[2]);
    normal = Vector3d(rotation.row(2)[0], rotation.row(2)[1], rotation.row(2)[2]);

    Matrix3d A;
    A << axisX[0], axisX[1], axisX[2],
	 axisY[0], axisY[1], axisY[2],
	 normal[0], normal[1], normal[2];
    inverse = A.inverse();

    target = _target;
}

bool Plane3d::intersectsEdge(Vector3d v0, Vector3d v1){
    Vector3d diffVec0 = v0 - target;
    double dotProduct0 = diffVec0.dot(normal);

    Vector3d diffVec1 = v1 - target;
    double dotProduct1 = diffVec1.dot(normal);

    return dotProduct0 * dotProduct1 < 0;
}

bool Plane3d::containsPoint(Vector3d v0){
    Vector3d diffVec0 = v0 - target;
    double dotProduct0 = diffVec0.dot(normal);
    return dotProduct0 == 0;
}

array<double, 3> Plane3d::findIntersection(Vector3d v0, Vector3d v1){
    Vector3d w = v0 - target;
    Vector3d u = v1 - v0;

    double N = -(normal.dot(w));
    double D = normal.dot(u);

    array<double, 3> coords3d = {v0[0] + (N/D) * u[0], v0[1] + (N/D) * u[1], v0[2] + (N/D) * u[2]};

    return coords3d;
}

int Plane3d::Id(){
    return id;
}

Vector2d Plane3d::Rotate(array<double, 3> _vec){
    Vector3d vec(_vec[0], _vec[1], _vec[2]);
    double xCoord = axisX.dot(vec - target);
    double yCoord = axisY.dot(vec - target);

    return Vector2d(xCoord, yCoord);
}

Vector3d Plane3d::Get3dPoint(Vector3d pt2d){
    double x=pt2d[0]*inverse.row(0)[0] + pt2d[1]*inverse.row(0)[1];
    double y=pt2d[0]*inverse.row(1)[0] + pt2d[1]*inverse.row(1)[1];
    double z=pt2d[0]*inverse.row(2)[0] + pt2d[1]*inverse.row(2)[1];
    Vector3d pt(x + target[0], y + target[1], z + target[2]);
    return pt;
}

Shape3d::Shape3d(unsigned long int _tetId, vector<array<double, 3>> _vertices, double _weight, int _label){
    tetId = _tetId;
    vertices = _vertices;
    weight = _weight;
    label = _label;
}

unsigned long int Shape3d::TetId(){
    return tetId;
}

vector<array<double, 3>> Shape3d::Vertices(){
    //return Vector3d(vertices[0], vertices[1], vertices[2]);
    //vector<Vector3d> verticesAsVecs;

    //for(int i=0; i<
    return vertices;
}

double Shape3d::Weight(){
    return weight;
}

int Shape3d::Label(){
    return label;
}


#pragma once

#include "../PolynomialBasisGen.hh"
#include "RBFKernel.hh"
#include "FiniteDifferentiator.hh"
#include <Eigen/Dense>
#include <boost/tuple/tuple.hpp>
#include <boost/static_assert.hpp>
#include <vector>

namespace kt84 {

template <int _DimIn, int _DimOut, class _RBFKernel_Core, int _DegreePolynomial>
struct GeneralizedMLS
    : public FiniteDifferentiator<GeneralizedMLS<_DimIn, _DimOut, _RBFKernel_Core, _DegreePolynomial>, _DimIn, _DimOut>
{
    enum {
        DimIn  = _DimIn,
        DimOut = _DimOut,
        DegreePolynomial = _DegreePolynomial,
    };

    typedef Eigen::Matrix<double, DimIn , 1> Point;
    typedef Eigen::Matrix<double, DimOut, 1> Value;
    typedef Eigen::Matrix<double, DimOut, DimIn> Gradient;
    typedef PolynomialBasisGen<DimIn, DegreePolynomial> PolynomialBasisGen;
    typedef RBFKernel_Bivariate<DimIn, _RBFKernel_Core> Kernel;
    typedef boost::tuple<Point, Value, Gradient> Constraint;

    BOOST_STATIC_ASSERT(Kernel::Decaying);

    std::vector<Constraint> constraints;
    Kernel kernel;

    void clear_constraints() {
        constraints.clear();
    }
    void add_constraint(const Point& point, const Value& value, const Gradient& gradient) {
        constraints.push_back(Constraint(point, value, gradient));
    }
    Value operator()(const Point& point) const {
        const int P = PolynomialBasisGen::DimOut;
        Eigen::Matrix<double, P, P> A;
        Eigen::Matrix<double, P, DimOut> b;
        A.setZero();
        b.setZero();
        for (size_t i = 0; i < constraints.size(); ++i) {
            const Point& point_i = constraints[i].get<0>();
            const Value& value_i = constraints[i].get<1>();
            const Gradient& gradient_i = constraints[i].get<2>();
            double w_i = kernel(point, point_i);
            if (w_i == std::numeric_limits<double>::infinity())
                return value_i;
            w_i = w_i * w_i;
            // value constraint
            PolynomialBasisGen::Basis basis_i = PolynomialBasisGen::basis(point_i);
            A += w_i * basis_i * basis_i.transpose();
            b += w_i * basis_i * value_i.transpose();
            // gradient constraint
            PolynomialBasisGen::Gradient basis_i_gradient = PolynomialBasisGen::gradient(point_i);
            A += w_i * basis_i_gradient * basis_i_gradient.transpose();
            b += w_i * basis_i_gradient * gradient_i.transpose();
        }
        Eigen::Matrix<double, P, DimOut> c = A.colPivHouseholderQr().solve(b);
        return c.transpose() * PolynomialBasisGen::basis(point);
    }
};

}


/*
Copyright (c) 2015, Tianwei Shen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* 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.

* Neither the name of libvot 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.
*/

/** \file euclidean_matrix.cpp
 *	\brief euclidean matrix completion (exe)
 */
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string>
#include <sstream>
#include <stdio.h>
#include <cmath>
#include <vector>

#include <Eigen/Dense>
#include <Eigen/SVD>

using namespace std;

/**
 * @brief An ad-hoc simple 2d point struct
 */
namespace {
struct point2d
{
	float x,y;
};
}	// end of namespace vot

float EuclideanDistance(point2d x1, point2d x2)
{
	return (x1.x - x2.x) * (x1.x - x2.x) + (x1.y - x2.y) * (x1.y - x2.y);
}

int main(int argc, char **argv)
{
	int input_size;
	cout << "the size of the matrix: \n";
	cin >> input_size;
	const int MATRIX_SIZE = input_size;
	string matrix_filename = "euclidean_matrix";
	stringstream ss;
	ss << matrix_filename << "_" << MATRIX_SIZE;
	ss >> matrix_filename;
	FILE *matrix_file = fopen(matrix_filename.c_str(), "w");

	std::vector<point2d> points(MATRIX_SIZE);
	for (int i = 0; i < MATRIX_SIZE; i++) {
		points[i].x = rand() % 1000;
		points[i].x /= 1000;
		points[i].y = rand() % 1000;
		points[i].y /= 1000;
	}

	Eigen::MatrixXf distance_matrix(MATRIX_SIZE, MATRIX_SIZE);
	for (int i = 0; i < MATRIX_SIZE; i++) {
		distance_matrix(i, i) = 0.0;
		for (int j = i+1; j < MATRIX_SIZE; j++) {
			distance_matrix(i, j) = EuclideanDistance(points[i], points[j]);
			distance_matrix(j, i) = distance_matrix(i, j);
		}
	}

	// output to the file
	for (int i = 0; i < MATRIX_SIZE; i++) {
		for (int j = 0; j < MATRIX_SIZE; j++) {
			cout << distance_matrix(i, j) << " ";
			fprintf(matrix_file, "%f ", distance_matrix(i, j));
		}
		cout << endl;
		fprintf(matrix_file, "\n");
	}

	Eigen::FullPivLU<Eigen::MatrixXf> lu_decomp(distance_matrix);
	//lu_decomp.setThreshold(1e-5);
	cout << "rank of distance matrix: " << lu_decomp.rank() << endl;

	//Eigen::JacobiSVD<Eigen::MatrixXf> svd(distance_matrix, Eigen::ComputeThinU | Eigen::ComputeThinV);
	//cout << svd.singularValues() << endl;

	fclose(matrix_file);
	return 0;
}


//==================================================================================================
/*!
  @file

  @copyright 2012-2015 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_CONSTANT_SQRT_2O_2_HPP_INCLUDED
#define BOOST_SIMD_CONSTANT_SQRT_2O_2_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{
  /*!
    @ingroup group-constant

    Generate value \f$\frac{\sqrt2}2\f$

    @par Semantic:

    @code
    T r = Sqrt_2o_2<T>();
    @endcode

    is similar to:

    @code
    T r = T(sqrt(T(2)))/T(2);
    @endcode

    @return The Sqrt_2o_2 constant for the proper type
  **/
  template<typename T> T Sqrt_2o_2();

  namespace functional
  {
    /*!
      @ingroup group-callable-constant
      Generate the  constant sqrt_2o_2.

      @return The Sqrt_2o_2 constant for the proper type
    **/
    const boost::dispatch::functor<tag::sqrt_2o_2_> sqrt_2o_2 = {};
  }
} }
#endif

#include <boost/simd/constant/definition/sqrt_2o_2.hpp>
#include <boost/simd/arch/common/scalar/constant/constant_value.hpp>
#include <boost/simd/arch/common/simd/constant/constant_value.hpp>

#endif


#pragma once

#include "Combinations.hpp"
#include "DyckPaths.hpp"
#include <boost/iterator/iterator_facade.hpp>

namespace discreture
{

////////////////////////////////////////////////////////////////////////////////////
/// \brief Class for iterating through all motzkin paths.
/// \param IntType must be a SIGNED integer type.
///
/// Motzkin paths are paths that go from \f$(0,0)\f$ to \f$(0,2n)\f$,
/// which never go below the \f$ y=0\f$ line, in which each step is from
/// \f$(x,y)\f$ to either \f$(x+1,y+1)\f$ or \f$(x+1,y-1)\f$ or \f$(x+1,y)\f$
/// #Example Usage:
///
///		motzkin_paths X(4)
///		for (auto&& x : X)
///			cout << x << endl;
/// Prints out:
///		[ 0 0 0 0 ]
///		[ 1 -1 0 0 ]
///		[ 1 0 -1 0 ]
///		[ 0 1 -1 0 ]
///		[ 1 0 0 -1 ]
///		[ 0 1 0 -1 ]
///		[ 0 0 1 -1 ]
///		[ 1 1 -1 -1 ]
///		[ 1 -1 1 -1 ]
///
///
/// # Example: Parenthesis
///
/// 	motzkin_paths X(4)
/// 	for (auto&& x : X)
/// 		cout << motzkin_paths::to_string(x, "(-)") << endl;
///
/// Prints out:
///		----
///		()--
///		(-)-
///		-()-
///		(--)
///		-(-)
///		--()
///		(())
///		()()
///
/////////////////////////////////////////////////////////////////////////////////////

template <class IntType = int, class RAContainerInt = std::vector<IntType>>
class MotzkinPaths
{
public:
    static_assert(std::is_integral<IntType>::value,
                  "Template parameter IntType must be integral");
    static_assert(std::is_signed<IntType>::value,
                  "Template parameter IntType must be signed");
    using value_type = RAContainerInt;
    using motzkin_path = value_type;
    using difference_type = std::ptrdiff_t;
    using size_type = difference_type;
    using comb_i = typename Combinations<IntType, RAContainerInt>::iterator;
    using dyck_i = typename DyckPaths<IntType, RAContainerInt>::iterator;
    class iterator;
    using const_iterator = iterator;

    static std::string to_string(const motzkin_path& data,
                                 const std::string& delim = "(-)")
    {
        std::string toReturn;

        for (auto i : data)
        {
            auto j = 1 - i;
            toReturn.push_back(delim[j]);
        }

        return toReturn;
    }

    // **************** End static functions

public:
    ////////////////////////////////////////////////////////////
    /// \brief Constructor
    ///
    /// \param n is an integer >= 0
    ///
    ////////////////////////////////////////////////////////////
    explicit MotzkinPaths(IntType n) : n_(n) {}

    ////////////////////////////////////////////////////////////
    /// \brief The total number of motzkin_paths
    ///
    /// \return M_n
    ///
    ////////////////////////////////////////////////////////////
    size_type size() const { return motzkin(n_); }

    IntType get_n() const { return n_; }

    iterator begin() const { return iterator(n_); }

    iterator end() const { return iterator::make_invalid_with_id(size()); }

    ////////////////////////////////////////////////////////////
    /// \brief Forward iterator class.
    ////////////////////////////////////////////////////////////
    class iterator
        : public boost::iterator_facade<iterator, const motzkin_path&, boost::forward_traversal_tag>
    {
    public:
        iterator() : data_(), comb_(), dyck_() {} // empty initializer

        explicit iterator(IntType n) : data_(n, 0), comb_(n, 0), dyck_(0) {}

        size_type ID() const { return ID_; }

        static iterator make_invalid_with_id(size_type id)
        {
            iterator it;
            it.ID_ = id;
            return it;
        }

    private:
        void increment()
        {
            ++ID_;
            auto n = data_.size();

            if (ID_ == motzkin(n))
                return;

            ++comb_;
            if (comb_.is_at_end(n))
            {
                ++dyck_;

                if (dyck_.is_at_end(num_nonzero_halved_))
                {
                    num_nonzero_halved_ += 1;

                    dyck_.reset(num_nonzero_halved_);
                }

                comb_.reset(n, 2*num_nonzero_halved_);
            }

            ConvertToMotzkin(); // TODO(mraggi): do this laziliy
        }

        const motzkin_path& dereference() const { return data_; }

        bool equal(const iterator& it) const { return it.ID() == ID(); }

    private:
        size_type ID_{0};
        motzkin_path data_;
        comb_i comb_;
        dyck_i dyck_;
        IntType num_nonzero_halved_{0};

        void ConvertToMotzkin()
        {
            // 				cout << "Converting: " << *comb_ << " and " <<
            // *dyck_
            // << endl;
            for (size_t i = 0; i < data_.size(); ++i)
            {
                data_[i] = 0;
            }

            size_t count = 0;

            for (auto x : (*comb_))
            {
                data_[x] = (*dyck_)[count];
                ++count;
            }
        }

        friend class boost::iterator_core_access;
    }; // end class iterator

private:
    IntType n_;
}; // end class MotzkinPaths

using boost::container::static_vector;

using motzkin_paths = MotzkinPaths<int>;
using motzkin_paths_stack = MotzkinPaths<int, static_vector<int, 48>>;

} // namespace discreture