xref: /petsc/src/snes/interface/noise/snesmfj2.c (revision bd55573b0bff5f8d05b86d7de029c40631c56bc2)
1d2dddef7SLois Curfman McInnes #ifndef lint
2*bd55573bSLois Curfman McInnes static char vcid[] = "$Id: snesmfj2.c,v 1.2 1997/07/04 18:57:55 curfman Exp curfman $";
3d2dddef7SLois Curfman McInnes #endif
4d2dddef7SLois Curfman McInnes 
5d2dddef7SLois Curfman McInnes #include "src/snes/snesimpl.h"   /*I  "snes.h"   I*/
6d2dddef7SLois Curfman McInnes #include "pinclude/pviewer.h"
7d2dddef7SLois Curfman McInnes #include <math.h>
8d2dddef7SLois Curfman McInnes 
9d2dddef7SLois Curfman McInnes extern int DiffParameterCreate_More(SNES,Vec,void**);
10d2dddef7SLois Curfman McInnes extern int DiffParameterCompute_More(SNES,void*,Vec,Vec,double*,double*);
11d2dddef7SLois Curfman McInnes extern int DiffParameterDestroy_More(void*);
12d2dddef7SLois Curfman McInnes 
13d2dddef7SLois Curfman McInnes typedef struct {  /* default context for matrix-free SNES */
14d2dddef7SLois Curfman McInnes   SNES        snes;      /* SNES context */
15d2dddef7SLois Curfman McInnes   Vec         w;         /* work vector */
16d2dddef7SLois Curfman McInnes   PCNullSpace sp;        /* null space context */
17d2dddef7SLois Curfman McInnes   double      error_rel; /* square root of relative error in computing function */
18d2dddef7SLois Curfman McInnes   double      umin;      /* minimum allowable u'a value relative to |u|_1 */
19d2dddef7SLois Curfman McInnes   int         jorge;     /* flag indicating use of Jorge's method for determining
20d2dddef7SLois Curfman McInnes                             the differencing parameter */
21d2dddef7SLois Curfman McInnes   Scalar      h;         /* differencing parameter */
22d2dddef7SLois Curfman McInnes   int         need_h;    /* flag indicating whether we must compute h */
23d2dddef7SLois Curfman McInnes   int         need_err;  /* flag indicating whether we must compute error_rel */
24d2dddef7SLois Curfman McInnes   void        *data;     /* implementation-specific data */
25d2dddef7SLois Curfman McInnes } MFCtx_Private;
26d2dddef7SLois Curfman McInnes 
27d2dddef7SLois Curfman McInnes #undef __FUNC__
28d2dddef7SLois Curfman McInnes #define __FUNC__ "SNESMatrixFreeDestroy2_Private" /* ADIC Ignore */
29d2dddef7SLois Curfman McInnes int SNESMatrixFreeDestroy2_Private(PetscObject obj)
30d2dddef7SLois Curfman McInnes {
31d2dddef7SLois Curfman McInnes   int           ierr;
32d2dddef7SLois Curfman McInnes   Mat           mat = (Mat) obj;
33d2dddef7SLois Curfman McInnes   MFCtx_Private *ctx;
34d2dddef7SLois Curfman McInnes 
35d2dddef7SLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx);
36d2dddef7SLois Curfman McInnes   ierr = VecDestroy(ctx->w); CHKERRQ(ierr);
37d2dddef7SLois Curfman McInnes   if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp); CHKERRQ(ierr);}
38d2dddef7SLois Curfman McInnes   if (ctx->jorge || ctx->need_err) {ierr = DiffParameterDestroy_More(ctx->data); CHKERRQ(ierr);}
39d2dddef7SLois Curfman McInnes   PetscFree(ctx);
40d2dddef7SLois Curfman McInnes   return 0;
41d2dddef7SLois Curfman McInnes }
42d2dddef7SLois Curfman McInnes 
43d2dddef7SLois Curfman McInnes #undef __FUNC__
44d2dddef7SLois Curfman McInnes #define __FUNC__ "SNESMatrixFreeView2_Private" /* ADIC Ignore */
45d2dddef7SLois Curfman McInnes /*
46d2dddef7SLois Curfman McInnes    SNESMatrixFreeView2_Private - Views matrix-free parameters.
47d2dddef7SLois Curfman McInnes  */
48d2dddef7SLois Curfman McInnes int SNESMatrixFreeView2_Private(Mat J,Viewer viewer)
49d2dddef7SLois Curfman McInnes {
50d2dddef7SLois Curfman McInnes   int           ierr;
51d2dddef7SLois Curfman McInnes   MFCtx_Private *ctx;
52d2dddef7SLois Curfman McInnes   MPI_Comm      comm;
53d2dddef7SLois Curfman McInnes   FILE          *fd;
54d2dddef7SLois Curfman McInnes   ViewerType    vtype;
55d2dddef7SLois Curfman McInnes 
56d2dddef7SLois Curfman McInnes   PetscObjectGetComm((PetscObject)J,&comm);
57d2dddef7SLois Curfman McInnes   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
58d2dddef7SLois Curfman McInnes   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
59d2dddef7SLois Curfman McInnes   ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
60d2dddef7SLois Curfman McInnes   if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
61d2dddef7SLois Curfman McInnes      PetscFPrintf(comm,fd,"  SNES matrix-free approximation:\n");
62d2dddef7SLois Curfman McInnes      if (ctx->jorge)
63d2dddef7SLois Curfman McInnes        PetscFPrintf(comm,fd,"    using Jorge's method of determining differencing parameter\n");
64d2dddef7SLois Curfman McInnes      PetscFPrintf(comm,fd,"    err=%g (relative error in function evaluation)\n",ctx->error_rel);
65d2dddef7SLois Curfman McInnes      PetscFPrintf(comm,fd,"    umin=%g (minimum iterate parameter)\n",ctx->umin);
66d2dddef7SLois Curfman McInnes   }
67d2dddef7SLois Curfman McInnes   return 0;
68d2dddef7SLois Curfman McInnes }
69d2dddef7SLois Curfman McInnes 
70e6ed2b1fSLois Curfman McInnes extern int VecDot_Seq(Vec,Vec,Scalar *);
71e6ed2b1fSLois Curfman McInnes extern int VecNorm_Seq(Vec,NormType,double *);
72e6ed2b1fSLois Curfman McInnes 
73d2dddef7SLois Curfman McInnes #undef __FUNC__
74d2dddef7SLois Curfman McInnes #define __FUNC__ "SNESMatrixFreeMult2_Private"
75d2dddef7SLois Curfman McInnes /*
76d2dddef7SLois Curfman McInnes   SNESMatrixFreeMult2_Private - Default matrix-free form for Jacobian-vector
77d2dddef7SLois Curfman McInnes   product, y = F'(u)*a:
78d2dddef7SLois Curfman McInnes         y = ( F(u + ha) - F(u) ) /h,
79d2dddef7SLois Curfman McInnes   where F = nonlinear function, as set by SNESSetFunction()
80d2dddef7SLois Curfman McInnes         u = current iterate
81d2dddef7SLois Curfman McInnes         h = difference interval
82d2dddef7SLois Curfman McInnes */
83d2dddef7SLois Curfman McInnes int SNESMatrixFreeMult2_Private(Mat mat,Vec a,Vec y)
84d2dddef7SLois Curfman McInnes {
85d2dddef7SLois Curfman McInnes   MFCtx_Private *ctx;
86d2dddef7SLois Curfman McInnes   SNES          snes;
87e6ed2b1fSLois Curfman McInnes   double        norm, sum, umin, noise, ovalues[3],values[3];
88d2dddef7SLois Curfman McInnes   Scalar        h, dot, mone = -1.0;
89d2dddef7SLois Curfman McInnes   Vec           w,U,F;
90d2dddef7SLois Curfman McInnes   int           ierr, (*eval_fct)(SNES,Vec,Vec);
91e6ed2b1fSLois Curfman McInnes   MPI_Comm      comm;
92d2dddef7SLois Curfman McInnes 
93d2dddef7SLois Curfman McInnes 
94d2dddef7SLois Curfman McInnes   /* We log matrix-free matrix-vector products separately, so that we can
95d2dddef7SLois Curfman McInnes      separate the performance monitoring from the cases that use conventional
96d2dddef7SLois Curfman McInnes      storage.  We may eventually modify event logging to associate events
97d2dddef7SLois Curfman McInnes      with particular objects, hence alleviating the more general problem. */
98d2dddef7SLois Curfman McInnes   PLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);
99d2dddef7SLois Curfman McInnes 
100e6ed2b1fSLois Curfman McInnes   PetscObjectGetComm((PetscObject)mat,&comm);
101e6ed2b1fSLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
102e6ed2b1fSLois Curfman McInnes   snes = ctx->snes;
103e6ed2b1fSLois Curfman McInnes   w    = ctx->w;
104e6ed2b1fSLois Curfman McInnes   umin = ctx->umin;
105e6ed2b1fSLois Curfman McInnes 
106d2dddef7SLois Curfman McInnes   ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr);
107d2dddef7SLois Curfman McInnes   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
108d2dddef7SLois Curfman McInnes     eval_fct = SNESComputeFunction;
109d2dddef7SLois Curfman McInnes     ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr);
110d2dddef7SLois Curfman McInnes   }
111d2dddef7SLois Curfman McInnes   else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
112d2dddef7SLois Curfman McInnes     eval_fct = SNESComputeGradient;
113d2dddef7SLois Curfman McInnes     ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr);
114d2dddef7SLois Curfman McInnes   }
115d2dddef7SLois Curfman McInnes   else SETERRQ(1,0,"Invalid method class");
116d2dddef7SLois Curfman McInnes 
117d2dddef7SLois Curfman McInnes   /* Determine a "good" step size, h */
118d2dddef7SLois Curfman McInnes   if (ctx->need_h) {
119d2dddef7SLois Curfman McInnes 
120d2dddef7SLois Curfman McInnes     /* Use Jorge's method to compute h */
121d2dddef7SLois Curfman McInnes     if (ctx->jorge) {
122d2dddef7SLois Curfman McInnes       ierr = DiffParameterCompute_More(snes,ctx->data,U,a,&noise,&h); CHKERRQ(ierr);
123d2dddef7SLois Curfman McInnes 
124d2dddef7SLois Curfman McInnes     /* Use the Brown/Saad method to compute h */
125d2dddef7SLois Curfman McInnes     } else {
126d2dddef7SLois Curfman McInnes       if (ctx->need_err) {
127d2dddef7SLois Curfman McInnes         /* Use Jorge's method to compute noise */
128d2dddef7SLois Curfman McInnes         ierr = DiffParameterCompute_More(snes,ctx->data,U,a,&noise,&h); CHKERRQ(ierr);
129d2dddef7SLois Curfman McInnes         ctx->error_rel = sqrt(noise);
130d2dddef7SLois Curfman McInnes         PLogInfo(snes,"SNESMatrixFreeMult2_Private: Using Jorge's noise: noise=%g, sqrt(noise)=%g, h_more=%g\n",
131d2dddef7SLois Curfman McInnes             noise,ctx->error_rel,h);
132d2dddef7SLois Curfman McInnes 
133d2dddef7SLois Curfman McInnes         ctx->need_err = 0;
134d2dddef7SLois Curfman McInnes       }
135e6ed2b1fSLois Curfman McInnes 
136e6ed2b1fSLois Curfman McInnes       /*
137d2dddef7SLois Curfman McInnes       ierr = VecDot(U,a,&dot); CHKERRQ(ierr);
138d2dddef7SLois Curfman McInnes       ierr = VecNorm(a,NORM_1,&sum); CHKERRQ(ierr);
139d2dddef7SLois Curfman McInnes       ierr = VecNorm(a,NORM_2,&norm); CHKERRQ(ierr);
140e6ed2b1fSLois Curfman McInnes       */
141e6ed2b1fSLois Curfman McInnes 
142e6ed2b1fSLois Curfman McInnes      /*
143e6ed2b1fSLois Curfman McInnes         Call the Seq Vector routines and then do a single reduction
144e6ed2b1fSLois Curfman McInnes         to reduce the number of communications required
145e6ed2b1fSLois Curfman McInnes      */
146e6ed2b1fSLois Curfman McInnes 
147e6ed2b1fSLois Curfman McInnes #if !defined(PETSC_COMPLEX)
148e6ed2b1fSLois Curfman McInnes      PLogEventBegin(VEC_Dot,U,a,0,0);
149e6ed2b1fSLois Curfman McInnes      ierr = VecDot_Seq(U,a,ovalues); CHKERRQ(ierr);
150e6ed2b1fSLois Curfman McInnes      PLogEventEnd(VEC_Dot,U,a,0,0);
151e6ed2b1fSLois Curfman McInnes      PLogEventBegin(VEC_Norm,a,0,0,0);
152e6ed2b1fSLois Curfman McInnes      ierr = VecNorm_Seq(a,NORM_1,ovalues+1); CHKERRQ(ierr);
153e6ed2b1fSLois Curfman McInnes      ierr = VecNorm_Seq(a,NORM_2,ovalues+2); CHKERRQ(ierr);
154e6ed2b1fSLois Curfman McInnes      ovalues[2] = ovalues[2]*ovalues[2];
155e6ed2b1fSLois Curfman McInnes      MPI_Allreduce(ovalues,values,3,MPI_DOUBLE,MPI_SUM,comm );
156e6ed2b1fSLois Curfman McInnes      dot = values[0]; sum = values[1]; norm = sqrt(values[2]);
157e6ed2b1fSLois Curfman McInnes      PLogEventEnd(VEC_Norm,a,0,0,0);
158e6ed2b1fSLois Curfman McInnes #else
159e6ed2b1fSLois Curfman McInnes      {
160e6ed2b1fSLois Curfman McInnes        Scalar cvalues[3],covalues[3];
161e6ed2b1fSLois Curfman McInnes 
162e6ed2b1fSLois Curfman McInnes        PLogEventBegin(VEC_Dot,U,a,0,0);
163e6ed2b1fSLois Curfman McInnes        ierr = VecDot_Seq(U,a,covalues); CHKERRQ(ierr);
164e6ed2b1fSLois Curfman McInnes        PLogEventEnd(VEC_Dot,U,a,0,0);
165e6ed2b1fSLois Curfman McInnes        PLogEventBegin(VEC_Norm,a,0,0,0);
166e6ed2b1fSLois Curfman McInnes        ierr = VecNorm_Seq(a,NORM_1,ovalues+1); CHKERRQ(ierr);
167e6ed2b1fSLois Curfman McInnes        ierr = VecNorm_Seq(a,NORM_2,ovalues+2); CHKERRQ(ierr);
168e6ed2b1fSLois Curfman McInnes        covalues[1] = ovalues[1];
169e6ed2b1fSLois Curfman McInnes        covalues[2] = ovalues[2]*ovalues[2];
170e6ed2b1fSLois Curfman McInnes        MPI_Allreduce(covalues,cvalues,6,MPI_DOUBLE,MPI_SUM,comm );
171e6ed2b1fSLois Curfman McInnes        dot = cvalues[0]; sum = PetscReal(cvalues[1]); norm = sqrt(PetscReal(cvalues[2]));
172e6ed2b1fSLois Curfman McInnes        PLogEventEnd(VEC_Norm,a,0,0,0);
173e6ed2b1fSLois Curfman McInnes      }
174e6ed2b1fSLois Curfman McInnes #endif
175d2dddef7SLois Curfman McInnes 
176d2dddef7SLois Curfman McInnes       /* Safeguard for step sizes too small */
177d2dddef7SLois Curfman McInnes       if (sum == 0.0) {dot = 1.0; norm = 1.0;}
178d2dddef7SLois Curfman McInnes #if defined(PETSC_COMPLEX)
179d2dddef7SLois Curfman McInnes       else if (abs(dot) < umin*sum && real(dot) >= 0.0) dot = umin*sum;
180d2dddef7SLois Curfman McInnes       else if (abs(dot) < 0.0 && real(dot) > -umin*sum) dot = -umin*sum;
181d2dddef7SLois Curfman McInnes #else
182d2dddef7SLois Curfman McInnes       else if (dot < umin*sum && dot >= 0.0) dot = umin*sum;
183d2dddef7SLois Curfman McInnes       else if (dot < 0.0 && dot > -umin*sum) dot = -umin*sum;
184d2dddef7SLois Curfman McInnes #endif
185d2dddef7SLois Curfman McInnes       h = ctx->error_rel*dot/(norm*norm);
186d2dddef7SLois Curfman McInnes     }
187d2dddef7SLois Curfman McInnes   } else {
188d2dddef7SLois Curfman McInnes     h = ctx->h;
189d2dddef7SLois Curfman McInnes   }
190d2dddef7SLois Curfman McInnes   if (!ctx->jorge || !ctx->need_h) PLogInfo(snes,"SNESMatrixFreeMult2_Private: h = %g\n",h);
191d2dddef7SLois Curfman McInnes 
192d2dddef7SLois Curfman McInnes   /* Evaluate function at F(u + ha) */
193d2dddef7SLois Curfman McInnes   ierr = VecWAXPY(&h,a,U,w); CHKERRQ(ierr);
194d2dddef7SLois Curfman McInnes   ierr = eval_fct(snes,w,y); CHKERRQ(ierr);
195d2dddef7SLois Curfman McInnes   ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr);
196d2dddef7SLois Curfman McInnes   h = 1.0/h;
197d2dddef7SLois Curfman McInnes   ierr = VecScale(&h,y); CHKERRQ(ierr);
198d2dddef7SLois Curfman McInnes   if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);}
199d2dddef7SLois Curfman McInnes 
200d2dddef7SLois Curfman McInnes   PLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);
201d2dddef7SLois Curfman McInnes   return 0;
202d2dddef7SLois Curfman McInnes }
203d2dddef7SLois Curfman McInnes 
204d2dddef7SLois Curfman McInnes #undef __FUNC__
205d2dddef7SLois Curfman McInnes #define __FUNC__ "SNESDefaultMatrixFreeMatCreate2"
206d2dddef7SLois Curfman McInnes /*@C
207d2dddef7SLois Curfman McInnes    SNESMatrixFreeMatCreate2 - Creates a matrix-free matrix
208d2dddef7SLois Curfman McInnes    context for use with a SNES solver.  This matrix can be used as
209d2dddef7SLois Curfman McInnes    the Jacobian argument for the routine SNESSetJacobian().
210d2dddef7SLois Curfman McInnes 
211d2dddef7SLois Curfman McInnes    Input Parameters:
212d2dddef7SLois Curfman McInnes .  snes - the SNES context
213d2dddef7SLois Curfman McInnes .  x - vector where SNES solution is to be stored.
214d2dddef7SLois Curfman McInnes 
215d2dddef7SLois Curfman McInnes    Output Parameter:
216d2dddef7SLois Curfman McInnes .  J - the matrix-free matrix
217d2dddef7SLois Curfman McInnes 
218d2dddef7SLois Curfman McInnes    Notes:
219d2dddef7SLois Curfman McInnes    The matrix-free matrix context merely contains the function pointers
220d2dddef7SLois Curfman McInnes    and work space for performing finite difference approximations of
221d2dddef7SLois Curfman McInnes    Jacobian-vector products, J(u)*a, via
222d2dddef7SLois Curfman McInnes 
223d2dddef7SLois Curfman McInnes $       J(u)*a = [J(u+h*a) - J(u)]/h,
224d2dddef7SLois Curfman McInnes $   where by default
225d2dddef7SLois Curfman McInnes $        h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
226d2dddef7SLois Curfman McInnes $          = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
227d2dddef7SLois Curfman McInnes $   where
228d2dddef7SLois Curfman McInnes $        error_rel = square root of relative error in
229d2dddef7SLois Curfman McInnes $                    function evaluation
230d2dddef7SLois Curfman McInnes $        umin = minimum iterate parameter
231d2dddef7SLois Curfman McInnes $   Alternatively, the differencing parameter, h, can be set using
232e6ed2b1fSLois Curfman McInnes $   Jorge's nifty new strategy if one specifies the option
233e6ed2b1fSLois Curfman McInnes $          -snes_mf_jorge
234d2dddef7SLois Curfman McInnes 
235d2dddef7SLois Curfman McInnes    The user can set these parameters via SNESSetMatrixFreeParameters().
236d2dddef7SLois Curfman McInnes    See the nonlinear solvers chapter of the users manual for details.
237d2dddef7SLois Curfman McInnes 
238d2dddef7SLois Curfman McInnes    The user should call MatDestroy() when finished with the matrix-free
239d2dddef7SLois Curfman McInnes    matrix context.
240d2dddef7SLois Curfman McInnes 
241d2dddef7SLois Curfman McInnes    Options Database Keys:
242e6ed2b1fSLois Curfman McInnes $  -snes_mf_compute_err
243d2dddef7SLois Curfman McInnes $  -snes_mf_err <error_rel>
244d2dddef7SLois Curfman McInnes $  -snes_mf_unim <umin>
245e6ed2b1fSLois Curfman McInnes $  -snes_mf_jorge
246d2dddef7SLois Curfman McInnes 
247d2dddef7SLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix
248d2dddef7SLois Curfman McInnes 
249d2dddef7SLois Curfman McInnes .seealso: MatDestroy(), SNESSetMatrixFreeParameters()
250d2dddef7SLois Curfman McInnes @*/
251d2dddef7SLois Curfman McInnes int SNESMatrixFreeMatCreate2(SNES snes,Vec x, Mat *J)
252d2dddef7SLois Curfman McInnes {
253d2dddef7SLois Curfman McInnes   MPI_Comm      comm;
254d2dddef7SLois Curfman McInnes   MFCtx_Private *mfctx;
255d2dddef7SLois Curfman McInnes   int           n, nloc, ierr, flg;
256d2dddef7SLois Curfman McInnes   char          p[64];
257d2dddef7SLois Curfman McInnes 
258d2dddef7SLois Curfman McInnes   mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx);
259d2dddef7SLois Curfman McInnes   PLogObjectMemory(snes,sizeof(MFCtx_Private));
260d2dddef7SLois Curfman McInnes   mfctx->sp   = 0;
261d2dddef7SLois Curfman McInnes   mfctx->snes = snes;
262d2dddef7SLois Curfman McInnes   mfctx->error_rel = 1.e-8; /* assumes double precision */
263d2dddef7SLois Curfman McInnes   mfctx->umin      = 1.e-6;
264d2dddef7SLois Curfman McInnes   mfctx->h         = 0.0;
265d2dddef7SLois Curfman McInnes   mfctx->need_h    = 1;
266d2dddef7SLois Curfman McInnes   mfctx->need_err  = 0;
267d2dddef7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg); CHKERRQ(ierr);
268d2dddef7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_umin",&mfctx->umin,&flg); CHKERRQ(ierr);
269e6ed2b1fSLois Curfman McInnes   ierr = OptionsHasName(snes->prefix,"-snes_mf_jorge",&mfctx->jorge); CHKERRQ(ierr);
270e6ed2b1fSLois Curfman McInnes   ierr = OptionsHasName(snes->prefix,"-snes_mf_compute_err",&mfctx->need_err); CHKERRQ(ierr);
271d2dddef7SLois Curfman McInnes   if (mfctx->jorge || mfctx->need_err) {
272d2dddef7SLois Curfman McInnes     ierr = DiffParameterCreate_More(snes,x,&mfctx->data); CHKERRQ(ierr);
273d2dddef7SLois Curfman McInnes   } else mfctx->data = 0;
274d2dddef7SLois Curfman McInnes 
275d2dddef7SLois Curfman McInnes   ierr = OptionsHasName(PETSC_NULL,"-help",&flg); CHKERRQ(ierr);
276d2dddef7SLois Curfman McInnes   PetscStrcpy(p,"-");
277d2dddef7SLois Curfman McInnes   if (snes->prefix) PetscStrcat(p,snes->prefix);
278d2dddef7SLois Curfman McInnes   if (flg) {
279*bd55573bSLois Curfman McInnes     PetscPrintf(snes->comm," Matrix-free Options (via SNES)\n");
280e6ed2b1fSLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_jorge: use Jorge More's method\n",p);
281*bd55573bSLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_compute_err: compute sqrt or relative error in function\n",p);
282*bd55573bSLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_err <err>: set sqrt of relative error in function (default %g)\n",p,mfctx->error_rel);
283d2dddef7SLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_umin <umin>: see users manual (default %g)\n",p,mfctx->umin);
284d2dddef7SLois Curfman McInnes   }
285d2dddef7SLois Curfman McInnes   ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr);
286d2dddef7SLois Curfman McInnes   ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr);
287d2dddef7SLois Curfman McInnes   ierr = VecGetSize(x,&n); CHKERRQ(ierr);
288d2dddef7SLois Curfman McInnes   ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr);
289d2dddef7SLois Curfman McInnes   ierr = MatCreateShell(comm,nloc,n,n,n,mfctx,J); CHKERRQ(ierr);
290d2dddef7SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)SNESMatrixFreeMult2_Private);CHKERRQ(ierr);
291d2dddef7SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)SNESMatrixFreeDestroy2_Private);CHKERRQ(ierr);
292d2dddef7SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)SNESMatrixFreeView2_Private); CHKERRQ(ierr);
293d2dddef7SLois Curfman McInnes 
294d2dddef7SLois Curfman McInnes   PLogObjectParent(*J,mfctx->w);
295d2dddef7SLois Curfman McInnes   PLogObjectParent(snes,*J);
296d2dddef7SLois Curfman McInnes   return 0;
297d2dddef7SLois Curfman McInnes }
298d2dddef7SLois Curfman McInnes 
299d2dddef7SLois Curfman McInnes #undef __FUNC__
300d2dddef7SLois Curfman McInnes #define __FUNC__ "SNESSetMatrixFreeParameters2"
301d2dddef7SLois Curfman McInnes /*@
302d2dddef7SLois Curfman McInnes    SNESSetMatrixFreeParameters2 - Sets the parameters for the approximation of
303d2dddef7SLois Curfman McInnes    matrix-vector products using finite differences.
304d2dddef7SLois Curfman McInnes 
305d2dddef7SLois Curfman McInnes $       J(u)*a = [J(u+h*a) - J(u)]/h where
306d2dddef7SLois Curfman McInnes 
307d2dddef7SLois Curfman McInnes    either the user sets h directly here, or this parameter is computed via
308d2dddef7SLois Curfman McInnes 
309d2dddef7SLois Curfman McInnes $        h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
310d2dddef7SLois Curfman McInnes $          = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
311d2dddef7SLois Curfman McInnes $
312d2dddef7SLois Curfman McInnes 
313d2dddef7SLois Curfman McInnes    Input Parameters:
314d2dddef7SLois Curfman McInnes .  snes - the SNES context
315d2dddef7SLois Curfman McInnes .  error_rel - relative error (should be set to the square root of
316d2dddef7SLois Curfman McInnes      the relative error in the function evaluations)
317d2dddef7SLois Curfman McInnes .  umin - minimum allowable u-value
318d2dddef7SLois Curfman McInnes .  h - differencing parameter
319d2dddef7SLois Curfman McInnes 
320d2dddef7SLois Curfman McInnes    Notes:
321d2dddef7SLois Curfman McInnes    If the user sets the parameter h directly, then this value will be used
322d2dddef7SLois Curfman McInnes    instead of the default computation indicated above.
323d2dddef7SLois Curfman McInnes 
324d2dddef7SLois Curfman McInnes .keywords: SNES, matrix-free, parameters
325d2dddef7SLois Curfman McInnes 
326d2dddef7SLois Curfman McInnes .seealso: SNESDefaultMatrixFreeMatCreate()
327d2dddef7SLois Curfman McInnes @*/
328d2dddef7SLois Curfman McInnes int SNESSetMatrixFreeParameters2(SNES snes,double error,double umin,double h)
329d2dddef7SLois Curfman McInnes {
330d2dddef7SLois Curfman McInnes   MFCtx_Private *ctx;
331d2dddef7SLois Curfman McInnes   int           ierr;
332d2dddef7SLois Curfman McInnes   Mat           mat;
333d2dddef7SLois Curfman McInnes 
334d2dddef7SLois Curfman McInnes   ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
335d2dddef7SLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
336d2dddef7SLois Curfman McInnes   if (ctx) {
337d2dddef7SLois Curfman McInnes     if (error != PETSC_DEFAULT) ctx->error_rel = error;
338d2dddef7SLois Curfman McInnes     if (umin  != PETSC_DEFAULT) ctx->umin = umin;
339d2dddef7SLois Curfman McInnes     if (h     != PETSC_DEFAULT) {
340d2dddef7SLois Curfman McInnes       ctx->h = h;
341d2dddef7SLois Curfman McInnes       ctx->need_h = 0;
342d2dddef7SLois Curfman McInnes     }
343d2dddef7SLois Curfman McInnes   }
344d2dddef7SLois Curfman McInnes   return 0;
345d2dddef7SLois Curfman McInnes }
346d2dddef7SLois Curfman McInnes 
347d2dddef7SLois Curfman McInnes int SNESUnSetMatrixFreeParameter(SNES snes)
348d2dddef7SLois Curfman McInnes {
349d2dddef7SLois Curfman McInnes   MFCtx_Private *ctx;
350d2dddef7SLois Curfman McInnes   int           ierr;
351d2dddef7SLois Curfman McInnes   Mat           mat;
352d2dddef7SLois Curfman McInnes 
353d2dddef7SLois Curfman McInnes   ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
354d2dddef7SLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
355d2dddef7SLois Curfman McInnes   if (ctx) ctx->need_h = 1;
356d2dddef7SLois Curfman McInnes   return 0;
357d2dddef7SLois Curfman McInnes }
358d2dddef7SLois Curfman McInnes 
359