xref: /petsc/src/snes/mf/snesmfj.c (revision ac2a4f0d24b3b6a4ee93edbcad41f4bb9e923944)
1 /*$Id: snesmfj.c,v 1.96 1999/10/13 20:38:27 bsmith Exp bsmith $*/
2 
3 #include "src/snes/snesimpl.h"
4 #include "src/snes/mf/snesmfj.h"   /*I  "snes.h"   I*/
5 
6 FList MatSNESMFList              = 0;
7 int   MatSNESMFRegisterAllCalled = 0;
8 
9 #undef __FUNC__
10 #define __FUNC__ "MatSNESMFSetType"
11 /*@C
12     MatSNESMFSetType - Sets the method that is used to compute the
13     differencing parameter for finite difference matrix-free formulations.
14 
15     Input Parameters:
16 +   mat - the "matrix-free" matrix created via MatCreateSNESMF()
17 -   ftype - the type requested
18 
19     Level: advanced
20 
21     Notes:
22     For example, such routines can compute h for use in
23     Jacobian-vector products of the form
24 
25                         F(x+ha) - F(x)
26           F'(u)a  ~=  ----------------
27                               h
28 
29 .seealso: MatCreateSNESMF(), MatSNESMFRegister()
30 @*/
31 int MatSNESMFSetType(Mat mat,char *ftype)
32 {
33   int          ierr, (*r)(MatSNESMFCtx);
34   MatSNESMFCtx ctx;
35   PetscTruth   match;
36 
37   PetscFunctionBegin;
38   PetscValidHeaderSpecific(mat,MAT_COOKIE);
39   PetscValidCharPointer(ftype);
40 
41   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
42 
43   /* already set, so just return */
44   ierr = PetscTypeCompare((PetscObject)ctx,ftype,&match);CHKERRQ(ierr);
45   if (match) PetscFunctionReturn(0);
46 
47   /* destroy the old one if it exists */
48   if (ctx->ops->destroy) {
49     ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);
50   }
51 
52   /* Get the function pointers for the requrested method */
53   if (!MatSNESMFRegisterAllCalled) {ierr = MatSNESMFRegisterAll(PETSC_NULL);CHKERRQ(ierr);}
54 
55   ierr =  FListFind(ctx->comm, MatSNESMFList, ftype,(int (**)(void *)) &r );CHKERRQ(ierr);
56 
57   if (!r) SETERRQ(1,1,"Unknown MatSNESMF type given");
58 
59   ierr = (*r)(ctx);CHKERRQ(ierr);
60 
61   ierr = PetscObjectChangeTypeName((PetscObject)ctx,ftype);CHKERRQ(ierr);
62 
63   PetscFunctionReturn(0);
64 }
65 
66 /*MC
67    MatSNESMFRegister - Adds a method to the MatSNESMF registry.
68 
69    Synopsis:
70    MatSNESMFRegister(char *name_solver,char *path,char *name_create,int (*routine_create)(MatSNESMF))
71 
72    Not Collective
73 
74    Input Parameters:
75 +  name_solver - name of a new user-defined compute-h module
76 .  path - path (either absolute or relative) the library containing this solver
77 .  name_create - name of routine to create method context
78 -  routine_create - routine to create method context
79 
80    Level: developer
81 
82    Notes:
83    MatSNESMFRegister() may be called multiple times to add several user-defined solvers.
84 
85    If dynamic libraries are used, then the fourth input argument (routine_create)
86    is ignored.
87 
88    Sample usage:
89 .vb
90    MatSNESMFRegister("my_h",/home/username/my_lib/lib/libO/solaris/mylib.a,
91                "MyHCreate",MyHCreate);
92 .ve
93 
94    Then, your solver can be chosen with the procedural interface via
95 $     MatSNESMFSetType(mfctx,"my_h")
96    or at runtime via the option
97 $     -snes_mf_type my_h
98 
99 .keywords: MatSNESMF, register
100 
101 .seealso: MatSNESMFRegisterAll(), MatSNESMFRegisterDestroy()
102 M*/
103 
104 #undef __FUNC__
105 #define __FUNC__ "MatSNESMFRegister_Private"
106 int MatSNESMFRegister_Private(char *sname,char *path,char *name,int (*function)(MatSNESMFCtx))
107 {
108   int ierr;
109   char fullname[256];
110 
111   PetscFunctionBegin;
112   ierr = FListConcat_Private(path,name,fullname); CHKERRQ(ierr);
113   ierr = FListAdd_Private(&MatSNESMFList,sname,fullname,(int (*)(void*))function);CHKERRQ(ierr);
114   PetscFunctionReturn(0);
115 }
116 
117 
118 #undef __FUNC__
119 #define __FUNC__ "MatSNESMFRegisterDestroy"
120 /*@C
121    MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were
122    registered by MatSNESMFRegister().
123 
124    Not Collective
125 
126    Level: developer
127 
128 .keywords: MatSNESMF, register, destroy
129 
130 .seealso: MatSNESMFRegister(), MatSNESMFRegisterAll()
131 @*/
132 int MatSNESMFRegisterDestroy(void)
133 {
134   int ierr;
135 
136   PetscFunctionBegin;
137   if (MatSNESMFList) {
138     ierr = FListDestroy( MatSNESMFList );CHKERRQ(ierr);
139     MatSNESMFList = 0;
140   }
141   MatSNESMFRegisterAllCalled = 0;
142   PetscFunctionReturn(0);
143 }
144 
145 /* ----------------------------------------------------------------------------------------*/
146 #undef __FUNC__
147 #define __FUNC__ "MatSNESMFDestroy_Private"
148 int MatSNESMFDestroy_Private(Mat mat)
149 {
150   int          ierr;
151   MatSNESMFCtx ctx;
152 
153   PetscFunctionBegin;
154   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
155   ierr = VecDestroy(ctx->w);CHKERRQ(ierr);
156   if (ctx->ops->destroy) {ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);}
157   if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp);CHKERRQ(ierr);}
158   PetscHeaderDestroy(ctx);
159   PetscFunctionReturn(0);
160 }
161 
162 #undef __FUNC__
163 #define __FUNC__ "MatSNESMFView_Private"
164 /*
165    MatSNESMFView_Private - Views matrix-free parameters.
166 
167 */
168 int MatSNESMFView_Private(Mat J,Viewer viewer)
169 {
170   int          ierr;
171   MatSNESMFCtx ctx;
172   PetscTruth   isascii;
173 
174   PetscFunctionBegin;
175   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
176   ierr = PetscTypeCompare((PetscObject)viewer,ASCII_VIEWER,&isascii);CHKERRQ(ierr);
177   if (isascii) {
178      ierr = ViewerASCIIPrintf(viewer,"  SNES matrix-free approximation:\n");CHKERRQ(ierr);
179      ierr = ViewerASCIIPrintf(viewer,"    err=%g (relative error in function evaluation)\n",ctx->error_rel);CHKERRQ(ierr);
180      ierr = ViewerASCIIPrintf(viewer,"    Using %s compute h routine\n",ctx->type_name);CHKERRQ(ierr);
181      if (ctx->ops->view) {
182        ierr = (*ctx->ops->view)(ctx,viewer);CHKERRQ(ierr);
183      }
184   } else {
185     SETERRQ1(1,1,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name);
186   }
187   PetscFunctionReturn(0);
188 }
189 
190 #undef __FUNC__
191 #define __FUNC__ "MatSNESMFAssemblyEnd_Private"
192 /*
193    MatSNESMFAssemblyEnd_Private - Resets the ctx->ncurrenth to zero. This
194    allows the user to indicate the beginning of a new linear solve by calling
195    MatAssemblyXXX() on the matrix free matrix. This then allows the
196    MatSNESMFCreate_WP() to properly compute ||U|| only the first time
197    in the linear solver rather than every time.
198 */
199 int MatSNESMFAssemblyEnd_Private(Mat J)
200 {
201   int            ierr;
202 
203   PetscFunctionBegin;
204   ierr = MatSNESMFResetHHistory(J);CHKERRQ(ierr);
205   PetscFunctionReturn(0);
206 }
207 
208 
209 #undef __FUNC__
210 #define __FUNC__ "MatSNESMFMult_Private"
211 /*
212   MatSNESMFMult_Private - Default matrix-free form for Jacobian-vector
213   product, y = F'(u)*a:
214 
215         y ~= ( F(u + ha) - F(u) )/h,
216   where F = nonlinear function, as set by SNESSetFunction()
217         u = current iterate
218         h = difference interval
219 */
220 int MatSNESMFMult_Private(Mat mat,Vec a,Vec y)
221 {
222   MatSNESMFCtx ctx;
223   SNES           snes;
224   Scalar         h, mone = -1.0;
225   Vec            w,U,F;
226   int            ierr, (*eval_fct)(SNES,Vec,Vec)=0;
227 
228   PetscFunctionBegin;
229   /* We log matrix-free matrix-vector products separately, so that we can
230      separate the performance monitoring from the cases that use conventional
231      storage.  We may eventually modify event logging to associate events
232      with particular objects, hence alleviating the more general problem. */
233   PLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);
234 
235   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
236   snes = ctx->snes;
237   w    = ctx->w;
238   ierr = SNESGetSolution(snes,&U);CHKERRQ(ierr);
239 
240   /*
241       Compute differencing parameter
242   */
243   if (!ctx->ops->compute) {
244     ierr = MatSNESMFSetType(mat,"default");CHKERRQ(ierr);
245     ierr = MatSNESMFSetFromOptions(mat);CHKERRQ(ierr);
246   }
247   ierr = (*ctx->ops->compute)(ctx,U,a,&h);CHKERRQ(ierr);
248 
249   /* keep a record of the current differencing parameter h */
250   ctx->currenth = h;
251 #if defined(PETSC_USE_COMPLEX)
252   PLogInfo(mat,"Current differencing parameter: %g + %g i\n",PetscReal(h),PetscImaginary(h));
253 #else
254   PLogInfo(mat,"Current differencing parameter: %g\n",h);
255 #endif
256   if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
257     ctx->historyh[ctx->ncurrenth] = h;
258   }
259   ctx->ncurrenth++;
260 
261   /* w = u + ha */
262   ierr = VecWAXPY(&h,a,U,w);CHKERRQ(ierr);
263 
264 
265   if (!ctx->func) {
266     if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
267       eval_fct = SNESComputeFunction;
268       ierr     = SNESGetFunction(snes,&F,PETSC_NULL);CHKERRQ(ierr);
269     } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
270       eval_fct = SNESComputeGradient;
271       ierr     = SNESGetGradient(snes,&F,PETSC_NULL);CHKERRQ(ierr);
272     } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Invalid method class");
273     ierr = eval_fct(snes,w,y);CHKERRQ(ierr);
274   } else {
275     F = ctx->funcvec;
276     /* compute func(U) as base for differencing */
277     if (ctx->ncurrenth == 1) {
278       ierr = (*ctx->func)(snes,U,F,ctx->funcctx);CHKERRQ(ierr);
279     }
280     ierr = (*ctx->func)(snes,w,y,ctx->funcctx);CHKERRQ(ierr);
281   }
282 
283   ierr = VecAXPY(&mone,F,y);CHKERRQ(ierr);
284   h    = 1.0/h;
285   ierr = VecScale(&h,y);CHKERRQ(ierr);
286   if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y);CHKERRQ(ierr);}
287 
288   PLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);
289   PetscFunctionReturn(0);
290 }
291 
292 #undef __FUNC__
293 #define __FUNC__ "MatCreateSNESMF"
294 /*@C
295    MatCreateSNESMF - Creates a matrix-free matrix context for use with
296    a SNES solver.  This matrix can be used as the Jacobian argument for
297    the routine SNESSetJacobian().
298 
299    Collective on SNES and Vec
300 
301    Input Parameters:
302 +  snes - the SNES context
303 -  x - vector where SNES solution is to be stored.
304 
305    Output Parameter:
306 .  J - the matrix-free matrix
307 
308    Level: advanced
309 
310    Notes:
311    The matrix-free matrix context merely contains the function pointers
312    and work space for performing finite difference approximations of
313    Jacobian-vector products, F'(u)*a,
314 
315    The default code uses the following approach to compute h
316 
317 .vb
318      F'(u)*a = [F(u+h*a) - F(u)]/h where
319      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
320        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
321  where
322      error_rel = square root of relative error in function evaluation
323      umin = minimum iterate parameter
324 .ve
325 
326    The user can set the error_rel via MatSNESMFSetFunctionError() and
327    umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
328    of the users manual for details.
329 
330    The user should call MatDestroy() when finished with the matrix-free
331    matrix context.
332 
333    Options Database Keys:
334 +  -snes_mf_err <error_rel> - Sets error_rel
335 .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
336 -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
337 
338 .keywords: SNES, default, matrix-free, create, matrix
339 
340 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
341           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
342           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegister()
343 
344 @*/
345 int MatCreateSNESMF(SNES snes,Vec x, Mat *J)
346 {
347   MPI_Comm     comm;
348   MatSNESMFCtx mfctx;
349   int          n, nloc, ierr;
350 
351   PetscFunctionBegin;
352   PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",snes->comm,MatSNESMFDestroy_Private,MatSNESMFView_Private);
353   PLogObjectCreate(mfctx);
354   mfctx->sp           = 0;
355   mfctx->snes         = snes;
356   mfctx->error_rel    = 1.e-8; /* assumes double precision */
357   mfctx->currenth     = 0.0;
358   mfctx->historyh     = PETSC_NULL;
359   mfctx->ncurrenth    = 0;
360   mfctx->maxcurrenth  = 0;
361   mfctx->type_name    = 0;
362 
363   /*
364      Create the empty data structure to contain compute-h routines.
365      These will be filled in below from the command line options or
366      a later call with MatSNESMFSetType() or if that is not called
367      then it will default in the first use of MatSNESMFMult_private()
368   */
369   mfctx->ops->compute        = 0;
370   mfctx->ops->destroy        = 0;
371   mfctx->ops->view           = 0;
372   mfctx->ops->printhelp      = 0;
373   mfctx->ops->setfromoptions = 0;
374   mfctx->hctx                = 0;
375 
376   mfctx->func                = 0;
377   mfctx->funcctx             = 0;
378   mfctx->funcvec             = 0;
379 
380   ierr = VecDuplicate(x,&mfctx->w);CHKERRQ(ierr);
381   ierr = PetscObjectGetComm((PetscObject)x,&comm);CHKERRQ(ierr);
382   ierr = VecGetSize(x,&n);CHKERRQ(ierr);
383   ierr = VecGetLocalSize(x,&nloc);CHKERRQ(ierr);
384   ierr = MatCreateShell(comm,nloc,nloc,n,n,mfctx,J);CHKERRQ(ierr);
385   ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)MatSNESMFMult_Private);CHKERRQ(ierr);
386   ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)MatSNESMFDestroy_Private);CHKERRQ(ierr);
387   ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)MatSNESMFView_Private);CHKERRQ(ierr);
388   ierr = MatShellSetOperation(*J,MATOP_ASSEMBLY_END,(void *)MatSNESMFAssemblyEnd_Private);CHKERRQ(ierr);
389   PLogObjectParent(*J,mfctx->w);
390   PLogObjectParent(snes,*J);
391 
392   mfctx->mat = *J;
393 
394 
395   PetscFunctionReturn(0);
396 }
397 
398 #undef __FUNC__
399 #define __FUNC__ "MatSNESMFSetFromOptions"
400 /*@
401    MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
402    parameter.
403 
404    Collective on Mat
405 
406    Input Parameters:
407 .  mat - the matrix obtained with MatCreateSNESMF()
408 
409    Options Database Keys:
410 +  -snes_mf_type - <default,wp>
411 -  -snes_mf_err - square root of estimated relative error in function evaluation
412 
413    Level: advanced
414 
415 .keywords: SNES, matrix-free, parameters
416 
417 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
418           MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
419 @*/
420 int MatSNESMFSetFromOptions(Mat mat)
421 {
422   MatSNESMFCtx mfctx;
423   int          ierr,flg;
424   char         ftype[256],p[64];
425 
426   PetscFunctionBegin;
427   ierr = MatShellGetContext(mat,(void **)&mfctx);CHKERRQ(ierr);
428   if (mfctx) {
429     /* allow user to set the type */
430     ierr = OptionsGetString(mfctx->snes->prefix,"-snes_mf_type",ftype,256,&flg);CHKERRQ(ierr);
431     if (flg) {
432       ierr = MatSNESMFSetType(mat,ftype);CHKERRQ(ierr);
433     }
434 
435     ierr = OptionsGetDouble(mfctx->snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg);CHKERRQ(ierr);
436     if (mfctx->ops->setfromoptions) {
437       ierr = (*mfctx->ops->setfromoptions)(mfctx);CHKERRQ(ierr);
438     }
439 
440     ierr = OptionsHasName(PETSC_NULL,"-help",&flg);CHKERRQ(ierr);
441     ierr = PetscStrcpy(p,"-");CHKERRQ(ierr);
442     if (mfctx->snes->prefix) {ierr = PetscStrcat(p,mfctx->snes->prefix);CHKERRQ(ierr);}
443     if (flg) {
444       ierr = (*PetscHelpPrintf)(mfctx->snes->comm,"   %ssnes_mf_err <err>: set sqrt rel error in function (default %g)\n",p,mfctx->error_rel);CHKERRQ(ierr);
445       if (mfctx->ops->printhelp) {
446         ierr = (*mfctx->ops->printhelp)(mfctx);CHKERRQ(ierr);
447       }
448     }
449   }
450   PetscFunctionReturn(0);
451 }
452 
453 #undef __FUNC__
454 #define __FUNC__ "MatSNESMFGetH"
455 /*@
456    MatSNESMFGetH - Gets the last value that was used as the differencing
457    parameter.
458 
459    Not Collective
460 
461    Input Parameters:
462 .  mat - the matrix obtained with MatCreateSNESMF()
463 
464    Output Paramter:
465 .  h - the differencing step size
466 
467    Level: advanced
468 
469 .keywords: SNES, matrix-free, parameters
470 
471 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
472           MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
473 @*/
474 int MatSNESMFGetH(Mat mat,Scalar *h)
475 {
476   MatSNESMFCtx ctx;
477   int          ierr;
478 
479   PetscFunctionBegin;
480   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
481   if (ctx) {
482     *h = ctx->currenth;
483   }
484   PetscFunctionReturn(0);
485 }
486 
487 #undef __FUNC__
488 #define __FUNC__ "MatSNESMFKSPMonitor"
489 /*
490    MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc
491    SNES matrix free routines. Prints the differencing parameter used at
492    each step.
493 */
494 int MatSNESMFKSPMonitor(KSP ksp,int n,double rnorm,void *dummy)
495 {
496   PC             pc;
497   MatSNESMFCtx   ctx;
498   int            ierr;
499   Mat            mat;
500   MPI_Comm       comm;
501   PetscTruth     nonzeroinitialguess;
502 
503   PetscFunctionBegin;
504   ierr = PetscObjectGetComm((PetscObject)ksp,&comm);CHKERRQ(ierr);
505   ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
506   ierr = KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);CHKERRQ(ierr);
507   ierr = PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
508   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
509   if (!ctx) {
510     SETERRQ(1,1,"Matrix is not a matrix free shell matrix");
511   }
512   if (n > 0 || nonzeroinitialguess) {
513 #if defined(PETSC_USE_COMPLEX)
514     ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g i\n",n,rnorm,
515                 PetscReal(ctx->currenth),PetscImaginary(ctx->currenth));CHKERRQ(ierr);
516 #else
517     ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);CHKERRQ(ierr);
518 #endif
519   } else {
520     ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e\n",n,rnorm);CHKERRQ(ierr);
521   }
522   PetscFunctionReturn(0);
523 }
524 
525 #undef __FUNC__
526 #define __FUNC__ "MatSNESMFSetFunction"
527 /*@C
528    MatSNESMFSetFunction - Sets the function used in applying the matrix free.
529 
530    Collective on Mat
531 
532    Input Parameters:
533 +  mat - the matrix free matrix created via MatCreateSNESMF()
534 .  v   - workspace vector
535 .  func - the function to use
536 -  funcctx - optional function context passed to function
537 
538    Level: advanced
539 
540    Notes:
541     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
542     matrix inside your compute Jacobian routine
543 
544     If this is not set then it will use the function set with SNESSetFunction()
545 
546 .keywords: SNES, matrix-free, function
547 
548 .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
549           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
550           MatSNESMFKSPMonitor(), SNESetFunction()
551 @*/
552 int MatSNESMFSetFunction(Mat mat,Vec v,int (*func)(SNES,Vec,Vec,void *),void *funcctx)
553 {
554   MatSNESMFCtx ctx;
555   int          ierr;
556 
557   PetscFunctionBegin;
558   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
559   if (ctx) {
560     ctx->func    = func;
561     ctx->funcctx = funcctx;
562     ctx->funcvec = v;
563   }
564   PetscFunctionReturn(0);
565 }
566 
567 
568 #undef __FUNC__
569 #define __FUNC__ "MatSNESMFSetFunctionError"
570 /*@
571    MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
572    matrix-vector products using finite differences.
573 
574    Collective on Mat
575 
576    Input Parameters:
577 +  mat - the matrix free matrix created via MatCreateSNESMF()
578 -  error_rel - relative error (should be set to the square root of
579                the relative error in the function evaluations)
580 
581    Options Database Keys:
582 +  -snes_mf_err <error_rel> - Sets error_rel
583 
584    Level: advanced
585 
586    Notes:
587    The default matrix-free matrix-vector product routine computes
588 .vb
589      F'(u)*a = [F(u+h*a) - F(u)]/h where
590      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
591        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
592 .ve
593 
594 .keywords: SNES, matrix-free, parameters
595 
596 .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
597           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
598           MatSNESMFKSPMonitor()
599 @*/
600 int MatSNESMFSetFunctionError(Mat mat,double error)
601 {
602   MatSNESMFCtx ctx;
603   int          ierr;
604 
605   PetscFunctionBegin;
606   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
607   if (ctx) {
608     if (error != PETSC_DEFAULT) ctx->error_rel = error;
609   }
610   PetscFunctionReturn(0);
611 }
612 
613 #undef __FUNC__
614 #define __FUNC__ "MatSNESMFAddNullSpace"
615 /*@
616    MatSNESMFAddNullSpace - Provides a null space that an operator is
617    supposed to have.  Since roundoff will create a small component in
618    the null space, if you know the null space you may have it
619    automatically removed.
620 
621    Collective on Mat
622 
623    Input Parameters:
624 +  J - the matrix-free matrix context
625 -  nullsp - object created with PCNullSpaceCreate()
626 
627    Level: advanced
628 
629 .keywords: SNES, matrix-free, null space
630 
631 .seealso: PCNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
632           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
633           MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
634 @*/
635 int MatSNESMFAddNullSpace(Mat J,PCNullSpace nullsp)
636 {
637   int          ierr;
638   MatSNESMFCtx ctx;
639   MPI_Comm     comm;
640 
641   PetscFunctionBegin;
642   ierr = PetscObjectGetComm((PetscObject)J,&comm);CHKERRQ(ierr);
643 
644   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
645   /* no context indicates that it is not the "matrix free" matrix type */
646   if (!ctx) PetscFunctionReturn(0);
647   ctx->sp = nullsp;
648   ierr = PetscObjectReference((PetscObject)nullsp);CHKERRQ(ierr);
649   PetscFunctionReturn(0);
650 }
651 
652 #undef __FUNC__
653 #define __FUNC__ "MatSNESMFSetHHistory"
654 /*@
655    MatSNESMFSetHHistory - Sets an array to collect a history of the
656    differencing values (h) computed for the matrix-free product.
657 
658    Collective on Mat
659 
660    Input Parameters:
661 +  J - the matrix-free matrix context
662 .  histroy - space to hold the history
663 -  nhistory - number of entries in history, if more entries are generated than
664               nhistory, then the later ones are discarded
665 
666    Level: advanced
667 
668    Notes:
669    Use MatSNESMFResetHHistory() to reset the history counter and collect
670    a new batch of differencing parameters, h.
671 
672 .keywords: SNES, matrix-free, h history, differencing history
673 
674 .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
675           MatSNESMFResetHHistory(),
676           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
677 
678 @*/
679 int MatSNESMFSetHHistory(Mat J,Scalar *history,int nhistory)
680 {
681   int          ierr;
682   MatSNESMFCtx ctx;
683 
684   PetscFunctionBegin;
685 
686   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
687   /* no context indicates that it is not the "matrix free" matrix type */
688   if (!ctx) PetscFunctionReturn(0);
689   ctx->historyh    = history;
690   ctx->maxcurrenth = nhistory;
691   ctx->currenth    = 0;
692 
693   PetscFunctionReturn(0);
694 }
695 
696 #undef __FUNC__
697 #define __FUNC__ "MatSNESMFResetHHistory"
698 /*@
699    MatSNESMFResetHHistory - Resets the counter to zero to begin
700    collecting a new set of differencing histories.
701 
702    Collective on Mat
703 
704    Input Parameters:
705 .  J - the matrix-free matrix context
706 
707    Level: advanced
708 
709    Notes:
710    Use MatSNESMFSetHHistory() to create the original history counter.
711 
712 .keywords: SNES, matrix-free, h history, differencing history
713 
714 .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
715           MatSNESMFSetHHistory(),
716           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
717 
718 @*/
719 int MatSNESMFResetHHistory(Mat J)
720 {
721   int          ierr;
722   MatSNESMFCtx ctx;
723 
724   PetscFunctionBegin;
725 
726   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
727   /* no context indicates that it is not the "matrix free" matrix type */
728   if (!ctx) PetscFunctionReturn(0);
729   ctx->ncurrenth    = 0;
730 
731   PetscFunctionReturn(0);
732 }
733 
734