Skip to content
Snippets Groups Projects
myblockproblem.hh 8.59 KiB
Newer Older
Elias Pipping's avatar
Elias Pipping committed
// Based on dune/tnnmg/problem-classes/blocknonlineartnnmgproblem.hh
Elias Pipping's avatar
Elias Pipping committed
#ifndef MY_BLOCK_PROBLEM_HH
#define MY_BLOCK_PROBLEM_HH

Elias Pipping's avatar
Elias Pipping committed
#include <dune/common/bitsetvector.hh>
Elias Pipping's avatar
Elias Pipping committed
#include <dune/common/nullptr.hh>
Elias Pipping's avatar
Elias Pipping committed
#include <dune/common/parametertree.hh>
Elias Pipping's avatar
Elias Pipping committed
#include <dune/fufem/arithmetic.hh>
#include <dune/solvers/common/interval.hh>
#include <dune/solvers/computeenergy.hh>
Elias Pipping's avatar
Elias Pipping committed
#include <dune/tnnmg/problem-classes/bisection.hh>

Elias Pipping's avatar
Elias Pipping committed
#include "globalnonlinearity.hh"
#include "minimisation.hh"
#include "mydirectionalconvexfunction.hh"
#include "ellipticenergy.hh"
Elias Pipping's avatar
Elias Pipping committed
/** \brief Base class for problems where each block can be solved with a
 * modified gradient method */
template <class ConvexProblem> class MyBlockProblem {
Elias Pipping's avatar
Elias Pipping committed
public:
  using ConvexProblemType = ConvexProblem;
  using VectorType = typename ConvexProblem::VectorType;
  using MatrixType = typename ConvexProblem::MatrixType;
  using LocalVector = typename ConvexProblem::LocalVectorType;
  using LocalMatrix = typename ConvexProblem::LocalMatrixType;
  size_t static const block_size = ConvexProblem::block_size;
  size_t static const coarse_block_size = block_size;
Elias Pipping's avatar
Elias Pipping committed
  /** \brief Solves one local system using a modified gradient method */
Elias Pipping's avatar
Elias Pipping committed
  class IterateObject;

Elias Pipping's avatar
Elias Pipping committed
  struct Linearization {
    size_t static const block_size = coarse_block_size;
Elias Pipping's avatar
Elias Pipping committed

    using LocalMatrix = typename MyBlockProblem<ConvexProblem>::LocalMatrix;
    using MatrixType = Dune::BCRSMatrix<typename Linearization::LocalMatrix>;
Elias Pipping's avatar
Elias Pipping committed
    using VectorType =
        Dune::BlockVector<Dune::FieldVector<double, Linearization::block_size>>;
    using BitVectorType = Dune::BitSetVector<Linearization::block_size>;
Elias Pipping's avatar
Elias Pipping committed

Elias Pipping's avatar
Elias Pipping committed
    typename Linearization::MatrixType A;
    typename Linearization::VectorType b;
    typename Linearization::BitVectorType ignore;

    Dune::BitSetVector<Linearization::block_size> truncation;
  };

Elias Pipping's avatar
Elias Pipping committed
  MyBlockProblem(Dune::ParameterTree const &parset,
                 ConvexProblem const &problem)
      : parset(parset), problem(problem), localBisection() // NOTE: defaults
  {}
Elias Pipping's avatar
Elias Pipping committed
  std::string getOutput(bool header = false) const {
Elias Pipping's avatar
Elias Pipping committed
    if (header) {
      outStream.str("");
      for (size_t j = 0; j < block_size; ++j)
Elias Pipping's avatar
Elias Pipping committed
        outStream << "  trunc" << std::setw(2) << j;
    }
    std::string s = outStream.str();
    outStream.str("");
    return s;
Elias Pipping's avatar
Elias Pipping committed
  }

  double computeEnergy(const VectorType &v) const {
    return 0.0; // FIXME
    // return ::computeEnergy(problem_.A, v, problem_.f) + problem_.phi(v);
  }

Elias Pipping's avatar
Elias Pipping committed
  void projectCoarseCorrection(VectorType const &u,
                               typename Linearization::VectorType const &v,
                               VectorType &projected_v,
                               Linearization const &linearization) const {
    projected_v = v;
    for (size_t i = 0; i < v.size(); ++i)
      for (size_t j = 0; j < block_size; ++j)
        if (linearization.truncation[i][j])
          projected_v[i][j] = 0;
  }
Elias Pipping's avatar
Elias Pipping committed

  double computeDampingParameter(VectorType const &u,
                                 VectorType const &projected_v) const {
    VectorType v = projected_v;

    double const vnorm = v.two_norm();
    if (vnorm <= 0)
      return 1.0;

    v /= vnorm; // Rescale for numerical stability
    MyDirectionalConvexFunction<
        GlobalNonlinearity<MatrixType, VectorType>> const
    psi(computeDirectionalA(problem.A, v),
        computeDirectionalb(problem.A, problem.f, u, v), problem.phi, u, v);
    Dune::Solvers::Interval<double> D;
    psi.subDiff(0, D);
Elias Pipping's avatar
Elias Pipping committed
    // NOTE: Numerical instability can actually get us here
    if (D[1] > 0)
      return 0;
    int bisectionsteps = 0;
    Bisection const globalBisection; // NOTE: defaults
    return globalBisection.minimize(psi, vnorm, 0.0, bisectionsteps) / vnorm;
Elias Pipping's avatar
Elias Pipping committed

  void assembleTruncate(VectorType const &u, Linearization &linearization,
                        Dune::BitSetVector<block_size> const &ignore) const {
    // we can just copy the ignore information
    linearization.ignore = ignore;

    // determine truncation pattern
    linearization.truncation.resize(u.size());
    linearization.truncation.unsetAll();
    for (size_t i = 0; i < u.size(); ++i) {
Elias Pipping's avatar
Elias Pipping committed
      if (problem.phi.regularity(i, u[i]) > 1e8) { // TODO: Make customisable
Elias Pipping's avatar
Elias Pipping committed
        linearization.truncation[i] = true;
      for (size_t j = 0; j < block_size; ++j)
        if (linearization.ignore[i][j])
          linearization.truncation[i][j] = true;
    }
Elias Pipping's avatar
Elias Pipping committed

    // construct sparsity pattern for linearization
    Dune::MatrixIndexSet indices(problem.A.N(), problem.A.M());
    indices.import(problem.A);
Elias Pipping's avatar
Elias Pipping committed
    problem.phi.addHessianIndices(indices);
Elias Pipping's avatar
Elias Pipping committed

    // construct matrix from pattern and initialize it
    indices.exportIdx(linearization.A);
    linearization.A = 0.0;

    // compute quadratic part of hessian (linearization.A += problem.A)
Elias Pipping's avatar
Elias Pipping committed
    for (size_t i = 0; i < problem.A.N(); ++i) {
Elias Pipping's avatar
Elias Pipping committed
      auto const end = problem.A[i].end();
      for (auto it = problem.A[i].begin(); it != end; ++it)
        linearization.A[i][it.index()] += *it;
Elias Pipping's avatar
Elias Pipping committed
    }

    // compute nonlinearity part of hessian
    problem.phi.addHessian(u, linearization.A);

    // compute quadratic part of gradient
    linearization.b.resize(u.size());
    problem.A.mv(u, linearization.b);
Elias Pipping's avatar
Elias Pipping committed
    linearization.b -= problem.f;

    // compute nonlinearity part of gradient
    problem.phi.addGradient(u, linearization.b);

    // -grad is needed for Newton step
    linearization.b *= -1.0;

    // apply truncation to stiffness matrix and rhs
Elias Pipping's avatar
Elias Pipping committed
    for (size_t row = 0; row < linearization.A.N(); ++row) {
      auto const col_end = linearization.A[row].end();
      for (auto col_it = linearization.A[row].begin(); col_it != col_end;
           ++col_it) {
        size_t const col = col_it.index();
        for (size_t i = 0; i < col_it->N(); ++i) {
          auto const blockEnd = (*col_it)[i].end();
          for (auto blockIt = (*col_it)[i].begin(); blockIt != blockEnd;
               ++blockIt)
Elias Pipping's avatar
Elias Pipping committed
            if (linearization.truncation[row][i] or linearization
                    .truncation[col][blockIt.index()])
Elias Pipping's avatar
Elias Pipping committed
              *blockIt = 0.0;
      for (size_t j = 0; j < block_size; ++j)
Elias Pipping's avatar
Elias Pipping committed
        if (linearization.truncation[row][j])
          linearization.b[row][j] = 0.0;
    }

    for (size_t j = 0; j < block_size; ++j)
Elias Pipping's avatar
Elias Pipping committed
      outStream << std::setw(9) << linearization.truncation.countmasked(j);
Elias Pipping's avatar
Elias Pipping committed
  /** \brief Constructs and returns an iterate object */
  IterateObject getIterateObject() {
    return IterateObject(parset, localBisection, problem);
Elias Pipping's avatar
Elias Pipping committed

private:
  Dune::ParameterTree const &parset;

Elias Pipping's avatar
Elias Pipping committed
  // problem data
  ConvexProblem const &problem;
  Bisection const localBisection;
Elias Pipping's avatar
Elias Pipping committed
  mutable std::ostringstream outStream;
Elias Pipping's avatar
Elias Pipping committed
};

/** \brief Solves one local system using a scalar Gauss-Seidel method */
template <class ConvexProblem>
class MyBlockProblem<ConvexProblem>::IterateObject {
Elias Pipping's avatar
Elias Pipping committed
  friend class MyBlockProblem;

protected:
  /** \brief Constructor, protected so only friends can instantiate it
   * \param bisection The class used to do a scalar bisection
Elias Pipping's avatar
Elias Pipping committed
   * \param problem The problem including quadratic part and nonlinear part
Elias Pipping's avatar
Elias Pipping committed
   */
Elias Pipping's avatar
Elias Pipping committed
  IterateObject(Dune::ParameterTree const &parset, Bisection const &bisection,
                ConvexProblem const &problem)
      : problem(problem),
        localsteps(parset.get<size_t>("localsolver.steps")) {}
Elias Pipping's avatar
Elias Pipping committed

public:
  /** \brief Set the current iterate */
Elias Pipping's avatar
Elias Pipping committed
  void setIterate(VectorType &u) {
Elias Pipping's avatar
Elias Pipping committed
    this->u = u;
    return;
Elias Pipping's avatar
Elias Pipping committed
  }
Elias Pipping's avatar
Elias Pipping committed

  /** \brief Update the i-th block of the current iterate */
  void updateIterate(LocalVector const &ui, size_t i) {
Elias Pipping's avatar
Elias Pipping committed
    u[i] = ui;
    return;
Elias Pipping's avatar
Elias Pipping committed
  }
Elias Pipping's avatar
Elias Pipping committed
  /** \brief Minimise a local problem using a modified gradient method
Elias Pipping's avatar
Elias Pipping committed
   * \param[out] ui The solution
Elias Pipping's avatar
Elias Pipping committed
   * \param m Block number
Elias Pipping's avatar
Elias Pipping committed
   * \param ignore Set of degrees of freedom to leave untouched
   */
  void solveLocalProblem(
      LocalVector &ui, size_t m,
      typename Dune::BitSetVector<block_size>::const_reference ignore) {
      LocalMatrix const *localA = nullptr;
      LocalVector localb(problem.f[m]);
Elias Pipping's avatar
Elias Pipping committed
      auto const end = problem.A[m].end();
      for (auto it = problem.A[m].begin(); it != end; ++it) {
        size_t const j = it.index();
Elias Pipping's avatar
Elias Pipping committed
          localA = &(*it); // localA = A[m][m]
          Arithmetic::subtractProduct(localb, *it, u[j]);
Elias Pipping's avatar
Elias Pipping committed
      assert(localA != nullptr);
Elias Pipping's avatar
Elias Pipping committed
      auto const phi = problem.phi.restriction(m);
      EllipticEnergy<block_size> localJ(*localA, localb, phi, ignore);
      minimise(localJ, ui, localsteps, bisection_);
Elias Pipping's avatar
Elias Pipping committed

private:
  // problem data
  ConvexProblem const &problem;
  Bisection const bisection_;
Elias Pipping's avatar
Elias Pipping committed

  // state data for smoothing procedure used by:
  // setIterate, updateIterate, solveLocalProblem
  VectorType u;

  size_t const localsteps;
Elias Pipping's avatar
Elias Pipping committed
};
Elias Pipping's avatar
Elias Pipping committed

#endif