xref: /petsc/src/snes/mf/snesmfj.c (revision 9a6cb015ac3094bf0593987cefb2928a6c0323c2)
1 
2 #ifdef PETSC_RCS_HEADER
3 static char vcid[] = "$Id: snesmfj.c,v 1.72 1998/11/05 04:28:55 bsmith Exp bsmith $";
4 #endif
5 
6 #include "src/snes/snesimpl.h"
7 #include "src/snes/mf/snesmfj.h"   /*I  "snes.h"   I*/
8 
9 FList MatSNESFDMFList              = 0;
10 int   MatSNESFDMFRegisterAllCalled = 0;
11 
12 
13 #undef __FUNC__
14 #define __FUNC__ "MatSNESFDMFSetType"
15 /*@
16       MatSNESFDMFSetType - Sets the method that is used to compute the h in the
17             finite difference matrix free formulation.
18 
19    Input Parameters:
20 +     mat - the matrix free matrix created via MatCreateSNESFDMF()
21 -     ftype - the type requested
22 
23 .seealso: MatCreateSNESFDMF(), MatSNESFDMFRegister()
24 @*/
25 int MatSNESFDMFSetType(Mat mat,char *ftype)
26 {
27   int            ierr, (*r)(MatSNESFDMFCtx);
28   MatSNESFDMFCtx ctx;
29 
30   PetscFunctionBegin;
31   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
32 
33   /* already set, so just return */
34   if (!PetscStrcmp(ctx->type_name,ftype)) PetscFunctionReturn(0);
35 
36   /* destroy the old one if it exists */
37   if (ctx->ops->destroy) {
38     ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);
39   }
40 
41   /* Get the function pointers for the iterative method requested */
42   if (!MatSNESFDMFRegisterAllCalled) {ierr = MatSNESFDMFRegisterAll(PETSC_NULL); CHKERRQ(ierr);}
43 
44   ierr =  FListFind(ctx->comm, MatSNESFDMFList, ftype,(int (**)(void *)) &r );CHKERRQ(ierr);
45 
46   if (!r) SETERRQ(1,1,"Unknown MatSNESFDMF type given");
47 
48   ierr = (*r)(ctx); CHKERRQ(ierr);
49   ierr = PetscStrncpy(ctx->type_name,ftype,256);CHKERRQ(ierr);
50 
51   PetscFunctionReturn(0);
52 }
53 
54 /*MC
55    MatSNESFDMFRegister - Adds a method to the MatSNESFDMF registry
56 
57    Synopsis:
58    MatSNESFDMFRegister(char *name_solver,char *path,char *name_create,int (*routine_create)(MatSNESFDMF))
59 
60    Not Collective
61 
62    Input Parameters:
63 +  name_solver - name of a new user-defined compute-h module
64 .  path - path (either absolute or relative) the library containing this solver
65 .  name_create - name of routine to create method context
66 -  routine_create - routine to create method context
67 
68    Notes:
69    MatSNESFDMFRegister() may be called multiple times to add several user-defined solvers.
70 
71    If dynamic libraries are used, then the fourth input argument (routine_create)
72    is ignored.
73 
74    Sample usage:
75 .vb
76    MatSNESFDMFRegister("my_h",/home/username/my_lib/lib/libO/solaris/mylib.a,
77                "MyHCreate",MyHCreate);
78 .ve
79 
80    Then, your solver can be chosen with the procedural interface via
81 $     MatSNESFDMFSetType(mfctx,"my_h")
82    or at runtime via the option
83 $     -snes_mf_type my_h
84 
85 .keywords: MatSNESFDMF, register
86 
87 .seealso: MatSNESFDMFRegisterAll(), MatSNESFDMFRegisterDestroy()
88 M*/
89 
90 #undef __FUNC__
91 #define __FUNC__ "MatSNESFDMFRegister_Private"
92 int MatSNESFDMFRegister_Private(char *sname,char *path,char *name,int (*function)(MatSNESFDMFCtx))
93 {
94   int ierr;
95   char fullname[256];
96 
97   PetscFunctionBegin;
98   PetscStrcpy(fullname,path); PetscStrcat(fullname,":");PetscStrcat(fullname,name);
99   ierr = FListAdd_Private(&MatSNESFDMFList,sname,fullname,(int (*)(void*))function);CHKERRQ(ierr);
100   PetscFunctionReturn(0);
101 }
102 
103 
104 #undef __FUNC__
105 #define __FUNC__ "MatSNESFDMFRegisterDestroy"
106 /*@C
107    MatSNESFDMFRegisterDestroy - Frees the list of MatSNESFDMF methods that were
108    registered by MatSNESFDMFRegister().
109 
110    Not Collective
111 
112 .keywords: MatSNESFDMF, register, destroy
113 
114 .seealso: MatSNESFDMFRegister(), MatSNESFDMFRegisterAll()
115 @*/
116 int MatSNESFDMFRegisterDestroy(void)
117 {
118   int ierr;
119 
120   PetscFunctionBegin;
121   if (MatSNESFDMFList) {
122     ierr = FListDestroy( MatSNESFDMFList );CHKERRQ(ierr);
123     MatSNESFDMFList = 0;
124   }
125   MatSNESFDMFRegisterAllCalled = 0;
126   PetscFunctionReturn(0);
127 }
128 
129 /* ----------------------------------------------------------------------------------------*/
130 #undef __FUNC__
131 #define __FUNC__ "MatSNESFDMFDestroy_Private"
132 int MatSNESFDMFDestroy_Private(Mat mat)
133 {
134   int            ierr;
135   MatSNESFDMFCtx ctx;
136 
137   PetscFunctionBegin;
138   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
139   ierr = VecDestroy(ctx->w); CHKERRQ(ierr);
140   if (ctx->ops->destroy) {ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);}
141   if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp);CHKERRQ(ierr);}
142   PetscFree(ctx->ops);
143   PetscFree(ctx);
144   PetscFunctionReturn(0);
145 }
146 
147 #undef __FUNC__
148 #define __FUNC__ "MatSNESFDMFView_Private"
149 /*
150    MatSNESFDMFView_Private - Views matrix-free parameters.
151 
152 */
153 int MatSNESFDMFView_Private(Mat J,Viewer viewer)
154 {
155   int            ierr;
156   MatSNESFDMFCtx ctx;
157   MPI_Comm       comm;
158   FILE           *fd;
159   ViewerType     vtype;
160 
161   PetscFunctionBegin;
162   PetscObjectGetComm((PetscObject)J,&comm);
163   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
164   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
165   ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
166   if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
167      PetscFPrintf(comm,fd,"  SNES matrix-free approximation:\n");
168      PetscFPrintf(comm,fd,"    err=%g (relative error in function evaluation)\n",ctx->error_rel);
169      PetscFPrintf(ctx->comm,fd,"    Using %s compute h routine \n",ctx->type_name);
170      if (ctx->ops->view) {
171        ierr = (*ctx->ops->view)(ctx,viewer);CHKERRQ(ierr);
172      }
173   } else {
174     SETERRQ(1,1,"Viewer type not supported for this object");
175   }
176   PetscFunctionReturn(0);
177 }
178 
179 
180 #undef __FUNC__
181 #define __FUNC__ "MatSNESFDMFMult_Private"
182 /*
183   MatSNESFDMFMult_Private - Default matrix-free form for Jacobian-vector
184   product, y = F'(u)*a:
185 
186         y ~= ( F(u + ha) - F(u) )/h,
187   where F = nonlinear function, as set by SNESSetFunction()
188         u = current iterate
189         h = difference interval
190 */
191 int MatSNESFDMFMult_Private(Mat mat,Vec a,Vec y)
192 {
193   MatSNESFDMFCtx ctx;
194   SNES           snes;
195   Scalar         h, mone = -1.0;
196   Vec            w,U,F;
197   int            ierr, (*eval_fct)(SNES,Vec,Vec);
198 
199   PetscFunctionBegin;
200   /* We log matrix-free matrix-vector products separately, so that we can
201      separate the performance monitoring from the cases that use conventional
202      storage.  We may eventually modify event logging to associate events
203      with particular objects, hence alleviating the more general problem. */
204   PLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);
205 
206   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
207   snes = ctx->snes;
208   w    = ctx->w;
209 
210   ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr);
211   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
212     eval_fct = SNESComputeFunction;
213     ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr);
214   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
215     eval_fct = SNESComputeGradient;
216     ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr);
217   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Invalid method class");
218 
219   if (!ctx->ops->compute) {
220     ierr = MatSNESFDMFSetType(mat,"default");CHKERRQ(ierr);
221     ierr = MatSNESFDMFSetFromOptions(mat);CHKERRQ(ierr);
222   }
223   ierr = (*ctx->ops->compute)(ctx,U,a,&h); CHKERRQ(ierr);
224 
225   /* keep a record of the current differencing parameter h */
226   ctx->currenth = h;
227 #if defined(USE_PETSC_COMPLEX)
228   PLogInfo(mat,"Current differencing parameter: %g + %g i\n",PetscReal(h),PetscImaginary(h));
229 #else
230   PLogInfo(mat,"Current differencing parameter: %g\n",h);
231 #endif
232   if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
233     ctx->historyh[ctx->ncurrenth++] = h;
234   }
235 
236   /* Evaluate function at F(u + ha) */
237   ierr = VecWAXPY(&h,a,U,w); CHKERRQ(ierr);
238   ierr = eval_fct(snes,w,y); CHKERRQ(ierr);
239 
240   ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr);
241   h = 1.0/h;
242   ierr = VecScale(&h,y); CHKERRQ(ierr);
243   if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);}
244 
245   PLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);
246   PetscFunctionReturn(0);
247 }
248 
249 #undef __FUNC__
250 #define __FUNC__ "MatCreateSNESFDMF"
251 /*@C
252    MatCreateSNESFDMF - Creates a matrix-free matrix
253    context for use with a SNES solver.  This matrix can be used as
254    the Jacobian argument for the routine SNESSetJacobian().
255 
256    Collective on SNES and Vec
257 
258    Input Parameters:
259 +  snes - the SNES context
260 -  x - vector where SNES solution is to be stored.
261 
262    Output Parameter:
263 .  J - the matrix-free matrix
264 
265    Notes:
266    The matrix-free matrix context merely contains the function pointers
267    and work space for performing finite difference approximations of
268    Jacobian-vector products, J(u)*a,
269 
270    The default code uses the following approach to compute h
271 
272 .vb
273      J(u)*a = [J(u+h*a) - J(u)]/h where
274      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
275        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
276  where
277      error_rel = square root of relative error in function evaluation
278      umin = minimum iterate parameter
279 .ve
280 
281    The user can set the error_rel via MatSNESFDMFSetFunctionError() and
282    umin via MatSNESFDMFDefaultSetUmin()
283    See the nonlinear solvers chapter of the users manual for details.
284 
285    The user should call MatDestroy() when finished with the matrix-free
286    matrix context.
287 
288    Options Database Keys:
289 +  -snes_mf_err <error_rel> - Sets error_rel
290 .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
291 -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
292 
293 .keywords: SNES, default, matrix-free, create, matrix
294 
295 .seealso: MatDestroy(), MatSNESFDMFSetFunctionError(), MatSNESFDMFDefaultSetUmin()
296           MatSNESFDMFSetHHistory(), MatSNESFDMFResetHHistory(),
297           MatSNESFDMFGetH(),MatSNESFDMFKSPMonitor(), MatSNESFDMFRegister()
298 
299 @*/
300 int MatCreateSNESFDMF(SNES snes,Vec x, Mat *J)
301 {
302   MPI_Comm       comm;
303   MatSNESFDMFCtx mfctx;
304   int            n, nloc, ierr;
305 
306   PetscFunctionBegin;
307   mfctx = (MatSNESFDMFCtx) PetscMalloc(sizeof(struct _p_MatSNESFDMFCtx)); CHKPTRQ(mfctx);
308   PLogObjectMemory(snes,sizeof(MatSNESFDMFCtx));
309   mfctx->comm         = snes->comm;
310   mfctx->sp           = 0;
311   mfctx->snes         = snes;
312   mfctx->error_rel    = 1.e-8; /* assumes double precision */
313   mfctx->currenth     = 0.0;
314   mfctx->historyh     = PETSC_NULL;
315   mfctx->ncurrenth    = 0;
316   mfctx->maxcurrenth  = 0;
317 
318   /*
319      Create the empty data structure to contain compute-h routines.
320      These will be filled in below from the command line options or
321      a later call with MatSNESFDMFSetType() or if that is not called
322      then it will default in the first use of MatSNESFDMFMult_private()
323   */
324   mfctx->ops                 = (MFOps *)PetscMalloc(sizeof(MFOps)); CHKPTRQ(mfctx->ops);
325   mfctx->ops->compute        = 0;
326   mfctx->ops->destroy        = 0;
327   mfctx->ops->view           = 0;
328   mfctx->ops->printhelp      = 0;
329   mfctx->ops->setfromoptions = 0;
330   mfctx->hctx                = 0;
331 
332   ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr);
333   ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr);
334   ierr = VecGetSize(x,&n); CHKERRQ(ierr);
335   ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr);
336   ierr = MatCreateShell(comm,nloc,n,n,n,mfctx,J); CHKERRQ(ierr);
337   ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)MatSNESFDMFMult_Private);CHKERRQ(ierr);
338   ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)MatSNESFDMFDestroy_Private);CHKERRQ(ierr);
339   ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)MatSNESFDMFView_Private); CHKERRQ(ierr);
340   PLogObjectParent(*J,mfctx->w);
341   PLogObjectParent(snes,*J);
342 
343   mfctx->mat = *J;
344 
345 
346   PetscFunctionReturn(0);
347 }
348 
349 #undef __FUNC__
350 #define __FUNC__ "MatSNESFDMFGetH"
351 /*@
352    MatSNESFDMFSetFromOptions - Sets the MatSNESFDMF options from the command line
353      parameter.
354 
355    Collective on Mat
356 
357    Input Parameters:
358 .   mat - the matrix obtained with MatCreateSNESFDMF()
359 
360 .keywords: SNES, matrix-free, parameters
361 
362 .seealso: MatCreateSNESFDMF(),MatSNESFDMFSetHHistory(),
363           MatSNESFDMFResetHHistory(),MatSNESFDMFKSPMonitor()
364 @*/
365 int MatSNESFDMFSetFromOptions(Mat mat)
366 {
367   MatSNESFDMFCtx mfctx;
368   int            ierr,flg;
369   char           ftype[256],p[64];
370 
371   PetscFunctionBegin;
372   ierr = MatShellGetContext(mat,(void **)&mfctx); CHKERRQ(ierr);
373   if (mfctx) {
374     /* allow user to set the type */
375     ierr = OptionsGetString(mfctx->snes->prefix,"-snes_mf_type",ftype,256,&flg);CHKERRQ(ierr);
376     if (flg) {
377       ierr = MatSNESFDMFSetType(mat,ftype);CHKERRQ(ierr);
378     }
379 
380     ierr = OptionsGetDouble(mfctx->snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg);CHKERRQ(ierr);
381     if (mfctx->ops->setfromoptions) {
382       ierr = (*mfctx->ops->setfromoptions)(mfctx);CHKERRQ(ierr);
383     }
384 
385     ierr = OptionsHasName(PETSC_NULL,"-help",&flg); CHKERRQ(ierr);
386     PetscStrcpy(p,"-");
387     if (mfctx->snes->prefix) PetscStrcat(p,mfctx->snes->prefix);
388     if (flg) {
389       (*PetscHelpPrintf)(mfctx->snes->comm,"   %ssnes_mf_err <err>: set sqrt rel error in function (default %g)\n",p,mfctx->error_rel);
390       if (mfctx->ops->printhelp) {
391         (*mfctx->ops->printhelp)(mfctx);CHKERRQ(ierr);
392       }
393     }
394   }
395   PetscFunctionReturn(0);
396 }
397 
398 #undef __FUNC__
399 #define __FUNC__ "MatSNESFDMFGetH"
400 /*@
401    MatSNESFDMFGetH - Gets the last h that was used as the differencing
402      parameter.
403 
404    Not Collective
405 
406    Input Parameters:
407 .   mat - the matrix obtained with MatCreateSNESFDMF()
408 
409    Output Paramter:
410 .  h - the differencing step size
411 
412 .keywords: SNES, matrix-free, parameters
413 
414 .seealso: MatCreateSNESFDMF(),MatSNESFDMFSetHHistory(),
415           MatSNESFDMFResetHHistory(),MatSNESFDMFKSPMonitor()
416 @*/
417 int MatSNESFDMFGetH(Mat mat,Scalar *h)
418 {
419   MatSNESFDMFCtx ctx;
420   int            ierr;
421 
422   PetscFunctionBegin;
423   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
424   if (ctx) {
425     *h = ctx->currenth;
426   }
427   PetscFunctionReturn(0);
428 }
429 
430 #undef __FUNC__
431 #define __FUNC__ "MatSNESFDMFKSPMonitor"
432 /*
433    MatSNESFDMFKSPMonitor - A KSP monitor for use with the default PETSc
434       SNES matrix free routines. Prints the h differencing parameter used at each
435       timestep.
436 
437 */
438 int MatSNESFDMFKSPMonitor(KSP ksp,int n,double rnorm,void *dummy)
439 {
440   PC             pc;
441   MatSNESFDMFCtx ctx;
442   int            ierr;
443   Mat            mat;
444   MPI_Comm       comm;
445   PetscTruth     nonzeroinitialguess;
446 
447   PetscFunctionBegin;
448   ierr = PetscObjectGetComm((PetscObject)ksp,&comm);CHKERRQ(ierr);
449   ierr = KSPGetPC(ksp,&pc); CHKERRQ(ierr);
450   ierr = KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);CHKERRQ(ierr);
451   ierr = PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
452   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
453   if (!ctx) {
454     SETERRQ(1,1,"Matrix is not a matrix free shell matrix");
455   }
456   if (n > 0 || nonzeroinitialguess) {
457 #if defined(USE_PETSC_COMPLEX)
458     PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g i\n",n,rnorm,
459                 PetscReal(ctx->currenth),PetscImaginary(ctx->currenth));
460 #else
461     PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);
462 #endif
463   } else {
464     PetscPrintf(comm,"%d KSP Residual norm %14.12e\n",n,rnorm);
465   }
466   PetscFunctionReturn(0);
467 }
468 
469 #undef __FUNC__
470 #define __FUNC__ "MatSNESFDMFSetFunctionError"
471 /*@
472    MatSNESFDMFSetFunctionError - Sets the error_rel for the approximation of
473    matrix-vector products using finite differences.
474 
475    Collective on Mat
476 
477    Input Parameters:
478 +  mat - the matrix free matrix created via MatCreateSNESFDMF()
479 -  error_rel - relative error (should be set to the square root of
480                the relative error in the function evaluations)
481 
482    Notes:
483    The default matrix-free matrix-vector product routine computes
484 .vb
485      J(u)*a = [J(u+h*a) - J(u)]/h where
486      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
487        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
488 .ve
489 
490    Options Database Keys:
491 +  -snes_mf_err <error_rel> - Sets error_rel
492 
493 .keywords: SNES, matrix-free, parameters
494 
495 .seealso: MatCreateSNESFDMF(),MatSNESFDMFGetH(),
496           MatSNESFDMFSetHHistory(), MatSNESFDMFResetHHistory(),
497           MatSNESFDMFKSPMonitor()
498 @*/
499 int MatSNESFDMFSetFunctionError(Mat mat,double error)
500 {
501   MatSNESFDMFCtx ctx;
502   int            ierr;
503 
504   PetscFunctionBegin;
505   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
506   if (ctx) {
507     if (error != PETSC_DEFAULT) ctx->error_rel = error;
508   }
509   PetscFunctionReturn(0);
510 }
511 
512 #undef __FUNC__
513 #define __FUNC__ "MatSNESFDMFAddNullSpace"
514 /*@
515    MatSNESFDMFAddNullSpace - Provides a null space that
516    an operator is supposed to have.  Since roundoff will create a
517    small component in the null space, if you know the null space
518    you may have it automatically removed.
519 
520    Collective on Mat
521 
522    Input Parameters:
523 +  J - the matrix-free matrix context
524 .  has_cnst - PETSC_TRUE or PETSC_FALSE, indicating if null space has constants
525 .  n - number of vectors (excluding constant vector) in null space
526 -  vecs - the vectors that span the null space (excluding the constant vector);
527           these vectors must be orthonormal
528 
529 .keywords: SNES, matrix-free, null space
530 
531 .seealso: MatSNESFDMFGetH(), MatCreateSNESFDMF(),
532           MatSNESFDMFSetHHistory(), MatSNESFDMFResetHHistory(),
533           MatSNESFDMFKSPMonitor(), MatSNESFDMFErrorRel()
534 
535 @*/
536 int MatSNESFDMFAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs)
537 {
538   int            ierr;
539   MatSNESFDMFCtx ctx;
540   MPI_Comm       comm;
541 
542   PetscFunctionBegin;
543   PetscObjectGetComm((PetscObject)J,&comm);
544 
545   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
546   /* no context indicates that it is not the "matrix free" matrix type */
547   if (!ctx) PetscFunctionReturn(0);
548   ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr);
549   PetscFunctionReturn(0);
550 }
551 
552 #undef __FUNC__
553 #define __FUNC__ "MatSNESFDMFSetHHistory"
554 /*@
555    MatSNESFDMFSetHHistory - Sets an array to collect a history
556       of the differencing values h computed for the matrix free product
557 
558    Collective on Mat
559 
560    Input Parameters:
561 +  J - the matrix-free matrix context
562 .  histroy - space to hold the h history
563 -  nhistory - number of entries in history, if more h are generated than
564               nhistory the later ones are discarded
565 
566    Notes:
567     Use MatSNESFDMFResetHHistory() to reset the history counter
568     and collect a new batch of h.
569 
570 .keywords: SNES, matrix-free, h history, differencing history
571 
572 .seealso: MatSNESFDMFGetH(), MatCreateSNESFDMF(),
573           MatSNESFDMFResetHHistory(),
574           MatSNESFDMFKSPMonitor(), MatSNESFDMFSetFunctionError()
575 
576 @*/
577 int MatSNESFDMFSetHHistory(Mat J,Scalar *history,int nhistory)
578 {
579   int            ierr;
580   MatSNESFDMFCtx ctx;
581 
582   PetscFunctionBegin;
583 
584   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
585   /* no context indicates that it is not the "matrix free" matrix type */
586   if (!ctx) PetscFunctionReturn(0);
587   ctx->historyh    = history;
588   ctx->maxcurrenth = nhistory;
589   ctx->currenth    = 0;
590 
591   PetscFunctionReturn(0);
592 }
593 
594 #undef __FUNC__
595 #define __FUNC__ "MatSNESFDMFResetHHistory"
596 /*@
597    MatSNESFDMFResetHHistory - Resets the counter to zero to begin
598       collecting a new set of differencing histories.
599 
600    Collective on Mat
601 
602    Input Parameters:
603 .  J - the matrix-free matrix context
604 
605    Notes:
606     Use MatSNESFDMFSetHHistory() to create the original history counter
607 
608 .keywords: SNES, matrix-free, h history, differencing history
609 
610 .seealso: MatSNESFDMFGetH(), MatCreateSNESFDMF(),
611           MatSNESFDMFSetHHistory(),
612           MatSNESFDMFKSPMonitor(), MatSNESFDMFSetFunctionError()
613 
614 @*/
615 int MatSNESFDMFResetHHistory(Mat J)
616 {
617   int            ierr;
618   MatSNESFDMFCtx ctx;
619 
620   PetscFunctionBegin;
621 
622   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
623   /* no context indicates that it is not the "matrix free" matrix type */
624   if (!ctx) PetscFunctionReturn(0);
625   ctx->currenth    = 0;
626 
627   PetscFunctionReturn(0);
628 }
629 
630