xref: /petsc/src/mat/impls/mffd/mffd.c (revision 52121784a72a1e1fc563920ccd75f23008cac2bf)
1 #define PETSCMAT_DLL
2 
3 #include "include/private/matimpl.h"
4 #include "src/mat/impls/mffd/mffdimpl.h"   /*I  "petscmat.h"   I*/
5 
6 PetscFList MatMFFDPetscFList        = 0;
7 PetscTruth MatMFFDRegisterAllCalled = PETSC_FALSE;
8 
9 PetscCookie PETSCMAT_DLLEXPORT MATMFFD_COOKIE = 0;
10 PetscEvent  MATMFFD_Mult = 0;
11 
12 #undef __FUNCT__
13 #define __FUNCT__ "MatMFFDInitializePackage"
14 /*@C
15   MatMFFDInitializePackage - This function initializes everything in the MatMFFD package. It is called
16   from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to MatCreate_MFFD()
17   when using static libraries.
18 
19   Input Parameter:
20 . path - The dynamic library path, or PETSC_NULL
21 
22   Level: developer
23 
24 .keywords: Vec, initialize, package
25 .seealso: PetscInitialize()
26 @*/
27 PetscErrorCode PETSCVEC_DLLEXPORT MatMFFDInitializePackage(const char path[])
28 {
29   static PetscTruth initialized = PETSC_FALSE;
30   char              logList[256];
31   char              *className;
32   PetscTruth        opt;
33   PetscErrorCode    ierr;
34 
35   PetscFunctionBegin;
36   if (initialized) PetscFunctionReturn(0);
37   initialized = PETSC_TRUE;
38   /* Register Classes */
39   ierr = PetscLogClassRegister(&MATMFFD_COOKIE,     "MatMFFD");CHKERRQ(ierr);
40   /* Register Constructors */
41   ierr = MatMFFDRegisterAll(path);CHKERRQ(ierr);
42   /* Register Events */
43   ierr = PetscLogEventRegister(&MATMFFD_Mult, "MatMult MF",          MATMFFD_COOKIE);CHKERRQ(ierr);
44 
45   /* Process info exclusions */
46   ierr = PetscOptionsGetString(PETSC_NULL, "-info_exclude", logList, 256, &opt);CHKERRQ(ierr);
47   if (opt) {
48     ierr = PetscStrstr(logList, "matmffd", &className);CHKERRQ(ierr);
49     if (className) {
50       ierr = PetscInfoDeactivateClass(MATMFFD_COOKIE);CHKERRQ(ierr);
51     }
52   }
53   /* Process summary exclusions */
54   ierr = PetscOptionsGetString(PETSC_NULL, "-log_summary_exclude", logList, 256, &opt);CHKERRQ(ierr);
55   if (opt) {
56     ierr = PetscStrstr(logList, "matmffd", &className);CHKERRQ(ierr);
57     if (className) {
58       ierr = PetscLogEventDeactivateClass(MATMFFD_COOKIE);CHKERRQ(ierr);
59     }
60   }
61   PetscFunctionReturn(0);
62 }
63 
64 #undef __FUNCT__
65 #define __FUNCT__ "MatMFFDSetType"
66 /*@C
67     MatMFFDSetType - Sets the method that is used to compute the
68     differencing parameter for finite differene matrix-free formulations.
69 
70     Input Parameters:
71 +   mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMFFD()
72           or MatSetType(mat,MATMFFD);
73 -   ftype - the type requested, either MATMFFD_WP or MATMFFD_DS
74 
75     Level: advanced
76 
77     Notes:
78     For example, such routines can compute h for use in
79     Jacobian-vector products of the form
80 
81                         F(x+ha) - F(x)
82           F'(u)a  ~=  ----------------
83                               h
84 
85 .seealso: MatCreateSNESMF(), MatMFFDRegisterDynamic)
86 @*/
87 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetType(Mat mat,MatMFFDType ftype)
88 {
89   PetscErrorCode ierr,(*r)(MatMFFD);
90   MatMFFD        ctx = (MatMFFD)mat->data;
91   PetscTruth     match;
92 
93   PetscFunctionBegin;
94   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
95   PetscValidCharPointer(ftype,2);
96 
97   /* already set, so just return */
98   ierr = PetscTypeCompare((PetscObject)ctx,ftype,&match);CHKERRQ(ierr);
99   if (match) PetscFunctionReturn(0);
100 
101   /* destroy the old one if it exists */
102   if (ctx->ops->destroy) {
103     ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);
104   }
105 
106   ierr =  PetscFListFind(ctx->comm,MatMFFDPetscFList,ftype,(void (**)(void)) &r);CHKERRQ(ierr);
107   if (!r) SETERRQ1(PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown MatMFFD type %s given",ftype);
108   ierr = (*r)(ctx);CHKERRQ(ierr);
109   ierr = PetscObjectChangeTypeName((PetscObject)ctx,ftype);CHKERRQ(ierr);
110   PetscFunctionReturn(0);
111 }
112 
113 typedef PetscErrorCode (*FCN1)(void*,Vec); /* force argument to next function to not be extern C*/
114 EXTERN_C_BEGIN
115 #undef __FUNCT__
116 #define __FUNCT__ "MatMFFDSetFunctioniBase_FD"
117 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetFunctioniBase_FD(Mat mat,FCN1 func)
118 {
119   MatMFFD ctx = (MatMFFD)mat->data;
120 
121   PetscFunctionBegin;
122   ctx->funcisetbase = func;
123   PetscFunctionReturn(0);
124 }
125 EXTERN_C_END
126 
127 typedef PetscErrorCode (*FCN2)(void*,PetscInt,Vec,PetscScalar*); /* force argument to next function to not be extern C*/
128 EXTERN_C_BEGIN
129 #undef __FUNCT__
130 #define __FUNCT__ "MatMFFDSetFunctioni_FD"
131 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetFunctioni_FD(Mat mat,FCN2 funci)
132 {
133   MatMFFD ctx = (MatMFFD)mat->data;
134 
135   PetscFunctionBegin;
136   ctx->funci = funci;
137   PetscFunctionReturn(0);
138 }
139 EXTERN_C_END
140 
141 
142 #undef __FUNCT__
143 #define __FUNCT__ "MatMFFDRegister"
144 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(MatMFFD))
145 {
146   PetscErrorCode ierr;
147   char           fullname[PETSC_MAX_PATH_LEN];
148 
149   PetscFunctionBegin;
150   ierr = PetscFListConcat(path,name,fullname);CHKERRQ(ierr);
151   ierr = PetscFListAdd(&MatMFFDPetscFList,sname,fullname,(void (*)(void))function);CHKERRQ(ierr);
152   PetscFunctionReturn(0);
153 }
154 
155 
156 #undef __FUNCT__
157 #define __FUNCT__ "MatMFFDRegisterDestroy"
158 /*@C
159    MatMFFDRegisterDestroy - Frees the list of MatMFFD methods that were
160    registered by MatMFFDRegisterDynamic).
161 
162    Not Collective
163 
164    Level: developer
165 
166 .keywords: MatMFFD, register, destroy
167 
168 .seealso: MatMFFDRegisterDynamic), MatMFFDRegisterAll()
169 @*/
170 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDRegisterDestroy(void)
171 {
172   PetscErrorCode ierr;
173 
174   PetscFunctionBegin;
175   ierr = PetscFListDestroy(&MatMFFDPetscFList);CHKERRQ(ierr);
176   MatMFFDRegisterAllCalled = PETSC_FALSE;
177   PetscFunctionReturn(0);
178 }
179 
180 /* ----------------------------------------------------------------------------------------*/
181 #undef __FUNCT__
182 #define __FUNCT__ "MatDestroy_MFFD"
183 PetscErrorCode MatDestroy_MFFD(Mat mat)
184 {
185   PetscErrorCode ierr;
186   MatMFFD        ctx = (MatMFFD)mat->data;
187 
188   PetscFunctionBegin;
189   if (ctx->w) {
190     ierr = VecDestroy(ctx->w);CHKERRQ(ierr);
191   }
192   if (ctx->ops->destroy) {ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);}
193   if (ctx->sp) {ierr = MatNullSpaceDestroy(ctx->sp);CHKERRQ(ierr);}
194   ierr = PetscHeaderDestroy(ctx);CHKERRQ(ierr);
195 
196   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetBase_C","",PETSC_NULL);CHKERRQ(ierr);
197   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C","",PETSC_NULL);CHKERRQ(ierr);
198   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioni_C","",PETSC_NULL);CHKERRQ(ierr);
199   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetCheckh_C","",PETSC_NULL);CHKERRQ(ierr);
200 
201   PetscFunctionReturn(0);
202 }
203 
204 #undef __FUNCT__
205 #define __FUNCT__ "MatView_MFFD"
206 /*
207    MatMFFDView_MFFD - Views matrix-free parameters.
208 
209 */
210 PetscErrorCode MatView_MFFD(Mat J,PetscViewer viewer)
211 {
212   PetscErrorCode ierr;
213   MatMFFD        ctx = (MatMFFD)J->data;
214   PetscTruth     iascii;
215 
216   PetscFunctionBegin;
217   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
218   if (iascii) {
219      ierr = PetscViewerASCIIPrintf(viewer,"  matrix-free approximation:\n");CHKERRQ(ierr);
220      ierr = PetscViewerASCIIPrintf(viewer,"    err=%G (relative error in function evaluation)\n",ctx->error_rel);CHKERRQ(ierr);
221      if (!ctx->type_name) {
222        ierr = PetscViewerASCIIPrintf(viewer,"    The compute h routine has not yet been set\n");CHKERRQ(ierr);
223      } else {
224        ierr = PetscViewerASCIIPrintf(viewer,"    Using %s compute h routine\n",ctx->type_name);CHKERRQ(ierr);
225      }
226      if (ctx->ops->view) {
227        ierr = (*ctx->ops->view)(ctx,viewer);CHKERRQ(ierr);
228      }
229   } else {
230     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for matrix-free matrix",((PetscObject)viewer)->type_name);
231   }
232   PetscFunctionReturn(0);
233 }
234 
235 #undef __FUNCT__
236 #define __FUNCT__ "MatAssemblyEnd_MFFD"
237 /*
238    MatAssemblyEnd_MFFD - Resets the ctx->ncurrenth to zero. This
239    allows the user to indicate the beginning of a new linear solve by calling
240    MatAssemblyXXX() on the matrix free matrix. This then allows the
241    MatMFFDCreate_WP() to properly compute ||U|| only the first time
242    in the linear solver rather than every time.
243 */
244 PetscErrorCode MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
245 {
246   PetscErrorCode ierr;
247   MatMFFD        j = (MatMFFD)J->data;
248 
249   PetscFunctionBegin;
250   ierr      = MatMFFDResetHHistory(J);CHKERRQ(ierr);
251   j->vshift = 0.0;
252   j->vscale = 1.0;
253   PetscFunctionReturn(0);
254 }
255 
256 #undef __FUNCT__
257 #define __FUNCT__ "MatMult_MFFD"
258 /*
259   MatMult_MFFD - Default matrix-free form for Jacobian-vector product, y = F'(u)*a:
260 
261         y ~= (F(u + ha) - F(u))/h,
262   where F = nonlinear function, as set by SNESSetFunction()
263         u = current iterate
264         h = difference interval
265 */
266 PetscErrorCode MatMult_MFFD(Mat mat,Vec a,Vec y)
267 {
268   MatMFFD        ctx = (MatMFFD)mat->data;
269   PetscScalar    h;
270   Vec            w,U,F;
271   PetscErrorCode ierr;
272   PetscTruth     zeroa;
273 
274   PetscFunctionBegin;
275   /* We log matrix-free matrix-vector products separately, so that we can
276      separate the performance monitoring from the cases that use conventional
277      storage.  We may eventually modify event logging to associate events
278      with particular objects, hence alleviating the more general problem. */
279   ierr = PetscLogEventBegin(MATMFFD_Mult,a,y,0,0);CHKERRQ(ierr);
280 
281   w    = ctx->w;
282   U    = ctx->current_u;
283   F    = ctx->current_f;
284   /*
285       Compute differencing parameter
286   */
287   if (!ctx->ops->compute) {
288     ierr = MatMFFDSetType(mat,MATMFFD_WP);CHKERRQ(ierr);
289     ierr = MatMFFDSetFromOptions(mat);CHKERRQ(ierr);
290   }
291   ierr = (*ctx->ops->compute)(ctx,U,a,&h,&zeroa);CHKERRQ(ierr);
292   if (zeroa) {
293     ierr = VecSet(y,0.0);CHKERRQ(ierr);
294     PetscFunctionReturn(0);
295   }
296 
297   if (h != h) SETERRQ(PETSC_ERR_PLIB,"Computed Nan differencing parameter h");
298   if (ctx->checkh) {
299     ierr = (*ctx->checkh)(ctx->checkhctx,U,a,&h);CHKERRQ(ierr);
300   }
301 
302   /* keep a record of the current differencing parameter h */
303   ctx->currenth = h;
304 #if defined(PETSC_USE_COMPLEX)
305   ierr = PetscInfo2(mat,"Current differencing parameter: %G + %G i\n",PetscRealPart(h),PetscImaginaryPart(h));CHKERRQ(ierr);
306 #else
307   ierr = PetscInfo1(mat,"Current differencing parameter: %15.12e\n",h);CHKERRQ(ierr);
308 #endif
309   if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
310     ctx->historyh[ctx->ncurrenth] = h;
311   }
312   ctx->ncurrenth++;
313 
314   /* w = u + ha */
315   ierr = VecWAXPY(w,h,a,U);CHKERRQ(ierr);
316 
317   /* compute func(U) as base for differencing; only needed first time in */
318   if (ctx->ncurrenth == 1) {
319     ierr = (*ctx->func)(ctx->funcctx,U,F);CHKERRQ(ierr);
320   }
321   ierr = (*ctx->func)(ctx->funcctx,w,y);CHKERRQ(ierr);
322 
323   ierr = VecAXPY(y,-1.0,F);CHKERRQ(ierr);
324   ierr = VecScale(y,1.0/h);CHKERRQ(ierr);
325 
326   ierr = VecAXPBY(y,ctx->vshift,ctx->vscale,a);CHKERRQ(ierr);
327 
328   if (ctx->sp) {ierr = MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);CHKERRQ(ierr);}
329 
330   ierr = PetscLogEventEnd(MATMFFD_Mult,a,y,0,0);CHKERRQ(ierr);
331   PetscFunctionReturn(0);
332 }
333 
334 #undef __FUNCT__
335 #define __FUNCT__ "MatGetDiagonal_MFFD"
336 /*
337   MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix
338 
339         y ~= (F(u + ha) - F(u))/h,
340   where F = nonlinear function, as set by SNESSetFunction()
341         u = current iterate
342         h = difference interval
343 */
344 PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a)
345 {
346   MatMFFD        ctx = (MatMFFD)mat->data;
347   PetscScalar    h,*aa,*ww,v;
348   PetscReal      epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
349   Vec            w,U;
350   PetscErrorCode ierr;
351   PetscInt       i,rstart,rend;
352 
353   PetscFunctionBegin;
354   if (!ctx->funci) {
355     SETERRQ(PETSC_ERR_ORDER,"Requires calling MatMFFDSetFunctioni() first");
356   }
357 
358   w    = ctx->w;
359   U    = ctx->current_u;
360   ierr = (*ctx->func)(ctx->funcctx,U,a);CHKERRQ(ierr);
361   ierr = (*ctx->funcisetbase)(ctx->funcctx,U);CHKERRQ(ierr);
362   ierr = VecCopy(U,w);CHKERRQ(ierr);
363 
364   ierr = VecGetOwnershipRange(a,&rstart,&rend);CHKERRQ(ierr);
365   ierr = VecGetArray(a,&aa);CHKERRQ(ierr);
366   for (i=rstart; i<rend; i++) {
367     ierr = VecGetArray(w,&ww);CHKERRQ(ierr);
368     h  = ww[i-rstart];
369     if (h == 0.0) h = 1.0;
370 #if !defined(PETSC_USE_COMPLEX)
371     if (h < umin && h >= 0.0)      h = umin;
372     else if (h < 0.0 && h > -umin) h = -umin;
373 #else
374     if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0)     h = umin;
375     else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
376 #endif
377     h     *= epsilon;
378 
379     ww[i-rstart] += h;
380     ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr);
381     ierr          = (*ctx->funci)(ctx->funcctx,i,w,&v);CHKERRQ(ierr);
382     aa[i-rstart]  = (v - aa[i-rstart])/h;
383 
384     /* possibly shift and scale result */
385     aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart];
386 
387     ierr = VecGetArray(w,&ww);CHKERRQ(ierr);
388     ww[i-rstart] -= h;
389     ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr);
390   }
391   ierr = VecRestoreArray(a,&aa);CHKERRQ(ierr);
392   PetscFunctionReturn(0);
393 }
394 
395 #undef __FUNCT__
396 #define __FUNCT__ "MatShift_MFFD"
397 PetscErrorCode MatShift_MFFD(Mat Y,PetscScalar a)
398 {
399   MatMFFD shell = (MatMFFD)Y->data;
400   PetscFunctionBegin;
401   shell->vshift += a;
402   PetscFunctionReturn(0);
403 }
404 
405 #undef __FUNCT__
406 #define __FUNCT__ "MatScale_MFFD"
407 PetscErrorCode MatScale_MFFD(Mat Y,PetscScalar a)
408 {
409   MatMFFD shell = (MatMFFD)Y->data;
410   PetscFunctionBegin;
411   shell->vscale *= a;
412   PetscFunctionReturn(0);
413 }
414 
415 EXTERN_C_BEGIN
416 #undef __FUNCT__
417 #define __FUNCT__ "MatMFFDSetBase_FD"
418 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetBase_FD(Mat J,Vec U,Vec F)
419 {
420   PetscErrorCode ierr;
421   MatMFFD        ctx = (MatMFFD)J->data;
422 
423   PetscFunctionBegin;
424   ierr = MatMFFDResetHHistory(J);CHKERRQ(ierr);
425   ctx->current_u = U;
426   if (F) {
427     ctx->current_f = F;
428   } else {
429     ierr = VecDuplicate(ctx->current_u, &ctx->current_f);CHKERRQ(ierr);
430   }
431   if (!ctx->w) {
432     ierr = VecDuplicate(ctx->current_u, &ctx->w);CHKERRQ(ierr);
433   }
434   J->assembled = PETSC_TRUE;
435   PetscFunctionReturn(0);
436 }
437 EXTERN_C_END
438 typedef PetscErrorCode (*FCN3)(void*,Vec,Vec,PetscScalar*); /* force argument to next function to not be extern C*/
439 EXTERN_C_BEGIN
440 #undef __FUNCT__
441 #define __FUNCT__ "MatMFFDSetCheckh_FD"
442 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetCheckh_FD(Mat J,FCN3 fun,void*ectx)
443 {
444   MatMFFD ctx = (MatMFFD)J->data;
445 
446   PetscFunctionBegin;
447   ctx->checkh    = fun;
448   ctx->checkhctx = ectx;
449   PetscFunctionReturn(0);
450 }
451 EXTERN_C_END
452 
453 #undef __FUNCT__
454 #define __FUNCT__ "MatMFFDSetFromOptions"
455 /*@
456    MatMFFDSetFromOptions - Sets the MatMFFD options from the command line
457    parameter.
458 
459    Collective on Mat
460 
461    Input Parameters:
462 .  mat - the matrix obtained with MatCreateMFFD() or MatCreateSNESMF()
463 
464    Options Database Keys:
465 +  -mat_mffd_type - wp or ds (see MATMFFD_WP or MATMFFD_DS)
466 -  -mat_mffd_err - square root of estimated relative error in function evaluation
467 -  -mat_mffd_period - how often h is recomputed, defaults to 1, everytime
468 
469    Level: advanced
470 
471 .keywords: SNES, matrix-free, parameters
472 
473 .seealso: MatCreateSNESMF(),MatMFFDSetHHistory(),
474           MatMFFDResetHHistory(), MatMFFDKSPMonitor()
475 @*/
476 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetFromOptions(Mat mat)
477 {
478   MatMFFD        mfctx = (MatMFFD)mat->data;
479   PetscErrorCode ierr;
480   PetscTruth     flg;
481   char           ftype[256];
482 
483   PetscFunctionBegin;
484   ierr = PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatMFFD");CHKERRQ(ierr);
485   ierr = PetscOptionsList("-mat_mffd_type","Matrix free type","MatMFFDSetType",MatMFFDPetscFList,mfctx->type_name,ftype,256,&flg);CHKERRQ(ierr);
486   if (flg) {
487     ierr = MatMFFDSetType(mat,ftype);CHKERRQ(ierr);
488   }
489 
490   ierr = PetscOptionsReal("-mat_mffd_err","set sqrt relative error in function","MatMFFDSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);CHKERRQ(ierr);
491   ierr = PetscOptionsInt("-mat_mffd_period","how often h is recomputed","MatMFFDSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);CHKERRQ(ierr);
492 
493   ierr = PetscOptionsName("-mat_mffd_check_positivity","Insure that U + h*a is nonnegative","MatMFFDSetCheckh",&flg);CHKERRQ(ierr);
494   if (flg) {
495     ierr = MatMFFDSetCheckh(mat,MatMFFDCheckPositivity,0);CHKERRQ(ierr);
496   }
497   if (mfctx->ops->setfromoptions) {
498     ierr = (*mfctx->ops->setfromoptions)(mfctx);CHKERRQ(ierr);
499   }
500   ierr = PetscOptionsEnd();CHKERRQ(ierr);
501   PetscFunctionReturn(0);
502 }
503 
504 /*MC
505   MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.
506 
507   Level: advanced
508 
509 .seealso: MatCreateMFFD(), MatCreateSNESMF()
510 M*/
511 EXTERN_C_BEGIN
512 #undef __FUNCT__
513 #define __FUNCT__ "MatCreate_MFFD"
514 PetscErrorCode PETSCMAT_DLLEXPORT MatCreate_MFFD(Mat A)
515 {
516   MatMFFD         mfctx;
517   PetscErrorCode  ierr;
518 
519   PetscFunctionBegin;
520 #ifndef PETSC_USE_DYNAMIC_LIBRARIES
521   ierr = MatMFFDInitializePackage(PETSC_NULL);CHKERRQ(ierr);
522 #endif
523 
524   ierr = PetscHeaderCreate(mfctx,_p_MatMFFD,struct _MFOps,MATMFFD_COOKIE,0,"MatMFFD",A->comm,MatDestroy_MFFD,MatView_MFFD);CHKERRQ(ierr);
525   mfctx->sp              = 0;
526   mfctx->error_rel       = PETSC_SQRT_MACHINE_EPSILON;
527   mfctx->recomputeperiod = 1;
528   mfctx->count           = 0;
529   mfctx->currenth        = 0.0;
530   mfctx->historyh        = PETSC_NULL;
531   mfctx->ncurrenth       = 0;
532   mfctx->maxcurrenth     = 0;
533   mfctx->type_name       = 0;
534 
535   mfctx->vshift          = 0.0;
536   mfctx->vscale          = 1.0;
537 
538   /*
539      Create the empty data structure to contain compute-h routines.
540      These will be filled in below from the command line options or
541      a later call with MatMFFDSetType() or if that is not called
542      then it will default in the first use of MatMult_MFFD()
543   */
544   mfctx->ops->compute        = 0;
545   mfctx->ops->destroy        = 0;
546   mfctx->ops->view           = 0;
547   mfctx->ops->setfromoptions = 0;
548   mfctx->hctx                = 0;
549 
550   mfctx->func                = 0;
551   mfctx->funcctx             = 0;
552   mfctx->w                   = PETSC_NULL;
553 
554   A->data                = mfctx;
555 
556   A->ops->mult           = MatMult_MFFD;
557   A->ops->destroy        = MatDestroy_MFFD;
558   A->ops->view           = MatView_MFFD;
559   A->ops->assemblyend    = MatAssemblyEnd_MFFD;
560   A->ops->getdiagonal    = MatGetDiagonal_MFFD;
561   A->ops->scale          = MatScale_MFFD;
562   A->ops->shift          = MatShift_MFFD;
563   A->ops->setfromoptions = MatMFFDSetFromOptions;
564   A->assembled = PETSC_TRUE;
565 
566   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetBase_C","MatMFFDSetBase_FD",MatMFFDSetBase_FD);CHKERRQ(ierr);
567   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetFunctioniBase_C","MatMFFDSetFunctioniBase_FD",MatMFFDSetFunctioniBase_FD);CHKERRQ(ierr);
568   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetFunctioni_C","MatMFFDSetFunctioni_FD",MatMFFDSetFunctioni_FD);CHKERRQ(ierr);
569   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatMFFDSetCheckh_C","MatMFFDSetCheckh_FD",MatMFFDSetCheckh_FD);CHKERRQ(ierr);
570   mfctx->mat = A;
571   ierr = PetscObjectChangeTypeName((PetscObject)A,MATMFFD);CHKERRQ(ierr);
572   PetscFunctionReturn(0);
573 }
574 EXTERN_C_END
575 
576 #undef __FUNCT__
577 #define __FUNCT__ "MatCreateMFFD"
578 /*@
579    MatCreateMFFD - Creates a matrix-free matrix. See also MatCreateSNESMF()
580 
581    Collective on Vec
582 
583    Input Parameters:
584 .  x - vector that defines layout of the vectors and matrices
585 
586    Output Parameter:
587 .  J - the matrix-free matrix
588 
589    Level: advanced
590 
591    Notes:
592    The matrix-free matrix context merely contains the function pointers
593    and work space for performing finite difference approximations of
594    Jacobian-vector products, F'(u)*a,
595 
596    The default code uses the following approach to compute h
597 
598 .vb
599      F'(u)*a = [F(u+h*a) - F(u)]/h where
600      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
601        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
602  where
603      error_rel = square root of relative error in function evaluation
604      umin = minimum iterate parameter
605 .ve
606 
607    The user can set the error_rel via MatMFFDSetFunctionError() and
608    umin via MatMFFDDefaultSetUmin(); see the nonlinear solvers chapter
609    of the users manual for details.
610 
611    The user should call MatDestroy() when finished with the matrix-free
612    matrix context.
613 
614    Options Database Keys:
615 +  -mat_mffd_err <error_rel> - Sets error_rel
616 .  -mat_mffd_unim <umin> - Sets umin (for default PETSc routine that computes h only)
617 .  -mat_mffd_ksp_monitor - KSP monitor routine that prints differencing h
618 -  -mat_mffd_check_positivity
619 
620 .keywords: default, matrix-free, create, matrix
621 
622 .seealso: MatDestroy(), MatMFFDSetFunctionError(), MatMFFDDefaultSetUmin(), MatMFFDSetFunction()
623           MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateSNESMF(),
624           MatMFFDGetH(),MatMFFDKSPMonitor(), MatMFFDRegisterDynamic),, MatMFFDComputeJacobian()
625 
626 @*/
627 PetscErrorCode PETSCMAT_DLLEXPORT MatCreateMFFD(Vec x,Mat *J)
628 {
629   MPI_Comm       comm;
630   PetscErrorCode ierr;
631   PetscInt       n,nloc;
632 
633   PetscFunctionBegin;
634   ierr = PetscObjectGetComm((PetscObject)x,&comm);CHKERRQ(ierr);
635   ierr = VecGetSize(x,&n);CHKERRQ(ierr);
636   ierr = VecGetLocalSize(x,&nloc);CHKERRQ(ierr);
637   ierr = MatCreate(comm,J);CHKERRQ(ierr);
638   ierr = MatSetSizes(*J,nloc,nloc,n,n);CHKERRQ(ierr);
639   ierr = MatSetType(*J,MATMFFD);CHKERRQ(ierr);
640   PetscFunctionReturn(0);
641 }
642 
643 
644 #undef __FUNCT__
645 #define __FUNCT__ "MatMFFDGetH"
646 /*@
647    MatMFFDGetH - Gets the last value that was used as the differencing
648    parameter.
649 
650    Not Collective
651 
652    Input Parameters:
653 .  mat - the matrix obtained with MatCreateSNESMF()
654 
655    Output Paramter:
656 .  h - the differencing step size
657 
658    Level: advanced
659 
660 .keywords: SNES, matrix-free, parameters
661 
662 .seealso: MatCreateSNESMF(),MatMFFDSetHHistory(), MatCreateMFFD(), MATMFFD
663           MatMFFDResetHHistory(),MatMFFDKSPMonitor()
664 @*/
665 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDGetH(Mat mat,PetscScalar *h)
666 {
667   MatMFFD ctx = (MatMFFD)mat->data;
668 
669   PetscFunctionBegin;
670   *h = ctx->currenth;
671   PetscFunctionReturn(0);
672 }
673 
674 
675 #undef __FUNCT__
676 #define __FUNCT__ "MatMFFDSetFunction"
677 /*@C
678    MatMFFDSetFunction - Sets the function used in applying the matrix free.
679 
680    Collective on Mat
681 
682    Input Parameters:
683 +  mat - the matrix free matrix created via MatCreateSNESMF()
684 .  func - the function to use
685 -  funcctx - optional function context passed to function
686 
687    Level: advanced
688 
689    Notes:
690     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
691     matrix inside your compute Jacobian routine
692 
693     If this is not set then it will use the function set with SNESSetFunction() if MatCreateSNESMF() was used.
694 
695 .keywords: SNES, matrix-free, function
696 
697 .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
698           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
699           MatMFFDKSPMonitor(), SNESetFunction()
700 @*/
701 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetFunction(Mat mat,PetscErrorCode (*func)(void*,Vec,Vec),void *funcctx)
702 {
703   MatMFFD ctx = (MatMFFD)mat->data;
704 
705   PetscFunctionBegin;
706   ctx->func    = func;
707   ctx->funcctx = funcctx;
708   PetscFunctionReturn(0);
709 }
710 
711 #undef __FUNCT__
712 #define __FUNCT__ "MatMFFDSetFunctioni"
713 /*@C
714    MatMFFDSetFunctioni - Sets the function for a single component
715 
716    Collective on Mat
717 
718    Input Parameters:
719 +  mat - the matrix free matrix created via MatCreateSNESMF()
720 -  funci - the function to use
721 
722    Level: advanced
723 
724    Notes:
725     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
726     matrix inside your compute Jacobian routine
727 
728 
729 .keywords: SNES, matrix-free, function
730 
731 .seealso: MatCreateSNESMF(),MatMFFDGetH(),
732           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
733           MatMFFDKSPMonitor(), SNESetFunction()
734 @*/
735 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetFunctioni(Mat mat,PetscErrorCode (*funci)(void*,PetscInt,Vec,PetscScalar*))
736 {
737   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,PetscInt,Vec,PetscScalar*));
738 
739   PetscFunctionBegin;
740   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
741   ierr = PetscObjectQueryFunction((PetscObject)mat,"MatMFFDSetFunctioni_C",(void (**)(void))&f);CHKERRQ(ierr);
742   if (f) {
743     ierr = (*f)(mat,funci);CHKERRQ(ierr);
744   }
745   PetscFunctionReturn(0);
746 }
747 
748 
749 #undef __FUNCT__
750 #define __FUNCT__ "MatMFFDSetFunctioniBase"
751 /*@C
752    MatMFFDSetFunctioniBase - Sets the base vector for a single component function evaluation
753 
754    Collective on Mat
755 
756    Input Parameters:
757 +  mat - the matrix free matrix created via MatCreateSNESMF()
758 -  func - the function to use
759 
760    Level: advanced
761 
762    Notes:
763     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
764     matrix inside your compute Jacobian routine
765 
766 
767 .keywords: SNES, matrix-free, function
768 
769 .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
770           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
771           MatMFFDKSPMonitor(), SNESetFunction()
772 @*/
773 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetFunctioniBase(Mat mat,PetscErrorCode (*func)(void*,Vec))
774 {
775   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,Vec));
776 
777   PetscFunctionBegin;
778   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
779   ierr = PetscObjectQueryFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C",(void (**)(void))&f);CHKERRQ(ierr);
780   if (f) {
781     ierr = (*f)(mat,func);CHKERRQ(ierr);
782   }
783   PetscFunctionReturn(0);
784 }
785 
786 
787 #undef __FUNCT__
788 #define __FUNCT__ "MatMFFDSetPeriod"
789 /*@
790    MatMFFDSetPeriod - Sets how often h is recomputed, by default it is everytime
791 
792    Collective on Mat
793 
794    Input Parameters:
795 +  mat - the matrix free matrix created via MatCreateSNESMF()
796 -  period - 1 for everytime, 2 for every second etc
797 
798    Options Database Keys:
799 +  -mat_mffd_period <period>
800 
801    Level: advanced
802 
803 
804 .keywords: SNES, matrix-free, parameters
805 
806 .seealso: MatCreateSNESMF(),MatMFFDGetH(),
807           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
808           MatMFFDKSPMonitor()
809 @*/
810 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetPeriod(Mat mat,PetscInt period)
811 {
812   MatMFFD ctx = (MatMFFD)mat->data;
813 
814   PetscFunctionBegin;
815   ctx->recomputeperiod = period;
816   PetscFunctionReturn(0);
817 }
818 
819 #undef __FUNCT__
820 #define __FUNCT__ "MatMFFDSetFunctionError"
821 /*@
822    MatMFFDSetFunctionError - Sets the error_rel for the approximation of
823    matrix-vector products using finite differences.
824 
825    Collective on Mat
826 
827    Input Parameters:
828 +  mat - the matrix free matrix created via MatCreateMFFD() or MatCreateSNESMF()
829 -  error_rel - relative error (should be set to the square root of
830                the relative error in the function evaluations)
831 
832    Options Database Keys:
833 +  -mat_mffd_err <error_rel> - Sets error_rel
834 
835    Level: advanced
836 
837    Notes:
838    The default matrix-free matrix-vector product routine computes
839 .vb
840      F'(u)*a = [F(u+h*a) - F(u)]/h where
841      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
842        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
843 .ve
844 
845 .keywords: SNES, matrix-free, parameters
846 
847 .seealso: MatCreateSNESMF(),MatMFFDGetH(), MatCreateMFFD(), MATMFFD
848           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
849           MatMFFDKSPMonitor()
850 @*/
851 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetFunctionError(Mat mat,PetscReal error)
852 {
853   MatMFFD ctx = (MatMFFD)mat->data;
854 
855   PetscFunctionBegin;
856   if (error != PETSC_DEFAULT) ctx->error_rel = error;
857   PetscFunctionReturn(0);
858 }
859 
860 #undef __FUNCT__
861 #define __FUNCT__ "MatMFFDAddNullSpace"
862 /*@
863    MatMFFDAddNullSpace - Provides a null space that an operator is
864    supposed to have.  Since roundoff will create a small component in
865    the null space, if you know the null space you may have it
866    automatically removed.
867 
868    Collective on Mat
869 
870    Input Parameters:
871 +  J - the matrix-free matrix context
872 -  nullsp - object created with MatNullSpaceCreate()
873 
874    Level: advanced
875 
876 .keywords: SNES, matrix-free, null space
877 
878 .seealso: MatNullSpaceCreate(), MatMFFDGetH(), MatCreateSNESMF(), MatCreateMFFD(), MATMFFD
879           MatMFFDSetHHistory(), MatMFFDResetHHistory(),
880           MatMFFDKSPMonitor(), MatMFFDErrorRel()
881 @*/
882 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDAddNullSpace(Mat J,MatNullSpace nullsp)
883 {
884   PetscErrorCode ierr;
885   MatMFFD      ctx = (MatMFFD)J->data;
886 
887   PetscFunctionBegin;
888   ierr = PetscObjectReference((PetscObject)nullsp);CHKERRQ(ierr);
889   if (ctx->sp) { ierr = MatNullSpaceDestroy(ctx->sp);CHKERRQ(ierr); }
890   ctx->sp = nullsp;
891   PetscFunctionReturn(0);
892 }
893 
894 #undef __FUNCT__
895 #define __FUNCT__ "MatMFFDSetHHistory"
896 /*@
897    MatMFFDSetHHistory - Sets an array to collect a history of the
898    differencing values (h) computed for the matrix-free product.
899 
900    Collective on Mat
901 
902    Input Parameters:
903 +  J - the matrix-free matrix context
904 .  histroy - space to hold the history
905 -  nhistory - number of entries in history, if more entries are generated than
906               nhistory, then the later ones are discarded
907 
908    Level: advanced
909 
910    Notes:
911    Use MatMFFDResetHHistory() to reset the history counter and collect
912    a new batch of differencing parameters, h.
913 
914 .keywords: SNES, matrix-free, h history, differencing history
915 
916 .seealso: MatMFFDGetH(), MatCreateSNESMF(),
917           MatMFFDResetHHistory(),
918           MatMFFDKSPMonitor(), MatMFFDSetFunctionError()
919 
920 @*/
921 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory)
922 {
923   MatMFFD ctx = (MatMFFD)J->data;
924 
925   PetscFunctionBegin;
926   ctx->historyh    = history;
927   ctx->maxcurrenth = nhistory;
928   ctx->currenth    = 0;
929   PetscFunctionReturn(0);
930 }
931 
932 #undef __FUNCT__
933 #define __FUNCT__ "MatMFFDResetHHistory"
934 /*@
935    MatMFFDResetHHistory - Resets the counter to zero to begin
936    collecting a new set of differencing histories.
937 
938    Collective on Mat
939 
940    Input Parameters:
941 .  J - the matrix-free matrix context
942 
943    Level: advanced
944 
945    Notes:
946    Use MatMFFDSetHHistory() to create the original history counter.
947 
948 .keywords: SNES, matrix-free, h history, differencing history
949 
950 .seealso: MatMFFDGetH(), MatCreateSNESMF(),
951           MatMFFDSetHHistory(),
952           MatMFFDKSPMonitor(), MatMFFDSetFunctionError()
953 
954 @*/
955 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDResetHHistory(Mat J)
956 {
957   MatMFFD ctx = (MatMFFD)J->data;
958 
959   PetscFunctionBegin;
960   ctx->ncurrenth    = 0;
961   PetscFunctionReturn(0);
962 }
963 
964 
965 #undef __FUNCT__
966 #define __FUNCT__ "MatMFFDSetBase"
967 /*@
968     MatMFFDSetBase - Sets the vector U at which matrix vector products of the
969         Jacobian are computed
970 
971     Collective on Mat
972 
973     Input Parameters:
974 +   J - the MatMFFD matrix
975 .   U - the vector
976 -   F - vector that contains F(u) if it has been already computed
977 
978     Notes: This is rarely used directly
979 
980     Level: advanced
981 
982 @*/
983 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetBase(Mat J,Vec U,Vec F)
984 {
985   PetscErrorCode ierr,(*f)(Mat,Vec,Vec);
986 
987   PetscFunctionBegin;
988   PetscValidHeaderSpecific(J,MAT_COOKIE,1);
989   PetscValidHeaderSpecific(U,VEC_COOKIE,2);
990   if (F) PetscValidHeaderSpecific(F,VEC_COOKIE,3);
991   ierr = PetscObjectQueryFunction((PetscObject)J,"MatMFFDSetBase_C",(void (**)(void))&f);CHKERRQ(ierr);
992   if (f) {
993     ierr = (*f)(J,U,F);CHKERRQ(ierr);
994   }
995   PetscFunctionReturn(0);
996 }
997 
998 #undef __FUNCT__
999 #define __FUNCT__ "MatMFFDSetCheckh"
1000 /*@C
1001     MatMFFDSetCheckh - Sets a function that checks the computed h and adjusts
1002         it to satisfy some criteria
1003 
1004     Collective on Mat
1005 
1006     Input Parameters:
1007 +   J - the MatMFFD matrix
1008 .   fun - the function that checks h
1009 -   ctx - any context needed by the function
1010 
1011     Options Database Keys:
1012 .   -mat_mffd_check_positivity
1013 
1014     Level: advanced
1015 
1016     Notes: For example, MatMFFDSetCheckPositivity() insures that all entries
1017        of U + h*a are non-negative
1018 
1019 .seealso:  MatMFFDSetCheckPositivity()
1020 @*/
1021 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDSetCheckh(Mat J,PetscErrorCode (*fun)(void*,Vec,Vec,PetscScalar*),void* ctx)
1022 {
1023   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(void*,Vec,Vec,PetscScalar*),void*);
1024 
1025   PetscFunctionBegin;
1026   PetscValidHeaderSpecific(J,MAT_COOKIE,1);
1027   ierr = PetscObjectQueryFunction((PetscObject)J,"MatMFFDSetCheckh_C",(void (**)(void))&f);CHKERRQ(ierr);
1028   if (f) {
1029     ierr = (*f)(J,fun,ctx);CHKERRQ(ierr);
1030   }
1031   PetscFunctionReturn(0);
1032 }
1033 
1034 #undef __FUNCT__
1035 #define __FUNCT__ "MatMFFDSetCheckPositivity"
1036 /*@
1037     MatMFFDCheckPositivity - Checks that all entries in U + h*a are positive or
1038         zero, decreases h until this is satisfied.
1039 
1040     Collective on Vec
1041 
1042     Input Parameters:
1043 +   U - base vector that is added to
1044 .   a - vector that is added
1045 .   h - scaling factor on a
1046 -   dummy - context variable (unused)
1047 
1048     Options Database Keys:
1049 .   -mat_mffd_check_positivity
1050 
1051     Level: advanced
1052 
1053     Notes: This is rarely used directly, rather it is passed as an argument to
1054            MatMFFDSetCheckh()
1055 
1056 .seealso:  MatMFFDSetCheckh()
1057 @*/
1058 PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDCheckPositivity(void* dummy,Vec U,Vec a,PetscScalar *h)
1059 {
1060   PetscReal      val, minval;
1061   PetscScalar    *u_vec, *a_vec;
1062   PetscErrorCode ierr;
1063   PetscInt       i,n;
1064   MPI_Comm       comm;
1065 
1066   PetscFunctionBegin;
1067   ierr = PetscObjectGetComm((PetscObject)U,&comm);CHKERRQ(ierr);
1068   ierr = VecGetArray(U,&u_vec);CHKERRQ(ierr);
1069   ierr = VecGetArray(a,&a_vec);CHKERRQ(ierr);
1070   ierr = VecGetLocalSize(U,&n);CHKERRQ(ierr);
1071   minval = PetscAbsScalar(*h*1.01);
1072   for(i=0;i<n;i++) {
1073     if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) {
1074       val = PetscAbsScalar(u_vec[i]/a_vec[i]);
1075       if (val < minval) minval = val;
1076     }
1077   }
1078   ierr = VecRestoreArray(U,&u_vec);CHKERRQ(ierr);
1079   ierr = VecRestoreArray(a,&a_vec);CHKERRQ(ierr);
1080   ierr = PetscGlobalMin(&minval,&val,comm);CHKERRQ(ierr);
1081   if (val <= PetscAbsScalar(*h)) {
1082     ierr = PetscInfo2(U,"Scaling back h from %G to %G\n",PetscRealPart(*h),.99*val);CHKERRQ(ierr);
1083     if (PetscRealPart(*h) > 0.0) *h =  0.99*val;
1084     else                         *h = -0.99*val;
1085   }
1086   PetscFunctionReturn(0);
1087 }
1088 
1089 
1090 
1091 
1092 
1093 
1094 
1095