xref: /petsc/src/snes/mf/snesmfj.c (revision 3f1db9ec2fd39765c6c3a00831044586630c4cca)
19a6cb015SBarry Smith 
2a5eb4965SSatish Balay #ifdef PETSC_RCS_HEADER
3*3f1db9ecSBarry Smith static char vcid[] = "$Id: snesmfj.c,v 1.76 1998/12/09 16:08:05 balay Exp bsmith $";
481e6777dSBarry Smith #endif
581e6777dSBarry Smith 
69a6cb015SBarry Smith #include "src/snes/snesimpl.h"
79a6cb015SBarry Smith #include "src/snes/mf/snesmfj.h"   /*I  "snes.h"   I*/
881e6777dSBarry Smith 
99a6cb015SBarry Smith FList MatSNESFDMFList              = 0;
109a6cb015SBarry Smith int   MatSNESFDMFRegisterAllCalled = 0;
11a4d4d686SBarry Smith 
1239e2f89bSBarry Smith 
135615d1e5SSatish Balay #undef __FUNC__
14a4d4d686SBarry Smith #define __FUNC__ "MatSNESFDMFSetType"
159a6cb015SBarry Smith /*@
169a6cb015SBarry Smith       MatSNESFDMFSetType - Sets the method that is used to compute the h in the
179a6cb015SBarry Smith             finite difference matrix free formulation.
189a6cb015SBarry Smith 
199a6cb015SBarry Smith    Input Parameters:
209a6cb015SBarry Smith +     mat - the matrix free matrix created via MatCreateSNESFDMF()
219a6cb015SBarry Smith -     ftype - the type requested
229a6cb015SBarry Smith 
239a6cb015SBarry Smith .seealso: MatCreateSNESFDMF(), MatSNESFDMFRegister()
249a6cb015SBarry Smith @*/
259a6cb015SBarry Smith int MatSNESFDMFSetType(Mat mat,char *ftype)
26b9fa9cd0SBarry Smith {
279a6cb015SBarry Smith   int            ierr, (*r)(MatSNESFDMFCtx);
28a4d4d686SBarry Smith   MatSNESFDMFCtx ctx;
29a4d4d686SBarry Smith 
30a4d4d686SBarry Smith   PetscFunctionBegin;
31a4d4d686SBarry Smith   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
32a4d4d686SBarry Smith 
339a6cb015SBarry Smith   /* already set, so just return */
34*3f1db9ecSBarry Smith   if (PetscTypeCompare(ctx->type_name,ftype)) PetscFunctionReturn(0);
35a4d4d686SBarry Smith 
369a6cb015SBarry Smith   /* destroy the old one if it exists */
379a6cb015SBarry Smith   if (ctx->ops->destroy) {
389a6cb015SBarry Smith     ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);
399a6cb015SBarry Smith   }
409a6cb015SBarry Smith 
419a6cb015SBarry Smith   /* Get the function pointers for the iterative method requested */
429a6cb015SBarry Smith   if (!MatSNESFDMFRegisterAllCalled) {ierr = MatSNESFDMFRegisterAll(PETSC_NULL); CHKERRQ(ierr);}
439a6cb015SBarry Smith 
449a6cb015SBarry Smith   ierr =  FListFind(ctx->comm, MatSNESFDMFList, ftype,(int (**)(void *)) &r );CHKERRQ(ierr);
459a6cb015SBarry Smith 
469a6cb015SBarry Smith   if (!r) SETERRQ(1,1,"Unknown MatSNESFDMF type given");
479a6cb015SBarry Smith 
489a6cb015SBarry Smith   ierr = (*r)(ctx); CHKERRQ(ierr);
499a6cb015SBarry Smith   ierr = PetscStrncpy(ctx->type_name,ftype,256);CHKERRQ(ierr);
509a6cb015SBarry Smith 
519a6cb015SBarry Smith   PetscFunctionReturn(0);
529a6cb015SBarry Smith }
539a6cb015SBarry Smith 
549a6cb015SBarry Smith /*MC
559a6cb015SBarry Smith    MatSNESFDMFRegister - Adds a method to the MatSNESFDMF registry
569a6cb015SBarry Smith 
579a6cb015SBarry Smith    Synopsis:
589a6cb015SBarry Smith    MatSNESFDMFRegister(char *name_solver,char *path,char *name_create,int (*routine_create)(MatSNESFDMF))
599a6cb015SBarry Smith 
609a6cb015SBarry Smith    Not Collective
619a6cb015SBarry Smith 
629a6cb015SBarry Smith    Input Parameters:
639a6cb015SBarry Smith +  name_solver - name of a new user-defined compute-h module
649a6cb015SBarry Smith .  path - path (either absolute or relative) the library containing this solver
659a6cb015SBarry Smith .  name_create - name of routine to create method context
669a6cb015SBarry Smith -  routine_create - routine to create method context
679a6cb015SBarry Smith 
689a6cb015SBarry Smith    Notes:
699a6cb015SBarry Smith    MatSNESFDMFRegister() may be called multiple times to add several user-defined solvers.
709a6cb015SBarry Smith 
719a6cb015SBarry Smith    If dynamic libraries are used, then the fourth input argument (routine_create)
729a6cb015SBarry Smith    is ignored.
739a6cb015SBarry Smith 
749a6cb015SBarry Smith    Sample usage:
759a6cb015SBarry Smith .vb
769a6cb015SBarry Smith    MatSNESFDMFRegister("my_h",/home/username/my_lib/lib/libO/solaris/mylib.a,
779a6cb015SBarry Smith                "MyHCreate",MyHCreate);
789a6cb015SBarry Smith .ve
799a6cb015SBarry Smith 
809a6cb015SBarry Smith    Then, your solver can be chosen with the procedural interface via
819a6cb015SBarry Smith $     MatSNESFDMFSetType(mfctx,"my_h")
829a6cb015SBarry Smith    or at runtime via the option
839a6cb015SBarry Smith $     -snes_mf_type my_h
849a6cb015SBarry Smith 
859a6cb015SBarry Smith .keywords: MatSNESFDMF, register
869a6cb015SBarry Smith 
879a6cb015SBarry Smith .seealso: MatSNESFDMFRegisterAll(), MatSNESFDMFRegisterDestroy()
889a6cb015SBarry Smith M*/
899a6cb015SBarry Smith 
909a6cb015SBarry Smith #undef __FUNC__
919a6cb015SBarry Smith #define __FUNC__ "MatSNESFDMFRegister_Private"
929a6cb015SBarry Smith int MatSNESFDMFRegister_Private(char *sname,char *path,char *name,int (*function)(MatSNESFDMFCtx))
939a6cb015SBarry Smith {
949a6cb015SBarry Smith   int ierr;
959a6cb015SBarry Smith   char fullname[256];
969a6cb015SBarry Smith 
979a6cb015SBarry Smith   PetscFunctionBegin;
989a6cb015SBarry Smith   PetscStrcpy(fullname,path); PetscStrcat(fullname,":");PetscStrcat(fullname,name);
999a6cb015SBarry Smith   ierr = FListAdd_Private(&MatSNESFDMFList,sname,fullname,(int (*)(void*))function);CHKERRQ(ierr);
1009a6cb015SBarry Smith   PetscFunctionReturn(0);
1019a6cb015SBarry Smith }
1029a6cb015SBarry Smith 
1039a6cb015SBarry Smith 
1049a6cb015SBarry Smith #undef __FUNC__
1059a6cb015SBarry Smith #define __FUNC__ "MatSNESFDMFRegisterDestroy"
1069a6cb015SBarry Smith /*@C
1079a6cb015SBarry Smith    MatSNESFDMFRegisterDestroy - Frees the list of MatSNESFDMF methods that were
1089a6cb015SBarry Smith    registered by MatSNESFDMFRegister().
1099a6cb015SBarry Smith 
1109a6cb015SBarry Smith    Not Collective
1119a6cb015SBarry Smith 
1129a6cb015SBarry Smith .keywords: MatSNESFDMF, register, destroy
1139a6cb015SBarry Smith 
1149a6cb015SBarry Smith .seealso: MatSNESFDMFRegister(), MatSNESFDMFRegisterAll()
1159a6cb015SBarry Smith @*/
1169a6cb015SBarry Smith int MatSNESFDMFRegisterDestroy(void)
1179a6cb015SBarry Smith {
1189a6cb015SBarry Smith   int ierr;
1199a6cb015SBarry Smith 
1209a6cb015SBarry Smith   PetscFunctionBegin;
1219a6cb015SBarry Smith   if (MatSNESFDMFList) {
1229a6cb015SBarry Smith     ierr = FListDestroy( MatSNESFDMFList );CHKERRQ(ierr);
1239a6cb015SBarry Smith     MatSNESFDMFList = 0;
1249a6cb015SBarry Smith   }
1259a6cb015SBarry Smith   MatSNESFDMFRegisterAllCalled = 0;
1269a6cb015SBarry Smith   PetscFunctionReturn(0);
1279a6cb015SBarry Smith }
1289a6cb015SBarry Smith 
1299a6cb015SBarry Smith /* ----------------------------------------------------------------------------------------*/
130a4d4d686SBarry Smith #undef __FUNC__
131a4d4d686SBarry Smith #define __FUNC__ "MatSNESFDMFDestroy_Private"
132a4d4d686SBarry Smith int MatSNESFDMFDestroy_Private(Mat mat)
133a4d4d686SBarry Smith {
134a4d4d686SBarry Smith   int            ierr;
135a4d4d686SBarry Smith   MatSNESFDMFCtx ctx;
136fae171e0SBarry Smith 
1373a40ed3dSBarry Smith   PetscFunctionBegin;
1380a25c783SBarry Smith   ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr);
139b9fa9cd0SBarry Smith   ierr = VecDestroy(ctx->w); CHKERRQ(ierr);
1409a6cb015SBarry Smith   if (ctx->ops->destroy) {ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);}
141b4fd4287SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp);CHKERRQ(ierr);}
1429a6cb015SBarry Smith   PetscFree(ctx->ops);
143fae171e0SBarry Smith   PetscFree(ctx);
1443a40ed3dSBarry Smith   PetscFunctionReturn(0);
145b9fa9cd0SBarry Smith }
14650361f65SLois Curfman McInnes 
1475615d1e5SSatish Balay #undef __FUNC__
148a4d4d686SBarry Smith #define __FUNC__ "MatSNESFDMFView_Private"
14939e2f89bSBarry Smith /*
150a4d4d686SBarry Smith    MatSNESFDMFView_Private - Views matrix-free parameters.
1518f6e3e37SBarry Smith 
15239e2f89bSBarry Smith */
153a4d4d686SBarry Smith int MatSNESFDMFView_Private(Mat J,Viewer viewer)
154eb9086c3SLois Curfman McInnes {
155eb9086c3SLois Curfman McInnes   int            ierr;
156a4d4d686SBarry Smith   MatSNESFDMFCtx ctx;
157eb9086c3SLois Curfman McInnes   MPI_Comm       comm;
158eb9086c3SLois Curfman McInnes   FILE           *fd;
159eb9086c3SLois Curfman McInnes   ViewerType     vtype;
160eb9086c3SLois Curfman McInnes 
1613a40ed3dSBarry Smith   PetscFunctionBegin;
162eb9086c3SLois Curfman McInnes   PetscObjectGetComm((PetscObject)J,&comm);
163eb9086c3SLois Curfman McInnes   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
164eb9086c3SLois Curfman McInnes   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
165eb9086c3SLois Curfman McInnes   ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
166*3f1db9ecSBarry Smith   if (PetscTypeCompare(vtype,ASCII_VIEWER)) {
167eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"  SNES matrix-free approximation:\n");
168eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"    err=%g (relative error in function evaluation)\n",ctx->error_rel);
1699a6cb015SBarry Smith      PetscFPrintf(ctx->comm,fd,"    Using %s compute h routine\n",ctx->type_name);
1709a6cb015SBarry Smith      if (ctx->ops->view) {
1719a6cb015SBarry Smith        ierr = (*ctx->ops->view)(ctx,viewer);CHKERRQ(ierr);
1729a6cb015SBarry Smith      }
1735cd90555SBarry Smith   } else {
1745cd90555SBarry Smith     SETERRQ(1,1,"Viewer type not supported for this object");
175eb9086c3SLois Curfman McInnes   }
1763a40ed3dSBarry Smith   PetscFunctionReturn(0);
177eb9086c3SLois Curfman McInnes }
178eb9086c3SLois Curfman McInnes 
179be726c96SBarry Smith #undef __FUNC__
180be726c96SBarry Smith #define __FUNC__ "MatSNESFDMFAssemblyEnd_Private"
181be726c96SBarry Smith /*
182be726c96SBarry Smith    MatSNESFDMFAssemblyEnd_Private - Resets the ctx->ncurrenth to zero. This
183be726c96SBarry Smith      allows the user to indicate the beginning of a new linear solve by call
184be726c96SBarry Smith      MatAssemblyXXX() on the matrix free matrix. This then allows the
185be726c96SBarry Smith      MatSNESFDMFCreate_WP() to properly compute the || U|| only the first
186be726c96SBarry Smith      time in the linear solver rather than every time
187be726c96SBarry Smith 
188be726c96SBarry Smith */
189be726c96SBarry Smith int MatSNESFDMFAssemblyEnd_Private(Mat J)
190be726c96SBarry Smith {
191be726c96SBarry Smith   int            ierr;
192be726c96SBarry Smith 
193be726c96SBarry Smith   PetscFunctionBegin;
194be726c96SBarry Smith   ierr = MatSNESFDMFResetHHistory(J);CHKERRQ(ierr);
195be726c96SBarry Smith   PetscFunctionReturn(0);
196be726c96SBarry Smith }
197be726c96SBarry Smith 
198c481317fSBarry Smith 
1995615d1e5SSatish Balay #undef __FUNC__
200a4d4d686SBarry Smith #define __FUNC__ "MatSNESFDMFMult_Private"
201eb9086c3SLois Curfman McInnes /*
202a4d4d686SBarry Smith   MatSNESFDMFMult_Private - Default matrix-free form for Jacobian-vector
203eb9086c3SLois Curfman McInnes   product, y = F'(u)*a:
204a4d4d686SBarry Smith 
2059a6cb015SBarry Smith         y ~= ( F(u + ha) - F(u) )/h,
206eb9086c3SLois Curfman McInnes   where F = nonlinear function, as set by SNESSetFunction()
207eb9086c3SLois Curfman McInnes         u = current iterate
208eb9086c3SLois Curfman McInnes         h = difference interval
209eb9086c3SLois Curfman McInnes */
210a4d4d686SBarry Smith int MatSNESFDMFMult_Private(Mat mat,Vec a,Vec y)
21139e2f89bSBarry Smith {
212a4d4d686SBarry Smith   MatSNESFDMFCtx ctx;
213fae171e0SBarry Smith   SNES           snes;
214a4d4d686SBarry Smith   Scalar         h, mone = -1.0;
215fae171e0SBarry Smith   Vec            w,U,F;
216a305c92eSSatish Balay   int            ierr, (*eval_fct)(SNES,Vec,Vec)=0;
21739e2f89bSBarry Smith 
2183a40ed3dSBarry Smith   PetscFunctionBegin;
2199a6cb015SBarry Smith   /* We log matrix-free matrix-vector products separately, so that we can
2209a6cb015SBarry Smith      separate the performance monitoring from the cases that use conventional
2219a6cb015SBarry Smith      storage.  We may eventually modify event logging to associate events
2229a6cb015SBarry Smith      with particular objects, hence alleviating the more general problem. */
22356cd22aeSBarry Smith   PLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);
22456cd22aeSBarry Smith 
2256e38a044SBarry Smith   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
226fae171e0SBarry Smith   snes = ctx->snes;
227fae171e0SBarry Smith   w    = ctx->w;
228fae171e0SBarry Smith 
22978b31e54SBarry Smith   ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr);
23083e56afdSLois Curfman McInnes   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
23183e56afdSLois Curfman McInnes     eval_fct = SNESComputeFunction;
23278b31e54SBarry Smith     ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr);
233a4d4d686SBarry Smith   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
23483e56afdSLois Curfman McInnes     eval_fct = SNESComputeGradient;
23583e56afdSLois Curfman McInnes     ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr);
236a4d4d686SBarry Smith   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,0,"Invalid method class");
23750361f65SLois Curfman McInnes 
2389a6cb015SBarry Smith   if (!ctx->ops->compute) {
2399a6cb015SBarry Smith     ierr = MatSNESFDMFSetType(mat,"default");CHKERRQ(ierr);
2409a6cb015SBarry Smith     ierr = MatSNESFDMFSetFromOptions(mat);CHKERRQ(ierr);
2419a6cb015SBarry Smith   }
2429a6cb015SBarry Smith   ierr = (*ctx->ops->compute)(ctx,U,a,&h); CHKERRQ(ierr);
243a4d4d686SBarry Smith 
244a4d4d686SBarry Smith   /* keep a record of the current differencing parameter h */
245a4d4d686SBarry Smith   ctx->currenth = h;
246a4d4d686SBarry Smith #if defined(USE_PETSC_COMPLEX)
247a4d4d686SBarry Smith   PLogInfo(mat,"Current differencing parameter: %g + %g i\n",PetscReal(h),PetscImaginary(h));
248a4d4d686SBarry Smith #else
249a4d4d686SBarry Smith   PLogInfo(mat,"Current differencing parameter: %g\n",h);
250a4d4d686SBarry Smith #endif
251a4d4d686SBarry Smith   if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
252a4d4d686SBarry Smith     ctx->historyh[ctx->ncurrenth++] = h;
253be726c96SBarry Smith   } else {
254be726c96SBarry Smith     ctx->ncurrenth++;
255a4d4d686SBarry Smith   }
256a4d4d686SBarry Smith 
257a4d4d686SBarry Smith   /* Evaluate function at F(u + ha) */
258a4d4d686SBarry Smith   ierr = VecWAXPY(&h,a,U,w); CHKERRQ(ierr);
259a4d4d686SBarry Smith   ierr = eval_fct(snes,w,y); CHKERRQ(ierr);
260a4d4d686SBarry Smith 
261a4d4d686SBarry Smith   ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr);
262a4d4d686SBarry Smith   h = 1.0/h;
263a4d4d686SBarry Smith   ierr = VecScale(&h,y); CHKERRQ(ierr);
264a4d4d686SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);}
265a4d4d686SBarry Smith 
266a4d4d686SBarry Smith   PLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);
267a4d4d686SBarry Smith   PetscFunctionReturn(0);
268a4d4d686SBarry Smith }
269a4d4d686SBarry Smith 
270a4d4d686SBarry Smith #undef __FUNC__
271a4d4d686SBarry Smith #define __FUNC__ "MatCreateSNESFDMF"
272a4d4d686SBarry Smith /*@C
273a4d4d686SBarry Smith    MatCreateSNESFDMF - Creates a matrix-free matrix
274a4d4d686SBarry Smith    context for use with a SNES solver.  This matrix can be used as
275a4d4d686SBarry Smith    the Jacobian argument for the routine SNESSetJacobian().
276a4d4d686SBarry Smith 
277a4d4d686SBarry Smith    Collective on SNES and Vec
278a4d4d686SBarry Smith 
279a4d4d686SBarry Smith    Input Parameters:
280a4d4d686SBarry Smith +  snes - the SNES context
281a4d4d686SBarry Smith -  x - vector where SNES solution is to be stored.
282a4d4d686SBarry Smith 
283a4d4d686SBarry Smith    Output Parameter:
284a4d4d686SBarry Smith .  J - the matrix-free matrix
285a4d4d686SBarry Smith 
286a4d4d686SBarry Smith    Notes:
287a4d4d686SBarry Smith    The matrix-free matrix context merely contains the function pointers
288a4d4d686SBarry Smith    and work space for performing finite difference approximations of
2899a6cb015SBarry Smith    Jacobian-vector products, J(u)*a,
2909a6cb015SBarry Smith 
2919a6cb015SBarry Smith    The default code uses the following approach to compute h
292a4d4d686SBarry Smith 
293a4d4d686SBarry Smith .vb
294a4d4d686SBarry Smith      J(u)*a = [J(u+h*a) - J(u)]/h where
295a4d4d686SBarry Smith      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
296a4d4d686SBarry Smith        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
297a4d4d686SBarry Smith  where
298a4d4d686SBarry Smith      error_rel = square root of relative error in function evaluation
299a4d4d686SBarry Smith      umin = minimum iterate parameter
300a4d4d686SBarry Smith .ve
301a4d4d686SBarry Smith 
3029a6cb015SBarry Smith    The user can set the error_rel via MatSNESFDMFSetFunctionError() and
3039a6cb015SBarry Smith    umin via MatSNESFDMFDefaultSetUmin()
304a4d4d686SBarry Smith    See the nonlinear solvers chapter of the users manual for details.
305a4d4d686SBarry Smith 
306a4d4d686SBarry Smith    The user should call MatDestroy() when finished with the matrix-free
307a4d4d686SBarry Smith    matrix context.
308a4d4d686SBarry Smith 
309a4d4d686SBarry Smith    Options Database Keys:
310a4d4d686SBarry Smith +  -snes_mf_err <error_rel> - Sets error_rel
3119a6cb015SBarry Smith .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
312a4d4d686SBarry Smith -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
313a4d4d686SBarry Smith 
314a4d4d686SBarry Smith .keywords: SNES, default, matrix-free, create, matrix
315a4d4d686SBarry Smith 
3169a6cb015SBarry Smith .seealso: MatDestroy(), MatSNESFDMFSetFunctionError(), MatSNESFDMFDefaultSetUmin()
317a4d4d686SBarry Smith           MatSNESFDMFSetHHistory(), MatSNESFDMFResetHHistory(),
3189a6cb015SBarry Smith           MatSNESFDMFGetH(),MatSNESFDMFKSPMonitor(), MatSNESFDMFRegister()
319a4d4d686SBarry Smith 
320a4d4d686SBarry Smith @*/
321a4d4d686SBarry Smith int MatCreateSNESFDMF(SNES snes,Vec x, Mat *J)
322a4d4d686SBarry Smith {
323a4d4d686SBarry Smith   MPI_Comm       comm;
324a4d4d686SBarry Smith   MatSNESFDMFCtx mfctx;
3259a6cb015SBarry Smith   int            n, nloc, ierr;
326a4d4d686SBarry Smith 
327a4d4d686SBarry Smith   PetscFunctionBegin;
328a4d4d686SBarry Smith   mfctx = (MatSNESFDMFCtx) PetscMalloc(sizeof(struct _p_MatSNESFDMFCtx)); CHKPTRQ(mfctx);
329a4d4d686SBarry Smith   PLogObjectMemory(snes,sizeof(MatSNESFDMFCtx));
3309a6cb015SBarry Smith   mfctx->comm         = snes->comm;
331a4d4d686SBarry Smith   mfctx->sp           = 0;
332a4d4d686SBarry Smith   mfctx->snes         = snes;
333a4d4d686SBarry Smith   mfctx->error_rel    = 1.e-8; /* assumes double precision */
334a4d4d686SBarry Smith   mfctx->currenth     = 0.0;
335a4d4d686SBarry Smith   mfctx->historyh     = PETSC_NULL;
336a4d4d686SBarry Smith   mfctx->ncurrenth    = 0;
337a4d4d686SBarry Smith   mfctx->maxcurrenth  = 0;
338a4d4d686SBarry Smith 
3399a6cb015SBarry Smith   /*
3409a6cb015SBarry Smith      Create the empty data structure to contain compute-h routines.
3419a6cb015SBarry Smith      These will be filled in below from the command line options or
3429a6cb015SBarry Smith      a later call with MatSNESFDMFSetType() or if that is not called
3439a6cb015SBarry Smith      then it will default in the first use of MatSNESFDMFMult_private()
3449a6cb015SBarry Smith   */
3459a6cb015SBarry Smith   mfctx->ops                 = (MFOps *)PetscMalloc(sizeof(MFOps)); CHKPTRQ(mfctx->ops);
3469a6cb015SBarry Smith   mfctx->ops->compute        = 0;
3479a6cb015SBarry Smith   mfctx->ops->destroy        = 0;
3489a6cb015SBarry Smith   mfctx->ops->view           = 0;
3499a6cb015SBarry Smith   mfctx->ops->printhelp      = 0;
3509a6cb015SBarry Smith   mfctx->ops->setfromoptions = 0;
3519a6cb015SBarry Smith   mfctx->hctx                = 0;
3529a6cb015SBarry Smith 
353a4d4d686SBarry Smith   ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr);
354a4d4d686SBarry Smith   ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr);
355a4d4d686SBarry Smith   ierr = VecGetSize(x,&n); CHKERRQ(ierr);
356a4d4d686SBarry Smith   ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr);
357a4d4d686SBarry Smith   ierr = MatCreateShell(comm,nloc,n,n,n,mfctx,J); CHKERRQ(ierr);
358a4d4d686SBarry Smith   ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)MatSNESFDMFMult_Private);CHKERRQ(ierr);
359a4d4d686SBarry Smith   ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)MatSNESFDMFDestroy_Private);CHKERRQ(ierr);
360a4d4d686SBarry Smith   ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)MatSNESFDMFView_Private); CHKERRQ(ierr);
361be726c96SBarry Smith   ierr = MatShellSetOperation(*J,MATOP_ASSEMBLY_END,(void *)MatSNESFDMFAssemblyEnd_Private);CHKERRQ(ierr);
362a4d4d686SBarry Smith   PLogObjectParent(*J,mfctx->w);
363a4d4d686SBarry Smith   PLogObjectParent(snes,*J);
3649a6cb015SBarry Smith 
3659a6cb015SBarry Smith   mfctx->mat = *J;
3669a6cb015SBarry Smith 
3679a6cb015SBarry Smith 
3689a6cb015SBarry Smith   PetscFunctionReturn(0);
3699a6cb015SBarry Smith }
3709a6cb015SBarry Smith 
3719a6cb015SBarry Smith #undef __FUNC__
3729a6cb015SBarry Smith #define __FUNC__ "MatSNESFDMFGetH"
3739a6cb015SBarry Smith /*@
3749a6cb015SBarry Smith    MatSNESFDMFSetFromOptions - Sets the MatSNESFDMF options from the command line
3759a6cb015SBarry Smith      parameter.
3769a6cb015SBarry Smith 
3779a6cb015SBarry Smith    Collective on Mat
3789a6cb015SBarry Smith 
3799a6cb015SBarry Smith    Input Parameters:
3809a6cb015SBarry Smith .   mat - the matrix obtained with MatCreateSNESFDMF()
3819a6cb015SBarry Smith 
3829a6cb015SBarry Smith .keywords: SNES, matrix-free, parameters
3839a6cb015SBarry Smith 
3849a6cb015SBarry Smith .seealso: MatCreateSNESFDMF(),MatSNESFDMFSetHHistory(),
3859a6cb015SBarry Smith           MatSNESFDMFResetHHistory(),MatSNESFDMFKSPMonitor()
3869a6cb015SBarry Smith @*/
3879a6cb015SBarry Smith int MatSNESFDMFSetFromOptions(Mat mat)
3889a6cb015SBarry Smith {
3899a6cb015SBarry Smith   MatSNESFDMFCtx mfctx;
3909a6cb015SBarry Smith   int            ierr,flg;
3919a6cb015SBarry Smith   char           ftype[256],p[64];
3929a6cb015SBarry Smith 
3939a6cb015SBarry Smith   PetscFunctionBegin;
3949a6cb015SBarry Smith   ierr = MatShellGetContext(mat,(void **)&mfctx); CHKERRQ(ierr);
3959a6cb015SBarry Smith   if (mfctx) {
3969a6cb015SBarry Smith     /* allow user to set the type */
3979a6cb015SBarry Smith     ierr = OptionsGetString(mfctx->snes->prefix,"-snes_mf_type",ftype,256,&flg);CHKERRQ(ierr);
3989a6cb015SBarry Smith     if (flg) {
3999a6cb015SBarry Smith       ierr = MatSNESFDMFSetType(mat,ftype);CHKERRQ(ierr);
4009a6cb015SBarry Smith     }
4019a6cb015SBarry Smith 
4029a6cb015SBarry Smith     ierr = OptionsGetDouble(mfctx->snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg);CHKERRQ(ierr);
4039a6cb015SBarry Smith     if (mfctx->ops->setfromoptions) {
4049a6cb015SBarry Smith       ierr = (*mfctx->ops->setfromoptions)(mfctx);CHKERRQ(ierr);
4059a6cb015SBarry Smith     }
4069a6cb015SBarry Smith 
4079a6cb015SBarry Smith     ierr = OptionsHasName(PETSC_NULL,"-help",&flg); CHKERRQ(ierr);
4089a6cb015SBarry Smith     PetscStrcpy(p,"-");
4099a6cb015SBarry Smith     if (mfctx->snes->prefix) PetscStrcat(p,mfctx->snes->prefix);
4109a6cb015SBarry Smith     if (flg) {
4119a6cb015SBarry Smith       (*PetscHelpPrintf)(mfctx->snes->comm,"   %ssnes_mf_err <err>: set sqrt rel error in function (default %g)\n",p,mfctx->error_rel);
4129a6cb015SBarry Smith       if (mfctx->ops->printhelp) {
4139a6cb015SBarry Smith         (*mfctx->ops->printhelp)(mfctx);CHKERRQ(ierr);
4149a6cb015SBarry Smith       }
4159a6cb015SBarry Smith     }
4169a6cb015SBarry Smith   }
417a4d4d686SBarry Smith   PetscFunctionReturn(0);
418a4d4d686SBarry Smith }
419a4d4d686SBarry Smith 
420a4d4d686SBarry Smith #undef __FUNC__
421a4d4d686SBarry Smith #define __FUNC__ "MatSNESFDMFGetH"
422a4d4d686SBarry Smith /*@
423a4d4d686SBarry Smith    MatSNESFDMFGetH - Gets the last h that was used as the differencing
424a4d4d686SBarry Smith      parameter.
425a4d4d686SBarry Smith 
426a4d4d686SBarry Smith    Not Collective
427a4d4d686SBarry Smith 
428a4d4d686SBarry Smith    Input Parameters:
429a4d4d686SBarry Smith .   mat - the matrix obtained with MatCreateSNESFDMF()
430a4d4d686SBarry Smith 
431a4d4d686SBarry Smith    Output Paramter:
432a4d4d686SBarry Smith .  h - the differencing step size
433a4d4d686SBarry Smith 
434a4d4d686SBarry Smith .keywords: SNES, matrix-free, parameters
435a4d4d686SBarry Smith 
436a4d4d686SBarry Smith .seealso: MatCreateSNESFDMF(),MatSNESFDMFSetHHistory(),
437a4d4d686SBarry Smith           MatSNESFDMFResetHHistory(),MatSNESFDMFKSPMonitor()
438a4d4d686SBarry Smith @*/
439a4d4d686SBarry Smith int MatSNESFDMFGetH(Mat mat,Scalar *h)
440a4d4d686SBarry Smith {
441a4d4d686SBarry Smith   MatSNESFDMFCtx ctx;
442a4d4d686SBarry Smith   int            ierr;
443a4d4d686SBarry Smith 
444a4d4d686SBarry Smith   PetscFunctionBegin;
445a4d4d686SBarry Smith   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
446a4d4d686SBarry Smith   if (ctx) {
447a4d4d686SBarry Smith     *h = ctx->currenth;
448a4d4d686SBarry Smith   }
449a4d4d686SBarry Smith   PetscFunctionReturn(0);
450a4d4d686SBarry Smith }
451a4d4d686SBarry Smith 
452a4d4d686SBarry Smith #undef __FUNC__
453a4d4d686SBarry Smith #define __FUNC__ "MatSNESFDMFKSPMonitor"
454a4d4d686SBarry Smith /*
455a4d4d686SBarry Smith    MatSNESFDMFKSPMonitor - A KSP monitor for use with the default PETSc
456a4d4d686SBarry Smith       SNES matrix free routines. Prints the h differencing parameter used at each
457a4d4d686SBarry Smith       timestep.
458a4d4d686SBarry Smith 
459a4d4d686SBarry Smith */
460a4d4d686SBarry Smith int MatSNESFDMFKSPMonitor(KSP ksp,int n,double rnorm,void *dummy)
461a4d4d686SBarry Smith {
462a4d4d686SBarry Smith   PC             pc;
463a4d4d686SBarry Smith   MatSNESFDMFCtx ctx;
464a4d4d686SBarry Smith   int            ierr;
465a4d4d686SBarry Smith   Mat            mat;
466a4d4d686SBarry Smith   MPI_Comm       comm;
467a4d4d686SBarry Smith   PetscTruth     nonzeroinitialguess;
468a4d4d686SBarry Smith 
469a4d4d686SBarry Smith   PetscFunctionBegin;
470a4d4d686SBarry Smith   ierr = PetscObjectGetComm((PetscObject)ksp,&comm);CHKERRQ(ierr);
471a4d4d686SBarry Smith   ierr = KSPGetPC(ksp,&pc); CHKERRQ(ierr);
472a4d4d686SBarry Smith   ierr = KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);CHKERRQ(ierr);
473a4d4d686SBarry Smith   ierr = PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
474a4d4d686SBarry Smith   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
4759a6cb015SBarry Smith   if (!ctx) {
4769a6cb015SBarry Smith     SETERRQ(1,1,"Matrix is not a matrix free shell matrix");
4779a6cb015SBarry Smith   }
478a4d4d686SBarry Smith   if (n > 0 || nonzeroinitialguess) {
479a4d4d686SBarry Smith #if defined(USE_PETSC_COMPLEX)
480a4d4d686SBarry Smith     PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g i\n",n,rnorm,
481a4d4d686SBarry Smith                 PetscReal(ctx->currenth),PetscImaginary(ctx->currenth));
482a4d4d686SBarry Smith #else
483a4d4d686SBarry Smith     PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);
484a4d4d686SBarry Smith #endif
485a4d4d686SBarry Smith   } else {
486a4d4d686SBarry Smith     PetscPrintf(comm,"%d KSP Residual norm %14.12e\n",n,rnorm);
487a4d4d686SBarry Smith   }
488a4d4d686SBarry Smith   PetscFunctionReturn(0);
489a4d4d686SBarry Smith }
490a4d4d686SBarry Smith 
491a4d4d686SBarry Smith #undef __FUNC__
4929a6cb015SBarry Smith #define __FUNC__ "MatSNESFDMFSetFunctionError"
493a4d4d686SBarry Smith /*@
4949a6cb015SBarry Smith    MatSNESFDMFSetFunctionError - Sets the error_rel for the approximation of
495a4d4d686SBarry Smith    matrix-vector products using finite differences.
496a4d4d686SBarry Smith 
497a4d4d686SBarry Smith    Collective on Mat
498a4d4d686SBarry Smith 
499a4d4d686SBarry Smith    Input Parameters:
500a4d4d686SBarry Smith +  mat - the matrix free matrix created via MatCreateSNESFDMF()
5019a6cb015SBarry Smith -  error_rel - relative error (should be set to the square root of
502a4d4d686SBarry Smith                the relative error in the function evaluations)
503a4d4d686SBarry Smith 
504a4d4d686SBarry Smith    Notes:
505a4d4d686SBarry Smith    The default matrix-free matrix-vector product routine computes
506a4d4d686SBarry Smith .vb
507a4d4d686SBarry Smith      J(u)*a = [J(u+h*a) - J(u)]/h where
508a4d4d686SBarry Smith      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
509a4d4d686SBarry Smith        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
510a4d4d686SBarry Smith .ve
511a4d4d686SBarry Smith 
512a4d4d686SBarry Smith    Options Database Keys:
513a4d4d686SBarry Smith +  -snes_mf_err <error_rel> - Sets error_rel
514a4d4d686SBarry Smith 
515a4d4d686SBarry Smith .keywords: SNES, matrix-free, parameters
516a4d4d686SBarry Smith 
517a4d4d686SBarry Smith .seealso: MatCreateSNESFDMF(),MatSNESFDMFGetH(),
518a4d4d686SBarry Smith           MatSNESFDMFSetHHistory(), MatSNESFDMFResetHHistory(),
519a4d4d686SBarry Smith           MatSNESFDMFKSPMonitor()
520a4d4d686SBarry Smith @*/
5219a6cb015SBarry Smith int MatSNESFDMFSetFunctionError(Mat mat,double error)
522a4d4d686SBarry Smith {
523a4d4d686SBarry Smith   MatSNESFDMFCtx ctx;
524a4d4d686SBarry Smith   int            ierr;
525a4d4d686SBarry Smith 
526a4d4d686SBarry Smith   PetscFunctionBegin;
527a4d4d686SBarry Smith   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
528a4d4d686SBarry Smith   if (ctx) {
529a4d4d686SBarry Smith     if (error != PETSC_DEFAULT) ctx->error_rel = error;
530a4d4d686SBarry Smith   }
531a4d4d686SBarry Smith   PetscFunctionReturn(0);
532a4d4d686SBarry Smith }
533a4d4d686SBarry Smith 
534a4d4d686SBarry Smith #undef __FUNC__
535a4d4d686SBarry Smith #define __FUNC__ "MatSNESFDMFAddNullSpace"
536a4d4d686SBarry Smith /*@
537a4d4d686SBarry Smith    MatSNESFDMFAddNullSpace - Provides a null space that
538a4d4d686SBarry Smith    an operator is supposed to have.  Since roundoff will create a
539a4d4d686SBarry Smith    small component in the null space, if you know the null space
540a4d4d686SBarry Smith    you may have it automatically removed.
541a4d4d686SBarry Smith 
542a4d4d686SBarry Smith    Collective on Mat
543a4d4d686SBarry Smith 
544a4d4d686SBarry Smith    Input Parameters:
545a4d4d686SBarry Smith +  J - the matrix-free matrix context
546a4d4d686SBarry Smith .  has_cnst - PETSC_TRUE or PETSC_FALSE, indicating if null space has constants
547a4d4d686SBarry Smith .  n - number of vectors (excluding constant vector) in null space
548a4d4d686SBarry Smith -  vecs - the vectors that span the null space (excluding the constant vector);
549a4d4d686SBarry Smith           these vectors must be orthonormal
550a4d4d686SBarry Smith 
551a4d4d686SBarry Smith .keywords: SNES, matrix-free, null space
552a4d4d686SBarry Smith 
553a4d4d686SBarry Smith .seealso: MatSNESFDMFGetH(), MatCreateSNESFDMF(),
554a4d4d686SBarry Smith           MatSNESFDMFSetHHistory(), MatSNESFDMFResetHHistory(),
5559a6cb015SBarry Smith           MatSNESFDMFKSPMonitor(), MatSNESFDMFErrorRel()
556a4d4d686SBarry Smith 
557a4d4d686SBarry Smith @*/
558a4d4d686SBarry Smith int MatSNESFDMFAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs)
559a4d4d686SBarry Smith {
560a4d4d686SBarry Smith   int            ierr;
561a4d4d686SBarry Smith   MatSNESFDMFCtx ctx;
562a4d4d686SBarry Smith   MPI_Comm       comm;
563a4d4d686SBarry Smith 
564a4d4d686SBarry Smith   PetscFunctionBegin;
565a4d4d686SBarry Smith   PetscObjectGetComm((PetscObject)J,&comm);
566a4d4d686SBarry Smith 
567a4d4d686SBarry Smith   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
568a4d4d686SBarry Smith   /* no context indicates that it is not the "matrix free" matrix type */
569a4d4d686SBarry Smith   if (!ctx) PetscFunctionReturn(0);
570a4d4d686SBarry Smith   ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr);
571a4d4d686SBarry Smith   PetscFunctionReturn(0);
572a4d4d686SBarry Smith }
573a4d4d686SBarry Smith 
574a4d4d686SBarry Smith #undef __FUNC__
575a4d4d686SBarry Smith #define __FUNC__ "MatSNESFDMFSetHHistory"
576a4d4d686SBarry Smith /*@
577a4d4d686SBarry Smith    MatSNESFDMFSetHHistory - Sets an array to collect a history
578a4d4d686SBarry Smith       of the differencing values h computed for the matrix free product
579a4d4d686SBarry Smith 
580a4d4d686SBarry Smith    Collective on Mat
581a4d4d686SBarry Smith 
582a4d4d686SBarry Smith    Input Parameters:
583a4d4d686SBarry Smith +  J - the matrix-free matrix context
584a4d4d686SBarry Smith .  histroy - space to hold the h history
585a4d4d686SBarry Smith -  nhistory - number of entries in history, if more h are generated than
586a4d4d686SBarry Smith               nhistory the later ones are discarded
587a4d4d686SBarry Smith 
588a4d4d686SBarry Smith    Notes:
589a4d4d686SBarry Smith     Use MatSNESFDMFResetHHistory() to reset the history counter
590a4d4d686SBarry Smith     and collect a new batch of h.
591a4d4d686SBarry Smith 
592a4d4d686SBarry Smith .keywords: SNES, matrix-free, h history, differencing history
593a4d4d686SBarry Smith 
594a4d4d686SBarry Smith .seealso: MatSNESFDMFGetH(), MatCreateSNESFDMF(),
595a4d4d686SBarry Smith           MatSNESFDMFResetHHistory(),
5969a6cb015SBarry Smith           MatSNESFDMFKSPMonitor(), MatSNESFDMFSetFunctionError()
597a4d4d686SBarry Smith 
598a4d4d686SBarry Smith @*/
599a4d4d686SBarry Smith int MatSNESFDMFSetHHistory(Mat J,Scalar *history,int nhistory)
600a4d4d686SBarry Smith {
601a4d4d686SBarry Smith   int            ierr;
602a4d4d686SBarry Smith   MatSNESFDMFCtx ctx;
603a4d4d686SBarry Smith 
604a4d4d686SBarry Smith   PetscFunctionBegin;
605a4d4d686SBarry Smith 
606a4d4d686SBarry Smith   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
607a4d4d686SBarry Smith   /* no context indicates that it is not the "matrix free" matrix type */
608a4d4d686SBarry Smith   if (!ctx) PetscFunctionReturn(0);
609a4d4d686SBarry Smith   ctx->historyh    = history;
610a4d4d686SBarry Smith   ctx->maxcurrenth = nhistory;
611a4d4d686SBarry Smith   ctx->currenth    = 0;
612a4d4d686SBarry Smith 
613a4d4d686SBarry Smith   PetscFunctionReturn(0);
614a4d4d686SBarry Smith }
615a4d4d686SBarry Smith 
616a4d4d686SBarry Smith #undef __FUNC__
617a4d4d686SBarry Smith #define __FUNC__ "MatSNESFDMFResetHHistory"
618a4d4d686SBarry Smith /*@
619a4d4d686SBarry Smith    MatSNESFDMFResetHHistory - Resets the counter to zero to begin
620a4d4d686SBarry Smith       collecting a new set of differencing histories.
621a4d4d686SBarry Smith 
622a4d4d686SBarry Smith    Collective on Mat
623a4d4d686SBarry Smith 
624a4d4d686SBarry Smith    Input Parameters:
625a4d4d686SBarry Smith .  J - the matrix-free matrix context
626a4d4d686SBarry Smith 
627a4d4d686SBarry Smith    Notes:
628a4d4d686SBarry Smith     Use MatSNESFDMFSetHHistory() to create the original history counter
629a4d4d686SBarry Smith 
630a4d4d686SBarry Smith .keywords: SNES, matrix-free, h history, differencing history
631a4d4d686SBarry Smith 
632a4d4d686SBarry Smith .seealso: MatSNESFDMFGetH(), MatCreateSNESFDMF(),
633a4d4d686SBarry Smith           MatSNESFDMFSetHHistory(),
6349a6cb015SBarry Smith           MatSNESFDMFKSPMonitor(), MatSNESFDMFSetFunctionError()
635a4d4d686SBarry Smith 
636a4d4d686SBarry Smith @*/
637a4d4d686SBarry Smith int MatSNESFDMFResetHHistory(Mat J)
638a4d4d686SBarry Smith {
639a4d4d686SBarry Smith   int            ierr;
640a4d4d686SBarry Smith   MatSNESFDMFCtx ctx;
641a4d4d686SBarry Smith 
642a4d4d686SBarry Smith   PetscFunctionBegin;
643a4d4d686SBarry Smith 
644a4d4d686SBarry Smith   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
645a4d4d686SBarry Smith   /* no context indicates that it is not the "matrix free" matrix type */
646a4d4d686SBarry Smith   if (!ctx) PetscFunctionReturn(0);
647be726c96SBarry Smith   ctx->ncurrenth    = 0;
648a4d4d686SBarry Smith 
649a4d4d686SBarry Smith   PetscFunctionReturn(0);
650a4d4d686SBarry Smith }
651a4d4d686SBarry Smith 
652