diff --git a/dumux/linear/symmetrize_constraints.hh b/dumux/linear/symmetrize_constraints.hh new file mode 100644 index 0000000000000000000000000000000000000000..d2bfd42325609c96453cd4f979a588e5257c5790 --- /dev/null +++ b/dumux/linear/symmetrize_constraints.hh @@ -0,0 +1,154 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \ingroup Linear + * \brief Helper function to symmetrize row-constraints in constrained linear systems + */ +#ifndef DUMUX_LINEAR_SYMMETRIZE_CONSTRAINTS_HH +#define DUMUX_LINEAR_SYMMETRIZE_CONSTRAINTS_HH + +#include <iostream> + +#include <dune/common/hybridutilities.hh> +#include <dune/common/fmatrix.hh> +#include <dune/istl/bcrsmatrix.hh> +#include <dune/istl/multitypeblockmatrix.hh> + +namespace Dumux::Detail { + +// loop over dense matrix block: end of recursion (actually do some work) +template<class K, int rows, int cols, class VectorRow, class VectorCol> +void symmetrizeConstraintsImpl(Dune::FieldMatrix<K, rows, cols>& A, + VectorRow& bRow, const VectorCol& bCol, + const VectorCol& constrainedRows, + bool isDiagonal) +{ + for (int j = 0; j < A.M(); ++j) + { + // all rows in this column can be eliminated by a Dirichlet row + const auto& constrainedRowsJ = constrainedRows[j]; + if (constrainedRowsJ > 0.5) + { + for (int i = 0; i < A.N(); ++i) + { + auto& Aij = A[i][j]; + auto& bi = bRow[i]; + const auto& bj = bCol[j]; + if (!((i == j) && isDiagonal)) + { + bi -= Aij*bj; + Aij = 0.0; + } + } + } + } +} + +// recursively loop over sub-blocks +template<class MBlock, class VectorRow, class VectorCol> +void symmetrizeConstraintsImpl(Dune::BCRSMatrix<MBlock>& A, + VectorRow& bRow, const VectorCol& bCol, + const VectorCol& constrainedRows, + bool isDiagonal) +{ + const auto rowEnd = A.end(); + for (auto row = A.begin(); row != rowEnd; ++row) + { + const auto colEnd = row->end(); + for (auto col = row->begin(); col != colEnd; ++col) + { + const auto i = row.index(); + const auto j = col.index(); + + auto& Aij = A[i][j]; + auto& bi = bRow[i]; + const auto& bj = bCol[j]; + const auto& dj = constrainedRows[j]; + + symmetrizeConstraintsImpl(Aij, bi, bj, dj, ((i == j) && isDiagonal)); + } + } +} + +// recursively loop over sub-blocks +template<class... MBlock, class VectorRow, class VectorCol> +void symmetrizeConstraintsImpl(Dune::MultiTypeBlockMatrix<MBlock...>& A, + VectorRow& bRow, const VectorCol& bCol, + const VectorCol& constrainedRows, + bool isDiagonal) +{ + using namespace Dune::Hybrid; + forEach(std::make_index_sequence<Dune::MultiTypeBlockMatrix<MBlock...>::N()>{}, [&](const auto i) + { + forEach(std::make_index_sequence<Dune::MultiTypeBlockMatrix<MBlock...>::M()>{}, [&](const auto j) + { + auto& Aij = A[i][j]; + auto& bi = bRow[i]; + const auto& bj = bCol[j]; + const auto& dj = constrainedRows[j]; + + symmetrizeConstraintsImpl(Aij, bi, bj, dj, ((i == j) && isDiagonal)); + }); + }); +} + +} // end namespace Dumux::Detail + +namespace Dumux { + +/*! + * \ingroup Linear + * \brief Symmetrize the constrained system Ax=b + * \note The function addresses the case where some rows in the linear system have been replaced + * to fix a degree of freedom to a fixed value. A typical use case is strongly enforced Dirichlet constraints. + * To symmetrize the constraints in operator A, this function eliminates the corresponding column entries by + * bringing them to the right-hand side. Particularly, if matrix operator A was symmetric before incorporating + * constraints, calling this function restores the symmetry of operator A. + * \note the constrainedRows vector is the same shape and type as b and contains 1 for each row + * that corresponds to constraints (e.g. strongly enforced Dirichlet dofs) and 0 elsewhere + * \note this is a specialization for Dune::BCRSMatrix + */ +template<class MBlock, class Vector> +void symmetrizeConstraints(Dune::BCRSMatrix<MBlock>& A, Vector& b, const Vector& constrainedRows) +{ + Detail::symmetrizeConstraintsImpl(A, b, b, constrainedRows, true); +} + +/*! + * \ingroup Linear + * \brief Symmetrize the constrained system Ax=b + * \note The function addresses the case where some rows in the linear system have been replaced + * to fix a degree of freedom to a fixed value. A typical use case is strongly enforced Dirichlet constraints. + * To symmetrize the constraints in operator A, this function eliminates the corresponding column entries by + * bringing them to the right-hand side. Particularly, if matrix operator A was symmetric before incorporating + * constraints, calling this function restores the symmetry of operator A. + * \note the constrainedRows vector is the same shape and type as b and contains 1 for each row + * that corresponds to constraints (e.g. strongly enforced Dirichlet dofs) and 0 elsewhere + * \note this is a specialization for Dune::MultiTypeBlockMatrix + */ +template<class... MBlock, class Vector> +void symmetrizeConstraints(Dune::MultiTypeBlockMatrix<MBlock...>& A, Vector& b, const Vector& constrainedRows) +{ + Detail::symmetrizeConstraintsImpl(A, b, b, constrainedRows, true); +} + +} // end namespace Dumux + +#endif