-
Christoph Grüninger authoredChristoph Grüninger authored
complexrhstest.cc 8.51 KiB
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
/**
* \author: Matthias Wohlmuth
* \file
* \brief Test different solvers and preconditioners for
* \f$A*x = b\f$ with \f$A\f$ being a \f$N^2 \times N^2\f$
* Laplacian and \f$b\f$ a complex valued rhs.
*/
#include <config.h>
#include <complex>
#include <dune/istl/bvector.hh>
#include <dune/istl/operators.hh>
#include <dune/istl/solvers.hh>
#include <dune/istl/preconditioners.hh>
#include "laplacian.hh"
#if HAVE_SUPERLU
#include <dune/istl/superlu.hh>
static_assert(SUPERLU_NTYPE == 3,
"If SuperLU is selected for complex rhs test, then SUPERLU_NTYPE must be set to 3 (std::complex<double>)!");
#endif
typedef std::complex<double> FIELD_TYPE;
/**
* \brief Test different solvers and preconditioners for
* \f$A*x = b\f$ with \f$A\f$ being a \f$N^2 \times N^2\f$
* Laplacian and \f$b\f$ a complex valued rhs.
*
* The rhs and reference solutions were computed using the following matlab code:
* \code
N=3;
A = full(gallery('poisson',N)); % create poisson matrix
% find a solution consiting of complex integers
indVec = (0:(N*N-1))',
iVec = complex(0,1).^indVec + indVec,
x0 = iVec .* indVec,
% compute corresponding rhs
b = A * x0,
% solve system using different solvers
xcg = pcg(A,b),
x = A \ b,
xgmres = gmres(A,b)
* \endcode
*/
template<class Operator, class Vector>
class SolverTest
{
public:
SolverTest(Operator & op, Vector & rhs, Vector & x0, double maxError = 1e-10)
: m_op(op),
m_x(rhs),
m_x0(x0),
m_b(rhs),
m_rhs(rhs),
m_maxError(maxError),
m_numTests(0),
m_numFailures(0)
{
std::cout << "SolverTest uses rhs: " << std::endl
<< m_rhs << std::endl
<< "and expects the solultion: " << m_x0 << std::endl << std::endl;
}
template<class Solver>
bool operator() (Solver & solver)
{
m_b = m_rhs;
m_x = 0;
solver.apply(m_x, m_b, m_res);
std::cout << "Defect reduction is " << m_res.reduction << std::endl;
std::cout << "Computed solution is: " << std::endl;
std::cout << m_x << std::endl;
m_b = m_x0;
m_b -= m_x;
const double errorNorm = m_b.two_norm();
std::cout << "Error = " << errorNorm << std::endl;
++m_numTests;
if(errorNorm > m_maxError)
{
std::cout << "SolverTest did not converge!" << std::endl;
++m_numFailures;
return false;
}
return true;
}
int getNumTests() const
{
return m_numTests;
}
int getNumFailures() const
{
return m_numFailures;
}
private:
const Operator & m_op;
Vector m_x, m_x0, m_b;
const Vector m_rhs;
double m_maxError;
int m_numTests, m_numFailures;
Dune::InverseOperatorResult m_res;
};
int main(int argc, char** argv)
{
const int BS = 1;
std::size_t N = 3;
const int maxIter = int(N*N*N*N);
const double reduction = 1e-16;
if (argc > 1)
N = atoi(argv[1]);
std::cout<<"testing for N="<<N<<" BS="<<1<<std::endl;
typedef Dune::FieldMatrix<FIELD_TYPE,BS,BS> MatrixBlock;
typedef Dune::BCRSMatrix<MatrixBlock> BCRSMat;
typedef Dune::FieldVector<FIELD_TYPE,BS> VectorBlock;
typedef Dune::BlockVector<VectorBlock> Vector;
typedef Dune::MatrixAdapter<BCRSMat,Vector,Vector> Operator;
BCRSMat mat;
Operator fop(mat);
Vector b(N*N), b0(N*N), x0(N*N), x(N*N), error(N*N);
setupLaplacian(mat,N);
typedef Vector::Iterator VectorIterator;
FIELD_TYPE count(0);
const FIELD_TYPE I(0.,1.); // complex case
for (VectorIterator it = x0.begin(); it != x0.end(); ++it)
{
*it = (count + std::pow(I,count))*count;
count = count + 1.;
}
std::cout << "x0 = " << x0 << std::endl;
mat.mv(x0,b);
std::cout << "b = " << b << std::endl;
b0 = b;
x = 0;
Dune::Timer watch;
watch.reset();
// create Dummy Preconditioner
typedef Dune::Richardson<Vector,Vector> DummyPreconditioner;
typedef Dune::SeqJac<BCRSMat,Vector,Vector> JacobiPreconditioner;
typedef Dune::SeqGS<BCRSMat,Vector,Vector> GaussSeidelPreconditioner;
typedef Dune::SeqSOR<BCRSMat,Vector,Vector> SORPreconditioner;
typedef Dune::SeqSSOR<BCRSMat,Vector,Vector> SSORPreconditioner;
const double maxError(1e-10);
SolverTest<Operator,Vector> solverTest(fop,b0,x0,maxError);
DummyPreconditioner dummyPrec(1.);
const FIELD_TYPE relaxFactor(1.);
JacobiPreconditioner jacobiPrec1(mat,1,relaxFactor);
JacobiPreconditioner jacobiPrec2(mat,maxIter,relaxFactor);
GaussSeidelPreconditioner gsPrec1(mat,1,relaxFactor);
GaussSeidelPreconditioner gsPrec2(mat,maxIter,relaxFactor);
SORPreconditioner sorPrec1(mat,1,relaxFactor);
SORPreconditioner sorPrec2(mat,maxIter,relaxFactor);
SSORPreconditioner ssorPrec1(mat,1,relaxFactor);
SSORPreconditioner ssorPrec2(mat,maxIter,relaxFactor);
#if HAVE_SUPERLU
Dune::SuperLU<BCRSMat> solverSuperLU(mat, true);
std::cout << "SuperLU converged: "<< solverTest(solverSuperLU) << std::endl << std::endl;
#else
std::cout << "SuperLU skipped because not found." << std::endl << std::endl;
#endif
typedef Dune::GradientSolver<Vector> GradientSolver;
GradientSolver solverGradient(fop,dummyPrec, reduction, maxIter, 1);
std::cout << "GradientSolver with identity preconditioner converged: " << solverTest(solverGradient) << std::endl << std::endl;
typedef Dune::CGSolver<Vector> CG;
CG solverCG(fop,dummyPrec, reduction, maxIter, 1);
std::cout << "CG with identity preconditioner converged: " << solverTest(solverCG) << std::endl << std::endl;
typedef Dune::BiCGSTABSolver<Vector> BiCG;
BiCG solverBiCG(fop,dummyPrec, reduction, maxIter, 1);
std::cout << "BiCGStab with identity preconditioner converged: " << solverTest(solverBiCG) << std::endl << std::endl;
typedef Dune::LoopSolver<Vector> JacobiSolver;
JacobiSolver solverJacobi1(fop,jacobiPrec1,reduction,maxIter,1);
std::cout << "LoopSolver with a single Jacobi iteration as preconditioner converged: " << solverTest(solverJacobi1) << std::endl << std::endl;
typedef Dune::LoopSolver<Vector> JacobiSolver;
JacobiSolver solverJacobi2(fop,jacobiPrec2,reduction,maxIter,1);
std::cout << "LoopSolver with multiple Jacobi iteration as preconditioner converged: " << solverTest(solverJacobi2) << std::endl << std::endl;
typedef Dune::LoopSolver<Vector> GaussSeidelSolver;
GaussSeidelSolver solverGaussSeidel1(fop,gsPrec1,reduction,maxIter,1);
std::cout << "LoopSolver with a single GaussSeidel iteration as preconditioner converged: " << solverTest(solverGaussSeidel1) << std::endl << std::endl;
typedef Dune::LoopSolver<Vector> GaussSeidelSolver;
GaussSeidelSolver solverGaussSeidel2(fop,gsPrec2,reduction,maxIter,1);
std::cout << "LoopSolver with multiple GaussSeidel iterations as preconditioner converged: " << solverTest(solverGaussSeidel2) << std::endl << std::endl;
typedef Dune::LoopSolver<Vector> SORSolver;
SORSolver solverSOR1(fop,sorPrec1,reduction,maxIter,1);
std::cout << "LoopSolver with a single SOR iteration as preconditioner converged: " << solverTest(solverSOR1) << std::endl << std::endl;
typedef Dune::LoopSolver<Vector> SORSolver;
SORSolver solverSOR2(fop,sorPrec2,reduction,maxIter,1);
std::cout << "LoopSolver with multiple SOR iterations as preconditioner converged: " << solverTest(solverSOR2) << std::endl << std::endl;
typedef Dune::LoopSolver<Vector> SSORSolver;
SSORSolver solverSSOR1(fop,ssorPrec1,reduction,maxIter,1);
std::cout << "LoopSolver with a single SSOR iteration as preconditioner converged: " << solverTest(solverSOR2) << std::endl << std::endl;
typedef Dune::LoopSolver<Vector> SSORSolver;
SSORSolver solverSSOR2(fop,ssorPrec2,reduction,maxIter,1);
std::cout << "LoopSolver with multiple SSOR iterations as preconditioner converged: " << solverTest(solverSSOR2) << std::endl << std::endl;
typedef Dune::MINRESSolver<Vector> MINRES;
MINRES solverMINRES(fop,dummyPrec, reduction, maxIter, 1);
std::cout << "MINRES with identity preconditioner converged: " << solverTest(solverMINRES) << std::endl << std::endl;
typedef Dune::RestartedGMResSolver<Vector> GMRES;
GMRES solverGMRES(fop,dummyPrec, reduction, maxIter, maxIter*maxIter, 1);
std::cout << "GMRES with identity preconditioner converged: " << solverTest(solverGMRES) << std::endl << std::endl;
const int testCount = solverTest.getNumTests();
const int errorCount = solverTest.getNumFailures();
std::cout << "Tested " << testCount << " different solvers or preconditioners " << " for a laplacian with complex rhs. " << testCount - errorCount << " out of " << testCount << " solvers converged! " << std::endl << std::endl;
return errorCount;
}