diff --git a/dune/istl/multitypeblockmatrix.hh b/dune/istl/multitypeblockmatrix.hh index 84d267a309396832f253c21d293e2432bbecc43e..7fc8f3d734fb47ee1ab68af47ffe39358fa94979 100644 --- a/dune/istl/multitypeblockmatrix.hh +++ b/dune/istl/multitypeblockmatrix.hh @@ -7,6 +7,8 @@ #include <iostream> #include <tuple> +#include <dune/common/hybridutilities.hh> + #include "istlexception.hh" // forward declaration @@ -31,163 +33,6 @@ namespace Dune { - /** - @brief prints out a matrix (type MultiTypeBlockMatrix) - - The parameters "crow" and "ccol" are the indices of - the element to be printed out. Via recursive calling - all other elements are printed, too. This is internally - called when a MultiTypeBlockMatrix object is passed to an output stream. - */ - - template<int crow, int remain_rows, int ccol, int remain_cols, - typename TMatrix> - class MultiTypeBlockMatrix_Print { - public: - - /** - * print out a matrix block and all following - */ - static void print(const TMatrix& m) { - std::cout << "\t(" << crow << ", " << ccol << "): \n" << std::get<ccol>( std::get<crow>(m)); - MultiTypeBlockMatrix_Print<crow,remain_rows,ccol+1,remain_cols-1,TMatrix>::print(m); //next column - } - }; - template<int crow, int remain_rows, int ccol, typename TMatrix> //specialization for remain_cols=0 - class MultiTypeBlockMatrix_Print<crow,remain_rows,ccol,0,TMatrix> { - public: static void print(const TMatrix& m) { - MultiTypeBlockMatrix_Print<crow+1,remain_rows-1,0,TMatrix::N(),TMatrix>::print(m); //next row - } - }; - - template<int crow, int ccol, int remain_cols, typename TMatrix> //recursion end: specialization for remain_rows=0 - class MultiTypeBlockMatrix_Print<crow,0,ccol,remain_cols,TMatrix> { - public: - static void print(const TMatrix& m) - {std::cout << std::endl;} - }; - - - - //make MultiTypeBlockVector_Ident known (for MultiTypeBlockMatrix_Ident) - template<int count, typename T1, typename T2> - class MultiTypeBlockVector_Ident; - - - /** - @brief Set a MultiTypeBlockMatrix to some specific scalar value - - This class is used by the MultiTypeBlockMatrix class' internal assignment operator. - Whenever a vector is assigned a scalar value, each block element - has to provide operator= for the right side. Example: - \code - typedef MultiTypeBlockVector<int,int,int> CVect; - MultiTypeBlockMatrix<CVect,CVect> CMat; - CMat = 3; //sets all 3x2 integer elements to 3 - \endcode - */ - template<int rowcount, typename T1, typename T2> - class MultiTypeBlockMatrix_Ident { - public: - - /** - * equalize two matrix' element - * note: uses MultiTypeBlockVector_Ident to equalize each row (which is of MultiTypeBlockVector type) - */ - static void equalize(T1& a, const T2& b) { - MultiTypeBlockVector_Ident<T1::M(),T1,T2>::equalize(a,b); //rows are cvectors - MultiTypeBlockMatrix_Ident<rowcount-1,T1,T2>::equalize(a,b); //iterate over rows - } - }; - - //recursion end for rowcount=0 - template<typename T1, typename T2> - class MultiTypeBlockMatrix_Ident<0,T1,T2> { - public: - static void equalize (T1&, const T2&) - {} - }; - - /** - @brief Matrix-vector multiplication - - This class implements matrix vector multiplication for MultiTypeBlockMatrix/MultiTypeBlockVector types - */ - template<int crow, int remain_rows, int ccol, int remain_cols, - typename TVecY, typename TMatrix, typename TVecX> - class MultiTypeBlockMatrix_VectMul { - public: - - /** \brief y += A x - */ - static void umv(TVecY& y, const TMatrix& A, const TVecX& x) { - std::get<ccol>( std::get<crow>(A) ).umv( std::get<ccol>(x), std::get<crow>(y) ); - MultiTypeBlockMatrix_VectMul<crow,remain_rows,ccol+1,remain_cols-1,TVecY,TMatrix,TVecX>::umv(y, A, x); - } - - /** \brief y -= A x - */ - static void mmv(TVecY& y, const TMatrix& A, const TVecX& x) { - std::get<ccol>( std::get<crow>(A) ).mmv( std::get<ccol>(x), std::get<crow>(y) ); - MultiTypeBlockMatrix_VectMul<crow,remain_rows,ccol+1,remain_cols-1,TVecY,TMatrix,TVecX>::mmv(y, A, x); - } - - /** \brief y += alpha A x - * \tparam AlphaType Type used for the scalar factor 'alpha' - */ - template<typename AlphaType> - static void usmv(const AlphaType& alpha, TVecY& y, const TMatrix& A, const TVecX& x) { - std::get<ccol>( std::get<crow>(A) ).usmv(alpha, std::get<ccol>(x), std::get<crow>(y) ); - MultiTypeBlockMatrix_VectMul<crow,remain_rows,ccol+1,remain_cols-1,TVecY,TMatrix,TVecX>::usmv(alpha,y, A, x); - } - - - }; - - //specialization for remain_cols = 0 - template<int crow, int remain_rows,int ccol, typename TVecY, - typename TMatrix, typename TVecX> - class MultiTypeBlockMatrix_VectMul<crow,remain_rows,ccol,0,TVecY,TMatrix,TVecX> { //start iteration over next row - - public: - /** - * do y += A x in next row - */ - static void umv(TVecY& y, const TMatrix& A, const TVecX& x) { - MultiTypeBlockMatrix_VectMul<crow+1,remain_rows-1,0,TMatrix::M(),TVecY,TMatrix,TVecX>::umv(y, A, x); - } - - /** - * do y -= A x in next row - */ - static void mmv(TVecY& y, const TMatrix& A, const TVecX& x) { - MultiTypeBlockMatrix_VectMul<crow+1,remain_rows-1,0,TMatrix::M(),TVecY,TMatrix,TVecX>::mmv(y, A, x); - } - - template <typename AlphaType> - static void usmv(const AlphaType& alpha, TVecY& y, const TMatrix& A, const TVecX& x) { - MultiTypeBlockMatrix_VectMul<crow+1,remain_rows-1,0,TMatrix::M(),TVecY,TMatrix,TVecX>::usmv(alpha,y, A, x); - } - }; - - //specialization for remain_rows = 0 - template<int crow, int ccol, int remain_cols, typename TVecY, - typename TMatrix, typename TVecX> - class MultiTypeBlockMatrix_VectMul<crow,0,ccol,remain_cols,TVecY,TMatrix,TVecX> { - //end recursion - public: - static void umv(TVecY&, const TMatrix&, const TVecX&) {} - static void mmv(TVecY&, const TMatrix&, const TVecX&) {} - - template<typename AlphaType> - static void usmv(const AlphaType&, TVecY&, const TMatrix&, const TVecX&) {} - }; - - - - - - /** @brief A Matrix class to support different block types @@ -259,7 +104,16 @@ namespace Dune { * assignment operator */ template<typename T> - void operator= (const T& newval) {MultiTypeBlockMatrix_Ident<N(),type,T>::equalize(*this, newval); } + void operator= (const T& newval) { + using namespace Dune::Hybrid; + auto size = index_constant<1+sizeof...(Args)>(); + // Since Dune::Hybrid::size(MultiTypeBlockMatrix) is not implemented, + // we cannot use a plain forEach(*this, ...). This could be achieved, + // e.g., by implementing a static size() method. + forEach(integralRange(size), [&](auto&& i) { + (*this)[i] = newval; + }); + } /** \brief y = A x */ @@ -268,7 +122,7 @@ namespace Dune { static_assert(X::size() == M(), "length of x does not match row length"); static_assert(Y::size() == N(), "length of y does not match row count"); y = 0; //reset y (for mv uses umv) - MultiTypeBlockMatrix_VectMul<0,N(),0,M(),Y,type,X>::umv(y, *this, x); //iterate over all matrix elements + umv(x,y); } /** \brief y += A x @@ -277,7 +131,12 @@ namespace Dune { void umv (const X& x, Y& y) const { static_assert(X::size() == M(), "length of x does not match row length"); static_assert(Y::size() == N(), "length of y does not match row count"); - MultiTypeBlockMatrix_VectMul<0,N(),0,M(),Y,type,X>::umv(y, *this, x); //iterate over all matrix elements + using namespace Dune::Hybrid; + forEach(integralRange(Hybrid::size(y)), [&](auto&& i) { + forEach(integralRange(Hybrid::size(x)), [&](auto&& j) { + (*this)[i][j].umv(x[j], y[i]); + }); + }); } /** \brief y -= A x @@ -286,7 +145,12 @@ namespace Dune { void mmv (const X& x, Y& y) const { static_assert(X::size() == M(), "length of x does not match row length"); static_assert(Y::size() == N(), "length of y does not match row count"); - MultiTypeBlockMatrix_VectMul<0,N(),0,M(),Y,type,X>::mmv(y, *this, x); //iterate over all matrix elements + using namespace Dune::Hybrid; + forEach(integralRange(Hybrid::size(y)), [&](auto&& i) { + forEach(integralRange(Hybrid::size(x)), [&](auto&& j) { + (*this)[i][j].mmv(x[j], y[i]); + }); + }); } /** \brief y += alpha A x @@ -295,7 +159,12 @@ namespace Dune { void usmv (const AlphaType& alpha, const X& x, Y& y) const { static_assert(X::size() == M(), "length of x does not match row length"); static_assert(Y::size() == N(), "length of y does not match row count"); - MultiTypeBlockMatrix_VectMul<0,N(),0,M(),Y,type,X>::usmv(alpha,y, *this, x); //iterate over all matrix elements + using namespace Dune::Hybrid; + forEach(integralRange(Hybrid::size(y)), [&](auto&& i) { + forEach(integralRange(Hybrid::size(x)), [&](auto&& j) { + (*this)[i][j].usmv(alpha, x[j], y[i]); + }); + }); } }; @@ -309,9 +178,15 @@ namespace Dune { */ template<typename T1, typename... Args> std::ostream& operator<< (std::ostream& s, const MultiTypeBlockMatrix<T1,Args...>& m) { - static const int N = MultiTypeBlockMatrix<T1,Args...>::N(); - static const int M = MultiTypeBlockMatrix<T1,Args...>::M(); - MultiTypeBlockMatrix_Print<0,N,0,M,MultiTypeBlockMatrix<T1,Args...> >::print(m); + auto N = index_constant<MultiTypeBlockMatrix<T1,Args...>::N()>(); + auto M = index_constant<MultiTypeBlockMatrix<T1,Args...>::M()>(); + using namespace Dune::Hybrid; + forEach(integralRange(N), [&](auto&& i) { + forEach(integralRange(M), [&](auto&& j) { + s << "\t(" << i << ", " << j << "): \n" << m[i][j]; + }); + }); + s << std::endl; return s; } diff --git a/dune/istl/multitypeblockvector.hh b/dune/istl/multitypeblockvector.hh index d718cb3f5cde44f8bcd668c290e541976f8e54ab..0865072ac98b37d9dedf525920637dfc6ee1341f 100644 --- a/dune/istl/multitypeblockvector.hh +++ b/dune/istl/multitypeblockvector.hh @@ -9,6 +9,7 @@ #include <dune/common/dotproduct.hh> #include <dune/common/ftraits.hh> +#include <dune/common/hybridutilities.hh> #include "istlexception.hh" @@ -30,266 +31,6 @@ namespace Dune { - /** - @brief prints out a vector (type MultiTypeBlockVector) - - The parameter "current_element" is the index of - the element to be printed out. Via recursive calling - all other elements (number is "remaining_elements") - are printed, too. This is internally called when - a MultiTypeBlockVector object is passed to an output stream. - Example: - \code - MultiTypeBlockVector<int,int> CVect; - std::cout << CVect; - \endcode - */ - - template<int current_element, int remaining_elements, typename TVec> - class MultiTypeBlockVector_Print { - public: - /** - * print out the current vector element and all following - */ - static void print(const TVec& v) { - std::cout << "\t(" << current_element << "):\n" << std::get<current_element>(v) << "\n"; - MultiTypeBlockVector_Print<current_element+1,remaining_elements-1,TVec>::print(v); //next element - } - }; - template<int current_element, typename TVec> //recursion end (remaining_elements=0) - class MultiTypeBlockVector_Print<current_element,0,TVec> { - public: - static void print(const TVec&) {std::cout << "\n";} - }; - - - - /** - @brief Set a MultiTypeBlockVector to some specific value - - This class is used by the MultiTypeBlockVector class' internal = operator. - Whenever a vector is assigned to a value, each vector element - has to provide the = operator for the right side. Example: - \code - MultiTypeBlockVector<int,int,int> CVect; - CVect = 3; //sets all integer elements to 3 - \endcode - */ - template<int count, typename T1, typename T2> - class MultiTypeBlockVector_Ident { - public: - - /** - * equalize two vectors' element (index is template parameter count) - * note: each MultiTypeBlockVector element has to provide the = operator with type T2 - */ - static void equalize(T1& a, const T2& b) { - std::get<count-1>(a) = b; //equalize current elements - MultiTypeBlockVector_Ident<count-1,T1,T2>::equalize(a,b); //next elements - } - }; - template<typename T1, typename T2> //recursion end (count=0) - class MultiTypeBlockVector_Ident<0,T1,T2> {public: static void equalize (T1&, const T2&) {} }; - - - - - - - /** - @brief Add/subtract second vector to/from the first (v1 += v2) - - This class implements vector addition/subtraction for any MultiTypeBlockVector-Class type. - */ - template<int count, typename T> - class MultiTypeBlockVector_Add { - public: - - /** - * add vector to vector - */ - static void add (T& a, const T& b) { //add vector elements - std::get<(count-1)>(a) += std::get<(count-1)>(b); - MultiTypeBlockVector_Add<count-1,T>::add(a,b); - } - - /** - * Subtract vector from vector - */ - static void sub (T& a, const T& b) { //sub vector elements - std::get<(count-1)>(a) -= std::get<(count-1)>(b); - MultiTypeBlockVector_Add<count-1,T>::sub(a,b); - } - }; - template<typename T> //recursion end; specialization for count=0 - class MultiTypeBlockVector_Add<0,T> {public: static void add (T&, const T&) {} static void sub (T&, const T&) {} }; - - - - /** - @brief AXPY operation on vectors - - calculates x += a * y - */ - template<int count, typename TVec, typename Ta> - class MultiTypeBlockVector_AXPY { - public: - - /** - * calculates x += a * y - */ - static void axpy(TVec& x, const Ta& a, const TVec& y) { - std::get<(count-1)>(x).axpy(a,std::get<(count-1)>(y)); - MultiTypeBlockVector_AXPY<count-1,TVec,Ta>::axpy(x,a,y); - } - }; - template<typename TVec, typename Ta> //specialization for count=0 - class MultiTypeBlockVector_AXPY<0,TVec,Ta> {public: static void axpy (TVec&, const Ta&, const TVec&) {} }; - - - /** @brief In-place multiplication with a scalar - * - * Calculates v *= a for each element of the given vector. - */ - template<int count, typename TVec, typename Ta> - class MultiTypeBlockVector_Mulscal { - public: - - /** - * calculates x *= a - */ - static void mul(TVec& x, const Ta& a) { - std::get<(count-1)>(x) *= a; - MultiTypeBlockVector_Mulscal<count-1,TVec,Ta>::mul(x,a); - } - }; - template<typename TVec, typename Ta> //specialization for count=0 - class MultiTypeBlockVector_Mulscal<0,TVec,Ta> {public: static void mul (TVec&, const Ta&) {} }; - - - - /** @brief Scalar products - * - * multiplies the current elements of x and y pairwise, and sum up the results. - * Provides two variants: - * 1) 'mul' computes the indefinite inner product and - * 2) 'dot' provides an inner product by conjugating the first argument - */ - template<int count, typename TVec> - class MultiTypeBlockVector_Mul { - public: - static typename TVec::field_type mul(const TVec& x, const TVec& y) - { - return (std::get<count-1>(x) * std::get<count-1>(y)) + MultiTypeBlockVector_Mul<count-1,TVec>::mul(x,y); - } - - static typename TVec::field_type dot(const TVec& x, const TVec& y) - { - return Dune::dot(std::get<count-1>(x),std::get<count-1>(y)) + MultiTypeBlockVector_Mul<count-1,TVec>::dot(x,y); - } - }; - - template<typename TVec> - class MultiTypeBlockVector_Mul<0,TVec> { - public: - static typename TVec::field_type mul(const TVec&, const TVec&) {return 0;} - static typename TVec::field_type dot(const TVec&, const TVec&) {return 0;} - }; - - - - - - /** \brief Calculate the 2-norm - - Each element of the vector has to provide the method "two_norm2()" - in order to calculate the whole vector's 2-norm. - */ - template<int count, typename T> - class MultiTypeBlockVector_Norm { - public: - typedef typename T::field_type field_type; - typedef typename FieldTraits<field_type>::real_type real_type; - - /** - * sum up all elements' 2-norms - */ - static real_type result (const T& a) { //result = sum of all elements' 2-norms - return std::get<count-1>(a).two_norm2() + MultiTypeBlockVector_Norm<count-1,T>::result(a); - } - }; - - template<typename T> //recursion end: no more vector elements to add... - class MultiTypeBlockVector_Norm<0,T> { - public: - typedef typename T::field_type field_type; - typedef typename FieldTraits<field_type>::real_type real_type; - static real_type result (const T&) {return 0.0;} - }; - - /** \brief Calculate the \infty-norm - - Each element of the vector has to provide the method "infinity_norm()" - in order to calculate the whole vector's norm. - */ - template<int count, typename T, - bool hasNaN = has_nan<typename T::field_type>::value> - class MultiTypeBlockVector_InfinityNorm { - public: - typedef typename T::field_type field_type; - typedef typename FieldTraits<field_type>::real_type real_type; - - /** - * Take the maximum over all elements' norms - */ - static real_type result (const T& a) - { - std::pair<real_type, real_type> const ret = resultHelper(a); - return ret.first * (ret.second / ret.second); - } - - // Computes the maximum while keeping track of NaN values - static std::pair<real_type, real_type> resultHelper(const T& a) { - using std::max; - auto const rest = - MultiTypeBlockVector_InfinityNorm<count - 1, T>::resultHelper(a); - real_type const norm = std::get<count - 1>(a).infinity_norm(); - return {max(norm, rest.first), norm + rest.second}; - } - }; - - template <int count, typename T> - class MultiTypeBlockVector_InfinityNorm<count, T, false> { - public: - typedef typename T::field_type field_type; - typedef typename FieldTraits<field_type>::real_type real_type; - - /** - * Take the maximum over all elements' norms - */ - static real_type result (const T& a) - { - using std::max; - return max(std::get<count-1>(a).infinity_norm(), MultiTypeBlockVector_InfinityNorm<count-1,T>::result(a)); - } - }; - - template<typename T, bool hasNaN> //recursion end - class MultiTypeBlockVector_InfinityNorm<0,T, hasNaN> { - public: - typedef typename T::field_type field_type; - typedef typename FieldTraits<field_type>::real_type real_type; - static real_type result (const T&) - { - return 0.0; - } - - static std::pair<real_type,real_type> resultHelper (const T&) - { - return {0.0, 1.0}; - } - }; - /** @addtogroup DenseMatVec @{ */ @@ -386,28 +127,83 @@ namespace Dune { /** \brief Assignment operator */ template<typename T> - void operator= (const T& newval) {MultiTypeBlockVector_Ident<sizeof...(Args),type,T>::equalize(*this, newval); } + void operator= (const T& newval) { + Dune::Hybrid::forEach(*this, [&](auto&& entry) { + entry = newval; + }); + } /** * operator for MultiTypeBlockVector += MultiTypeBlockVector operations */ - void operator+= (const type& newv) {MultiTypeBlockVector_Add<sizeof...(Args),type>::add(*this,newv);} + void operator+= (const type& newv) { + using namespace Dune::Hybrid; + forEach(integralRange(Hybrid::size(*this)), [&](auto&& i) { + (*this)[i] += newv[i]; + }); + } /** * operator for MultiTypeBlockVector -= MultiTypeBlockVector operations */ - void operator-= (const type& newv) {MultiTypeBlockVector_Add<sizeof...(Args),type>::sub(*this,newv);} + void operator-= (const type& newv) { + using namespace Dune::Hybrid; + forEach(integralRange(Hybrid::size(*this)), [&](auto&& i) { + (*this)[i] -= newv[i]; + }); + } + + // Once we have the IsNumber traits class the following + // three implementations could be replaced by: + // + // template<class T, + // std::enable_if_t< IsNumber<T>::value, int> = 0> + // void operator*= (const T& w) { + // Dune::Hybrid::forEach(*this, [&](auto&& entry) { + // entry *= w; + // }); + // } + + void operator*= (const int& w) { + Dune::Hybrid::forEach(*this, [&](auto&& entry) { + entry *= w; + }); + } - void operator*= (const int& w) {MultiTypeBlockVector_Mulscal<sizeof...(Args),type,const int>::mul(*this,w);} - void operator*= (const float& w) {MultiTypeBlockVector_Mulscal<sizeof...(Args),type,const float>::mul(*this,w);} - void operator*= (const double& w) {MultiTypeBlockVector_Mulscal<sizeof...(Args),type,const double>::mul(*this,w);} + void operator*= (const float& w) { + Dune::Hybrid::forEach(*this, [&](auto&& entry) { + entry *= w; + }); + } + + void operator*= (const double& w) { + Dune::Hybrid::forEach(*this, [&](auto&& entry) { + entry *= w; + }); + } + + field_type operator* (const type& newv) const { + using namespace Dune::Hybrid; + return accumulate(integralRange(Hybrid::size(*this)), field_type(0), [&](auto&& a, auto&& i) { + return a + (*this)[i]*newv[i]; + }); + } - field_type operator* (const type& newv) const {return MultiTypeBlockVector_Mul<sizeof...(Args),type>::mul(*this,newv);} - field_type dot (const type& newv) const {return MultiTypeBlockVector_Mul<sizeof...(Args),type>::dot(*this,newv);} + field_type dot (const type& newv) const { + using namespace Dune::Hybrid; + return accumulate(integralRange(Hybrid::size(*this)), field_type(0), [&](auto&& a, auto&& i) { + return a + (*this)[i].dot(newv[i]); + }); + } /** \brief Compute the squared Euclidean norm */ - typename FieldTraits<field_type>::real_type two_norm2() const {return MultiTypeBlockVector_Norm<sizeof...(Args),type>::result(*this);} + typename FieldTraits<field_type>::real_type two_norm2() const { + using namespace Dune::Hybrid; + return accumulate(*this, typename FieldTraits<field_type>::real_type(0), [&](auto&& a, auto&& entry) { + return a + entry.two_norm2(); + }); + } /** \brief Compute the Euclidean norm */ @@ -417,7 +213,29 @@ namespace Dune { */ typename FieldTraits<field_type>::real_type infinity_norm() const { - return MultiTypeBlockVector_InfinityNorm<sizeof...(Args),type>::result(*this); + using namespace Dune::Hybrid; + using std::max; + using real_type = typename FieldTraits<field_type>::real_type; + + real_type result = 0.0; + // Compute max norm tracking appearing nan values + // if the field type supports nan. + ifElse(has_nan<field_type>(), [&](auto&& id) { + // This variable will preserve any nan value + real_type nanTracker = 1.0; + forEach(*this, [&](auto&& entry) { + real_type entryNorm = entry.infinity_norm(); + result = max(entryNorm, result); + nanTracker += entryNorm; + }); + // Incorporate possible nan value into result + result *= (nanTracker / nanTracker); + }, [&](auto&& id) { + forEach(*this, [&](auto&& entry) { + result = max(entry.infinity_norm(), result); + }); + }); + return result; } /** \brief Axpy operation on this vector (*this += a * y) @@ -426,7 +244,10 @@ namespace Dune { */ template<typename Ta> void axpy (const Ta& a, const type& y) { - MultiTypeBlockVector_AXPY<sizeof...(Args),type,Ta>::axpy(*this,a,y); + using namespace Dune::Hybrid; + forEach(integralRange(Hybrid::size(*this)), [&](auto&& i) { + (*this)[i].axpy(a, y[i]); + }); } }; @@ -437,7 +258,10 @@ namespace Dune { */ template <typename... Args> std::ostream& operator<< (std::ostream& s, const MultiTypeBlockVector<Args...>& v) { - MultiTypeBlockVector_Print<0,sizeof...(Args),MultiTypeBlockVector<Args...> >::print(v); + using namespace Dune::Hybrid; + forEach(integralRange(size(v)), [&](auto&& i) { + s << "\t(" << i << "):\n" << v[i] << "\n"; + }); return s; } diff --git a/dune/istl/test/multitypeblockmatrixtest.cc b/dune/istl/test/multitypeblockmatrixtest.cc index b1d296182365d1f369b9ac03b49e0ea1c714302c..359393d46507b2d7eb73fba8a8a5534ff3e24cd8 100644 --- a/dune/istl/test/multitypeblockmatrixtest.cc +++ b/dune/istl/test/multitypeblockmatrixtest.cc @@ -71,10 +71,22 @@ int main(int argc, char** argv) try result[_0].resize(3); result[_1].resize(2); + multiMatrix[_0][_0] = 4200; + multiMatrix[_0][_1] = 4201; + multiMatrix[_1][_0] = 4210; + multiMatrix[_1][_1] = 4211; + multiMatrix.mv(multiVector,result); + std::cout << "mv result" << std::endl << result << std::endl; + multiMatrix.umv(multiVector,result); + std::cout << "umv result" << std::endl << result << std::endl; + multiMatrix.mmv(multiVector,result); + std::cout << "mmv result" << std::endl << result << std::endl; + multiMatrix.usmv(3.14,multiVector,result); + std::cout << "usmv result" << std::endl << result << std::endl; /////////////////////////////////////////////////////////////////////////////////////////////////////////// // Next test: Set up a linear system with a matrix consisting of 2x2 sparse scalar matrices.