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