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