From 611784cbf79629c45aa7c5fc02ce2e31b7cb2339 Mon Sep 17 00:00:00 2001 From: Max Kahnt <max.kahnt@fu-berlin.de> Date: Sat, 23 Sep 2017 09:20:50 +0200 Subject: [PATCH] Add test for energyNorm. --- dune/solvers/test/CMakeLists.txt | 1 + dune/solvers/test/energynormtest.cc | 276 ++++++++++++++++++++++++++++ 2 files changed, 277 insertions(+) create mode 100644 dune/solvers/test/energynormtest.cc diff --git a/dune/solvers/test/CMakeLists.txt b/dune/solvers/test/CMakeLists.txt index 22af4820..1c7553ed 100644 --- a/dune/solvers/test/CMakeLists.txt +++ b/dune/solvers/test/CMakeLists.txt @@ -1,5 +1,6 @@ dune_add_test(SOURCES cgsteptest.cc) dune_add_test(SOURCES gssteptest.cc) +dune_add_test(SOURCES energynormtest.cc) dune_add_test(SOURCES mmgtest.cc) dune_add_test(SOURCES multigridtest.cc) dune_add_test(SOURCES projectedgradienttest.cc) diff --git a/dune/solvers/test/energynormtest.cc b/dune/solvers/test/energynormtest.cc new file mode 100644 index 00000000..f56eaf35 --- /dev/null +++ b/dune/solvers/test/energynormtest.cc @@ -0,0 +1,276 @@ +#include <config.h> + +#include <cmath> +#include <iostream> + +#include <dune/common/exceptions.hh> +#include <dune/common/fvector.hh> +#include <dune/common/fmatrix.hh> +#include <dune/common/hybridutilities.hh> +#include <dune/common/typetraits.hh> + +#include <dune/istl/bcrsmatrix.hh> +#include <dune/istl/bvector.hh> +#include <dune/istl/matrixindexset.hh> +#include <dune/istl/multitypeblockvector.hh> +#include <dune/istl/multitypeblockmatrix.hh> + +#include <dune/solvers/common/defaultbitvector.hh> +#include <dune/solvers/norms/energynorm.hh> + +template <class M, class V, class BV> +struct FakeLinearIterationStep : public LinearIterationStep<M, V, BV> { + using Base = LinearIterationStep<M, V, BV>; + using Base::Base; + void iterate() override { + DUNE_THROW(Dune::Exception, "This FakeLinearIterationStep must not be iterated."); + } +}; + +//! \brief tests with given matrix and vector +template<class M, class V, class Field> +bool testWith(const M& m, const V& v, Field normValue, const char* s) { + using namespace Dune; + using Norm = EnergyNorm<M, V>; + + std::cout << "Test with " << s << "..." << std::endl; + + // test unset matrix exception + std::cout << "Testing unset matrix exception.. "; + try { + Norm norm; + norm(v); + std::cout << "FAILURE." << std::endl; + std::cout << "...FAILED." << std::endl; + return false; + } catch (...) { + // TODO assert that the matrix exception is helpful + std::cout << " done." << std::endl; + } + + + // evaluation test lambda + auto evaluate = [&v, &normValue](auto&& norm) { + if(std::fabs(norm(v)-normValue) > 1e-10) { + std::cout << norm(v) << " vs " << normValue << std::endl; + DUNE_THROW(Exception, "Energy norm evaluation failed."); + } + }; + + try { + std::cout << "Testing matrix usage.. "; + // test on-construction matrix usage + { + Norm norm(m); + evaluate(norm); + } + // test setter matrix usage + { + Norm norm; + norm.setMatrix(&m); + evaluate(norm); + } + std::cout << "done." << std::endl; + + std::cout << "Testing step usage.. "; + // test on-construction default step usage + using DefaultBV = Solvers::DefaultBitVector_t<V>; + auto defaultStep = FakeLinearIterationStep<M, V, DefaultBV>(); + defaultStep.setMatrix(m); + { + Norm norm(defaultStep); + evaluate(norm); + } + // test setter default step usage + { + Norm norm; + norm.setIterationStep(&defaultStep); + evaluate(norm); + } + // test on-construction custom step usage + using CustomBV = double; + auto customStep = FakeLinearIterationStep<M, V, CustomBV>(); + customStep.setMatrix(m); + { + Norm norm(customStep); + evaluate(norm); + } + // test setter custom step usage + { + Norm norm; + norm.setIterationStep(&customStep); + evaluate(norm); + } + std::cout << "done." << std::endl; + + std::cout << "Testing reset usage.. "; + // test resetting matrix + { + M wrongM = m; + wrongM *= 2; + Norm norm(wrongM); + norm.setMatrix(&m); + evaluate(norm); + } + // test resetting step (with different (ignore node) type even) + { + auto wrongStep = customStep; + M wrongM = m; + wrongM *= 2; + wrongStep.setMatrix(wrongM); + Norm norm(wrongStep); + norm.setIterationStep(&defaultStep); + evaluate(norm); + } + std::cout << "done." << std::endl; + + } catch(...) { + std::cout << "FAILURE." << std::endl; + std::cout << "...FAILED." << std::endl; + throw; + } + + std::cout << "...done.\n" << std::endl; +} + +template<class... Args> +struct NestableMultiTypeBlockVector : public Dune::MultiTypeBlockVector<Args...> { + constexpr static size_t blocklevel = 1; // fake value need for BlockVector nesting + template<class K, typename = std::enable_if_t<Dune::IsNumber<K>::value>> + void operator=(K v) { Dune::Hybrid::forEach(*this, [v](auto& m) { m = v; }); } // allow init by scalar +}; + +template<class... Args> +struct NestableMultiTypeBlockMatrix : public Dune::MultiTypeBlockMatrix<Args...> { + constexpr static size_t blocklevel = 1; // fake value needed for BCRSMatrix nesting +}; + +// inject field traits for custom multi type block vector to be used by the norms +namespace Dune { +template<class T, class... TT> +struct FieldTraits<NestableMultiTypeBlockVector<T, TT...>> { + using field_type = typename FieldTraits<T>::field_type; + using real_type = typename FieldTraits<T>::real_type; +}; +} + +// inject fake(!) default bit vector for custom multi type block vector +namespace Dune { namespace Solvers { namespace Imp { +template<class T, class... TT> +struct DefaultBitVector<NestableMultiTypeBlockVector<T, TT...>> { + using type = T; +}; +}}} + + +//! \brief create and fill diagonal of sparse matrix with blocks +template<class Block> +void fillDiagonal(Dune::BCRSMatrix<Block>& m, const Block& b, size_t size) { + Dune::MatrixIndexSet indices(size, size); + for(size_t i=0; i<size; ++i) + indices.add(i, i); + indices.exportIdx(m); + for(size_t i=0; i<size; ++i) + m[i][i] = b; +} + +//! \brief fill diagonal of static multi type matrix with block +template<class M, class Block> +void fillDiagonalStatic(M& m, const Block& b) { + using namespace Dune::Hybrid; + forEach(m, [&](auto& row) { + forEach(row, [&](auto& col) { + col = b; + }); + }); + using namespace Dune::Indices; + m[_0][_1] = 0.0; + m[_1][_0] = 0.0; +} + + +int main() try +{ + bool passed = true; + + using namespace Dune; + using Field = double; + + /// test with simple vectors + // types + constexpr size_t fSize = 2; + using FVector = FieldVector<Field, fSize>; + using FMatrix = FieldMatrix<Field, fSize, fSize>; + // instance setup + FMatrix fMatrix = {{1.0, 0.0}, {0.0, 1.0}}; + FVector fVector = {3.0, 4.0}; + // test + passed = passed && testWith(fMatrix, fVector, 5.0, "simple vectors"); + + /// test with blocked vectors + // types + constexpr size_t bSize = 4; + using BVector = BlockVector<FVector>; + using BMatrix = BCRSMatrix<FMatrix>; + // instance setup + BMatrix bMatrix; + fillDiagonal(bMatrix, fMatrix, bSize); + BVector bVector(bSize); + for(auto& b : bVector) + b = fVector; + // test + passed = passed && testWith(bMatrix, bVector, std::sqrt(bSize)*5.0, "blocked vectors"); + + /// test with multi blocked vectors + // types + using MVector = MultiTypeBlockVector<BVector, BVector>; + using MMatrix0 = MultiTypeBlockMatrix<BMatrix, BMatrix>; + using MMatrix1 = MultiTypeBlockMatrix<BMatrix, BMatrix>; + using MMatrix = MultiTypeBlockMatrix<MMatrix0, MMatrix1>; + // instance setup + using namespace Dune::Hybrid; + MVector mVector; + forEach(mVector, [&](auto& m) { m = bVector; }); + MMatrix mMatrix; + fillDiagonalStatic(mMatrix, bMatrix); + // test + passed = passed && testWith(mMatrix, mVector, sqrt(2)*sqrt(bSize)*5.0, "multi blocked vectors"); + + /// test with blocked multitype vectors + // types + using NVector = NestableMultiTypeBlockVector<FVector, FVector>; + using NMatrix0 = NestableMultiTypeBlockMatrix<FMatrix, FMatrix>; + using NMatrix1 = NestableMultiTypeBlockMatrix<FMatrix, FMatrix>; + using NMatrix = NestableMultiTypeBlockMatrix<NMatrix0, NMatrix1>; + constexpr size_t bnSize = 4; + using BNVector = BlockVector<NVector>; + using BNMatrix = BCRSMatrix<NMatrix>; + // instance setup + NVector nVector; + forEach(nVector, [&](auto& n) { n = fVector; }); + BNVector bnVector(bnSize); + NMatrix nMatrix; + fillDiagonalStatic(nMatrix, fMatrix); + BNMatrix bnMatrix; + fillDiagonal(bnMatrix, nMatrix, bnSize); + +// TODO DEBUG +using namespace Dune::Indices; + std::cout << "Entry 0" << bnMatrix[0][0][_0][_0][0][0] << std::endl; + std::cout << "Entry 0" << bnMatrix[0][0][_1][_1][0][0] << std::endl; + // test + passed = passed && testWith(bnMatrix, bnVector, sqrt(bnSize)*sqrt(2)*5.0, "blocked multitype vectors"); + + if(not passed) + return 1; + + return 0; +} catch(Dune::Exception e) { + std::cout << e << std::endl; + return 1; +} catch(...) { + std::cout << "Unknown exception thrown." << std::endl; + return 1; +} + + -- GitLab