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