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