Skip to content
Snippets Groups Projects
Forked from agnumpde / dune-tectonic
40 commits ahead of the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
multilevelpatchpreconditioner.hh 7.74 KiB
#ifndef MULTILEVEL_PATCH_PRECONDITIONER_HH
#define MULTILEVEL_PATCH_PRECONDITIONER_HH

#include <string>

#include <dune/common/timer.hh>
#include <dune/common/fvector.hh>
#include <dune/common/bitsetvector.hh>

#include <dune/solvers/iterationsteps/lineariterationstep.hh>

#include "nbodytransfer.hh"
#include "levelpatchpreconditioner.hh"
#include <dune/faultnetworks/dgmgtransfer.hh>

template <class ContactNetwork, class PatchSolver, class MatrixType, class VectorType>
class MultilevelPatchPreconditioner : public LinearIterationStep<MatrixType, VectorType> {
public:
    enum Mode {additive, multiplicative};

private:
    using LevelContactNetwork = typename ContactNetwork::LevelContactNetwork;
    using LevelPatchPreconditioner = LevelPatchPreconditioner<LevelContactNetwork, PatchSolver, MatrixType, VectorType>;
    using LevelGlobalPreconditioner = LevelPatchPreconditioner<LevelContactNetwork, PatchSolver, MatrixType, VectorType>;
    using BitVector = typename LinearIterationStep<MatrixType, VectorType>::BitVector;

    using MGTransfer = ;

    const ContactNetwork& contactNetwork_;
    const Dune::BitSetVector<1>& activeLevels_;

    const Mode mode_;

    std::vector<std::shared_ptr<LevelPatchPreconditioner>> levelPatchPreconditioners_;

    std::vector<MatrixType> levelMat_;
    std::vector<VectorType> levelX_;
    std::vector<VectorType> levelRhs_;
    std::vector<BitVector> levelIgnore_;

    PatchSolver coarseSolver_;

    std::vector<std::shared_ptr<MGTransfer>> mgTransfer_; //TODO

public:
    MultilevelPatchPreconditioner(const ContactNetwork& contactNetwork,
                                  const Dune::BitSetVector<1>& activeLevels,
                                  const Mode mode = MultilevelPatchPreconditioner::Mode::additive) :
          contactNetwork_(contactNetwork),
          activeLevels_(activeLevels),
          mode_(mode) {

        assert(activeLevels.size() == contactNetwork_.nLevels());

        // init level patch preconditioners and multigrid transfer
        levelPatchPreconditioners_.resize(0);
        mgTransfer_.resize(0);

        int maxLevel = -1;
        for (size_t i=0; i<activeLevels_.size(); i++) {
            if (activeLevels_[i][0]) {
                // init global problem on coarsest level
                const auto& levelNetwork = *contactNetwork_.level(i);
                coarseGlobalPreconditioner_ = std::make_shared<LevelGlobalPreconditioner>(levelNetwork);

                maxLevel = i;
                break;
            }
        }
        const int coarsestLevel = maxLevel;

        typename LevelPatchPreconditioner::Mode levelMode = LevelPatchPreconditioner::Mode::additive;
        if (mode_ != additive){
            levelMode = LevelPatchPreconditioner::Mode::multiplicative;
        }

        for (size_t i=maxLevel+1; i<activeLevels_.size(); i++) {
            if (activeLevels_[i][0]) {
                // init local patch preconditioners on each level
                const auto& fineNetwork = contactNetwork_.level(i);
                levelPatchPreconditioners_.push_back(std::make_shared<LevelPatchPreconditioner(*contactNetwork_.level(maxLevel), fineNetwork, levelMode));

                maxLevel = i;
            }
        }

        levelX_.resize(size());
        levelRhs_.resize(size());

        // init multigrid transfer
        for (size_t i=0; i<levelPatchPreconditioners_.size(); i++) {
            mgTransfer_.push_back(std::make_shared<MGTransfer>(...));
        }
        mgTransfer_.push_back(std::make_shared<MGTransfer>(coarseGlobalPreconditioner_->basis(), *allFaultBasis_));
    }


   void setProblem(const MatrixType& mat, VectorType& x, const VectorType& rhs) override {
        this->setProblem(mat, x, rhs);

        for (size_t i=0; i<levelPatchPreconditioners_.size(); i++) {
            const auto& transfer = *mgTransfer_[i];
            auto& _x = levelX_[i];
            auto& _rhs = levelRhs_[i];
            auto& _mat = levelMat_[i];

            transfer.restrict(x, _x);
            transfer.restrict(rhs, _rhs);
            transfer.galerkinRestrict(mat, _mat);

            levelPatchPreconditioners_[i]->setProblem(_mat, _x, _rhs);
        }

        // set coarse global problem
        const auto& coarseTransfer = *mgTransfer_.back();
        auto& coarseX = levelX_.back();
        auto& coarseRhs = levelRhs_.back();
        auto& coarseMat = levelMat_.back();

        coarseTransfer.restrict(x, coarseX);
        coarseTransfer.restrict(rhs, coarseRhs);
        coarseTransfer.galerkinRestrict(mat, coarseMat);

        coarseSolver_.getIterationStep().setProblem(coarseMat, coarseX, coarseRhs);
    }


    void iterate() {
        if (mode_ == additive)
            iterateAdd();
        else
            iterateMult();
    }

    void iterateAdd() {
        *(this->x_) = 0;	

        VectorType x;
        // solve coarse global problem
        auto& coarseIgnore = levelIgnore_.back();
        mgTransfer_.back()->restrict(this->ignore(), coarseIgnore);
        coarseSolver_.getIterationStep().setIgnore(coarseIgnore);

        coarseSolver_.check();
        coarseSolver_.preprocess();
        coarseSolver_.solve();

        mgTransfer_.back()->prolong(coarseSolver_.getSol(), x);

        for (size_t i=levelPatchPreconditioners_.size()-2; i>=0; i--) {
            const auto& transfer = *mgTransfer_[i];
            auto& preconditioner = *levelPatchPreconditioners_[i];

            auto& _ignore = levelIgnore_[i];
            transfer.restrict(this->ignore(), _ignore);
            preconditioner.setIgnore(_ignore);

            preconditioner.iterate();

            x += preconditioner.getSol();

            VectorType newX;
            transfer.prolong(x, newX);

            x = newX;
        }

        *(this->x_) = x;
    }


    void iterateMult() {
        *(this->x_) = 0;

        /*
        VectorType x;

        for (int i=(levelPatchPreconditioners_.size()-1); i>=0; i--) {
            VectorType updatedRhs(*(this->rhs_));
            this->mat_->mmv(*(this->x_), updatedRhs);

            mgTransfer_[i]->restrict(*(this->x_), levelX_[i]);
            mgTransfer_[i]->restrict(updatedRhs, levelRhs_[i]);

            levelPatchPreconditioners_[i]->setProblem(*(this->mat_), levelX_[i], levelRhs_[i]);

            levelPatchPreconditioners_[i]->iterate();
            const VectorType& it = levelPatchPreconditioners_[i]->getSol();

            mgTransfer_[i]->prolong(it, x);

            *(this->x_) += x;
        }

        VectorType updatedCoarseRhs(*(this->rhs_));
        this->mat_->mmv(*(this->x_), updatedCoarseRhs);

        size_t j = levelPatchPreconditioners_.size();
        mgTransfer_[j]->restrict(*(this->x_), levelX_[j]);
        mgTransfer_[j]->restrict(updatedCoarseRhs, levelRhs_[j]);

        coarseGlobalPreconditioner_->setProblem(*(this->mat_), levelX_[j], levelRhs_[j]);
        coarseGlobalPreconditioner_->iterate();
        const VectorType& it = coarseGlobalPreconditioner_->getSol();

        mgTransfer_[j]->prolong(it, x);

        *(this->x_) += x; */
    }

    void build() {
        coarseGlobalPreconditioner_->build();

        for (size_t i=0; i<levelPatchPreconditioners_.size(); i++) {
            levelPatchPreconditioners_[i]->build();
        }
    }

    void setPatchSolver(PatchSolver&& patchSolver) {
        for (size_t i=0; i<levelPatchPreconditioners_.size(); i++) {
            levelPatchPreconditioners_[i]->setPatchSolver(std::forward<PatchSolver>(patchSolver));
        }
        coarseGlobalPreconditioner_->setPatchSolver(std::forward<PatchSolver>(patchSolver));
    };

    void setPatchDepth(const size_t patchDepth = 0) {
        for (size_t i=0; i<levelPatchPreconditioners_.size(); i++) {
            levelPatchPreconditioners_[i]->setPatchDepth(patchDepth);
        }
    }

    size_t size() const {
        return levelPatchPreconditioners_.size()+1;
    }
};

#endif