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