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

#include <config.h>

#include <cmath>
#include <iostream>
#include <sstream>

// dune-common includes
#include <dune/common/bitsetvector.hh>
#include <dune/common/parallel/mpihelper.hh>

// dune-istl includes
#include <dune/istl/bcrsmatrix.hh>

// dune-grid includes

// dune-solver includes
#include <dune/solvers/transferoperators/compressedmultigridtransfer.hh>
#include <dune/solvers/norms/energynorm.hh>
#include <dune/solvers/solvers/loopsolver.hh>
#include <dune/solvers/iterationsteps/blockgssteps.hh>
#include <dune/solvers/iterationsteps/multigridstep.hh>


#include "common.hh"

/**  \brief test for the MultigridStep class
  *
  *  This test tests if the Dirichlet problem for a laplace operator is solved correctly for a "random" rhs by a LoopSolver employing the MultigridStep.
  *  It furthermore tests the functionality to solve correctly for a different rhs with otherwise unaltered data without calling preprocess().
  *  Setting and using different smoothers in different levels is NOT a tested feature.
  */
template <size_t blocksize, bool trivialDirichletOnly = true>
struct MultigridTestSuite
{
    template <class GridType>
    bool check(const GridType& grid)
    {
        double tol = 1e-12;
        int maxIterations = 200;

        bool passed = true;

        using Problem =
            SymmetricSampleProblem<blocksize, typename GridType::LevelGridView, trivialDirichletOnly>;
        Problem p(grid.levelGridView(grid.maxLevel()));

        typedef typename Problem::Vector Vector;
        typedef typename Problem::Matrix Matrix;
        typedef typename Problem::BitVector BitVector;
        typedef ::LoopSolver<Vector> Solver;
        typedef MultigridStep<Matrix, Vector, BitVector> MGStep;
        typedef MultigridTransfer<Vector, BitVector, Matrix> Transfer;
        typedef CompressedMultigridTransfer<Vector, BitVector, Matrix> TransferImplementation;

        // we need a vector of pointers to the transfer operator base class
        std::vector<Transfer*> transfer(grid.maxLevel());
        for (size_t i = 0; i < transfer.size(); ++i)
        {
            // create transfer operator from level i to i+1 (note that this will only work for either uniformly refined grids or adaptive grids with RefinementType=COPY)
            TransferImplementation* t = new TransferImplementation;
            t->setup(grid, i, i+1);
            transfer[i] = t;
        }

        // set up smoothers and basesolver
        auto smoother =
            Dune::Solvers::BlockGSStepFactory<Matrix, Vector>::create(
                Dune::Solvers::BlockGS::LocalSolvers::gs());
        auto basesolver_step =
            Dune::Solvers::BlockGSStepFactory<Matrix, Vector>::create(
                Dune::Solvers::BlockGS::LocalSolvers::gs());

        typename Problem::Norm basenorm(basesolver_step);

        Solver basesolver(&basesolver_step, 1, 1e-10, &basenorm, Solver::QUIET);

        // create iteration step and set all kinds of data
        MGStep mgStep;
        mgStep.setTransferOperators(transfer);
        mgStep.setProblem(p.A,p.u,p.rhs);
        mgStep.setSmoother(&smoother);
        mgStep.setMGType(1,3,3);
        mgStep.ignoreNodes_ = &p.ignore;
        mgStep.basesolver_  = &basesolver;

        // create loop solver
        Solver solver(&mgStep, maxIterations, tol, &p.energyNorm, Solver::FULL);

        // solve problem
        solver.preprocess();
        solver.solve();

        p.u = mgStep.getSol();

        if (p.energyNorm.diff(p.u,p.u_ex)>tol*10)
        {
            std::cout << "The MultigridStep did not produce a satisfactory result. ||u-u_ex||=" << p.energyNorm.diff(p.u,p.u_ex) << std::endl;
            std::cout << "||u_ex||=" << p.energyNorm(p.u_ex) << std::endl;
            passed = false;
        }

        p.randomize();

        // reset rhs in mgStep without calling preprocess subsequently
        mgStep.setRhs(p.rhs);

        solver.solve();

        p.u = mgStep.getSol();

        if (p.energyNorm.diff(p.u,p.u_ex)>tol*10)
        {
            std::cout << "The MultigridStep did not produce a satisfactory result after calling setRhs(). ||u-u_ex||=" << p.energyNorm.diff(p.u,p.u_ex) << std::endl;
            std::cout << "||u_ex||=" << p.energyNorm(p.u_ex) << std::endl;
            passed = false;
        }

        return passed;
    }
};



int main(int argc, char** argv)
{
    Dune::MPIHelper::instance(argc, argv);
    bool passed(true);

    MultigridTestSuite<1> testsuite1;
    MultigridTestSuite<2> testsuite2;
    MultigridTestSuite<3, false> testsuite3f;
    MultigridTestSuite<8> testsuite8;
    passed = checkWithStandardGrids(testsuite1);
    passed = checkWithStandardGrids(testsuite2);
    passed = checkWithStandardGrids(testsuite3f);
    passed = checkWithStandardGrids(testsuite8);
    return passed ? 0 : 1;
}