Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
multigridstep.cc 9.45 KiB
// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=8 sw=4 sts=4:

#include <typeinfo>

#include <dune/solvers/transferoperators/multigridtransfer.hh>
#include <dune/solvers/solvers/loopsolver.hh>
#include <dune/solvers/solvers/linearsolver.hh>
#include <dune/solvers/common/genericvectortools.hh>

//template<class MatrixType, class VectorType, class BitVectorType>
//inline
//const MatrixType* MultigridStep<MatrixType, VectorType, BitVectorType>::
//getMatrix()
//{
//    return this->mat_;
//}

template<class MatrixType, class VectorType, class BitVectorType>
inline
void MultigridStep<MatrixType, VectorType, BitVectorType>::
setMGType(int mu, int nu1, int nu2)
{
    mu_ = mu;
    nu1_ = nu1;
    nu2_ = nu2;
}

/** \brief Sets up the MultigridStep for computation
 *
 *  Resizes all hierarchy containers to appropriate size
 *  Sets up:
 *  \li matrix hierarchy
 *  \li ignore nodes hierarchy
 *  \li the base solver
 *
 *  \b NOTE: All data, i.e.
 *  \li transfer operators
 *  \li fine level matrix, solution vector and right hand side
 *  \li smoothers
 *  have to be set prior to the call to preprocess().
 *  If any is changed subsequently, preprocess() has to be called again before iterate().
 *  There is one exception. The right hand side may be changed by setRhs() without a subsequent call to preprocess().
 *  This is in order to be able to compute solutions to multiple rhs w/o having to reassemble the same matrix hierarchy time and again.
 */
template<class MatrixType, class VectorType, class BitVectorType>
void MultigridStep<MatrixType, VectorType, BitVectorType>::preprocess()
{
    if(preprocessCalled)
        std::cout << "Warning: Preprocess has already been called without calling iterate afterwards!" << std::endl;
    preprocessCalled = true;

    this->level_ = numLevels()-1;

    // //////////////////////////////////////////////////////////
    //   Check that transfer operators have been supplied
    // //////////////////////////////////////////////////////////
    for (size_t i=0; i<this->mgTransfer_.size(); i++)
        if (this->mgTransfer_[i] == NULL)
            DUNE_THROW(SolverError, "You have not supplied a multigrid restriction operator "
                       "for level " << i);


    // //////////////////////////////////////////////////////////
    //   Resize hierarchy containers to current number of levels
    //   and set fine level data where needed.
    // //////////////////////////////////////////////////////////
    for (int i=0; i<int(ignoreNodesHierarchy_.size())-1; i++)
        if (ignoreNodesHierarchy_[i])
            delete(ignoreNodesHierarchy_[i]);

    xHierarchy_.resize(numLevels());
    rhsHierarchy_.resize(numLevels());
    matrixHierarchy_.resize(numLevels());
    ignoreNodesHierarchy_.resize(numLevels());

    for (int i=0; i<int(matrixHierarchy_.size())-1; i++)
    {
        matrixHierarchy_[i].reset();
        xHierarchy_[i].reset();
        ignoreNodesHierarchy_[i] = NULL;
    }

    matrixHierarchy_.back() = this->mat_;
    xHierarchy_.back()      = Dune::stackobject_to_shared_ptr(*(this->x_));
    rhsHierarchy_.back()    = *(this->rhs_);

    presmoother_.resize(numLevels());
    postsmoother_.resize(numLevels());

    typename SmootherCache::iterator end=levelWiseSmoothers_.end();
    for (size_t i=0; i<numLevels(); ++i)
    {
        typename SmootherCache::iterator levelSmoother = levelWiseSmoothers_.find(i);
        if (levelSmoother != end)
            presmoother_[i] = postsmoother_[i] = levelSmoother->second;
        else
        {
            presmoother_[i]  = presmootherDefault_;
            postsmoother_[i] = postsmootherDefault_;
        }
    }

    // /////////////////////////////////////////////////////
    //   Assemble the complete hierarchy of matrices
    // /////////////////////////////////////////////////////
    for (int i=this->numLevels()-2; i>=0; i--)
    {
        this->matrixHierarchy_[i] = std::shared_ptr<MatrixType>(new MatrixType);
        this->xHierarchy_[i] = std::shared_ptr<VectorType>(new VectorType);

        // Compute which entries are present in the (sparse) coarse grid stiffness
        // matrices.
        this->mgTransfer_[i]->galerkinRestrictSetOccupation(*this->matrixHierarchy_[i+1], *std::const_pointer_cast<MatrixType>(this->matrixHierarchy_[i]));

        // setup matrix
        this->mgTransfer_[i]->galerkinRestrict(*this->matrixHierarchy_[i+1], *std::const_pointer_cast<MatrixType>(this->matrixHierarchy_[i]));

        // Set solution vector sizes for the lower levels
        GenericVector::resize(*(this->xHierarchy_[i]),*this->matrixHierarchy_[i]);
    }

    // /////////////////////////////////////////////////////
    //   Setup dirichlet bitfields
    // /////////////////////////////////////////////////////
    if (this->ignoreNodes_!=0)
    {
        ignoreNodesHierarchy_[numLevels()-1] = const_cast<BitVectorType*>(this->ignoreNodes_);
        for (int i=numLevels()-2; i>=0; --i)
        {
            ignoreNodesHierarchy_[i] = new BitVectorType();
            this->mgTransfer_[i]->restrictToFathers(*ignoreNodesHierarchy_[i+1], *ignoreNodesHierarchy_[i]);
        }
    } else
        DUNE_THROW(SolverError, "We need a set of nodes to ignore");

    // /////////////////////////////////////////////
    //   Set up base solver
    // /////////////////////////////////////////////
    using SmootherType = LinearIterationStep<MatrixType, VectorType, BitVectorType>;
    using LinearSolverType = LinearSolver<MatrixType, VectorType>;
    if (basesolver_)
    {
        // If the base solver can ignore dofs give it the ignoreNodes field
        if (dynamic_cast<CanIgnore<BitVectorType>*>(this->basesolver_.get()))
            dynamic_cast<CanIgnore<BitVectorType>*>(this->basesolver_.get())->setIgnore(*ignoreNodesHierarchy_[0]);

        typedef ::LoopSolver<VectorType> DuneSolversLoopSolver;

        if (dynamic_cast<DuneSolversLoopSolver*>(this->basesolver_.get())) {

            DuneSolversLoopSolver* loopBaseSolver = dynamic_cast<DuneSolversLoopSolver*> (this->basesolver_.get());

            assert(dynamic_cast<SmootherType*>(&loopBaseSolver->getIterationStep()));

            dynamic_cast<SmootherType*>(&loopBaseSolver->getIterationStep())->setProblem(*(this->matrixHierarchy_[0]), *this->xHierarchy_[0], this->rhsHierarchy_[0]);
            dynamic_cast<SmootherType*>(&loopBaseSolver->getIterationStep())->setIgnore(*ignoreNodesHierarchy_[0]);

        }
        else if (dynamic_cast<LinearSolverType*>(this->basesolver_.get())) {

            LinearSolverType* linearBaseSolver = dynamic_cast<LinearSolverType*> (this->basesolver_.get());

            linearBaseSolver->setProblem(*(this->matrixHierarchy_[0]), *this->xHierarchy_[0], this->rhsHierarchy_[0]);
        }
        else {
            DUNE_THROW(SolverError, "You can't use " << typeid(*this->basesolver_).name()
                       << " as a base solver in a MultigridStep!");
        }
    }
}


template<class MatrixType, class VectorType, class BitVectorType>
void MultigridStep<MatrixType, VectorType, BitVectorType>::nestedIteration()
{
    for (level_ = 0; level_<(int) numLevels(); level_++)
    {
        iterate();

        mgTransfer_[level_]->prolong(*xHierarchy_[level_], *xHierarchy_[level_+1]);
    }

    iterate();
}


template<class MatrixType, class VectorType, class BitVectorType>
void MultigridStep<MatrixType, VectorType, BitVectorType>::postprocess()
{
}


template<class MatrixType, class VectorType, class BitVectorType>
void MultigridStep<MatrixType, VectorType, BitVectorType>::iterate()
{
    preprocessCalled = false;

    int& level = this->level_;

    // Define references just for ease of notation
    std::vector<std::shared_ptr<const MatrixType> > const &mat = this->matrixHierarchy_;
    std::vector<std::shared_ptr<VectorType> >& x   = this->xHierarchy_;
    std::vector<VectorType>& rhs = this->rhsHierarchy_;

    // Solve directly if we're looking at the coarse problem
    if ((level == 0) and (basesolver_)) {
        basesolver_->solve();
        return;
    }

    // Presmoothing

    presmoother_[level]->setProblem(*(this->matrixHierarchy_[level]), *x[level], rhs[level]);
    presmoother_[level]->ignoreNodes_ = ignoreNodesHierarchy_[level];

    for (int i=0; i<this->nu1_; i++)
        presmoother_[level]->iterate();

    if (level>0)
    {
        // /////////////////////////
        // Restriction

        // compute residual
        // fineResidual = rhs[level] - mat[level] * x[level];
        VectorType fineResidual = rhs[level];
        mat[level]->mmv(*x[level], fineResidual);

        // restrict residual
        this->mgTransfer_[level-1]->restrict(fineResidual, rhs[level-1]);


        // Set Dirichlet values.
        GenericVector::truncate(rhs[level-1], *ignoreNodesHierarchy_[level-1]);

        // Choose all zeros as the initial correction
        *x[level-1] = 0;

        // ///////////////////////////////////////
        // Recursively solve the coarser system
        level--;
        for (int i=0; i<mu_; i++)
            iterate();
        level++;

        // ////////////////////////////////////////
        // Prolong

        // add correction to the presmoothed solution
        VectorType tmp;
        this->mgTransfer_[level-1]->prolong(*x[level-1], tmp);
        *x[level] += tmp;
    }

    // Postsmoothing
    postsmoother_[level]->setProblem(*(mat[level]), *x[level], rhs[level]);
    postsmoother_[level]->ignoreNodes_ = ignoreNodesHierarchy_[level];

    for (int i=0; i<this->nu2_; i++)
        postsmoother_[level]->iterate();

//    *(this->x_) = xHierarchy_.back();

}