xref: /petsc/src/snes/mf/snesmfj.c (revision 53e63a63e2b322862e46cb3df41e7eff98a20d20)
1 /*$Id: snesmfj.c,v 1.115 2001/01/15 21:47:52 bsmith Exp bsmith $*/
2 
3 #include "src/snes/snesimpl.h"
4 #include "src/snes/mf/snesmfj.h"   /*I  "petscsnes.h"   I*/
5 
6 PetscFList      MatSNESMPetscFList              = 0;
7 PetscTruth MatSNESMFRegisterAllCalled = PETSC_FALSE;
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 differene 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(), MatSNESMFRegisterDynamic)
30 @*/
31 int MatSNESMFSetType(Mat mat,MatSNESMFType 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 =  PetscFListFind(ctx->comm,MatSNESMPetscFList,ftype,(int (**)(void *)) &r);CHKERRQ(ierr);
56 
57   if (!r) SETERRQ(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    MatSNESMFRegisterDynamic - Adds a method to the MatSNESMF registry.
68 
69    Synopsis:
70    MatSNESMFRegisterDynamicchar *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    MatSNESMFRegisterDynamic) 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    MatSNESMFRegisterDynamic"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"
106 int MatSNESMFRegister(char *sname,char *path,char *name,int (*function)(MatSNESMFCtx))
107 {
108   int ierr;
109   char fullname[256];
110 
111   PetscFunctionBegin;
112   ierr = PetscFListConcat(path,name,fullname);CHKERRQ(ierr);
113   ierr = PetscFListAdd(&MatSNESMPetscFList,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 MatSNESMFRegisterDynamic).
123 
124    Not Collective
125 
126    Level: developer
127 
128 .keywords: MatSNESMF, register, destroy
129 
130 .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll()
131 @*/
132 int MatSNESMFRegisterDestroy(void)
133 {
134   int ierr;
135 
136   PetscFunctionBegin;
137   if (MatSNESMPetscFList) {
138     ierr = PetscFListDestroy(&MatSNESMPetscFList);CHKERRQ(ierr);
139     MatSNESMPetscFList = 0;
140   }
141   MatSNESMFRegisterAllCalled = PETSC_FALSE;
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 = MatNullSpaceDestroy(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,PetscViewer 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,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr);
177   if (isascii) {
178      ierr = PetscViewerASCIIPrintf(viewer,"  SNES matrix-free approximation:\n");CHKERRQ(ierr);
179      ierr = PetscViewerASCIIPrintf(viewer,"    err=%g (relative error in function evaluation)\n",ctx->error_rel);CHKERRQ(ierr);
180      if (!ctx->type_name) {
181        ierr = PetscViewerASCIIPrintf(viewer,"    The compute h routine has not yet been set\n");CHKERRQ(ierr);
182      } else {
183        ierr = PetscViewerASCIIPrintf(viewer,"    Using %s compute h routine\n",ctx->type_name);CHKERRQ(ierr);
184      }
185      if (ctx->ops->view) {
186        ierr = (*ctx->ops->view)(ctx,viewer);CHKERRQ(ierr);
187      }
188   } else {
189     SETERRQ1(1,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name);
190   }
191   PetscFunctionReturn(0);
192 }
193 
194 #undef __FUNC__
195 #define __FUNC__ "MatSNESMFAssemblyEnd_Private"
196 /*
197    MatSNESMFAssemblyEnd_Private - Resets the ctx->ncurrenth to zero. This
198    allows the user to indicate the beginning of a new linear solve by calling
199    MatAssemblyXXX() on the matrix free matrix. This then allows the
200    MatSNESMFCreate_WP() to properly compute ||U|| only the first time
201    in the linear solver rather than every time.
202 */
203 int MatSNESMFAssemblyEnd_Private(Mat J)
204 {
205   int          ierr;
206   MatSNESMFCtx j;
207 
208   PetscFunctionBegin;
209   ierr = MatSNESMFResetHHistory(J);CHKERRQ(ierr);
210   ierr = MatShellGetContext(J,(void **)&j);CHKERRQ(ierr);
211   if (j->usesnes) {
212     ierr = SNESGetSolution(j->snes,&j->current_u);CHKERRQ(ierr);
213     if (j->snes->method_class == SNES_NONLINEAR_EQUATIONS) {
214       ierr = SNESGetFunction(j->snes,&j->current_f,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
215     } else if (j->snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
216       ierr = SNESGetGradient(j->snes,&j->current_f,PETSC_NULL);CHKERRQ(ierr);
217     } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid method class");
218   }
219   PetscFunctionReturn(0);
220 }
221 
222 
223 #undef __FUNC__
224 #define __FUNC__ "MatSNESMFMult_Private"
225 /*
226   MatSNESMFMult_Private - Default matrix-free form for Jacobian-vector
227   product, y = F'(u)*a:
228 
229         y ~= (F(u + ha) - F(u))/h,
230   where F = nonlinear function, as set by SNESSetFunction()
231         u = current iterate
232         h = difference interval
233 */
234 int MatSNESMFMult_Private(Mat mat,Vec a,Vec y)
235 {
236   MatSNESMFCtx ctx;
237   SNES         snes;
238   Scalar       h,mone = -1.0;
239   Vec          w,U,F;
240   int          ierr,(*eval_fct)(SNES,Vec,Vec)=0;
241 
242   PetscFunctionBegin;
243   /* We log matrix-free matrix-vector products separately, so that we can
244      separate the performance monitoring from the cases that use conventional
245      storage.  We may eventually modify event logging to associate events
246      with particular objects, hence alleviating the more general problem. */
247   ierr = PetscLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);CHKERRQ(ierr);
248 
249   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
250   snes = ctx->snes;
251   w    = ctx->w;
252   U    = ctx->current_u;
253 
254   /*
255       Compute differencing parameter
256   */
257   if (!ctx->ops->compute) {
258     ierr = MatSNESMFSetType(mat,MATSNESMF_DEFAULT);CHKERRQ(ierr);
259     ierr = MatSNESMFSetFromOptions(mat);CHKERRQ(ierr);
260   }
261   ierr = (*ctx->ops->compute)(ctx,U,a,&h);CHKERRQ(ierr);
262 
263   /* keep a record of the current differencing parameter h */
264   ctx->currenth = h;
265 #if defined(PETSC_USE_COMPLEX)
266   PetscLogInfo(mat,"MatSNESMFMult_Private:Current differencing parameter: %g + %g i\n",PetscRealPart(h),PetscImaginaryPart(h));
267 #else
268   PetscLogInfo(mat,"MatSNESMFMult_Private:Current differencing parameter: %15.12e\n",h);
269 #endif
270   if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
271     ctx->historyh[ctx->ncurrenth] = h;
272   }
273   ctx->ncurrenth++;
274 
275   /* w = u + ha */
276   ierr = VecWAXPY(&h,a,U,w);CHKERRQ(ierr);
277 
278   if (ctx->usesnes) {
279     if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
280       eval_fct = SNESComputeFunction;
281     } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
282       eval_fct = SNESComputeGradient;
283     } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid method class");
284     F    = ctx->current_f;
285     if (!F) SETERRQ(1,"You must call MatAssembly() even on matrix-free matrices");
286     ierr = (*eval_fct)(snes,w,y);CHKERRQ(ierr);
287   } else {
288     F = ctx->funcvec;
289     /* compute func(U) as base for differencing */
290     if (ctx->ncurrenth == 1) {
291       ierr = (*ctx->func)(snes,U,F,ctx->funcctx);CHKERRQ(ierr);
292     }
293     ierr = (*ctx->func)(snes,w,y,ctx->funcctx);CHKERRQ(ierr);
294   }
295 
296   ierr = VecAXPY(&mone,F,y);CHKERRQ(ierr);
297   h    = 1.0/h;
298   ierr = VecScale(&h,y);CHKERRQ(ierr);
299   if (ctx->sp) {ierr = MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);CHKERRQ(ierr);}
300 
301   ierr = PetscLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);CHKERRQ(ierr);
302   PetscFunctionReturn(0);
303 }
304 
305 #undef __FUNC__
306 #define __FUNC__ "MatCreateSNESMF"
307 /*@C
308    MatCreateSNESMF - Creates a matrix-free matrix context for use with
309    a SNES solver.  This matrix can be used as the Jacobian argument for
310    the routine SNESSetJacobian().
311 
312    Collective on SNES and Vec
313 
314    Input Parameters:
315 +  snes - the SNES context
316 -  x - vector where SNES solution is to be stored.
317 
318    Output Parameter:
319 .  J - the matrix-free matrix
320 
321    Level: advanced
322 
323    Notes:
324    The matrix-free matrix context merely contains the function pointers
325    and work space for performing finite difference approximations of
326    Jacobian-vector products, F'(u)*a,
327 
328    The default code uses the following approach to compute h
329 
330 .vb
331      F'(u)*a = [F(u+h*a) - F(u)]/h where
332      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
333        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
334  where
335      error_rel = square root of relative error in function evaluation
336      umin = minimum iterate parameter
337 .ve
338 
339    The user can set the error_rel via MatSNESMFSetFunctionError() and
340    umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
341    of the users manual for details.
342 
343    The user should call MatDestroy() when finished with the matrix-free
344    matrix context.
345 
346    Options Database Keys:
347 +  -snes_mf_err <error_rel> - Sets error_rel
348 .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
349 -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
350 
351 .keywords: SNES, default, matrix-free, create, matrix
352 
353 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
354           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(),
355           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFFormJacobian()
356 
357 @*/
358 int MatCreateSNESMF(SNES snes,Vec x,Mat *J)
359 {
360   MatSNESMFCtx mfctx;
361   int          ierr;
362 
363   PetscFunctionBegin;
364   ierr = MatCreateMF(x,J);CHKERRQ(ierr);
365   ierr = MatShellGetContext(*J,(void **)&mfctx);CHKERRQ(ierr);
366   mfctx->snes    = snes;
367   mfctx->usesnes = PETSC_TRUE;
368   PetscLogObjectParent(snes,*J);
369   PetscFunctionReturn(0);
370 }
371 
372 #undef __FUNC__
373 #define __FUNC__ "MatCreateMF"
374 /*@C
375    MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF()
376 
377    Collective on Vec
378 
379    Input Parameters:
380 .  x - vector that defines layout of the vectors and matrices
381 
382    Output Parameter:
383 .  J - the matrix-free matrix
384 
385    Level: advanced
386 
387    Notes:
388    The matrix-free matrix context merely contains the function pointers
389    and work space for performing finite difference approximations of
390    Jacobian-vector products, F'(u)*a,
391 
392    The default code uses the following approach to compute h
393 
394 .vb
395      F'(u)*a = [F(u+h*a) - F(u)]/h where
396      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
397        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
398  where
399      error_rel = square root of relative error in function evaluation
400      umin = minimum iterate parameter
401 .ve
402 
403    The user can set the error_rel via MatSNESMFSetFunctionError() and
404    umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
405    of the users manual for details.
406 
407    The user should call MatDestroy() when finished with the matrix-free
408    matrix context.
409 
410    Options Database Keys:
411 +  -snes_mf_err <error_rel> - Sets error_rel
412 .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
413 -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
414 
415 .keywords: default, matrix-free, create, matrix
416 
417 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
418           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(),
419           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFFormJacobian()
420 
421 @*/
422 int MatCreateMF(Vec x,Mat *J)
423 {
424   MPI_Comm     comm;
425   MatSNESMFCtx mfctx;
426   int          n,nloc,ierr;
427 
428   PetscFunctionBegin;
429   ierr = PetscObjectGetComm((PetscObject)x,&comm);CHKERRQ(ierr);
430   PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",comm,MatSNESMFDestroy_Private,MatSNESMFView_Private);
431   PetscLogObjectCreate(mfctx);
432   mfctx->sp              = 0;
433   mfctx->snes            = 0;
434   mfctx->error_rel       = 1.e-8; /* assumes PetscReal precision */
435   mfctx->recomputeperiod = 1;
436   mfctx->count           = 0;
437   mfctx->currenth        = 0.0;
438   mfctx->historyh        = PETSC_NULL;
439   mfctx->ncurrenth       = 0;
440   mfctx->maxcurrenth     = 0;
441   mfctx->type_name       = 0;
442   mfctx->usesnes         = PETSC_FALSE;
443 
444   /*
445      Create the empty data structure to contain compute-h routines.
446      These will be filled in below from the command line options or
447      a later call with MatSNESMFSetType() or if that is not called
448      then it will default in the first use of MatSNESMFMult_private()
449   */
450   mfctx->ops->compute        = 0;
451   mfctx->ops->destroy        = 0;
452   mfctx->ops->view           = 0;
453   mfctx->ops->setfromoptions = 0;
454   mfctx->hctx                = 0;
455 
456   mfctx->func                = 0;
457   mfctx->funcctx             = 0;
458   mfctx->funcvec             = 0;
459 
460   ierr = VecDuplicate(x,&mfctx->w);CHKERRQ(ierr);
461   ierr = VecGetSize(mfctx->w,&n);CHKERRQ(ierr);
462   ierr = VecGetLocalSize(mfctx->w,&nloc);CHKERRQ(ierr);
463   ierr = MatCreateShell(comm,nloc,nloc,n,n,mfctx,J);CHKERRQ(ierr);
464   ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)MatSNESMFMult_Private);CHKERRQ(ierr);
465   ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)MatSNESMFDestroy_Private);CHKERRQ(ierr);
466   ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)MatSNESMFView_Private);CHKERRQ(ierr);
467   ierr = MatShellSetOperation(*J,MATOP_ASSEMBLY_END,(void *)MatSNESMFAssemblyEnd_Private);CHKERRQ(ierr);
468   PetscLogObjectParent(*J,mfctx->w);
469 
470   mfctx->mat = *J;
471   PetscFunctionReturn(0);
472 }
473 
474 #undef __FUNC__
475 #define __FUNC__ "MatSNESMFSetFromOptions"
476 /*@
477    MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
478    parameter.
479 
480    Collective on Mat
481 
482    Input Parameters:
483 .  mat - the matrix obtained with MatCreateSNESMF()
484 
485    Options Database Keys:
486 +  -snes_mf_type - <default,wp>
487 -  -snes_mf_err - square root of estimated relative error in function evaluation
488 -  -snes_mf_period - how often h is recomputed, defaults to 1, everytime
489 
490    Level: advanced
491 
492 .keywords: SNES, matrix-free, parameters
493 
494 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
495           MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
496 @*/
497 int MatSNESMFSetFromOptions(Mat mat)
498 {
499   MatSNESMFCtx mfctx;
500   int          ierr;
501   PetscTruth   flg;
502   char         ftype[256];
503 
504   PetscFunctionBegin;
505   ierr = MatShellGetContext(mat,(void **)&mfctx);CHKERRQ(ierr);
506   if (mfctx) {
507     if (!MatSNESMFRegisterAllCalled) {ierr = MatSNESMFRegisterAll(PETSC_NULL);CHKERRQ(ierr);}
508 
509     ierr = PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");CHKERRQ(ierr);
510       ierr = PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);CHKERRQ(ierr);
511       if (flg) {
512         ierr = MatSNESMFSetType(mat,ftype);CHKERRQ(ierr);
513       }
514 
515       ierr = PetscOptionsDouble("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);CHKERRQ(ierr);
516       ierr = PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);CHKERRQ(ierr);
517       if (mfctx->snes) {
518         ierr = PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);CHKERRQ(ierr);
519         if (flg) {
520           SLES sles;
521           KSP  ksp;
522           ierr = SNESGetSLES(mfctx->snes,&sles);CHKERRQ(ierr);
523           ierr = SLESGetKSP(sles,&ksp);CHKERRQ(ierr);
524           ierr = KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);CHKERRQ(ierr);
525         }
526       }
527       if (mfctx->ops->setfromoptions) {
528         ierr = (*mfctx->ops->setfromoptions)(mfctx);CHKERRQ(ierr);
529       }
530     ierr = PetscOptionsEnd();CHKERRQ(ierr);
531 
532   }
533   PetscFunctionReturn(0);
534 }
535 
536 #undef __FUNC__
537 #define __FUNC__ "MatSNESMFGetH"
538 /*@
539    MatSNESMFGetH - Gets the last value that was used as the differencing
540    parameter.
541 
542    Not Collective
543 
544    Input Parameters:
545 .  mat - the matrix obtained with MatCreateSNESMF()
546 
547    Output Paramter:
548 .  h - the differencing step size
549 
550    Level: advanced
551 
552 .keywords: SNES, matrix-free, parameters
553 
554 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
555           MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
556 @*/
557 int MatSNESMFGetH(Mat mat,Scalar *h)
558 {
559   MatSNESMFCtx ctx;
560   int          ierr;
561 
562   PetscFunctionBegin;
563   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
564   if (ctx) {
565     *h = ctx->currenth;
566   }
567   PetscFunctionReturn(0);
568 }
569 
570 #undef __FUNC__
571 #define __FUNC__ "MatSNESMFKSPMonitor"
572 /*
573    MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc
574    SNES matrix free routines. Prints the differencing parameter used at
575    each step.
576 */
577 int MatSNESMFKSPMonitor(KSP ksp,int n,PetscReal rnorm,void *dummy)
578 {
579   PC             pc;
580   MatSNESMFCtx   ctx;
581   int            ierr;
582   Mat            mat;
583   MPI_Comm       comm;
584   PetscTruth     nonzeroinitialguess;
585 
586   PetscFunctionBegin;
587   ierr = PetscObjectGetComm((PetscObject)ksp,&comm);CHKERRQ(ierr);
588   ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
589   ierr = KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);CHKERRQ(ierr);
590   ierr = PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
591   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
592   if (!ctx) {
593     SETERRQ(1,"Matrix is not a matrix free shell matrix");
594   }
595   if (n > 0 || nonzeroinitialguess) {
596 #if defined(PETSC_USE_COMPLEX)
597     ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g i\n",n,rnorm,
598                 PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));CHKERRQ(ierr);
599 #else
600     ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);CHKERRQ(ierr);
601 #endif
602   } else {
603     ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e\n",n,rnorm);CHKERRQ(ierr);
604   }
605   PetscFunctionReturn(0);
606 }
607 
608 #undef __FUNC__
609 #define __FUNC__ "MatSNESMFSetFunction"
610 /*@C
611    MatSNESMFSetFunction - Sets the function used in applying the matrix free.
612 
613    Collective on Mat
614 
615    Input Parameters:
616 +  mat - the matrix free matrix created via MatCreateSNESMF()
617 .  v   - workspace vector
618 .  func - the function to use
619 -  funcctx - optional function context passed to function
620 
621    Level: advanced
622 
623    Notes:
624     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
625     matrix inside your compute Jacobian routine
626 
627     If this is not set then it will use the function set with SNESSetFunction()
628 
629 .keywords: SNES, matrix-free, function
630 
631 .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
632           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
633           MatSNESMFKSPMonitor(), SNESetFunction()
634 @*/
635 int MatSNESMFSetFunction(Mat mat,Vec v,int (*func)(SNES,Vec,Vec,void *),void *funcctx)
636 {
637   MatSNESMFCtx ctx;
638   int          ierr;
639 
640   PetscFunctionBegin;
641   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
642   if (ctx) {
643     ctx->func    = func;
644     ctx->funcctx = funcctx;
645     ctx->funcvec = v;
646   }
647   PetscFunctionReturn(0);
648 }
649 
650 
651 #undef __FUNC__
652 #define __FUNC__ "MatSNESMFSetPeriod"
653 /*@
654    MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime
655 
656    Collective on Mat
657 
658    Input Parameters:
659 +  mat - the matrix free matrix created via MatCreateSNESMF()
660 -  period - 1 for everytime, 2 for every second etc
661 
662    Options Database Keys:
663 +  -snes_mf_period <period>
664 
665    Level: advanced
666 
667 
668 .keywords: SNES, matrix-free, parameters
669 
670 .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
671           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
672           MatSNESMFKSPMonitor()
673 @*/
674 int MatSNESMFSetPeriod(Mat mat,int period)
675 {
676   MatSNESMFCtx ctx;
677   int          ierr;
678 
679   PetscFunctionBegin;
680   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
681   if (ctx) {
682     ctx->recomputeperiod = period;
683   }
684   PetscFunctionReturn(0);
685 }
686 
687 #undef __FUNC__
688 #define __FUNC__ "MatSNESMFSetFunctionError"
689 /*@
690    MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
691    matrix-vector products using finite differences.
692 
693    Collective on Mat
694 
695    Input Parameters:
696 +  mat - the matrix free matrix created via MatCreateSNESMF()
697 -  error_rel - relative error (should be set to the square root of
698                the relative error in the function evaluations)
699 
700    Options Database Keys:
701 +  -snes_mf_err <error_rel> - Sets error_rel
702 
703    Level: advanced
704 
705    Notes:
706    The default matrix-free matrix-vector product routine computes
707 .vb
708      F'(u)*a = [F(u+h*a) - F(u)]/h where
709      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
710        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
711 .ve
712 
713 .keywords: SNES, matrix-free, parameters
714 
715 .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
716           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
717           MatSNESMFKSPMonitor()
718 @*/
719 int MatSNESMFSetFunctionError(Mat mat,PetscReal error)
720 {
721   MatSNESMFCtx ctx;
722   int          ierr;
723 
724   PetscFunctionBegin;
725   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
726   if (ctx) {
727     if (error != PETSC_DEFAULT) ctx->error_rel = error;
728   }
729   PetscFunctionReturn(0);
730 }
731 
732 #undef __FUNC__
733 #define __FUNC__ "MatSNESMFAddNullSpace"
734 /*@
735    MatSNESMFAddNullSpace - Provides a null space that an operator is
736    supposed to have.  Since roundoff will create a small component in
737    the null space, if you know the null space you may have it
738    automatically removed.
739 
740    Collective on Mat
741 
742    Input Parameters:
743 +  J - the matrix-free matrix context
744 -  nullsp - object created with MatNullSpaceCreate()
745 
746    Level: advanced
747 
748 .keywords: SNES, matrix-free, null space
749 
750 .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
751           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
752           MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
753 @*/
754 int MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp)
755 {
756   int          ierr;
757   MatSNESMFCtx ctx;
758   MPI_Comm     comm;
759 
760   PetscFunctionBegin;
761   ierr = PetscObjectGetComm((PetscObject)J,&comm);CHKERRQ(ierr);
762 
763   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
764   /* no context indicates that it is not the "matrix free" matrix type */
765   if (!ctx) PetscFunctionReturn(0);
766   ctx->sp = nullsp;
767   ierr = PetscObjectReference((PetscObject)nullsp);CHKERRQ(ierr);
768   PetscFunctionReturn(0);
769 }
770 
771 #undef __FUNC__
772 #define __FUNC__ "MatSNESMFSetHHistory"
773 /*@
774    MatSNESMFSetHHistory - Sets an array to collect a history of the
775    differencing values (h) computed for the matrix-free product.
776 
777    Collective on Mat
778 
779    Input Parameters:
780 +  J - the matrix-free matrix context
781 .  histroy - space to hold the history
782 -  nhistory - number of entries in history, if more entries are generated than
783               nhistory, then the later ones are discarded
784 
785    Level: advanced
786 
787    Notes:
788    Use MatSNESMFResetHHistory() to reset the history counter and collect
789    a new batch of differencing parameters, h.
790 
791 .keywords: SNES, matrix-free, h history, differencing history
792 
793 .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
794           MatSNESMFResetHHistory(),
795           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
796 
797 @*/
798 int MatSNESMFSetHHistory(Mat J,Scalar *history,int nhistory)
799 {
800   int          ierr;
801   MatSNESMFCtx ctx;
802 
803   PetscFunctionBegin;
804 
805   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
806   /* no context indicates that it is not the "matrix free" matrix type */
807   if (!ctx) PetscFunctionReturn(0);
808   ctx->historyh    = history;
809   ctx->maxcurrenth = nhistory;
810   ctx->currenth    = 0;
811 
812   PetscFunctionReturn(0);
813 }
814 
815 #undef __FUNC__
816 #define __FUNC__ "MatSNESMFResetHHistory"
817 /*@
818    MatSNESMFResetHHistory - Resets the counter to zero to begin
819    collecting a new set of differencing histories.
820 
821    Collective on Mat
822 
823    Input Parameters:
824 .  J - the matrix-free matrix context
825 
826    Level: advanced
827 
828    Notes:
829    Use MatSNESMFSetHHistory() to create the original history counter.
830 
831 .keywords: SNES, matrix-free, h history, differencing history
832 
833 .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
834           MatSNESMFSetHHistory(),
835           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
836 
837 @*/
838 int MatSNESMFResetHHistory(Mat J)
839 {
840   int          ierr;
841   MatSNESMFCtx ctx;
842 
843   PetscFunctionBegin;
844 
845   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
846   /* no context indicates that it is not the "matrix free" matrix type */
847   if (!ctx) PetscFunctionReturn(0);
848   ctx->ncurrenth    = 0;
849 
850   PetscFunctionReturn(0);
851 }
852 
853 #undef __FUNC__
854 #define __FUNC__ "MatSNESMFFormJacobian"
855 int MatSNESMFFormJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
856 {
857   int ierr;
858   PetscFunctionBegin;
859   ierr = MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
860   ierr = MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
861   PetscFunctionReturn(0);
862 }
863 
864 #undef __FUNC__
865 #define __FUNC__ "MatSNESMFSetBase"
866 int MatSNESMFSetBase(Mat J,Vec U)
867 {
868   int          ierr;
869   MatSNESMFCtx ctx;
870 
871   PetscFunctionBegin;
872   PetscValidHeaderSpecific(J,MAT_COOKIE);
873   PetscValidHeaderSpecific(U,VEC_COOKIE);
874 
875   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
876   ctx->current_u = U;
877   ctx->usesnes   = PETSC_FALSE;
878   PetscFunctionReturn(0);
879 }
880