Actual source code: snesimpl.h
1: #pragma once
3: #include <petscsnes.h>
4: #include <petsc/private/petscimpl.h>
6: /* SUBMANSEC = SNES */
8: PETSC_EXTERN PetscBool SNESRegisterAllCalled;
9: PETSC_EXTERN PetscErrorCode SNESRegisterAll(void);
11: typedef struct _SNESOps *SNESOps;
13: struct _SNESOps {
14: PetscErrorCode (*computeinitialguess)(SNES, Vec, void *);
15: PetscErrorCode (*computescaling)(Vec, Vec, void *);
16: PetscErrorCode (*update)(SNES, PetscInt); /* General purpose function for update */
17: PetscErrorCode (*converged)(SNES, PetscInt, PetscReal, PetscReal, PetscReal, SNESConvergedReason *, void *);
18: PetscCtxDestroyFn *convergeddestroy;
19: PetscErrorCode (*setup)(SNES); /* routine to set up the nonlinear solver */
20: PetscErrorCode (*solve)(SNES); /* actual nonlinear solver */
21: PetscErrorCode (*view)(SNES, PetscViewer);
22: PetscErrorCode (*setfromoptions)(SNES, PetscOptionItems); /* sets options from database */
23: PetscErrorCode (*destroy)(SNES);
24: PetscErrorCode (*reset)(SNES);
25: PetscErrorCode (*usercompute)(SNES, void **);
26: PetscCtxDestroyFn *ctxdestroy;
27: PetscErrorCode (*computevariablebounds)(SNES, Vec, Vec); /* user provided routine to set box constrained variable bounds */
28: PetscErrorCode (*computepfunction)(SNES, Vec, Vec, void *);
29: PetscErrorCode (*computepjacobian)(SNES, Vec, Mat, Mat, void *);
30: PetscErrorCode (*load)(SNES, PetscViewer);
31: };
33: /*
34: Nonlinear solver context
35: */
36: #define MAXSNESMONITORS 5
37: #define MAXSNESREASONVIEWS 5
39: struct _p_SNES {
40: PETSCHEADER(struct _SNESOps);
41: DM dm;
42: PetscBool dmAuto; /* SNES created currently used DM automatically */
43: SNES npc;
44: PCSide npcside;
45: PetscBool usesnpc; /* type can use a nonlinear preconditioner */
47: /* ------------------------ User-provided stuff -------------------------------*/
48: void *ctx; /* user-defined context */
50: Vec vec_rhs; /* If non-null, solve F(x) = rhs */
51: Vec vec_sol; /* pointer to solution */
53: Vec vec_func; /* pointer to function */
55: Mat jacobian; /* Jacobian matrix */
56: Mat jacobian_pre; /* matrix used to construct the preconditioner of the Jacobian */
57: Mat picard; /* copy of jacobian_pre needed for Picard with -snes_mf_operator */
58: void *initialguessP; /* user-defined initial guess context */
59: KSP ksp; /* linear solver context */
60: SNESLineSearch linesearch; /* line search context */
61: PetscBool usesksp;
62: MatStructure matstruct; /* Used by Picard solver */
64: Vec vec_sol_update; /* pointer to solution update */
66: Vec scaling; /* scaling vector */
67: void *scaP; /* scaling context */
69: PetscReal precheck_picard_angle; /* For use with SNESLineSearchPreCheckPicard */
71: /* ------------------------Time stepping hooks-----------------------------------*/
73: /* ---------------- PETSc-provided (or user-provided) stuff ---------------------*/
75: PetscErrorCode (*monitor[MAXSNESMONITORS])(SNES, PetscInt, PetscReal, void *); /* monitor routine */
76: PetscCtxDestroyFn *monitordestroy[MAXSNESMONITORS]; /* monitor context destroy routine */
77: void *monitorcontext[MAXSNESMONITORS]; /* monitor context */
78: PetscInt numbermonitors; /* number of monitors */
79: PetscBool pauseFinal; /* pause all drawing monitor at the final iterate */
80: void *cnvP; /* convergence context */
81: SNESConvergedReason reason; /* converged reason */
83: PetscViewer convergedreasonviewer;
84: PetscViewerFormat convergedreasonformat;
85: PetscErrorCode (*reasonview[MAXSNESREASONVIEWS])(SNES, void *); /* snes converged reason view */
86: PetscCtxDestroyFn *reasonviewdestroy[MAXSNESREASONVIEWS]; /* reason view context destroy routine */
87: void *reasonviewcontext[MAXSNESREASONVIEWS]; /* reason view context */
88: PetscInt numberreasonviews; /* number of reason views */
89: PetscBool errorifnotconverged;
91: /* --- Routines and data that are unique to each particular solver --- */
93: PetscBool setupcalled; /* true if setup has been called */
94: void *data; /* implementation-specific data */
96: /* -------------------------- Parameters -------------------------------------- */
98: PetscInt nfuncs; /* number of function evaluations */
99: PetscInt iter; /* global iteration number */
100: PetscInt linear_its; /* total number of linear solver iterations */
101: PetscReal norm; /* residual norm of current iterate */
102: PetscReal ynorm; /* update norm of current iterate */
103: PetscReal xnorm; /* solution norm of current iterate */
104: PetscBool forceiteration; /* Force SNES to take at least one iteration regardless of the initial residual norm */
105: PetscInt lagpreconditioner; /* SNESSetLagPreconditioner() */
106: PetscInt lagjacobian; /* SNESSetLagJacobian() */
107: PetscInt jac_iter; /* The present iteration of the Jacobian lagging */
108: PetscBool lagjac_persist; /* The jac_iter persists until reset */
109: PetscInt pre_iter; /* The present iteration of the Preconditioner lagging */
110: PetscBool lagpre_persist; /* The pre_iter persists until reset */
111: PetscInt gridsequence; /* number of grid sequence steps to take; defaults to zero */
112: PetscObjectParameterDeclare(PetscInt, max_its); /* max number of iterations */
113: PetscObjectParameterDeclare(PetscInt, max_funcs); /* max number of function evals */
114: PetscObjectParameterDeclare(PetscReal, rtol); /* relative tolerance */
115: PetscObjectParameterDeclare(PetscReal, divtol); /* relative divergence tolerance */
116: PetscObjectParameterDeclare(PetscReal, abstol); /* absolute tolerance */
117: PetscObjectParameterDeclare(PetscReal, stol); /* step length tolerance*/
119: PetscBool vec_func_init_set; /* the initial function has been set */
121: SNESNormSchedule normschedule; /* Norm computation type for SNES instance */
122: SNESFunctionType functype; /* Function type for the SNES instance */
124: /* ------------------------ Default work-area management ---------------------- */
126: PetscInt nwork;
127: Vec *work;
129: /* ---------------------------------- Testing --------------------------------- */
130: PetscBool testFunc; // Test the function routine
131: PetscBool testJac; // Test the Jacobian routine
133: /* ------------------------- Miscellaneous Information ------------------------ */
135: PetscInt setfromoptionscalled;
136: PetscReal *conv_hist; /* If !0, stores function norm (or
137: gradient norm) at each iteration */
138: PetscInt *conv_hist_its; /* linear iterations for each Newton step */
139: size_t conv_hist_len; /* size of convergence history array */
140: size_t conv_hist_max; /* actual amount of data in conv_history */
141: PetscBool conv_hist_reset; /* reset counter for each new SNES solve */
142: PetscBool conv_hist_alloc;
143: PetscBool counters_reset; /* reset counter for each new SNES solve */
145: /* the next two are used for failures in the line search; they should be put elsewhere */
146: PetscInt numFailures; /* number of unsuccessful step attempts */
147: PetscInt maxFailures; /* maximum number of unsuccessful step attempts */
149: PetscInt numLinearSolveFailures;
150: PetscInt maxLinearSolveFailures;
152: PetscBool functiondomainerror; /* set with SNESSetFunctionDomainError() */
153: PetscBool objectivedomainerror; /* set with SNESSetObjectiveDomainError() */
154: PetscBool jacobiandomainerror; /* set with SNESSetJacobianDomainError() */
155: PetscBool checkjacdomainerror; /* if SNESCheckJacobianDomainError() is called after Jacobian evaluations */
157: PetscBool ksp_ewconv; /* flag indicating use of Eisenstat-Walker KSP convergence criteria */
158: void *kspconvctx; /* Eisenstat-Walker KSP convergence context */
160: /* SNESConvergedDefault context: split it off into a separate var/struct to be passed as context to SNESConvergedDefault? */
161: PetscReal ttol; /* rtol*initial_residual_norm */
162: PetscReal rnorm0; /* initial residual norm (used for divergence testing) */
164: Vec *vwork; /* more work vectors for Jacobian approx */
165: PetscInt nvwork;
167: PetscBool mf; /* -snes_mf OR -snes_mf_operator was used on this snes */
168: PetscBool mf_operator; /* -snes_mf_operator was used on this snes */
169: PetscInt mf_version; /* The version of snes_mf used */
171: PetscReal vizerotolerance; /* tolerance for considering an x[] value to be on the bound */
172: Vec xl, xu; /* upper and lower bounds for box constrained VI problems */
173: PetscInt ntruebounds; /* number of non-infinite bounds set for VI box constraints */
174: PetscBool usersetbounds; /* bounds have been set via SNESVISetVariableBounds(), rather than via computevariablebounds() callback. */
176: PetscBool alwayscomputesfinalresidual; /* Does SNESSolve_XXX always compute the value of the residual at the final
177: * solution and put it in vec_func? Used inside SNESSolve_FAS to determine
178: * if the final residual must be computed before restricting or prolonging
179: * it. */
180: };
182: typedef struct _p_DMSNES *DMSNES;
183: typedef struct _DMSNESOps *DMSNESOps;
184: struct _DMSNESOps {
185: SNESFunctionFn *computefunction;
186: SNESFunctionFn *computemffunction;
187: SNESJacobianFn *computejacobian;
189: /* objective */
190: SNESObjectiveFn *computeobjective;
192: /* Picard iteration functions */
193: SNESFunctionFn *computepfunction;
194: SNESJacobianFn *computepjacobian;
196: /* User-defined smoother */
197: SNESNGSFn *computegs;
199: PetscErrorCode (*destroy)(DMSNES);
200: PetscErrorCode (*duplicate)(DMSNES, DMSNES);
201: };
203: /*S
204: DMSNES - Object held by a `DM` that contains all the callback functions and their contexts needed by a `SNES`
206: Level: developer
208: Notes:
209: Users provides callback functions and their contexts to `SNES` using, for example, `SNESSetFunction()`. These values are stored
210: in a `DMSNES` that is contained in the `DM` associated with the `SNES`. If no `DM` was provided by
211: the user with `SNESSetDM()` it is automatically created by `SNESGetDM()` with `DMShellCreate()`.
213: Users very rarely need to worked directly with the `DMSNES` object, rather they work with the `SNES` and the `DM` they created
215: Multiple `DM` can share a single `DMSNES`, often each `DM` is associated with
216: a grid refinement level. `DMGetDMSNES()` returns the `DMSNES` associated with a `DM`. `DMGetDMSNESWrite()` returns a unique
217: `DMSNES` that is only associated with the current `DM`, making a copy of the shared `DMSNES` if needed (copy-on-write).
219: See `DMKSP` for details on why there is a needed for `DMSNES` instead of simply storing the user callbacks directly in the `DM` or the `TS`
221: Developer Note:
222: The `originaldm` inside the `DMSNES` is NOT reference counted (to prevent a reference count loop between a `DM` and a `DMSNES`).
223: The `DM` on which this context was first created is cached here to implement one-way
224: copy-on-write. When `DMGetDMSNESWrite()` sees a request using a different `DM`, it makes a copy of the `TSDM`. Thus, if a user
225: only interacts directly with one level, e.g., using `TSSetIFunction()`, then coarse levels of a multilevel item
226: integrator are built, then the user changes the routine with another call to `TSSetIFunction()`, it automatically
227: propagates to all the levels. If instead, they get out a specific level and set the function on that level,
228: subsequent changes to the original level will no longer propagate to that level.
230: .seealso: [](ch_snes), `SNES`, `SNESCreate()`, `DM`, `DMGetDMSNESWrite()`, `DMGetDMSNES()`, `DMKSP`, `DMTS`, `DMSNESSetFunction()`, `DMSNESGetFunction()`,
231: `DMSNESSetFunctionContextDestroy()`, `DMSNESSetMFFunction()`, `DMSNESSetNGS()`, `DMSNESGetNGS()`, `DMSNESSetJacobian()`, `DMSNESGetJacobian()`,
232: `DMSNESSetJacobianContextDestroy()`, `DMSNESSetPicard()`, `DMSNESGetPicard()`, `DMSNESSetObjective()`, `DMSNESGetObjective()`, `DMCopyDMSNES()`
233: S*/
234: struct _p_DMSNES {
235: PETSCHEADER(struct _DMSNESOps);
236: PetscContainer functionctxcontainer;
237: PetscContainer jacobianctxcontainer;
238: void *mffunctionctx;
239: void *gsctx;
240: void *pctx;
241: void *objectivectx;
243: void *data;
245: /* See developer note for DMSNES above */
246: DM originaldm;
247: };
248: PETSC_EXTERN PetscErrorCode DMGetDMSNES(DM, DMSNES *);
249: PETSC_EXTERN PetscErrorCode DMSNESView(DMSNES, PetscViewer);
250: PETSC_EXTERN PetscErrorCode DMSNESLoad(DMSNES, PetscViewer);
251: PETSC_EXTERN PetscErrorCode DMGetDMSNESWrite(DM, DMSNES *);
253: /* Context for Eisenstat-Walker convergence criteria for KSP solvers */
254: typedef struct {
255: PetscInt version; /* flag indicating version (1,2,3 or 4) */
256: PetscReal rtol_0; /* initial rtol */
257: PetscReal rtol_last; /* last rtol */
258: PetscReal rtol_max; /* maximum rtol */
259: PetscReal gamma; /* mult. factor for version 2 rtol computation */
260: PetscReal alpha; /* power for version 2 rtol computation */
261: PetscReal alpha2; /* power for safeguard */
262: PetscReal threshold; /* threshold for imposing safeguard */
263: PetscReal lresid_last; /* linear residual from last iteration */
264: PetscReal norm_last; /* function norm from last iteration */
265: PetscReal norm_first; /* function norm from the beginning of the first iteration. */
266: PetscReal rtol_last_2, rk_last, rk_last_2;
267: PetscReal v4_p1, v4_p2, v4_p3, v4_m1, v4_m2, v4_m3, v4_m4;
268: } SNESKSPEW;
270: static inline PetscErrorCode SNESLogConvergenceHistory(SNES snes, PetscReal res, PetscInt its)
271: {
272: PetscFunctionBegin;
273: PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
274: if (snes->conv_hist && snes->conv_hist_max > snes->conv_hist_len) {
275: if (snes->conv_hist) snes->conv_hist[snes->conv_hist_len] = res;
276: if (snes->conv_hist_its) snes->conv_hist_its[snes->conv_hist_len] = its;
277: snes->conv_hist_len++;
278: }
279: PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
280: PetscFunctionReturn(PETSC_SUCCESS);
281: }
283: PETSC_EXTERN PetscErrorCode SNESVIProjectOntoBounds(SNES, Vec);
284: PETSC_INTERN PetscErrorCode SNESVICheckLocalMin_Private(SNES, Mat, Vec, Vec, PetscReal, PetscBool *);
285: PETSC_INTERN PetscErrorCode SNESReset_VI(SNES);
286: PETSC_INTERN PetscErrorCode SNESDestroy_VI(SNES);
287: PETSC_INTERN PetscErrorCode SNESView_VI(SNES, PetscViewer);
288: PETSC_INTERN PetscErrorCode SNESSetFromOptions_VI(SNES, PetscOptionItems);
289: PETSC_INTERN PetscErrorCode SNESSetUp_VI(SNES);
290: PETSC_EXTERN_TYPEDEF typedef PetscErrorCode SNESVIComputeVariableBoundsFn(SNES, Vec, Vec);
291: PETSC_EXTERN_TYPEDEF typedef SNESVIComputeVariableBoundsFn *SNESVIComputeVariableBoundsFunction; // deprecated version
292: PETSC_INTERN PetscErrorCode SNESVISetComputeVariableBounds_VI(SNES, SNESVIComputeVariableBoundsFn);
293: PETSC_INTERN PetscErrorCode SNESVISetVariableBounds_VI(SNES, Vec, Vec);
294: PETSC_INTERN PetscErrorCode SNESConvergedDefault_VI(SNES, PetscInt, PetscReal, PetscReal, PetscReal, SNESConvergedReason *, void *);
296: PETSC_INTERN PetscErrorCode DMSNESUnsetFunctionContext_Internal(DM);
297: PETSC_EXTERN PetscErrorCode DMSNESUnsetJacobianContext_Internal(DM);
299: PETSC_EXTERN PetscLogEvent SNES_Solve;
300: PETSC_EXTERN PetscLogEvent SNES_SetUp;
301: PETSC_EXTERN PetscLogEvent SNES_FunctionEval;
302: PETSC_EXTERN PetscLogEvent SNES_JacobianEval;
303: PETSC_EXTERN PetscLogEvent SNES_NGSEval;
304: PETSC_EXTERN PetscLogEvent SNES_NGSFuncEval;
305: PETSC_EXTERN PetscLogEvent SNES_NewtonALEval;
306: PETSC_EXTERN PetscLogEvent SNES_NPCSolve;
307: PETSC_EXTERN PetscLogEvent SNES_ObjectiveEval;
309: PETSC_INTERN PetscBool SNEScite;
310: PETSC_INTERN const char SNESCitation[];
312: /* Used by TAOBNK solvers */
313: PETSC_SINGLE_LIBRARY_VISIBILITY_INTERNAL PetscErrorCode KSPPostSolve_SNESEW(KSP, Vec, Vec, void *);
314: PETSC_SINGLE_LIBRARY_VISIBILITY_INTERNAL PetscErrorCode KSPPreSolve_SNESEW(KSP, Vec, Vec, void *);
315: PETSC_SINGLE_LIBRARY_VISIBILITY_INTERNAL PetscErrorCode SNESEWSetFromOptions_Private(SNESKSPEW *, PetscBool, MPI_Comm, const char *);
317: /*MC
318: SNESCheckFunctionDomainError - Called after a `SNESComputeFunction()` and `VecNorm()` in a `SNES` solver to check if the function norm is infinity or NaN and
319: if the function callback set with `SNESSetFunction()` called `SNESSetFunctionDomainError()`.
321: Synopsis:
322: #include <snesimpl.h>
323: void SNESCheckFunctionDomainError(SNES snes, PetscReal fnorm)
325: Collective
327: Input Parameters:
328: + snes - the `SNES` solver object
329: - fnorm - the value of the norm
331: Level: developer
333: Notes:
334: If `fnorm` is infinity or NaN and `SNESSetErrorIfNotConverged()` was set, this immediately generates a `PETSC_ERR_CONV_FAILED`.
336: If `fnorm` is infinity or NaN and `SNESSetFunctionDomainError()` was called, this sets the `SNESConvergedReason` to `SNES_DIVERGED_FUNCTION_DOMAIN`
337: and exits the solver
339: Otherwise if `fnorm` is infinity or NaN, this sets the `SNESConvergedReason` to `SNES_DIVERGED_FUNCTION_NANORINF` and exits the solver
341: Developer Note:
342: This function exists so that `SNESSetFunctionDomainError()` does not need to be a collective operation since making it collective
343: would be cumbersome in most applications and require extra communication. Instead, `SNESSetFunctionDomainError()` sets the `functiondomainerror`
344: flag in the `SNES` object to true, `SNESComputeFunction()` checks that flag and sets a NaN into its local part of the vector if the flag has been set.
345: Then, when `VecNorm()` is called on the vector containing the computed function value, any NaN is propagated to all MPI processes without
346: any additional communication. Virtually all nonlinear solvers need to compute the function norm at some point so no extra communication needs to take place.
348: .seealso: [](ch_snes), `SNESSetFunctionDomainError()`, `SNESCheckObjectiveDomainError()`, `PETSC_ERR_CONV_FAILED`, `SNESSetErrorIfNotConverged()`, `SNES_DIVERGED_FUNCTION_DOMAIN`,
349: `SNESConvergedReason`, `SNES_DIVERGED_FUNCTION_NAN`
350: MC*/
351: #define SNESCheckFunctionDomainError(snes, fnorm) \
352: do { \
353: if (PetscIsInfOrNanReal(fnorm)) { \
354: PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESSolve has not converged due to infinity or NaN norm"); \
355: { \
356: PetscBool domainerror; \
357: PetscCallMPI(MPIU_Allreduce(&snes->functiondomainerror, &domainerror, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)snes))); \
358: if (domainerror) snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; \
359: else snes->reason = SNES_DIVERGED_FUNCTION_NANORINF; \
360: PetscFunctionReturn(PETSC_SUCCESS); \
361: } \
362: } \
363: } while (0)
365: /*MC
366: SNESCheckObjectiveDomainError - Called after a `SNESComputeObjective()` in a `SNES` solver to check if the objective value is infinity or NaN and/or
367: if the function callback set with `SNESSetObjective()` called `SNESSetObjectiveDomainError()`.
369: Synopsis:
370: #include <snesimpl.h>
371: void SNESCheckObjectiveDomainError(SNES snes, PetscReal fobj)
373: Collective
375: Input Parameters:
376: + snes - the `SNES` solver object
377: - fobj - the value of the objective function
379: Level: developer
381: Notes:
382: If `fobj` is infinity or NaN and `SNESSetErrorIfNotConverged()` was set, this immediately generates a `PETSC_ERR_CONV_FAILED`.
384: If `SNESSetObjectiveDomainError()` was called, this sets the `SNESConvergedReason` to `SNES_DIVERGED_OBJECTIVE_DOMAIN`
385: and exits the solver
387: Otherwise if `fobj` is infinity or NaN, this sets the `SNESConvergedReason` to `SNES_DIVERGED_OBJECTIVE_NANORINF` and exits the solver
389: .seealso: [](ch_snes), `SNESSetObjectiveDomainError()`, `PETSC_ERR_CONV_FAILED`, `SNESSetErrorIfNotConverged()`, `SNES_DIVERGED_OBJECTIVE_DOMAIN`, `SNES_DIVERGED_FUNCTION_DOMAIN`,
390: `SNESSetFunctionDomainError()`, `SNESConvergedReason`, `SNES_DIVERGED_OBJECTIVE_NANORINF`, `SNES_DIVERGED_FUNCTION_NAN`, `SNESLineSearchCheckObjectiveDomainError()`
391: MC*/
392: #define SNESCheckObjectiveDomainError(snes, fobj) \
393: do { \
394: if (snes->errorifnotconverged) { \
395: PetscCheck(!snes->objectivedomainerror, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESSolve has not converged due objective domain error"); \
396: PetscCheck(!PetscIsInfOrNanReal(fobj), PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESSolve has not converged due to infinity or NaN norm"); \
397: } \
398: if (snes->objectivedomainerror) { \
399: snes->reason = SNES_DIVERGED_OBJECTIVE_DOMAIN; \
400: PetscFunctionReturn(PETSC_SUCCESS); \
401: } else if (PetscIsInfOrNanReal(fobj)) { \
402: snes->reason = SNES_DIVERGED_OBJECTIVE_NANORINF; \
403: PetscFunctionReturn(PETSC_SUCCESS); \
404: } \
405: } while (0)
407: /*MC
408: SNESCheckJacobianDomainError - Called after a `SNESComputeJacobian()` in a SNES solver to check if `SNESSetJacobianDomainError()` has been called.
410: Synopsis:
411: #include <snesimpl.h>
412: void SNESCheckJacobianDomainError(SNES snes)
414: Collective
416: Input Parameters:
417: . snes - the `SNES` solver object
419: Level: developer
421: Notes:
422: This turns the non-collective `SNESSetJacobianDomainError()` into a collective operation
424: This check is done in debug mode or if `SNESSetCheckJacobianDomainError()` has been called
426: .seealso: [](ch_snes), `SNESSetCheckJacobianDomainError()`, `SNESCheckObjectiveDomainError()`, `SNESSetFunctionDomainError()`, `PETSC_ERR_CONV_FAILED`, `SNESSetErrorIfNotConverged()`, `SNES_DIVERGED_FUNCTION_DOMAIN`,
427: `SNESConvergedReason`, `SNES_DIVERGED_FUNCTION_NAN`
428: MC*/
429: #define SNESCheckJacobianDomainError(snes) \
430: do { \
431: if (snes->checkjacdomainerror) { \
432: PetscBool domainerror; \
433: PetscCallMPI(MPIU_Allreduce(&snes->jacobiandomainerror, &domainerror, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)snes))); \
434: if (domainerror) { \
435: snes->reason = SNES_DIVERGED_JACOBIAN_DOMAIN; \
436: PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESSolve has not converged due to Jacobian domain error"); \
437: PetscFunctionReturn(PETSC_SUCCESS); \
438: } \
439: } \
440: } while (0)
442: /*MC
443: SNESCheckLineSearchFailure - Checks if a `SNESLineSearchApply()` has failed and possibly ends the current `SNESSolve()` if so
445: Synopsis:
446: #include <snesimpl.h>
447: void SNESCheckLineSearchFailure(SNES snes)
449: Collective
451: Input Parameters:
452: . snes - the `SNES` solver object
454: Level: developer
456: Notes:
457: If `SNESLineSearchApply()` produces a `SNES_LINESEARCH_FAILED_NANORINF` or `SNES_LINESEARCH_FAILED_NANORINF` the `SNESSolve()` is ended.
459: If the `SNESLineSearchApply()` produces any other failure reason and the number of failed steps is greater than the number set with
460: `SNESSetMaxNonlinearStepFailures()` the `SNESSolve()` is ended
462: .seealso: [](ch_snes), `SNESLineSearchApply()`, `SNESSetFunctionDomainError()`, `PETSC_ERR_CONV_FAILED`, `SNESSetErrorIfNotConverged()`, `SNES_DIVERGED_FUNCTION_DOMAIN`,
463: `SNESConvergedReason`, `SNES_DIVERGED_FUNCTION_NAN`, `SNESSolve()`, `SNESSetMaxNonlinearStepFailures()`
464: MC*/
465: #define SNESCheckLineSearchFailure(snes) \
466: do { \
467: SNESLineSearchReason lsreason; \
468: PetscCall(SNESLineSearchGetReason(snes->linesearch, &lsreason)); \
469: if (lsreason) { \
470: if (lsreason == SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN) { \
471: PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESLineSearchApply() has produced failure with function domain"); \
472: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; \
473: PetscFunctionReturn(PETSC_SUCCESS); \
474: } \
475: if (lsreason == SNES_LINESEARCH_FAILED_NANORINF) { \
476: PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESLineSearchApply() has produced failure with infinity or NaN"); \
477: snes->reason = SNES_DIVERGED_FUNCTION_NANORINF; \
478: PetscFunctionReturn(PETSC_SUCCESS); \
479: } \
480: if (lsreason == SNES_LINESEARCH_FAILED_OBJECTIVE_DOMAIN) { \
481: PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESLineSearchApply() has produced failure with objective function domain"); \
482: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; \
483: PetscFunctionReturn(PETSC_SUCCESS); \
484: } \
485: if (lsreason == SNES_LINESEARCH_FAILED_JACOBIAN_DOMAIN) { \
486: PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESLineSearchApply() has produced failure with Jacobian domain"); \
487: snes->reason = SNES_DIVERGED_JACOBIAN_DOMAIN; \
488: PetscFunctionReturn(PETSC_SUCCESS); \
489: } \
490: if (++snes->numFailures >= snes->maxFailures) { \
491: PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESLineSearchApply() has produced failure"); \
492: snes->reason = SNES_DIVERGED_LINE_SEARCH; \
493: PetscFunctionReturn(PETSC_SUCCESS); \
494: } \
495: } \
496: } while (0)
498: #define SNESCheckKSPSolve(snes) \
499: do { \
500: KSPConvergedReason kspreason; \
501: PetscInt lits; \
502: PetscCall(KSPGetIterationNumber(snes->ksp, &lits)); \
503: snes->linear_its += lits; \
504: PetscCall(KSPGetConvergedReason(snes->ksp, &kspreason)); \
505: if (kspreason < 0) { \
506: if (kspreason == KSP_DIVERGED_NANORINF) { \
507: PetscBool domainerror; \
508: PetscCallMPI(MPIU_Allreduce(&snes->functiondomainerror, &domainerror, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)snes))); \
509: if (domainerror) { \
510: snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; \
511: snes->functiondomainerror = PETSC_FALSE; \
512: } else snes->reason = SNES_DIVERGED_LINEAR_SOLVE; \
513: PetscFunctionReturn(PETSC_SUCCESS); \
514: } else { \
515: if (++snes->numLinearSolveFailures >= snes->maxLinearSolveFailures) { \
516: PetscCall(PetscInfo(snes, "iter=%" PetscInt_FMT ", number linear solve failures %" PetscInt_FMT " greater than current SNES allowed %" PetscInt_FMT ", stopping solve\n", snes->iter, snes->numLinearSolveFailures, snes->maxLinearSolveFailures)); \
517: snes->reason = SNES_DIVERGED_LINEAR_SOLVE; \
518: PetscFunctionReturn(PETSC_SUCCESS); \
519: } \
520: } \
521: } \
522: } while (0)
524: #define SNESNeedNorm_Private(snes, iter) \
525: (((iter) == (snes)->max_its && ((snes)->normschedule == SNES_NORM_FINAL_ONLY || (snes)->normschedule == SNES_NORM_INITIAL_FINAL_ONLY)) || ((iter) == 0 && ((snes)->normschedule == SNES_NORM_INITIAL_ONLY || (snes)->normschedule == SNES_NORM_INITIAL_FINAL_ONLY)) || \
526: (snes)->normschedule == SNES_NORM_ALWAYS)