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