xref: /petsc/src/snes/mf/snesmfj.c (revision 50f98bb9ea1b583aea06e8eecc10af09f55ac3a8)
1 /*$Id: snesmfj.c,v 1.123 2001/06/21 21:18:42 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 __FUNCT__
10 #define __FUNCT__ "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,(void (**)(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    int MatSNESMFRegisterDynamic(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    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 __FUNCT__
105 #define __FUNCT__ "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,(void (*)())function);CHKERRQ(ierr);
114   PetscFunctionReturn(0);
115 }
116 
117 
118 #undef __FUNCT__
119 #define __FUNCT__ "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 __FUNCT__
147 #define __FUNCT__ "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 __FUNCT__
163 #define __FUNCT__ "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 __FUNCT__
195 #define __FUNCT__ "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 #undef __FUNCT__
223 #define __FUNCT__ "MatSNESMFMult_Private"
224 /*
225   MatSNESMFMult_Private - Default matrix-free form for Jacobian-vector
226   product, y = F'(u)*a:
227 
228         y ~= (F(u + ha) - F(u))/h,
229   where F = nonlinear function, as set by SNESSetFunction()
230         u = current iterate
231         h = difference interval
232 */
233 int MatSNESMFMult_Private(Mat mat,Vec a,Vec y)
234 {
235   MatSNESMFCtx ctx;
236   SNES         snes;
237   Scalar       h,mone = -1.0;
238   Vec          w,U,F;
239   int          ierr,(*eval_fct)(SNES,Vec,Vec)=0;
240 
241   PetscFunctionBegin;
242   /* We log matrix-free matrix-vector products separately, so that we can
243      separate the performance monitoring from the cases that use conventional
244      storage.  We may eventually modify event logging to associate events
245      with particular objects, hence alleviating the more general problem. */
246   ierr = PetscLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);CHKERRQ(ierr);
247 
248   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
249   snes = ctx->snes;
250   w    = ctx->w;
251   U    = ctx->current_u;
252 
253   /*
254       Compute differencing parameter
255   */
256   if (!ctx->ops->compute) {
257     ierr = MatSNESMFSetType(mat,MATSNESMF_DEFAULT);CHKERRQ(ierr);
258     ierr = MatSNESMFSetFromOptions(mat);CHKERRQ(ierr);
259   }
260   ierr = (*ctx->ops->compute)(ctx,U,a,&h);CHKERRQ(ierr);
261 
262   /* keep a record of the current differencing parameter h */
263   ctx->currenth = h;
264 #if defined(PETSC_USE_COMPLEX)
265   PetscLogInfo(mat,"MatSNESMFMult_Private:Current differencing parameter: %g + %g i\n",PetscRealPart(h),PetscImaginaryPart(h));
266 #else
267   PetscLogInfo(mat,"MatSNESMFMult_Private:Current differencing parameter: %15.12e\n",h);
268 #endif
269   if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
270     ctx->historyh[ctx->ncurrenth] = h;
271   }
272   ctx->ncurrenth++;
273 
274   /* w = u + ha */
275   ierr = VecWAXPY(&h,a,U,w);CHKERRQ(ierr);
276 
277   if (ctx->usesnes) {
278     if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
279       eval_fct = SNESComputeFunction;
280     } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
281       eval_fct = SNESComputeGradient;
282     } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid method class");
283     F    = ctx->current_f;
284     if (!F) SETERRQ(1,"You must call MatAssembly() even on matrix-free matrices");
285     ierr = (*eval_fct)(snes,w,y);CHKERRQ(ierr);
286   } else {
287     F = ctx->funcvec;
288     /* compute func(U) as base for differencing */
289     if (ctx->ncurrenth == 1) {
290       ierr = (*ctx->func)(snes,U,F,ctx->funcctx);CHKERRQ(ierr);
291     }
292     ierr = (*ctx->func)(snes,w,y,ctx->funcctx);CHKERRQ(ierr);
293   }
294 
295   ierr = VecAXPY(&mone,F,y);CHKERRQ(ierr);
296   h    = 1.0/h;
297   ierr = VecScale(&h,y);CHKERRQ(ierr);
298   if (ctx->sp) {ierr = MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);CHKERRQ(ierr);}
299 
300   ierr = PetscLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);CHKERRQ(ierr);
301   PetscFunctionReturn(0);
302 }
303 
304 #undef __FUNCT__
305 #define __FUNCT__ "MatSNESMFGetDiagonal_Private"
306 /*
307   MatSNESMFGetDiagonal_Private - Gets the diagonal for a matrix free matrix
308 
309         y ~= (F(u + ha) - F(u))/h,
310   where F = nonlinear function, as set by SNESSetFunction()
311         u = current iterate
312         h = difference interval
313 */
314 int MatSNESMFGetDiagonal_Private(Mat mat,Vec a)
315 {
316   MatSNESMFCtx ctx;
317   Scalar       h,h1,mone = -1.0,*aa,*ww,v,epsilon = 1.e-8,umin = 1.e-6;
318   Vec          w,U,F;
319   int          i,ierr,rstart,rend;
320 
321   PetscFunctionBegin;
322   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
323   if (!ctx->funci) {
324     SETERRQ(1,"Requirers calling MatSNESMFSetFunctioni() first");
325   }
326 
327   w    = ctx->w;
328   U    = ctx->current_u;
329   ierr = (*ctx->func)(0,U,a,ctx->funcctx);CHKERRQ(ierr);
330   ierr = (*ctx->funcisetbase)(U,ctx->funcctx);CHKERRQ(ierr);
331   ierr = VecCopy(U,w);CHKERRQ(ierr);
332 
333   ierr = VecGetOwnershipRange(a,&rstart,&rend);CHKERRQ(ierr);
334   ierr = VecGetArray(a,&aa);CHKERRQ(ierr);
335   for (i=rstart; i<rend; i++) {
336     ierr = VecGetArray(w,&ww);CHKERRQ(ierr);
337     h  = ww[i-rstart];
338     if (h == 0.0) h = 1.0;
339 #if !defined(PETSC_USE_COMPLEX)
340     if (h < umin && h >= 0.0)      h = umin;
341     else if (h < 0.0 && h > -umin) h = -umin;
342 #else
343     if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0)     h = umin;
344     else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
345 #endif
346     h     *= epsilon;
347 
348     ww[i-rstart] += h;
349     ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr);
350     ierr          = (*ctx->funci)(i,w,&v,ctx->funcctx);CHKERRQ(ierr);
351     aa[i-rstart]  = (v - aa[i-rstart])/h;
352     ierr = VecGetArray(w,&ww);CHKERRQ(ierr);
353     ww[i-rstart] -= h;
354     ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr);
355   }
356   ierr = VecRestoreArray(a,&aa);CHKERRQ(ierr);
357   PetscFunctionReturn(0);
358 }
359 
360 #undef __FUNCT__
361 #define __FUNCT__ "MatCreateSNESMF"
362 /*@C
363    MatCreateSNESMF - Creates a matrix-free matrix context for use with
364    a SNES solver.  This matrix can be used as the Jacobian argument for
365    the routine SNESSetJacobian().
366 
367    Collective on SNES and Vec
368 
369    Input Parameters:
370 +  snes - the SNES context
371 -  x - vector where SNES solution is to be stored.
372 
373    Output Parameter:
374 .  J - the matrix-free matrix
375 
376    Level: advanced
377 
378    Notes:
379    The matrix-free matrix context merely contains the function pointers
380    and work space for performing finite difference approximations of
381    Jacobian-vector products, F'(u)*a,
382 
383    The default code uses the following approach to compute h
384 
385 .vb
386      F'(u)*a = [F(u+h*a) - F(u)]/h where
387      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
388        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
389  where
390      error_rel = square root of relative error in function evaluation
391      umin = minimum iterate parameter
392 .ve
393 
394    The user can set the error_rel via MatSNESMFSetFunctionError() and
395    umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
396    of the users manual for details.
397 
398    The user should call MatDestroy() when finished with the matrix-free
399    matrix context.
400 
401    Options Database Keys:
402 +  -snes_mf_err <error_rel> - Sets error_rel
403 .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
404 -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
405 
406 .keywords: SNES, default, matrix-free, create, matrix
407 
408 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
409           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(),
410           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian()
411 
412 @*/
413 int MatCreateSNESMF(SNES snes,Vec x,Mat *J)
414 {
415   MatSNESMFCtx mfctx;
416   int          ierr;
417 
418   PetscFunctionBegin;
419   ierr = MatCreateMF(x,J);CHKERRQ(ierr);
420   ierr = MatShellGetContext(*J,(void **)&mfctx);CHKERRQ(ierr);
421   mfctx->snes    = snes;
422   mfctx->usesnes = PETSC_TRUE;
423   PetscLogObjectParent(snes,*J);
424   PetscFunctionReturn(0);
425 }
426 
427 EXTERN_C_BEGIN
428 #undef __FUNCT__
429 #define __FUNCT__ "MatSNESMFSetBase_FD"
430 int MatSNESMFSetBase_FD(Mat J,Vec U)
431 {
432   int          ierr;
433   MatSNESMFCtx ctx;
434 
435   PetscFunctionBegin;
436   ierr = MatSNESMFResetHHistory(J);CHKERRQ(ierr);
437   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
438   ctx->current_u = U;
439   ctx->usesnes   = PETSC_FALSE;
440   PetscFunctionReturn(0);
441 }
442 EXTERN_C_END
443 
444 #undef __FUNCT__
445 #define __FUNCT__ "MatCreateMF"
446 /*@C
447    MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF()
448 
449    Collective on Vec
450 
451    Input Parameters:
452 .  x - vector that defines layout of the vectors and matrices
453 
454    Output Parameter:
455 .  J - the matrix-free matrix
456 
457    Level: advanced
458 
459    Notes:
460    The matrix-free matrix context merely contains the function pointers
461    and work space for performing finite difference approximations of
462    Jacobian-vector products, F'(u)*a,
463 
464    The default code uses the following approach to compute h
465 
466 .vb
467      F'(u)*a = [F(u+h*a) - F(u)]/h where
468      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
469        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
470  where
471      error_rel = square root of relative error in function evaluation
472      umin = minimum iterate parameter
473 .ve
474 
475    The user can set the error_rel via MatSNESMFSetFunctionError() and
476    umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
477    of the users manual for details.
478 
479    The user should call MatDestroy() when finished with the matrix-free
480    matrix context.
481 
482    Options Database Keys:
483 +  -snes_mf_err <error_rel> - Sets error_rel
484 .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
485 -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
486 
487 .keywords: default, matrix-free, create, matrix
488 
489 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
490           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(),
491           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian()
492 
493 @*/
494 int MatCreateMF(Vec x,Mat *J)
495 {
496   MPI_Comm     comm;
497   MatSNESMFCtx mfctx;
498   int          n,nloc,ierr;
499 
500   PetscFunctionBegin;
501   ierr = PetscObjectGetComm((PetscObject)x,&comm);CHKERRQ(ierr);
502   PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",comm,MatSNESMFDestroy_Private,MatSNESMFView_Private);
503   PetscLogObjectCreate(mfctx);
504   mfctx->sp              = 0;
505   mfctx->snes            = 0;
506   mfctx->error_rel       = 1.e-8; /* assumes PetscReal precision */
507   mfctx->recomputeperiod = 1;
508   mfctx->count           = 0;
509   mfctx->currenth        = 0.0;
510   mfctx->historyh        = PETSC_NULL;
511   mfctx->ncurrenth       = 0;
512   mfctx->maxcurrenth     = 0;
513   mfctx->type_name       = 0;
514   mfctx->usesnes         = PETSC_FALSE;
515 
516   /*
517      Create the empty data structure to contain compute-h routines.
518      These will be filled in below from the command line options or
519      a later call with MatSNESMFSetType() or if that is not called
520      then it will default in the first use of MatSNESMFMult_private()
521   */
522   mfctx->ops->compute        = 0;
523   mfctx->ops->destroy        = 0;
524   mfctx->ops->view           = 0;
525   mfctx->ops->setfromoptions = 0;
526   mfctx->hctx                = 0;
527 
528   mfctx->func                = 0;
529   mfctx->funcctx             = 0;
530   mfctx->funcvec             = 0;
531 
532   ierr = VecDuplicate(x,&mfctx->w);CHKERRQ(ierr);
533   ierr = VecGetSize(mfctx->w,&n);CHKERRQ(ierr);
534   ierr = VecGetLocalSize(mfctx->w,&nloc);CHKERRQ(ierr);
535   ierr = MatCreateShell(comm,nloc,nloc,n,n,mfctx,J);CHKERRQ(ierr);
536   ierr = MatShellSetOperation(*J,MATOP_MULT,(void(*)())MatSNESMFMult_Private);CHKERRQ(ierr);
537   ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void(*)())MatSNESMFDestroy_Private);CHKERRQ(ierr);
538   ierr = MatShellSetOperation(*J,MATOP_VIEW,(void(*)())MatSNESMFView_Private);CHKERRQ(ierr);
539   ierr = MatShellSetOperation(*J,MATOP_ASSEMBLY_END,(void(*)())MatSNESMFAssemblyEnd_Private);CHKERRQ(ierr);
540   ierr = MatShellSetOperation(*J,MATOP_GET_DIAGONAL,(void(*)())MatSNESMFGetDiagonal_Private);CHKERRQ(ierr);
541   ierr = PetscObjectComposeFunctionDynamic((PetscObject)*J,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);CHKERRQ(ierr);
542   PetscLogObjectParent(*J,mfctx->w);
543 
544   mfctx->mat = *J;
545   PetscFunctionReturn(0);
546 }
547 
548 #undef __FUNCT__
549 #define __FUNCT__ "MatSNESMFSetFromOptions"
550 /*@
551    MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
552    parameter.
553 
554    Collective on Mat
555 
556    Input Parameters:
557 .  mat - the matrix obtained with MatCreateSNESMF()
558 
559    Options Database Keys:
560 +  -snes_mf_type - <default,wp>
561 -  -snes_mf_err - square root of estimated relative error in function evaluation
562 -  -snes_mf_period - how often h is recomputed, defaults to 1, everytime
563 
564    Level: advanced
565 
566 .keywords: SNES, matrix-free, parameters
567 
568 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
569           MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
570 @*/
571 int MatSNESMFSetFromOptions(Mat mat)
572 {
573   MatSNESMFCtx mfctx;
574   int          ierr;
575   PetscTruth   flg;
576   char         ftype[256];
577 
578   PetscFunctionBegin;
579   ierr = MatShellGetContext(mat,(void **)&mfctx);CHKERRQ(ierr);
580   if (mfctx) {
581     if (!MatSNESMFRegisterAllCalled) {ierr = MatSNESMFRegisterAll(PETSC_NULL);CHKERRQ(ierr);}
582 
583     ierr = PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");CHKERRQ(ierr);
584       ierr = PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);CHKERRQ(ierr);
585       if (flg) {
586         ierr = MatSNESMFSetType(mat,ftype);CHKERRQ(ierr);
587       }
588 
589       ierr = PetscOptionsDouble("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);CHKERRQ(ierr);
590       ierr = PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);CHKERRQ(ierr);
591       if (mfctx->snes) {
592         ierr = PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);CHKERRQ(ierr);
593         if (flg) {
594           SLES sles;
595           KSP  ksp;
596           ierr = SNESGetSLES(mfctx->snes,&sles);CHKERRQ(ierr);
597           ierr = SLESGetKSP(sles,&ksp);CHKERRQ(ierr);
598           ierr = KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);CHKERRQ(ierr);
599         }
600       }
601       if (mfctx->ops->setfromoptions) {
602         ierr = (*mfctx->ops->setfromoptions)(mfctx);CHKERRQ(ierr);
603       }
604     ierr = PetscOptionsEnd();CHKERRQ(ierr);
605 
606   }
607   PetscFunctionReturn(0);
608 }
609 
610 #undef __FUNCT__
611 #define __FUNCT__ "MatSNESMFGetH"
612 /*@
613    MatSNESMFGetH - Gets the last value that was used as the differencing
614    parameter.
615 
616    Not Collective
617 
618    Input Parameters:
619 .  mat - the matrix obtained with MatCreateSNESMF()
620 
621    Output Paramter:
622 .  h - the differencing step size
623 
624    Level: advanced
625 
626 .keywords: SNES, matrix-free, parameters
627 
628 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
629           MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
630 @*/
631 int MatSNESMFGetH(Mat mat,Scalar *h)
632 {
633   MatSNESMFCtx ctx;
634   int          ierr;
635 
636   PetscFunctionBegin;
637   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
638   if (ctx) {
639     *h = ctx->currenth;
640   }
641   PetscFunctionReturn(0);
642 }
643 
644 #undef __FUNCT__
645 #define __FUNCT__ "MatSNESMFKSPMonitor"
646 /*
647    MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc
648    SNES matrix free routines. Prints the differencing parameter used at
649    each step.
650 */
651 int MatSNESMFKSPMonitor(KSP ksp,int n,PetscReal rnorm,void *dummy)
652 {
653   PC             pc;
654   MatSNESMFCtx   ctx;
655   int            ierr;
656   Mat            mat;
657   MPI_Comm       comm;
658   PetscTruth     nonzeroinitialguess;
659 
660   PetscFunctionBegin;
661   ierr = PetscObjectGetComm((PetscObject)ksp,&comm);CHKERRQ(ierr);
662   ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
663   ierr = KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);CHKERRQ(ierr);
664   ierr = PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
665   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
666   if (!ctx) {
667     SETERRQ(1,"Matrix is not a matrix free shell matrix");
668   }
669   if (n > 0 || nonzeroinitialguess) {
670 #if defined(PETSC_USE_COMPLEX)
671     ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g i\n",n,rnorm,
672                 PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));CHKERRQ(ierr);
673 #else
674     ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);CHKERRQ(ierr);
675 #endif
676   } else {
677     ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e\n",n,rnorm);CHKERRQ(ierr);
678   }
679   PetscFunctionReturn(0);
680 }
681 
682 #undef __FUNCT__
683 #define __FUNCT__ "MatSNESMFSetFunction"
684 /*@C
685    MatSNESMFSetFunction - Sets the function used in applying the matrix free.
686 
687    Collective on Mat
688 
689    Input Parameters:
690 +  mat - the matrix free matrix created via MatCreateSNESMF()
691 .  v   - workspace vector
692 .  func - the function to use
693 -  funcctx - optional function context passed to function
694 
695    Level: advanced
696 
697    Notes:
698     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
699     matrix inside your compute Jacobian routine
700 
701     If this is not set then it will use the function set with SNESSetFunction()
702 
703 .keywords: SNES, matrix-free, function
704 
705 .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
706           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
707           MatSNESMFKSPMonitor(), SNESetFunction()
708 @*/
709 int MatSNESMFSetFunction(Mat mat,Vec v,int (*func)(SNES,Vec,Vec,void *),void *funcctx)
710 {
711   MatSNESMFCtx ctx;
712   int          ierr;
713 
714   PetscFunctionBegin;
715   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
716   if (ctx) {
717     ctx->func    = func;
718     ctx->funcctx = funcctx;
719     ctx->funcvec = v;
720   }
721   PetscFunctionReturn(0);
722 }
723 
724 #undef __FUNCT__
725 #define __FUNCT__ "MatSNESMFSetFunctioni"
726 /*@C
727    MatSNESMFSetFunctioni - Sets the function for a single component
728 
729    Collective on Mat
730 
731    Input Parameters:
732 +  mat - the matrix free matrix created via MatCreateSNESMF()
733 -  funci - the function to use
734 
735    Level: advanced
736 
737    Notes:
738     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
739     matrix inside your compute Jacobian routine
740 
741 
742 .keywords: SNES, matrix-free, function
743 
744 .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
745           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
746           MatSNESMFKSPMonitor(), SNESetFunction()
747 @*/
748 int MatSNESMFSetFunctioni(Mat mat,int (*funci)(int,Vec,Scalar*,void *))
749 {
750   MatSNESMFCtx ctx;
751   int          ierr;
752 
753   PetscFunctionBegin;
754   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
755   if (ctx) {
756     ctx->funci   = funci;
757   }
758   PetscFunctionReturn(0);
759 }
760 
761 #undef __FUNCT__
762 #define __FUNCT__ "MatSNESMFSetFunctioniBase"
763 /*@C
764    MatSNESMFSetFunctioniBase - Sets the base vector for a single component function evaluation
765 
766    Collective on Mat
767 
768    Input Parameters:
769 +  mat - the matrix free matrix created via MatCreateSNESMF()
770 -  func - the function to use
771 
772    Level: advanced
773 
774    Notes:
775     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
776     matrix inside your compute Jacobian routine
777 
778 
779 .keywords: SNES, matrix-free, function
780 
781 .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
782           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
783           MatSNESMFKSPMonitor(), SNESetFunction()
784 @*/
785 int MatSNESMFSetFunctioniBase(Mat mat,int (*func)(Vec,void *))
786 {
787   MatSNESMFCtx ctx;
788   int          ierr;
789 
790   PetscFunctionBegin;
791   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
792   if (ctx) {
793     ctx->funcisetbase   = func;
794   }
795   PetscFunctionReturn(0);
796 }
797 
798 
799 #undef __FUNCT__
800 #define __FUNCT__ "MatSNESMFSetPeriod"
801 /*@
802    MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime
803 
804    Collective on Mat
805 
806    Input Parameters:
807 +  mat - the matrix free matrix created via MatCreateSNESMF()
808 -  period - 1 for everytime, 2 for every second etc
809 
810    Options Database Keys:
811 +  -snes_mf_period <period>
812 
813    Level: advanced
814 
815 
816 .keywords: SNES, matrix-free, parameters
817 
818 .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
819           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
820           MatSNESMFKSPMonitor()
821 @*/
822 int MatSNESMFSetPeriod(Mat mat,int period)
823 {
824   MatSNESMFCtx ctx;
825   int          ierr;
826 
827   PetscFunctionBegin;
828   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
829   if (ctx) {
830     ctx->recomputeperiod = period;
831   }
832   PetscFunctionReturn(0);
833 }
834 
835 #undef __FUNCT__
836 #define __FUNCT__ "MatSNESMFSetFunctionError"
837 /*@
838    MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
839    matrix-vector products using finite differences.
840 
841    Collective on Mat
842 
843    Input Parameters:
844 +  mat - the matrix free matrix created via MatCreateSNESMF()
845 -  error_rel - relative error (should be set to the square root of
846                the relative error in the function evaluations)
847 
848    Options Database Keys:
849 +  -snes_mf_err <error_rel> - Sets error_rel
850 
851    Level: advanced
852 
853    Notes:
854    The default matrix-free matrix-vector product routine computes
855 .vb
856      F'(u)*a = [F(u+h*a) - F(u)]/h where
857      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
858        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
859 .ve
860 
861 .keywords: SNES, matrix-free, parameters
862 
863 .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
864           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
865           MatSNESMFKSPMonitor()
866 @*/
867 int MatSNESMFSetFunctionError(Mat mat,PetscReal error)
868 {
869   MatSNESMFCtx ctx;
870   int          ierr;
871 
872   PetscFunctionBegin;
873   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
874   if (ctx) {
875     if (error != PETSC_DEFAULT) ctx->error_rel = error;
876   }
877   PetscFunctionReturn(0);
878 }
879 
880 #undef __FUNCT__
881 #define __FUNCT__ "MatSNESMFAddNullSpace"
882 /*@
883    MatSNESMFAddNullSpace - Provides a null space that an operator is
884    supposed to have.  Since roundoff will create a small component in
885    the null space, if you know the null space you may have it
886    automatically removed.
887 
888    Collective on Mat
889 
890    Input Parameters:
891 +  J - the matrix-free matrix context
892 -  nullsp - object created with MatNullSpaceCreate()
893 
894    Level: advanced
895 
896 .keywords: SNES, matrix-free, null space
897 
898 .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
899           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
900           MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
901 @*/
902 int MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp)
903 {
904   int          ierr;
905   MatSNESMFCtx ctx;
906   MPI_Comm     comm;
907 
908   PetscFunctionBegin;
909   ierr = PetscObjectGetComm((PetscObject)J,&comm);CHKERRQ(ierr);
910 
911   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
912   /* no context indicates that it is not the "matrix free" matrix type */
913   if (!ctx) PetscFunctionReturn(0);
914   ctx->sp = nullsp;
915   ierr = PetscObjectReference((PetscObject)nullsp);CHKERRQ(ierr);
916   PetscFunctionReturn(0);
917 }
918 
919 #undef __FUNCT__
920 #define __FUNCT__ "MatSNESMFSetHHistory"
921 /*@
922    MatSNESMFSetHHistory - Sets an array to collect a history of the
923    differencing values (h) computed for the matrix-free product.
924 
925    Collective on Mat
926 
927    Input Parameters:
928 +  J - the matrix-free matrix context
929 .  histroy - space to hold the history
930 -  nhistory - number of entries in history, if more entries are generated than
931               nhistory, then the later ones are discarded
932 
933    Level: advanced
934 
935    Notes:
936    Use MatSNESMFResetHHistory() to reset the history counter and collect
937    a new batch of differencing parameters, h.
938 
939 .keywords: SNES, matrix-free, h history, differencing history
940 
941 .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
942           MatSNESMFResetHHistory(),
943           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
944 
945 @*/
946 int MatSNESMFSetHHistory(Mat J,Scalar *history,int nhistory)
947 {
948   int          ierr;
949   MatSNESMFCtx ctx;
950 
951   PetscFunctionBegin;
952 
953   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
954   /* no context indicates that it is not the "matrix free" matrix type */
955   if (!ctx) PetscFunctionReturn(0);
956   ctx->historyh    = history;
957   ctx->maxcurrenth = nhistory;
958   ctx->currenth    = 0;
959 
960   PetscFunctionReturn(0);
961 }
962 
963 #undef __FUNCT__
964 #define __FUNCT__ "MatSNESMFResetHHistory"
965 /*@
966    MatSNESMFResetHHistory - Resets the counter to zero to begin
967    collecting a new set of differencing histories.
968 
969    Collective on Mat
970 
971    Input Parameters:
972 .  J - the matrix-free matrix context
973 
974    Level: advanced
975 
976    Notes:
977    Use MatSNESMFSetHHistory() to create the original history counter.
978 
979 .keywords: SNES, matrix-free, h history, differencing history
980 
981 .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
982           MatSNESMFSetHHistory(),
983           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
984 
985 @*/
986 int MatSNESMFResetHHistory(Mat J)
987 {
988   int          ierr;
989   MatSNESMFCtx ctx;
990 
991   PetscFunctionBegin;
992 
993   ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr);
994   /* no context indicates that it is not the "matrix free" matrix type */
995   if (!ctx) PetscFunctionReturn(0);
996   ctx->ncurrenth    = 0;
997 
998   PetscFunctionReturn(0);
999 }
1000 
1001 #undef __FUNCT__
1002 #define __FUNCT__ "MatSNESMFComputeJacobian"
1003 int MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
1004 {
1005   int ierr;
1006   PetscFunctionBegin;
1007   ierr = MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1008   ierr = MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1009   PetscFunctionReturn(0);
1010 }
1011 
1012 #undef __FUNCT__
1013 #define __FUNCT__ "MatSNESMFSetBase"
1014 int MatSNESMFSetBase(Mat J,Vec U)
1015 {
1016   int  ierr,(*f)(Mat,Vec);
1017 
1018   PetscFunctionBegin;
1019   PetscValidHeaderSpecific(J,MAT_COOKIE);
1020   PetscValidHeaderSpecific(U,VEC_COOKIE);
1021   ierr = PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)())&f);CHKERRQ(ierr);
1022   if (f) {
1023     ierr = (*f)(J,U);CHKERRQ(ierr);
1024   }
1025   PetscFunctionReturn(0);
1026 }
1027 
1028 
1029 
1030 
1031 
1032 
1033 
1034 
1035 
1036