xref: /petsc/src/snes/interface/noise/snesmfj2.c (revision 1a7c28d59d4bc937eda0c8e7b268b82df2814007)
1d834d2e4SLois Curfman McInnes #ifdef PETSC_RCS_HEADER
2*1a7c28d5SLois Curfman McInnes static char vcid[] = "$Id: snesmfj2.c,v 1.9 1998/05/29 22:51:12 balay 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 */
21db0b4b35SLois Curfman McInnes   double      h;                /* differencing parameter */
22d2dddef7SLois Curfman McInnes   int         need_h;           /* flag indicating whether we must compute h */
23295f7fbbSLois Curfman McInnes   int         need_err;         /* flag indicating whether we must currently compute error_rel */
24295f7fbbSLois Curfman McInnes   int         compute_err;      /* flag indicating whether we must ever compute error_rel */
25295f7fbbSLois Curfman McInnes   int         compute_err_iter; /* last iter where we've computer error_rel */
26295f7fbbSLois Curfman McInnes   int         compute_err_freq; /* frequency of computing error_rel */
27d2dddef7SLois Curfman McInnes   void        *data;            /* implementation-specific data */
28d2dddef7SLois Curfman McInnes } MFCtx_Private;
29d2dddef7SLois Curfman McInnes 
30d2dddef7SLois Curfman McInnes #undef __FUNC__
31d2dddef7SLois Curfman McInnes #define __FUNC__ "SNESMatrixFreeDestroy2_Private" /* ADIC Ignore */
32f1d4f8a3SBarry Smith int SNESMatrixFreeDestroy2_Private(Mat mat)
33d2dddef7SLois Curfman McInnes {
34d2dddef7SLois Curfman McInnes   int           ierr;
35d2dddef7SLois Curfman McInnes   MFCtx_Private *ctx;
36d2dddef7SLois Curfman McInnes 
3707a3eed9SLois Curfman McInnes   PetscFunctionBegin;
38d2dddef7SLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx);
39d2dddef7SLois Curfman McInnes   ierr = VecDestroy(ctx->w); CHKERRQ(ierr);
40d2dddef7SLois Curfman McInnes   if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp); CHKERRQ(ierr);}
41295f7fbbSLois Curfman McInnes   if (ctx->jorge || ctx->compute_err) {ierr = DiffParameterDestroy_More(ctx->data); CHKERRQ(ierr);}
42d2dddef7SLois Curfman McInnes   PetscFree(ctx);
4307a3eed9SLois Curfman McInnes   PetscFunctionReturn(0);
44d2dddef7SLois Curfman McInnes }
45d2dddef7SLois Curfman McInnes 
46d2dddef7SLois Curfman McInnes #undef __FUNC__
47d2dddef7SLois Curfman McInnes #define __FUNC__ "SNESMatrixFreeView2_Private" /* ADIC Ignore */
48d2dddef7SLois Curfman McInnes /*
49d2dddef7SLois Curfman McInnes    SNESMatrixFreeView2_Private - Views matrix-free parameters.
50d2dddef7SLois Curfman McInnes  */
51d2dddef7SLois Curfman McInnes int SNESMatrixFreeView2_Private(Mat J,Viewer viewer)
52d2dddef7SLois Curfman McInnes {
53d2dddef7SLois Curfman McInnes   int           ierr;
54d2dddef7SLois Curfman McInnes   MFCtx_Private *ctx;
55d2dddef7SLois Curfman McInnes   MPI_Comm      comm;
56d2dddef7SLois Curfman McInnes   FILE          *fd;
57d2dddef7SLois Curfman McInnes   ViewerType    vtype;
58d2dddef7SLois Curfman McInnes 
5907a3eed9SLois Curfman McInnes   PetscFunctionBegin;
60d2dddef7SLois Curfman McInnes   PetscObjectGetComm((PetscObject)J,&comm);
61d2dddef7SLois Curfman McInnes   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
62d2dddef7SLois Curfman McInnes   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
63d2dddef7SLois Curfman McInnes   ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
64d2dddef7SLois Curfman McInnes   if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
65d2dddef7SLois Curfman McInnes      PetscFPrintf(comm,fd,"  SNES matrix-free approximation:\n");
66d2dddef7SLois Curfman McInnes      if (ctx->jorge)
67d2dddef7SLois Curfman McInnes        PetscFPrintf(comm,fd,"    using Jorge's method of determining differencing parameter\n");
68d2dddef7SLois Curfman McInnes      PetscFPrintf(comm,fd,"    err=%g (relative error in function evaluation)\n",ctx->error_rel);
69d2dddef7SLois Curfman McInnes      PetscFPrintf(comm,fd,"    umin=%g (minimum iterate parameter)\n",ctx->umin);
70295f7fbbSLois Curfman McInnes      if (ctx->compute_err)
71295f7fbbSLois Curfman McInnes        PetscFPrintf(comm,fd,"    freq_err=%d (frequency for computing err)\n",ctx->compute_err_freq);
72d2dddef7SLois Curfman McInnes   }
7307a3eed9SLois Curfman McInnes   PetscFunctionReturn(0);
74d2dddef7SLois Curfman McInnes }
75d2dddef7SLois Curfman McInnes 
76e6ed2b1fSLois Curfman McInnes extern int VecDot_Seq(Vec,Vec,Scalar *);
77e6ed2b1fSLois Curfman McInnes extern int VecNorm_Seq(Vec,NormType,double *);
78e6ed2b1fSLois Curfman McInnes 
79d2dddef7SLois Curfman McInnes #undef __FUNC__
80d2dddef7SLois Curfman McInnes #define __FUNC__ "SNESMatrixFreeMult2_Private"
81d2dddef7SLois Curfman McInnes /*
82d2dddef7SLois Curfman McInnes   SNESMatrixFreeMult2_Private - Default matrix-free form for Jacobian-vector
83d2dddef7SLois Curfman McInnes   product, y = F'(u)*a:
84d2dddef7SLois Curfman McInnes         y = ( F(u + ha) - F(u) ) /h,
85d2dddef7SLois Curfman McInnes   where F = nonlinear function, as set by SNESSetFunction()
86d2dddef7SLois Curfman McInnes         u = current iterate
87d2dddef7SLois Curfman McInnes         h = difference interval
88d2dddef7SLois Curfman McInnes */
89d2dddef7SLois Curfman McInnes int SNESMatrixFreeMult2_Private(Mat mat,Vec a,Vec y)
90d2dddef7SLois Curfman McInnes {
91d2dddef7SLois Curfman McInnes   MFCtx_Private *ctx;
92d2dddef7SLois Curfman McInnes   SNES          snes;
93db0b4b35SLois Curfman McInnes   double        h, norm, sum, umin, noise, ovalues[3],values[3];
94db0b4b35SLois Curfman McInnes   Scalar        hs, dot, mone = -1.0;
95d2dddef7SLois Curfman McInnes   Vec           w,U,F;
96295f7fbbSLois Curfman McInnes   int           ierr, iter, (*eval_fct)(SNES,Vec,Vec);
97e6ed2b1fSLois Curfman McInnes   MPI_Comm      comm;
98d2dddef7SLois Curfman McInnes 
9907a3eed9SLois Curfman McInnes   PetscFunctionBegin;
10007a3eed9SLois Curfman McInnes 
101d2dddef7SLois Curfman McInnes   /* We log matrix-free matrix-vector products separately, so that we can
102d2dddef7SLois Curfman McInnes      separate the performance monitoring from the cases that use conventional
103d2dddef7SLois Curfman McInnes      storage.  We may eventually modify event logging to associate events
104d2dddef7SLois Curfman McInnes      with particular objects, hence alleviating the more general problem. */
105d2dddef7SLois Curfman McInnes   PLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);
106d2dddef7SLois Curfman McInnes 
107e6ed2b1fSLois Curfman McInnes   PetscObjectGetComm((PetscObject)mat,&comm);
108e6ed2b1fSLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
109e6ed2b1fSLois Curfman McInnes   snes = ctx->snes;
110e6ed2b1fSLois Curfman McInnes   w    = ctx->w;
111e6ed2b1fSLois Curfman McInnes   umin = ctx->umin;
112e6ed2b1fSLois Curfman McInnes 
113d2dddef7SLois Curfman McInnes   ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr);
114d2dddef7SLois Curfman McInnes   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
115d2dddef7SLois Curfman McInnes     eval_fct = SNESComputeFunction;
116d2dddef7SLois Curfman McInnes     ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr);
117d2dddef7SLois Curfman McInnes   }
118d2dddef7SLois Curfman McInnes   else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
119d2dddef7SLois Curfman McInnes     eval_fct = SNESComputeGradient;
120d2dddef7SLois Curfman McInnes     ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr);
121d2dddef7SLois Curfman McInnes   }
122d2dddef7SLois Curfman McInnes   else SETERRQ(1,0,"Invalid method class");
123d2dddef7SLois Curfman McInnes 
124295f7fbbSLois Curfman McInnes 
125d2dddef7SLois Curfman McInnes   /* Determine a "good" step size, h */
126d2dddef7SLois Curfman McInnes   if (ctx->need_h) {
127d2dddef7SLois Curfman McInnes 
128d2dddef7SLois Curfman McInnes     /* Use Jorge's method to compute h */
129d2dddef7SLois Curfman McInnes     if (ctx->jorge) {
130d2dddef7SLois Curfman McInnes       ierr = DiffParameterCompute_More(snes,ctx->data,U,a,&noise,&h); CHKERRQ(ierr);
131d2dddef7SLois Curfman McInnes 
132d2dddef7SLois Curfman McInnes     /* Use the Brown/Saad method to compute h */
133d2dddef7SLois Curfman McInnes     } else {
134295f7fbbSLois Curfman McInnes       /* Compute error if desired */
135295f7fbbSLois Curfman McInnes       ierr = SNESGetIterationNumber(snes,&iter); CHKERRQ(ierr);
136295f7fbbSLois Curfman McInnes       if ((ctx->need_err) ||
137295f7fbbSLois Curfman McInnes           ((ctx->compute_err_freq) && (ctx->compute_err_iter != iter) && (!((iter-1)%ctx->compute_err_freq)))) {
138d2dddef7SLois Curfman McInnes         /* Use Jorge's method to compute noise */
139d2dddef7SLois Curfman McInnes         ierr = DiffParameterCompute_More(snes,ctx->data,U,a,&noise,&h); CHKERRQ(ierr);
140d2dddef7SLois Curfman McInnes         ctx->error_rel = sqrt(noise);
141d2dddef7SLois Curfman McInnes         PLogInfo(snes,"SNESMatrixFreeMult2_Private: Using Jorge's noise: noise=%g, sqrt(noise)=%g, h_more=%g\n",
142d2dddef7SLois Curfman McInnes             noise,ctx->error_rel,h);
143295f7fbbSLois Curfman McInnes         ctx->compute_err_iter = iter;
144d2dddef7SLois Curfman McInnes         ctx->need_err = 0;
145d2dddef7SLois Curfman McInnes       }
146e6ed2b1fSLois Curfman McInnes 
147e6ed2b1fSLois Curfman McInnes       /*
148d2dddef7SLois Curfman McInnes       ierr = VecDot(U,a,&dot); CHKERRQ(ierr);
149d2dddef7SLois Curfman McInnes       ierr = VecNorm(a,NORM_1,&sum); CHKERRQ(ierr);
150d2dddef7SLois Curfman McInnes       ierr = VecNorm(a,NORM_2,&norm); CHKERRQ(ierr);
151e6ed2b1fSLois Curfman McInnes       */
152e6ed2b1fSLois Curfman McInnes 
153e6ed2b1fSLois Curfman McInnes      /*
154e6ed2b1fSLois Curfman McInnes         Call the Seq Vector routines and then do a single reduction
155e6ed2b1fSLois Curfman McInnes         to reduce the number of communications required
156e6ed2b1fSLois Curfman McInnes      */
157e6ed2b1fSLois Curfman McInnes 
158db0b4b35SLois Curfman McInnes #if !defined(USE_PETSC_COMPLEX)
159e6ed2b1fSLois Curfman McInnes      PLogEventBegin(VEC_Dot,U,a,0,0);
160e6ed2b1fSLois Curfman McInnes      ierr = VecDot_Seq(U,a,ovalues); CHKERRQ(ierr);
161e6ed2b1fSLois Curfman McInnes      PLogEventEnd(VEC_Dot,U,a,0,0);
162e6ed2b1fSLois Curfman McInnes      PLogEventBegin(VEC_Norm,a,0,0,0);
163e6ed2b1fSLois Curfman McInnes      ierr = VecNorm_Seq(a,NORM_1,ovalues+1); CHKERRQ(ierr);
164e6ed2b1fSLois Curfman McInnes      ierr = VecNorm_Seq(a,NORM_2,ovalues+2); CHKERRQ(ierr);
165e6ed2b1fSLois Curfman McInnes      ovalues[2] = ovalues[2]*ovalues[2];
166e6ed2b1fSLois Curfman McInnes      MPI_Allreduce(ovalues,values,3,MPI_DOUBLE,MPI_SUM,comm );
167e6ed2b1fSLois Curfman McInnes      dot = values[0]; sum = values[1]; norm = sqrt(values[2]);
168e6ed2b1fSLois Curfman McInnes      PLogEventEnd(VEC_Norm,a,0,0,0);
169e6ed2b1fSLois Curfman McInnes #else
170e6ed2b1fSLois Curfman McInnes      {
171e6ed2b1fSLois Curfman McInnes        Scalar cvalues[3],covalues[3];
172e6ed2b1fSLois Curfman McInnes 
173e6ed2b1fSLois Curfman McInnes        PLogEventBegin(VEC_Dot,U,a,0,0);
174e6ed2b1fSLois Curfman McInnes        ierr = VecDot_Seq(U,a,covalues); CHKERRQ(ierr);
175e6ed2b1fSLois Curfman McInnes        PLogEventEnd(VEC_Dot,U,a,0,0);
176e6ed2b1fSLois Curfman McInnes        PLogEventBegin(VEC_Norm,a,0,0,0);
177e6ed2b1fSLois Curfman McInnes        ierr = VecNorm_Seq(a,NORM_1,ovalues+1); CHKERRQ(ierr);
178e6ed2b1fSLois Curfman McInnes        ierr = VecNorm_Seq(a,NORM_2,ovalues+2); CHKERRQ(ierr);
179e6ed2b1fSLois Curfman McInnes        covalues[1] = ovalues[1];
180e6ed2b1fSLois Curfman McInnes        covalues[2] = ovalues[2]*ovalues[2];
181e6ed2b1fSLois Curfman McInnes        MPI_Allreduce(covalues,cvalues,6,MPI_DOUBLE,MPI_SUM,comm );
182e6ed2b1fSLois Curfman McInnes        dot = cvalues[0]; sum = PetscReal(cvalues[1]); norm = sqrt(PetscReal(cvalues[2]));
183e6ed2b1fSLois Curfman McInnes        PLogEventEnd(VEC_Norm,a,0,0,0);
184e6ed2b1fSLois Curfman McInnes      }
185e6ed2b1fSLois Curfman McInnes #endif
186d2dddef7SLois Curfman McInnes 
187d2dddef7SLois Curfman McInnes       /* Safeguard for step sizes too small */
188d2dddef7SLois Curfman McInnes       if (sum == 0.0) {dot = 1.0; norm = 1.0;}
189db0b4b35SLois Curfman McInnes #if defined(USE_PETSC_COMPLEX)
190e20fef11SSatish Balay       else if (PetscAbsScalar(dot) < umin*sum && PetscReal(dot) >= 0.0) dot = umin*sum;
191e20fef11SSatish Balay       else if (PetscAbsScalar(dot) < 0.0 && PetscReal(dot) > -umin*sum) dot = -umin*sum;
192d2dddef7SLois Curfman McInnes #else
193d2dddef7SLois Curfman McInnes       else if (dot < umin*sum && dot >= 0.0) dot = umin*sum;
194d2dddef7SLois Curfman McInnes       else if (dot < 0.0 && dot > -umin*sum) dot = -umin*sum;
195d2dddef7SLois Curfman McInnes #endif
196db0b4b35SLois Curfman McInnes       h = PetscReal(ctx->error_rel*dot/(norm*norm));
197d2dddef7SLois Curfman McInnes     }
198d2dddef7SLois Curfman McInnes   } else {
199d2dddef7SLois Curfman McInnes     h = ctx->h;
200d2dddef7SLois Curfman McInnes   }
201d2dddef7SLois Curfman McInnes   if (!ctx->jorge || !ctx->need_h) PLogInfo(snes,"SNESMatrixFreeMult2_Private: h = %g\n",h);
202d2dddef7SLois Curfman McInnes 
203d2dddef7SLois Curfman McInnes   /* Evaluate function at F(u + ha) */
204db0b4b35SLois Curfman McInnes   hs = h;
205db0b4b35SLois Curfman McInnes   ierr = VecWAXPY(&hs,a,U,w); CHKERRQ(ierr);
206d2dddef7SLois Curfman McInnes   ierr = eval_fct(snes,w,y); CHKERRQ(ierr);
207d2dddef7SLois Curfman McInnes   ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr);
208db0b4b35SLois Curfman McInnes   hs = 1.0/hs;
209db0b4b35SLois Curfman McInnes   ierr = VecScale(&hs,y); CHKERRQ(ierr);
210d2dddef7SLois Curfman McInnes   if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);}
211d2dddef7SLois Curfman McInnes 
212d2dddef7SLois Curfman McInnes   PLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);
21307a3eed9SLois Curfman McInnes   PetscFunctionReturn(0);
214d2dddef7SLois Curfman McInnes }
215d2dddef7SLois Curfman McInnes 
216d2dddef7SLois Curfman McInnes #undef __FUNC__
217*1a7c28d5SLois Curfman McInnes #define __FUNC__ "SNESMatrixFreeMatCreate2"
218d2dddef7SLois Curfman McInnes /*@C
219d2dddef7SLois Curfman McInnes    SNESMatrixFreeMatCreate2 - Creates a matrix-free matrix
220d2dddef7SLois Curfman McInnes    context for use with a SNES solver.  This matrix can be used as
221d2dddef7SLois Curfman McInnes    the Jacobian argument for the routine SNESSetJacobian().
222d2dddef7SLois Curfman McInnes 
223d2dddef7SLois Curfman McInnes    Input Parameters:
224d2dddef7SLois Curfman McInnes .  snes - the SNES context
225d2dddef7SLois Curfman McInnes .  x - vector where SNES solution is to be stored.
226d2dddef7SLois Curfman McInnes 
227d2dddef7SLois Curfman McInnes    Output Parameter:
228d2dddef7SLois Curfman McInnes .  J - the matrix-free matrix
229d2dddef7SLois Curfman McInnes 
230d2dddef7SLois Curfman McInnes    Notes:
231d2dddef7SLois Curfman McInnes    The matrix-free matrix context merely contains the function pointers
232d2dddef7SLois Curfman McInnes    and work space for performing finite difference approximations of
233d2dddef7SLois Curfman McInnes    Jacobian-vector products, J(u)*a, via
234d2dddef7SLois Curfman McInnes 
235d2dddef7SLois Curfman McInnes $       J(u)*a = [J(u+h*a) - J(u)]/h,
236d2dddef7SLois Curfman McInnes $   where by default
237d2dddef7SLois Curfman McInnes $        h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
238d2dddef7SLois Curfman McInnes $          = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
239d2dddef7SLois Curfman McInnes $   where
240d2dddef7SLois Curfman McInnes $        error_rel = square root of relative error in
241d2dddef7SLois Curfman McInnes $                    function evaluation
242d2dddef7SLois Curfman McInnes $        umin = minimum iterate parameter
243d2dddef7SLois Curfman McInnes $   Alternatively, the differencing parameter, h, can be set using
244e6ed2b1fSLois Curfman McInnes $   Jorge's nifty new strategy if one specifies the option
245e6ed2b1fSLois Curfman McInnes $          -snes_mf_jorge
246d2dddef7SLois Curfman McInnes 
247d2dddef7SLois Curfman McInnes    The user can set these parameters via SNESSetMatrixFreeParameters().
248d2dddef7SLois Curfman McInnes    See the nonlinear solvers chapter of the users manual for details.
249d2dddef7SLois Curfman McInnes 
250d2dddef7SLois Curfman McInnes    The user should call MatDestroy() when finished with the matrix-free
251d2dddef7SLois Curfman McInnes    matrix context.
252d2dddef7SLois Curfman McInnes 
253d2dddef7SLois Curfman McInnes    Options Database Keys:
254d2dddef7SLois Curfman McInnes $  -snes_mf_err <error_rel>
255d2dddef7SLois Curfman McInnes $  -snes_mf_unim <umin>
256295f7fbbSLois Curfman McInnes $  -snes_mf_compute_err
257295f7fbbSLois Curfman McInnes $  -snes_mf_freq_err <freq>
258e6ed2b1fSLois Curfman McInnes $  -snes_mf_jorge
259d2dddef7SLois Curfman McInnes 
260d2dddef7SLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix
261d2dddef7SLois Curfman McInnes 
262d2dddef7SLois Curfman McInnes .seealso: MatDestroy(), SNESSetMatrixFreeParameters()
263d2dddef7SLois Curfman McInnes @*/
264d2dddef7SLois Curfman McInnes int SNESMatrixFreeMatCreate2(SNES snes,Vec x, Mat *J)
265d2dddef7SLois Curfman McInnes {
266d2dddef7SLois Curfman McInnes   MPI_Comm      comm;
267d2dddef7SLois Curfman McInnes   MFCtx_Private *mfctx;
268d2dddef7SLois Curfman McInnes   int           n, nloc, ierr, flg;
269d2dddef7SLois Curfman McInnes   char          p[64];
270d2dddef7SLois Curfman McInnes 
27107a3eed9SLois Curfman McInnes   PetscFunctionBegin;
272d2dddef7SLois Curfman McInnes   mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx);
27307a3eed9SLois Curfman McInnes   PetscMemzero(mfctx,sizeof(MFCtx_Private));
274d2dddef7SLois Curfman McInnes   PLogObjectMemory(snes,sizeof(MFCtx_Private));
275d2dddef7SLois Curfman McInnes   mfctx->sp   = 0;
276d2dddef7SLois Curfman McInnes   mfctx->snes = snes;
277d2dddef7SLois Curfman McInnes   mfctx->error_rel        = 1.e-8; /* assumes double precision */
278d2dddef7SLois Curfman McInnes   mfctx->umin             = 1.e-6;
279d2dddef7SLois Curfman McInnes   mfctx->h                = 0.0;
280d2dddef7SLois Curfman McInnes   mfctx->need_h           = 1;
281d2dddef7SLois Curfman McInnes   mfctx->need_err         = 0;
282295f7fbbSLois Curfman McInnes   mfctx->compute_err      = 0;
283295f7fbbSLois Curfman McInnes   mfctx->compute_err_freq = 0;
284295f7fbbSLois Curfman McInnes   mfctx->compute_err_iter = -1;
285d2dddef7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg); CHKERRQ(ierr);
286d2dddef7SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_umin",&mfctx->umin,&flg); CHKERRQ(ierr);
287e6ed2b1fSLois Curfman McInnes   ierr = OptionsHasName(snes->prefix,"-snes_mf_jorge",&mfctx->jorge); CHKERRQ(ierr);
288295f7fbbSLois Curfman McInnes   ierr = OptionsHasName(snes->prefix,"-snes_mf_compute_err",&mfctx->compute_err); CHKERRQ(ierr);
289295f7fbbSLois Curfman McInnes   ierr = OptionsGetInt(snes->prefix,"-snes_mf_freq_err",&mfctx->compute_err_freq,&flg); CHKERRQ(ierr);
290295f7fbbSLois Curfman McInnes   if (flg) {
291295f7fbbSLois Curfman McInnes     if (mfctx->compute_err_freq < 0) mfctx->compute_err_freq = 0;
292295f7fbbSLois Curfman McInnes     mfctx->compute_err = 1;
293295f7fbbSLois Curfman McInnes   }
294295f7fbbSLois Curfman McInnes   if (mfctx->compute_err == 1) mfctx->need_err = 1;
295295f7fbbSLois Curfman McInnes   if (mfctx->jorge || mfctx->compute_err) {
296d2dddef7SLois Curfman McInnes     ierr = DiffParameterCreate_More(snes,x,&mfctx->data); CHKERRQ(ierr);
297d2dddef7SLois Curfman McInnes   } else mfctx->data = 0;
298d2dddef7SLois Curfman McInnes 
299d2dddef7SLois Curfman McInnes   ierr = OptionsHasName(PETSC_NULL,"-help",&flg); CHKERRQ(ierr);
300d2dddef7SLois Curfman McInnes   PetscStrcpy(p,"-");
301d2dddef7SLois Curfman McInnes   if (snes->prefix) PetscStrcat(p,snes->prefix);
302d2dddef7SLois Curfman McInnes   if (flg) {
303295f7fbbSLois Curfman McInnes     PetscPrintf(snes->comm," Matrix-free Options (via SNES):\n");
304bd55573bSLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_err <err>: set sqrt of relative error in function (default %g)\n",p,mfctx->error_rel);
305d2dddef7SLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_umin <umin>: see users manual (default %g)\n",p,mfctx->umin);
306295f7fbbSLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_jorge: use Jorge More's method\n",p);
307295f7fbbSLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_compute_err: compute sqrt or relative error in function\n",p);
308295f7fbbSLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_freq_err <freq>: frequency to recompute this (default only once)\n",p);
309295f7fbbSLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_noise_file <file>: set file for printing noise info\n",p);
310d2dddef7SLois Curfman McInnes   }
311d2dddef7SLois Curfman McInnes   ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr);
312d2dddef7SLois Curfman McInnes   ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr);
313d2dddef7SLois Curfman McInnes   ierr = VecGetSize(x,&n); CHKERRQ(ierr);
314d2dddef7SLois Curfman McInnes   ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr);
315d2dddef7SLois Curfman McInnes   ierr = MatCreateShell(comm,nloc,n,n,n,mfctx,J); CHKERRQ(ierr);
316d2dddef7SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)SNESMatrixFreeMult2_Private);CHKERRQ(ierr);
317d2dddef7SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)SNESMatrixFreeDestroy2_Private);CHKERRQ(ierr);
318d2dddef7SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)SNESMatrixFreeView2_Private); CHKERRQ(ierr);
319d2dddef7SLois Curfman McInnes 
320d2dddef7SLois Curfman McInnes   PLogObjectParent(*J,mfctx->w);
321d2dddef7SLois Curfman McInnes   PLogObjectParent(snes,*J);
32207a3eed9SLois Curfman McInnes   PetscFunctionReturn(0);
323d2dddef7SLois Curfman McInnes }
324d2dddef7SLois Curfman McInnes 
325d2dddef7SLois Curfman McInnes #undef __FUNC__
326d2dddef7SLois Curfman McInnes #define __FUNC__ "SNESSetMatrixFreeParameters2"
327d2dddef7SLois Curfman McInnes /*@
328d2dddef7SLois Curfman McInnes    SNESSetMatrixFreeParameters2 - Sets the parameters for the approximation of
329d2dddef7SLois Curfman McInnes    matrix-vector products using finite differences.
330d2dddef7SLois Curfman McInnes 
331d2dddef7SLois Curfman McInnes $       J(u)*a = [J(u+h*a) - J(u)]/h where
332d2dddef7SLois Curfman McInnes 
333d2dddef7SLois Curfman McInnes    either the user sets h directly here, or this parameter is computed via
334d2dddef7SLois Curfman McInnes 
335d2dddef7SLois Curfman McInnes $        h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
336d2dddef7SLois Curfman McInnes $          = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
337d2dddef7SLois Curfman McInnes $
338d2dddef7SLois Curfman McInnes 
339d2dddef7SLois Curfman McInnes    Input Parameters:
340d2dddef7SLois Curfman McInnes .  snes - the SNES context
341d2dddef7SLois Curfman McInnes .  error_rel - relative error (should be set to the square root of
342d2dddef7SLois Curfman McInnes      the relative error in the function evaluations)
343d2dddef7SLois Curfman McInnes .  umin - minimum allowable u-value
344d2dddef7SLois Curfman McInnes .  h - differencing parameter
345d2dddef7SLois Curfman McInnes 
346d2dddef7SLois Curfman McInnes    Notes:
347d2dddef7SLois Curfman McInnes    If the user sets the parameter h directly, then this value will be used
348d2dddef7SLois Curfman McInnes    instead of the default computation indicated above.
349d2dddef7SLois Curfman McInnes 
350d2dddef7SLois Curfman McInnes .keywords: SNES, matrix-free, parameters
351d2dddef7SLois Curfman McInnes 
352d2dddef7SLois Curfman McInnes .seealso: SNESDefaultMatrixFreeMatCreate()
353d2dddef7SLois Curfman McInnes @*/
354d2dddef7SLois Curfman McInnes int SNESSetMatrixFreeParameters2(SNES snes,double error,double umin,double h)
355d2dddef7SLois Curfman McInnes {
356d2dddef7SLois Curfman McInnes   MFCtx_Private *ctx;
357d2dddef7SLois Curfman McInnes   int           ierr;
358d2dddef7SLois Curfman McInnes   Mat           mat;
359d2dddef7SLois Curfman McInnes 
36007a3eed9SLois Curfman McInnes   PetscFunctionBegin;
361d2dddef7SLois Curfman McInnes   ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
362d2dddef7SLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
363d2dddef7SLois Curfman McInnes   if (ctx) {
364d2dddef7SLois Curfman McInnes     if (error != PETSC_DEFAULT) ctx->error_rel = error;
365d2dddef7SLois Curfman McInnes     if (umin  != PETSC_DEFAULT) ctx->umin = umin;
366d2dddef7SLois Curfman McInnes     if (h     != PETSC_DEFAULT) {
367d2dddef7SLois Curfman McInnes       ctx->h = h;
368d2dddef7SLois Curfman McInnes       ctx->need_h = 0;
369d2dddef7SLois Curfman McInnes     }
370d2dddef7SLois Curfman McInnes   }
37107a3eed9SLois Curfman McInnes   PetscFunctionReturn(0);
372d2dddef7SLois Curfman McInnes }
373d2dddef7SLois Curfman McInnes 
374d2dddef7SLois Curfman McInnes int SNESUnSetMatrixFreeParameter(SNES snes)
375d2dddef7SLois Curfman McInnes {
376d2dddef7SLois Curfman McInnes   MFCtx_Private *ctx;
377d2dddef7SLois Curfman McInnes   int           ierr;
378d2dddef7SLois Curfman McInnes   Mat           mat;
379d2dddef7SLois Curfman McInnes 
38007a3eed9SLois Curfman McInnes   PetscFunctionBegin;
381d2dddef7SLois Curfman McInnes   ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
382d2dddef7SLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
383d2dddef7SLois Curfman McInnes   if (ctx) ctx->need_h = 1;
38407a3eed9SLois Curfman McInnes   PetscFunctionReturn(0);
385d2dddef7SLois Curfman McInnes }
386d2dddef7SLois Curfman McInnes 
387