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: }