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