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: PetscFunctionBegin;
13: PetscCall(VecDestroyVecs(ngmres->msize, &ngmres->Fdot));
14: PetscCall(VecDestroyVecs(ngmres->msize, &ngmres->Xdot));
15: PetscCall(SNESLineSearchDestroy(&ngmres->additive_linesearch));
16: PetscFunctionReturn(PETSC_SUCCESS);
17: }
19: PetscErrorCode SNESDestroy_NGMRES(SNES snes)
20: {
21: SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
23: PetscFunctionBegin;
24: PetscCall(SNESReset_NGMRES(snes));
25: PetscCall(PetscFree4(ngmres->h, ngmres->beta, ngmres->xi, ngmres->q));
26: PetscCall(PetscFree3(ngmres->xnorms, ngmres->fnorms, ngmres->s));
27: #if defined(PETSC_USE_COMPLEX)
28: PetscCall(PetscFree(ngmres->rwork));
29: #endif
30: PetscCall(PetscFree(ngmres->work));
31: PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetSelectType_C", NULL));
32: PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartType_C", NULL));
33: PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", NULL));
34: PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", NULL));
35: PetscCall(PetscFree(snes->data));
36: PetscFunctionReturn(PETSC_SUCCESS);
37: }
39: PetscErrorCode SNESSetUp_NGMRES(SNES snes)
40: {
41: SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
42: const char *optionsprefix;
43: PetscInt msize, hsize;
44: DM dm;
46: PetscFunctionBegin;
47: if (snes->npc && snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
48: SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNESNGMRES does not support left preconditioning with unpreconditioned function");
49: }
50: if (snes->npcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) snes->functype = SNES_FUNCTION_PRECONDITIONED;
51: PetscCall(SNESSetWorkVecs(snes, 5));
53: if (!snes->vec_sol) {
54: PetscCall(SNESGetDM(snes, &dm));
55: PetscCall(DMCreateGlobalVector(dm, &snes->vec_sol));
56: }
58: if (!ngmres->Xdot) PetscCall(VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->Xdot));
59: if (!ngmres->Fdot) PetscCall(VecDuplicateVecs(snes->vec_sol, ngmres->msize, &ngmres->Fdot));
60: if (!ngmres->setup_called) {
61: msize = ngmres->msize; /* restart size */
62: hsize = msize * msize;
64: /* explicit least squares minimization solve */
65: PetscCall(PetscCalloc4(hsize, &ngmres->h, msize, &ngmres->beta, msize, &ngmres->xi, hsize, &ngmres->q));
66: PetscCall(PetscMalloc3(msize, &ngmres->xnorms, msize, &ngmres->fnorms, msize, &ngmres->s));
67: ngmres->nrhs = 1;
68: ngmres->lda = msize;
69: ngmres->ldb = msize;
70: ngmres->lwork = 12 * msize;
71: #if defined(PETSC_USE_COMPLEX)
72: PetscCall(PetscMalloc1(ngmres->lwork, &ngmres->rwork));
73: #endif
74: PetscCall(PetscMalloc1(ngmres->lwork, &ngmres->work));
75: }
77: /* linesearch setup */
78: PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix));
80: if (ngmres->select_type == SNES_NGMRES_SELECT_LINESEARCH) {
81: PetscCall(SNESLineSearchCreate(PetscObjectComm((PetscObject)snes), &ngmres->additive_linesearch));
82: PetscCall(SNESLineSearchSetSNES(ngmres->additive_linesearch, snes));
83: if (!((PetscObject)ngmres->additive_linesearch)->type_name) PetscCall(SNESLineSearchSetType(ngmres->additive_linesearch, SNESLINESEARCHL2));
84: PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, "additive_"));
85: PetscCall(SNESLineSearchAppendOptionsPrefix(ngmres->additive_linesearch, optionsprefix));
86: PetscCall(SNESLineSearchSetFromOptions(ngmres->additive_linesearch));
87: }
89: ngmres->setup_called = PETSC_TRUE;
90: PetscFunctionReturn(PETSC_SUCCESS);
91: }
93: static PetscErrorCode SNESSetFromOptions_NGMRES(SNES snes, PetscOptionItems *PetscOptionsObject)
94: {
95: SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
96: PetscBool debug = PETSC_FALSE;
98: PetscFunctionBegin;
99: PetscOptionsHeadBegin(PetscOptionsObject, "SNES NGMRES options");
100: PetscCall(PetscOptionsEnum("-snes_ngmres_select_type", "Select type", "SNESNGMRESSetSelectType", SNESNGMRESSelectTypes, (PetscEnum)ngmres->select_type, (PetscEnum *)&ngmres->select_type, NULL));
101: PetscCall(PetscOptionsEnum("-snes_ngmres_restart_type", "Restart type", "SNESNGMRESSetRestartType", SNESNGMRESRestartTypes, (PetscEnum)ngmres->restart_type, (PetscEnum *)&ngmres->restart_type, NULL));
102: PetscCall(PetscOptionsBool("-snes_ngmres_candidate", "Use candidate storage", "SNES", ngmres->candidate, &ngmres->candidate, NULL));
103: PetscCall(PetscOptionsBool("-snes_ngmres_approxfunc", "Linearly approximate the function", "SNES", ngmres->approxfunc, &ngmres->approxfunc, NULL));
104: PetscCall(PetscOptionsInt("-snes_ngmres_m", "Number of directions", "SNES", ngmres->msize, &ngmres->msize, NULL));
105: PetscCall(PetscOptionsInt("-snes_ngmres_restart", "Iterations before forced restart", "SNES", ngmres->restart_periodic, &ngmres->restart_periodic, NULL));
106: PetscCall(PetscOptionsInt("-snes_ngmres_restart_it", "Tolerance iterations before restart", "SNES", ngmres->restart_it, &ngmres->restart_it, NULL));
107: PetscCall(PetscOptionsBool("-snes_ngmres_monitor", "Monitor actions of NGMRES", "SNES", ngmres->monitor ? PETSC_TRUE : PETSC_FALSE, &debug, NULL));
108: if (debug) ngmres->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));
109: PetscCall(PetscOptionsReal("-snes_ngmres_gammaA", "Residual selection constant", "SNES", ngmres->gammaA, &ngmres->gammaA, NULL));
110: PetscCall(PetscOptionsReal("-snes_ngmres_gammaC", "Residual restart constant", "SNES", ngmres->gammaC, &ngmres->gammaC, NULL));
111: PetscCall(PetscOptionsReal("-snes_ngmres_epsilonB", "Difference selection constant", "SNES", ngmres->epsilonB, &ngmres->epsilonB, NULL));
112: PetscCall(PetscOptionsReal("-snes_ngmres_deltaB", "Difference residual selection constant", "SNES", ngmres->deltaB, &ngmres->deltaB, NULL));
113: PetscCall(PetscOptionsBool("-snes_ngmres_single_reduction", "Aggregate reductions", "SNES", ngmres->singlereduction, &ngmres->singlereduction, NULL));
114: PetscCall(PetscOptionsBool("-snes_ngmres_restart_fm_rise", "Restart on F_M residual rise", "SNESNGMRESSetRestartFmRise", ngmres->restart_fm_rise, &ngmres->restart_fm_rise, NULL));
115: PetscOptionsHeadEnd();
116: if ((ngmres->gammaA > ngmres->gammaC) && (ngmres->gammaC > 2.)) ngmres->gammaC = ngmres->gammaA;
117: PetscFunctionReturn(PETSC_SUCCESS);
118: }
120: PetscErrorCode SNESView_NGMRES(SNES snes, PetscViewer viewer)
121: {
122: SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
123: PetscBool iascii;
125: PetscFunctionBegin;
126: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
127: if (iascii) {
128: PetscCall(PetscViewerASCIIPrintf(viewer, " Number of stored past updates: %" PetscInt_FMT "\n", ngmres->msize));
129: PetscCall(PetscViewerASCIIPrintf(viewer, " Residual selection: gammaA=%1.0e, gammaC=%1.0e\n", (double)ngmres->gammaA, (double)ngmres->gammaC));
130: PetscCall(PetscViewerASCIIPrintf(viewer, " Difference restart: epsilonB=%1.0e, deltaB=%1.0e\n", (double)ngmres->epsilonB, (double)ngmres->deltaB));
131: PetscCall(PetscViewerASCIIPrintf(viewer, " Restart on F_M residual increase: %s\n", PetscBools[ngmres->restart_fm_rise]));
132: }
133: PetscFunctionReturn(PETSC_SUCCESS);
134: }
136: static PetscErrorCode SNESSolve_NGMRES(SNES snes)
137: {
138: SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
139: /* present solution, residual, and preconditioned residual */
140: Vec X, F, B, D, Y;
142: /* candidate linear combination answers */
143: Vec XA, FA, XM, FM;
145: /* coefficients and RHS to the minimization problem */
146: PetscReal fnorm, fMnorm, fAnorm;
147: PetscReal xnorm, xMnorm, xAnorm;
148: PetscReal ynorm, yMnorm, yAnorm;
149: PetscInt k, k_restart, l, ivec, restart_count = 0;
151: /* solution selection data */
152: PetscBool selectRestart;
153: /*
154: These two variables are initialized to prevent compilers/analyzers from producing false warnings about these variables being passed
155: to SNESNGMRESSelect_Private() without being set when SNES_NGMRES_RESTART_DIFFERENCE, the values are not used in the subroutines in that case
156: so the code is correct as written.
157: */
158: PetscReal dnorm = 0.0, dminnorm = 0.0;
159: PetscReal fminnorm;
161: SNESConvergedReason reason;
162: SNESLineSearchReason lssucceed;
164: PetscFunctionBegin;
165: PetscCheck(!snes->xl && !snes->xu && !snes->ops->computevariablebounds, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
167: PetscCall(PetscCitationsRegister(SNESCitation, &SNEScite));
168: /* variable initialization */
169: snes->reason = SNES_CONVERGED_ITERATING;
170: X = snes->vec_sol;
171: F = snes->vec_func;
172: B = snes->vec_rhs;
173: XA = snes->work[2];
174: FA = snes->work[0];
175: D = snes->work[1];
177: /* work for the line search */
178: Y = snes->vec_sol_update;
179: XM = snes->work[3];
180: FM = snes->work[4];
182: PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
183: snes->iter = 0;
184: snes->norm = 0.;
185: PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
187: /* initialization */
189: if (snes->npc && snes->npcside == PC_LEFT) {
190: PetscCall(SNESApplyNPC(snes, X, NULL, F));
191: PetscCall(SNESGetConvergedReason(snes->npc, &reason));
192: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
193: snes->reason = SNES_DIVERGED_INNER;
194: PetscFunctionReturn(PETSC_SUCCESS);
195: }
196: PetscCall(VecNorm(F, NORM_2, &fnorm));
197: } else {
198: if (!snes->vec_func_init_set) {
199: PetscCall(SNESComputeFunction(snes, X, F));
200: } else snes->vec_func_init_set = PETSC_FALSE;
202: PetscCall(VecNorm(F, NORM_2, &fnorm));
203: SNESCheckFunctionNorm(snes, fnorm);
204: }
205: fminnorm = fnorm;
207: PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
208: snes->norm = fnorm;
209: PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
210: PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0));
211: PetscCall(SNESConverged(snes, 0, 0.0, 0.0, fnorm));
212: PetscCall(SNESMonitor(snes, 0, fnorm));
213: if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS);
214: PetscCall(SNESNGMRESUpdateSubspace_Private(snes, 0, 0, F, fnorm, X));
216: k_restart = 1;
217: l = 1;
218: ivec = 0;
219: for (k = 1; k < snes->max_its + 1; k++) {
220: /* Call general purpose update function */
221: PetscTryTypeMethod(snes, update, snes->iter);
223: /* Computation of x^M */
224: if (snes->npc && snes->npcside == PC_RIGHT) {
225: PetscCall(VecCopy(X, XM));
226: PetscCall(SNESSetInitialFunction(snes->npc, F));
228: PetscCall(PetscLogEventBegin(SNES_NPCSolve, snes->npc, XM, B, 0));
229: PetscCall(SNESSolve(snes->npc, B, XM));
230: PetscCall(PetscLogEventEnd(SNES_NPCSolve, snes->npc, XM, B, 0));
232: PetscCall(SNESGetConvergedReason(snes->npc, &reason));
233: if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
234: snes->reason = SNES_DIVERGED_INNER;
235: PetscFunctionReturn(PETSC_SUCCESS);
236: }
237: PetscCall(SNESGetNPCFunction(snes, FM, &fMnorm));
238: } else {
239: /* no preconditioner -- just take gradient descent with line search */
240: PetscCall(VecCopy(F, Y));
241: PetscCall(VecCopy(F, FM));
242: PetscCall(VecCopy(X, XM));
244: fMnorm = fnorm;
246: PetscCall(SNESLineSearchApply(snes->linesearch, XM, FM, &fMnorm, Y));
247: PetscCall(SNESLineSearchGetReason(snes->linesearch, &lssucceed));
248: if (lssucceed) {
249: if (++snes->numFailures >= snes->maxFailures) {
250: snes->reason = SNES_DIVERGED_LINE_SEARCH;
251: PetscFunctionReturn(PETSC_SUCCESS);
252: }
253: }
254: }
256: PetscCall(SNESNGMRESFormCombinedSolution_Private(snes, ivec, l, XM, FM, fMnorm, X, XA, FA));
257: /* r = F(x) */
258: if (fminnorm > fMnorm) fminnorm = fMnorm; /* the minimum norm is now of F^M */
260: /* differences for selection and restart */
261: if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE || ngmres->select_type == SNES_NGMRES_SELECT_DIFFERENCE) {
262: PetscCall(SNESNGMRESNorms_Private(snes, l, X, F, XM, FM, XA, FA, D, &dnorm, &dminnorm, &xMnorm, NULL, &yMnorm, &xAnorm, &fAnorm, &yAnorm));
263: } else {
264: PetscCall(SNESNGMRESNorms_Private(snes, l, X, F, XM, FM, XA, FA, D, NULL, NULL, &xMnorm, NULL, &yMnorm, &xAnorm, &fAnorm, &yAnorm));
265: }
266: SNESCheckFunctionNorm(snes, fnorm);
268: /* combination (additive) or selection (multiplicative) of the N-GMRES solution */
269: PetscCall(SNESNGMRESSelect_Private(snes, k_restart, XM, FM, xMnorm, fMnorm, yMnorm, XA, FA, xAnorm, fAnorm, yAnorm, dnorm, fminnorm, dminnorm, X, F, Y, &xnorm, &fnorm, &ynorm));
270: selectRestart = PETSC_FALSE;
272: if (ngmres->restart_type == SNES_NGMRES_RESTART_DIFFERENCE) {
273: PetscCall(SNESNGMRESSelectRestart_Private(snes, l, fMnorm, fAnorm, dnorm, fminnorm, dminnorm, &selectRestart));
275: /* if the restart conditions persist for more than restart_it iterations, restart. */
276: if (selectRestart) restart_count++;
277: else restart_count = 0;
278: } else if (ngmres->restart_type == SNES_NGMRES_RESTART_PERIODIC) {
279: if (k_restart > ngmres->restart_periodic) {
280: if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "periodic restart after %" PetscInt_FMT " iterations\n", k_restart));
281: restart_count = ngmres->restart_it;
282: }
283: }
285: ivec = k_restart % ngmres->msize; /* replace the last used part of the subspace */
287: /* restart after restart conditions have persisted for a fixed number of iterations */
288: if (restart_count >= ngmres->restart_it) {
289: if (ngmres->monitor) PetscCall(PetscViewerASCIIPrintf(ngmres->monitor, "Restarted at iteration %" PetscInt_FMT "\n", k_restart));
290: restart_count = 0;
291: k_restart = 1;
292: l = 1;
293: ivec = 0;
294: /* q_{00} = nu */
295: PetscCall(SNESNGMRESUpdateSubspace_Private(snes, 0, 0, FM, fMnorm, XM));
296: } else {
297: /* select the current size of the subspace */
298: if (l < ngmres->msize) l++;
299: k_restart++;
300: /* place the current entry in the list of previous entries */
301: if (ngmres->candidate) {
302: if (fminnorm > fMnorm) fminnorm = fMnorm;
303: PetscCall(SNESNGMRESUpdateSubspace_Private(snes, ivec, l, FM, fMnorm, XM));
304: } else {
305: if (fminnorm > fnorm) fminnorm = fnorm;
306: PetscCall(SNESNGMRESUpdateSubspace_Private(snes, ivec, l, F, fnorm, X));
307: }
308: }
310: PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
311: snes->iter = k;
312: snes->norm = fnorm;
313: snes->ynorm = ynorm;
314: snes->xnorm = xnorm;
315: PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
316: PetscCall(SNESLogConvergenceHistory(snes, snes->norm, snes->iter));
317: PetscCall(SNESConverged(snes, snes->iter, 0, 0, fnorm));
318: PetscCall(SNESMonitor(snes, snes->iter, snes->norm));
319: if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS);
320: }
321: snes->reason = SNES_DIVERGED_MAX_IT;
322: PetscFunctionReturn(PETSC_SUCCESS);
323: }
325: /*@
326: SNESNGMRESSetRestartFmRise - Increase the restart count if the step x_M increases the residual F_M
328: Input Parameters:
329: + snes - the `SNES` context.
330: - flg - boolean value deciding whether to use the option or not, default is `PETSC_FALSE`
332: Options Database Key:
333: . -snes_ngmres_restart_fm_rise - Increase the restart count if the step x_M increases the residual F_M
335: Level: intermediate
337: Notes:
338: If the proposed step x_M increases the residual F_M, it might be trying to get out of a stagnation area.
339: To help the solver do that, reset the Krylov subspace whenever F_M increases.
341: This option must be used with the `SNESNGMRES` `SNESNGMRESRestartType` of `SNES_NGMRES_RESTART_DIFFERENCE`
343: .seealso: [](ch_snes), `SNES`, `SNES_NGMRES_RESTART_DIFFERENCE`, `SNESNGMRES`, `SNESNGMRESRestartType`, `SNESNGMRESSetRestartType()`
344: @*/
345: PetscErrorCode SNESNGMRESSetRestartFmRise(SNES snes, PetscBool flg)
346: {
347: PetscErrorCode (*f)(SNES, PetscBool);
349: PetscFunctionBegin;
350: PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", &f));
351: if (f) PetscCall((f)(snes, flg));
352: PetscFunctionReturn(PETSC_SUCCESS);
353: }
355: static PetscErrorCode SNESNGMRESSetRestartFmRise_NGMRES(SNES snes, PetscBool flg)
356: {
357: SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
359: PetscFunctionBegin;
360: ngmres->restart_fm_rise = flg;
361: PetscFunctionReturn(PETSC_SUCCESS);
362: }
364: PetscErrorCode SNESNGMRESGetRestartFmRise(SNES snes, PetscBool *flg)
365: {
366: PetscErrorCode (*f)(SNES, PetscBool *);
368: PetscFunctionBegin;
369: PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", &f));
370: if (f) PetscCall((f)(snes, flg));
371: PetscFunctionReturn(PETSC_SUCCESS);
372: }
374: static PetscErrorCode SNESNGMRESGetRestartFmRise_NGMRES(SNES snes, PetscBool *flg)
375: {
376: SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
378: PetscFunctionBegin;
379: *flg = ngmres->restart_fm_rise;
380: PetscFunctionReturn(PETSC_SUCCESS);
381: }
383: /*@
384: SNESNGMRESSetRestartType - Sets the restart type for `SNESNGMRES`.
386: Logically Collective
388: Input Parameters:
389: + snes - the iterative context
390: - rtype - restart type, see `SNESNGMRESRestartType`
392: Options Database Keys:
393: + -snes_ngmres_restart_type<difference,periodic,none> - set the restart type
394: - -snes_ngmres_restart <30> - sets the number of iterations before restart for periodic
396: Level: intermediate
398: .seealso: [](ch_snes), `SNES`, `SNES_NGMRES_RESTART_DIFFERENCE`, `SNESNGMRES`, `SNESNGMRESRestartType`, `SNESNGMRESSetRestartFmRise()`,
399: `SNESNGMRESSetSelectType()`
400: @*/
401: PetscErrorCode SNESNGMRESSetRestartType(SNES snes, SNESNGMRESRestartType rtype)
402: {
403: PetscFunctionBegin;
405: PetscTryMethod(snes, "SNESNGMRESSetRestartType_C", (SNES, SNESNGMRESRestartType), (snes, rtype));
406: PetscFunctionReturn(PETSC_SUCCESS);
407: }
409: /*@
410: SNESNGMRESSetSelectType - Sets the selection type for `SNESNGMRES`. This determines how the candidate solution and
411: combined solution are used to create the next iterate.
413: Logically Collective
415: Input Parameters:
416: + snes - the iterative context
417: - stype - selection type, see `SNESNGMRESSelectType`
419: Options Database Key:
420: . -snes_ngmres_select_type<difference,none,linesearch> - select type
422: Level: intermediate
424: Note:
425: The default line search used is the `SNESLINESEARCHL2` line search and it requires two additional function evaluations.
427: .seealso: [](ch_snes), `SNES`, `SNESNGMRES`, `SNESNGMRESSelectType`, `SNES_NGMRES_SELECT_NONE`, `SNES_NGMRES_SELECT_DIFFERENCE`, `SNES_NGMRES_SELECT_LINESEARCH`,
428: `SNESNGMRESSetRestartType()`
429: @*/
430: PetscErrorCode SNESNGMRESSetSelectType(SNES snes, SNESNGMRESSelectType stype)
431: {
432: PetscFunctionBegin;
434: PetscTryMethod(snes, "SNESNGMRESSetSelectType_C", (SNES, SNESNGMRESSelectType), (snes, stype));
435: PetscFunctionReturn(PETSC_SUCCESS);
436: }
438: static PetscErrorCode SNESNGMRESSetSelectType_NGMRES(SNES snes, SNESNGMRESSelectType stype)
439: {
440: SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
442: PetscFunctionBegin;
443: ngmres->select_type = stype;
444: PetscFunctionReturn(PETSC_SUCCESS);
445: }
447: static PetscErrorCode SNESNGMRESSetRestartType_NGMRES(SNES snes, SNESNGMRESRestartType rtype)
448: {
449: SNES_NGMRES *ngmres = (SNES_NGMRES *)snes->data;
451: PetscFunctionBegin;
452: ngmres->restart_type = rtype;
453: PetscFunctionReturn(PETSC_SUCCESS);
454: }
456: /*MC
457: SNESNGMRES - The Nonlinear Generalized Minimum Residual method {cite}`ow1`, {cite}`bruneknepleysmithtu15`
459: Level: beginner
461: Options Database Keys:
462: + -snes_ngmres_select_type<difference,none,linesearch> - choose the select between candidate and combined solution
463: . -snes_ngmres_restart_type<difference,none,periodic> - choose the restart conditions
464: . -snes_ngmres_candidate - Use `SNESNGMRES` variant which combines candidate solutions instead of actual solutions
465: . -snes_ngmres_m - Number of stored previous solutions and residuals
466: . -snes_ngmres_restart_it - Number of iterations the restart conditions hold before restart
467: . -snes_ngmres_gammaA - Residual tolerance for solution select between the candidate and combination
468: . -snes_ngmres_gammaC - Residual tolerance for restart
469: . -snes_ngmres_epsilonB - Difference tolerance between subsequent solutions triggering restart
470: . -snes_ngmres_deltaB - Difference tolerance between residuals triggering restart
471: . -snes_ngmres_restart_fm_rise - Restart on residual rise from x_M step
472: . -snes_ngmres_monitor - Prints relevant information about the ngmres iteration
473: . -snes_linesearch_type <basic,l2,cp> - Line search type used for the default smoother
474: - -additive_snes_linesearch_type - line search type used to select between the candidate and combined solution with additive select type
476: Notes:
477: The N-GMRES method combines m previous solutions into a minimum-residual solution by solving a small linearized
478: optimization problem at each iteration.
480: Very similar to the `SNESANDERSON` algorithm.
482: .seealso: [](ch_snes), `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESType`, `SNESANDERSON`, `SNESNGMRESSetSelectType()`, `SNESNGMRESSetRestartType()`,
483: `SNESNGMRESSetRestartFmRise()`, `SNESNGMRESSelectType`, ``SNESNGMRESRestartType`
484: M*/
486: PETSC_EXTERN PetscErrorCode SNESCreate_NGMRES(SNES snes)
487: {
488: SNES_NGMRES *ngmres;
489: SNESLineSearch linesearch;
491: PetscFunctionBegin;
492: snes->ops->destroy = SNESDestroy_NGMRES;
493: snes->ops->setup = SNESSetUp_NGMRES;
494: snes->ops->setfromoptions = SNESSetFromOptions_NGMRES;
495: snes->ops->view = SNESView_NGMRES;
496: snes->ops->solve = SNESSolve_NGMRES;
497: snes->ops->reset = SNESReset_NGMRES;
499: snes->usesnpc = PETSC_TRUE;
500: snes->usesksp = PETSC_FALSE;
501: snes->npcside = PC_RIGHT;
503: snes->alwayscomputesfinalresidual = PETSC_TRUE;
505: PetscCall(PetscNew(&ngmres));
506: snes->data = (void *)ngmres;
507: ngmres->msize = 30;
509: if (!snes->tolerancesset) {
510: snes->max_funcs = 30000;
511: snes->max_its = 10000;
512: }
514: ngmres->candidate = PETSC_FALSE;
516: PetscCall(SNESGetLineSearch(snes, &linesearch));
517: if (!((PetscObject)linesearch)->type_name) PetscCall(SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC));
519: ngmres->additive_linesearch = NULL;
520: ngmres->approxfunc = PETSC_FALSE;
521: ngmres->restart_it = 2;
522: ngmres->restart_periodic = 30;
523: ngmres->gammaA = 2.0;
524: ngmres->gammaC = 2.0;
525: ngmres->deltaB = 0.9;
526: ngmres->epsilonB = 0.1;
527: ngmres->restart_fm_rise = PETSC_FALSE;
529: ngmres->restart_type = SNES_NGMRES_RESTART_DIFFERENCE;
530: ngmres->select_type = SNES_NGMRES_SELECT_DIFFERENCE;
532: PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetSelectType_C", SNESNGMRESSetSelectType_NGMRES));
533: PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartType_C", SNESNGMRESSetRestartType_NGMRES));
534: PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESSetRestartFmRise_C", SNESNGMRESSetRestartFmRise_NGMRES));
535: PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNGMRESGetRestartFmRise_C", SNESNGMRESGetRestartFmRise_NGMRES));
536: PetscFunctionReturn(PETSC_SUCCESS);
537: }