1 /*
2 This file implements GMRES (a Generalized Minimal Residual) method.
3 Reference: Saad and Schultz, 1986.
4
5 Some comments on left vs. right preconditioning, and restarts.
6 Left and right preconditioning.
7 If right preconditioning is chosen, then the problem being solved
8 by GMRES is actually
9 My = AB^-1 y = f
10 so the initial residual is
11 r = f - M y
12 Note that B^-1 y = x or y = B x, and if x is non-zero, the initial
13 residual is
14 r = f - A x
15 The final solution is then
16 x = B^-1 y
17
18 If left preconditioning is chosen, then the problem being solved is
19 My = B^-1 A x = B^-1 f,
20 and the initial residual is
21 r = B^-1(f - Ax)
22
23 Restarts: Restarts are basically solves with x0 not equal to zero.
24 Note that we can eliminate an extra application of B^-1 between
25 restarts as long as we don't require that the solution at the end
26 of an unsuccessful gmres iteration always be the solution x.
27 */
28
29 #include <../src/ksp/ksp/impls/gmres/gmresimpl.h> /*I "petscksp.h" I*/
30 #define GMRES_DELTA_DIRECTIONS 10
31 #define GMRES_DEFAULT_MAXK 30
32 static PetscErrorCode KSPGMRESUpdateHessenberg(KSP, PetscInt, PetscBool, PetscReal *);
33 static PetscErrorCode KSPGMRESBuildSoln(PetscScalar *, Vec, Vec, KSP, PetscInt);
34
KSPSetUp_GMRES(KSP ksp)35 PetscErrorCode KSPSetUp_GMRES(KSP ksp)
36 {
37 PetscInt hh, hes, rs, cc;
38 PetscInt max_k, k;
39 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
40
41 PetscFunctionBegin;
42 max_k = gmres->max_k; /* restart size */
43 hh = (max_k + 2) * (max_k + 1);
44 hes = (max_k + 1) * (max_k + 1);
45 rs = (max_k + 2);
46 cc = (max_k + 1);
47
48 PetscCall(PetscCalloc5(hh, &gmres->hh_origin, hes, &gmres->hes_origin, rs, &gmres->rs_origin, cc, &gmres->cc_origin, cc, &gmres->ss_origin));
49
50 if (ksp->calc_sings) {
51 /* Allocate workspace to hold Hessenberg matrix needed by LAPACK */
52 PetscCall(PetscMalloc1((max_k + 3) * (max_k + 9), &gmres->Rsvd));
53 PetscCall(PetscMalloc1(6 * (max_k + 2), &gmres->Dsvd));
54 }
55
56 /* Allocate array to hold pointers to user vectors. Note that we need
57 4 + max_k + 1 (since we need it+1 vectors, and it <= max_k) */
58 gmres->vecs_allocated = VEC_OFFSET + 2 + max_k + gmres->nextra_vecs;
59 PetscCall(PetscMalloc1(gmres->vecs_allocated, &gmres->vecs));
60 PetscCall(PetscMalloc1(VEC_OFFSET + 2 + max_k, &gmres->user_work));
61 PetscCall(PetscMalloc1(VEC_OFFSET + 2 + max_k, &gmres->mwork_alloc));
62 if (gmres->q_preallocate || ksp->normtype == KSP_NORM_NONE) gmres->vv_allocated = VEC_OFFSET + 2 + PetscMin(max_k, ksp->max_it);
63 else gmres->vv_allocated = VEC_OFFSET + 2 + PetscMin(PetscMin(5, max_k), ksp->max_it);
64 PetscCall(KSPCreateVecs(ksp, gmres->vv_allocated, &gmres->user_work[0], 0, NULL));
65 gmres->mwork_alloc[0] = gmres->vv_allocated;
66 gmres->nwork_alloc = 1;
67 for (k = 0; k < gmres->vv_allocated; k++) gmres->vecs[k] = gmres->user_work[0][k];
68 PetscFunctionReturn(PETSC_SUCCESS);
69 }
70
71 /*
72 Run gmres, possibly with restart. Return residual history if requested.
73 input parameters:
74
75 . gmres - structure containing parameters and work areas
76
77 output parameters:
78 . nres - residuals (from preconditioned system) at each step.
79 If restarting, consider passing nres+it. If null,
80 ignored
81 . itcount - number of iterations used. nres[0] to nres[itcount]
82 are defined. If null, ignored.
83
84 Notes:
85 On entry, the value in vector VEC_VV(0) should be the initial residual
86 (this allows shortcuts where the initial preconditioned residual is 0).
87 */
KSPGMRESCycle(PetscInt * itcount,KSP ksp)88 static PetscErrorCode KSPGMRESCycle(PetscInt *itcount, KSP ksp)
89 {
90 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
91 PetscReal res, hapbnd, tt;
92 PetscInt it = 0, max_k = gmres->max_k;
93 PetscBool hapend = PETSC_FALSE;
94
95 PetscFunctionBegin;
96 if (itcount) *itcount = 0;
97 PetscCall(VecNormalize(VEC_VV(0), &res));
98 KSPCheckNorm(ksp, res);
99
100 /* the constant .1 is arbitrary, just some measure at how incorrect the residuals are */
101 if ((ksp->rnorm > 0.0) && (PetscAbsReal(res - ksp->rnorm) > gmres->breakdowntol * gmres->rnorm0)) {
102 PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_CONV_FAILED, "Residual norm computed by GMRES recursion formula %g is far from the computed residual norm %g at restart, residual norm at start of cycle %g",
103 (double)ksp->rnorm, (double)res, (double)gmres->rnorm0);
104 PetscCall(PetscInfo(ksp, "Residual norm computed by GMRES recursion formula %g is far from the computed residual norm %g at restart, residual norm at start of cycle %g\n", (double)ksp->rnorm, (double)res, (double)gmres->rnorm0));
105 ksp->reason = KSP_DIVERGED_BREAKDOWN;
106 PetscFunctionReturn(PETSC_SUCCESS);
107 }
108 *GRS(0) = gmres->rnorm0 = res;
109
110 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
111 ksp->rnorm = res;
112 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
113 gmres->it = (it - 1);
114 PetscCall(KSPLogResidualHistory(ksp, res));
115 PetscCall(KSPLogErrorHistory(ksp));
116 PetscCall(KSPMonitor(ksp, ksp->its, res));
117 if (!res) {
118 ksp->reason = KSP_CONVERGED_ATOL;
119 PetscCall(PetscInfo(ksp, "Converged due to zero residual norm on entry\n"));
120 PetscFunctionReturn(PETSC_SUCCESS);
121 }
122
123 /* check for the convergence */
124 PetscCall((*ksp->converged)(ksp, ksp->its, res, &ksp->reason, ksp->cnvP));
125 while (!ksp->reason && it < max_k && ksp->its < ksp->max_it) {
126 if (it) {
127 PetscCall(KSPLogResidualHistory(ksp, res));
128 PetscCall(KSPLogErrorHistory(ksp));
129 PetscCall(KSPMonitor(ksp, ksp->its, res));
130 }
131 gmres->it = (it - 1);
132 if (gmres->vv_allocated <= it + VEC_OFFSET + 1) PetscCall(KSPGMRESGetNewVectors(ksp, it + 1));
133 PetscCall(KSP_PCApplyBAorAB(ksp, VEC_VV(it), VEC_VV(1 + it), VEC_TEMP_MATOP));
134
135 /* update Hessenberg matrix and do Gram-Schmidt */
136 PetscCall((*gmres->orthog)(ksp, it));
137 if (ksp->reason) break;
138
139 /* vv(i+1) . vv(i+1) */
140 PetscCall(VecNormalize(VEC_VV(it + 1), &tt));
141 KSPCheckNorm(ksp, tt);
142
143 /* save the magnitude */
144 *HH(it + 1, it) = tt;
145 *HES(it + 1, it) = tt;
146
147 /* check for the happy breakdown */
148 hapbnd = PetscAbsScalar(tt / *GRS(it));
149 if (hapbnd > gmres->haptol) hapbnd = gmres->haptol;
150 if (tt < hapbnd) {
151 PetscCall(PetscInfo(ksp, "Detected happy ending, current hapbnd = %14.12e tt = %14.12e\n", (double)hapbnd, (double)tt));
152 hapend = PETSC_TRUE;
153 }
154 PetscCall(KSPGMRESUpdateHessenberg(ksp, it, hapend, &res));
155
156 it++;
157 gmres->it = (it - 1); /* For converged */
158 ksp->its++;
159 ksp->rnorm = res;
160 if (ksp->reason) break;
161
162 PetscCall((*ksp->converged)(ksp, ksp->its, res, &ksp->reason, ksp->cnvP));
163
164 /* Catch error in happy breakdown and signal convergence and break from loop */
165 if (hapend) {
166 if (ksp->normtype == KSP_NORM_NONE) { /* convergence test was skipped in this case */
167 ksp->reason = KSP_CONVERGED_HAPPY_BREAKDOWN;
168 } else if (!ksp->reason) {
169 PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "Reached happy break down, but convergence was not indicated. Residual norm = %g", (double)res);
170 ksp->reason = KSP_DIVERGED_BREAKDOWN;
171 break;
172 }
173 }
174 }
175
176 if (itcount) *itcount = it;
177
178 /*
179 Down here we have to solve for the "best" coefficients of the Krylov
180 columns, add the solution values together, and possibly unwind the
181 preconditioning from the solution
182 */
183 /* Form the solution (or the solution so far) */
184 PetscCall(KSPGMRESBuildSoln(GRS(0), ksp->vec_sol, ksp->vec_sol, ksp, it - 1));
185
186 /* Monitor if we know that we will not return for a restart */
187 if (ksp->reason == KSP_CONVERGED_ITERATING && ksp->its >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
188 if (it && ksp->reason) {
189 PetscCall(KSPLogResidualHistory(ksp, res));
190 PetscCall(KSPLogErrorHistory(ksp));
191 PetscCall(KSPMonitor(ksp, ksp->its, res));
192 }
193 PetscFunctionReturn(PETSC_SUCCESS);
194 }
195
KSPSolve_GMRES(KSP ksp)196 static PetscErrorCode KSPSolve_GMRES(KSP ksp)
197 {
198 PetscInt its, itcount, i;
199 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
200 PetscBool guess_zero = ksp->guess_zero;
201 PetscInt N = gmres->max_k + 1;
202
203 PetscFunctionBegin;
204 PetscCheck(!ksp->calc_sings || gmres->Rsvd, PetscObjectComm((PetscObject)ksp), PETSC_ERR_ORDER, "Must call KSPSetComputeSingularValues() before KSPSetUp() is called");
205
206 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)ksp));
207 ksp->its = 0;
208 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)ksp));
209
210 itcount = 0;
211 gmres->fullcycle = 0;
212 ksp->rnorm = -1.0; /* special marker for KSPGMRESCycle() */
213 while (!ksp->reason || (ksp->rnorm == -1 && ksp->reason == KSP_DIVERGED_PC_FAILED)) {
214 PetscCall(KSPInitialResidual(ksp, ksp->vec_sol, VEC_TEMP, VEC_TEMP_MATOP, VEC_VV(0), ksp->vec_rhs));
215 PetscCall(KSPGMRESCycle(&its, ksp));
216 /* Store the Hessenberg matrix and the basis vectors of the Krylov subspace
217 if the cycle is complete for the computation of the Ritz pairs */
218 if (its == gmres->max_k) {
219 gmres->fullcycle++;
220 if (ksp->calc_ritz) {
221 if (!gmres->hes_ritz) {
222 PetscCall(PetscMalloc1(N * N, &gmres->hes_ritz));
223 PetscCall(VecDuplicateVecs(VEC_VV(0), N, &gmres->vecb));
224 }
225 PetscCall(PetscArraycpy(gmres->hes_ritz, gmres->hes_origin, N * N));
226 for (i = 0; i < gmres->max_k + 1; i++) PetscCall(VecCopy(VEC_VV(i), gmres->vecb[i]));
227 }
228 }
229 itcount += its;
230 if (itcount >= ksp->max_it) {
231 if (!ksp->reason) ksp->reason = KSP_DIVERGED_ITS;
232 break;
233 }
234 ksp->guess_zero = PETSC_FALSE; /* every future call to KSPInitialResidual() will have nonzero guess */
235 }
236 ksp->guess_zero = guess_zero; /* restore if user provided nonzero initial guess */
237 PetscFunctionReturn(PETSC_SUCCESS);
238 }
239
KSPReset_GMRES(KSP ksp)240 PetscErrorCode KSPReset_GMRES(KSP ksp)
241 {
242 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
243 PetscInt i;
244
245 PetscFunctionBegin;
246 /* Free the Hessenberg matrices */
247 PetscCall(PetscFree5(gmres->hh_origin, gmres->hes_origin, gmres->rs_origin, gmres->cc_origin, gmres->ss_origin));
248 PetscCall(PetscFree(gmres->hes_ritz));
249
250 /* free work vectors */
251 PetscCall(PetscFree(gmres->vecs));
252 for (i = 0; i < gmres->nwork_alloc; i++) PetscCall(VecDestroyVecs(gmres->mwork_alloc[i], &gmres->user_work[i]));
253 gmres->nwork_alloc = 0;
254 if (gmres->vecb) PetscCall(VecDestroyVecs(gmres->max_k + 1, &gmres->vecb));
255
256 PetscCall(PetscFree(gmres->user_work));
257 PetscCall(PetscFree(gmres->mwork_alloc));
258 PetscCall(PetscFree(gmres->nrs));
259 PetscCall(VecDestroy(&gmres->sol_temp));
260 PetscCall(PetscFree(gmres->Rsvd));
261 PetscCall(PetscFree(gmres->Dsvd));
262 PetscCall(PetscFree(gmres->orthogwork));
263
264 gmres->vv_allocated = 0;
265 gmres->vecs_allocated = 0;
266 gmres->sol_temp = NULL;
267 PetscFunctionReturn(PETSC_SUCCESS);
268 }
269
KSPDestroy_GMRES(KSP ksp)270 PetscErrorCode KSPDestroy_GMRES(KSP ksp)
271 {
272 PetscFunctionBegin;
273 PetscCall(KSPReset_GMRES(ksp));
274 PetscCall(PetscFree(ksp->data));
275 /* clear composed functions */
276 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetPreAllocateVectors_C", NULL));
277 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetOrthogonalization_C", NULL));
278 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetOrthogonalization_C", NULL));
279 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetRestart_C", NULL));
280 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetRestart_C", NULL));
281 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetHapTol_C", NULL));
282 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetBreakdownTolerance_C", NULL));
283 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetCGSRefinementType_C", NULL));
284 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetCGSRefinementType_C", NULL));
285 PetscFunctionReturn(PETSC_SUCCESS);
286 }
287 /*
288 KSPGMRESBuildSoln - create the solution from the starting vector and the
289 current iterates.
290
291 Input parameters:
292 nrs - work area of size it + 1.
293 vs - index of initial guess
294 vdest - index of result. Note that vs may == vdest (replace
295 guess with the solution).
296
297 This is an internal routine that knows about the GMRES internals.
298 */
KSPGMRESBuildSoln(PetscScalar * nrs,Vec vs,Vec vdest,KSP ksp,PetscInt it)299 static PetscErrorCode KSPGMRESBuildSoln(PetscScalar *nrs, Vec vs, Vec vdest, KSP ksp, PetscInt it)
300 {
301 PetscScalar tt;
302 PetscInt ii, k, j;
303 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
304
305 PetscFunctionBegin;
306 /* Solve for solution vector that minimizes the residual */
307
308 /* If it is < 0, no gmres steps have been performed */
309 if (it < 0) {
310 PetscCall(VecCopy(vs, vdest)); /* VecCopy() is smart, exists immediately if vguess == vdest */
311 PetscFunctionReturn(PETSC_SUCCESS);
312 }
313 if (*HH(it, it) != 0.0) {
314 nrs[it] = *GRS(it) / *HH(it, it);
315 } else {
316 PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "You reached the break down in GMRES; HH(it,it) = 0");
317 ksp->reason = KSP_DIVERGED_BREAKDOWN;
318
319 PetscCall(PetscInfo(ksp, "Likely your matrix or preconditioner is singular. HH(it,it) is identically zero; it = %" PetscInt_FMT " GRS(it) = %g\n", it, (double)PetscAbsScalar(*GRS(it))));
320 PetscFunctionReturn(PETSC_SUCCESS);
321 }
322 for (ii = 1; ii <= it; ii++) {
323 k = it - ii;
324 tt = *GRS(k);
325 for (j = k + 1; j <= it; j++) tt = tt - *HH(k, j) * nrs[j];
326 if (*HH(k, k) == 0.0) {
327 PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "Likely your matrix or preconditioner is singular. HH(k,k) is identically zero; k = %" PetscInt_FMT, k);
328 ksp->reason = KSP_DIVERGED_BREAKDOWN;
329 PetscCall(PetscInfo(ksp, "Likely your matrix or preconditioner is singular. HH(k,k) is identically zero; k = %" PetscInt_FMT "\n", k));
330 PetscFunctionReturn(PETSC_SUCCESS);
331 }
332 nrs[k] = tt / *HH(k, k);
333 }
334
335 /* Accumulate the correction to the solution of the preconditioned problem in TEMP */
336 PetscCall(VecMAXPBY(VEC_TEMP, it + 1, nrs, 0, &VEC_VV(0)));
337
338 PetscCall(KSPUnwindPreconditioner(ksp, VEC_TEMP, VEC_TEMP_MATOP));
339 /* add solution to previous solution */
340 if (vdest != vs) PetscCall(VecCopy(vs, vdest));
341 PetscCall(VecAXPY(vdest, 1.0, VEC_TEMP));
342 PetscFunctionReturn(PETSC_SUCCESS);
343 }
344 /*
345 Do the scalar work for the orthogonalization. Return new residual norm.
346 */
KSPGMRESUpdateHessenberg(KSP ksp,PetscInt it,PetscBool hapend,PetscReal * res)347 static PetscErrorCode KSPGMRESUpdateHessenberg(KSP ksp, PetscInt it, PetscBool hapend, PetscReal *res)
348 {
349 PetscScalar *hh, *cc, *ss, tt;
350 PetscInt j;
351 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
352
353 PetscFunctionBegin;
354 hh = HH(0, it);
355 cc = CC(0);
356 ss = SS(0);
357
358 /* Apply all the previously computed plane rotations to the new column
359 of the Hessenberg matrix */
360 for (j = 1; j <= it; j++) {
361 tt = *hh;
362 *hh = PetscConj(*cc) * tt + *ss * *(hh + 1);
363 hh++;
364 *hh = *cc++ * *hh - (*ss++ * tt);
365 }
366
367 /*
368 compute the new plane rotation, and apply it to:
369 1) the right-hand side of the Hessenberg system
370 2) the new column of the Hessenberg matrix
371 thus obtaining the updated value of the residual
372 */
373 if (!hapend) {
374 tt = PetscSqrtScalar(PetscConj(*hh) * *hh + PetscConj(*(hh + 1)) * *(hh + 1));
375 if (tt == 0.0) {
376 PetscCheck(!ksp->errorifnotconverged, PetscObjectComm((PetscObject)ksp), PETSC_ERR_NOT_CONVERGED, "tt == 0.0");
377 ksp->reason = KSP_DIVERGED_NULL;
378 PetscFunctionReturn(PETSC_SUCCESS);
379 }
380 *cc = *hh / tt;
381 *ss = *(hh + 1) / tt;
382 *GRS(it + 1) = -(*ss * *GRS(it));
383 *GRS(it) = PetscConj(*cc) * *GRS(it);
384 *hh = PetscConj(*cc) * *hh + *ss * *(hh + 1);
385 *res = PetscAbsScalar(*GRS(it + 1));
386 } else {
387 /* happy breakdown: HH(it+1, it) = 0, therefore we don't need to apply
388 another rotation matrix (so RH doesn't change). The new residual is
389 always the new sine term times the residual from last time (GRS(it)),
390 but now the new sine rotation would be zero...so the residual should
391 be zero...so we will multiply "zero" by the last residual. This might
392 not be exactly what we want to do here -could just return "zero". */
393
394 *res = 0.0;
395 }
396 PetscFunctionReturn(PETSC_SUCCESS);
397 }
398 /*
399 This routine allocates more work vectors, starting from VEC_VV(it).
400 */
KSPGMRESGetNewVectors(KSP ksp,PetscInt it)401 PetscErrorCode KSPGMRESGetNewVectors(KSP ksp, PetscInt it)
402 {
403 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
404 PetscInt nwork = gmres->nwork_alloc, k, nalloc;
405
406 PetscFunctionBegin;
407 nalloc = PetscMin(ksp->max_it, gmres->delta_allocate);
408 /* Adjust the number to allocate to make sure that we don't exceed the
409 number of available slots */
410 if (it + VEC_OFFSET + nalloc >= gmres->vecs_allocated) nalloc = gmres->vecs_allocated - it - VEC_OFFSET;
411 if (!nalloc) PetscFunctionReturn(PETSC_SUCCESS);
412
413 gmres->vv_allocated += nalloc;
414
415 PetscCall(KSPCreateVecs(ksp, nalloc, &gmres->user_work[nwork], 0, NULL));
416
417 gmres->mwork_alloc[nwork] = nalloc;
418 for (k = 0; k < nalloc; k++) gmres->vecs[it + VEC_OFFSET + k] = gmres->user_work[nwork][k];
419 gmres->nwork_alloc++;
420 PetscFunctionReturn(PETSC_SUCCESS);
421 }
422
KSPBuildSolution_GMRES(KSP ksp,Vec ptr,Vec * result)423 static PetscErrorCode KSPBuildSolution_GMRES(KSP ksp, Vec ptr, Vec *result)
424 {
425 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
426
427 PetscFunctionBegin;
428 if (!ptr) {
429 if (!gmres->sol_temp) PetscCall(VecDuplicate(ksp->vec_sol, &gmres->sol_temp));
430 ptr = gmres->sol_temp;
431 }
432 if (!gmres->nrs) {
433 /* allocate the work area */
434 PetscCall(PetscMalloc1(gmres->max_k, &gmres->nrs));
435 }
436
437 PetscCall(KSPGMRESBuildSoln(gmres->nrs, ksp->vec_sol, ptr, ksp, gmres->it));
438 if (result) *result = ptr;
439 PetscFunctionReturn(PETSC_SUCCESS);
440 }
441
KSPView_GMRES(KSP ksp,PetscViewer viewer)442 PetscErrorCode KSPView_GMRES(KSP ksp, PetscViewer viewer)
443 {
444 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
445 const char *cstr;
446 PetscBool isascii, isstring;
447
448 PetscFunctionBegin;
449 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
450 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
451 if (gmres->orthog == KSPGMRESClassicalGramSchmidtOrthogonalization) {
452 switch (gmres->cgstype) {
453 case KSP_GMRES_CGS_REFINE_NEVER:
454 cstr = "classical (unmodified) Gram-Schmidt orthogonalization with no iterative refinement";
455 break;
456 case KSP_GMRES_CGS_REFINE_ALWAYS:
457 cstr = "classical (unmodified) Gram-Schmidt orthogonalization with one step of iterative refinement";
458 break;
459 case KSP_GMRES_CGS_REFINE_IFNEEDED:
460 cstr = "classical (unmodified) Gram-Schmidt orthogonalization with one step of iterative refinement when needed";
461 break;
462 default:
463 SETERRQ(PetscObjectComm((PetscObject)ksp), PETSC_ERR_ARG_OUTOFRANGE, "Unknown orthogonalization");
464 }
465 } else if (gmres->orthog == KSPGMRESModifiedGramSchmidtOrthogonalization) {
466 cstr = "modified Gram-Schmidt orthogonalization";
467 } else {
468 cstr = "unknown orthogonalization";
469 }
470 if (isascii) {
471 PetscCall(PetscViewerASCIIPrintf(viewer, " restart=%" PetscInt_FMT ", using %s\n", gmres->max_k, cstr));
472 PetscCall(PetscViewerASCIIPrintf(viewer, " happy breakdown tolerance=%g\n", (double)gmres->haptol));
473 } else if (isstring) {
474 PetscCall(PetscViewerStringSPrintf(viewer, "%s restart %" PetscInt_FMT, cstr, gmres->max_k));
475 }
476 PetscFunctionReturn(PETSC_SUCCESS);
477 }
478
479 /*@C
480 KSPGMRESMonitorKrylov - Calls `VecView()` to monitor each new direction in the `KSPGMRES` accumulated Krylov space.
481
482 Collective
483
484 Input Parameters:
485 + ksp - the `KSP` context
486 . its - iteration number
487 . fgnorm - 2-norm of residual (or gradient)
488 - Viewers - a collection of viewers created with `PetscViewersCreate()`
489
490 Options Database Key:
491 . -ksp_gmres_krylov_monitor <bool> - Plot the Krylov directions
492
493 Level: intermediate
494
495 Note:
496 A new `PETSCVIEWERDRAW` is created for each Krylov vector so they can all be simultaneously viewed
497
498 .seealso: [](ch_ksp), `KSPGMRES`, `KSPMonitorSet()`, `KSPMonitorResidual()`, `VecView()`, `PetscViewersCreate()`, `PetscViewersDestroy()`
499 @*/
KSPGMRESMonitorKrylov(KSP ksp,PetscInt its,PetscReal fgnorm,void * Viewers)500 PetscErrorCode KSPGMRESMonitorKrylov(KSP ksp, PetscInt its, PetscReal fgnorm, void *Viewers)
501 {
502 PetscViewers viewers = (PetscViewers)Viewers;
503 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
504 Vec x;
505 PetscViewer viewer;
506 PetscBool flg;
507
508 PetscFunctionBegin;
509 PetscCall(PetscViewersGetViewer(viewers, gmres->it + 1, &viewer));
510 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &flg));
511 if (!flg) {
512 PetscCall(PetscViewerSetType(viewer, PETSCVIEWERDRAW));
513 PetscCall(PetscViewerDrawSetInfo(viewer, NULL, "Krylov GMRES Monitor", PETSC_DECIDE, PETSC_DECIDE, 300, 300));
514 }
515 x = VEC_VV(gmres->it + 1);
516 PetscCall(VecView(x, viewer));
517 PetscFunctionReturn(PETSC_SUCCESS);
518 }
519
KSPSetFromOptions_GMRES(KSP ksp,PetscOptionItems PetscOptionsObject)520 PetscErrorCode KSPSetFromOptions_GMRES(KSP ksp, PetscOptionItems PetscOptionsObject)
521 {
522 PetscInt restart;
523 PetscReal haptol, breakdowntol;
524 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
525 PetscBool flg, set;
526
527 PetscFunctionBegin;
528 PetscOptionsHeadBegin(PetscOptionsObject, "KSP GMRES Options");
529 PetscCall(PetscOptionsInt("-ksp_gmres_restart", "Number of Krylov search directions", "KSPGMRESSetRestart", gmres->max_k, &restart, &flg));
530 if (flg) PetscCall(KSPGMRESSetRestart(ksp, restart));
531 PetscCall(PetscOptionsReal("-ksp_gmres_haptol", "Tolerance for exact convergence (happy ending)", "KSPGMRESSetHapTol", gmres->haptol, &haptol, &flg));
532 if (flg) PetscCall(KSPGMRESSetHapTol(ksp, haptol));
533 PetscCall(PetscOptionsReal("-ksp_gmres_breakdown_tolerance", "Divergence breakdown tolerance during GMRES restart", "KSPGMRESSetBreakdownTolerance", gmres->breakdowntol, &breakdowntol, &flg));
534 if (flg) PetscCall(KSPGMRESSetBreakdownTolerance(ksp, breakdowntol));
535 flg = PETSC_FALSE;
536 PetscCall(PetscOptionsBool("-ksp_gmres_preallocate", "Preallocate Krylov vectors", "KSPGMRESSetPreAllocateVectors", gmres->q_preallocate, &flg, &set));
537 PetscCheck(!set || flg, PetscObjectComm((PetscObject)ksp), PETSC_ERR_SUP, "Cannot turn off preallocation with -ksp_gmres_preallocate false");
538 if (set) PetscCall(KSPGMRESSetPreAllocateVectors(ksp));
539 PetscCall(PetscOptionsBoolGroupBegin("-ksp_gmres_classicalgramschmidt", "classical (unmodified) Gram-Schmidt (fast)", "KSPGMRESSetOrthogonalization", &flg));
540 if (flg) PetscCall(KSPGMRESSetOrthogonalization(ksp, KSPGMRESClassicalGramSchmidtOrthogonalization));
541 PetscCall(PetscOptionsBoolGroupEnd("-ksp_gmres_modifiedgramschmidt", "modified Gram-Schmidt (slow, more stable)", "KSPGMRESSetOrthogonalization", &flg));
542 if (flg) PetscCall(KSPGMRESSetOrthogonalization(ksp, KSPGMRESModifiedGramSchmidtOrthogonalization));
543 PetscCall(PetscOptionsEnum("-ksp_gmres_cgs_refinement_type", "Type of iterative refinement for classical (unmodified) Gram-Schmidt", "KSPGMRESSetCGSRefinementType", KSPGMRESCGSRefinementTypes, (PetscEnum)gmres->cgstype, (PetscEnum *)&gmres->cgstype, &flg));
544 flg = PETSC_FALSE;
545 PetscCall(PetscOptionsBool("-ksp_gmres_krylov_monitor", "Plot the Krylov directions", "KSPMonitorSet", flg, &flg, NULL));
546 if (flg) {
547 PetscViewers viewers;
548
549 PetscCall(PetscViewersCreate(PetscObjectComm((PetscObject)ksp), &viewers));
550 PetscCall(KSPMonitorSet(ksp, KSPGMRESMonitorKrylov, viewers, (PetscCtxDestroyFn *)PetscViewersDestroy));
551 }
552 PetscOptionsHeadEnd();
553 PetscFunctionReturn(PETSC_SUCCESS);
554 }
555
KSPGMRESSetHapTol_GMRES(KSP ksp,PetscReal tol)556 PetscErrorCode KSPGMRESSetHapTol_GMRES(KSP ksp, PetscReal tol)
557 {
558 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
559
560 PetscFunctionBegin;
561 PetscCheck(tol >= 0.0, PetscObjectComm((PetscObject)ksp), PETSC_ERR_ARG_OUTOFRANGE, "Tolerance must be non-negative");
562 gmres->haptol = tol;
563 PetscFunctionReturn(PETSC_SUCCESS);
564 }
565
KSPGMRESSetBreakdownTolerance_GMRES(KSP ksp,PetscReal tol)566 static PetscErrorCode KSPGMRESSetBreakdownTolerance_GMRES(KSP ksp, PetscReal tol)
567 {
568 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
569
570 PetscFunctionBegin;
571 if (tol == (PetscReal)PETSC_DEFAULT) {
572 gmres->breakdowntol = 0.1;
573 PetscFunctionReturn(PETSC_SUCCESS);
574 }
575 PetscCheck(tol >= 0.0, PetscObjectComm((PetscObject)ksp), PETSC_ERR_ARG_OUTOFRANGE, "Breakdown tolerance must be non-negative");
576 gmres->breakdowntol = tol;
577 PetscFunctionReturn(PETSC_SUCCESS);
578 }
579
KSPGMRESGetRestart_GMRES(KSP ksp,PetscInt * max_k)580 PetscErrorCode KSPGMRESGetRestart_GMRES(KSP ksp, PetscInt *max_k)
581 {
582 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
583
584 PetscFunctionBegin;
585 *max_k = gmres->max_k;
586 PetscFunctionReturn(PETSC_SUCCESS);
587 }
588
KSPGMRESSetRestart_GMRES(KSP ksp,PetscInt max_k)589 PetscErrorCode KSPGMRESSetRestart_GMRES(KSP ksp, PetscInt max_k)
590 {
591 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
592
593 PetscFunctionBegin;
594 PetscCheck(max_k >= 1, PetscObjectComm((PetscObject)ksp), PETSC_ERR_ARG_OUTOFRANGE, "Restart must be positive");
595 if (!ksp->setupstage) {
596 gmres->max_k = max_k;
597 } else if (gmres->max_k != max_k) {
598 gmres->max_k = max_k;
599 ksp->setupstage = KSP_SETUP_NEW;
600 /* free the data structures, then create them again */
601 PetscCall(KSPReset_GMRES(ksp));
602 }
603 PetscFunctionReturn(PETSC_SUCCESS);
604 }
605
KSPGMRESSetOrthogonalization_GMRES(KSP ksp,FCN fcn)606 PetscErrorCode KSPGMRESSetOrthogonalization_GMRES(KSP ksp, FCN fcn)
607 {
608 PetscFunctionBegin;
609 ((KSP_GMRES *)ksp->data)->orthog = fcn;
610 PetscFunctionReturn(PETSC_SUCCESS);
611 }
612
KSPGMRESGetOrthogonalization_GMRES(KSP ksp,FCN * fcn)613 PetscErrorCode KSPGMRESGetOrthogonalization_GMRES(KSP ksp, FCN *fcn)
614 {
615 PetscFunctionBegin;
616 *fcn = ((KSP_GMRES *)ksp->data)->orthog;
617 PetscFunctionReturn(PETSC_SUCCESS);
618 }
619
KSPGMRESSetPreAllocateVectors_GMRES(KSP ksp)620 PetscErrorCode KSPGMRESSetPreAllocateVectors_GMRES(KSP ksp)
621 {
622 KSP_GMRES *gmres;
623
624 PetscFunctionBegin;
625 gmres = (KSP_GMRES *)ksp->data;
626 gmres->q_preallocate = PETSC_TRUE;
627 PetscFunctionReturn(PETSC_SUCCESS);
628 }
629
KSPGMRESSetCGSRefinementType_GMRES(KSP ksp,KSPGMRESCGSRefinementType type)630 PetscErrorCode KSPGMRESSetCGSRefinementType_GMRES(KSP ksp, KSPGMRESCGSRefinementType type)
631 {
632 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
633
634 PetscFunctionBegin;
635 gmres->cgstype = type;
636 PetscFunctionReturn(PETSC_SUCCESS);
637 }
638
KSPGMRESGetCGSRefinementType_GMRES(KSP ksp,KSPGMRESCGSRefinementType * type)639 PetscErrorCode KSPGMRESGetCGSRefinementType_GMRES(KSP ksp, KSPGMRESCGSRefinementType *type)
640 {
641 KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
642
643 PetscFunctionBegin;
644 *type = gmres->cgstype;
645 PetscFunctionReturn(PETSC_SUCCESS);
646 }
647
648 /*@
649 KSPGMRESSetCGSRefinementType - Sets the type of iterative refinement to use
650 in the classical Gram-Schmidt orthogonalization used by `KSPGMRES` and other PETSc GMRES implementations.
651
652 Logically Collective
653
654 Input Parameters:
655 + ksp - the Krylov space solver context
656 - type - the type of refinement
657 .vb
658 KSP_GMRES_CGS_REFINE_NEVER
659 KSP_GMRES_CGS_REFINE_IFNEEDED
660 KSP_GMRES_CGS_REFINE_ALWAYS
661 .ve
662
663 Options Database Key:
664 . -ksp_gmres_cgs_refinement_type <refine_never,refine_ifneeded,refine_always> - refinement type
665
666 Level: intermediate
667
668 Notes:
669 The default is `KSP_GMRES_CGS_REFINE_NEVER`
670
671 For a very small set of problems not using refinement, that is `KSP_GMRES_CGS_REFINE_NEVER` may be unstable, thus causing `KSPSolve()`
672 to not converge.
673
674 .seealso: [](ch_ksp), `KSPGMRES`, `KSPGMRESSetOrthogonalization()`, `KSPGMRESCGSRefinementType`, `KSPGMRESClassicalGramSchmidtOrthogonalization()`, `KSPGMRESGetCGSRefinementType()`,
675 `KSPGMRESGetOrthogonalization()`
676 @*/
KSPGMRESSetCGSRefinementType(KSP ksp,KSPGMRESCGSRefinementType type)677 PetscErrorCode KSPGMRESSetCGSRefinementType(KSP ksp, KSPGMRESCGSRefinementType type)
678 {
679 PetscFunctionBegin;
680 PetscValidHeaderSpecific(ksp, KSP_CLASSID, 1);
681 PetscValidLogicalCollectiveEnum(ksp, type, 2);
682 PetscTryMethod(ksp, "KSPGMRESSetCGSRefinementType_C", (KSP, KSPGMRESCGSRefinementType), (ksp, type));
683 PetscFunctionReturn(PETSC_SUCCESS);
684 }
685
686 /*@
687 KSPGMRESGetCGSRefinementType - Gets the type of iterative refinement to use
688 in the classical Gram-Schmidt orthogonalization used by `KSPGMRES` and other PETSc GMRES implementations.
689
690 Not Collective
691
692 Input Parameter:
693 . ksp - the Krylov space solver context
694
695 Output Parameter:
696 . type - the type of refinement
697
698 Level: intermediate
699
700 .seealso: [](ch_ksp), `KSPGMRES`, `KSPGMRESSetOrthogonalization()`, `KSPGMRESCGSRefinementType`, `KSPGMRESClassicalGramSchmidtOrthogonalization()`, `KSPGMRESSetCGSRefinementType()`,
701 `KSPGMRESGetOrthogonalization()`
702 @*/
KSPGMRESGetCGSRefinementType(KSP ksp,KSPGMRESCGSRefinementType * type)703 PetscErrorCode KSPGMRESGetCGSRefinementType(KSP ksp, KSPGMRESCGSRefinementType *type)
704 {
705 PetscFunctionBegin;
706 PetscValidHeaderSpecific(ksp, KSP_CLASSID, 1);
707 PetscUseMethod(ksp, "KSPGMRESGetCGSRefinementType_C", (KSP, KSPGMRESCGSRefinementType *), (ksp, type));
708 PetscFunctionReturn(PETSC_SUCCESS);
709 }
710
711 /*@
712 KSPGMRESSetRestart - Sets number of iterations at which GMRES (`KSPGMRES`, `KSPFGMRES`, `KSPPGMRES`, `KSPAGMRES`, `KSPDGMRES`, `KSPPIPEFGMRES`,
713 and `KSPLGMRES`) restarts.
714
715 Logically Collective
716
717 Input Parameters:
718 + ksp - the Krylov space solver context
719 - restart - integer restart value, this corresponds to the number of iterations of GMRES to perform before restarting
720
721 Options Database Key:
722 . -ksp_gmres_restart <positive integer> - integer restart value
723
724 Level: intermediate
725
726 Notes:
727 The default value is 30.
728
729 GMRES builds a Krylov subspace of increasing size, where each new vector is orthogonalized against the previous ones using a Gram-Schmidt process.
730 As the size of the Krylov subspace grows, the computational cost and memory requirements increase. To mitigate this issue, GMRES methods
731 usually employ restart strategies, which involve periodically deleting the Krylov subspace and beginning to generate a new one. This can help reduce
732 the computational cost and memory usage while still maintaining convergence. The maximum size of the Krylov subspace, that is the maximum number
733 of vectors orthogonalized is called the `restart` parameter.
734
735 A larger restart parameter generally leads to faster convergence of GMRES but the memory usage is higher than with a smaller `restart` parameter,
736 as is the average time to perform each iteration. For more ill-conditioned problems a larger restart value may be necessary.
737
738 `KSPBCGS` has the advantage over `KSPGMRES` in that it does not explicitly store the Krylov space and thus does not require as much memory
739 as GMRES might need.
740
741 .seealso: [](ch_ksp), `KSPGMRES`, `KSPSetTolerances()`, `KSPGMRESSetOrthogonalization()`, `KSPGMRESSetPreAllocateVectors()`, `KSPGMRESGetRestart()`,
742 `KSPFGMRES`, `KSPLGMRES`, `KSPPGMRES`, `KSPAGMRES`, `KSPDGMRES`, `KSPPIPEFGMRES`
743 @*/
KSPGMRESSetRestart(KSP ksp,PetscInt restart)744 PetscErrorCode KSPGMRESSetRestart(KSP ksp, PetscInt restart)
745 {
746 PetscFunctionBegin;
747 PetscValidLogicalCollectiveInt(ksp, restart, 2);
748
749 PetscTryMethod(ksp, "KSPGMRESSetRestart_C", (KSP, PetscInt), (ksp, restart));
750 PetscFunctionReturn(PETSC_SUCCESS);
751 }
752
753 /*@
754 KSPGMRESGetRestart - Gets number of iterations at which GMRES (`KSPGMRES`, `KSPFGMRES`, `KSPPGMRES`, `KSPAGMRES`, `KSPDGMRES`, `KSPPIPEFGMRES`,
755 and `KSPLGMRES`) restarts.
756
757 Not Collective
758
759 Input Parameter:
760 . ksp - the Krylov space solver context
761
762 Output Parameter:
763 . restart - integer restart value
764
765 Level: intermediate
766
767 .seealso: [](ch_ksp), `KSPGMRES`, `KSPSetTolerances()`, `KSPGMRESSetOrthogonalization()`, `KSPGMRESSetPreAllocateVectors()`, `KSPGMRESSetRestart()`,
768 `KSPFGMRES`, `KSPLGMRES`, `KSPPGMRES`, `KSPAGMRES`, `KSPDGMRES`, `KSPPIPEFGMRES`
769 @*/
KSPGMRESGetRestart(KSP ksp,PetscInt * restart)770 PetscErrorCode KSPGMRESGetRestart(KSP ksp, PetscInt *restart)
771 {
772 PetscFunctionBegin;
773 PetscUseMethod(ksp, "KSPGMRESGetRestart_C", (KSP, PetscInt *), (ksp, restart));
774 PetscFunctionReturn(PETSC_SUCCESS);
775 }
776
777 /*@
778 KSPGMRESSetHapTol - Sets the tolerance for detecting a happy ending in GMRES (`KSPGMRES`, `KSPFGMRES` and `KSPLGMRES` and others)
779
780 Logically Collective
781
782 Input Parameters:
783 + ksp - the Krylov space solver context
784 - tol - the tolerance for detecting a happy ending
785
786 Options Database Key:
787 . -ksp_gmres_haptol <positive real value> - set tolerance for determining happy breakdown
788
789 Level: intermediate
790
791 Note:
792 Happy ending is the rare case in `KSPGMRES` where a very near zero matrix entry is generated in the upper Hessenberg matrix indicating
793 an 'exact' solution has been obtained. If you attempt more iterations after this point with GMRES unstable
794 things can happen.
795
796 The default tolerance value for detecting a happy ending with GMRES in PETSc is 1.0e-30.
797
798 .seealso: [](ch_ksp), `KSPGMRES`, `KSPSetTolerances()`
799 @*/
KSPGMRESSetHapTol(KSP ksp,PetscReal tol)800 PetscErrorCode KSPGMRESSetHapTol(KSP ksp, PetscReal tol)
801 {
802 PetscFunctionBegin;
803 PetscValidLogicalCollectiveReal(ksp, tol, 2);
804 PetscTryMethod(ksp, "KSPGMRESSetHapTol_C", (KSP, PetscReal), (ksp, tol));
805 PetscFunctionReturn(PETSC_SUCCESS);
806 }
807
808 /*@
809 KSPGMRESSetBreakdownTolerance - Sets the tolerance for determining divergence breakdown in `KSPGMRES` at restart.
810
811 Logically Collective
812
813 Input Parameters:
814 + ksp - the Krylov space solver context
815 - tol - the tolerance
816
817 Options Database Key:
818 . -ksp_gmres_breakdown_tolerance <positive real value> - set tolerance for determining divergence breakdown
819
820 Level: intermediate
821
822 Note:
823 Divergence breakdown occurs when the norm of the GMRES residual increases significantly at a restart.
824 This is defined to be $ | truenorm - gmresnorm | > tol * gmresnorm $ where $ gmresnorm $ is the norm computed
825 by the GMRES process at a restart iteration using the standard GMRES recursion formula and $ truenorm $ is computed after
826 the restart using the definition $ \| r \| = \| b - A x \|$.
827
828 Divergence breakdown stops the iterative solve with a `KSPConvergedReason` of `KSP_DIVERGED_BREAKDOWN` indicating the
829 GMRES solver has not converged.
830
831 Divergence breakdown can occur when there is an error (bug) in either the application of the matrix or the preconditioner,
832 or the preconditioner is extremely ill-conditioned.
833
834 The default is .1
835
836 .seealso: [](ch_ksp), `KSPGMRES`, `KSPSetTolerances()`, `KSPGMRESSetHapTol()`, `KSPConvergedReason`
837 @*/
KSPGMRESSetBreakdownTolerance(KSP ksp,PetscReal tol)838 PetscErrorCode KSPGMRESSetBreakdownTolerance(KSP ksp, PetscReal tol)
839 {
840 PetscFunctionBegin;
841 PetscValidLogicalCollectiveReal(ksp, tol, 2);
842 PetscTryMethod(ksp, "KSPGMRESSetBreakdownTolerance_C", (KSP, PetscReal), (ksp, tol));
843 PetscFunctionReturn(PETSC_SUCCESS);
844 }
845
846 /*MC
847 KSPGMRES - Implements the Generalized Minimal Residual method {cite}`saad.schultz:gmres` with restart for solving linear systems using `KSP`.
848
849 Options Database Keys:
850 + -ksp_gmres_restart <restart> - the number of Krylov directions to orthogonalize against
851 . -ksp_gmres_haptol <tol> - sets the tolerance for happy ending (exact convergence) of `KSPGMRES`
852 . -ksp_gmres_preallocate - preallocate all the Krylov search directions initially (otherwise groups of
853 vectors are allocated as needed), see `KSPGMRESSetPreAllocateVectors()`
854 . -ksp_gmres_classicalgramschmidt - use classical (unmodified) Gram-Schmidt to orthogonalize against
855 the Krylov space (fast) (the default)
856 . -ksp_gmres_modifiedgramschmidt - use modified Gram-Schmidt in the orthogonalization (more stable, but slower)
857 . -ksp_gmres_cgs_refinement_type <refine_never,refine_ifneeded,refine_always> - determine if iterative refinement is used to increase the
858 stability of the classical Gram-Schmidt orthogonalization.
859 - -ksp_gmres_krylov_monitor - plot the Krylov space generated
860
861 Level: beginner
862
863 Notes:
864 Left and right preconditioning are supported, but not symmetric preconditioning.
865
866 Using `KSPGMRESSetPreAllocateVectors()` or `-ksp_gmres_preallocate` can improve the efficiency of the orthogonalization step with certain vector implementations.
867
868 .seealso: [](ch_ksp), `KSPCreate()`, `KSPSetType()`, `KSPType`, `KSP`, `KSPFGMRES`, `KSPLGMRES`, `KSPPGMRES`, `KSPAGMRES`, `KSPDGMRES`, `KSPPIPEFGMRES`,
869 `KSPGMRESSetRestart()`, `KSPGMRESSetHapTol()`, `KSPGMRESSetPreAllocateVectors()`, `KSPGMRESSetOrthogonalization()`, `KSPGMRESGetOrthogonalization()`,
870 `KSPGMRESClassicalGramSchmidtOrthogonalization()`, `KSPGMRESModifiedGramSchmidtOrthogonalization()`,
871 `KSPGMRESCGSRefinementType`, `KSPGMRESSetCGSRefinementType()`, `KSPGMRESGetCGSRefinementType()`, `KSPGMRESMonitorKrylov()`, `KSPSetPCSide()`
872 M*/
873
KSPCreate_GMRES(KSP ksp)874 PETSC_EXTERN PetscErrorCode KSPCreate_GMRES(KSP ksp)
875 {
876 KSP_GMRES *gmres;
877
878 PetscFunctionBegin;
879 PetscCall(PetscNew(&gmres));
880 ksp->data = (void *)gmres;
881
882 PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_PRECONDITIONED, PC_LEFT, 4));
883 PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_UNPRECONDITIONED, PC_RIGHT, 3));
884 PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_PRECONDITIONED, PC_SYMMETRIC, 2));
885 PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NONE, PC_RIGHT, 1));
886 PetscCall(KSPSetSupportedNorm(ksp, KSP_NORM_NONE, PC_LEFT, 1));
887
888 ksp->ops->buildsolution = KSPBuildSolution_GMRES;
889 ksp->ops->setup = KSPSetUp_GMRES;
890 ksp->ops->solve = KSPSolve_GMRES;
891 ksp->ops->reset = KSPReset_GMRES;
892 ksp->ops->destroy = KSPDestroy_GMRES;
893 ksp->ops->view = KSPView_GMRES;
894 ksp->ops->setfromoptions = KSPSetFromOptions_GMRES;
895 ksp->ops->computeextremesingularvalues = KSPComputeExtremeSingularValues_GMRES;
896 ksp->ops->computeeigenvalues = KSPComputeEigenvalues_GMRES;
897 ksp->ops->computeritz = KSPComputeRitz_GMRES;
898 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetPreAllocateVectors_C", KSPGMRESSetPreAllocateVectors_GMRES));
899 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetOrthogonalization_C", KSPGMRESSetOrthogonalization_GMRES));
900 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetOrthogonalization_C", KSPGMRESGetOrthogonalization_GMRES));
901 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetRestart_C", KSPGMRESSetRestart_GMRES));
902 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetRestart_C", KSPGMRESGetRestart_GMRES));
903 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetHapTol_C", KSPGMRESSetHapTol_GMRES));
904 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetBreakdownTolerance_C", KSPGMRESSetBreakdownTolerance_GMRES));
905 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESSetCGSRefinementType_C", KSPGMRESSetCGSRefinementType_GMRES));
906 PetscCall(PetscObjectComposeFunction((PetscObject)ksp, "KSPGMRESGetCGSRefinementType_C", KSPGMRESGetCGSRefinementType_GMRES));
907
908 gmres->haptol = 1.0e-30;
909 gmres->breakdowntol = 0.1;
910 gmres->q_preallocate = PETSC_FALSE;
911 gmres->delta_allocate = GMRES_DELTA_DIRECTIONS;
912 gmres->orthog = KSPGMRESClassicalGramSchmidtOrthogonalization;
913 gmres->nrs = NULL;
914 gmres->sol_temp = NULL;
915 gmres->max_k = GMRES_DEFAULT_MAXK;
916 gmres->Rsvd = NULL;
917 gmres->cgstype = KSP_GMRES_CGS_REFINE_NEVER;
918 gmres->orthogwork = NULL;
919 PetscFunctionReturn(PETSC_SUCCESS);
920 }
921