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