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)