Actual source code: snesngmres.c

  1: #include <../src/snes/impls/ngmres/snesngmres.h>
  2: #include <petscblaslapack.h>
  3: #include <petscdm.h>

  5: const char *const SNESNGMRESRestartTypes[] = {"NONE", "PERIODIC", "DIFFERENCE", "SNESNGMRESRestartType", "SNES_NGMRES_RESTART_", NULL};
  6: const char *const SNESNGMRESSelectTypes[]  = {"NONE", "DIFFERENCE", "LINESEARCH", "SNESNGMRESSelectType", "SNES_NGMRES_SELECT_", NULL};

  8: PetscErrorCode SNESReset_NGMRES(SNES snes)
  9: {
 10:   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;

 12:   VecDestroyVecs(ngmres->msize, &ngmres->Fdot);
 13:   VecDestroyVecs(ngmres->msize, &ngmres->Xdot);
 14:   SNESLineSearchDestroy(&ngmres->additive_linesearch);
 15:   return 0;
 16: }

 18: PetscErrorCode SNESDestroy_NGMRES(SNES snes)
 19: {
 20:   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;

 22:   SNESReset_NGMRES(snes);
 23:   PetscFree4(ngmres->h, ngmres->beta, ngmres->xi, ngmres->q);
 24:   PetscFree3(ngmres->xnorms, ngmres->fnorms, ngmres->s);
 25: #if defined(PETSC_USE_COMPLEX)
 26:   PetscFree(ngmres->rwork);
 27: #endif
 28:   PetscFree(ngmres->work);
 29:   PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetSelectType_C", NULL);
 30:   PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartType_C", NULL);
 31:   PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", NULL);
 32:   PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", NULL);
 33:   PetscFree(snes->data);
 34:   return 0;
 35: }

 37: PetscErrorCode SNESSetUp_NGMRES(SNES snes)
 38: {
 39:   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
 40:   const char  *optionsprefix;
 41:   PetscInt     msize, hsize;
 42:   DM           dm;

 44:   if (snes->npc && snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
 45:     SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNESNGMRES does not support left preconditioning with unpreconditioned function");
 46:   }
 47:   if (snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED;
 48:   SNESSetWorkVecs(snes, 5);

 50:   if (!snes->vec_sol) {
 51:     SNESGetDM(snes, &dm);
 52:     DMCreateGlobalVector(dm, &snes->vec_sol);
 53:   }

 55:   if (!ngmres->Xdot) VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->Xdot);
 56:   if (!ngmres->Fdot) VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->Fdot);
 57:   if (!ngmres->setup_called) {
 58:     msize = ngmres->msize; /* restart size */
 59:     hsize = msize * msize;

 61:     /* explicit least squares minimization solve */
 62:     PetscCalloc4(hsize, &ngmres->h, msize, &ngmres->beta, msize, &ngmres->xi, hsize, &ngmres->q);
 63:     PetscMalloc3(msize, &ngmres->xnorms, msize, &ngmres->fnorms, msize, &ngmres->s);
 64:     ngmres->nrhs  = 1;
 65:     ngmres->lda   = msize;
 66:     ngmres->ldb   = msize;
 67:     ngmres->lwork = 12 * msize;
 68: #if defined(PETSC_USE_COMPLEX)
 69:     PetscMalloc1(ngmres->lwork, &ngmres->rwork);
 70: #endif
 71:     PetscMalloc1(ngmres->lwork, &ngmres->work);
 72:   }

 74:   /* linesearch setup */
 75:   SNESGetOptionsPrefix(snes, &optionsprefix);

 77:   if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
 78:     SNESLineSearchCreate(PetscObjectComm((PetscObject)snes), &ngmres->additive_linesearch);
 79:     SNESLineSearchSetSNES(ngmres->additive_linesearch, snes);
 80:     if (!((PetscObject)ngmres->additive_linesearch)->type_name) SNESLineSearchSetType(ngmres->additive_linesearch, SNESLINESEARCHL2);
 81:     SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, "additive_");
 82:     SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, optionsprefix);
 83:     SNESLineSearchSetFromOptions(ngmres->additive_linesearch);
 84:   }

 86:   ngmres->setup_called = PETSC_TRUE;
 87:   return 0;
 88: }

 90: PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes, PetscOptionItems *PetscOptionsObject)
 91: {
 92:   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
 93:   PetscBool    debug  = PETSC_FALSE;

 95:   PetscOptionsHeadBegin(PetscOptionsObject, "SNES NGMRES options");
 96:   PetscOptionsEnum("-snes_ngmres_select_type", "Select type", "SNESNGMRESSetSelectType", SNESNGMRESSelectTypes, (PetscEnum)ngmres->select_type, (PetscEnum *)&ngmres->select_type, NULL);
 97:   PetscOptionsEnum("-snes_ngmres_restart_type", "Restart type", "SNESNGMRESSetRestartType", SNESNGMRESRestartTypes, (PetscEnum)ngmres->restart_type, (PetscEnum *)&ngmres->restart_type, NULL);
 98:   PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage", "SNES", ngmres->candidate, &ngmres->candidate, NULL);
 99:   PetscOptionsBool("-snes_ngmres_approxfunc", "Linearly approximate the function", "SNES", ngmres->approxfunc, &ngmres->approxfunc, NULL);
100:   PetscOptionsInt("-snes_ngmres_m", "Number of directions", "SNES", ngmres->msize, &ngmres->msize, NULL);
101:   PetscOptionsInt("-snes_ngmres_restart", "Iterations before forced restart", "SNES", ngmres->restart_periodic, &ngmres->restart_periodic, NULL);
102:   PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart", "SNES", ngmres->restart_it, &ngmres->restart_it, NULL);
103:   PetscOptionsBool("-snes_ngmres_monitor", "Monitor actions of NGMRES", "SNES", ngmres->monitor ? PETSC_TRUE : PETSC_FALSE, &debug, NULL);
104:   if (debug) ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));
105:   PetscOptionsReal("-snes_ngmres_gammaA", "Residual selection constant", "SNES", ngmres->gammaA, &ngmres->gammaA, NULL);
106:   PetscOptionsReal("-snes_ngmres_gammaC", "Residual restart constant", "SNES", ngmres->gammaC, &ngmres->gammaC, NULL);
107:   PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, NULL);
108:   PetscOptionsReal("-snes_ngmres_deltaB", "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, NULL);
109:   PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions", "SNES", ngmres->singlereduction, &ngmres->singlereduction, NULL);
110:   PetscOptionsBool("-snes_ngmres_restart_fm_rise", "Restart on F_M residual rise", "SNESNGMRESSetRestartFmRise", ngmres->restart_fm_rise, &ngmres->restart_fm_rise, NULL);
111:   PetscOptionsHeadEnd();
112:   if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
113:   return 0;
114: }

116: PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer)
117: {
118:   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
119:   PetscBool    iascii;

121:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii);
122:   if (iascii) {
123:     PetscViewerASCIIPrintf(viewer, "  Number of stored past updates: %" PetscInt_FMT "\n", ngmres->msize);
124:     PetscViewerASCIIPrintf(viewer, "  Residual selection: gammaA=%1.0e, gammaC=%1.0e\n", (double)ngmres->gammaA, (double)ngmres->gammaC);
125:     PetscViewerASCIIPrintf(viewer, "  Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n", (double)ngmres->epsilonB, (double)ngmres->deltaB);
126:     PetscViewerASCIIPrintf(viewer, "  Restart on F_M residual increase: %s\n", PetscBools[ngmres->restart_fm_rise]);
127:   }
128:   return 0;
129: }

131: PetscErrorCode SNESSolve_NGMRES(SNES snes)
132: {
133:   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
134:   /* present solution, residual, and preconditioned residual */
135:   Vec X, F, B, D, Y;

137:   /* candidate linear combination answers */
138:   Vec XA, FA, XM, FM;

140:   /* coefficients and RHS to the minimization problem */
141:   PetscReal fnorm, fMnorm, fAnorm;
142:   PetscReal xnorm, xMnorm, xAnorm;
143:   PetscReal ynorm, yMnorm, yAnorm;
144:   PetscInt  k, k_restart, l, ivec, restart_count = 0;

146:   /* solution selection data */
147:   PetscBool selectRestart;
148:   /*
149:       These two variables are initialized to prevent compilers/analyzers from producing false warnings about these variables being passed
150:       to SNESNGMRESSelect_Private() without being set when SNES_NGMRES_RESTART_DIFFERENCE, the values are not used in the subroutines in that case
151:       so the code is correct as written.
152:   */
153:   PetscReal dnorm = 0.0, dminnorm = 0.0;
154:   PetscReal fminnorm;

156:   SNESConvergedReason  reason;
157:   SNESLineSearchReason lssucceed;


161:   PetscCitationsRegister(SNESCitation, &SNEScite);
162:   /* variable initialization */
163:   snes->reason = SNES_CONVERGED_ITERATING;
164:   X            = snes->vec_sol;
165:   F            = snes->vec_func;
166:   B            = snes->vec_rhs;
167:   XA           = snes->vec_sol_update;
168:   FA           = snes->work[0];
169:   D            = snes->work[1];

171:   /* work for the line search */
172:   Y  = snes->work[2];
173:   XM = snes->work[3];
174:   FM = snes->work[4];

176:   PetscObjectSAWsTakeAccess((PetscObject)snes);
177:   snes->iter = 0;
178:   snes->norm = 0.;
179:   PetscObjectSAWsGrantAccess((PetscObject)snes);

181:   /* initialization */

183:   if (snes->npc && snes->npcside == PC_LEFT) {
184:     SNESApplyNPC(snes, X, NULL, F);
185:     SNESGetConvergedReason(snes->npc, &reason);
186:     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
187:       snes->reason = SNES_DIVERGED_INNER;
188:       return 0;
189:     }
190:     VecNorm(F, NORM_2, &fnorm);
191:   } else {
192:     if (!snes->vec_func_init_set) {
193:       SNESComputeFunction(snes, X, F);
194:     } else snes->vec_func_init_set = PETSC_FALSE;

196:     VecNorm(F, NORM_2, &fnorm);
197:     SNESCheckFunctionNorm(snes, fnorm);
198:   }
199:   fminnorm = fnorm;

201:   PetscObjectSAWsTakeAccess((PetscObject)snes);
202:   snes->norm = fnorm;
203:   PetscObjectSAWsGrantAccess((PetscObject)snes);
204:   SNESLogConvergenceHistory(snes, fnorm, 0);
205:   SNESMonitor(snes, 0, fnorm);
206:   PetscUseTypeMethod(snes, converged, 0, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP);
207:   if (snes->reason) return 0;
208:   SNESNGMRESUpdateSubspace_Private(snes, 0, 0, F, fnorm, X);

210:   k_restart = 1;
211:   l         = 1;
212:   ivec      = 0;
213:   for (k = 1; k < snes->max_its + 1; k++) {
214:     /* Computation of x^M */
215:     if (snes->npc && snes->npcside == PC_RIGHT) {
216:       VecCopy(X, XM);
217:       SNESSetInitialFunction(snes->npc, F);

219:       PetscLogEventBegin(SNES_NPCSolve, snes->npc, XM, B, 0);
220:       SNESSolve(snes->npc, B, XM);
221:       PetscLogEventEnd(SNES_NPCSolve, snes->npc, XM, B, 0);

223:       SNESGetConvergedReason(snes->npc, &reason);
224:       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
225:         snes->reason = SNES_DIVERGED_INNER;
226:         return 0;
227:       }
228:       SNESGetNPCFunction(snes, FM, &fMnorm);
229:     } else {
230:       /* no preconditioner -- just take gradient descent with line search */
231:       VecCopy(F, Y);
232:       VecCopy(F, FM);
233:       VecCopy(X, XM);

235:       fMnorm = fnorm;

237:       SNESLineSearchApply(snes->linesearch, XM, FM, &fMnorm, Y);
238:       SNESLineSearchGetReason(snes->linesearch, &lssucceed);
239:       if (lssucceed) {
240:         if (++snes->numFailures >= snes->maxFailures) {
241:           snes->reason = SNES_DIVERGED_LINE_SEARCH;
242:           return 0;
243:         }
244:       }
245:     }

247:     SNESNGMRESFormCombinedSolution_Private(snes, ivec, l, XM, FM, fMnorm, X, XA, FA);
248:     /* r = F(x) */
249:     if (fminnorm > fMnorm) fminnorm = fMnorm; /* the minimum norm is now of F^M */

251:     /* differences for selection and restart */
252:     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
253:       SNESNGMRESNorms_Private(snes, l, X, F, XM, FM, XA, FA, D, &dnorm, &dminnorm, &xMnorm, NULL, &yMnorm, &xAnorm, &fAnorm, &yAnorm);
254:     } else {
255:       SNESNGMRESNorms_Private(snes, l, X, F, XM, FM, XA, FA, D, NULL, NULL, &xMnorm, NULL, &yMnorm, &xAnorm, &fAnorm, &yAnorm);
256:     }
257:     SNESCheckFunctionNorm(snes, fnorm);

259:     /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
260:     SNESNGMRESSelect_Private(snes, k_restart, XM, FM, xMnorm, fMnorm, yMnorm, XA, FA, xAnorm, fAnorm, yAnorm, dnorm, fminnorm, dminnorm, X, F, Y, &xnorm, &fnorm, &ynorm);
261:     selectRestart = PETSC_FALSE;

263:     if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) {
264:       SNESNGMRESSelectRestart_Private(snes, l, fMnorm, fAnorm, dnorm, fminnorm, dminnorm, &selectRestart);

266:       /* if the restart conditions persist for more than restart_it iterations, restart. */
267:       if (selectRestart) restart_count++;
268:       else restart_count = 0;
269:     } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) {
270:       if (k_restart > ngmres->restart_periodic) {
271:         if (ngmres->monitor) PetscViewerASCIIPrintf(ngmres->monitor, "periodic restart after %" PetscInt_FMT " iterations\n", k_restart);
272:         restart_count = ngmres->restart_it;
273:       }
274:     }

276:     ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */

278:     /* restart after restart conditions have persisted for a fixed number of iterations */
279:     if (restart_count >= ngmres->restart_it) {
280:       if (ngmres->monitor) PetscViewerASCIIPrintf(ngmres->monitor, "Restarted at iteration %" PetscInt_FMT "\n", k_restart);
281:       restart_count = 0;
282:       k_restart     = 1;
283:       l             = 1;
284:       ivec          = 0;
285:       /* q_{00} = nu */
286:       SNESNGMRESUpdateSubspace_Private(snes, 0, 0, FM, fMnorm, XM);
287:     } else {
288:       /* select the current size of the subspace */
289:       if (l < ngmres->msize) l++;
290:       k_restart++;
291:       /* place the current entry in the list of previous entries */
292:       if (ngmres->candidate) {
293:         if (fminnorm > fMnorm) fminnorm = fMnorm;
294:         SNESNGMRESUpdateSubspace_Private(snes, ivec, l, FM, fMnorm, XM);
295:       } else {
296:         if (fminnorm > fnorm) fminnorm = fnorm;
297:         SNESNGMRESUpdateSubspace_Private(snes, ivec, l, F, fnorm, X);
298:       }
299:     }

301:     PetscObjectSAWsTakeAccess((PetscObject)snes);
302:     snes->iter = k;
303:     snes->norm = fnorm;
304:     PetscObjectSAWsGrantAccess((PetscObject)snes);
305:     SNESLogConvergenceHistory(snes, snes->norm, snes->iter);
306:     SNESMonitor(snes, snes->iter, snes->norm);
307:     PetscUseTypeMethod(snes, converged, snes->iter, 0, 0, fnorm, &snes->reason, snes->cnvP);
308:     if (snes->reason) return 0;
309:   }
310:   snes->reason = SNES_DIVERGED_MAX_IT;
311:   return 0;
312: }

314: /*@
315:  SNESNGMRESSetRestartFmRise - Increase the restart count if the step x_M increases the residual F_M

317:    Input Parameters:
318: +  snes - the `SNES` context.
319: -  flg  - boolean value deciding whether to use the option or not, default is `PETSC_FALSE`

321:    Options Database Key:
322: .   -snes_ngmres_restart_fm_rise - Increase the restart count if the step x_M increases the residual F_M

324:    Level: intermediate

326:    Notes:
327:    If the proposed step x_M increases the residual F_M, it might be trying to get out of a stagnation area.
328:    To help the solver do that, reset the Krylov subspace whenever F_M increases.

330:    This option must be used with the `SNESNGMRES` `SNESNGMRESRestartType` of `SNES_NGMRES_RESTART_DIFFERENCE`

332: .seealso: `SNES_NGMRES_RESTART_DIFFERENCE`, `SNESNGMRES`, `SNESNGMRESRestartType`, `SNESNGMRESSetRestartType()`
333:   @*/
334: PetscErrorCode SNESNGMRESSetRestartFmRise(SNES snes, PetscBool flg)
335: {
336:   PetscErrorCode (*f)(SNES, PetscBool);

338:   PetscObjectQueryFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", &f);
339:   if (f) (f)(snes, flg);
340:   return 0;
341: }

343: PetscErrorCode SNESNGMRESSetRestartFmRise_NGMRES(SNES snes, PetscBool flg)
344: {
345:   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;

347:   ngmres->restart_fm_rise = flg;
348:   return 0;
349: }

351: PetscErrorCode SNESNGMRESGetRestartFmRise(SNES snes, PetscBool *flg)
352: {
353:   PetscErrorCode (*f)(SNES, PetscBool *);

355:   PetscObjectQueryFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", &f);
356:   if (f) (f)(snes, flg);
357:   return 0;
358: }

360: PetscErrorCode SNESNGMRESGetRestartFmRise_NGMRES(SNES snes, PetscBool *flg)
361: {
362:   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;

364:   *flg = ngmres->restart_fm_rise;
365:   return 0;
366: }

368: /*@
369:     SNESNGMRESSetRestartType - Sets the restart type for `SNESNGMRES`.

371:     Logically Collective

373:     Input Parameters:
374: +   snes - the iterative context
375: -   rtype - restart type

377:     Options Database Keys:
378: +   -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
379: -   -snes_ngmres_restart[30] - sets the number of iterations before restart for periodic

381:     `SNESNGMRESRestartType`s:
382: +   `SNES_NGMRES_RESTART_NONE` - never restart
383: .   `SNES_NGMRES_RESTART_DIFFERENCE` - restart based upon difference criteria
384: -   `SNES_NGMRES_RESTART_PERIODIC` - restart after a fixed number of iterations

386:     Level: intermediate

388: .seealso: `SNES_NGMRES_RESTART_DIFFERENCE`, `SNESNGMRES`, `SNESNGMRESRestartType`, `SNESNGMRESSetRestartFmRise()`
389: @*/
390: PetscErrorCode SNESNGMRESSetRestartType(SNES snes, SNESNGMRESRestartType rtype)
391: {
393:   PetscTryMethod(snes, "SNESNGMRESSetRestartType_C", (SNES, SNESNGMRESRestartType), (snes, rtype));
394:   return 0;
395: }

397: /*@
398:     SNESNGMRESSetSelectType - Sets the selection type for `SNESNGMRES`.  This determines how the candidate solution and
399:     combined solution are used to create the next iterate.

401:     Logically Collective

403:     Input Parameters:
404: +   snes - the iterative context
405: -   stype - selection type

407:     Options Database Key:
408: .   -snes_ngmres_select_type<difference,none,linesearch> - select type

410:     Level: intermediate

412:     `SNESNGMRESSelectType`s:
413: +   `SNES_NGMRES_SELECT_NONE` - choose the combined solution all the time
414: .   `SNES_NGMRES_SELECT_DIFFERENCE` - choose based upon the selection criteria
415: -   `SNES_NGMRES_SELECT_LINESEARCH` - choose based upon line search combination

417:     Note:
418:     The default line search used is the `SNESLINESEARCHL2` line search and it requires two additional function evaluations.

420: .seealso: `SNESNGMRESSelectType()`, `SNES_NGMRES_SELECT_NONE`, `SNES_NGMRES_SELECT_DIFFERENCE`, `SNES_NGMRES_SELECT_LINESEARCH`
421: @*/
422: PetscErrorCode SNESNGMRESSetSelectType(SNES snes, SNESNGMRESSelectType stype)
423: {
425:   PetscTryMethod(snes, "SNESNGMRESSetSelectType_C", (SNES, SNESNGMRESSelectType), (snes, stype));
426:   return 0;
427: }

429: PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes, SNESNGMRESSelectType stype)
430: {
431:   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;

433:   ngmres->select_type = stype;
434:   return 0;
435: }

437: PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes, SNESNGMRESRestartType rtype)
438: {
439:   SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;

441:   ngmres->restart_type = rtype;
442:   return 0;
443: }

445: /*MC
446:   SNESNGMRES - The Nonlinear Generalized Minimum Residual method.

448:    Level: beginner

450:    Options Database Keys:
451: +  -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
452: .  -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
453: .  -snes_ngmres_candidate        - Use `SNESNGMRES` variant which combines candidate solutions instead of actual solutions
454: .  -snes_ngmres_m                - Number of stored previous solutions and residuals
455: .  -snes_ngmres_restart_it       - Number of iterations the restart conditions hold before restart
456: .  -snes_ngmres_gammaA           - Residual tolerance for solution select between the candidate and combination
457: .  -snes_ngmres_gammaC           - Residual tolerance for restart
458: .  -snes_ngmres_epsilonB         - Difference tolerance between subsequent solutions triggering restart
459: .  -snes_ngmres_deltaB           - Difference tolerance between residuals triggering restart
460: .  -snes_ngmres_restart_fm_rise  - Restart on residual rise from x_M step
461: .  -snes_ngmres_monitor          - Prints relevant information about the ngmres iteration
462: .  -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother
463: -  -additive_snes_linesearch_type - linesearch type used to select between the candidate and combined solution with additive select type

465:    Notes:
466:    The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
467:    optimization problem at each iteration.

469:    Very similar to the `SNESANDERSON` algorithm.

471:    References:
472: +  * - C. W. Oosterlee and T. Washio, "Krylov Subspace Acceleration of Nonlinear Multigrid with Application to Recirculating Flows",
473:    SIAM Journal on Scientific Computing, 21(5), 2000.
474: -  * - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers",
475:    SIAM Review, 57(4), 2015

477: .seealso: `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESType`, `SNESANDERSON`, `SNESNGMRESSetSelectType()`, `SNESNGMRESSetRestartType()`,
478:           `SNESNGMRESSetRestartFmRise()`
479: M*/

481: PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes)
482: {
483:   SNES_NGMRES   *ngmres;
484:   SNESLineSearch linesearch;

486:   snes->ops->destroy        = SNESDestroy_NGMRES;
487:   snes->ops->setup          = SNESSetUp_NGMRES;
488:   snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
489:   snes->ops->view           = SNESView_NGMRES;
490:   snes->ops->solve          = SNESSolve_NGMRES;
491:   snes->ops->reset          = SNESReset_NGMRES;

493:   snes->usesnpc = PETSC_TRUE;
494:   snes->usesksp = PETSC_FALSE;
495:   snes->npcside = PC_RIGHT;

497:   snes->alwayscomputesfinalresidual = PETSC_TRUE;

499:   PetscNew(&ngmres);
500:   snes->data    = (void *)ngmres;
501:   ngmres->msize = 30;

503:   if (!snes->tolerancesset) {
504:     snes->max_funcs = 30000;
505:     snes->max_its   = 10000;
506:   }

508:   ngmres->candidate = PETSC_FALSE;

510:   SNESGetLineSearch(snes, &linesearch);
511:   if (!((PetscObject)linesearch)->type_name) SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC);

513:   ngmres->additive_linesearch = NULL;
514:   ngmres->approxfunc          = PETSC_FALSE;
515:   ngmres->restart_it          = 2;
516:   ngmres->restart_periodic    = 30;
517:   ngmres->gammaA              = 2.0;
518:   ngmres->gammaC              = 2.0;
519:   ngmres->deltaB              = 0.9;
520:   ngmres->epsilonB            = 0.1;
521:   ngmres->restart_fm_rise     = PETSC_FALSE;

523:   ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE;
524:   ngmres->select_type  = SNES_NGMRES_SELECT_DIFFERENCE;

526:   PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetSelectType_C", SNESNGMRESSetSelectType_NGMRES);
527:   PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartType_C", SNESNGMRESSetRestartType_NGMRES);
528:   PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", SNESNGMRESSetRestartFmRise_NGMRES);
529:   PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", SNESNGMRESGetRestartFmRise_NGMRES);
530:   return 0;
531: }