Actual source code: linesearchimpl.h
1: #pragma once
3: #include <petscsnes.h>
4: #include <petsc/private/petscimpl.h>
6: PETSC_EXTERN PetscBool SNESLineSearchRegisterAllCalled;
7: PETSC_EXTERN PetscErrorCode SNESLineSearchRegisterAll(void);
8: PETSC_EXTERN PetscLogEvent SNESLINESEARCH_Apply;
10: typedef struct _LineSearchOps *LineSearchOps;
12: struct _LineSearchOps {
13: PetscErrorCode (*view)(SNESLineSearch, PetscViewer);
14: SNESLineSearchApplyFn *apply;
15: PetscErrorCode (*precheck)(SNESLineSearch, Vec, Vec, PetscBool *, void *);
16: SNESLineSearchVIProjectFn *viproject;
17: SNESLineSearchVINormFn *vinorm;
18: SNESLineSearchVIDirDerivFn *vidirderiv;
19: PetscErrorCode (*postcheck)(SNESLineSearch, Vec, Vec, Vec, PetscBool *, PetscBool *, void *);
20: PetscErrorCode (*setfromoptions)(SNESLineSearch, PetscOptionItems);
21: PetscErrorCode (*reset)(SNESLineSearch);
22: PetscErrorCode (*destroy)(SNESLineSearch);
23: PetscErrorCode (*setup)(SNESLineSearch);
24: PetscErrorCode (*snesfunc)(SNES, Vec, Vec);
25: };
27: #define MAXSNESLSMONITORS 5
29: struct _p_LineSearch {
30: PETSCHEADER(struct _LineSearchOps);
32: SNES snes;
34: void *data;
36: PetscBool setupcalled;
38: Vec vec_sol;
39: Vec vec_sol_new;
40: Vec vec_func;
41: Vec vec_func_new;
42: Vec vec_update;
44: PetscInt nwork;
45: Vec *work;
47: PetscReal lambda;
49: PetscBool norms;
50: PetscReal fnorm;
51: PetscReal ynorm;
52: PetscReal xnorm;
53: PetscBool keeplambda;
55: PetscReal damping;
56: PetscReal maxlambda;
57: PetscReal minlambda;
58: PetscInt max_it;
59: PetscReal rtol;
60: PetscReal atol;
61: PetscReal ltol;
62: PetscInt order;
64: PetscReal precheck_picard_angle;
66: void *precheckctx;
67: void *postcheckctx;
69: PetscBool jacobiandomainerror; /* set with SNESSetJacobianDomainError() */
70: PetscBool checkjacdomainerror; /* does it check Jacobian domain error after Jacobian evaluations */
72: SNESLineSearchReason reason;
74: PetscViewer monitor;
75: PetscErrorCode (*monitorftns[MAXSNESLSMONITORS])(SNESLineSearch, void *); /* monitor routine */
76: PetscCtxDestroyFn *monitordestroy[MAXSNESLSMONITORS]; /* monitor context destroy routine */
77: void *monitorcontext[MAXSNESLSMONITORS]; /* monitor context */
78: PetscInt numbermonitors; /* number of monitors */
79: };
81: /*MC
82: SNESLineSearchCheckFunctionDomainError - Called after a `SNESComputeFunction()` and `VecNorm()` in a `SNES` line search to check if the function norm is infinity or NaN and
83: if the function callback set with `SNESSetFunction()` called `SNESSetFunctionDomainError()`.
85: Synopsis:
86: #include <snesimpl.h>
87: void SNESLineSearchCheckFunctionDomainError(SNES snes, SNESLineSearch ls, PetscReal fnorm)
89: Collective
91: Input Parameters:
92: + snes - the `SNES` object
93: . ls - the `SNESLineSearch` object
94: - fnorm - the value of the norm
96: Level: developer
98: Notes:
99: If `fnorm` is infinity or NaN and `SNESSetErrorIfNotConverged()` was set, this immediately generates a `PETSC_ERR_CONV_FAILED`.
101: If `fnorm` is infinity or NaN and `SNESSetFunctionDomainError()` was called, this sets the `SNESLineSearchReason` to `SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN`
102: and exits the solver
104: Otherwise, if `fnorm` is infinity or NaN, this sets the `SNESLineSearchReason` to `SNES_LINESEARCH_FAILED_NANORINF` and exits the line search
106: See `SNESCheckFunctionDomainError()` for an explanation of the design
108: .seealso: [](ch_snes), `SNESCheckFunctionDomainError()`, `SNESSetFunctionDomainError()`, `PETSC_ERR_CONV_FAILED`, `SNESSetErrorIfNotConverged()`, `SNES_DIVERGED_FUNCTION_DOMAIN`,
109: `SNESConvergedReason`, `SNES_DIVERGED_FUNCTION_NAN`
110: MC*/
111: #define SNESLineSearchCheckFunctionDomainError(snes, ls, fnorm) \
112: do { \
113: if (PetscIsInfOrNanReal(fnorm)) { \
114: PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)ls), PETSC_ERR_NOT_CONVERGED, "SNES line search failure due to infinity or NaN norm"); \
115: { \
116: PetscBool functiondomainerror; \
117: PetscCallMPI(MPIU_Allreduce(&snes->functiondomainerror, &functiondomainerror, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)ls))); \
118: if (functiondomainerror) { \
119: ls->reason = SNES_LINESEARCH_FAILED_FUNCTION_DOMAIN; \
120: snes->functiondomainerror = PETSC_FALSE; \
121: } else ls->reason = SNES_LINESEARCH_FAILED_NANORINF; \
122: PetscFunctionReturn(PETSC_SUCCESS); \
123: } \
124: } \
125: } while (0)
127: /*MC
128: SNESLineSearchCheckObjectiveDomainError - Called after a `SNESComputeObjective()` in a `SNESLineSearch` to check if the objective value is infinity or NaN and/or
129: if the function callback set with `SNESSetObjective()` called `SNESSetObjectiveDomainError()`.
131: Synopsis:
132: #include <snesimpl.h>
133: void SNESLineSearchCheckObjectiveDomainError(SNES snes, PetscReal fobj)
135: Collective
137: Input Parameters:
138: + snes - the `SNES` solver object
139: - fobj - the value of the objective function
141: Level: developer
143: Notes:
144: If `fobj` is infinity or NaN and `SNESSetErrorIfNotConverged()` was set, this immediately generates a `PETSC_ERR_CONV_FAILED`.
146: If `SNESSetObjectiveDomainError()` was called, this sets the `SNESLineSearchReason` to `SNES_LINESEARCH_FAILED_OBJECTIVE_DOMAIN`
147: and exits the line search
149: Otherwise if `fobj` is infinity or NaN, this sets the `SNESLineSearchReason` to `SNES_LINESEARCH_FAILED_NANORINF` and exits the line search
151: .seealso: [](ch_snes), `SNESSetObjectiveDomainError()`, `PETSC_ERR_CONV_FAILED`, `SNESSetErrorIfNotConverged()`, `SNES_DIVERGED_OBJECTIVE_DOMAIN`, `SNES_DIVERGED_FUNCTION_DOMAIN`,
152: `SNESSetFunctionDomainError()`, `SNESConvergedReason`, `SNES_DIVERGED_OBJECTIVE_NANORINF`, `SNES_DIVERGED_FUNCTION_NAN`, `SNESLineSearchCheckObjectiveDomainError()`
153: MC*/
154: #define SNESLineSearchCheckObjectiveDomainError(snes, fobj) \
155: do { \
156: if (snes->errorifnotconverged) { \
157: PetscCheck(!snes->objectivedomainerror, PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESSolve has not converged due objective domain error"); \
158: PetscCheck(!PetscIsInfOrNanReal(fobj), PetscObjectComm((PetscObject)snes), PETSC_ERR_NOT_CONVERGED, "SNESSolve has not converged due to infinity or NaN norm"); \
159: } \
160: if (snes->objectivedomainerror) { \
161: snes->linesearch->reason = SNES_LINESEARCH_FAILED_OBJECTIVE_DOMAIN; \
162: snes->objectivedomainerror = PETSC_FALSE; \
163: PetscFunctionReturn(PETSC_SUCCESS); \
164: } else if (PetscIsInfOrNanReal(fobj)) { \
165: snes->linesearch->reason = SNES_LINESEARCH_FAILED_NANORINF; \
166: PetscFunctionReturn(PETSC_SUCCESS); \
167: } \
168: } while (0)
170: /*MC
171: SNESLineSearchCheckJacobianDomainError - Called after a `SNESComputeJacobian()` in a SNES line search to check if `SNESSetJacobianDomainError()` has been called.
173: Synopsis:
174: #include <snesimpl.h>
175: void SNESLineSearchCheckJacobian(SNES snes, SNESLineSearch ls)
177: Collective
179: Input Parameters:
180: + snes - the `SNES` solver object
181: - ls - the `SNESLineSearch` object
183: Level: developer
185: Notes:
186: This turns the non-collective `SNESSetJacobianDomainError()` into a collective operation
188: This check is done in debug mode or if `SNESSetCheckJacobianDomainError()` has been called
190: .seealso: [](ch_snes), `SNESSetCheckJacobianDomainError()`, `SNESSetFunctionDomainError()`, `PETSC_ERR_CONV_FAILED`, `SNESSetErrorIfNotConverged()`, `SNES_DIVERGED_FUNCTION_DOMAIN`,
191: `SNESConvergedReason`, `SNES_DIVERGED_FUNCTION_NAN`
192: MC*/
193: #define SNESLineSearchCheckJacobianDomainError(snes, ls) \
194: do { \
195: if (snes->checkjacdomainerror) { \
196: PetscBool jacobiandomainerror; \
197: PetscCallMPI(MPIU_Allreduce(&snes->jacobiandomainerror, &jacobiandomainerror, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)ls))); \
198: if (jacobiandomainerror) { \
199: ls->reason = SNES_LINESEARCH_FAILED_JACOBIAN_DOMAIN; \
200: snes->jacobiandomainerror = PETSC_FALSE; \
201: PetscCheck(!snes->errorifnotconverged, PetscObjectComm((PetscObject)ls), PETSC_ERR_NOT_CONVERGED, "SNESSolve has not converged due to Jacobian domain error"); \
202: PetscFunctionReturn(PETSC_SUCCESS); \
203: } \
204: } \
205: } while (0)