xref: /petsc/src/snes/interface/snesob.c (revision 420bcc1b905230dede3c88f397d1a4e60493adde)
1af0996ceSBarry Smith #include <petsc/private/snesimpl.h>
22a4ee8f2SPeter Brune 
3075cc632SBarry Smith /*MC
4dc4c0fb0SBarry Smith     SNESObjectiveFunction - functional form used to convey an objective function to the nonlinear solver, that will be used instead of the 2-norm of the residual
52a4ee8f2SPeter Brune 
6075cc632SBarry Smith      Synopsis:
7aaa7dc30SBarry Smith      #include <petscsnes.h>
8075cc632SBarry Smith        SNESObjectiveFunction(SNES snes,Vec x,PetscReal *obj,void *ctx);
92a4ee8f2SPeter Brune 
102a4ee8f2SPeter Brune      Input Parameters:
11dc4c0fb0SBarry Smith +      snes - the `SNES` context
122a4ee8f2SPeter Brune .      X    - solution
132a4ee8f2SPeter Brune .      obj  - real to hold the objective value
142a4ee8f2SPeter Brune -      ctx  - optional user-defined objective context
152a4ee8f2SPeter Brune 
16878cb397SSatish Balay    Level: advanced
17878cb397SSatish Balay 
18*420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESSetFunction()`, `SNESGetFunction()`, `SNESSetObjective()`, `SNESGetObjective()`, `SNESJacobianFunction`, `SNESFunction`
19075cc632SBarry Smith M*/
20075cc632SBarry Smith 
21075cc632SBarry Smith /*@C
22dc4c0fb0SBarry Smith   SNESSetObjective - Sets the objective function minimized by some of the `SNES` linesearch methods, used instead of the 2-norm of the residual
23075cc632SBarry Smith 
24c3339decSBarry Smith   Logically Collective
25075cc632SBarry Smith 
26075cc632SBarry Smith   Input Parameters:
27f6dfbefdSBarry Smith + snes - the `SNES` context
28f6dfbefdSBarry Smith . obj  - objective evaluation routine; see `SNESObjectiveFunction` for details
29075cc632SBarry Smith - ctx  - [optional] user-defined context for private data for the
30dc4c0fb0SBarry Smith          function evaluation routine (may be `NULL`)
31075cc632SBarry Smith 
322b26979fSBarry Smith   Level: intermediate
332a4ee8f2SPeter Brune 
34f6dfbefdSBarry Smith   Note:
35f6dfbefdSBarry Smith   Some of the `SNESLineSearch` methods attempt to minimize a given objective provided by this function to determine a step length.
36eb23ba39SBarry Smith 
37*420bcc1bSBarry Smith   If not provided then this defaults to the two-norm of the function evaluation (set with `SNESSetFunction()`)
38075cc632SBarry Smith 
39f6dfbefdSBarry Smith   This is not used in the `SNESLINESEARCHCP` line search.
40f6dfbefdSBarry Smith 
41*420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESLineSearch()`, `SNESGetObjective()`, `SNESComputeObjective()`, `SNESSetFunction()`, `SNESSetJacobian()`, `SNESObjectiveFunction`
422a4ee8f2SPeter Brune @*/
43d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESSetObjective(SNES snes, PetscErrorCode (*obj)(SNES, Vec, PetscReal *, void *), void *ctx)
44d71ae5a4SJacob Faibussowitsch {
452a4ee8f2SPeter Brune   DM dm;
462a4ee8f2SPeter Brune 
472a4ee8f2SPeter Brune   PetscFunctionBegin;
482a4ee8f2SPeter Brune   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
499566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
509566063dSJacob Faibussowitsch   PetscCall(DMSNESSetObjective(dm, obj, ctx));
513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
522a4ee8f2SPeter Brune }
532a4ee8f2SPeter Brune 
542a4ee8f2SPeter Brune /*@C
55dc4c0fb0SBarry Smith   SNESGetObjective - Returns the objective function set with `SNESSetObjective()`
562a4ee8f2SPeter Brune 
572a4ee8f2SPeter Brune   Not Collective
582a4ee8f2SPeter Brune 
592a4ee8f2SPeter Brune   Input Parameter:
60f6dfbefdSBarry Smith . snes - the `SNES` context
612a4ee8f2SPeter Brune 
62d8d19677SJose E. Roman   Output Parameters:
63*420bcc1bSBarry Smith + obj - objective evaluation routine (or `NULL`); see `SNESObjectiveFunction` for details
64dc4c0fb0SBarry Smith - ctx - the function context (or `NULL`)
652a4ee8f2SPeter Brune 
662a4ee8f2SPeter Brune   Level: advanced
672a4ee8f2SPeter Brune 
68*420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESSetObjective()`, `SNESObjectiveFunction`, `SNESGetSolution()`
692a4ee8f2SPeter Brune @*/
70d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESGetObjective(SNES snes, PetscErrorCode (**obj)(SNES, Vec, PetscReal *, void *), void **ctx)
71d71ae5a4SJacob Faibussowitsch {
722a4ee8f2SPeter Brune   DM dm;
735fd66863SKarl Rupp 
742a4ee8f2SPeter Brune   PetscFunctionBegin;
752a4ee8f2SPeter Brune   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
769566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
779566063dSJacob Faibussowitsch   PetscCall(DMSNESGetObjective(dm, obj, ctx));
783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
792a4ee8f2SPeter Brune }
802a4ee8f2SPeter Brune 
812a4ee8f2SPeter Brune /*@C
82f6dfbefdSBarry Smith   SNESComputeObjective - Computes the objective function that has been provided by `SNESSetObjective()`
832a4ee8f2SPeter Brune 
84c3339decSBarry Smith   Collective
852a4ee8f2SPeter Brune 
86d8d19677SJose E. Roman   Input Parameters:
87f6dfbefdSBarry Smith + snes - the `SNES` context
882a4ee8f2SPeter Brune - X    - the state vector
892a4ee8f2SPeter Brune 
902a4ee8f2SPeter Brune   Output Parameter:
912a4ee8f2SPeter Brune . ob - the objective value
922a4ee8f2SPeter Brune 
93f6dfbefdSBarry Smith   Level: developer
942a4ee8f2SPeter Brune 
95*420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESLineSearch`, `SNES`, `SNESSetObjective()`, `SNESGetSolution()`
962a4ee8f2SPeter Brune @*/
97d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESComputeObjective(SNES snes, Vec X, PetscReal *ob)
98d71ae5a4SJacob Faibussowitsch {
992a4ee8f2SPeter Brune   DM     dm;
100942e3340SBarry Smith   DMSNES sdm;
101f23aa3ddSBarry Smith 
1022a4ee8f2SPeter Brune   PetscFunctionBegin;
1032a4ee8f2SPeter Brune   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
1042a4ee8f2SPeter Brune   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
1054f572ea9SToby Isaac   PetscAssertPointer(ob, 3);
1069566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
1079566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(dm, &sdm));
1080fdf79fbSJacob Faibussowitsch   PetscCheck(sdm->ops->computeobjective, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Must call SNESSetObjective() before SNESComputeObjective().");
1099566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(SNES_ObjectiveEval, snes, X, 0, 0));
1109566063dSJacob Faibussowitsch   PetscCall((sdm->ops->computeobjective)(snes, X, ob, sdm->objectivectx));
1119566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(SNES_ObjectiveEval, snes, X, 0, 0));
1123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1132a4ee8f2SPeter Brune }
11497584545SPeter Brune 
1155c3e6ab7SPeter Brune /*@C
116f6dfbefdSBarry Smith   SNESObjectiveComputeFunctionDefaultFD - Computes the gradient of a user provided objective function
1175c3e6ab7SPeter Brune 
118c3339decSBarry Smith   Collective
1195c3e6ab7SPeter Brune 
120d8d19677SJose E. Roman   Input Parameters:
121f6dfbefdSBarry Smith + snes - the `SNES` context
1225c3e6ab7SPeter Brune . X    - the state vector
1235c3e6ab7SPeter Brune - ctx  - the (ignored) function context
1245c3e6ab7SPeter Brune 
1255c3e6ab7SPeter Brune   Output Parameter:
1265c3e6ab7SPeter Brune . F - the function value
1275c3e6ab7SPeter Brune 
128f6dfbefdSBarry Smith   Options Database Keys:
129f6dfbefdSBarry Smith + -snes_fd_function_eps - Tolerance for including non-zero entries into the gradient, default is 1.e-6
130f6dfbefdSBarry Smith - -snes_fd_function     - Computes function from user provided objective function (set with `SNESSetObjective()`) with finite difference
1315c3e6ab7SPeter Brune 
132dc4c0fb0SBarry Smith   Level: advanced
133dc4c0fb0SBarry Smith 
1345c3e6ab7SPeter Brune   Notes:
135f6dfbefdSBarry Smith   This function can be used with `SNESSetFunction()` to have the nonlinear function solved for with `SNES` defined by the gradient of an objective function
136f6dfbefdSBarry Smith   `SNESObjectiveComputeFunctionDefaultFD()` is similar in character to `SNESComputeJacobianDefault()`.
1375c3e6ab7SPeter Brune   Therefore, it should be used for debugging purposes only.  Using it in conjunction with
138f6dfbefdSBarry Smith   `SNESComputeJacobianDefault()` is excessively costly and produces a Jacobian that is quite
139f6dfbefdSBarry Smith   noisy.  This is often necessary, but should be done with care, even when debugging
1405c3e6ab7SPeter Brune   small problems.
1415c3e6ab7SPeter Brune 
142*420bcc1bSBarry Smith   This uses quadratic interpolation of the objective to form each value in the function.
1435c3e6ab7SPeter Brune 
144*420bcc1bSBarry Smith .seealso: [](ch_snes), `SNESSetObjective()`, `SNESSetFunction()`, `SNESComputeObjective()`, `SNESComputeJacobianDefault()`
1455c3e6ab7SPeter Brune @*/
146d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESObjectiveComputeFunctionDefaultFD(SNES snes, Vec X, Vec F, void *ctx)
147d71ae5a4SJacob Faibussowitsch {
14897584545SPeter Brune   Vec         Xh;
14997584545SPeter Brune   PetscInt    i, N, start, end;
15097584545SPeter Brune   PetscReal   ob, ob1, ob2, ob3, fob, dx, eps = 1e-6;
15197584545SPeter Brune   PetscScalar fv, xv;
15297584545SPeter Brune 
15397584545SPeter Brune   PetscFunctionBegin;
1549566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &Xh));
155d0609cedSBarry Smith   PetscOptionsBegin(PetscObjectComm((PetscObject)snes), ((PetscObject)snes)->prefix, "Differencing parameters", "SNES");
1569566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-snes_fd_function_eps", "Tolerance for nonzero entries in fd function", "None", eps, &eps, NULL));
157d0609cedSBarry Smith   PetscOptionsEnd();
1589566063dSJacob Faibussowitsch   PetscCall(VecSet(F, 0.));
15997584545SPeter Brune 
1609566063dSJacob Faibussowitsch   PetscCall(VecNorm(X, NORM_2, &fob));
16197584545SPeter Brune 
1629566063dSJacob Faibussowitsch   PetscCall(VecGetSize(X, &N));
1639566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(X, &start, &end));
1649566063dSJacob Faibussowitsch   PetscCall(SNESComputeObjective(snes, X, &ob));
16597584545SPeter Brune 
166f5af7f23SKarl Rupp   if (fob > 0.) dx = 1e-6 * fob;
167f5af7f23SKarl Rupp   else dx = 1e-6;
16897584545SPeter Brune 
16997584545SPeter Brune   for (i = 0; i < N; i++) {
17097584545SPeter Brune     /* compute the 1st value */
1719566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, Xh));
17297584545SPeter Brune     if (i >= start && i < end) {
17397584545SPeter Brune       xv = dx;
1749566063dSJacob Faibussowitsch       PetscCall(VecSetValues(Xh, 1, &i, &xv, ADD_VALUES));
17597584545SPeter Brune     }
1769566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(Xh));
1779566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(Xh));
1789566063dSJacob Faibussowitsch     PetscCall(SNESComputeObjective(snes, Xh, &ob1));
17997584545SPeter Brune 
18097584545SPeter Brune     /* compute the 2nd value */
1819566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, Xh));
18297584545SPeter Brune     if (i >= start && i < end) {
18397584545SPeter Brune       xv = 2. * dx;
1849566063dSJacob Faibussowitsch       PetscCall(VecSetValues(Xh, 1, &i, &xv, ADD_VALUES));
18597584545SPeter Brune     }
1869566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(Xh));
1879566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(Xh));
1889566063dSJacob Faibussowitsch     PetscCall(SNESComputeObjective(snes, Xh, &ob2));
18997584545SPeter Brune 
19097584545SPeter Brune     /* compute the 3rd value */
1919566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, Xh));
19297584545SPeter Brune     if (i >= start && i < end) {
19397584545SPeter Brune       xv = -dx;
1949566063dSJacob Faibussowitsch       PetscCall(VecSetValues(Xh, 1, &i, &xv, ADD_VALUES));
19597584545SPeter Brune     }
1969566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(Xh));
1979566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(Xh));
1989566063dSJacob Faibussowitsch     PetscCall(SNESComputeObjective(snes, Xh, &ob3));
19997584545SPeter Brune 
20097584545SPeter Brune     if (i >= start && i < end) {
20197584545SPeter Brune       /* set this entry to be the gradient of the objective */
20297584545SPeter Brune       fv = (-ob2 + 6. * ob1 - 3. * ob - 2. * ob3) / (6. * dx);
20397584545SPeter Brune       if (PetscAbsScalar(fv) > eps) {
2049566063dSJacob Faibussowitsch         PetscCall(VecSetValues(F, 1, &i, &fv, INSERT_VALUES));
20597584545SPeter Brune       } else {
20697584545SPeter Brune         fv = 0.;
2079566063dSJacob Faibussowitsch         PetscCall(VecSetValues(F, 1, &i, &fv, INSERT_VALUES));
20897584545SPeter Brune       }
20997584545SPeter Brune     }
21097584545SPeter Brune   }
2119566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&Xh));
2129566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(F));
2139566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(F));
2143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21597584545SPeter Brune }
216