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