Actual source code: taosnes.c

  1: #include <petsc/private/taoimpl.h>

  3: typedef struct {
  4:   SNES      snes;
  5:   PetscBool setfromoptionscalled;
  6: } Tao_SNES;

  8: static PetscErrorCode TaoSolve_SNES(Tao tao)
  9: {
 10:   Tao_SNES           *taosnes = (Tao_SNES *)tao->data;
 11:   SNESConvergedReason reason;
 12:   PetscInt            its;

 14:   PetscFunctionBegin;
 15:   /* TODO SNES fails if KSP reaches max_it, while TAO accepts whatever we got */
 16:   PetscCall(SNESSolve(taosnes->snes, NULL, tao->solution));
 17:   PetscCall(SNESGetConvergedReason(taosnes->snes, &reason));
 18:   tao->reason = TaoConvergedReasonFromSNES(reason);
 19:   PetscCall(SNESGetIterationNumber(taosnes->snes, &its));
 20:   PetscCall(TaoSetIterationNumber(tao, its));
 21:   PetscFunctionReturn(PETSC_SUCCESS);
 22: }

 24: static PetscErrorCode TaoDestroy_SNES(Tao tao)
 25: {
 26:   Tao_SNES *taosnes = (Tao_SNES *)tao->data;

 28:   PetscFunctionBegin;
 29:   PetscCall(SNESDestroy(&taosnes->snes));
 30:   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoSNESGetSNES_C", NULL));
 31:   PetscCall(PetscFree(tao->data));
 32:   PetscFunctionReturn(PETSC_SUCCESS);
 33: }

 35: static PetscErrorCode TAOSNESObj(SNES snes, Vec X, PetscReal *f, PetscCtx ctx)
 36: {
 37:   Tao tao = (Tao)ctx;

 39:   PetscFunctionBegin;
 40:   PetscCall(TaoComputeObjective(tao, X, f));
 41:   PetscFunctionReturn(PETSC_SUCCESS);
 42: }

 44: static PetscErrorCode TAOSNESFunc(SNES snes, Vec X, Vec F, PetscCtx ctx)
 45: {
 46:   Tao tao = (Tao)ctx;

 48:   PetscFunctionBegin;
 49:   PetscCall(TaoComputeGradient(tao, X, F));
 50:   PetscFunctionReturn(PETSC_SUCCESS);
 51: }

 53: static PetscErrorCode TAOSNESJac(SNES snes, Vec X, Mat A, Mat P, PetscCtx ctx)
 54: {
 55:   Tao tao = (Tao)ctx;

 57:   PetscFunctionBegin;
 58:   PetscCall(TaoComputeHessian(tao, X, A, P));
 59:   PetscFunctionReturn(PETSC_SUCCESS);
 60: }

 62: static PetscErrorCode TAOSNESMonitor(SNES snes, PetscInt its, PetscReal fnorm, PetscCtx ctx)
 63: {
 64:   Tao       tao = (Tao)ctx;
 65:   PetscReal obj;
 66:   Vec       X;

 68:   PetscFunctionBegin;
 69:   PetscCall(SNESGetSolution(snes, &X));
 70:   PetscCall(TaoComputeObjective(tao, X, &obj));
 71:   PetscCall(TaoSetIterationNumber(tao, its));
 72:   PetscCall(TaoMonitor(tao, its, obj, fnorm, 0.0, 0.0));
 73:   PetscFunctionReturn(PETSC_SUCCESS);
 74: }

 76: static PetscErrorCode TaoSetUp_SNES(Tao tao)
 77: {
 78:   Tao_SNES   *taosnes = (Tao_SNES *)tao->data;
 79:   Mat         A, P;
 80:   const char *prefix;

 82:   PetscFunctionBegin;
 83:   PetscCall(TaoGetOptionsPrefix(tao, &prefix));
 84:   PetscCall(SNESSetOptionsPrefix(taosnes->snes, prefix));
 85:   PetscCall(SNESSetSolution(taosnes->snes, tao->solution));
 86:   PetscCall(SNESSetObjective(taosnes->snes, TAOSNESObj, tao));
 87:   PetscCall(SNESSetFunction(taosnes->snes, NULL, TAOSNESFunc, tao));
 88:   PetscCall(SNESMonitorSet(taosnes->snes, TAOSNESMonitor, tao, NULL));
 89:   PetscCall(TaoGetHessian(tao, &A, &P, NULL, NULL));
 90:   if (A) PetscCall(SNESSetJacobian(taosnes->snes, A, P, TAOSNESJac, tao));
 91:   if (taosnes->setfromoptionscalled) PetscCall(SNESSetFromOptions(taosnes->snes));
 92:   taosnes->setfromoptionscalled = PETSC_FALSE;
 93:   PetscCall(SNESSetUp(taosnes->snes));
 94:   PetscFunctionReturn(PETSC_SUCCESS);
 95: }

 97: static PetscErrorCode TaoSetFromOptions_SNES(Tao tao, PetscOptionItems PetscOptionsObject)
 98: {
 99:   Tao_SNES *taosnes = (Tao_SNES *)tao->data;

101:   PetscFunctionBegin;
102:   taosnes->setfromoptionscalled = PETSC_TRUE;
103:   PetscFunctionReturn(PETSC_SUCCESS);
104: }

106: static PetscErrorCode TaoView_SNES(Tao tao, PetscViewer viewer)
107: {
108:   Tao_SNES *taosnes = (Tao_SNES *)tao->data;

110:   PetscFunctionBegin;
111:   PetscCall(SNESView(taosnes->snes, viewer));
112:   PetscFunctionReturn(PETSC_SUCCESS);
113: }

115: static PetscErrorCode TaoSNESGetSNES_SNES(Tao tao, SNES *snes)
116: {
117:   Tao_SNES *taosnes = (Tao_SNES *)tao->data;

119:   PetscFunctionBegin;
120:   *snes = taosnes->snes;
121:   PetscFunctionReturn(PETSC_SUCCESS);
122: }

124: /*@
125:   TaoSNESGetSNES - Gets the nonlinear solver used by `TAOSNES`.

127:   Not Collective

129:   Input Parameter:
130: . tao - the `Tao` solver

132:   Output Parameter:
133: . snes - the underlying nonlinear solver

135:   Level: advanced

137:   Notes:
138:   The `Tao` type must be `TAOSNES`. The returned object is owned by `tao` and must not be destroyed by the caller.

140:   Use `SNESGetConvergedReason()` to obtain the precise nonlinear termination reason.
141:   `TAOSNES` maps reasons with a `TaoConvergedReason` equivalent to that value; other reasons map to
142:   `TAO_CONVERGED_USER` or `TAO_DIVERGED_USER` according to their sign.
143:   The mapped reasons refer to the tolerances and limits of the underlying `SNES`.

145: .seealso: [](ch_tao), `Tao`, `TAOSNES`, `TaoGetConvergedReason()`, `TaoConvergedReasonFromSNES()`, `SNESGetType()`, `SNESGetConvergedReason()`
146: @*/
147: PetscErrorCode TaoSNESGetSNES(Tao tao, SNES *snes)
148: {
149:   PetscFunctionBegin;
151:   PetscAssertPointer(snes, 2);
152:   PetscUseMethod(tao, "TaoSNESGetSNES_C", (Tao, SNES *), (tao, snes));
153:   PetscFunctionReturn(PETSC_SUCCESS);
154: }

156: /*MC
157:   TAOSNES - nonlinear solver using SNES

159:    Level: advanced

161: .seealso: `TaoCreate()`, `Tao`, `TaoSetType()`, `TaoType`, `TaoSNESGetSNES()`
162: M*/
163: PETSC_EXTERN PetscErrorCode TaoCreate_SNES(Tao tao)
164: {
165:   Tao_SNES *taosnes;

167:   PetscFunctionBegin;
168:   tao->ops->destroy          = TaoDestroy_SNES;
169:   tao->ops->setup            = TaoSetUp_SNES;
170:   tao->ops->setfromoptions   = TaoSetFromOptions_SNES;
171:   tao->ops->view             = TaoView_SNES;
172:   tao->ops->solve            = TaoSolve_SNES;
173:   tao->uses_gradient         = PETSC_TRUE;
174:   tao->uses_hessian_matrices = PETSC_TRUE;

176:   PetscCall(PetscNew(&taosnes));
177:   tao->data = (void *)taosnes;
178:   PetscCall(SNESCreate(PetscObjectComm((PetscObject)tao), &taosnes->snes));
179:   {
180:     DM dm;

182:     PetscCall(TaoGetDM(tao, &dm));
183:     PetscCall(SNESSetDM(taosnes->snes, dm));
184:   }
185:   PetscCall(PetscObjectIncrementTabLevel((PetscObject)taosnes->snes, (PetscObject)tao, 1));
186:   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoSNESGetSNES_C", TaoSNESGetSNES_SNES));
187:   PetscFunctionReturn(PETSC_SUCCESS);
188: }