diff --git a/dune/matrix-vector/test/CMakeLists.txt b/dune/matrix-vector/test/CMakeLists.txt index ff2014510d0732066fea5e2d69018bd6e0eab2e1..7519ef82e11269b0f5bbaf657cd61d772bf9f239 100644 --- a/dune/matrix-vector/test/CMakeLists.txt +++ b/dune/matrix-vector/test/CMakeLists.txt @@ -1,3 +1,4 @@ dune_add_test(SOURCES arithmetictest.cc) +dune_add_test(SOURCES genericvectortoolstest.cc) dune_add_test(SOURCES staticmatrixtoolstest.cc) dune_add_test(SOURCES triangularsolvetest.cc) diff --git a/dune/matrix-vector/test/genericvectortoolstest.cc b/dune/matrix-vector/test/genericvectortoolstest.cc new file mode 100644 index 0000000000000000000000000000000000000000..1b0354e7a9679d3d32b3766dfb50fdee4e6b6c62 --- /dev/null +++ b/dune/matrix-vector/test/genericvectortoolstest.cc @@ -0,0 +1,246 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <dune/common/exceptions.hh> +#include <dune/common/fvector.hh> +#include <dune/common/fmatrix.hh> +#include <dune/common/parallel/mpihelper.hh> +#include <dune/common/typeutilities.hh> + +#include <dune/istl/bcrsmatrix.hh> +#include <dune/istl/bvector.hh> +#include <dune/istl/matrixindexset.hh> +#include <dune/istl/multitypeblockmatrix.hh> +#include <dune/istl/multitypeblockvector.hh> + +#include <dune/matrix-vector/algorithm.hh> +#include <dune/matrix-vector/genericvectortools.hh> + + +/// custom multitype types to allow for BlockVector nesting +template <class... Args> +struct CustomMultiTypeBlockVector : public Dune::MultiTypeBlockVector<Args...> { + constexpr static int blocklevel = 1; // fake value +}; +template <class... Args> +struct CustomMultiTypeBlockMatrix : public Dune::MultiTypeBlockMatrix<Args...> { + constexpr static int blocklevel = 1; // fake value +}; +// inject matrix traits for CustomMultiTypeBlockMatrix +namespace Dune { namespace MatrixVector { + template <class... Args> + struct MatrixTraits<CustomMultiTypeBlockMatrix<Args...>> { + enum { isMatrix = true }; + }; +}} + + +class ResizeTestSuite { + /// typedefs + using BS = std::bitset<2>; + using FV = Dune::FieldVector<double, 3>; + using BV = Dune::BlockVector<FV>; + using MV = CustomMultiTypeBlockVector<BV, BV, FV>; + using FM = Dune::FieldMatrix<double, 3, 10>; + using BM = Dune::BCRSMatrix<FM>; + using MM = CustomMultiTypeBlockMatrix< + CustomMultiTypeBlockMatrix<BM>, + CustomMultiTypeBlockMatrix<BM>, + CustomMultiTypeBlockMatrix<FM>>; + /// instanciation helper + auto createBM(size_t n) { + BM bm; + Dune::MatrixIndexSet indices(n, n+10); + indices.exportIdx(bm); + return bm; + } + auto createMM(size_t n1, size_t n2) { + using namespace Dune::Indices; + MM mm; + mm[_0][_0] = createBM(n1); + mm[_1][_0] = createBM(n2); + return mm; + } + + bool checkGetSize() { + using namespace Dune::MatrixVector::Generic::Impl; + std::cout << "Testing getSize... "; + + auto hasSize = [](auto&& c, auto&& size) { + if(getSize(c, Dune::PriorityTag<42>()) != size) + DUNE_THROW(Dune::Exception, "Unexpected getSize mismatch."); + }; + + try { + // test vector types + using BS = std::bitset<2>; + hasSize(BS(), (uint) 2); + using FV = Dune::FieldVector<double, 3>; + hasSize(FV(), (uint) 3); + using BV = Dune::BlockVector<FV>; + hasSize(BV(4), (uint) 4); + using MV = CustomMultiTypeBlockVector<FV, BV, FV, FV, BV>; + hasSize(MV(), (uint) 5); + // test matrix types + using FM = Dune::FieldMatrix<double, 3, 10>; + hasSize(FM(), (uint) 3); + using BM = Dune::BCRSMatrix<FM>; + BM bm; + Dune::MatrixIndexSet indices(4, 10); + indices.exportIdx(bm); + hasSize(bm, (uint) 4); + using MM = CustomMultiTypeBlockMatrix<BM, BM, BM, FM, FM>; + hasSize(MM(), (uint) 5); + } catch (Dune::Exception e) { + std::cout << "FAILURE." << std::endl; + std::cout << e << std::endl; + return false; + } + + std::cout << "done." << std::endl; + return true; +} + + //! yield test access to protected ScalarSwitch method subSizeProvider + template <class Vector> + struct SubSizeProviderAccess : Dune::MatrixVector::Generic::Impl::ScalarSwitch<Vector> { + using Base = Dune::MatrixVector::Generic::Impl::ScalarSwitch<Vector>; + template <class T> + static decltype(auto) test(T&& t) { + return Base::subSizeProvider(std::forward<T>(t)); + } + }; + +bool checkSubSizeProvider() { + using namespace Dune::MatrixVector; + std::cout << "Testing subSizeProvider... "; + + // check if the sizeProvider yields the same result as given in t + auto pointsToSame = [](auto& o1, auto& o2) { + if (&o1 != &o2) + DUNE_THROW(Dune::Exception, "Unexpected subSizeProvider."); + }; + + // check if the sizeProvider yields the correct result for given vector type + auto testVectorRange = [&](const auto& v) { + sparseRangeFor(v, [&](auto&& vi, auto) { + pointsToSame(vi, SubSizeProviderAccess<std::decay_t<decltype(v)>>::test(vi)); + }); + }; + + // check if the sizeProvider yields the correct result for given matrix type + auto testMatrixRange = [&](const auto& m) { + sparseRangeFor(m, [&](auto&& mi, auto) { + sparseRangeFirst(mi, [&](auto&& mii) { + pointsToSame(mii, SubSizeProviderAccess<std::decay_t<decltype(m)>>::test(mi)); + }); + }); + }; + + try { + // test vector types + testVectorRange(FV()); + testVectorRange(BV(4)); + testVectorRange(MV()); + // test matrix types + testMatrixRange(FM()); + testMatrixRange(createBM(4)); + testMatrixRange(createMM(6,0)); + + } catch (Dune::Exception e) { + std::cout << "FAILURE." << std::endl; + std::cout << e << std::endl; + return false; + } + + std::cout << "done." << std::endl; + return true; +} + +bool checkResize() { + using namespace Dune::MatrixVector::Generic; + std::cout << "Testing resize... "; + + // test failure for invalid static resize + try { + resize(FV(), Dune::FieldVector<int, 5>()); + return false; + } catch (Dune::Exception) { + // TODO make sure the right exception is thrown + } + + auto hasSize = [](auto&& size, auto&& expectedSize) { + if(size != expectedSize) + DUNE_THROW(Dune::Exception, "Resize created unexpected size."); + }; + + try { + // test vector types + BS bs, bs2; + resize(bs, bs2); + FV fv, fv2; + resize(fv, fv2); + BV bv, bv2(5); + resize(bv, bv2); + hasSize(bv.size(), (uint) 5); + MV mv, mv2; + using namespace Dune::Indices; + mv2[_0].resize(5); + resize(mv, mv2); + hasSize(mv[_0].size(), (uint) 5); + hasSize(mv[_1].size(), (uint) 0); + hasSize(mv[_2].size(), (uint) 3); + // test "natural" matrix types + FM fm; + resize(fv, fm); + BM bm = createBM(4); + resize(bv, bm); + hasSize(bv.size(), (uint) 4); + MM mm = createMM(0, 6); + resize(mv, mm); + hasSize(mv[_0].size(), (uint) 0); + hasSize(mv[_1].size(), (uint) 6); + hasSize(mv[_2].size(), (uint) 3); + // test "unnatural" matrix types + // TODO + + } catch (Dune::Exception e) { + std::cout << "FAILURE." << std::endl; + std::cout << e << std::endl; + return false; + } + + std::cout << "done." << std::endl; + return true; +} + +public: + +bool check() { + std::cout << "Resize test starting.." << std::endl; + bool passed = true; + + passed = passed and checkGetSize(); + passed = passed and checkSubSizeProvider(); + passed = passed and checkResize(); + // TODO test ignore nodes type + + if(passed) + std::cout << "Resize test succeeded.\n" << std::endl; + return passed; +} + +}; + +int main(int argc, char* argv[]) { + Dune::MPIHelper::instance(argc, argv); + + bool passed = ResizeTestSuite().check(); + + + if(not passed) + return 1; + + return 0; +}