Actual source code: snesob.c

petsc-3.11.4 2019-09-28
Report Typos and Errors
  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: .      F - current function/gradient
 14: .      obj - real to hold the objective value
 15: -      ctx - optional user-defined objective context

 17:    Level: advanced

 19: .seealso:   SNESSetFunction(), SNESGetFunction(), SNESSetObjective(), SNESGetObjective(), SNESJacobianFunction, SNESFunction
 20: M*/


 23: /*@C
 24:    SNESSetObjective - Sets the objective function minimized by some of the SNES linesearch methods.

 26:    Logically Collective on SNES

 28:    Input Parameters:
 29: +  snes - the SNES context
 30: .  obj - objective evaluation routine; see SNESObjectiveFunction for details
 31: -  ctx - [optional] user-defined context for private data for the
 32:          function evaluation routine (may be NULL)

 34:    Level: intermediate

 36:    Note: This is not used in the SNESLINESEARCHCP line search.

 38:          If not provided then this defaults to the two norm of the function evaluation (set with SNESSetFunction())

 40: .keywords: SNES, nonlinear, set, objective

 42: .seealso: SNESGetObjective(), SNESComputeObjective(), SNESSetFunction(), SNESSetJacobian(), SNESObjectiveFunction
 43: @*/
 44: PetscErrorCode  SNESSetObjective(SNES snes,PetscErrorCode (*obj)(SNES,Vec,PetscReal*,void*),void *ctx)
 45: {
 47:   DM             dm;

 51:   SNESGetDM(snes,&dm);
 52:   DMSNESSetObjective(dm,obj,ctx);
 53:   return(0);
 54: }

 56: /*@C
 57:    SNESGetObjective - Returns the objective function.

 59:    Not Collective

 61:    Input Parameter:
 62: .  snes - the SNES context

 64:    Output Parameter:
 65: +  obj - objective evaluation routine (or NULL); see SNESObjectFunction for details
 66: -  ctx - the function context (or NULL)

 68:    Level: advanced

 70: .keywords: SNES, nonlinear, get, objective

 72: .seealso: SNESSetObjective(), SNESGetSolution()
 73: @*/
 74: PetscErrorCode SNESGetObjective(SNES snes,PetscErrorCode (**obj)(SNES,Vec,PetscReal*,void*),void **ctx)
 75: {
 77:   DM             dm;

 81:   SNESGetDM(snes,&dm);
 82:   DMSNESGetObjective(dm,obj,ctx);
 83:   return(0);
 84: }

 86: /*@C
 87:    SNESComputeObjective - Computes the objective.

 89:    Collective on SNES

 91:    Input Parameter:
 92: +  snes - the SNES context
 93: -  X    - the state vector

 95:    Output Parameter:
 96: .  ob   - the objective value

 98:    Level: advanced

100: .keywords: SNES, nonlinear, compute, objective

102: .seealso: SNESSetObjective(), SNESGetSolution()
103: @*/
104: PetscErrorCode SNESComputeObjective(SNES snes,Vec X,PetscReal *ob)
105: {
107:   DM             dm;
108:   DMSNES         sdm;

114:   SNESGetDM(snes,&dm);
115:   DMGetDMSNES(dm,&sdm);
116:   if (sdm->ops->computeobjective) {
117:     PetscLogEventBegin(SNES_ObjectiveEval,snes,X,0,0);
118:     (sdm->ops->computeobjective)(snes,X,ob,sdm->objectivectx);
119:     PetscLogEventEnd(SNES_ObjectiveEval,snes,X,0,0);
120:   } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "Must call SNESSetObjective() before SNESComputeObjective().");
121:   return(0);
122: }


125: /*@C
126:    SNESObjectiveComputeFunctionDefaultFD - Computes the gradient of a user provided objective

128:    Collective on SNES

130:    Input Parameter:
131: +  snes - the SNES context
132: .  X    - the state vector
133: -  ctx  - the (ignored) function context

135:    Output Parameter:
136: .  F   - the function value

138:    Options Database Key:
139: +  -snes_fd_function_eps - The differencing parameter
140: -  -snes_fd_function - Compute function from user provided objective with finite difference

142:    Notes:
143:    SNESObjectiveComputeFunctionDefaultFD is similar in character to SNESComputeJacobianDefault.
144:    Therefore, it should be used for debugging purposes only.  Using it in conjunction with
145:    SNESComputeJacobianDefault is excessively costly and produces a Jacobian that is quite
146:    noisy.  This is often necessary, but should be done with a grain of salt, even when debugging
147:    small problems.

149:    Note that this uses quadratic interpolation of the objective to form each value in the function.

151:    Level: advanced

153: .keywords: SNES, objective, debugging, finite differences, function

155: .seealso: SNESSetFunction(), SNESComputeObjective(), SNESComputeJacobianDefault()
156: @*/
157: PetscErrorCode SNESObjectiveComputeFunctionDefaultFD(SNES snes,Vec X,Vec F,void *ctx)
158: {
159:   Vec            Xh;
161:   PetscInt       i,N,start,end;
162:   PetscReal      ob,ob1,ob2,ob3,fob,dx,eps=1e-6;
163:   PetscScalar    fv,xv;

166:   VecDuplicate(X,&Xh);
167:   PetscOptionsBegin(PetscObjectComm((PetscObject)snes),((PetscObject)snes)->prefix,"Differencing parameters","SNES");
168:   PetscOptionsReal("-snes_fd_function_eps","Tolerance for nonzero entries in fd function","None",eps,&eps,NULL);
169:   PetscOptionsEnd();
170:   VecSet(F,0.);

172:   VecNorm(X,NORM_2,&fob);

174:   VecGetSize(X,&N);
175:   VecGetOwnershipRange(X,&start,&end);
176:   SNESComputeObjective(snes,X,&ob);

178:   if (fob > 0.) dx =1e-6*fob;
179:   else dx = 1e-6;

181:   for (i=0; i<N; i++) {
182:     /* compute the 1st value */
183:     VecCopy(X,Xh);
184:     if (i>= start && i<end) {
185:       xv   = dx;
186:       VecSetValues(Xh,1,&i,&xv,ADD_VALUES);
187:     }
188:     VecAssemblyBegin(Xh);
189:     VecAssemblyEnd(Xh);
190:     SNESComputeObjective(snes,Xh,&ob1);

192:     /* compute the 2nd value */
193:     VecCopy(X,Xh);
194:     if (i>= start && i<end) {
195:       xv   = 2.*dx;
196:       VecSetValues(Xh,1,&i,&xv,ADD_VALUES);
197:     }
198:     VecAssemblyBegin(Xh);
199:     VecAssemblyEnd(Xh);
200:     SNESComputeObjective(snes,Xh,&ob2);

202:     /* compute the 3rd value */
203:     VecCopy(X,Xh);
204:     if (i>= start && i<end) {
205:       xv   = -dx;
206:       VecSetValues(Xh,1,&i,&xv,ADD_VALUES);
207:     }
208:     VecAssemblyBegin(Xh);
209:     VecAssemblyEnd(Xh);
210:     SNESComputeObjective(snes,Xh,&ob3);

212:     if (i >= start && i<end) {
213:       /* set this entry to be the gradient of the objective */
214:       fv = (-ob2 + 6.*ob1 - 3.*ob -2.*ob3) / (6.*dx);
215:       if (PetscAbsScalar(fv) > eps) {
216:         VecSetValues(F,1,&i,&fv,INSERT_VALUES);
217:       } else {
218:         fv   = 0.;
219:         VecSetValues(F,1,&i,&fv,INSERT_VALUES);
220:       }
221:     }
222:   }

224:   VecDestroy(&Xh);

226:   VecAssemblyBegin(F);
227:   VecAssemblyEnd(F);
228:   return(0);
229: }