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: }