1
// Copyright (C) 2005 Johan Jansson.
2
// Licensed under the GNU LGPL Version 2.1.
4
// Modified by Anders Logg 2005-2006.
5
// Modified by Garth N. Wells 2005-2006.
7
// First added: 2005-12-02
8
// Last changed: 2007-07-31
12
#include <private/pcimpl.h>
14
#include <dolfin/dolfin_log.h>
15
#include <dolfin/PETScKrylovSolver.h>
17
#include <dolfin/PETScMatrix.h>
18
#include <dolfin/PETScVector.h>
19
#include <dolfin/PETScKrylovMatrix.h>
21
using namespace dolfin;
26
int monitor(KSP ksp, int iteration, real rnorm, void *mctx)
28
message("Iteration %d: residual = %g", iteration, rnorm);
33
//-----------------------------------------------------------------------------
34
PETScKrylovSolver::PETScKrylovSolver(KrylovMethod method, Preconditioner pc)
35
: PETScLinearSolver(),
36
method(method), pc_petsc(pc), pc_dolfin(0),
37
ksp(0), M(0), N(0), parameters_read(false), pc_set(false)
41
//-----------------------------------------------------------------------------
42
PETScKrylovSolver::PETScKrylovSolver(KrylovMethod method,
43
PETScPreconditioner& preconditioner)
44
: PETScLinearSolver(),
45
method(method), pc_petsc(default_pc), pc_dolfin(&preconditioner),
46
ksp(0), M(0), N(0), parameters_read(false), pc_set(false)
50
//-----------------------------------------------------------------------------
51
PETScKrylovSolver::~PETScKrylovSolver()
53
// Destroy solver environment.
54
if ( ksp ) KSPDestroy(ksp);
56
//-----------------------------------------------------------------------------
57
dolfin::uint PETScKrylovSolver::solve(const PETScMatrix& A, PETScVector& x, const PETScVector& b)
63
error("Non-matching dimensions for linear system.");
66
if ( get("Krylov report") )
67
message("Solving linear system of size %d x %d (Krylov solver).", M, N);
69
// Reinitialize KSP solver if necessary
72
// Reinitialize solution vector if necessary
75
// Read parameters if not done
76
if ( !parameters_read )
79
// Solve linear system
80
KSPSetOperators(ksp, A.mat(), A.mat(), SAME_NONZERO_PATTERN);
82
// FIXME: Preconditioner being set here to avoid PETSc bug with Hypre.
83
// See explanation inside PETScKrylovSolver:init().
86
setPETScPreconditioner();
90
KSPSolve(ksp, b.vec(), x.vec());
92
// Check if the solution converged
93
KSPConvergedReason reason;
94
KSPGetConvergedReason(ksp, &reason);
96
error("Krylov solver did not converge.");
98
// Get the number of iterations
99
int num_iterations = 0;
100
KSPGetIterationNumber(ksp, &num_iterations);
103
writeReport(num_iterations);
105
return num_iterations;
107
//-----------------------------------------------------------------------------
108
dolfin::uint PETScKrylovSolver::solve(const PETScKrylovMatrix& A, PETScVector& x, const PETScVector& b)
114
error("Non-matching dimensions for linear system.");
117
if ( get("Krylov report") )
118
message("Solving virtual linear system of size %d x %d (Krylov solver).", M, N);
120
// Reinitialize KSP solver if necessary
123
// Reinitialize solution vector if necessary
126
// Read parameters if not done
127
if ( !parameters_read )
130
// Don't use preconditioner that can't handle virtual (shell) matrix
135
PCSetType(pc, PCNONE);
138
// Solve linear system
139
KSPSetOperators(ksp, A.mat(), A.mat(), DIFFERENT_NONZERO_PATTERN);
140
KSPSolve(ksp, b.vec(), x.vec());
142
// Check if the solution converged
143
KSPConvergedReason reason;
144
KSPGetConvergedReason(ksp, &reason);
146
error("Krylov solver did not converge.");
148
// Get the number of iterations
149
int num_iterations = 0;
150
KSPGetIterationNumber(ksp, &num_iterations);
153
writeReport(num_iterations);
155
return num_iterations;
157
//-----------------------------------------------------------------------------
158
void PETScKrylovSolver::disp() const
160
KSPView(ksp, PETSC_VIEWER_STDOUT_WORLD);
162
//-----------------------------------------------------------------------------
163
void PETScKrylovSolver::init(uint M, uint N)
165
// Check if we need to reinitialize
166
if ( ksp != 0 && M == this->M && N == this->N )
169
// Save size of system
173
// Destroy old solver environment if necessary
177
// Set up solver environment
178
KSPCreate(PETSC_COMM_SELF, &ksp);
179
KSPSetFromOptions(ksp);
180
//KSPSetInitialGuessNonzero(ksp, PETSC_TRUE);
185
// FIXME: The preconditioner is being set in solve() due to a PETSc bug
186
// when using Hypre preconditioner. The problem can be avoided by
187
// setting the preconditioner after KSPSetOperators(). This will be
188
// fixed in PETSc, the the preconditioner can be set here again.
189
// Set preconditioner
190
// setPETScPreconditioner();
192
//-----------------------------------------------------------------------------
193
void PETScKrylovSolver::readParameters()
195
// Don't do anything if not initialized
200
if ( get("Krylov monitor convergence") )
201
KSPMonitorSet(ksp, monitor, 0, 0);
204
KSPSetTolerances(ksp,
205
get("Krylov relative tolerance"),
206
get("Krylov absolute tolerance"),
207
get("Krylov divergence limit"),
208
get("Krylov maximum iterations"));
210
// Set nonzero shift for preconditioner
215
PCFactorSetShiftNonzero(pc, get("Krylov shift nonzero"));
218
// Remember that we have read parameters
219
parameters_read = true;
221
//-----------------------------------------------------------------------------
222
void PETScKrylovSolver::setSolver()
224
// Don't do anything for default method
225
if ( method == default_method )
228
// Set PETSc Krylov solver
229
KSPType ksp_type = getType(method);
230
KSPSetType(ksp, ksp_type);
232
//-----------------------------------------------------------------------------
233
void PETScKrylovSolver::setPETScPreconditioner()
235
// Treat special case DOLFIN user-defined preconditioner
238
PETScPreconditioner::setup(ksp, *pc_dolfin);
242
// Treat special case default preconditioner (do nothing)
243
if ( pc_petsc == default_pc )
246
// Get PETSc PC pointer
250
// Treat special case Hypre AMG preconditioner
251
if ( pc_petsc == amg )
254
PCSetType(pc, PCHYPRE);
255
PCHYPRESetType(pc, "boomeramg");
257
warning("PETSc has not been compiled with the HYPRE library for "
258
"algerbraic multigrid. Default PETSc solver will be used. "
259
"For performance, installation of HYPRE is recommended. "
260
"See the DOLFIN user manual for more information.");
265
// Set preconditioner
266
PCSetType(pc, PETScPreconditioner::getType(pc_petsc));
268
//-----------------------------------------------------------------------------
269
void PETScKrylovSolver::writeReport(int num_iterations)
271
// Check if we should write the report
272
bool report = get("Krylov report");
276
// Get name of solver
278
KSPGetType(ksp, &ksp_type);
280
// Get name of preconditioner
284
PCGetType(pc, &pc_type);
286
// Report number of iterations and solver type
287
message("Krylov solver (%s, %s) converged in %d iterations.",
288
ksp_type, pc_type, num_iterations);
290
//-----------------------------------------------------------------------------
291
KSPType PETScKrylovSolver::getType(KrylovMethod method) const
304
warning("Requested Krylov method unknown. Using GMRES.");
308
//-----------------------------------------------------------------------------