// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /* This file is part of the Open Porous Media project (OPM). OPM 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 2 of the License, or (at your option) any later version. OPM 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 OPM. If not, see . Consult the COPYING file in the top-level source directory of this module for the precise wording of the license and the list of copyright holders. */ /*! * \file * \copydoc Opm::Linear::WeightedResidualReductionCriterion */ #ifndef EWOMS_WEIGHTED_RESIDUAL_REDUCTION_CRITERION_HH #define EWOMS_WEIGHTED_RESIDUAL_REDUCTION_CRITERION_HH #include "convergencecriterion.hh" #include namespace Opm { namespace Linear { /*! \addtogroup Linear * \{ */ /*! * \brief Convergence criterion which looks at the weighted absolute * value of the residual * * For the WeightedResidualReductionCriterion, the error of the * solution is defined as * \f[ e^k = \max_i\{ \left| w_i r^k_i \right| \}\;, \f] * * where \f$r^k = \mathbf{A} x^k - b \f$ is the residual for the * k-th iterative solution vector \f$x^k\f$ and \f$w_i\f$ is the * weight of the \f$i\f$-th linear equation. * * In addition, to the reduction of the maximum defect, the linear * solver is also considered to be converged, if the defect goes below * a given absolute limit. */ template class WeightedResidualReductionCriterion : public ConvergenceCriterion { using Scalar = typename Vector::field_type; using BlockType = typename Vector::block_type; public: WeightedResidualReductionCriterion(const CollectiveCommunication& comm) : comm_(comm) {} WeightedResidualReductionCriterion(const CollectiveCommunication& comm, const Vector& residWeights, Scalar residualReductionTolerance, Scalar fixPointTolerance, Scalar absResidualTolerance = 0.0, Scalar maxError = 0.0) : comm_(comm), residWeightVec_(residWeights), fixPointTolerance_(fixPointTolerance), residualReductionTolerance_(residualReductionTolerance), absResidualTolerance_(absResidualTolerance), maxError_(maxError) { } /*! * \brief Sets the relative weight of each row of the residual. * * For the WeightedResidualReductionCriterion, the error of the solution is * defined as * \f[ e^k = \max_i\{ \left| w_i r^k_i \right| \}\;, \f] * * where \f$r^k = \mathbf{A} x^k - b \f$ is the residual for the * k-th iterative solution vector \f$x^k\f$ and \f$w_i\f$ is the * weight of the \f$i\f$-th linear equation. * * This method is not part of the generic ConvergenceCriteria interface. * * \param residWeightVec A Dune::BlockVector > * with the relative weights of the linear equations */ void setResidualWeight(const Vector& residWeightVec) { residWeightVec_ = residWeightVec; } /*! * \brief Return the relative weight of a row of the residual. * * \param outerIdx The index of the outer vector (i.e. Dune::BlockVector) * \param innerIdx The index of the inner vector (i.e. Dune::FieldVector) */ Scalar residualWeight(size_t outerIdx, unsigned innerIdx) const { return (residWeightVec_.size() == 0) ? 1.0 : residWeightVec_[outerIdx][innerIdx]; } /*! * \brief Sets the residual reduction tolerance. */ void setResidualReductionTolerance(Scalar tol) { residualReductionTolerance_ = tol; } /*! * \brief Returns the tolerance of the residual reduction of the solution. */ Scalar residualReductionTolerance() const { return residualReductionTolerance_; } /*! * \brief Sets the maximum absolute tolerated residual. */ void setResidualTolerance(Scalar tol) { absResidualTolerance_ = tol; } /*! * \brief Returns the maximum absolute tolerated residual. */ Scalar absResidualTolerance() const { return absResidualTolerance_; } /*! * \brief Returns the reduction of the weighted maximum of the * residual compared to the initial solution. */ Scalar residualAccuracy() const { return residualError_/std::max(1e-20, initialResidualError_); } /*! * \brief Sets the fix-point tolerance. */ void setFixPointTolerance(Scalar tol) { fixPointTolerance_ = tol; } /*! * \brief Returns the maximum tolerated difference between two * iterations to be met before a solution is considered to be * converged. */ Scalar fixPointTolerance() const { return fixPointTolerance_; } /*! * \brief Returns the weighted maximum of the difference * between the last two iterative solutions. */ Scalar fixPointAccuracy() const { return fixPointError_; } /*! * \copydoc ConvergenceCriterion::setInitial(const Vector& , const Vector& ) */ void setInitial(const Vector& curSol, const Vector& curResid) { lastResidualError_ = 1e100; lastSolVec_ = curSol; updateErrors_(curSol, curResid); // the fix-point error is not applicable for the initial solution! fixPointError_ = 1e100; // make sure that we don't allow an initial error of 0 to avoid // divisions by zero residualError_ = std::max(residualError_, 1e-20); initialResidualError_ = residualError_; } /*! * \copydoc ConvergenceCriterion::update(const Vector& , const Vector& ) */ void update(const Vector& curSol, const Vector&, const Vector& curResid) { lastResidualError_ = residualError_; updateErrors_(curSol, curResid); } /*! * \copydoc ConvergenceCriterion::converged() */ bool converged() const { // we're converged if the solution is better than the tolerance // fix-point and residual tolerance. return residualAccuracy() <= residualReductionTolerance() || residualError_ <= absResidualTolerance_; } /*! * \copydoc ConvergenceCriterion::failed() */ bool failed() const { return (!converged() && fixPointError_ <= fixPointTolerance_) || residualError_ > maxError_; } /*! * \copydoc ConvergenceCriterion::accuracy() * * For the accuracy we only take the residual into account, */ Scalar accuracy() const { return residualError_; } /*! * \copydoc ConvergenceCriterion::printInitial() */ void printInitial(std::ostream& os = std::cout) const { os << std::setw(20) << " Iter "; os << std::setw(20) << " Delta "; os << std::setw(20) << " Residual "; os << std::setw(20) << " ResidRed "; os << std::setw(20) << " Rate "; os << std::endl; } /*! * \copydoc ConvergenceCriterion::print() */ void print(Scalar iter, std::ostream& os = std::cout) const { static constexpr Scalar eps = std::numeric_limits::min()*1e10; os << std::setw(20) << iter << " "; os << std::setw(20) << fixPointAccuracy() << " "; os << std::setw(20) << residualError_ << " "; os << std::setw(20) << 1.0/residualAccuracy() << " "; os << std::setw(20) << lastResidualError_ / std::max(residualError_, eps) << " "; os << std::endl << std::flush; } private: // update the weighted absolute residual void updateErrors_(const Vector& curSol, const Vector& curResid) { residualError_ = 0.0; fixPointError_ = 0.0; for (size_t i = 0; i < curResid.size(); ++i) { for (unsigned j = 0; j < BlockType::dimension; ++j) { residualError_ = std::max(residualError_, residualWeight(i, j)*std::abs(curResid[i][j])); fixPointError_ = std::max(fixPointError_, std::abs(curSol[i][j] - lastSolVec_[i][j]) /std::max(1.0, curSol[i][j])); } } lastSolVec_ = curSol; residualError_ = comm_.max(residualError_); fixPointError_ = comm_.max(fixPointError_); } const CollectiveCommunication& comm_; // the weights of the components of the residual Vector residWeightVec_; // solution vector of the last iteration Vector lastSolVec_; // the maximum of the weighted difference between the last two // iterations Scalar fixPointError_; // the maximum allowed relative tolerance for difference of the // solution of two iterations Scalar fixPointTolerance_; // the maximum of the absolute weighted residual of the last // iteration Scalar residualError_; // the maximum of the absolute weighted difference of the last // iteration Scalar lastResidualError_; // the maximum of the absolute weighted residual of the initial // solution Scalar initialResidualError_; // the maximum allowed relative tolerance of the residual for the // solution to be considered converged Scalar residualReductionTolerance_; // the maximum allowed absolute tolerance of the residual for the // solution to be considered converged Scalar absResidualTolerance_; // The maximum error which is tolerated before we fail. Scalar maxError_; }; //! \} end documentation }} // end namespace Linear, Opm #endif