Actual source code: snesob.c
petsc-3.14.6 2021-03-30
1: #include <petsc/private/snesimpl.h>
3: /*MC
4: SNESObjectiveFunction - functional form used to convey the objective function to the nonlinear solver
6: Synopsis:
7: #include <petscsnes.h>
8: SNESObjectiveFunction(SNES snes,Vec x,PetscReal *obj,void *ctx);
10: Input Parameters:
11: + snes - the SNES context
12: . X - solution
13: . obj - real to hold the objective value
14: - ctx - optional user-defined objective context
16: Level: advanced
18: .seealso: SNESSetFunction(), SNESGetFunction(), SNESSetObjective(), SNESGetObjective(), SNESJacobianFunction, SNESFunction
19: M*/
22: /*@C
23: SNESSetObjective - Sets the objective function minimized by some of the SNES linesearch methods.
25: Logically Collective on SNES
27: Input Parameters:
28: + snes - the SNES context
29: . obj - objective evaluation routine; see SNESObjectiveFunction for details
30: - ctx - [optional] user-defined context for private data for the
31: function evaluation routine (may be NULL)
33: Level: intermediate
35: Note: This is not used in the SNESLINESEARCHCP line search.
37: If not provided then this defaults to the two norm of the function evaluation (set with SNESSetFunction())
39: .seealso: SNESGetObjective(), SNESComputeObjective(), SNESSetFunction(), SNESSetJacobian(), SNESObjectiveFunction
40: @*/
41: PetscErrorCode SNESSetObjective(SNES snes,PetscErrorCode (*obj)(SNES,Vec,PetscReal*,void*),void *ctx)
42: {
44: DM dm;
48: SNESGetDM(snes,&dm);
49: DMSNESSetObjective(dm,obj,ctx);
50: return(0);
51: }
53: /*@C
54: SNESGetObjective - Returns the objective function.
56: Not Collective
58: Input Parameter:
59: . snes - the SNES context
61: Output Parameter:
62: + obj - objective evaluation routine (or NULL); see SNESObjectFunction for details
63: - ctx - the function context (or NULL)
65: Level: advanced
67: .seealso: SNESSetObjective(), SNESGetSolution()
68: @*/
69: PetscErrorCode SNESGetObjective(SNES snes,PetscErrorCode (**obj)(SNES,Vec,PetscReal*,void*),void **ctx)
70: {
72: DM dm;
76: SNESGetDM(snes,&dm);
77: DMSNESGetObjective(dm,obj,ctx);
78: return(0);
79: }
81: /*@C
82: SNESComputeObjective - Computes the objective.
84: Collective on SNES
86: Input Parameter:
87: + snes - the SNES context
88: - X - the state vector
90: Output Parameter:
91: . ob - the objective value
93: Level: advanced
95: .seealso: SNESSetObjective(), SNESGetSolution()
96: @*/
97: PetscErrorCode SNESComputeObjective(SNES snes,Vec X,PetscReal *ob)
98: {
100: DM dm;
101: DMSNES sdm;
107: SNESGetDM(snes,&dm);
108: DMGetDMSNES(dm,&sdm);
109: if (sdm->ops->computeobjective) {
110: PetscLogEventBegin(SNES_ObjectiveEval,snes,X,0,0);
111: (sdm->ops->computeobjective)(snes,X,ob,sdm->objectivectx);
112: PetscLogEventEnd(SNES_ObjectiveEval,snes,X,0,0);
113: } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "Must call SNESSetObjective() before SNESComputeObjective().");
114: return(0);
115: }
118: /*@C
119: SNESObjectiveComputeFunctionDefaultFD - Computes the gradient of a user provided objective
121: Collective on SNES
123: Input Parameter:
124: + snes - the SNES context
125: . X - the state vector
126: - ctx - the (ignored) function context
128: Output Parameter:
129: . F - the function value
131: Options Database Key:
132: + -snes_fd_function_eps - The differencing parameter
133: - -snes_fd_function - Compute function from user provided objective with finite difference
135: Notes:
136: SNESObjectiveComputeFunctionDefaultFD is similar in character to SNESComputeJacobianDefault.
137: Therefore, it should be used for debugging purposes only. Using it in conjunction with
138: SNESComputeJacobianDefault is excessively costly and produces a Jacobian that is quite
139: noisy. This is often necessary, but should be done with a grain of salt, even when debugging
140: small problems.
142: Note that this uses quadratic interpolation of the objective to form each value in the function.
144: Level: advanced
146: .seealso: SNESSetFunction(), SNESComputeObjective(), SNESComputeJacobianDefault()
147: @*/
148: PetscErrorCode SNESObjectiveComputeFunctionDefaultFD(SNES snes,Vec X,Vec F,void *ctx)
149: {
150: Vec Xh;
152: PetscInt i,N,start,end;
153: PetscReal ob,ob1,ob2,ob3,fob,dx,eps=1e-6;
154: PetscScalar fv,xv;
157: VecDuplicate(X,&Xh);
158: PetscOptionsBegin(PetscObjectComm((PetscObject)snes),((PetscObject)snes)->prefix,"Differencing parameters","SNES");
159: PetscOptionsReal("-snes_fd_function_eps","Tolerance for nonzero entries in fd function","None",eps,&eps,NULL);
160: PetscOptionsEnd();
161: VecSet(F,0.);
163: VecNorm(X,NORM_2,&fob);
165: VecGetSize(X,&N);
166: VecGetOwnershipRange(X,&start,&end);
167: SNESComputeObjective(snes,X,&ob);
169: if (fob > 0.) dx =1e-6*fob;
170: else dx = 1e-6;
172: for (i=0; i<N; i++) {
173: /* compute the 1st value */
174: VecCopy(X,Xh);
175: if (i>= start && i<end) {
176: xv = dx;
177: VecSetValues(Xh,1,&i,&xv,ADD_VALUES);
178: }
179: VecAssemblyBegin(Xh);
180: VecAssemblyEnd(Xh);
181: SNESComputeObjective(snes,Xh,&ob1);
183: /* compute the 2nd value */
184: VecCopy(X,Xh);
185: if (i>= start && i<end) {
186: xv = 2.*dx;
187: VecSetValues(Xh,1,&i,&xv,ADD_VALUES);
188: }
189: VecAssemblyBegin(Xh);
190: VecAssemblyEnd(Xh);
191: SNESComputeObjective(snes,Xh,&ob2);
193: /* compute the 3rd value */
194: VecCopy(X,Xh);
195: if (i>= start && i<end) {
196: xv = -dx;
197: VecSetValues(Xh,1,&i,&xv,ADD_VALUES);
198: }
199: VecAssemblyBegin(Xh);
200: VecAssemblyEnd(Xh);
201: SNESComputeObjective(snes,Xh,&ob3);
203: if (i >= start && i<end) {
204: /* set this entry to be the gradient of the objective */
205: fv = (-ob2 + 6.*ob1 - 3.*ob -2.*ob3) / (6.*dx);
206: if (PetscAbsScalar(fv) > eps) {
207: VecSetValues(F,1,&i,&fv,INSERT_VALUES);
208: } else {
209: fv = 0.;
210: VecSetValues(F,1,&i,&fv,INSERT_VALUES);
211: }
212: }
213: }
215: VecDestroy(&Xh);
217: VecAssemblyBegin(F);
218: VecAssemblyEnd(F);
219: return(0);
220: }