xref: /petsc/src/ksp/ksp/impls/gmres/pgmres/pgmres.c (revision fad22124558c3e9d4037150e6d1a55fbc78e6dda)
1 
2 /*
3     This file implements PGMRES (a Pipelined Generalized Minimal Residual method)
4 */
5 
6 #include <../src/ksp/ksp/impls/gmres/pgmres/pgmresimpl.h>       /*I  "petscksp.h"  I*/
7 #define PGMRES_DELTA_DIRECTIONS 10
8 #define PGMRES_DEFAULT_MAXK     30
9 
10 static PetscErrorCode KSPPGMRESUpdateHessenberg(KSP,PetscInt,PetscBool*,PetscReal*);
11 static PetscErrorCode KSPPGMRESBuildSoln(PetscScalar*,Vec,Vec,KSP,PetscInt);
12 
13 /*
14 
15     KSPSetUp_PGMRES - Sets up the workspace needed by pgmres.
16 
17     This is called once, usually automatically by KSPSolve() or KSPSetUp(),
18     but can be called directly by KSPSetUp().
19 
20 */
21 #undef __FUNCT__
22 #define __FUNCT__ "KSPSetUp_PGMRES"
23 static PetscErrorCode KSPSetUp_PGMRES(KSP ksp)
24 {
25   PetscErrorCode ierr;
26 
27   PetscFunctionBegin;
28   ierr = KSPSetUp_GMRES(ksp);CHKERRQ(ierr);
29   PetscFunctionReturn(0);
30 }
31 
32 /*
33 
34     KSPPGMRESCycle - Run pgmres, possibly with restart.  Return residual
35                   history if requested.
36 
37     input parameters:
38 .        pgmres  - structure containing parameters and work areas
39 
40     output parameters:
41 .        itcount - number of iterations used.  If null, ignored.
42 .        converged - 0 if not converged
43 
44     Notes:
45     On entry, the value in vector VEC_VV(0) should be
46     the initial residual.
47 
48 
49  */
50 #undef __FUNCT__
51 #define __FUNCT__ "KSPPGMRESCycle"
52 static PetscErrorCode KSPPGMRESCycle(PetscInt *itcount,KSP ksp)
53 {
54   KSP_PGMRES     *pgmres = (KSP_PGMRES*)(ksp->data);
55   PetscReal      res_norm,res,newnorm;
56   PetscErrorCode ierr;
57   PetscInt       it     = 0,j,k;
58   PetscBool      hapend = PETSC_FALSE;
59 
60   PetscFunctionBegin;
61   if (itcount) *itcount = 0;
62   ierr   = VecNormalize(VEC_VV(0),&res_norm);CHKERRQ(ierr);
63   res    = res_norm;
64   *RS(0) = res_norm;
65 
66   /* check for the convergence */
67   ierr       = PetscObjectTakeAccess(ksp);CHKERRQ(ierr);
68   ksp->rnorm = res;
69   ierr       = PetscObjectGrantAccess(ksp);CHKERRQ(ierr);
70   pgmres->it = it-2;
71   KSPLogResidualHistory(ksp,res);
72   ierr = KSPMonitor(ksp,ksp->its,res);CHKERRQ(ierr);
73   if (!res) {
74     ksp->reason = KSP_CONVERGED_ATOL;
75     ierr        = PetscInfo(ksp,"Converged due to zero residual norm on entry\n");CHKERRQ(ierr);
76     PetscFunctionReturn(0);
77   }
78 
79   ierr = (*ksp->converged)(ksp,ksp->its,res,&ksp->reason,ksp->cnvP);CHKERRQ(ierr);
80   for (; !ksp->reason; it++) {
81     Vec Zcur,Znext;
82     if (pgmres->vv_allocated <= it + VEC_OFFSET + 1) {
83       ierr = KSPGMRESGetNewVectors(ksp,it+1);CHKERRQ(ierr);
84     }
85     /* VEC_VV(it-1) is orthogonal, it will be normalized once the VecNorm arrives. */
86     Zcur  = VEC_VV(it);         /* Zcur is not yet orthogonal, but the VecMDot to orthogonalize it has been started. */
87     Znext = VEC_VV(it+1);       /* This iteration will compute Znext, update with a deferred correction once we know how
88                                  * Zcur relates to the previous vectors, and start the reduction to orthogonalize it. */
89 
90     if (it < pgmres->max_k+1 && ksp->its+1 < PetscMax(2,ksp->max_it)) { /* We don't know whether what we have computed is enough, so apply the matrix. */
91       ierr = KSP_PCApplyBAorAB(ksp,Zcur,Znext,VEC_TEMP_MATOP);CHKERRQ(ierr);
92     }
93 
94     if (it > 1) {               /* Complete the pending reduction */
95       ierr           = VecNormEnd(VEC_VV(it-1),NORM_2,&newnorm);CHKERRQ(ierr);
96       *HH(it-1,it-2) = newnorm;
97     }
98     if (it > 0) {               /* Finish the reduction computing the latest column of H */
99       ierr = VecMDotEnd(Zcur,it,&(VEC_VV(0)),HH(0,it-1));CHKERRQ(ierr);
100     }
101 
102     if (it > 1) {
103       /* normalize the base vector from two iterations ago, basis is complete up to here */
104       ierr = VecScale(VEC_VV(it-1),1./ *HH(it-1,it-2));CHKERRQ(ierr);
105 
106       ierr       = KSPPGMRESUpdateHessenberg(ksp,it-2,&hapend,&res);CHKERRQ(ierr);
107       pgmres->it = it-2;
108       ksp->its++;
109       ksp->rnorm = res;
110 
111       ierr = (*ksp->converged)(ksp,ksp->its,res,&ksp->reason,ksp->cnvP);CHKERRQ(ierr);
112       if (it < pgmres->max_k+1 || ksp->reason || ksp->its == ksp->max_it) {  /* Monitor if we are done or still iterating, but not before a restart. */
113         KSPLogResidualHistory(ksp,res);
114         ierr = KSPMonitor(ksp,ksp->its,res);CHKERRQ(ierr);
115       }
116       if (ksp->reason) break;
117       /* Catch error in happy breakdown and signal convergence and break from loop */
118       if (hapend) SETERRQ1(((PetscObject)ksp)->comm,PETSC_ERR_PLIB,"You reached the happy break down, but convergence was not indicated. Residual norm = %G",res);
119       if (!(it < pgmres->max_k+1 && ksp->its < ksp->max_it)) break;
120 
121       /* The it-2 column of H was not scaled when we computed Zcur, apply correction */
122       ierr = VecScale(Zcur,1./ *HH(it-1,it-2));CHKERRQ(ierr);
123       /* And Znext computed in this iteration was computed using the under-scaled Zcur */
124       ierr = VecScale(Znext,1./ *HH(it-1,it-2));CHKERRQ(ierr);
125 
126       /* In the previous iteration, we projected an unnormalized Zcur against the Krylov basis, so we need to fix the column of H resulting from that projection. */
127       for (k=0; k<it; k++) *HH(k,it-1) /= *HH(it-1,it-2);
128       /* When Zcur was projected against the Krylov basis, VV(it-1) was still not normalized, so fix that too. This
129        * column is complete except for HH(it,it-1) which we won't know until the next iteration. */
130       *HH(it-1,it-1) /= *HH(it-1,it-2);
131     }
132 
133     if (it > 0) {
134       PetscScalar *work;
135       if (!pgmres->orthogwork) {ierr = PetscMalloc((pgmres->max_k + 2)*sizeof(PetscScalar),&pgmres->orthogwork);CHKERRQ(ierr);}
136       work = pgmres->orthogwork;
137       /* Apply correction computed by the VecMDot in the last iteration to Znext. The original form is
138        *
139        *   Znext -= sum_{j=0}^{i-1} Z[j+1] * H[j,i-1]
140        *
141        * where
142        *
143        *   Z[j] = sum_{k=0}^j V[k] * H[k,j-1]
144        *
145        * substituting
146        *
147        *   Znext -= sum_{j=0}^{i-1} sum_{k=0}^{j+1} V[k] * H[k,j] * H[j,i-1]
148        *
149        * rearranging the iteration space from row-column to column-row
150        *
151        *   Znext -= sum_{k=0}^i sum_{j=k-1}^{i-1} V[k] * H[k,j] * H[j,i-1]
152        *
153        * Note that column it-1 of HH is correct. For all previous columns, we must look at HES because HH has already
154        * been transformed to upper triangular form.
155        */
156       for (k=0; k<it+1; k++) {
157         work[k] = 0;
158         for (j=PetscMax(0,k-1); j<it-1; j++) work[k] -= *HES(k,j) * *HH(j,it-1);
159       }
160       ierr = VecMAXPY(Znext,it+1,work,&VEC_VV(0));CHKERRQ(ierr);
161       ierr = VecAXPY(Znext,-*HH(it-1,it-1),Zcur);CHKERRQ(ierr);
162 
163       /* Orthogonalize Zcur against existing basis vectors. */
164       for (k=0; k<it; k++) work[k] = -*HH(k,it-1);
165       ierr = VecMAXPY(Zcur,it,work,&VEC_VV(0));CHKERRQ(ierr);
166       /* Zcur is now orthogonal, and will be referred to as VEC_VV(it) again, though it is still not normalized. */
167       /* Begin computing the norm of the new vector, will be normalized after the MatMult in the next iteration. */
168       ierr = VecNormBegin(VEC_VV(it),NORM_2,&newnorm);CHKERRQ(ierr);
169     }
170 
171     /* Compute column of H (to the diagonal, but not the subdiagonal) to be able to orthogonalize the newest vector. */
172     ierr = VecMDotBegin(Znext,it+1,&VEC_VV(0),HH(0,it));CHKERRQ(ierr);
173 
174     /* Start an asynchronous split-mode reduction, the result of the MDot and Norm will be collected on the next iteration. */
175     ierr = PetscCommSplitReductionBegin(((PetscObject)Znext)->comm);CHKERRQ(ierr);
176   }
177 
178   if (itcount) *itcount = it-1; /* Number of iterations actually completed. */
179 
180   /*
181     Down here we have to solve for the "best" coefficients of the Krylov
182     columns, add the solution values together, and possibly unwind the
183     preconditioning from the solution
184    */
185   /* Form the solution (or the solution so far) */
186   ierr = KSPPGMRESBuildSoln(RS(0),ksp->vec_sol,ksp->vec_sol,ksp,it-2);CHKERRQ(ierr);
187   PetscFunctionReturn(0);
188 }
189 
190 /*
191     KSPSolve_PGMRES - This routine applies the PGMRES method.
192 
193 
194    Input Parameter:
195 .     ksp - the Krylov space object that was set to use pgmres
196 
197    Output Parameter:
198 .     outits - number of iterations used
199 
200 */
201 #undef __FUNCT__
202 #define __FUNCT__ "KSPSolve_PGMRES"
203 static PetscErrorCode KSPSolve_PGMRES(KSP ksp)
204 {
205   PetscErrorCode ierr;
206   PetscInt       its,itcount;
207   KSP_PGMRES     *pgmres    = (KSP_PGMRES*)ksp->data;
208   PetscBool      guess_zero = ksp->guess_zero;
209 
210   PetscFunctionBegin;
211   if (ksp->calc_sings && !pgmres->Rsvd) SETERRQ(((PetscObject)ksp)->comm,PETSC_ERR_ORDER,"Must call KSPSetComputeSingularValues() before KSPSetUp() is called");
212   ierr     = PetscObjectTakeAccess(ksp);CHKERRQ(ierr);
213   ksp->its = 0;
214   ierr     = PetscObjectGrantAccess(ksp);CHKERRQ(ierr);
215 
216   itcount     = 0;
217   ksp->reason = KSP_CONVERGED_ITERATING;
218   while (!ksp->reason) {
219     ierr     = KSPInitialResidual(ksp,ksp->vec_sol,VEC_TEMP,VEC_TEMP_MATOP,VEC_VV(0),ksp->vec_rhs);CHKERRQ(ierr);
220     ierr     = KSPPGMRESCycle(&its,ksp);CHKERRQ(ierr);
221     itcount += its;
222     if (itcount >= ksp->max_it) {
223       if (!ksp->reason) ksp->reason = KSP_DIVERGED_ITS;
224       break;
225     }
226     ksp->guess_zero = PETSC_FALSE; /* every future call to KSPInitialResidual() will have nonzero guess */
227   }
228   ksp->guess_zero = guess_zero; /* restore if user provided nonzero initial guess */
229   PetscFunctionReturn(0);
230 }
231 
232 #undef __FUNCT__
233 #define __FUNCT__ "KSPDestroy_PGMRES"
234 static PetscErrorCode KSPDestroy_PGMRES(KSP ksp)
235 {
236   PetscErrorCode ierr;
237 
238   PetscFunctionBegin;
239   ierr = KSPDestroy_GMRES(ksp);CHKERRQ(ierr);
240   PetscFunctionReturn(0);
241 }
242 
243 /*
244     KSPPGMRESBuildSoln - create the solution from the starting vector and the
245                       current iterates.
246 
247     Input parameters:
248         nrs - work area of size it + 1.
249         vguess  - index of initial guess
250         vdest - index of result.  Note that vguess may == vdest (replace
251                 guess with the solution).
252         it - HH upper triangular part is a block of size (it+1) x (it+1)
253 
254      This is an internal routine that knows about the PGMRES internals.
255  */
256 #undef __FUNCT__
257 #define __FUNCT__ "KSPPGMRESBuildSoln"
258 static PetscErrorCode KSPPGMRESBuildSoln(PetscScalar *nrs,Vec vguess,Vec vdest,KSP ksp,PetscInt it)
259 {
260   PetscScalar    tt;
261   PetscErrorCode ierr;
262   PetscInt       k,j;
263   KSP_PGMRES     *pgmres = (KSP_PGMRES*)(ksp->data);
264 
265   PetscFunctionBegin;
266   /* Solve for solution vector that minimizes the residual */
267 
268   if (it < 0) {                                 /* no pgmres steps have been performed */
269     ierr = VecCopy(vguess,vdest);CHKERRQ(ierr); /* VecCopy() is smart, exits immediately if vguess == vdest */
270     PetscFunctionReturn(0);
271   }
272 
273   /* solve the upper triangular system - RS is the right side and HH is
274      the upper triangular matrix  - put soln in nrs */
275   if (*HH(it,it) != 0.0) nrs[it] = *RS(it) / *HH(it,it);
276   else nrs[it] = 0.0;
277 
278   for (k=it-1; k>=0; k--) {
279     tt = *RS(k);
280     for (j=k+1; j<=it; j++) tt -= *HH(k,j) * nrs[j];
281     nrs[k] = tt / *HH(k,k);
282   }
283 
284   /* Accumulate the correction to the solution of the preconditioned problem in TEMP */
285   ierr = VecZeroEntries(VEC_TEMP);CHKERRQ(ierr);
286   ierr = VecMAXPY(VEC_TEMP,it+1,nrs,&VEC_VV(0));CHKERRQ(ierr);
287   ierr = KSPUnwindPreconditioner(ksp,VEC_TEMP,VEC_TEMP_MATOP);CHKERRQ(ierr);
288   /* add solution to previous solution */
289   if (vdest == vguess) {
290     ierr = VecAXPY(vdest,1.0,VEC_TEMP);CHKERRQ(ierr);
291   } else {
292     ierr = VecWAXPY(vdest,1.0,VEC_TEMP,vguess);CHKERRQ(ierr);
293   }
294   PetscFunctionReturn(0);
295 }
296 
297 /*
298 
299     KSPPGMRESUpdateHessenberg - Do the scalar work for the orthogonalization.
300                             Return new residual.
301 
302     input parameters:
303 
304 .        ksp -    Krylov space object
305 .        it  -    plane rotations are applied to the (it+1)th column of the
306                   modified hessenberg (i.e. HH(:,it))
307 .        hapend - PETSC_FALSE not happy breakdown ending.
308 
309     output parameters:
310 .        res - the new residual
311 
312  */
313 #undef __FUNCT__
314 #define __FUNCT__ "KSPPGMRESUpdateHessenberg"
315 /*
316 .  it - column of the Hessenberg that is complete, PGMRES is actually computing two columns ahead of this
317  */
318 static PetscErrorCode KSPPGMRESUpdateHessenberg(KSP ksp,PetscInt it,PetscBool *hapend,PetscReal *res)
319 {
320   PetscScalar    *hh,*cc,*ss,*rs;
321   PetscInt       j;
322   PetscReal      hapbnd;
323   KSP_PGMRES     *pgmres = (KSP_PGMRES*)(ksp->data);
324   PetscErrorCode ierr;
325 
326   PetscFunctionBegin;
327   hh = HH(0,it);   /* pointer to beginning of column to update */
328   cc = CC(0);      /* beginning of cosine rotations */
329   ss = SS(0);      /* beginning of sine rotations */
330   rs = RS(0);      /* right hand side of least squares system */
331 
332   /* The Hessenberg matrix is now correct through column it, save that form for possible spectral analysis */
333   for (j=0; j<=it+1; j++) *HES(j,it) = hh[j];
334 
335   /* check for the happy breakdown */
336   hapbnd = PetscMin(PetscAbsScalar(hh[it+1] / rs[it]),pgmres->haptol);
337   if (PetscAbsScalar(hh[it+1]) < hapbnd) {
338     ierr    = PetscInfo4(ksp,"Detected happy breakdown, current hapbnd = %14.12e H(%D,%D) = %14.12e\n",(double)hapbnd,it+1,it,(double)PetscAbsScalar(*HH(it+1,it)));CHKERRQ(ierr);
339     *hapend = PETSC_TRUE;
340   }
341 
342   /* Apply all the previously computed plane rotations to the new column
343      of the Hessenberg matrix */
344   /* Note: this uses the rotation [conj(c)  s ; -s   c], c= cos(theta), s= sin(theta),
345      and some refs have [c   s ; -conj(s)  c] (don't be confused!) */
346 
347   for (j=0; j<it; j++) {
348     PetscScalar hhj = hh[j];
349     hh[j]   = PetscConj(cc[j])*hhj + ss[j]*hh[j+1];
350     hh[j+1] =          -ss[j] *hhj + cc[j]*hh[j+1];
351   }
352 
353   /*
354     compute the new plane rotation, and apply it to:
355      1) the right-hand-side of the Hessenberg system (RS)
356         note: it affects RS(it) and RS(it+1)
357      2) the new column of the Hessenberg matrix
358         note: it affects HH(it,it) which is currently pointed to
359         by hh and HH(it+1, it) (*(hh+1))
360     thus obtaining the updated value of the residual...
361   */
362 
363   /* compute new plane rotation */
364 
365   if (!*hapend) {
366     PetscReal delta = PetscSqrtReal(PetscSqr(PetscAbsScalar(hh[it])) + PetscSqr(PetscAbsScalar(hh[it+1])));
367     if (delta == 0.0) {
368       ksp->reason = KSP_DIVERGED_NULL;
369       PetscFunctionReturn(0);
370     }
371 
372     cc[it] = hh[it] / delta;    /* new cosine value */
373     ss[it] = hh[it+1] / delta;  /* new sine value */
374 
375     hh[it]   = PetscConj(cc[it])*hh[it] + ss[it]*hh[it+1];
376     rs[it+1] = -ss[it]*rs[it];
377     rs[it]   = PetscConj(cc[it])*rs[it];
378     *res     = PetscAbsScalar(rs[it+1]);
379   } else { /* happy breakdown: HH(it+1, it) = 0, therefore we don't need to apply
380             another rotation matrix (so RH doesn't change).  The new residual is
381             always the new sine term times the residual from last time (RS(it)),
382             but now the new sine rotation would be zero...so the residual should
383             be zero...so we will multiply "zero" by the last residual.  This might
384             not be exactly what we want to do here -could just return "zero". */
385 
386     *res = 0.0;
387   }
388   PetscFunctionReturn(0);
389 }
390 
391 /*
392    KSPBuildSolution_PGMRES
393 
394      Input Parameter:
395 .     ksp - the Krylov space object
396 .     ptr-
397 
398    Output Parameter:
399 .     result - the solution
400 
401    Note: this calls KSPPGMRESBuildSoln - the same function that KSPPGMRESCycle
402    calls directly.
403 
404 */
405 #undef __FUNCT__
406 #define __FUNCT__ "KSPBuildSolution_PGMRES"
407 PetscErrorCode KSPBuildSolution_PGMRES(KSP ksp,Vec ptr,Vec *result)
408 {
409   KSP_PGMRES     *pgmres = (KSP_PGMRES*)ksp->data;
410   PetscErrorCode ierr;
411 
412   PetscFunctionBegin;
413   if (!ptr) {
414     if (!pgmres->sol_temp) {
415       ierr = VecDuplicate(ksp->vec_sol,&pgmres->sol_temp);CHKERRQ(ierr);
416       ierr = PetscLogObjectParent(ksp,pgmres->sol_temp);CHKERRQ(ierr);
417     }
418     ptr = pgmres->sol_temp;
419   }
420   if (!pgmres->nrs) {
421     /* allocate the work area */
422     ierr = PetscMalloc(pgmres->max_k*sizeof(PetscScalar),&pgmres->nrs);CHKERRQ(ierr);
423     ierr = PetscLogObjectMemory(ksp,pgmres->max_k*sizeof(PetscScalar));CHKERRQ(ierr);
424   }
425 
426   ierr = KSPPGMRESBuildSoln(pgmres->nrs,ksp->vec_sol,ptr,ksp,pgmres->it);CHKERRQ(ierr);
427   if (result) *result = ptr;
428   PetscFunctionReturn(0);
429 }
430 
431 #undef __FUNCT__
432 #define __FUNCT__ "KSPSetFromOptions_PGMRES"
433 PetscErrorCode KSPSetFromOptions_PGMRES(KSP ksp)
434 {
435   PetscErrorCode ierr;
436 
437   PetscFunctionBegin;
438   ierr = KSPSetFromOptions_GMRES(ksp);CHKERRQ(ierr);
439   ierr = PetscOptionsHead("KSP pipelined GMRES Options");CHKERRQ(ierr);
440   ierr = PetscOptionsTail();CHKERRQ(ierr);
441   PetscFunctionReturn(0);
442 }
443 
444 #undef __FUNCT__
445 #define __FUNCT__ "KSPReset_PGMRES"
446 PetscErrorCode KSPReset_PGMRES(KSP ksp)
447 {
448   PetscErrorCode ierr;
449 
450   PetscFunctionBegin;
451   ierr = KSPReset_GMRES(ksp);CHKERRQ(ierr);
452   PetscFunctionReturn(0);
453 }
454 
455 /*MC
456      KSPPGMRES - Implements the Pipelined Generalized Minimal Residual method.
457 
458    Options Database Keys:
459 +   -ksp_gmres_restart <restart> - the number of Krylov directions to orthogonalize against
460 .   -ksp_gmres_haptol <tol> - sets the tolerance for "happy ending" (exact convergence)
461 .   -ksp_gmres_preallocate - preallocate all the Krylov search directions initially (otherwise groups of
462                              vectors are allocated as needed)
463 .   -ksp_gmres_classicalgramschmidt - use classical (unmodified) Gram-Schmidt to orthogonalize against the Krylov space (fast) (the default)
464 .   -ksp_gmres_modifiedgramschmidt - use modified Gram-Schmidt in the orthogonalization (more stable, but slower)
465 .   -ksp_gmres_cgs_refinement_type <never,ifneeded,always> - determine if iterative refinement is used to increase the
466                                    stability of the classical Gram-Schmidt  orthogonalization.
467 -   -ksp_gmres_krylov_monitor - plot the Krylov space generated
468 
469    Level: beginner
470 
471    Reference:
472    Ghysels, Ashby, Meerbergen, Vanroose, Hiding global communication latencies in the GMRES algorithm on massively parallel machines, 2012.
473 
474    Developer Notes: This object is subclassed off of KSPGMRES
475 
476 .seealso:  KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP, KSPGMRES, KSPLGMRES,
477            KSPGMRESSetRestart(), KSPGMRESSetHapTol(), KSPGMRESSetPreAllocateVectors(), KSPGMRESSetOrthogonalization(), KSPGMRESGetOrthogonalization(),
478            KSPGMRESClassicalGramSchmidtOrthogonalization(), KSPGMRESModifiedGramSchmidtOrthogonalization(),
479            KSPGMRESCGSRefinementType, KSPGMRESSetCGSRefinementType(),  KSPGMRESGetCGSRefinementType(), KSPGMRESMonitorKrylov()
480 M*/
481 
482 #undef __FUNCT__
483 #define __FUNCT__ "KSPCreate_PGMRES"
484 PETSC_EXTERN_C PetscErrorCode KSPCreate_PGMRES(KSP ksp)
485 {
486   KSP_PGMRES     *pgmres;
487   PetscErrorCode ierr;
488 
489   PetscFunctionBegin;
490   ierr = PetscNewLog(ksp,KSP_PGMRES,&pgmres);CHKERRQ(ierr);
491 
492   ksp->data                              = (void*)pgmres;
493   ksp->ops->buildsolution                = KSPBuildSolution_PGMRES;
494   ksp->ops->setup                        = KSPSetUp_PGMRES;
495   ksp->ops->solve                        = KSPSolve_PGMRES;
496   ksp->ops->reset                        = KSPReset_PGMRES;
497   ksp->ops->destroy                      = KSPDestroy_PGMRES;
498   ksp->ops->view                         = KSPView_GMRES;
499   ksp->ops->setfromoptions               = KSPSetFromOptions_PGMRES;
500   ksp->ops->computeextremesingularvalues = KSPComputeExtremeSingularValues_GMRES;
501   ksp->ops->computeeigenvalues           = KSPComputeEigenvalues_GMRES;
502 
503   ierr = KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,2);CHKERRQ(ierr);
504   ierr = KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_RIGHT,1);CHKERRQ(ierr);
505 
506   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPGMRESSetPreAllocateVectors_C",
507                                            "KSPGMRESSetPreAllocateVectors_GMRES",
508                                            KSPGMRESSetPreAllocateVectors_GMRES);CHKERRQ(ierr);
509   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPGMRESSetOrthogonalization_C",
510                                            "KSPGMRESSetOrthogonalization_GMRES",
511                                            KSPGMRESSetOrthogonalization_GMRES);CHKERRQ(ierr);
512   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPGMRESGetOrthogonalization_C",
513                                            "KSPGMRESGetOrthogonalization_GMRES",
514                                            KSPGMRESGetOrthogonalization_GMRES);CHKERRQ(ierr);
515   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPGMRESSetRestart_C",
516                                            "KSPGMRESSetRestart_GMRES",
517                                            KSPGMRESSetRestart_GMRES);CHKERRQ(ierr);
518   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPGMRESGetRestart_C",
519                                            "KSPGMRESGetRestart_GMRES",
520                                            KSPGMRESGetRestart_GMRES);CHKERRQ(ierr);
521   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPGMRESSetCGSRefinementType_C",
522                                            "KSPGMRESSetCGSRefinementType_GMRES",
523                                            KSPGMRESSetCGSRefinementType_GMRES);CHKERRQ(ierr);
524   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ksp,"KSPGMRESGetCGSRefinementType_C",
525                                            "KSPGMRESGetCGSRefinementType_GMRES",
526                                            KSPGMRESGetCGSRefinementType_GMRES);CHKERRQ(ierr);
527 
528   pgmres->nextra_vecs    = 1;
529   pgmres->haptol         = 1.0e-30;
530   pgmres->q_preallocate  = 0;
531   pgmres->delta_allocate = PGMRES_DELTA_DIRECTIONS;
532   pgmres->orthog         = KSPGMRESClassicalGramSchmidtOrthogonalization;
533   pgmres->nrs            = 0;
534   pgmres->sol_temp       = 0;
535   pgmres->max_k          = PGMRES_DEFAULT_MAXK;
536   pgmres->Rsvd           = 0;
537   pgmres->orthogwork     = 0;
538   pgmres->cgstype        = KSP_GMRES_CGS_REFINE_NEVER;
539   PetscFunctionReturn(0);
540 }
541