xref: /petsc/src/snes/interface/snesob.c (revision 9566063d113dddea24716c546802770db7481bc0)
1af0996ceSBarry Smith #include <petsc/private/snesimpl.h>
22a4ee8f2SPeter Brune 
3075cc632SBarry Smith /*MC
4075cc632SBarry Smith     SNESObjectiveFunction - functional form used to convey the objective function to the nonlinear solver
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:
112a4ee8f2SPeter Brune +      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 
18f8b49ee9SBarry Smith .seealso:   SNESSetFunction(), SNESGetFunction(), SNESSetObjective(), SNESGetObjective(), SNESJacobianFunction, SNESFunction
19075cc632SBarry Smith M*/
20075cc632SBarry Smith 
21075cc632SBarry Smith /*@C
22eb23ba39SBarry Smith    SNESSetObjective - Sets the objective function minimized by some of the SNES linesearch methods.
23075cc632SBarry Smith 
24075cc632SBarry Smith    Logically Collective on SNES
25075cc632SBarry Smith 
26075cc632SBarry Smith    Input Parameters:
27075cc632SBarry Smith +  snes - the SNES context
28f8b49ee9SBarry Smith .  obj - objective evaluation routine; see SNESObjectiveFunction for details
29075cc632SBarry Smith -  ctx - [optional] user-defined context for private data for the
300298fd71SBarry Smith          function evaluation routine (may be NULL)
31075cc632SBarry Smith 
322b26979fSBarry Smith    Level: intermediate
332a4ee8f2SPeter Brune 
34eb23ba39SBarry Smith    Note: This is not used in the SNESLINESEARCHCP line search.
35eb23ba39SBarry Smith 
36eb23ba39SBarry Smith          If not provided then this defaults to the two norm of the function evaluation (set with SNESSetFunction())
37075cc632SBarry Smith 
38075cc632SBarry Smith .seealso: SNESGetObjective(), SNESComputeObjective(), SNESSetFunction(), SNESSetJacobian(), SNESObjectiveFunction
392a4ee8f2SPeter Brune @*/
40f8b49ee9SBarry Smith PetscErrorCode  SNESSetObjective(SNES snes,PetscErrorCode (*obj)(SNES,Vec,PetscReal*,void*),void *ctx)
412a4ee8f2SPeter Brune {
422a4ee8f2SPeter Brune   DM             dm;
432a4ee8f2SPeter Brune 
442a4ee8f2SPeter Brune   PetscFunctionBegin;
452a4ee8f2SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
46*9566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes,&dm));
47*9566063dSJacob Faibussowitsch   PetscCall(DMSNESSetObjective(dm,obj,ctx));
482a4ee8f2SPeter Brune   PetscFunctionReturn(0);
492a4ee8f2SPeter Brune }
502a4ee8f2SPeter Brune 
512a4ee8f2SPeter Brune /*@C
522a4ee8f2SPeter Brune    SNESGetObjective - Returns the objective function.
532a4ee8f2SPeter Brune 
542a4ee8f2SPeter Brune    Not Collective
552a4ee8f2SPeter Brune 
562a4ee8f2SPeter Brune    Input Parameter:
572a4ee8f2SPeter Brune .  snes - the SNES context
582a4ee8f2SPeter Brune 
59d8d19677SJose E. Roman    Output Parameters:
60f8b49ee9SBarry Smith +  obj - objective evaluation routine (or NULL); see SNESObjectFunction for details
610298fd71SBarry Smith -  ctx - the function context (or NULL)
622a4ee8f2SPeter Brune 
632a4ee8f2SPeter Brune    Level: advanced
642a4ee8f2SPeter Brune 
652a4ee8f2SPeter Brune .seealso: SNESSetObjective(), SNESGetSolution()
662a4ee8f2SPeter Brune @*/
67f8b49ee9SBarry Smith PetscErrorCode SNESGetObjective(SNES snes,PetscErrorCode (**obj)(SNES,Vec,PetscReal*,void*),void **ctx)
682a4ee8f2SPeter Brune {
692a4ee8f2SPeter Brune   DM             dm;
705fd66863SKarl Rupp 
712a4ee8f2SPeter Brune   PetscFunctionBegin;
722a4ee8f2SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
73*9566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes,&dm));
74*9566063dSJacob Faibussowitsch   PetscCall(DMSNESGetObjective(dm,obj,ctx));
752a4ee8f2SPeter Brune   PetscFunctionReturn(0);
762a4ee8f2SPeter Brune }
772a4ee8f2SPeter Brune 
782a4ee8f2SPeter Brune /*@C
792a4ee8f2SPeter Brune    SNESComputeObjective - Computes the objective.
802a4ee8f2SPeter Brune 
812a4ee8f2SPeter Brune    Collective on SNES
822a4ee8f2SPeter Brune 
83d8d19677SJose E. Roman    Input Parameters:
842a4ee8f2SPeter Brune +  snes - the SNES context
852a4ee8f2SPeter Brune -  X    - the state vector
862a4ee8f2SPeter Brune 
872a4ee8f2SPeter Brune    Output Parameter:
882a4ee8f2SPeter Brune .  ob   - the objective value
892a4ee8f2SPeter Brune 
902a4ee8f2SPeter Brune    Level: advanced
912a4ee8f2SPeter Brune 
922a4ee8f2SPeter Brune .seealso: SNESSetObjective(), SNESGetSolution()
932a4ee8f2SPeter Brune @*/
942a4ee8f2SPeter Brune PetscErrorCode SNESComputeObjective(SNES snes,Vec X,PetscReal *ob)
952a4ee8f2SPeter Brune {
962a4ee8f2SPeter Brune   DM             dm;
97942e3340SBarry Smith   DMSNES         sdm;
98f23aa3ddSBarry Smith 
992a4ee8f2SPeter Brune   PetscFunctionBegin;
1002a4ee8f2SPeter Brune   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
1012a4ee8f2SPeter Brune   PetscValidHeaderSpecific(X,VEC_CLASSID,2);
102534a8f05SLisandro Dalcin   PetscValidRealPointer(ob,3);
103*9566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes,&dm));
104*9566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(dm,&sdm));
10522c6f798SBarry Smith   if (sdm->ops->computeobjective) {
106*9566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(SNES_ObjectiveEval,snes,X,0,0));
107*9566063dSJacob Faibussowitsch     PetscCall((sdm->ops->computeobjective)(snes,X,ob,sdm->objectivectx));
108*9566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(SNES_ObjectiveEval,snes,X,0,0));
109ce94432eSBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "Must call SNESSetObjective() before SNESComputeObjective().");
1102a4ee8f2SPeter Brune   PetscFunctionReturn(0);
1112a4ee8f2SPeter Brune }
11297584545SPeter Brune 
1135c3e6ab7SPeter Brune /*@C
1145c3e6ab7SPeter Brune    SNESObjectiveComputeFunctionDefaultFD - Computes the gradient of a user provided objective
1155c3e6ab7SPeter Brune 
1165c3e6ab7SPeter Brune    Collective on SNES
1175c3e6ab7SPeter Brune 
118d8d19677SJose E. Roman    Input Parameters:
1195c3e6ab7SPeter Brune +  snes - the SNES context
1205c3e6ab7SPeter Brune .  X    - the state vector
1215c3e6ab7SPeter Brune -  ctx  - the (ignored) function context
1225c3e6ab7SPeter Brune 
1235c3e6ab7SPeter Brune    Output Parameter:
1245c3e6ab7SPeter Brune .  F   - the function value
1255c3e6ab7SPeter Brune 
1265c3e6ab7SPeter Brune    Options Database Key:
1275c3e6ab7SPeter Brune +  -snes_fd_function_eps - The differencing parameter
1285c3e6ab7SPeter Brune -  -snes_fd_function - Compute function from user provided objective with finite difference
1295c3e6ab7SPeter Brune 
1305c3e6ab7SPeter Brune    Notes:
1315c3e6ab7SPeter Brune    SNESObjectiveComputeFunctionDefaultFD is similar in character to SNESComputeJacobianDefault.
1325c3e6ab7SPeter Brune    Therefore, it should be used for debugging purposes only.  Using it in conjunction with
1335c3e6ab7SPeter Brune    SNESComputeJacobianDefault is excessively costly and produces a Jacobian that is quite
1345c3e6ab7SPeter Brune    noisy.  This is often necessary, but should be done with a grain of salt, even when debugging
1355c3e6ab7SPeter Brune    small problems.
1365c3e6ab7SPeter Brune 
1375c3e6ab7SPeter Brune    Note that this uses quadratic interpolation of the objective to form each value in the function.
1385c3e6ab7SPeter Brune 
1395c3e6ab7SPeter Brune    Level: advanced
1405c3e6ab7SPeter Brune 
1415c3e6ab7SPeter Brune .seealso: SNESSetFunction(), SNESComputeObjective(), SNESComputeJacobianDefault()
1425c3e6ab7SPeter Brune @*/
1438d359177SBarry Smith PetscErrorCode SNESObjectiveComputeFunctionDefaultFD(SNES snes,Vec X,Vec F,void *ctx)
1440adebc6cSBarry Smith {
14597584545SPeter Brune   Vec            Xh;
14697584545SPeter Brune   PetscErrorCode ierr;
14797584545SPeter Brune   PetscInt       i,N,start,end;
14897584545SPeter Brune   PetscReal      ob,ob1,ob2,ob3,fob,dx,eps=1e-6;
14997584545SPeter Brune   PetscScalar    fv,xv;
15097584545SPeter Brune 
15197584545SPeter Brune   PetscFunctionBegin;
152*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X,&Xh));
153*9566063dSJacob Faibussowitsch   ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)snes),((PetscObject)snes)->prefix,"Differencing parameters","SNES");PetscCall(ierr);
154*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-snes_fd_function_eps","Tolerance for nonzero entries in fd function","None",eps,&eps,NULL));
155*9566063dSJacob Faibussowitsch   ierr = PetscOptionsEnd();PetscCall(ierr);
156*9566063dSJacob Faibussowitsch   PetscCall(VecSet(F,0.));
15797584545SPeter Brune 
158*9566063dSJacob Faibussowitsch   PetscCall(VecNorm(X,NORM_2,&fob));
15997584545SPeter Brune 
160*9566063dSJacob Faibussowitsch   PetscCall(VecGetSize(X,&N));
161*9566063dSJacob Faibussowitsch   PetscCall(VecGetOwnershipRange(X,&start,&end));
162*9566063dSJacob Faibussowitsch   PetscCall(SNESComputeObjective(snes,X,&ob));
16397584545SPeter Brune 
164f5af7f23SKarl Rupp   if (fob > 0.) dx =1e-6*fob;
165f5af7f23SKarl Rupp   else dx = 1e-6;
16697584545SPeter Brune 
16797584545SPeter Brune   for (i=0; i<N; i++) {
16897584545SPeter Brune     /* compute the 1st value */
169*9566063dSJacob Faibussowitsch     PetscCall(VecCopy(X,Xh));
17097584545SPeter Brune     if (i>= start && i<end) {
17197584545SPeter Brune       xv   = dx;
172*9566063dSJacob Faibussowitsch       PetscCall(VecSetValues(Xh,1,&i,&xv,ADD_VALUES));
17397584545SPeter Brune     }
174*9566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(Xh));
175*9566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(Xh));
176*9566063dSJacob Faibussowitsch     PetscCall(SNESComputeObjective(snes,Xh,&ob1));
17797584545SPeter Brune 
17897584545SPeter Brune     /* compute the 2nd value */
179*9566063dSJacob Faibussowitsch     PetscCall(VecCopy(X,Xh));
18097584545SPeter Brune     if (i>= start && i<end) {
18197584545SPeter Brune       xv   = 2.*dx;
182*9566063dSJacob Faibussowitsch       PetscCall(VecSetValues(Xh,1,&i,&xv,ADD_VALUES));
18397584545SPeter Brune     }
184*9566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(Xh));
185*9566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(Xh));
186*9566063dSJacob Faibussowitsch     PetscCall(SNESComputeObjective(snes,Xh,&ob2));
18797584545SPeter Brune 
18897584545SPeter Brune     /* compute the 3rd value */
189*9566063dSJacob Faibussowitsch     PetscCall(VecCopy(X,Xh));
19097584545SPeter Brune     if (i>= start && i<end) {
19197584545SPeter Brune       xv   = -dx;
192*9566063dSJacob Faibussowitsch       PetscCall(VecSetValues(Xh,1,&i,&xv,ADD_VALUES));
19397584545SPeter Brune     }
194*9566063dSJacob Faibussowitsch     PetscCall(VecAssemblyBegin(Xh));
195*9566063dSJacob Faibussowitsch     PetscCall(VecAssemblyEnd(Xh));
196*9566063dSJacob Faibussowitsch     PetscCall(SNESComputeObjective(snes,Xh,&ob3));
19797584545SPeter Brune 
19897584545SPeter Brune     if (i >= start && i<end) {
19997584545SPeter Brune       /* set this entry to be the gradient of the objective */
20097584545SPeter Brune       fv = (-ob2 + 6.*ob1 - 3.*ob -2.*ob3) / (6.*dx);
20197584545SPeter Brune       if (PetscAbsScalar(fv) > eps) {
202*9566063dSJacob Faibussowitsch         PetscCall(VecSetValues(F,1,&i,&fv,INSERT_VALUES));
20397584545SPeter Brune       } else {
20497584545SPeter Brune         fv   = 0.;
205*9566063dSJacob Faibussowitsch         PetscCall(VecSetValues(F,1,&i,&fv,INSERT_VALUES));
20697584545SPeter Brune       }
20797584545SPeter Brune     }
20897584545SPeter Brune   }
20997584545SPeter Brune 
210*9566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&Xh));
21197584545SPeter Brune 
212*9566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(F));
213*9566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(F));
21497584545SPeter Brune   PetscFunctionReturn(0);
21597584545SPeter Brune }
216