diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ebe450ad46632a25bf64de707f75679c9ffbb5c..6943ee9948b886c70588ea5c051ebf4dfa5b854d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ - CholmodSolver: Added `errorCode_` member to report errors and warnings during the matrix decomposition +- CholmodSolver: `CholmodSolver` can be used with any blocked matrix/vector type supported by `flatMatrixForEach` and `flatVectorForEach` in dune-istl. + ## Deprecations and removals - The file `blockgsstep.hh` has been removed after four years of deprecation. Use the replacement diff --git a/dune/solvers/solvers/cholmodsolver.hh b/dune/solvers/solvers/cholmodsolver.hh index 7cbe2fb8d043b8b5192b98a304c055267a80faa5..553f528dc687f8d20d824faa1160c91c0de07e6e 100644 --- a/dune/solvers/solvers/cholmodsolver.hh +++ b/dune/solvers/solvers/cholmodsolver.hh @@ -13,11 +13,13 @@ #include <dune/istl/solver.hh> #include <dune/istl/cholmod.hh> +#include <dune/istl/foreach.hh> #include <dune/istl/matrixindexset.hh> #include <dune/istl/io.hh> #include <dune/solvers/common/canignore.hh> #include <dune/solvers/solvers/linearsolver.hh> +#include <dune/solvers/common/defaultbitvector.hh> namespace Dune { @@ -33,17 +35,12 @@ namespace Solvers * This class wraps the dune-istl CHOLMOD solver for dune-solvers to provide * a Solvers::LinearSolver interface. */ -template <class MatrixType, class VectorType> +template <class MatrixType, class VectorType, class BitVectorType = DefaultBitVector_t<VectorType>> class CholmodSolver -: public LinearSolver<MatrixType,VectorType>, public CanIgnore<Dune::BitSetVector<VectorType::block_type::dimension> > +: public LinearSolver<MatrixType,VectorType>, public CanIgnore<BitVectorType> { - enum {blocksize = VectorType::block_type::dimension}; - using field_type = typename VectorType::field_type; - using MatrixBlock = Dune::FieldMatrix<field_type, blocksize, blocksize> ; - using VectorBlock = Dune::FieldVector<field_type, blocksize>; - public: /** \brief Default constructor */ @@ -110,46 +107,45 @@ public: // get the error code from Cholmod in case something happened errorCode_ = solver.cholmodCommonObject().status; - auto modifiedRhs = *rhs_; + // create flat vectors + using T = typename VectorType::field_type; + std::size_t flatSize = flatVectorForEach(ignore, [](...){}); + std::vector<bool> flatIgnore(flatSize); + std::vector<T> flatX(flatSize), flatRhsModifier(flatSize); - // pull all ignored columns to the rhs - for(auto rowIt = matrix_->begin(); rowIt != matrix_->end(); rowIt++) + // define a lambda that copies the entries of a blocked vector into a flat one + auto copyToFlat = [&](auto&& blocked, auto&& flat) { - const auto row = rowIt.index(); - - for(auto ii=0; ii<blocksize; ii++) + flatVectorForEach(blocked, [&](auto&& entry, auto&& offset) { - if( ignore[row][ii] ) - continue; - - for(auto colIt = rowIt->begin(); colIt != rowIt->end(); colIt++) - { - const auto col = colIt.index(); - for(auto jj=0; jj<blocksize; jj++) - { - if( ignore[col][jj] ) - { - // we assume values only in the upper part - if ( row < col ) - { - // upper part -> use canonical indices - modifiedRhs[row][ii] -= (*matrix_)[row][col][ii][jj] * (*x_)[col][jj]; - } - else if (row == col and ii > jj ) - { - // diagonal block but there in the lower part -> swap ii <-> jj - modifiedRhs[row][ii] -= (*matrix_)[row][col][jj][ii] * (*x_)[col][jj]; - } - else - { - // lower part -> swap col <-> row and ii <-> jj - modifiedRhs[row][ii] -= (*matrix_)[col][row][jj][ii] * (*x_)[col][jj]; - } - } - } - } - } - } + flat[offset] = entry; + }); + }; + + // copy x and the ignore field for the modification of the rhs + copyToFlat(ignore,flatIgnore); + copyToFlat(*x_,flatX); + + flatMatrixForEach( *matrix_, [&]( auto&& entry, auto&& rowOffset, auto&& colOffset){ + + // we assume entries only in the upper part and do nothing on the diagonal + if ( rowOffset >= colOffset ) + return; + + // upper part: if either col or row is ignored: move the entry or the symmetric duplicate to the rhs + if ( flatIgnore[colOffset] and not flatIgnore[rowOffset] ) + flatRhsModifier[rowOffset] += entry * flatX[colOffset]; + + else if ( not flatIgnore[colOffset] and flatIgnore[rowOffset] ) + flatRhsModifier[colOffset] += entry * flatX[rowOffset]; + }); + + // update the rhs + auto modifiedRhs = *rhs_; + flatVectorForEach(modifiedRhs, [&](auto&& entry, auto&& offset){ + if ( not flatIgnore[offset] ) + entry -= flatRhsModifier[offset]; + }); // Solve the modified system solver.apply(*x_, modifiedRhs, statistics);