1#ifndef DUNE_FEM_PETSCINVERSEOPERATORS_HH
2#define DUNE_FEM_PETSCINVERSEOPERATORS_HH
6#include <dune/fem/function/common/scalarproducts.hh>
7#include <dune/fem/operator/common/operator.hh>
8#include <dune/fem/io/parameter.hh>
9#include <dune/fem/solver/inverseoperatorinterface.hh>
13#include <dune/fem/operator/linear/petscoperator.hh>
14#include <dune/fem/misc/petsc/petsccommon.hh>
15#include <dune/fem/function/petscdiscretefunction.hh>
16#include <dune/fem/solver/parameter.hh>
17#include <dune/fem/solver/petscavailable.hh>
35 template<
class DF,
class Op = Dune::Fem::Operator< DF, DF > >
36 class PetscInverseOperator;
38 template <
class DF,
class Op >
39 struct PetscInverseOperatorTraits
42 typedef typename DF :: DiscreteFunctionSpaceType
SpaceType ;
45 typedef Op OperatorType;
46 typedef OperatorType PreconditionerType;
47 typedef PetscDiscreteFunction< SpaceType > SolverDiscreteFunctionType;
48 typedef PetscLinearOperator< DF, DF > AssembledOperatorType;
50 typedef PetscSolverParameter SolverParameterType;
55 template<
class DF,
class Op >
56 class PetscInverseOperator
57 :
public InverseOperatorInterface< PetscInverseOperatorTraits< DF, Op > >,
58 public PetscInverseOperatorAvailable
63 monitor (KSP ksp, PetscInt it, PetscReal rnorm,
void *mctx)
67 std::cout <<
"PETSc::KSP: it = "
68 << std::setw(3) << std::left << it
69 <<
" res = " << rnorm << std::endl;
71 return PetscErrorCode(0);
77 void operator() ( KSP* p )
const
82 ::Dune::Petsc::KSPDestroy( p );
87 typedef PetscInverseOperatorTraits< DF, Op > Traits;
88 typedef InverseOperatorInterface< Traits > BaseType;
89 friend class InverseOperatorInterface< Traits >;
91 using PetscInverseOperatorAvailable::PetscSolver;
94 using PetscInverseOperatorAvailable::supportedSolverMethods;
95 using PetscInverseOperatorAvailable::supportedPreconditionMethods;
96 using PetscInverseOperatorAvailable::extraPreconditionMethods;
101 static const bool preconditioningAvailable =
false;
103 typedef typename BaseType :: SolverDiscreteFunctionType PetscDiscreteFunctionType;
104 typedef typename BaseType :: OperatorType OperatorType;
105 typedef typename BaseType :: PreconditionerType PreconditionerType;
107 PetscInverseOperator (
const PetscSolverParameter ¶meter = PetscSolverParameter(Parameter::container()) )
108 : BaseType( parameter )
111 PetscInverseOperator (
const OperatorType &op,
const PetscSolverParameter ¶meter = PetscSolverParameter(Parameter::container()) )
112 : BaseType( parameter )
117 void bind (
const OperatorType &op )
119 BaseType :: bind( op );
120 initialize( *parameter_ );
123 void bind (
const OperatorType &op,
const PreconditionerType& p )
125 DUNE_THROW(NotImplemented,
"PetscInverseOperator::bind: preconditioners cannot be set from outside!");
130 BaseType :: unbind();
134 void printTexInfo(std::ostream& out)
const
136 out <<
"Solver: " << solverName_ <<
" eps = " << parameter_->tolerance() ;
141 template <
class Reader>
142 bool parseAndSetOptions(
const Reader& reader,
const std::string& optionsKey)
const
144 if( reader.exists(optionsKey) )
146 std::string opts = reader.template getValue< std::string > (optionsKey);
148 std::stringstream options( opts );
155 while (! options.eof() )
165 if( key.length() == 0 )
170 if ( value.length() > 0 && value[0] ==
'-')
179 ::Dune::Petsc::PetscOptionsSetValue( key, value);
185 std::cout <<
"WARNING: 'kspoptions' selected but no options delivered with '" << optionsKey <<
"'!" << std::endl;
191 void initialize (
const PetscSolverParameter& parameter )
193 if( !assembledOperator_ )
194 DUNE_THROW(NotImplemented,
"Petsc solver with matrix free implementations not yet supported!");
197 ksp_.reset(
new KSP() );
198 const auto& comm = assembledOperator_->domainSpace().gridPart().comm();
200 ::Dune::Petsc::KSPCreate( comm, &ksp() );
203 Mat& A = assembledOperator_->exportMatrix();
204#if PETSC_VERSION_MAJOR <= 3 && PETSC_VERSION_MINOR < 5
205 ::Dune::Petsc::KSPSetOperators( ksp(), A, A, SAME_PRECONDITIONER);
207 ::Dune::Petsc::KSPSetOperators( ksp(), A, A );
211 ::Dune::Petsc::KSPSetInitialGuessNonzero( ksp(), PETSC_TRUE );
214 PetscInt maxits = parameter_->maxIterations();
215 PetscReal tolerance = parameter_->tolerance();
216 PetscReal omega = parameter_->relaxation();
217 if (parameter_->errorMeasure() == 0)
218 ::Dune::Petsc::KSPSetTolerances(ksp(), 1e-50, tolerance, PETSC_DEFAULT, maxits);
220 ::Dune::Petsc::KSPSetTolerances(ksp(), tolerance, 1e-50, PETSC_DEFAULT, maxits);
224 const auto& reader = parameter.parameter();
225 PetscSolver kspType = PetscSolver::gmres;
226 if( reader.exists(
"petsc.kspsolver.method") )
229 const std::string kspNames[] = {
"default",
"cg",
"bicgstab",
"gmres",
"minres",
"gradient",
"loop",
"superlu",
"bicg",
"preonly" };
230 kspType =
static_cast< PetscSolver
>( reader.getEnum(
"petsc.kspsolver.method", kspNames,
int(PetscSolver::gmres) ) );
231 std::cout <<
"WARNING: using deprecated parameter 'petsc.kpsolver.method' use "
232 << parameter.keyPrefix() <<
"method instead\n";
235 kspType =
static_cast< PetscSolver
>(
236 parameter.solverMethod (
237 supportedSolverMethods(), {
"kspoptions" } )
240 if (kspType > PetscSolver::kspoptions)
241 solverName_ = SolverParameter::solverMethodTable(
static_cast< int >( kspType ) );
243 solverName_ =
"kspoptions";
248 case PetscSolver::cg:
249 ::Dune::Petsc::KSPSetType( ksp(), KSPCG );
251 case PetscSolver::bicgstab:
252 ::Dune::Petsc::KSPSetType( ksp(), KSPBCGS );
254 case PetscSolver::gmres:
256 ::Dune::Petsc::KSPSetType( ksp(), KSPGMRES );
257 PetscInt restart = 10;
258 if( reader.exists(
"petsc.gmresrestart") )
260 restart = reader.getValue<
int>(
"petsc.gmresrestart", restart );
261 std::cout <<
"WARNING: using deprecated parameter 'petsc.gmresrestart' use "
262 << parameter.keyPrefix() <<
"gmres.restart instead\n";
265 restart = parameter.gmresRestart() ;
267 ::Dune::Petsc::KSPGMRESSetRestart( ksp(), restart );
270 case PetscSolver::minres:
271 ::Dune::Petsc::KSPSetType( ksp(), KSPMINRES );
273 case PetscSolver::bicg:
274 ::Dune::Petsc::KSPSetType( ksp(), KSPBICG );
276 case PetscSolver::preonly:
277 ::Dune::Petsc::KSPSetType( ksp(), KSPPREONLY );
279 case PetscSolver::kspoptions:
281 const std::string key = parameter.keyPrefix() +
"kspoptions";
282 const bool foundOptions = parseAndSetOptions( reader, key );
285 ::Dune::Petsc::KSPSetFromOptions( ksp() );
286 ::Dune::Petsc::KSPSetUp( ksp() );
290 ::Dune::Petsc::PetscOptionsClear();
296 DUNE_THROW(InvalidStateException,
"PetscInverseOperator: invalid solver choosen." );
298 if ( parameter_->knollTrick() )
300 ::Dune::Petsc::KSPSetInitialGuessKnoll( ksp(), PETSC_TRUE );
308 if( reader.exists(
"petsc.preconditioning.method") )
310 const std::string pcNames[] = {
"default",
"none",
"asm",
"sor",
"jacobi",
"ilu",
"icc",
"superlu",
"hypre",
"ml",
"lu" };
311 pcType = reader.getEnum(
"petsc.preconditioning.method", pcNames, 0 );
312 std::cout <<
"WARNING: using deprecated parameter 'petsc.preconditioning.method' use "
313 << parameter.keyPrefix() <<
".preconditioning.method instead\n";
319 pcType = parameter.preconditionMethod(
320 supportedPreconditionMethods(),
321 extraPreconditionMethods() );
326 ::Dune::Petsc::KSPGetPC( ksp(), &pc );
332 if ( kspType != PetscSolver::kspoptions )
334 const std::string key = parameter.keyPrefix() +
"kspoptions";
335 const bool foundOptions = parseAndSetOptions( reader, key );
338 ::Dune::Petsc::PCSetFromOptions( pc );
339 ::Dune::Petsc::PCSetUp( pc );
343 ::Dune::Petsc::PetscOptionsClear();
348 ::Dune::Petsc::PCSetType( pc, PCNONE );
350 case SolverParameter::oas:
352 ::Dune::Petsc::PCSetType( pc, PCASM );
353 ::Dune::Petsc::PCSetUp( pc );
356 case SolverParameter::gauss_seidel:
357 ::Dune::Petsc::PCSetType( pc, PCSOR );
358 ::Dune::Petsc::PCSORSetOmega( pc, 1.0 );
360 case SolverParameter::sor:
361 ::Dune::Petsc::PCSetType( pc, PCSOR );
362 ::Dune::Petsc::PCSORSetOmega( pc, omega );
364 case SolverParameter::ssor:
365 ::Dune::Petsc::PCSetType( pc, PCSOR );
367 ::Dune::Petsc::PCSORSetSymmetric( pc, SOR_LOCAL_SYMMETRIC_SWEEP );
368 ::Dune::Petsc::PCSORSetOmega( pc, omega );
370 case SolverParameter::jacobi:
371 ::Dune::Petsc::PCSetType( pc, PCJACOBI );
375#ifdef PETSC_HAVE_HYPRE
377 int hypreType = parameter.hypreMethod();
379 if ( hypreType == PetscSolverParameter::boomeramg )
381 else if ( hypreType == PetscSolverParameter::parasails )
383 else if ( hypreType == PetscSolverParameter::pilut )
386 DUNE_THROW( InvalidStateException,
"PetscInverseOperator: invalid hypre preconditioner choosen." );
388 ::Dune::Petsc::PCSetType( pc, PCHYPRE );
389 ::Dune::Petsc::PCHYPRESetType( pc, hypre.c_str() );
390 ::Dune::Petsc::PCSetUp( pc );
392 DUNE_THROW( InvalidStateException,
"PetscInverseOperator: petsc not build with hypre support." );
398 ::Dune::Petsc::PCSetType( pc, PCML );
400 DUNE_THROW( InvalidStateException,
"PetscInverseOperator: petsc not build with ml support." );
403 case SolverParameter::ilu:
405 if ( MPIManager::size() > 1 )
406 DUNE_THROW( InvalidStateException,
"PetscInverseOperator: ilu preconditioner does not work in parallel." );
410 if( reader.exists(
"petsc.preconditioning.levels") )
412 pcLevel = reader.getValue<
int>(
"petsc.preconditioning.levels", 0 );
413 std::cout <<
"WARNING: using deprecated parameter 'petsc.preconditioning.levels' use "
414 << parameter.keyPrefix() <<
"preconditioning.level instead\n";
417 pcLevel = parameter.preconditionerLevel() ;
419 ::Dune::Petsc::PCSetType( pc, PCILU );
420 ::Dune::Petsc::PCFactorSetLevels( pc, pcLevel );
423 ::Dune::Petsc::PCSetType( pc, PCML );
425 case SolverParameter::icc:
428 if ( MPIManager::size() > 1 )
429 DUNE_THROW( InvalidStateException,
"PetscInverseOperator: icc preconditioner does not worl in parallel." );
433 if( reader.exists(
"petsc.preconditioning.levels") )
435 pcLevel = reader.getValue<
int>(
"petsc.preconditioning.levels", 0 );
436 std::cout <<
"WARNING: using deprecated parameter 'petsc.preconditioning.levels' use "
437 << parameter.keyPrefix() <<
"preconditioning.level instead\n";
440 pcLevel = parameter.preconditionerLevel() ;
443 ::Dune::Petsc::PCSetType( pc, PCICC );
444 ::Dune::Petsc::PCFactorSetLevels( pc, pcLevel );
446 DUNE_THROW( InvalidStateException,
"PetscInverseOperator: petsc not build with icc support." );
451 case SolverParameter::superlu:
453 enum class Factorization { petsc = 0, superlu = 1, mumps = 2 };
454 Factorization factorType = Factorization::superlu;
455 if (pcType != SolverParameter::superlu)
456 factorType =
static_cast<Factorization
>(parameter.superluMethod());
458 ::Dune::Petsc::PCSetType( pc, PCLU );
460 if ( factorType == Factorization::petsc )
461 ::Dune::Petsc::PCFactorSetMatSolverPackage( pc, MATSOLVERPETSC );
462 else if ( factorType == Factorization::superlu )
463 ::Dune::Petsc::PCFactorSetMatSolverPackage( pc, MATSOLVERSUPERLU_DIST );
464 else if ( factorType == Factorization::mumps )
465 ::Dune::Petsc::PCFactorSetMatSolverPackage( pc, MATSOLVERMUMPS );
467 DUNE_THROW( InvalidStateException,
"PetscInverseOperator: invalid factorization package choosen." );
469 ::Dune::Petsc::PCSetUp( pc );
474 if( parameter.blockedMode() )
476 DUNE_THROW(NotImplemented,
"PetscInverseOperator: 'pcgamg' requires 'aij' matrix. Set 'petsc.blockedmode' to false!");
478 ::Dune::Petsc::PCSetType( pc, PCGAMG );
482 DUNE_THROW( InvalidStateException,
"PetscInverseOperator: invalid preconditioner choosen." );
491 ::Dune::Petsc::KSPView( comm, ksp() );
493 ::Dune::Petsc::KSPMonitorSet( ksp(), &monitor, PETSC_NULLPTR, PETSC_NULLPTR);
497 int apply(
const PetscDiscreteFunctionType& arg, PetscDiscreteFunctionType& dest )
const
500 if( dest.space().continuous() )
501 dest.dofVector().clearGhost();
504 ::Dune::Petsc::KSPSolve( *ksp_, *arg.petscVec() , *dest.petscVec() );
507 if( dest.space().continuous() )
514 ::Dune::Petsc::KSPGetIterationNumber( *ksp_, &its );
515 KSPConvergedReason reason;
516 ::Dune::Petsc::KSPGetConvergedReason( *ksp_, &reason );
518 bool converged = int(reason) >= 0 ;
525 std::cout <<
"Converged reason: ";
527 std::cout <<
"**Diverged** reason: ";
528 std::cout << reason <<
" linear iterations: " << its << std::endl;
531 return (converged) ? its : -its;
535 KSP & ksp () { assert( ksp_ );
return *ksp_; }
537 using BaseType :: assembledOperator_;
538 using BaseType :: parameter_;
539 using BaseType :: iterations_;
541 std::unique_ptr< KSP, KSPDeleter > ksp_;
543 std::string solverName_;
Inverse operator base on CG method. Uses a runtime parameter fem.preconditioning which enables diagon...
Definition: cginverseoperator.hh:408
A vector valued function space.
Definition: functionspace.hh:60
static bool verbose()
obtain the cached value for fem.verbose with default verbosity level 2
Definition: parameter.hh:466
forward declaration
Definition: discretefunction.hh:51
#define DUNE_THROW(E, m)
Definition: exceptions.hh:218
constexpr GeometryType none(unsigned int dim)
Returns a GeometryType representing a singular of dimension dim.
Definition: type.hh:471
Dune namespace.
Definition: alignedallocator.hh:13