2015-06-01 06:33:37 -05:00
/*
Copyright 2015 SINTEF ICT , Applied Mathematics .
2015-06-16 04:35:23 -05:00
Copyright 2015 Dr . Blatt - HPC - Simulation - Software & Services
Copyright 2015 NTNU
2015-06-01 06:33:37 -05:00
Copyright 2015 Statoil AS
2015-10-07 10:48:27 -05:00
Copyright 2015 IRIS AS
2015-06-01 06:33:37 -05:00
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 3 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/>.
*/
# include <config.h>
# include <opm/autodiff/DuneMatrix.hpp>
2015-10-07 13:49:20 -05:00
# include <opm/autodiff/AdditionalObjectDeleter.hpp>
2016-02-08 07:46:29 -06:00
# include <opm/autodiff/CPRPreconditioner.hpp>
2015-06-01 06:33:37 -05:00
# include <opm/autodiff/NewtonIterationBlackoilInterleaved.hpp>
2015-06-16 03:18:11 -05:00
# include <opm/autodiff/NewtonIterationUtilities.hpp>
2015-12-01 07:56:29 -06:00
# include <opm/autodiff/ParallelRestrictedAdditiveSchwarz.hpp>
# include <opm/autodiff/ParallelOverlappingILU0.hpp>
2015-06-01 06:33:37 -05:00
# include <opm/autodiff/AutoDiffHelpers.hpp>
2015-10-08 04:43:36 -05:00
# include <opm/common/Exceptions.hpp>
2015-06-16 04:35:23 -05:00
# include <opm/core/linalg/ParallelIstlInformation.hpp>
2015-06-01 06:33:37 -05:00
2015-10-07 13:49:20 -05:00
# include <opm/common/utility/platform_dependent/disable_warnings.h>
2015-10-07 10:48:27 -05:00
# include <dune/istl/scalarproducts.hh>
# include <dune/istl/operators.hh>
# include <dune/istl/preconditioners.hh>
# include <dune/istl/solvers.hh>
# include <dune/istl/owneroverlapcopy.hh>
# include <dune/istl/paamg/amg.hh>
2015-06-01 06:33:37 -05:00
# if HAVE_UMFPACK
# include <Eigen/UmfPackSupport>
# else
# include <Eigen/SparseLU>
# endif
2015-10-06 05:11:49 -05:00
# include <opm/common/utility/platform_dependent/reenable_warnings.h>
2015-06-01 06:33:37 -05:00
2015-06-15 09:12:23 -05:00
2016-02-08 06:28:28 -06:00
namespace Dune
{
2016-02-12 05:05:08 -06:00
namespace ISTLUtility {
//! invert matrix by calling FMatrixHelp::invert
template < typename K >
static inline void invertMatrix ( FieldMatrix < K , 1 , 1 > & matrix )
{
FieldMatrix < K , 1 , 1 > A ( matrix ) ;
FMatrixHelp : : invertMatrix ( A , matrix ) ;
}
//! invert matrix by calling FMatrixHelp::invert
template < typename K >
static inline void invertMatrix ( FieldMatrix < K , 2 , 2 > & matrix )
{
FieldMatrix < K , 2 , 2 > A ( matrix ) ;
FMatrixHelp : : invertMatrix ( A , matrix ) ;
2016-02-08 06:28:28 -06:00
}
2016-02-12 05:05:08 -06:00
//! invert matrix by calling FMatrixHelp::invert
template < typename K >
static inline void invertMatrix ( FieldMatrix < K , 3 , 3 > & matrix )
{
FieldMatrix < K , 3 , 3 > A ( matrix ) ;
FMatrixHelp : : invertMatrix ( A , matrix ) ;
}
//! invert matrix by calling matrix.invert
template < typename K , int n >
static inline void invertMatrix ( FieldMatrix < K , n , n > & matrix )
{
matrix . invert ( ) ;
}
} // end ISTLUtility
2016-02-08 07:46:29 -06:00
template < class Scalar , int n , int m >
class MatrixBlock : public Dune : : FieldMatrix < Scalar , n , m >
{
2016-02-08 08:52:32 -06:00
public :
2016-02-08 07:46:29 -06:00
typedef Dune : : FieldMatrix < Scalar , n , m > BaseType ;
using BaseType : : operator = ;
using BaseType : : rows ;
using BaseType : : cols ;
explicit MatrixBlock ( const Scalar scalar = 0 ) : BaseType ( scalar ) { }
void invert ( )
{
2016-02-12 05:05:08 -06:00
ISTLUtility : : invertMatrix ( * this ) ;
2016-02-08 07:46:29 -06:00
}
2016-02-08 08:52:32 -06:00
const BaseType & asBase ( ) const { return static_cast < const BaseType & > ( * this ) ; }
BaseType & asBase ( ) { return static_cast < BaseType & > ( * this ) ; }
2016-02-08 07:46:29 -06:00
} ;
template < class K , int n , int m >
2016-02-08 08:52:32 -06:00
void
print_row ( std : : ostream & s , const MatrixBlock < K , n , m > & A ,
typename FieldMatrix < K , n , m > : : size_type I ,
typename FieldMatrix < K , n , m > : : size_type J ,
typename FieldMatrix < K , n , m > : : size_type therow , int width ,
int precision )
{
print_row ( s , A . asBase ( ) , I , J , therow , width , precision ) ;
}
template < class K , int n , int m >
K & firstmatrixelement ( MatrixBlock < K , n , m > & A )
2016-02-08 07:46:29 -06:00
{
2016-02-08 08:52:32 -06:00
return firstmatrixelement ( A . asBase ( ) ) ;
2016-02-08 06:28:28 -06:00
}
2016-02-08 07:46:29 -06:00
2016-02-08 08:52:32 -06:00
2016-02-08 07:46:29 -06:00
template < typename Scalar , int n , int m >
struct MatrixDimension < MatrixBlock < Scalar , n , m > >
: public MatrixDimension < typename MatrixBlock < Scalar , n , m > : : BaseType >
{
} ;
} // end namespace Dune
2015-06-01 06:33:37 -05:00
namespace Opm
{
2015-10-07 10:48:27 -05:00
namespace detail {
/**
* Simple binary operator that always returns 0.1
* It is used to get the sparsity pattern for our
* interleaved system , and is marginally faster than using
* operator + = .
*/
template < typename Scalar > struct PointOneOp {
EIGEN_EMPTY_STRUCT_CTOR ( PointOneOp )
2015-10-08 08:24:47 -05:00
Scalar operator ( ) ( const Scalar & , const Scalar & ) const { return 0.1 ; }
2015-10-07 10:48:27 -05:00
} ;
2015-06-01 06:33:37 -05:00
}
2015-10-07 10:48:27 -05:00
/// This class solves the fully implicit black-oil system by
/// solving the reduced system (after eliminating well variables)
/// as a block-structured matrix (one block for all cell variables) for a fixed
/// number of cell variables np .
2016-02-08 06:28:28 -06:00
template < int np , class ScalarT = double >
2015-10-07 10:48:27 -05:00
class NewtonIterationBlackoilInterleavedImpl : public NewtonIterationBlackoilInterface
2015-06-01 06:33:37 -05:00
{
2016-02-08 06:28:28 -06:00
typedef ScalarT Scalar ;
2015-10-09 06:39:02 -05:00
typedef Dune : : FieldVector < Scalar , np > VectorBlockType ;
2016-02-08 06:28:28 -06:00
2016-02-08 07:46:29 -06:00
typedef Dune : : MatrixBlock < Scalar , np , np > MatrixBlockType ;
2015-10-07 10:48:27 -05:00
typedef Dune : : BCRSMatrix < MatrixBlockType > Mat ;
typedef Dune : : BlockVector < VectorBlockType > Vector ;
public :
typedef NewtonIterationBlackoilInterface : : SolutionVector SolutionVector ;
/// Construct a system solver.
2015-10-09 05:03:58 -05:00
/// \param[in] param parameters controlling the behaviour of the linear solvers
2015-10-07 10:48:27 -05:00
/// \param[in] parallelInformation In the case of a parallel run
2015-10-09 05:03:58 -05:00
/// with dune-istl the information about the parallelization.
NewtonIterationBlackoilInterleavedImpl ( const NewtonIterationBlackoilInterleavedParameters & param ,
2015-10-07 10:48:27 -05:00
const boost : : any & parallelInformation_arg = boost : : any ( ) )
: iterations_ ( 0 ) ,
parallelInformation_ ( parallelInformation_arg ) ,
2015-10-09 05:03:58 -05:00
parameters_ ( param )
2015-10-07 10:48:27 -05:00
{
2015-06-01 06:33:37 -05:00
}
2015-10-07 10:48:27 -05:00
/// Solve the system of linear equations Ax = b, with A being the
/// combined derivative matrix of the residual and b
/// being the residual itself.
/// \param[in] residual residual object containing A and b.
/// \return the solution x
/// \copydoc NewtonIterationBlackoilInterface::iterations
int iterations ( ) const { return iterations_ ; }
/// \copydoc NewtonIterationBlackoilInterface::parallelInformation
const boost : : any & parallelInformation ( ) const { return parallelInformation_ ; }
public :
/// \brief construct the CPR preconditioner and the solver.
/// \tparam P The type of the parallel information.
/// \param parallelInformation the information about the parallelization.
template < int category = Dune : : SolverCategory : : sequential , class O , class POrComm >
void constructPreconditionerAndSolve ( O & opA ,
Vector & x , Vector & istlb ,
const POrComm & parallelInformation_arg ,
Dune : : InverseOperatorResult & result ) const
2015-06-01 06:33:37 -05:00
{
2015-10-07 10:48:27 -05:00
// Construct scalar product.
typedef Dune : : ScalarProductChooser < Vector , POrComm , category > ScalarProductChooser ;
typedef std : : unique_ptr < typename ScalarProductChooser : : ScalarProduct > SPPointer ;
SPPointer sp ( ScalarProductChooser : : construct ( parallelInformation_arg ) ) ;
2015-06-01 06:33:37 -05:00
2015-10-07 10:48:27 -05:00
// Communicate if parallel.
parallelInformation_arg . copyOwnerToAll ( istlb , istlb ) ;
2016-02-08 07:46:29 -06:00
# if ! HAVE_UMFPACK
const bool useAmg = false ;
if ( useAmg )
{
typedef ISTLUtility : : CPRSelector < Mat , Vector , Vector , POrComm > CPRSelectorType ;
typedef typename CPRSelectorType : : AMG AMG ;
std : : unique_ptr < AMG > amg ;
// Construct preconditioner.
constructAMGPrecond ( opA , parallelInformation_arg , amg ) ;
// Solve.
solve ( opA , x , istlb , * sp , * amg , result ) ;
}
else
# endif
{
// Construct preconditioner.
auto precond = constructPrecond ( opA , parallelInformation_arg ) ;
2015-08-17 06:04:07 -05:00
2016-02-08 07:46:29 -06:00
// Solve.
solve ( opA , x , istlb , * sp , * precond , result ) ;
}
}
2015-08-17 06:04:07 -05:00
2015-10-07 10:48:27 -05:00
typedef Dune : : SeqILU0 < Mat , Vector , Vector > SeqPreconditioner ;
2015-06-15 09:12:23 -05:00
2015-10-07 10:48:27 -05:00
template < class Operator >
std : : unique_ptr < SeqPreconditioner > constructPrecond ( Operator & opA , const Dune : : Amg : : SequentialInformation & ) const
{
2016-02-08 10:13:43 -06:00
const double relax = 0.9 ;
2015-10-07 10:48:27 -05:00
std : : unique_ptr < SeqPreconditioner > precond ( new SeqPreconditioner ( opA . getmat ( ) , relax ) ) ;
return precond ;
}
2015-06-01 06:33:37 -05:00
2015-06-16 06:28:11 -05:00
# if HAVE_MPI
2015-10-07 10:48:27 -05:00
typedef Dune : : OwnerOverlapCopyCommunication < int , int > Comm ;
2015-09-08 14:23:22 -05:00
typedef ParallelOverlappingILU0 < Mat , Vector , Vector , Comm > ParPreconditioner ;
2015-10-07 10:48:27 -05:00
template < class Operator >
2015-12-01 08:11:27 -06:00
std : : unique_ptr < ParPreconditioner >
2015-10-07 10:48:27 -05:00
constructPrecond ( Operator & opA , const Comm & comm ) const
2015-06-16 04:35:23 -05:00
{
2015-09-08 14:23:22 -05:00
typedef std : : unique_ptr < ParPreconditioner > Pointer ;
2016-02-08 10:13:43 -06:00
const double relax = 0.9 ;
2015-09-08 14:23:22 -05:00
return Pointer ( new ParPreconditioner ( opA . getmat ( ) , comm , relax ) ) ;
2015-06-16 04:35:23 -05:00
}
# endif
2015-10-07 10:48:27 -05:00
2016-02-08 07:46:29 -06:00
template < class Operator , class POrComm , class AMG >
void
constructAMGPrecond ( Operator & opA , const POrComm & comm , std : : unique_ptr < AMG > & amg ) const
{
const double relax = 1.0 ;
ISTLUtility : : createAMGPreconditionerPointer ( opA , relax , comm , amg ) ;
}
2015-10-07 10:48:27 -05:00
/// \brief Solve the system using the given preconditioner and scalar product.
template < class Operator , class ScalarProd , class Precond >
void solve ( Operator & opA , Vector & x , Vector & istlb , ScalarProd & sp , Precond & precond , Dune : : InverseOperatorResult & result ) const
2015-06-16 04:35:23 -05:00
{
2015-10-07 10:48:27 -05:00
// TODO: Revise when linear solvers interface opm-core is done
// Construct linear solver.
// GMRes solver
2015-10-09 05:03:58 -05:00
if ( parameters_ . newton_use_gmres_ ) {
2015-10-07 10:48:27 -05:00
Dune : : RestartedGMResSolver < Vector > linsolve ( opA , sp , precond ,
2015-10-09 05:03:58 -05:00
parameters_ . linear_solver_reduction_ ,
parameters_ . linear_solver_restart_ ,
parameters_ . linear_solver_maxiter_ ,
parameters_ . linear_solver_verbosity_ ) ;
2015-10-07 10:48:27 -05:00
// Solve system.
linsolve . apply ( x , istlb , result ) ;
}
else { // BiCGstab solver
Dune : : BiCGSTABSolver < Vector > linsolve ( opA , sp , precond ,
2015-10-09 05:03:58 -05:00
parameters_ . linear_solver_reduction_ ,
parameters_ . linear_solver_maxiter_ ,
parameters_ . linear_solver_verbosity_ ) ;
2015-10-07 10:48:27 -05:00
// Solve system.
linsolve . apply ( x , istlb , result ) ;
}
2015-06-16 04:35:23 -05:00
}
2015-06-01 06:33:37 -05:00
2015-10-07 10:48:27 -05:00
void formInterleavedSystem ( const std : : vector < LinearisedBlackoilResidual : : ADB > & eqs ,
Mat & istlA ) const
{
assert ( np = = int ( eqs . size ( ) ) ) ;
// Find sparsity structure as union of basic block sparsity structures,
// corresponding to the jacobians with respect to pressure.
// Use our custom PointOneOp to get to the union structure.
2016-05-11 08:13:52 -05:00
// As default we only iterate over the pressure derivatives.
2015-10-07 10:48:27 -05:00
Eigen : : SparseMatrix < double , Eigen : : ColMajor > col_major = eqs [ 0 ] . derivative ( ) [ 0 ] . getSparse ( ) ;
detail : : PointOneOp < double > point_one ;
for ( int phase = 1 ; phase < np ; + + phase ) {
const AutoDiffMatrix : : SparseRep & mat = eqs [ phase ] . derivative ( ) [ 0 ] . getSparse ( ) ;
col_major = col_major . binaryExpr ( mat , point_one ) ;
}
2016-05-11 08:13:52 -05:00
// For some cases (for instance involving Solvent flow) the reasoning for only adding
// the pressure derivatives fails. As getting the sparsity pattern is non-trivial, in terms
// of work, the full sparsity pattern is only added when required.
if ( parameters_ . require_full_sparsity_pattern_ ) {
for ( int p1 = 0 ; p1 < np ; + + p1 ) {
for ( int p2 = 1 ; p2 < np ; + + p2 ) { // pressure is already added
const AutoDiffMatrix : : SparseRep & mat = eqs [ p1 ] . derivative ( ) [ p2 ] . getSparse ( ) ;
col_major = col_major . binaryExpr ( mat , point_one ) ;
}
}
}
2015-06-01 06:33:37 -05:00
2015-10-07 10:48:27 -05:00
// Automatically convert the column major structure to a row-major structure
Eigen : : SparseMatrix < double , Eigen : : RowMajor > row_major = col_major ;
const int size = row_major . rows ( ) ;
assert ( size = = row_major . cols ( ) ) ;
2015-10-08 08:24:47 -05:00
{
// Create ISTL matrix with interleaved rows and columns (block structured).
istlA . setSize ( row_major . rows ( ) , row_major . cols ( ) , row_major . nonZeros ( ) ) ;
istlA . setBuildMode ( Mat : : row_wise ) ;
const int * ia = row_major . outerIndexPtr ( ) ;
const int * ja = row_major . innerIndexPtr ( ) ;
const typename Mat : : CreateIterator endrow = istlA . createend ( ) ;
for ( typename Mat : : CreateIterator row = istlA . createbegin ( ) ; row ! = endrow ; + + row ) {
const int ri = row . index ( ) ;
for ( int i = ia [ ri ] ; i < ia [ ri + 1 ] ; + + i ) {
row . insert ( ja [ i ] ) ;
}
2015-10-07 10:48:27 -05:00
}
}
2016-02-08 08:52:32 -06:00
/*
// not neeeded since MatrixBlock initially zeros all elements during construction
// Set all blocks to zero.
for ( auto row = istlA . begin ( ) , rowend = istlA . end ( ) ; row ! = rowend ; + + row ) {
for ( auto col = row - > begin ( ) , colend = row - > end ( ) ; col ! = colend ; + + col ) {
* col = 0.0 ;
}
}
*/
2015-10-07 10:48:27 -05:00
/**
* Go through all jacobians , and insert in correct spot
*
* The straight forward way to do this would be to run through each
* element in the output matrix , and set all block entries by gathering
* from all " input matrices " ( derivatives ) .
*
* A faster alternative is to instead run through each " input matrix " and
* insert its elements in the correct spot in the output matrix .
*
*/
2015-10-08 08:24:47 -05:00
for ( int p1 = 0 ; p1 < np ; + + p1 ) {
for ( int p2 = 0 ; p2 < np ; + + p2 ) {
// Note that that since these are CSC and not CSR matrices,
// ja contains row numbers instead of column numbers.
const AutoDiffMatrix : : SparseRep & s = eqs [ p1 ] . derivative ( ) [ p2 ] . getSparse ( ) ;
const int * ia = s . outerIndexPtr ( ) ;
const int * ja = s . innerIndexPtr ( ) ;
const double * sa = s . valuePtr ( ) ;
for ( int col = 0 ; col < size ; + + col ) {
2015-10-07 10:48:27 -05:00
for ( int elem_ix = ia [ col ] ; elem_ix < ia [ col + 1 ] ; + + elem_ix ) {
const int row = ja [ elem_ix ] ;
istlA [ row ] [ col ] [ p1 ] [ p2 ] = sa [ elem_ix ] ;
}
}
}
}
2015-06-01 06:33:37 -05:00
}
2015-10-07 10:48:27 -05:00
/// Solve the linear system Ax = b, with A being the
/// combined derivative matrix of the residual and b
/// being the residual itself.
/// \param[in] residual residual object containing A and b.
/// \return the solution x
SolutionVector computeNewtonIncrement ( const LinearisedBlackoilResidual & residual ) const
{
2015-10-09 06:39:02 -05:00
typedef LinearisedBlackoilResidual : : ADB ADB ;
typedef ADB : : V V ;
2015-10-07 10:48:27 -05:00
// Build the vector of equations.
//const int np = residual.material_balance_eq.size();
assert ( np = = int ( residual . material_balance_eq . size ( ) ) ) ;
std : : vector < ADB > eqs ;
eqs . reserve ( np + 2 ) ;
for ( int phase = 0 ; phase < np ; + + phase ) {
eqs . push_back ( residual . material_balance_eq [ phase ] ) ;
}
2015-06-01 06:33:37 -05:00
2015-10-07 10:48:27 -05:00
// check if wells are present
const bool hasWells = residual . well_flux_eq . size ( ) > 0 ;
std : : vector < ADB > elim_eqs ;
if ( hasWells )
{
eqs . push_back ( residual . well_flux_eq ) ;
eqs . push_back ( residual . well_eq ) ;
// Eliminate the well-related unknowns, and corresponding equations.
elim_eqs . reserve ( 2 ) ;
elim_eqs . push_back ( eqs [ np ] ) ;
eqs = eliminateVariable ( eqs , np ) ; // Eliminate well flux unknowns.
elim_eqs . push_back ( eqs [ np ] ) ;
eqs = eliminateVariable ( eqs , np ) ; // Eliminate well bhp unknowns.
assert ( int ( eqs . size ( ) ) = = np ) ;
}
2015-06-01 06:33:37 -05:00
2015-10-07 10:48:27 -05:00
// Scale material balance equations.
for ( int phase = 0 ; phase < np ; + + phase ) {
eqs [ phase ] = eqs [ phase ] * residual . matbalscale [ phase ] ;
}
2015-09-17 06:46:05 -05:00
2015-10-07 10:48:27 -05:00
// calculating the size for b
int size_b = 0 ;
for ( int elem = 0 ; elem < np ; + + elem ) {
const int loc_size = eqs [ elem ] . size ( ) ;
size_b + = loc_size ;
}
2015-06-01 06:33:37 -05:00
2015-10-07 10:48:27 -05:00
V b ( size_b ) ;
2015-06-19 04:33:30 -05:00
2015-10-07 10:48:27 -05:00
int pos = 0 ;
for ( int elem = 0 ; elem < np ; + + elem ) {
const int loc_size = eqs [ elem ] . size ( ) ;
b . segment ( pos , loc_size ) = eqs [ elem ] . value ( ) ;
pos + = loc_size ;
2015-06-19 04:33:30 -05:00
}
2015-10-07 10:48:27 -05:00
assert ( pos = = size_b ) ;
2015-08-17 06:04:07 -05:00
2015-10-07 10:48:27 -05:00
// Create ISTL matrix with interleaved rows and columns (block structured).
Mat istlA ;
formInterleavedSystem ( eqs , istlA ) ;
// Solve reduced system.
SolutionVector dx ( SolutionVector : : Zero ( b . size ( ) ) ) ;
// Right hand side.
const int size = istlA . N ( ) ;
Vector istlb ( size ) ;
for ( int i = 0 ; i < size ; + + i ) {
for ( int p = 0 , idx = i ; p < np ; + + p , idx + = size ) {
istlb [ i ] [ p ] = b ( idx ) ;
}
2015-09-09 03:22:25 -05:00
}
2015-10-07 10:48:27 -05:00
// System solution
Vector x ( istlA . M ( ) ) ;
x = 0.0 ;
Dune : : InverseOperatorResult result ;
// Parallel version is deactivated until we figure out how to do it properly.
# if HAVE_MPI
if ( parallelInformation_ . type ( ) = = typeid ( ParallelISTLInformation ) )
{
typedef Dune : : OwnerOverlapCopyCommunication < int , int > Comm ;
const ParallelISTLInformation & info =
boost : : any_cast < const ParallelISTLInformation & > ( parallelInformation_ ) ;
Comm istlComm ( info . communicator ( ) ) ;
// As we use a dune-istl with block size np the number of components
// per parallel is only one.
info . copyValuesTo ( istlComm . indexSet ( ) , istlComm . remoteIndices ( ) ,
size , 1 ) ;
// Construct operator, scalar product and vectors needed.
typedef Dune : : OverlappingSchwarzOperator < Mat , Vector , Vector , Comm > Operator ;
Operator opA ( istlA , istlComm ) ;
constructPreconditionerAndSolve < Dune : : SolverCategory : : overlapping > ( opA , x , istlb , istlComm , result ) ;
}
else
# endif
{
// Construct operator, scalar product and vectors needed.
typedef Dune : : MatrixAdapter < Mat , Vector , Vector > Operator ;
Operator opA ( istlA ) ;
Dune : : Amg : : SequentialInformation info ;
constructPreconditionerAndSolve ( opA , x , istlb , info , result ) ;
}
// store number of iterations
iterations_ = result . iterations ;
// Check for failure of linear solver.
2016-05-27 05:55:46 -05:00
if ( ! parameters_ . ignoreConvergenceFailure_ & & ! result . converged ) {
2015-10-07 10:48:27 -05:00
OPM_THROW ( LinearSolverProblem , " Convergence failure for linear solver. " ) ;
}
// Copy solver output to dx.
for ( int i = 0 ; i < size ; + + i ) {
for ( int p = 0 , idx = i ; p < np ; + + p , idx + = size ) {
dx ( idx ) = x [ i ] [ p ] ;
2015-06-19 04:33:30 -05:00
}
}
2015-10-07 10:48:27 -05:00
if ( hasWells ) {
// Compute full solution using the eliminated equations.
// Recovery in inverse order of elimination.
dx = recoverVariable ( elim_eqs [ 1 ] , dx , np ) ;
dx = recoverVariable ( elim_eqs [ 0 ] , dx , np ) ;
}
return dx ;
2015-06-19 04:33:30 -05:00
}
2015-10-07 10:48:27 -05:00
protected :
mutable int iterations_ ;
boost : : any parallelInformation_ ;
2015-10-09 05:03:58 -05:00
NewtonIterationBlackoilInterleavedParameters parameters_ ;
2015-10-07 10:48:27 -05:00
} ; // end NewtonIterationBlackoilInterleavedImpl
/// Construct a system solver.
NewtonIterationBlackoilInterleaved : : NewtonIterationBlackoilInterleaved ( const parameter : : ParameterGroup & param ,
const boost : : any & parallelInformation_arg )
2016-02-08 08:52:32 -06:00
: newtonIncrementDoublePrecision_ ( ) ,
newtonIncrementSinglePrecision_ ( ) ,
2015-10-09 05:03:58 -05:00
parameters_ ( param ) ,
2015-10-07 10:48:27 -05:00
parallelInformation_ ( parallelInformation_arg ) ,
iterations_ ( 0 )
{
2015-06-19 04:33:30 -05:00
}
2015-10-08 07:04:05 -05:00
namespace detail {
2015-06-19 04:33:30 -05:00
2016-02-08 06:28:28 -06:00
template < int NP , class Scalar >
2015-10-08 07:04:05 -05:00
struct NewtonIncrement
{
template < class NewtonIncVector >
static const NewtonIterationBlackoilInterface &
get ( NewtonIncVector & newtonIncrements ,
2015-10-09 05:03:58 -05:00
const NewtonIterationBlackoilInterleavedParameters & param ,
2015-10-08 07:04:05 -05:00
const boost : : any & parallelInformation ,
const int np )
{
if ( np = = NP )
{
assert ( np < int ( newtonIncrements . size ( ) ) ) ;
// create NewtonIncrement with fixed np
if ( ! newtonIncrements [ NP ] )
2016-02-08 06:28:28 -06:00
newtonIncrements [ NP ] . reset ( new NewtonIterationBlackoilInterleavedImpl < NP , Scalar > ( param , parallelInformation ) ) ;
2015-10-08 07:04:05 -05:00
return * ( newtonIncrements [ NP ] ) ;
}
else
{
2016-02-08 06:28:28 -06:00
return NewtonIncrement < NP - 1 , Scalar > : : get ( newtonIncrements , param , parallelInformation , np ) ;
2015-10-08 07:04:05 -05:00
}
}
} ;
2015-06-19 04:33:30 -05:00
2016-02-08 06:28:28 -06:00
template < class Scalar >
struct NewtonIncrement < 0 , Scalar >
2015-10-07 10:48:27 -05:00
{
2015-10-08 07:04:05 -05:00
template < class NewtonIncVector >
static const NewtonIterationBlackoilInterface &
2015-10-09 06:49:00 -05:00
get ( NewtonIncVector & ,
2015-10-09 05:03:58 -05:00
const NewtonIterationBlackoilInterleavedParameters & ,
const boost : : any & ,
2015-10-09 06:49:00 -05:00
const int np )
2015-10-08 07:04:05 -05:00
{
2015-10-09 06:49:00 -05:00
OPM_THROW ( std : : runtime_error , " NewtonIncrement::get: number of variables not supported yet. Adjust maxNumberEquations appropriately to cover np = " < < np ) ;
2015-10-08 07:04:05 -05:00
}
} ;
2015-12-01 07:15:35 -06:00
std : : pair < NewtonIterationBlackoilInterleaved : : SolutionVector , Dune : : InverseOperatorResult >
computePressureIncrement ( const LinearisedBlackoilResidual & residual )
{
typedef LinearisedBlackoilResidual : : ADB ADB ;
typedef ADB : : V V ;
// Build the vector of equations (should be just a single material balance equation
// in which the pressure equation is stored).
const int np = residual . material_balance_eq . size ( ) ;
assert ( np = = 1 ) ;
std : : vector < ADB > eqs ;
eqs . reserve ( np + 2 ) ;
for ( int phase = 0 ; phase < np ; + + phase ) {
eqs . push_back ( residual . material_balance_eq [ phase ] ) ;
}
// Check if wells are present.
const bool hasWells = residual . well_flux_eq . size ( ) > 0 ;
std : : vector < ADB > elim_eqs ;
if ( hasWells ) {
// Eliminate the well-related unknowns, and corresponding equations.
eqs . push_back ( residual . well_flux_eq ) ;
eqs . push_back ( residual . well_eq ) ;
elim_eqs . reserve ( 2 ) ;
elim_eqs . push_back ( eqs [ np ] ) ;
eqs = eliminateVariable ( eqs , np ) ; // Eliminate well flux unknowns.
elim_eqs . push_back ( eqs [ np ] ) ;
eqs = eliminateVariable ( eqs , np ) ; // Eliminate well bhp unknowns.
assert ( int ( eqs . size ( ) ) = = np ) ;
}
// Solve the linearised oil equation.
Eigen : : SparseMatrix < double , Eigen : : RowMajor > eigenA = eqs [ 0 ] . derivative ( ) [ 0 ] . getSparse ( ) ;
DuneMatrix opA ( eigenA ) ;
const int size = eqs [ 0 ] . size ( ) ;
typedef Dune : : BlockVector < Dune : : FieldVector < double , 1 > > Vector1 ;
Vector1 x ;
x . resize ( size ) ;
x = 0.0 ;
Vector1 b ;
b . resize ( size ) ;
b = 0.0 ;
std : : copy_n ( eqs [ 0 ] . value ( ) . data ( ) , size , b . begin ( ) ) ;
// Solve with AMG solver.
typedef Dune : : BCRSMatrix < Dune : : FieldMatrix < double , 1 , 1 > > Mat ;
typedef Dune : : MatrixAdapter < Mat , Vector1 , Vector1 > Operator ;
Operator sOpA ( opA ) ;
typedef Dune : : Amg : : SequentialInformation ParallelInformation ;
typedef Dune : : SeqILU0 < Mat , Vector1 , Vector1 > EllipticPreconditioner ;
typedef EllipticPreconditioner Smoother ;
typedef Dune : : Amg : : AMG < Operator , Vector1 , Smoother , ParallelInformation > AMG ;
typedef Dune : : Amg : : FirstDiagonal CouplingMetric ;
typedef Dune : : Amg : : SymmetricCriterion < Mat , CouplingMetric > CritBase ;
typedef Dune : : Amg : : CoarsenCriterion < CritBase > Criterion ;
// TODO: revise choice of parameters
const int coarsenTarget = 1200 ;
Criterion criterion ( 15 , coarsenTarget ) ;
criterion . setDebugLevel ( 0 ) ; // no debug information, 1 for printing hierarchy information
criterion . setDefaultValuesIsotropic ( 2 ) ;
criterion . setNoPostSmoothSteps ( 1 ) ;
criterion . setNoPreSmoothSteps ( 1 ) ;
// for DUNE 2.2 we also need to pass the smoother args
typedef typename AMG : : Smoother Smoother ;
typedef typename Dune : : Amg : : SmootherTraits < Smoother > : : Arguments SmootherArgs ;
SmootherArgs smootherArgs ;
smootherArgs . iterations = 1 ;
smootherArgs . relaxationFactor = 1.0 ;
AMG precond ( sOpA , criterion , smootherArgs ) ;
const int verbosity = 0 ;
const int maxit = 30 ;
const double tolerance = 1e-5 ;
// Construct linear solver.
Dune : : BiCGSTABSolver < Vector1 > linsolve ( sOpA , precond , tolerance , maxit , verbosity ) ;
// Solve system.
Dune : : InverseOperatorResult result ;
linsolve . apply ( x , b , result ) ;
// Check for failure of linear solver.
if ( ! result . converged ) {
OPM_THROW ( LinearSolverProblem , " Convergence failure for linear solver in computePressureIncrement(). " ) ;
}
// Copy solver output to dx.
NewtonIterationBlackoilInterleaved : : SolutionVector dx ( size ) ;
for ( int i = 0 ; i < size ; + + i ) {
dx ( i ) = x [ i ] ;
}
if ( hasWells ) {
// Compute full solution using the eliminated equations.
// Recovery in inverse order of elimination.
dx = recoverVariable ( elim_eqs [ 1 ] , dx , np ) ;
dx = recoverVariable ( elim_eqs [ 0 ] , dx , np ) ;
}
return std : : make_pair ( dx , result ) ;
}
2015-10-08 07:04:05 -05:00
} // end namespace detail
2015-06-19 04:33:30 -05:00
2015-10-07 10:48:27 -05:00
NewtonIterationBlackoilInterleaved : : SolutionVector
2015-10-08 07:04:05 -05:00
NewtonIterationBlackoilInterleaved : : computeNewtonIncrement ( const LinearisedBlackoilResidual & residual ) const
2015-06-16 03:18:11 -05:00
{
2015-10-08 07:04:05 -05:00
// get np and call appropriate template method
const int np = residual . material_balance_eq . size ( ) ;
2015-12-01 07:15:35 -06:00
if ( np = = 1 ) {
auto result = detail : : computePressureIncrement ( residual ) ;
iterations_ = result . second . iterations ;
return result . first ;
}
2016-02-09 09:07:56 -06:00
const NewtonIterationBlackoilInterface & newtonIncrement = residual . singlePrecision ?
2016-02-08 06:28:28 -06:00
detail : : NewtonIncrement < maxNumberEquations_ , float > : : get ( newtonIncrementSinglePrecision_ , parameters_ , parallelInformation_ , np ) :
2016-02-08 08:52:32 -06:00
detail : : NewtonIncrement < maxNumberEquations_ , double > : : get ( newtonIncrementDoublePrecision_ , parameters_ , parallelInformation_ , np ) ;
2015-10-07 10:48:27 -05:00
// compute newton increment
2015-10-08 07:04:05 -05:00
SolutionVector dx = newtonIncrement . computeNewtonIncrement ( residual ) ;
2015-10-07 10:48:27 -05:00
// get number of linear iterations
2015-10-08 07:04:05 -05:00
iterations_ = newtonIncrement . iterations ( ) ;
2016-09-26 02:33:13 -05:00
return dx ;
2015-06-16 03:18:11 -05:00
}
2015-06-01 06:33:37 -05:00
2015-10-07 10:48:27 -05:00
const boost : : any & NewtonIterationBlackoilInterleaved : : parallelInformation ( ) const
{
return parallelInformation_ ;
}
2015-06-01 06:33:37 -05:00
} // namespace Opm