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