2018-11-14 05:13:28 -06:00
// -*- 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 < http : //www.gnu.org/licenses/>.
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
*
2019-09-05 10:04:39 -05:00
* \ copydoc Opm : : EclNewtonMethod
2018-11-14 05:13:28 -06:00
*/
# ifndef EWOMS_ECL_NEWTON_METHOD_HH
# define EWOMS_ECL_NEWTON_METHOD_HH
2019-09-16 04:22:14 -05:00
# include <opm/models/blackoil/blackoilnewtonmethod.hh>
2019-09-16 03:58:20 -05:00
# include <opm/models/utils/signum.hh>
2019-10-07 07:51:23 -05:00
# include <opm/common/OpmLog/OpmLog.hpp>
2018-11-14 05:13:28 -06:00
# include <opm/material/common/Unused.hpp>
2020-08-21 06:42:08 -05:00
namespace Opm : : Properties {
2018-11-14 05:13:28 -06:00
2020-08-27 04:38:38 -05:00
template < class TypeTag , class MyTypeTag >
struct EclNewtonSumTolerance {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct EclNewtonStrictIterations {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct EclNewtonRelaxedVolumeFraction {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct EclNewtonSumToleranceExponent {
using type = UndefinedProperty ;
} ;
template < class TypeTag , class MyTypeTag >
struct EclNewtonRelaxedTolerance {
using type = UndefinedProperty ;
} ;
2018-11-14 05:13:28 -06:00
2020-08-21 06:42:08 -05:00
} // namespace Opm::Properties
2018-11-14 05:13:28 -06:00
2019-09-05 10:04:39 -05:00
namespace Opm {
2018-11-14 05:13:28 -06:00
/*!
* \ brief A newton solver which is ebos specific .
*/
template < class TypeTag >
class EclNewtonMethod : public BlackOilNewtonMethod < TypeTag >
{
typedef BlackOilNewtonMethod < TypeTag > ParentType ;
2020-08-26 03:49:52 -05:00
using DiscNewtonMethod = GetPropType < TypeTag , Properties : : DiscNewtonMethod > ;
using Simulator = GetPropType < TypeTag , Properties : : Simulator > ;
using FluidSystem = GetPropType < TypeTag , Properties : : FluidSystem > ;
using SolutionVector = GetPropType < TypeTag , Properties : : SolutionVector > ;
using GlobalEqVector = GetPropType < TypeTag , Properties : : GlobalEqVector > ;
using PrimaryVariables = GetPropType < TypeTag , Properties : : PrimaryVariables > ;
using EqVector = GetPropType < TypeTag , Properties : : EqVector > ;
using Indices = GetPropType < TypeTag , Properties : : Indices > ;
using Scalar = GetPropType < TypeTag , Properties : : Scalar > ;
using Linearizer = GetPropType < TypeTag , Properties : : Linearizer > ;
using ElementContext = GetPropType < TypeTag , Properties : : ElementContext > ;
2018-11-14 05:13:28 -06:00
2020-08-27 02:13:30 -05:00
static const unsigned numEq = getPropValue < TypeTag , Properties : : NumEq > ( ) ;
2018-11-14 05:13:28 -06:00
static constexpr int contiSolventEqIdx = Indices : : contiSolventEqIdx ;
static constexpr int contiPolymerEqIdx = Indices : : contiPolymerEqIdx ;
static constexpr int contiEnergyEqIdx = Indices : : contiEnergyEqIdx ;
friend NewtonMethod < TypeTag > ;
friend DiscNewtonMethod ;
friend ParentType ;
public :
EclNewtonMethod ( Simulator & simulator ) : ParentType ( simulator )
{
errorPvFraction_ = 1.0 ;
2019-01-07 06:26:10 -06:00
relaxedMaxPvFraction_ = EWOMS_GET_PARAM ( TypeTag , Scalar , EclNewtonRelaxedVolumeFraction ) ;
sumTolerance_ = 0.0 ; // this gets determined in the error calculation proceedure
relaxedTolerance_ = EWOMS_GET_PARAM ( TypeTag , Scalar , EclNewtonRelaxedTolerance ) ;
numStrictIterations_ = EWOMS_GET_PARAM ( TypeTag , int , EclNewtonStrictIterations ) ;
2018-11-14 05:13:28 -06:00
}
/*!
* \ brief Register all run - time parameters for the Newton method .
*/
static void registerParameters ( )
{
ParentType : : registerParameters ( ) ;
2019-01-07 06:26:10 -06:00
EWOMS_REGISTER_PARAM ( TypeTag , Scalar , EclNewtonSumTolerance ,
2018-11-14 05:13:28 -06:00
" The maximum error tolerated by the Newton "
" method for considering a solution to be "
" converged " ) ;
2019-01-07 06:26:10 -06:00
EWOMS_REGISTER_PARAM ( TypeTag , int , EclNewtonStrictIterations ,
" The number of Newton iterations where the "
" volumetric error is considered. " ) ;
EWOMS_REGISTER_PARAM ( TypeTag , Scalar , EclNewtonRelaxedVolumeFraction ,
" The fraction of the pore volume of the reservoir "
" where the volumetric error may be voilated during "
" strict Newton iterations. " ) ;
2019-01-11 04:18:06 -06:00
EWOMS_REGISTER_PARAM ( TypeTag , Scalar , EclNewtonSumToleranceExponent ,
" The the exponent used to scale the sum tolerance by "
" the total pore volume of the reservoir. " ) ;
2019-01-07 06:26:10 -06:00
EWOMS_REGISTER_PARAM ( TypeTag , Scalar , EclNewtonRelaxedTolerance ,
" The maximum error which the volumetric residual "
" may exhibit if it is in a 'relaxed' "
" region during a strict iteration. " ) ;
2018-11-14 05:13:28 -06:00
}
/*!
* \ brief Returns true if the error of the solution is below the
* tolerance .
*/
bool converged ( ) const
{
2019-01-07 06:26:10 -06:00
if ( errorPvFraction_ < relaxedMaxPvFraction_ )
2018-11-14 05:13:28 -06:00
return ( this - > error_ < relaxedTolerance_ & & errorSum_ < sumTolerance_ ) ;
2019-01-07 06:26:10 -06:00
else if ( this - > numIterations ( ) > numStrictIterations_ )
2018-11-14 05:13:28 -06:00
return ( this - > error_ < relaxedTolerance_ & & errorSum_ < sumTolerance_ ) ;
return this - > error_ < = this - > tolerance ( ) & & errorSum_ < = sumTolerance_ ;
}
2021-08-02 07:55:41 -05:00
void preSolve_ ( const SolutionVector & ,
2018-11-14 05:13:28 -06:00
const GlobalEqVector & currentResidual )
{
const auto & constraintsMap = this - > model ( ) . linearizer ( ) . constraintsMap ( ) ;
this - > lastError_ = this - > error_ ;
Scalar newtonMaxError = EWOMS_GET_PARAM ( TypeTag , Scalar , NewtonMaxError ) ;
// calculate the error as the maximum weighted tolerance of
// the solution's residual
this - > error_ = 0.0 ;
Dune : : FieldVector < Scalar , numEq > componentSumError ;
std : : fill ( componentSumError . begin ( ) , componentSumError . end ( ) , 0.0 ) ;
Scalar sumPv = 0.0 ;
errorPvFraction_ = 0.0 ;
const Scalar dt = this - > simulator_ . timeStepSize ( ) ;
for ( unsigned dofIdx = 0 ; dofIdx < currentResidual . size ( ) ; + + dofIdx ) {
// do not consider auxiliary DOFs for the error
if ( dofIdx > = this - > model ( ) . numGridDof ( )
| | this - > model ( ) . dofTotalVolume ( dofIdx ) < = 0.0 )
continue ;
if ( ! this - > model ( ) . isLocalDof ( dofIdx ) )
continue ;
// also do not consider DOFs which are constraint
if ( this - > enableConstraints_ ( ) ) {
if ( constraintsMap . count ( dofIdx ) > 0 )
continue ;
}
const auto & r = currentResidual [ dofIdx ] ;
2019-03-01 03:36:29 -06:00
Scalar pvValue =
2019-03-12 09:51:41 -05:00
this - > simulator_ . problem ( ) . referencePorosity ( dofIdx , /*timeIdx=*/ 0 )
2018-11-14 05:13:28 -06:00
* this - > model ( ) . dofTotalVolume ( dofIdx ) ;
sumPv + = pvValue ;
bool cnvViolated = false ;
2019-03-01 03:36:29 -06:00
Scalar dofVolume = this - > model ( ) . dofTotalVolume ( dofIdx ) ;
2018-11-14 05:13:28 -06:00
for ( unsigned eqIdx = 0 ; eqIdx < r . size ( ) ; + + eqIdx ) {
Scalar tmpError = r [ eqIdx ] * dt * this - > model ( ) . eqWeight ( dofIdx , eqIdx ) / pvValue ;
Scalar tmpError2 = r [ eqIdx ] * this - > model ( ) . eqWeight ( dofIdx , eqIdx ) ;
2019-03-01 03:36:29 -06:00
// in the case of a volumetric formulation, the residual in the above is
// per cubic meter
2020-08-27 02:13:30 -05:00
if ( getPropValue < TypeTag , Properties : : UseVolumetricResidual > ( ) ) {
2019-03-01 03:36:29 -06:00
tmpError * = dofVolume ;
tmpError2 * = dofVolume ;
}
2021-05-05 04:22:44 -05:00
this - > error_ = max ( std : : abs ( tmpError ) , this - > error_ ) ;
2018-11-14 05:13:28 -06:00
if ( std : : abs ( tmpError ) > this - > tolerance_ )
cnvViolated = true ;
componentSumError [ eqIdx ] + = std : : abs ( tmpError2 ) ;
}
if ( cnvViolated )
errorPvFraction_ + = pvValue ;
}
// take the other processes into account
this - > error_ = this - > comm_ . max ( this - > error_ ) ;
componentSumError = this - > comm_ . sum ( componentSumError ) ;
sumPv = this - > comm_ . sum ( sumPv ) ;
errorPvFraction_ = this - > comm_ . sum ( errorPvFraction_ ) ;
componentSumError / = sumPv ;
componentSumError * = dt ;
errorPvFraction_ / = sumPv ;
errorSum_ = 0 ;
for ( unsigned eqIdx = 0 ; eqIdx < numEq ; + + eqIdx )
errorSum_ = std : : max ( std : : abs ( componentSumError [ eqIdx ] ) , errorSum_ ) ;
2019-01-11 04:18:06 -06:00
// scale the tolerance for the total error with the pore volume. by default, the
// exponent is 1/3, i.e., cubic root.
Scalar x = EWOMS_GET_PARAM ( TypeTag , Scalar , EclNewtonSumTolerance ) ;
Scalar y = EWOMS_GET_PARAM ( TypeTag , Scalar , EclNewtonSumToleranceExponent ) ;
sumTolerance_ = x * std : : pow ( sumPv , y ) ;
2018-11-14 05:13:28 -06:00
2019-03-01 03:36:29 -06:00
this - > endIterMsg ( ) < < " (max: " < < this - > tolerance_ < < " , violated for " < < errorPvFraction_ * 100 < < " % of the pore volume), aggegate error: " < < errorSum_ < < " (max: " < < sumTolerance_ < < " ) " ;
2018-11-14 05:13:28 -06:00
// make sure that the error never grows beyond the maximum
// allowed one
if ( this - > error_ > newtonMaxError )
2021-05-05 04:22:44 -05:00
throw NumericalIssue ( " Newton: Error " + std : : to_string ( double ( this - > error_ ) )
2018-11-14 05:13:28 -06:00
+ " is larger than maximum allowed error of "
+ std : : to_string ( double ( newtonMaxError ) ) ) ;
// make sure that the error never grows beyond the maximum
// allowed one
if ( errorSum_ > newtonMaxError )
2021-05-05 04:22:44 -05:00
throw NumericalIssue ( " Newton: Sum of the error " + std : : to_string ( double ( errorSum_ ) )
2018-11-14 05:13:28 -06:00
+ " is larger than maximum allowed error of "
+ std : : to_string ( double ( newtonMaxError ) ) ) ;
}
2019-10-07 07:51:23 -05:00
void endIteration_ ( SolutionVector & nextSolution ,
const SolutionVector & currentSolution )
{
ParentType : : endIteration_ ( nextSolution , currentSolution ) ;
OpmLog : : debug ( " Newton iteration " + std : : to_string ( this - > numIterations_ ) + " "
+ " error: " + std : : to_string ( double ( this - > error_ ) )
+ this - > endIterMsg ( ) . str ( ) ) ;
this - > endIterMsg ( ) . str ( " " ) ;
}
2018-11-14 05:13:28 -06:00
private :
Scalar errorPvFraction_ ;
Scalar errorSum_ ;
Scalar relaxedTolerance_ ;
2019-01-07 06:26:10 -06:00
Scalar relaxedMaxPvFraction_ ;
2018-11-14 05:13:28 -06:00
Scalar sumTolerance_ ;
2019-01-07 06:26:10 -06:00
int numStrictIterations_ ;
2018-11-14 05:13:28 -06:00
} ;
2019-09-05 10:04:39 -05:00
} // namespace Opm
2018-11-14 05:13:28 -06:00
# endif