// -*- 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::CombinedCriterion */ #ifndef EWOMS_COMBINED_CRITERION_HH #define EWOMS_COMBINED_CRITERION_HH #include "convergencecriterion.hh" #include namespace Opm { namespace Linear { /*! \addtogroup Linear * \{ */ /*! * \brief Convergence criterion which looks at the absolute value of the residual and * fails if the linear solver stagnates. * * For the CombinedCriterion, the error of the solution is defined as \f[ e^k = \max_i\{ * \left| 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$. * * In addition, to the reduction of the maximum residual, the linear solver is aborted * early if the residual goes below or above absolute limits. */ template class CombinedCriterion : public ConvergenceCriterion { using Scalar = typename Vector::field_type; using BlockType = typename Vector::block_type; public: CombinedCriterion(const CollectiveCommunication& comm) : comm_(comm) {} CombinedCriterion(const CollectiveCommunication& comm, Scalar residualReductionTolerance, Scalar absResidualTolerance = 0.0, Scalar maxResidual = 0.0) : comm_(comm), residualReductionTolerance_(residualReductionTolerance), absResidualTolerance_(absResidualTolerance), maxResidual_(maxResidual) { } /*! * \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 Returns the reduction of the maximum of the residual compared to the * initial solution. */ Scalar residualReduction() const { return residualError_/std::max(1e-20, initialResidualError_); } /*! * \brief Sets the maximum absolute tolerated residual. */ void setAbsResidualTolerance(Scalar tol) { absResidualTolerance_ = tol; } /*! * \brief Returns the tolerated maximum of the the infinity norm of the absolute * residual. */ Scalar absResidualTolerance() const { return absResidualTolerance_; } /*! * \brief Returns the infinity norm of the absolute residual. */ Scalar absResidual() const { return residualError_; } /*! * \copydoc ConvergenceCriterion::setInitial(const Vector& , const Vector& ) */ void setInitial(const Vector& curSol, const Vector& curResid) override { updateErrors_(curSol, curSol, curResid); stagnates_ = false; // to avoid divisions by zero, make sure that we don't use an initial error of 0 residualError_ = std::max(residualError_, std::numeric_limits::min()*1e10); initialResidualError_ = residualError_; lastResidualError_ = residualError_; } /*! * \copydoc ConvergenceCriterion::update(const Vector&, const Vector&, const Vector&) */ void update(const Vector& curSol, const Vector& changeIndicator, const Vector& curResid) override { updateErrors_(curSol, changeIndicator, curResid); } /*! * \copydoc ConvergenceCriterion::converged() */ bool converged() const override { // we're converged if the solution is better than the tolerance // fix-point and residual tolerance. return residualReduction() <= residualReductionTolerance() || absResidual() <= absResidualTolerance(); } /*! * \copydoc ConvergenceCriterion::failed() */ bool failed() const override { return !converged() && (stagnates_ || residualError_ > maxResidual_); } /*! * \copydoc ConvergenceCriterion::accuracy() * * For the accuracy we only take the residual into account, */ Scalar accuracy() const override { return residualError_/initialResidualError_; } /*! * \copydoc ConvergenceCriterion::printInitial() */ void printInitial(std::ostream& os = std::cout) const override { os << std::setw(20) << "iteration "; os << std::setw(20) << "residual "; os << std::setw(20) << "reduction "; os << std::setw(20) << "rate "; os << std::endl; } /*! * \copydoc ConvergenceCriterion::print() */ void print(Scalar iter, std::ostream& os = std::cout) const override { const Scalar eps = std::numeric_limits::min()*1e10; os << std::setw(20) << iter << " "; os << std::setw(20) << absResidual() << " "; os << std::setw(20) << accuracy() << " "; os << std::setw(20) << lastResidualError_/std::max(residualError_, eps) << " "; os << std::endl << std::flush; } private: // update the weighted absolute residual void updateErrors_(const Vector&, const Vector& changeIndicator, const Vector& curResid) { lastResidualError_ = residualError_; residualError_ = 0.0; stagnates_ = true; for (size_t i = 0; i < curResid.size(); ++i) { for (unsigned j = 0; j < BlockType::dimension; ++j) { residualError_ = std::max(residualError_, std::abs(curResid[i][j])); if (stagnates_ && changeIndicator[i][j] != 0.0) // only stagnation means that we've failed! stagnates_ = false; } } residualError_ = comm_.max(residualError_); // the linear solver only stagnates if all processes stagnate stagnates_ = comm_.min(stagnates_); } const CollectiveCommunication& comm_; // the infinity norm of the residual of the last iteration Scalar lastResidualError_; // the infinity norm of the residual of the current iteration Scalar residualError_; // the infinity norm of the residual of the initial solution Scalar initialResidualError_; // the minimum reduction of the residual norm where the solution is to be considered // converged Scalar residualReductionTolerance_; // the maximum residual norm for the residual for the solution to be considered to be // converged Scalar absResidualTolerance_; // The maximum error which is tolerated before we fail. Scalar maxResidual_; // does the linear solver seem to stagnate, i.e. were the last two solutions // identical? bool stagnates_; }; //! \} end documentation }} // end namespace Linear, Opm #endif