xref: /petsc/src/snes/mf/snesmfj.c (revision e884886f040fd140b63a22c479f657cf835a1983)
163dd3a1aSKris Buschelman #define PETSCSNES_DLL
281e6777dSBarry Smith 
3b9147fbbSdalcinl #include "include/private/matimpl.h"
4325e03aeSBarry Smith #include "src/snes/mf/snesmfj.h"   /*I  "petscsnes.h"   I*/
581e6777dSBarry Smith 
6*e884886fSBarry Smith #undef __FUNCT__
7*e884886fSBarry Smith #define __FUNCT__ "MatMFFDComputeJacobian"
8*e884886fSBarry Smith /*@
9*e884886fSBarry Smith    MatMFFDComputeJacobian - Tells the matrix-free Jacobian object the new location at which
10*e884886fSBarry Smith        Jacobian matrix vector products will be computed at, i.e. J(x) * a.
11*e884886fSBarry Smith 
12*e884886fSBarry Smith    Collective on SNES
13*e884886fSBarry Smith 
14*e884886fSBarry Smith    Input Parameters:
15*e884886fSBarry Smith +   snes - the nonlinear solver context
16*e884886fSBarry Smith .   x - the point at which the Jacobian vector products will be performed
17*e884886fSBarry Smith .   jac - the matrix-free Jacobian object
18*e884886fSBarry Smith .   B - either the same as jac or another matrix type (ignored)
19*e884886fSBarry Smith .   flag - not relevent for matrix-free form
20*e884886fSBarry Smith -   dummy - the user context (ignored)
21*e884886fSBarry Smith 
22*e884886fSBarry Smith    Level: developer
23*e884886fSBarry Smith 
24*e884886fSBarry Smith    Notes:
25*e884886fSBarry Smith      This can be passed into SNESSetJacobian() when using a completely matrix-free solver,
26*e884886fSBarry Smith      that is the B matrix is also the same matrix operator. This is used when you select
27*e884886fSBarry Smith      -mat_mffd but rarely used directly by users.
28*e884886fSBarry Smith 
29*e884886fSBarry Smith .seealso: MatMFFDGetH(), MatCreateSNESMF(),
30*e884886fSBarry Smith           MatMFFDSetHHistory(),
31*e884886fSBarry Smith           MatMFFDKSPMonitor(), MatMFFDSetFunctionError(), MatMFFDCreate(), SNESSetJacobian()
32*e884886fSBarry Smith 
33*e884886fSBarry Smith @*/
34*e884886fSBarry Smith PetscErrorCode PETSCMAT_DLLEXPORT MatMFFDComputeJacobian(SNES *snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
35*e884886fSBarry Smith {
36*e884886fSBarry Smith   PetscErrorCode ierr;
37*e884886fSBarry Smith   PetscFunctionBegin;
38*e884886fSBarry Smith   ierr = MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
39*e884886fSBarry Smith   ierr = MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
40*e884886fSBarry Smith   PetscFunctionReturn(0);
41*e884886fSBarry Smith }
42*e884886fSBarry Smith 
43b0a32e0cSBarry Smith PetscFList MatSNESMPetscFList         = 0;
444c49b128SBarry Smith PetscTruth MatSNESMFRegisterAllCalled = PETSC_FALSE;
45a4d4d686SBarry Smith 
4663dd3a1aSKris Buschelman PetscCookie PETSCSNES_DLLEXPORT MATSNESMFCTX_COOKIE = 0;
4746129b97SKris Buschelman PetscEvent  MATSNESMF_Mult = 0;
4846129b97SKris Buschelman 
494a2ae208SSatish Balay #undef __FUNCT__
504a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFSetType"
51fd4bdd07SBarry Smith /*@C
5265f2ba5bSLois Curfman McInnes     MatSNESMFSetType - Sets the method that is used to compute the
53b0a32e0cSBarry Smith     differencing parameter for finite differene matrix-free formulations.
549a6cb015SBarry Smith 
559a6cb015SBarry Smith     Input Parameters:
567e9d5209SBarry Smith +   mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMF()
577e9d5209SBarry Smith           or MatSetType(mat,MATMFFD);
58efb30889SBarry Smith -   ftype - the type requested, either MATSNESMF_WP or MATSNESMF_DS
599a6cb015SBarry Smith 
6015091d37SBarry Smith     Level: advanced
6115091d37SBarry Smith 
6265f2ba5bSLois Curfman McInnes     Notes:
6365f2ba5bSLois Curfman McInnes     For example, such routines can compute h for use in
6465f2ba5bSLois Curfman McInnes     Jacobian-vector products of the form
6565f2ba5bSLois Curfman McInnes 
6665f2ba5bSLois Curfman McInnes                         F(x+ha) - F(x)
67ef4ad1fdSLois Curfman McInnes           F'(u)a  ~=  ----------------
6865f2ba5bSLois Curfman McInnes                               h
6965f2ba5bSLois Curfman McInnes 
70f1af5d2fSBarry Smith .seealso: MatCreateSNESMF(), MatSNESMFRegisterDynamic)
719a6cb015SBarry Smith @*/
722e90c967SHong Zhang PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetType(Mat mat,MatSNESMFType ftype)
73b9fa9cd0SBarry Smith {
7478392ef1SBarry Smith   PetscErrorCode ierr,(*r)(MatSNESMF);
7578392ef1SBarry Smith   MatSNESMF      ctx = (MatSNESMF)mat->data;
766831982aSBarry Smith   PetscTruth     match;
77a4d4d686SBarry Smith 
78a4d4d686SBarry Smith   PetscFunctionBegin;
794482741eSBarry Smith   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
804482741eSBarry Smith   PetscValidCharPointer(ftype,2);
810f5bd95cSBarry Smith 
829a6cb015SBarry Smith   /* already set, so just return */
836831982aSBarry Smith   ierr = PetscTypeCompare((PetscObject)ctx,ftype,&match);CHKERRQ(ierr);
840f5bd95cSBarry Smith   if (match) PetscFunctionReturn(0);
85a4d4d686SBarry Smith 
869a6cb015SBarry Smith   /* destroy the old one if it exists */
879a6cb015SBarry Smith   if (ctx->ops->destroy) {
889a6cb015SBarry Smith     ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);
899a6cb015SBarry Smith   }
909a6cb015SBarry Smith 
91b9617806SBarry Smith   ierr =  PetscFListFind(ctx->comm,MatSNESMPetscFList,ftype,(void (**)(void)) &r);CHKERRQ(ierr);
92958c9bccSBarry Smith   if (!r) SETERRQ1(PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown MatSNESMF type %s given",ftype);
939a6cb015SBarry Smith   ierr = (*r)(ctx);CHKERRQ(ierr);
946831982aSBarry Smith   ierr = PetscObjectChangeTypeName((PetscObject)ctx,ftype);CHKERRQ(ierr);
959a6cb015SBarry Smith   PetscFunctionReturn(0);
969a6cb015SBarry Smith }
979a6cb015SBarry Smith 
986849ba73SBarry Smith typedef PetscErrorCode (*FCN1)(Vec,void*); /* force argument to next function to not be extern C*/
99c5c390f1SBarry Smith EXTERN_C_BEGIN
10087828ca2SBarry Smith #undef __FUNCT__
10187828ca2SBarry Smith #define __FUNCT__ "MatSNESMFSetFunctioniBase_FD"
10263dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctioniBase_FD(Mat mat,FCN1 func)
10387828ca2SBarry Smith {
10478392ef1SBarry Smith   MatSNESMF ctx = (MatSNESMF)mat->data;
10587828ca2SBarry Smith 
10687828ca2SBarry Smith   PetscFunctionBegin;
10787828ca2SBarry Smith   ctx->funcisetbase = func;
10887828ca2SBarry Smith   PetscFunctionReturn(0);
10987828ca2SBarry Smith }
110c5c390f1SBarry Smith EXTERN_C_END
11187828ca2SBarry Smith 
112a7cc72afSBarry Smith typedef PetscErrorCode (*FCN2)(PetscInt,Vec,PetscScalar*,void*); /* force argument to next function to not be extern C*/
113c5c390f1SBarry Smith EXTERN_C_BEGIN
11487828ca2SBarry Smith #undef __FUNCT__
11587828ca2SBarry Smith #define __FUNCT__ "MatSNESMFSetFunctioni_FD"
11663dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctioni_FD(Mat mat,FCN2 funci)
11787828ca2SBarry Smith {
11878392ef1SBarry Smith   MatSNESMF ctx = (MatSNESMF)mat->data;
11987828ca2SBarry Smith 
12087828ca2SBarry Smith   PetscFunctionBegin;
12187828ca2SBarry Smith   ctx->funci = funci;
12287828ca2SBarry Smith   PetscFunctionReturn(0);
12387828ca2SBarry Smith }
124c5c390f1SBarry Smith EXTERN_C_END
12587828ca2SBarry Smith 
1269a6cb015SBarry Smith 
1274a2ae208SSatish Balay #undef __FUNCT__
1284a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFRegister"
12978392ef1SBarry Smith PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(MatSNESMF))
1309a6cb015SBarry Smith {
131dfbe8321SBarry Smith   PetscErrorCode ierr;
132e2d1d2b7SBarry Smith   char           fullname[PETSC_MAX_PATH_LEN];
1339a6cb015SBarry Smith 
1349a6cb015SBarry Smith   PetscFunctionBegin;
135b0a32e0cSBarry Smith   ierr = PetscFListConcat(path,name,fullname);CHKERRQ(ierr);
136c134de8dSSatish Balay   ierr = PetscFListAdd(&MatSNESMPetscFList,sname,fullname,(void (*)(void))function);CHKERRQ(ierr);
1379a6cb015SBarry Smith   PetscFunctionReturn(0);
1389a6cb015SBarry Smith }
1399a6cb015SBarry Smith 
1409a6cb015SBarry Smith 
1414a2ae208SSatish Balay #undef __FUNCT__
1424a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFRegisterDestroy"
1439a6cb015SBarry Smith /*@C
1445a655dc6SBarry Smith    MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were
145f1af5d2fSBarry Smith    registered by MatSNESMFRegisterDynamic).
1469a6cb015SBarry Smith 
1479a6cb015SBarry Smith    Not Collective
1489a6cb015SBarry Smith 
14915091d37SBarry Smith    Level: developer
15015091d37SBarry Smith 
1515a655dc6SBarry Smith .keywords: MatSNESMF, register, destroy
1529a6cb015SBarry Smith 
153f1af5d2fSBarry Smith .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll()
1549a6cb015SBarry Smith @*/
15563dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFRegisterDestroy(void)
1569a6cb015SBarry Smith {
157dfbe8321SBarry Smith   PetscErrorCode ierr;
1589a6cb015SBarry Smith 
1599a6cb015SBarry Smith   PetscFunctionBegin;
1601441b1d3SBarry Smith   ierr = PetscFListDestroy(&MatSNESMPetscFList);CHKERRQ(ierr);
1614c49b128SBarry Smith   MatSNESMFRegisterAllCalled = PETSC_FALSE;
1629a6cb015SBarry Smith   PetscFunctionReturn(0);
1639a6cb015SBarry Smith }
1649a6cb015SBarry Smith 
1659a6cb015SBarry Smith /* ----------------------------------------------------------------------------------------*/
1664a2ae208SSatish Balay #undef __FUNCT__
1678a124369SBarry Smith #define __FUNCT__ "MatDestroy_MFFD"
168dfbe8321SBarry Smith PetscErrorCode MatDestroy_MFFD(Mat mat)
169a4d4d686SBarry Smith {
170dfbe8321SBarry Smith   PetscErrorCode ierr;
17178392ef1SBarry Smith   MatSNESMF      ctx = (MatSNESMF)mat->data;
172fae171e0SBarry Smith 
1733a40ed3dSBarry Smith   PetscFunctionBegin;
174abc0a331SBarry Smith   if (ctx->w) {
175b9fa9cd0SBarry Smith     ierr = VecDestroy(ctx->w);CHKERRQ(ierr);
176ba6a83e5SMatthew Knepley   }
1779a6cb015SBarry Smith   if (ctx->ops->destroy) {ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);}
17874637425SBarry Smith   if (ctx->sp) {ierr = MatNullSpaceDestroy(ctx->sp);CHKERRQ(ierr);}
179d38fa0fbSBarry Smith   ierr = PetscHeaderDestroy(ctx);CHKERRQ(ierr);
180901853e0SKris Buschelman 
181901853e0SKris Buschelman   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetBase_C","",PETSC_NULL);CHKERRQ(ierr);
182901853e0SKris Buschelman   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C","",PETSC_NULL);CHKERRQ(ierr);
183901853e0SKris Buschelman   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C","",PETSC_NULL);CHKERRQ(ierr);
184901853e0SKris Buschelman   ierr = PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetCheckh_C","",PETSC_NULL);CHKERRQ(ierr);
185901853e0SKris Buschelman 
1863a40ed3dSBarry Smith   PetscFunctionReturn(0);
187b9fa9cd0SBarry Smith }
18850361f65SLois Curfman McInnes 
1894a2ae208SSatish Balay #undef __FUNCT__
1908a124369SBarry Smith #define __FUNCT__ "MatView_MFFD"
19139e2f89bSBarry Smith /*
1928a124369SBarry Smith    MatSNESMFView_MFFD - Views matrix-free parameters.
1938f6e3e37SBarry Smith 
19439e2f89bSBarry Smith */
195dfbe8321SBarry Smith PetscErrorCode MatView_MFFD(Mat J,PetscViewer viewer)
196eb9086c3SLois Curfman McInnes {
197dfbe8321SBarry Smith   PetscErrorCode ierr;
19878392ef1SBarry Smith   MatSNESMF      ctx = (MatSNESMF)J->data;
19932077d6dSBarry Smith   PetscTruth     iascii;
200eb9086c3SLois Curfman McInnes 
2013a40ed3dSBarry Smith   PetscFunctionBegin;
20232077d6dSBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
20332077d6dSBarry Smith   if (iascii) {
204b0a32e0cSBarry Smith      ierr = PetscViewerASCIIPrintf(viewer,"  SNES matrix-free approximation:\n");CHKERRQ(ierr);
205a83599f4SBarry Smith      ierr = PetscViewerASCIIPrintf(viewer,"    err=%G (relative error in function evaluation)\n",ctx->error_rel);CHKERRQ(ierr);
206473c83c3SBarry Smith      if (!ctx->type_name) {
207b0a32e0cSBarry Smith        ierr = PetscViewerASCIIPrintf(viewer,"    The compute h routine has not yet been set\n");CHKERRQ(ierr);
208473c83c3SBarry Smith      } else {
209b0a32e0cSBarry Smith        ierr = PetscViewerASCIIPrintf(viewer,"    Using %s compute h routine\n",ctx->type_name);CHKERRQ(ierr);
210473c83c3SBarry Smith      }
2119a6cb015SBarry Smith      if (ctx->ops->view) {
2129a6cb015SBarry Smith        ierr = (*ctx->ops->view)(ctx,viewer);CHKERRQ(ierr);
2139a6cb015SBarry Smith      }
2145cd90555SBarry Smith   } else {
21579a5c55eSBarry Smith     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name);
216eb9086c3SLois Curfman McInnes   }
2173a40ed3dSBarry Smith   PetscFunctionReturn(0);
218eb9086c3SLois Curfman McInnes }
219eb9086c3SLois Curfman McInnes 
2204a2ae208SSatish Balay #undef __FUNCT__
2218a124369SBarry Smith #define __FUNCT__ "MatAssemblyEnd_MFFD"
222be726c96SBarry Smith /*
22332dfb669SBarry Smith    MatAssemblyEnd_MFFD - Resets the ctx->ncurrenth to zero. This
22465f2ba5bSLois Curfman McInnes    allows the user to indicate the beginning of a new linear solve by calling
225be726c96SBarry Smith    MatAssemblyXXX() on the matrix free matrix. This then allows the
22665f2ba5bSLois Curfman McInnes    MatSNESMFCreate_WP() to properly compute ||U|| only the first time
22765f2ba5bSLois Curfman McInnes    in the linear solver rather than every time.
228be726c96SBarry Smith */
229dfbe8321SBarry Smith PetscErrorCode MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt)
230be726c96SBarry Smith {
231dfbe8321SBarry Smith   PetscErrorCode ierr;
23278392ef1SBarry Smith   MatSNESMF      j = (MatSNESMF)J->data;
233be726c96SBarry Smith 
234be726c96SBarry Smith   PetscFunctionBegin;
2355a655dc6SBarry Smith   ierr = MatSNESMFResetHHistory(J);CHKERRQ(ierr);
236b0a32e0cSBarry Smith   if (j->usesnes) {
2371d1367b7SBarry Smith     ierr = SNESGetSolution(j->snes,&j->current_u);CHKERRQ(ierr);
2381d1367b7SBarry Smith     ierr = SNESGetFunction(j->snes,&j->current_f,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
239958c9bccSBarry Smith     if (!j->w) {
2402740c1caSMatthew Knepley       ierr = VecDuplicate(j->current_u, &j->w);CHKERRQ(ierr);
2412740c1caSMatthew Knepley     }
2421d1367b7SBarry Smith   }
243c5c390f1SBarry Smith   j->vshift = 0.0;
244c5c390f1SBarry Smith   j->vscale = 1.0;
245be726c96SBarry Smith   PetscFunctionReturn(0);
246be726c96SBarry Smith }
247be726c96SBarry Smith 
2484a2ae208SSatish Balay #undef __FUNCT__
2498a124369SBarry Smith #define __FUNCT__ "MatMult_MFFD"
250eb9086c3SLois Curfman McInnes /*
251adb62b0dSMatthew Knepley   MatMult_MFFD - Default matrix-free form for Jacobian-vector product, y = F'(u)*a:
252a4d4d686SBarry Smith 
2539a6cb015SBarry Smith         y ~= (F(u + ha) - F(u))/h,
254eb9086c3SLois Curfman McInnes   where F = nonlinear function, as set by SNESSetFunction()
255eb9086c3SLois Curfman McInnes         u = current iterate
256eb9086c3SLois Curfman McInnes         h = difference interval
257eb9086c3SLois Curfman McInnes */
258dfbe8321SBarry Smith PetscErrorCode MatMult_MFFD(Mat mat,Vec a,Vec y)
25939e2f89bSBarry Smith {
26078392ef1SBarry Smith   MatSNESMF      ctx = (MatSNESMF)mat->data;
261fae171e0SBarry Smith   SNES           snes;
262efb30889SBarry Smith   PetscScalar    h;
263fae171e0SBarry Smith   Vec            w,U,F;
264dfbe8321SBarry Smith   PetscErrorCode ierr,(*eval_fct)(SNES,Vec,Vec)=0;
2654dc4c822SBarry Smith   PetscTruth     zeroa;
26639e2f89bSBarry Smith 
2673a40ed3dSBarry Smith   PetscFunctionBegin;
2689a6cb015SBarry Smith   /* We log matrix-free matrix-vector products separately, so that we can
2699a6cb015SBarry Smith      separate the performance monitoring from the cases that use conventional
2709a6cb015SBarry Smith      storage.  We may eventually modify event logging to associate events
2719a6cb015SBarry Smith      with particular objects, hence alleviating the more general problem. */
27246129b97SKris Buschelman   ierr = PetscLogEventBegin(MATSNESMF_Mult,a,y,0,0);CHKERRQ(ierr);
27356cd22aeSBarry Smith 
274fae171e0SBarry Smith   snes = ctx->snes;
275fae171e0SBarry Smith   w    = ctx->w;
2761d1367b7SBarry Smith   U    = ctx->current_u;
27750361f65SLois Curfman McInnes 
27885614651SBarry Smith   /*
27985614651SBarry Smith       Compute differencing parameter
28085614651SBarry Smith   */
2819a6cb015SBarry Smith   if (!ctx->ops->compute) {
2822f859189SBarry Smith     ierr = MatSNESMFSetType(mat,MATSNESMF_WP);CHKERRQ(ierr);
2835a655dc6SBarry Smith     ierr = MatSNESMFSetFromOptions(mat);CHKERRQ(ierr);
2849a6cb015SBarry Smith   }
2854dc4c822SBarry Smith   ierr = (*ctx->ops->compute)(ctx,U,a,&h,&zeroa);CHKERRQ(ierr);
2864dc4c822SBarry Smith   if (zeroa) {
28719bdad02SBarry Smith     ierr = VecSet(y,0.0);CHKERRQ(ierr);
2884dc4c822SBarry Smith     PetscFunctionReturn(0);
2894dc4c822SBarry Smith   }
290a4d4d686SBarry Smith 
2915b7f0c42SBarry Smith   if (ctx->checkh) {
2925b7f0c42SBarry Smith     ierr = (*ctx->checkh)(U,a,&h,ctx->checkhctx);CHKERRQ(ierr);
2935b7f0c42SBarry Smith   }
2945b7f0c42SBarry Smith 
295a4d4d686SBarry Smith   /* keep a record of the current differencing parameter h */
296a4d4d686SBarry Smith   ctx->currenth = h;
297aa482453SBarry Smith #if defined(PETSC_USE_COMPLEX)
298ae15b995SBarry Smith   ierr = PetscInfo2(mat,"Current differencing parameter: %G + %G i\n",PetscRealPart(h),PetscImaginaryPart(h));CHKERRQ(ierr);
299a4d4d686SBarry Smith #else
300ae15b995SBarry Smith   ierr = PetscInfo1(mat,"Current differencing parameter: %15.12e\n",h);CHKERRQ(ierr);
301a4d4d686SBarry Smith #endif
302a4d4d686SBarry Smith   if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) {
30385614651SBarry Smith     ctx->historyh[ctx->ncurrenth] = h;
304a4d4d686SBarry Smith   }
30585614651SBarry Smith   ctx->ncurrenth++;
306a4d4d686SBarry Smith 
30785614651SBarry Smith   /* w = u + ha */
3082dcb1b2aSMatthew Knepley   ierr = VecWAXPY(w,h,a,U);CHKERRQ(ierr);
30985614651SBarry Smith 
310b0a32e0cSBarry Smith   if (ctx->usesnes) {
31185614651SBarry Smith     eval_fct = SNESComputeFunction;
3121d1367b7SBarry Smith     F    = ctx->current_f;
3131302d50aSBarry Smith     if (!F) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"You must call MatAssembly() even on matrix-free matrices");
31439903ad8SBarry Smith     ierr = (*eval_fct)(snes,w,y);CHKERRQ(ierr);
31585614651SBarry Smith   } else {
31685614651SBarry Smith     F = ctx->funcvec;
31785614651SBarry Smith     /* compute func(U) as base for differencing */
31885614651SBarry Smith     if (ctx->ncurrenth == 1) {
31985614651SBarry Smith       ierr = (*ctx->func)(snes,U,F,ctx->funcctx);CHKERRQ(ierr);
32085614651SBarry Smith     }
32185614651SBarry Smith     ierr = (*ctx->func)(snes,w,y,ctx->funcctx);CHKERRQ(ierr);
32285614651SBarry Smith   }
323a4d4d686SBarry Smith 
324efb30889SBarry Smith   ierr = VecAXPY(y,-1.0,F);CHKERRQ(ierr);
325efb30889SBarry Smith   ierr = VecScale(y,1.0/h);CHKERRQ(ierr);
326c5c390f1SBarry Smith 
3272dcb1b2aSMatthew Knepley   ierr = VecAXPBY(y,ctx->vshift,ctx->vscale,a);CHKERRQ(ierr);
328c5c390f1SBarry Smith 
32974637425SBarry Smith   if (ctx->sp) {ierr = MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);CHKERRQ(ierr);}
330a4d4d686SBarry Smith 
33146129b97SKris Buschelman   ierr = PetscLogEventEnd(MATSNESMF_Mult,a,y,0,0);CHKERRQ(ierr);
332a4d4d686SBarry Smith   PetscFunctionReturn(0);
333a4d4d686SBarry Smith }
334a4d4d686SBarry Smith 
3354a2ae208SSatish Balay #undef __FUNCT__
3368a124369SBarry Smith #define __FUNCT__ "MatGetDiagonal_MFFD"
337cf57b110SBarry Smith /*
3388a124369SBarry Smith   MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix
339cf57b110SBarry Smith 
340cf57b110SBarry Smith         y ~= (F(u + ha) - F(u))/h,
341cf57b110SBarry Smith   where F = nonlinear function, as set by SNESSetFunction()
342cf57b110SBarry Smith         u = current iterate
343cf57b110SBarry Smith         h = difference interval
344cf57b110SBarry Smith */
345dfbe8321SBarry Smith PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a)
346cf57b110SBarry Smith {
34778392ef1SBarry Smith   MatSNESMF      ctx = (MatSNESMF)mat->data;
348ea709b57SSatish Balay   PetscScalar    h,*aa,*ww,v;
34977d8c4bbSBarry Smith   PetscReal      epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON;
35065df01d8SBarry Smith   Vec            w,U;
3516849ba73SBarry Smith   PetscErrorCode ierr;
352a7cc72afSBarry Smith   PetscInt       i,rstart,rend;
353cf57b110SBarry Smith 
354cf57b110SBarry Smith   PetscFunctionBegin;
355cf57b110SBarry Smith   if (!ctx->funci) {
3561302d50aSBarry Smith     SETERRQ(PETSC_ERR_ORDER,"Requires calling MatSNESMFSetFunctioni() first");
357cf57b110SBarry Smith   }
358cf57b110SBarry Smith 
359cf57b110SBarry Smith   w    = ctx->w;
360cf57b110SBarry Smith   U    = ctx->current_u;
361cf57b110SBarry Smith   ierr = (*ctx->func)(0,U,a,ctx->funcctx);CHKERRQ(ierr);
362cf57b110SBarry Smith   ierr = (*ctx->funcisetbase)(U,ctx->funcctx);CHKERRQ(ierr);
363cf57b110SBarry Smith   ierr = VecCopy(U,w);CHKERRQ(ierr);
364cf57b110SBarry Smith 
365cf57b110SBarry Smith   ierr = VecGetOwnershipRange(a,&rstart,&rend);CHKERRQ(ierr);
366cf57b110SBarry Smith   ierr = VecGetArray(a,&aa);CHKERRQ(ierr);
367cf57b110SBarry Smith   for (i=rstart; i<rend; i++) {
368cf57b110SBarry Smith     ierr = VecGetArray(w,&ww);CHKERRQ(ierr);
369cf57b110SBarry Smith     h  = ww[i-rstart];
370cf57b110SBarry Smith     if (h == 0.0) h = 1.0;
371cf57b110SBarry Smith #if !defined(PETSC_USE_COMPLEX)
372cf57b110SBarry Smith     if (h < umin && h >= 0.0)      h = umin;
373cf57b110SBarry Smith     else if (h < 0.0 && h > -umin) h = -umin;
374cf57b110SBarry Smith #else
375cf57b110SBarry Smith     if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0)     h = umin;
376cf57b110SBarry Smith     else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin;
377cf57b110SBarry Smith #endif
378cf57b110SBarry Smith     h     *= epsilon;
379cf57b110SBarry Smith 
380cf57b110SBarry Smith     ww[i-rstart] += h;
381cf57b110SBarry Smith     ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr);
382cf57b110SBarry Smith     ierr          = (*ctx->funci)(i,w,&v,ctx->funcctx);CHKERRQ(ierr);
383cf57b110SBarry Smith     aa[i-rstart]  = (v - aa[i-rstart])/h;
384c5c390f1SBarry Smith 
385c5c390f1SBarry Smith     /* possibly shift and scale result */
386c5c390f1SBarry Smith     aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart];
387c5c390f1SBarry Smith 
388cf57b110SBarry Smith     ierr = VecGetArray(w,&ww);CHKERRQ(ierr);
389cf57b110SBarry Smith     ww[i-rstart] -= h;
390cf57b110SBarry Smith     ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr);
391cf57b110SBarry Smith   }
392cf57b110SBarry Smith   ierr = VecRestoreArray(a,&aa);CHKERRQ(ierr);
393cf57b110SBarry Smith   PetscFunctionReturn(0);
394cf57b110SBarry Smith }
395cf57b110SBarry Smith 
396cf57b110SBarry Smith #undef __FUNCT__
397c5c390f1SBarry Smith #define __FUNCT__ "MatShift_MFFD"
398f4df32b1SMatthew Knepley PetscErrorCode MatShift_MFFD(Mat Y,PetscScalar a)
399c5c390f1SBarry Smith {
40078392ef1SBarry Smith   MatSNESMF shell = (MatSNESMF)Y->data;
401c5c390f1SBarry Smith   PetscFunctionBegin;
402f4df32b1SMatthew Knepley   shell->vshift += a;
403c5c390f1SBarry Smith   PetscFunctionReturn(0);
404c5c390f1SBarry Smith }
405c5c390f1SBarry Smith 
406c5c390f1SBarry Smith #undef __FUNCT__
407c5c390f1SBarry Smith #define __FUNCT__ "MatScale_MFFD"
408f4df32b1SMatthew Knepley PetscErrorCode MatScale_MFFD(Mat Y,PetscScalar a)
409c5c390f1SBarry Smith {
41078392ef1SBarry Smith   MatSNESMF shell = (MatSNESMF)Y->data;
411c5c390f1SBarry Smith   PetscFunctionBegin;
412f4df32b1SMatthew Knepley   shell->vscale *= a;
413c5c390f1SBarry Smith   PetscFunctionReturn(0);
414c5c390f1SBarry Smith }
415c5c390f1SBarry Smith 
416c5c390f1SBarry Smith 
417c5c390f1SBarry Smith #undef __FUNCT__
4184a2ae208SSatish Balay #define __FUNCT__ "MatCreateSNESMF"
41952baeb72SSatish Balay /*@
42065f2ba5bSLois Curfman McInnes    MatCreateSNESMF - Creates a matrix-free matrix context for use with
42165f2ba5bSLois Curfman McInnes    a SNES solver.  This matrix can be used as the Jacobian argument for
42265f2ba5bSLois Curfman McInnes    the routine SNESSetJacobian().
423a4d4d686SBarry Smith 
424a4d4d686SBarry Smith    Collective on SNES and Vec
425a4d4d686SBarry Smith 
426a4d4d686SBarry Smith    Input Parameters:
427a4d4d686SBarry Smith +  snes - the SNES context
428a4d4d686SBarry Smith -  x - vector where SNES solution is to be stored.
429a4d4d686SBarry Smith 
430a4d4d686SBarry Smith    Output Parameter:
431a4d4d686SBarry Smith .  J - the matrix-free matrix
432a4d4d686SBarry Smith 
43315091d37SBarry Smith    Level: advanced
43415091d37SBarry Smith 
435a4d4d686SBarry Smith    Notes:
436a4d4d686SBarry Smith    The matrix-free matrix context merely contains the function pointers
437a4d4d686SBarry Smith    and work space for performing finite difference approximations of
43865f2ba5bSLois Curfman McInnes    Jacobian-vector products, F'(u)*a,
4399a6cb015SBarry Smith 
4409a6cb015SBarry Smith    The default code uses the following approach to compute h
441a4d4d686SBarry Smith 
442a4d4d686SBarry Smith .vb
44365f2ba5bSLois Curfman McInnes      F'(u)*a = [F(u+h*a) - F(u)]/h where
444a4d4d686SBarry Smith      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
445a4d4d686SBarry Smith        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
446a4d4d686SBarry Smith  where
447a4d4d686SBarry Smith      error_rel = square root of relative error in function evaluation
448a4d4d686SBarry Smith      umin = minimum iterate parameter
449a4d4d686SBarry Smith .ve
450efb30889SBarry Smith    (see MATSNESMF_WP or MATSNESMF_DS)
451a4d4d686SBarry Smith 
4525a655dc6SBarry Smith    The user can set the error_rel via MatSNESMFSetFunctionError() and
45365f2ba5bSLois Curfman McInnes    umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
45465f2ba5bSLois Curfman McInnes    of the users manual for details.
455a4d4d686SBarry Smith 
456a4d4d686SBarry Smith    The user should call MatDestroy() when finished with the matrix-free
457a4d4d686SBarry Smith    matrix context.
458a4d4d686SBarry Smith 
459a4d4d686SBarry Smith    Options Database Keys:
460a4d4d686SBarry Smith +  -snes_mf_err <error_rel> - Sets error_rel
461efb30889SBarry Smith +  -snes_mf_type - wp or ds (see MATSNESMF_WP or MATSNESMF_DS)
4629a6cb015SBarry Smith .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
463a4d4d686SBarry Smith -  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
464a4d4d686SBarry Smith 
465a4d4d686SBarry Smith .keywords: SNES, default, matrix-free, create, matrix
466a4d4d686SBarry Smith 
4675a655dc6SBarry Smith .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin()
4681d1367b7SBarry Smith           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(),
469fed8bd04SBarry Smith           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian()
470a4d4d686SBarry Smith 
471a4d4d686SBarry Smith @*/
47263dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatCreateSNESMF(SNES snes,Vec x,Mat *J)
473a4d4d686SBarry Smith {
47478392ef1SBarry Smith   MatSNESMF      mfctx;
475dfbe8321SBarry Smith   PetscErrorCode ierr;
4761d1367b7SBarry Smith 
4771d1367b7SBarry Smith   PetscFunctionBegin;
4781d1367b7SBarry Smith   ierr = MatCreateMF(x,J);CHKERRQ(ierr);
4797e9d5209SBarry Smith 
48078392ef1SBarry Smith   mfctx          = (MatSNESMF)(*J)->data;
4811d1367b7SBarry Smith   mfctx->snes    = snes;
482b0a32e0cSBarry Smith   mfctx->usesnes = PETSC_TRUE;
48352e6d16bSBarry Smith   ierr = PetscLogObjectParent(snes,*J);CHKERRQ(ierr);
4841d1367b7SBarry Smith   PetscFunctionReturn(0);
4851d1367b7SBarry Smith }
4861d1367b7SBarry Smith 
487cf3bea43SBarry Smith EXTERN_C_BEGIN
488cf3bea43SBarry Smith #undef __FUNCT__
489cf3bea43SBarry Smith #define __FUNCT__ "MatSNESMFSetBase_FD"
49063dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetBase_FD(Mat J,Vec U)
491cf3bea43SBarry Smith {
492dfbe8321SBarry Smith   PetscErrorCode ierr;
49378392ef1SBarry Smith   MatSNESMF      ctx = (MatSNESMF)J->data;
494cf3bea43SBarry Smith 
495cf3bea43SBarry Smith   PetscFunctionBegin;
496cf3bea43SBarry Smith   ierr = MatSNESMFResetHHistory(J);CHKERRQ(ierr);
497cf3bea43SBarry Smith   ctx->current_u = U;
498cf3bea43SBarry Smith   ctx->usesnes   = PETSC_FALSE;
499958c9bccSBarry Smith   if (!ctx->w) {
500ba6a83e5SMatthew Knepley     ierr = VecDuplicate(ctx->current_u, &ctx->w);CHKERRQ(ierr);
501ba6a83e5SMatthew Knepley   }
50232dfb669SBarry Smith   J->assembled = PETSC_TRUE;
503cf3bea43SBarry Smith   PetscFunctionReturn(0);
504cf3bea43SBarry Smith }
505cf3bea43SBarry Smith EXTERN_C_END
5066849ba73SBarry Smith typedef PetscErrorCode (*FCN3)(Vec,Vec,PetscScalar*,void*); /* force argument to next function to not be extern C*/
5075b7f0c42SBarry Smith EXTERN_C_BEGIN
5085b7f0c42SBarry Smith #undef __FUNCT__
5095b7f0c42SBarry Smith #define __FUNCT__ "MatSNESMFSetCheckh_FD"
51063dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetCheckh_FD(Mat J,FCN3 fun,void*ectx)
5115b7f0c42SBarry Smith {
51278392ef1SBarry Smith   MatSNESMF ctx = (MatSNESMF)J->data;
5135b7f0c42SBarry Smith 
5145b7f0c42SBarry Smith   PetscFunctionBegin;
5155b7f0c42SBarry Smith   ctx->checkh    = fun;
5165b7f0c42SBarry Smith   ctx->checkhctx = ectx;
5175b7f0c42SBarry Smith   PetscFunctionReturn(0);
5185b7f0c42SBarry Smith }
5195b7f0c42SBarry Smith EXTERN_C_END
5205b7f0c42SBarry Smith 
5214a2ae208SSatish Balay #undef __FUNCT__
5227e9d5209SBarry Smith #define __FUNCT__ "MatSNESMFSetFromOptions"
5237e9d5209SBarry Smith /*@
5247e9d5209SBarry Smith    MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line
5257e9d5209SBarry Smith    parameter.
5267e9d5209SBarry Smith 
5277e9d5209SBarry Smith    Collective on Mat
5287e9d5209SBarry Smith 
5297e9d5209SBarry Smith    Input Parameters:
5307e9d5209SBarry Smith .  mat - the matrix obtained with MatCreateSNESMF()
5317e9d5209SBarry Smith 
5327e9d5209SBarry Smith    Options Database Keys:
533efb30889SBarry Smith +  -snes_mf_type - wp or ds (see MATSNESMF_WP or MATSNESMF_DS)
5347e9d5209SBarry Smith -  -snes_mf_err - square root of estimated relative error in function evaluation
5357e9d5209SBarry Smith -  -snes_mf_period - how often h is recomputed, defaults to 1, everytime
5367e9d5209SBarry Smith 
5377e9d5209SBarry Smith    Level: advanced
5387e9d5209SBarry Smith 
5397e9d5209SBarry Smith .keywords: SNES, matrix-free, parameters
5407e9d5209SBarry Smith 
5417e9d5209SBarry Smith .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
5427e9d5209SBarry Smith           MatSNESMFResetHHistory(), MatSNESMFKSPMonitor()
5437e9d5209SBarry Smith @*/
54463dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFromOptions(Mat mat)
5457e9d5209SBarry Smith {
54678392ef1SBarry Smith   MatSNESMF      mfctx = (MatSNESMF)mat->data;
547dfbe8321SBarry Smith   PetscErrorCode ierr;
5487e9d5209SBarry Smith   PetscTruth     flg;
5497e9d5209SBarry Smith   char           ftype[256];
5507e9d5209SBarry Smith 
5517e9d5209SBarry Smith   PetscFunctionBegin;
5527e9d5209SBarry Smith   if (!MatSNESMFRegisterAllCalled) {ierr = MatSNESMFRegisterAll(PETSC_NULL);CHKERRQ(ierr);}
5537e9d5209SBarry Smith 
5547e9d5209SBarry Smith   ierr = PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");CHKERRQ(ierr);
5557e9d5209SBarry Smith   ierr = PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);CHKERRQ(ierr);
5567e9d5209SBarry Smith   if (flg) {
5577e9d5209SBarry Smith     ierr = MatSNESMFSetType(mat,ftype);CHKERRQ(ierr);
5587e9d5209SBarry Smith   }
5597e9d5209SBarry Smith 
56087828ca2SBarry Smith   ierr = PetscOptionsReal("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);CHKERRQ(ierr);
5617e9d5209SBarry Smith   ierr = PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);CHKERRQ(ierr);
5627e9d5209SBarry Smith   if (mfctx->snes) {
5637e9d5209SBarry Smith     ierr = PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);CHKERRQ(ierr);
5647e9d5209SBarry Smith     if (flg) {
5657e9d5209SBarry Smith       KSP ksp;
56694b7f48cSBarry Smith       ierr = SNESGetKSP(mfctx->snes,&ksp);CHKERRQ(ierr);
567a6570f20SBarry Smith       ierr = KSPMonitorSet(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);CHKERRQ(ierr);
5687e9d5209SBarry Smith     }
5697e9d5209SBarry Smith   }
5705b7f0c42SBarry Smith   ierr = PetscOptionsName("-snes_mf_check_positivity","Insure that U + h*a is nonnegative","MatSNESMFSetCheckh",&flg);CHKERRQ(ierr);
5715b7f0c42SBarry Smith   if (flg) {
5725b7f0c42SBarry Smith     ierr = MatSNESMFSetCheckh(mat,MatSNESMFCheckPositivity,0);CHKERRQ(ierr);
5735b7f0c42SBarry Smith   }
5747e9d5209SBarry Smith   if (mfctx->ops->setfromoptions) {
5757e9d5209SBarry Smith     ierr = (*mfctx->ops->setfromoptions)(mfctx);CHKERRQ(ierr);
5767e9d5209SBarry Smith   }
5777e9d5209SBarry Smith   ierr = PetscOptionsEnd();CHKERRQ(ierr);
5787e9d5209SBarry Smith   PetscFunctionReturn(0);
5797e9d5209SBarry Smith }
5807e9d5209SBarry Smith 
5810bad9183SKris Buschelman /*MC
582fafad747SKris Buschelman   MATMFFD - MATMFFD = "mffd" - A matrix free matrix type.
5830bad9183SKris Buschelman 
5840bad9183SKris Buschelman   Level: advanced
5850bad9183SKris Buschelman 
5868bc8193eSBarry Smith .seealso: MatCreateMF(), MatCreateSNESMF()
5870bad9183SKris Buschelman M*/
588fe93831dSBarry Smith EXTERN_C_BEGIN
5897e9d5209SBarry Smith #undef __FUNCT__
5907e9d5209SBarry Smith #define __FUNCT__ "MatCreate_MFFD"
59163dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatCreate_MFFD(Mat A)
5927e9d5209SBarry Smith {
59378392ef1SBarry Smith   MatSNESMF      mfctx;
594dfbe8321SBarry Smith   PetscErrorCode ierr;
5957e9d5209SBarry Smith 
5967e9d5209SBarry Smith   PetscFunctionBegin;
5976e087cb5SMatthew Knepley #ifndef PETSC_USE_DYNAMIC_LIBRARIES
5986e087cb5SMatthew Knepley   ierr = SNESInitializePackage(PETSC_NULL);CHKERRQ(ierr);
5996e087cb5SMatthew Knepley #endif
6006e087cb5SMatthew Knepley 
60178392ef1SBarry Smith   ierr = PetscHeaderCreate(mfctx,_p_MatSNESMF,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",A->comm,MatDestroy_MFFD,MatView_MFFD);CHKERRQ(ierr);
6027e9d5209SBarry Smith   mfctx->sp              = 0;
6037e9d5209SBarry Smith   mfctx->snes            = 0;
60477d8c4bbSBarry Smith   mfctx->error_rel       = PETSC_SQRT_MACHINE_EPSILON;
6057e9d5209SBarry Smith   mfctx->recomputeperiod = 1;
6067e9d5209SBarry Smith   mfctx->count           = 0;
6077e9d5209SBarry Smith   mfctx->currenth        = 0.0;
6087e9d5209SBarry Smith   mfctx->historyh        = PETSC_NULL;
6097e9d5209SBarry Smith   mfctx->ncurrenth       = 0;
6107e9d5209SBarry Smith   mfctx->maxcurrenth     = 0;
6117e9d5209SBarry Smith   mfctx->type_name       = 0;
6127e9d5209SBarry Smith   mfctx->usesnes         = PETSC_FALSE;
6137e9d5209SBarry Smith 
614c5c390f1SBarry Smith   mfctx->vshift          = 0.0;
615c5c390f1SBarry Smith   mfctx->vscale          = 1.0;
616c5c390f1SBarry Smith 
6177e9d5209SBarry Smith   /*
6187e9d5209SBarry Smith      Create the empty data structure to contain compute-h routines.
6197e9d5209SBarry Smith      These will be filled in below from the command line options or
6207e9d5209SBarry Smith      a later call with MatSNESMFSetType() or if that is not called
6218a124369SBarry Smith      then it will default in the first use of MatMult_MFFD()
6227e9d5209SBarry Smith   */
6237e9d5209SBarry Smith   mfctx->ops->compute        = 0;
6247e9d5209SBarry Smith   mfctx->ops->destroy        = 0;
6257e9d5209SBarry Smith   mfctx->ops->view           = 0;
6267e9d5209SBarry Smith   mfctx->ops->setfromoptions = 0;
6277e9d5209SBarry Smith   mfctx->hctx                = 0;
6287e9d5209SBarry Smith 
6297e9d5209SBarry Smith   mfctx->func                = 0;
6307e9d5209SBarry Smith   mfctx->funcctx             = 0;
6317e9d5209SBarry Smith   mfctx->funcvec             = 0;
632ba6a83e5SMatthew Knepley   mfctx->w                   = PETSC_NULL;
6337e9d5209SBarry Smith 
63465df01d8SBarry Smith   A->data                = mfctx;
6357e9d5209SBarry Smith 
6368a124369SBarry Smith   A->ops->mult           = MatMult_MFFD;
6378a124369SBarry Smith   A->ops->destroy        = MatDestroy_MFFD;
6388a124369SBarry Smith   A->ops->view           = MatView_MFFD;
6398a124369SBarry Smith   A->ops->assemblyend    = MatAssemblyEnd_MFFD;
6408a124369SBarry Smith   A->ops->getdiagonal    = MatGetDiagonal_MFFD;
641c5c390f1SBarry Smith   A->ops->scale          = MatScale_MFFD;
642c5c390f1SBarry Smith   A->ops->shift          = MatShift_MFFD;
64365df01d8SBarry Smith   A->ops->setfromoptions = MatSNESMFSetFromOptions;
64432dfb669SBarry Smith   A->assembled = PETSC_TRUE;
6457e9d5209SBarry Smith 
64665df01d8SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);CHKERRQ(ierr);
647c5c390f1SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioniBase_C","MatSNESMFSetFunctioniBase_FD",MatSNESMFSetFunctioniBase_FD);CHKERRQ(ierr);
64887828ca2SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioni_C","MatSNESMFSetFunctioni_FD",MatSNESMFSetFunctioni_FD);CHKERRQ(ierr);
6495b7f0c42SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetCheckh_C","MatSNESMFSetCheckh_FD",MatSNESMFSetCheckh_FD);CHKERRQ(ierr);
65065df01d8SBarry Smith   mfctx->mat = A;
65117667f90SBarry Smith   ierr = PetscObjectChangeTypeName((PetscObject)A,MATMFFD);CHKERRQ(ierr);
6527e9d5209SBarry Smith   PetscFunctionReturn(0);
6537e9d5209SBarry Smith }
654fe93831dSBarry Smith EXTERN_C_END
6557e9d5209SBarry Smith 
6567e9d5209SBarry Smith #undef __FUNCT__
6574a2ae208SSatish Balay #define __FUNCT__ "MatCreateMF"
65852baeb72SSatish Balay /*@
6591d1367b7SBarry Smith    MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF()
6601d1367b7SBarry Smith 
6611d1367b7SBarry Smith    Collective on Vec
6621d1367b7SBarry Smith 
6631d1367b7SBarry Smith    Input Parameters:
6641d1367b7SBarry Smith .  x - vector that defines layout of the vectors and matrices
6651d1367b7SBarry Smith 
6661d1367b7SBarry Smith    Output Parameter:
6671d1367b7SBarry Smith .  J - the matrix-free matrix
6681d1367b7SBarry Smith 
6691d1367b7SBarry Smith    Level: advanced
6701d1367b7SBarry Smith 
6711d1367b7SBarry Smith    Notes:
6721d1367b7SBarry Smith    The matrix-free matrix context merely contains the function pointers
6731d1367b7SBarry Smith    and work space for performing finite difference approximations of
6741d1367b7SBarry Smith    Jacobian-vector products, F'(u)*a,
6751d1367b7SBarry Smith 
6761d1367b7SBarry Smith    The default code uses the following approach to compute h
6771d1367b7SBarry Smith 
6781d1367b7SBarry Smith .vb
6791d1367b7SBarry Smith      F'(u)*a = [F(u+h*a) - F(u)]/h where
6801d1367b7SBarry Smith      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
6811d1367b7SBarry Smith        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
6821d1367b7SBarry Smith  where
6831d1367b7SBarry Smith      error_rel = square root of relative error in function evaluation
6841d1367b7SBarry Smith      umin = minimum iterate parameter
6851d1367b7SBarry Smith .ve
6861d1367b7SBarry Smith 
6871d1367b7SBarry Smith    The user can set the error_rel via MatSNESMFSetFunctionError() and
6881d1367b7SBarry Smith    umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter
6891d1367b7SBarry Smith    of the users manual for details.
6901d1367b7SBarry Smith 
6911d1367b7SBarry Smith    The user should call MatDestroy() when finished with the matrix-free
6921d1367b7SBarry Smith    matrix context.
6931d1367b7SBarry Smith 
6941d1367b7SBarry Smith    Options Database Keys:
6951d1367b7SBarry Smith +  -snes_mf_err <error_rel> - Sets error_rel
6961d1367b7SBarry Smith .  -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only)
6975b7f0c42SBarry Smith .  -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h
6985b7f0c42SBarry Smith -  -snes_mf_check_positivity
6991d1367b7SBarry Smith 
7001d1367b7SBarry Smith .keywords: default, matrix-free, create, matrix
7011d1367b7SBarry Smith 
7026ce558aeSBarry Smith .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin(), MatSNESMFSetFunction()
7031d1367b7SBarry Smith           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(),
704fed8bd04SBarry Smith           MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian()
7051d1367b7SBarry Smith 
7061d1367b7SBarry Smith @*/
70763dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatCreateMF(Vec x,Mat *J)
7081d1367b7SBarry Smith {
709a4d4d686SBarry Smith   MPI_Comm       comm;
7106849ba73SBarry Smith   PetscErrorCode ierr;
711a7cc72afSBarry Smith   PetscInt       n,nloc;
712a4d4d686SBarry Smith 
713a4d4d686SBarry Smith   PetscFunctionBegin;
7141d1367b7SBarry Smith   ierr = PetscObjectGetComm((PetscObject)x,&comm);CHKERRQ(ierr);
71565df01d8SBarry Smith   ierr = VecGetSize(x,&n);CHKERRQ(ierr);
71665df01d8SBarry Smith   ierr = VecGetLocalSize(x,&nloc);CHKERRQ(ierr);
717f69a0ea3SMatthew Knepley   ierr = MatCreate(comm,J);CHKERRQ(ierr);
718f69a0ea3SMatthew Knepley   ierr = MatSetSizes(*J,nloc,nloc,n,n);CHKERRQ(ierr);
719e56c5435SBarry Smith   ierr = MatRegisterDynamic(MATMFFD,0,"MatCreate_MFFD",MatCreate_MFFD);CHKERRQ(ierr);
72065df01d8SBarry Smith   ierr = MatSetType(*J,MATMFFD);CHKERRQ(ierr);
7219a6cb015SBarry Smith   PetscFunctionReturn(0);
7229a6cb015SBarry Smith }
7239a6cb015SBarry Smith 
724a4d4d686SBarry Smith 
7254a2ae208SSatish Balay #undef __FUNCT__
7264a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFGetH"
727a4d4d686SBarry Smith /*@
72865f2ba5bSLois Curfman McInnes    MatSNESMFGetH - Gets the last value that was used as the differencing
729a4d4d686SBarry Smith    parameter.
730a4d4d686SBarry Smith 
731a4d4d686SBarry Smith    Not Collective
732a4d4d686SBarry Smith 
733a4d4d686SBarry Smith    Input Parameters:
7345a655dc6SBarry Smith .  mat - the matrix obtained with MatCreateSNESMF()
735a4d4d686SBarry Smith 
736a4d4d686SBarry Smith    Output Paramter:
737a4d4d686SBarry Smith .  h - the differencing step size
738a4d4d686SBarry Smith 
73915091d37SBarry Smith    Level: advanced
74015091d37SBarry Smith 
741a4d4d686SBarry Smith .keywords: SNES, matrix-free, parameters
742a4d4d686SBarry Smith 
7435a655dc6SBarry Smith .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(),
7445a655dc6SBarry Smith           MatSNESMFResetHHistory(),MatSNESMFKSPMonitor()
745a4d4d686SBarry Smith @*/
74663dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFGetH(Mat mat,PetscScalar *h)
747a4d4d686SBarry Smith {
74878392ef1SBarry Smith   MatSNESMF ctx = (MatSNESMF)mat->data;
749a4d4d686SBarry Smith 
750a4d4d686SBarry Smith   PetscFunctionBegin;
751a4d4d686SBarry Smith   *h = ctx->currenth;
752a4d4d686SBarry Smith   PetscFunctionReturn(0);
753a4d4d686SBarry Smith }
754a4d4d686SBarry Smith 
7554a2ae208SSatish Balay #undef __FUNCT__
7564a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFKSPMonitor"
757906ed7ccSBarry Smith /*@C
758906ed7ccSBarry Smith    MatSNESMFKSPMonitor - A KSP monitor for use with the  PETSc
75965f2ba5bSLois Curfman McInnes                 SNES matrix free routines. Prints the differencing parameter used at
76065f2ba5bSLois Curfman McInnes                 each step.
761906ed7ccSBarry Smith 
762906ed7ccSBarry Smith    Collective on KSP
763906ed7ccSBarry Smith 
764906ed7ccSBarry Smith    Input Parameters:
765906ed7ccSBarry Smith +    ksp - the Krylov solver object
766906ed7ccSBarry Smith .    n  - the current iteration
767906ed7ccSBarry Smith .    rnorm  - the current residual norm (may be preconditioned or not depending on solver and options
768906ed7ccSBarry Smith _    dummy  - unused argument
769906ed7ccSBarry Smith 
770906ed7ccSBarry Smith   Options Database:
771906ed7ccSBarry Smith .   -snes_mf_ksp_monitor - turn this monitor on
772906ed7ccSBarry Smith 
773a6570f20SBarry Smith    Notes: Use KSPMonitorSet(ksp,MatSNESMFKSPMonitor,PETSC_NULL,PETSC_NULL);
774906ed7ccSBarry Smith 
775a6570f20SBarry Smith .seealso:  KSPMonitorSet()
776906ed7ccSBarry Smith 
777906ed7ccSBarry Smith @*/
77863dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFKSPMonitor(KSP ksp,PetscInt n,PetscReal rnorm,void *dummy)
779a4d4d686SBarry Smith {
78078392ef1SBarry Smith   MatSNESMF      ctx;
781dfbe8321SBarry Smith   PetscErrorCode ierr;
782a4d4d686SBarry Smith   Mat            mat;
783a4d4d686SBarry Smith   MPI_Comm       comm;
784a4d4d686SBarry Smith   PetscTruth     nonzeroinitialguess;
785a4d4d686SBarry Smith 
786a4d4d686SBarry Smith   PetscFunctionBegin;
787a4d4d686SBarry Smith   ierr = PetscObjectGetComm((PetscObject)ksp,&comm);CHKERRQ(ierr);
788a4d4d686SBarry Smith   ierr = KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);CHKERRQ(ierr);
789906ed7ccSBarry Smith   ierr = KSPGetOperators(ksp,&mat,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr);
79078392ef1SBarry Smith   ctx  = (MatSNESMF)mat->data;
7917e9d5209SBarry Smith 
792a4d4d686SBarry Smith   if (n > 0 || nonzeroinitialguess) {
793aa482453SBarry Smith #if defined(PETSC_USE_COMPLEX)
794a83599f4SBarry Smith     ierr = PetscPrintf(comm,"%D KSP Residual norm %14.12e h %G + %G i\n",n,rnorm,
795329f5518SBarry Smith                 PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));CHKERRQ(ierr);
796a4d4d686SBarry Smith #else
797a83599f4SBarry Smith     ierr = PetscPrintf(comm,"%D KSP Residual norm %14.12e h %G \n",n,rnorm,ctx->currenth);CHKERRQ(ierr);
798a4d4d686SBarry Smith #endif
799a4d4d686SBarry Smith   } else {
80077431f27SBarry Smith     ierr = PetscPrintf(comm,"%D KSP Residual norm %14.12e\n",n,rnorm);CHKERRQ(ierr);
801a4d4d686SBarry Smith   }
802a4d4d686SBarry Smith   PetscFunctionReturn(0);
803a4d4d686SBarry Smith }
804a4d4d686SBarry Smith 
8054a2ae208SSatish Balay #undef __FUNCT__
8064a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFSetFunction"
80785614651SBarry Smith /*@C
80885614651SBarry Smith    MatSNESMFSetFunction - Sets the function used in applying the matrix free.
80985614651SBarry Smith 
81085614651SBarry Smith    Collective on Mat
81185614651SBarry Smith 
81285614651SBarry Smith    Input Parameters:
81385614651SBarry Smith +  mat - the matrix free matrix created via MatCreateSNESMF()
81485614651SBarry Smith .  v   - workspace vector
81585614651SBarry Smith .  func - the function to use
81685614651SBarry Smith -  funcctx - optional function context passed to function
81785614651SBarry Smith 
81885614651SBarry Smith    Level: advanced
81985614651SBarry Smith 
82085614651SBarry Smith    Notes:
82185614651SBarry Smith     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
82285614651SBarry Smith     matrix inside your compute Jacobian routine
82385614651SBarry Smith 
82485614651SBarry Smith     If this is not set then it will use the function set with SNESSetFunction()
82585614651SBarry Smith 
82685614651SBarry Smith .keywords: SNES, matrix-free, function
82785614651SBarry Smith 
82885614651SBarry Smith .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
82985614651SBarry Smith           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
83085614651SBarry Smith           MatSNESMFKSPMonitor(), SNESetFunction()
83185614651SBarry Smith @*/
83263dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunction(Mat mat,Vec v,PetscErrorCode (*func)(SNES,Vec,Vec,void *),void *funcctx)
83385614651SBarry Smith {
83478392ef1SBarry Smith   MatSNESMF ctx = (MatSNESMF)mat->data;
83585614651SBarry Smith 
83685614651SBarry Smith   PetscFunctionBegin;
83785614651SBarry Smith   ctx->func    = func;
83885614651SBarry Smith   ctx->funcctx = funcctx;
83985614651SBarry Smith   ctx->funcvec = v;
84085614651SBarry Smith   PetscFunctionReturn(0);
84185614651SBarry Smith }
84285614651SBarry Smith 
843cf57b110SBarry Smith #undef __FUNCT__
844cf57b110SBarry Smith #define __FUNCT__ "MatSNESMFSetFunctioni"
845cf57b110SBarry Smith /*@C
846cf57b110SBarry Smith    MatSNESMFSetFunctioni - Sets the function for a single component
847cf57b110SBarry Smith 
848cf57b110SBarry Smith    Collective on Mat
849cf57b110SBarry Smith 
850cf57b110SBarry Smith    Input Parameters:
851cf57b110SBarry Smith +  mat - the matrix free matrix created via MatCreateSNESMF()
852cf57b110SBarry Smith -  funci - the function to use
853cf57b110SBarry Smith 
854cf57b110SBarry Smith    Level: advanced
855cf57b110SBarry Smith 
856cf57b110SBarry Smith    Notes:
857cf57b110SBarry Smith     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
858cf57b110SBarry Smith     matrix inside your compute Jacobian routine
859cf57b110SBarry Smith 
860cf57b110SBarry Smith 
861cf57b110SBarry Smith .keywords: SNES, matrix-free, function
862cf57b110SBarry Smith 
863cf57b110SBarry Smith .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
864cf57b110SBarry Smith           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
865cf57b110SBarry Smith           MatSNESMFKSPMonitor(), SNESetFunction()
866cf57b110SBarry Smith @*/
86763dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctioni(Mat mat,PetscErrorCode (*funci)(PetscInt,Vec,PetscScalar*,void *))
868cf57b110SBarry Smith {
869a7cc72afSBarry Smith   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(PetscInt,Vec,PetscScalar*,void *));
870cf57b110SBarry Smith 
871cf57b110SBarry Smith   PetscFunctionBegin;
8724482741eSBarry Smith   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
873c134de8dSSatish Balay   ierr = PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C",(void (**)(void))&f);CHKERRQ(ierr);
87487828ca2SBarry Smith   if (f) {
87587828ca2SBarry Smith     ierr = (*f)(mat,funci);CHKERRQ(ierr);
87687828ca2SBarry Smith   }
877cf57b110SBarry Smith   PetscFunctionReturn(0);
878cf57b110SBarry Smith }
879cf57b110SBarry Smith 
88087828ca2SBarry Smith 
881cf57b110SBarry Smith #undef __FUNCT__
882cf57b110SBarry Smith #define __FUNCT__ "MatSNESMFSetFunctioniBase"
883cf57b110SBarry Smith /*@C
884cf57b110SBarry Smith    MatSNESMFSetFunctioniBase - Sets the base vector for a single component function evaluation
885cf57b110SBarry Smith 
886cf57b110SBarry Smith    Collective on Mat
887cf57b110SBarry Smith 
888cf57b110SBarry Smith    Input Parameters:
889cf57b110SBarry Smith +  mat - the matrix free matrix created via MatCreateSNESMF()
890cf57b110SBarry Smith -  func - the function to use
891cf57b110SBarry Smith 
892cf57b110SBarry Smith    Level: advanced
893cf57b110SBarry Smith 
894cf57b110SBarry Smith    Notes:
895cf57b110SBarry Smith     If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free
896cf57b110SBarry Smith     matrix inside your compute Jacobian routine
897cf57b110SBarry Smith 
898cf57b110SBarry Smith 
899cf57b110SBarry Smith .keywords: SNES, matrix-free, function
900cf57b110SBarry Smith 
901cf57b110SBarry Smith .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
902cf57b110SBarry Smith           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
903cf57b110SBarry Smith           MatSNESMFKSPMonitor(), SNESetFunction()
904cf57b110SBarry Smith @*/
90563dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctioniBase(Mat mat,PetscErrorCode (*func)(Vec,void *))
906cf57b110SBarry Smith {
9076849ba73SBarry Smith   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(Vec,void *));
908cf57b110SBarry Smith 
909cf57b110SBarry Smith   PetscFunctionBegin;
9104482741eSBarry Smith   PetscValidHeaderSpecific(mat,MAT_COOKIE,1);
911c134de8dSSatish Balay   ierr = PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C",(void (**)(void))&f);CHKERRQ(ierr);
91287828ca2SBarry Smith   if (f) {
91387828ca2SBarry Smith     ierr = (*f)(mat,func);CHKERRQ(ierr);
91487828ca2SBarry Smith   }
915cf57b110SBarry Smith   PetscFunctionReturn(0);
916cf57b110SBarry Smith }
917cf57b110SBarry Smith 
91885614651SBarry Smith 
9194a2ae208SSatish Balay #undef __FUNCT__
9204a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFSetPeriod"
921329f5518SBarry Smith /*@
922329f5518SBarry Smith    MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime
923329f5518SBarry Smith 
924329f5518SBarry Smith    Collective on Mat
925329f5518SBarry Smith 
926329f5518SBarry Smith    Input Parameters:
927329f5518SBarry Smith +  mat - the matrix free matrix created via MatCreateSNESMF()
928329f5518SBarry Smith -  period - 1 for everytime, 2 for every second etc
929329f5518SBarry Smith 
930329f5518SBarry Smith    Options Database Keys:
931329f5518SBarry Smith +  -snes_mf_period <period>
932329f5518SBarry Smith 
933329f5518SBarry Smith    Level: advanced
934329f5518SBarry Smith 
935329f5518SBarry Smith 
936329f5518SBarry Smith .keywords: SNES, matrix-free, parameters
937329f5518SBarry Smith 
938329f5518SBarry Smith .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
939329f5518SBarry Smith           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
940329f5518SBarry Smith           MatSNESMFKSPMonitor()
941329f5518SBarry Smith @*/
94263dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetPeriod(Mat mat,PetscInt period)
943329f5518SBarry Smith {
94478392ef1SBarry Smith   MatSNESMF ctx = (MatSNESMF)mat->data;
945329f5518SBarry Smith 
946329f5518SBarry Smith   PetscFunctionBegin;
947329f5518SBarry Smith   ctx->recomputeperiod = period;
948329f5518SBarry Smith   PetscFunctionReturn(0);
949329f5518SBarry Smith }
950329f5518SBarry Smith 
9514a2ae208SSatish Balay #undef __FUNCT__
9524a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFSetFunctionError"
953a4d4d686SBarry Smith /*@
9545a655dc6SBarry Smith    MatSNESMFSetFunctionError - Sets the error_rel for the approximation of
955a4d4d686SBarry Smith    matrix-vector products using finite differences.
956a4d4d686SBarry Smith 
957a4d4d686SBarry Smith    Collective on Mat
958a4d4d686SBarry Smith 
959a4d4d686SBarry Smith    Input Parameters:
9605a655dc6SBarry Smith +  mat - the matrix free matrix created via MatCreateSNESMF()
9619a6cb015SBarry Smith -  error_rel - relative error (should be set to the square root of
962a4d4d686SBarry Smith                the relative error in the function evaluations)
963a4d4d686SBarry Smith 
96415091d37SBarry Smith    Options Database Keys:
96515091d37SBarry Smith +  -snes_mf_err <error_rel> - Sets error_rel
96615091d37SBarry Smith 
96715091d37SBarry Smith    Level: advanced
96815091d37SBarry Smith 
969a4d4d686SBarry Smith    Notes:
970a4d4d686SBarry Smith    The default matrix-free matrix-vector product routine computes
971a4d4d686SBarry Smith .vb
97265f2ba5bSLois Curfman McInnes      F'(u)*a = [F(u+h*a) - F(u)]/h where
973a4d4d686SBarry Smith      h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
974a4d4d686SBarry Smith        = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
975a4d4d686SBarry Smith .ve
976a4d4d686SBarry Smith 
977a4d4d686SBarry Smith .keywords: SNES, matrix-free, parameters
978a4d4d686SBarry Smith 
9795a655dc6SBarry Smith .seealso: MatCreateSNESMF(),MatSNESMFGetH(),
9805a655dc6SBarry Smith           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
9815a655dc6SBarry Smith           MatSNESMFKSPMonitor()
982a4d4d686SBarry Smith @*/
98363dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetFunctionError(Mat mat,PetscReal error)
984a4d4d686SBarry Smith {
98578392ef1SBarry Smith   MatSNESMF ctx = (MatSNESMF)mat->data;
986a4d4d686SBarry Smith 
987a4d4d686SBarry Smith   PetscFunctionBegin;
988a4d4d686SBarry Smith   if (error != PETSC_DEFAULT) ctx->error_rel = error;
989a4d4d686SBarry Smith   PetscFunctionReturn(0);
990a4d4d686SBarry Smith }
991a4d4d686SBarry Smith 
9924a2ae208SSatish Balay #undef __FUNCT__
9934a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFAddNullSpace"
994a4d4d686SBarry Smith /*@
99565f2ba5bSLois Curfman McInnes    MatSNESMFAddNullSpace - Provides a null space that an operator is
99665f2ba5bSLois Curfman McInnes    supposed to have.  Since roundoff will create a small component in
99765f2ba5bSLois Curfman McInnes    the null space, if you know the null space you may have it
99865f2ba5bSLois Curfman McInnes    automatically removed.
999a4d4d686SBarry Smith 
1000a4d4d686SBarry Smith    Collective on Mat
1001a4d4d686SBarry Smith 
1002a4d4d686SBarry Smith    Input Parameters:
1003a4d4d686SBarry Smith +  J - the matrix-free matrix context
100474637425SBarry Smith -  nullsp - object created with MatNullSpaceCreate()
1005a4d4d686SBarry Smith 
100615091d37SBarry Smith    Level: advanced
100715091d37SBarry Smith 
1008a4d4d686SBarry Smith .keywords: SNES, matrix-free, null space
1009a4d4d686SBarry Smith 
101074637425SBarry Smith .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(),
10115a655dc6SBarry Smith           MatSNESMFSetHHistory(), MatSNESMFResetHHistory(),
10125a655dc6SBarry Smith           MatSNESMFKSPMonitor(), MatSNESMFErrorRel()
1013a4d4d686SBarry Smith @*/
101463dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp)
1015a4d4d686SBarry Smith {
1016dfbe8321SBarry Smith   PetscErrorCode ierr;
101778392ef1SBarry Smith   MatSNESMF      ctx = (MatSNESMF)J->data;
1018a4d4d686SBarry Smith 
1019a4d4d686SBarry Smith   PetscFunctionBegin;
102085614651SBarry Smith   ierr = PetscObjectReference((PetscObject)nullsp);CHKERRQ(ierr);
1021c3122656SLisandro Dalcin   if (ctx->sp) { ierr = MatNullSpaceDestroy(ctx->sp);CHKERRQ(ierr); }
1022c3122656SLisandro Dalcin   ctx->sp = nullsp;
1023a4d4d686SBarry Smith   PetscFunctionReturn(0);
1024a4d4d686SBarry Smith }
1025a4d4d686SBarry Smith 
10264a2ae208SSatish Balay #undef __FUNCT__
10274a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFSetHHistory"
1028a4d4d686SBarry Smith /*@
102965f2ba5bSLois Curfman McInnes    MatSNESMFSetHHistory - Sets an array to collect a history of the
103065f2ba5bSLois Curfman McInnes    differencing values (h) computed for the matrix-free product.
1031a4d4d686SBarry Smith 
1032a4d4d686SBarry Smith    Collective on Mat
1033a4d4d686SBarry Smith 
1034a4d4d686SBarry Smith    Input Parameters:
1035a4d4d686SBarry Smith +  J - the matrix-free matrix context
103665f2ba5bSLois Curfman McInnes .  histroy - space to hold the history
103765f2ba5bSLois Curfman McInnes -  nhistory - number of entries in history, if more entries are generated than
103865f2ba5bSLois Curfman McInnes               nhistory, then the later ones are discarded
1039a4d4d686SBarry Smith 
104015091d37SBarry Smith    Level: advanced
104115091d37SBarry Smith 
1042a4d4d686SBarry Smith    Notes:
104365f2ba5bSLois Curfman McInnes    Use MatSNESMFResetHHistory() to reset the history counter and collect
104465f2ba5bSLois Curfman McInnes    a new batch of differencing parameters, h.
1045a4d4d686SBarry Smith 
1046a4d4d686SBarry Smith .keywords: SNES, matrix-free, h history, differencing history
1047a4d4d686SBarry Smith 
10485a655dc6SBarry Smith .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
10495a655dc6SBarry Smith           MatSNESMFResetHHistory(),
10505a655dc6SBarry Smith           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
1051a4d4d686SBarry Smith 
1052a4d4d686SBarry Smith @*/
105363dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory)
1054a4d4d686SBarry Smith {
105578392ef1SBarry Smith   MatSNESMF ctx = (MatSNESMF)J->data;
1056a4d4d686SBarry Smith 
1057a4d4d686SBarry Smith   PetscFunctionBegin;
1058a4d4d686SBarry Smith   ctx->historyh    = history;
1059a4d4d686SBarry Smith   ctx->maxcurrenth = nhistory;
1060a4d4d686SBarry Smith   ctx->currenth    = 0;
1061a4d4d686SBarry Smith   PetscFunctionReturn(0);
1062a4d4d686SBarry Smith }
1063a4d4d686SBarry Smith 
10644a2ae208SSatish Balay #undef __FUNCT__
10654a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFResetHHistory"
1066a4d4d686SBarry Smith /*@
10675a655dc6SBarry Smith    MatSNESMFResetHHistory - Resets the counter to zero to begin
1068a4d4d686SBarry Smith    collecting a new set of differencing histories.
1069a4d4d686SBarry Smith 
1070a4d4d686SBarry Smith    Collective on Mat
1071a4d4d686SBarry Smith 
1072a4d4d686SBarry Smith    Input Parameters:
1073a4d4d686SBarry Smith .  J - the matrix-free matrix context
1074a4d4d686SBarry Smith 
107515091d37SBarry Smith    Level: advanced
107615091d37SBarry Smith 
1077a4d4d686SBarry Smith    Notes:
107865f2ba5bSLois Curfman McInnes    Use MatSNESMFSetHHistory() to create the original history counter.
1079a4d4d686SBarry Smith 
1080a4d4d686SBarry Smith .keywords: SNES, matrix-free, h history, differencing history
1081a4d4d686SBarry Smith 
10825a655dc6SBarry Smith .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
10835a655dc6SBarry Smith           MatSNESMFSetHHistory(),
10845a655dc6SBarry Smith           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError()
1085a4d4d686SBarry Smith 
1086a4d4d686SBarry Smith @*/
108763dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFResetHHistory(Mat J)
1088a4d4d686SBarry Smith {
108978392ef1SBarry Smith   MatSNESMF ctx = (MatSNESMF)J->data;
1090a4d4d686SBarry Smith 
1091a4d4d686SBarry Smith   PetscFunctionBegin;
1092be726c96SBarry Smith   ctx->ncurrenth    = 0;
1093a4d4d686SBarry Smith   PetscFunctionReturn(0);
1094a4d4d686SBarry Smith }
1095a4d4d686SBarry Smith 
10964a2ae208SSatish Balay #undef __FUNCT__
1097fed8bd04SBarry Smith #define __FUNCT__ "MatSNESMFComputeJacobian"
10983960baedSBarry Smith /*@
10993960baedSBarry Smith    MatSNESMFComputeJacobian - Tells the matrix-free Jacobian object the new location at which
11003960baedSBarry Smith        Jacobian matrix vector products will be computed at, i.e. J(x) * a.
11013960baedSBarry Smith 
11023960baedSBarry Smith    Collective on SNES
11033960baedSBarry Smith 
11043960baedSBarry Smith    Input Parameters:
11053960baedSBarry Smith +   snes - the nonlinear solver context
11063960baedSBarry Smith .   x - the point at which the Jacobian vector products will be performed
11073960baedSBarry Smith .   jac - the matrix-free Jacobian object
11083960baedSBarry Smith .   B - either the same as jac or another matrix type (ignored)
11093960baedSBarry Smith .   flag - not relevent for matrix-free form
11103960baedSBarry Smith -   dummy - the user context (ignored)
11113960baedSBarry Smith 
11123960baedSBarry Smith    Level: developer
11133960baedSBarry Smith 
11143960baedSBarry Smith    Notes:
11153960baedSBarry Smith      This can be passed into SNESSetJacobian() when using a completely matrix-free solver,
11163960baedSBarry Smith      that is the B matrix is also the same matrix operator. This is used when you select
11173960baedSBarry Smith      -snes_mf but rarely used directly by users.
11183960baedSBarry Smith 
11193960baedSBarry Smith .seealso: MatSNESMFGetH(), MatCreateSNESMF(),
11203960baedSBarry Smith           MatSNESMFSetHHistory(),
11213960baedSBarry Smith           MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError(), MatSNESMFCreate(), SNESSetJacobian()
11223960baedSBarry Smith 
11233960baedSBarry Smith @*/
112463dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy)
11251d1367b7SBarry Smith {
1126dfbe8321SBarry Smith   PetscErrorCode ierr;
11271d1367b7SBarry Smith   PetscFunctionBegin;
11281d1367b7SBarry Smith   ierr = MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11291d1367b7SBarry Smith   ierr = MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11301d1367b7SBarry Smith   PetscFunctionReturn(0);
11311d1367b7SBarry Smith }
11321d1367b7SBarry Smith 
11334a2ae208SSatish Balay #undef __FUNCT__
11344a2ae208SSatish Balay #define __FUNCT__ "MatSNESMFSetBase"
11355b7f0c42SBarry Smith /*@
11365b7f0c42SBarry Smith     MatSNESMFSetBase - Sets the vector U at which matrix vector products of the
11375b7f0c42SBarry Smith         Jacobian are computed
11385b7f0c42SBarry Smith 
11395b7f0c42SBarry Smith     Collective on Mat
11405b7f0c42SBarry Smith 
11415b7f0c42SBarry Smith     Input Parameters:
11425b7f0c42SBarry Smith +   J - the MatSNESMF matrix
11435b7f0c42SBarry Smith -   U - the vector
11445b7f0c42SBarry Smith 
11455b7f0c42SBarry Smith     Notes: This is rarely used directly
11465b7f0c42SBarry Smith 
11475b7f0c42SBarry Smith     Level: advanced
11485b7f0c42SBarry Smith 
11495b7f0c42SBarry Smith @*/
115063dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetBase(Mat J,Vec U)
11511d1367b7SBarry Smith {
1152dfbe8321SBarry Smith   PetscErrorCode ierr,(*f)(Mat,Vec);
11531d1367b7SBarry Smith 
11541d1367b7SBarry Smith   PetscFunctionBegin;
11554482741eSBarry Smith   PetscValidHeaderSpecific(J,MAT_COOKIE,1);
11564482741eSBarry Smith   PetscValidHeaderSpecific(U,VEC_COOKIE,2);
1157c134de8dSSatish Balay   ierr = PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)(void))&f);CHKERRQ(ierr);
1158cf3bea43SBarry Smith   if (f) {
1159cf3bea43SBarry Smith     ierr = (*f)(J,U);CHKERRQ(ierr);
116049d4803aSBarry Smith   }
11611d1367b7SBarry Smith   PetscFunctionReturn(0);
11621d1367b7SBarry Smith }
1163cf57b110SBarry Smith 
11645b7f0c42SBarry Smith #undef __FUNCT__
11655b7f0c42SBarry Smith #define __FUNCT__ "MatSNESMFSetCheckh"
116661860be5SBarry Smith /*@C
11675b7f0c42SBarry Smith     MatSNESMFSetCheckh - Sets a function that checks the computed h and adjusts
11685b7f0c42SBarry Smith         it to satisfy some criteria
1169cf57b110SBarry Smith 
11705b7f0c42SBarry Smith     Collective on Mat
11715b7f0c42SBarry Smith 
11725b7f0c42SBarry Smith     Input Parameters:
11735b7f0c42SBarry Smith +   J - the MatSNESMF matrix
11745b7f0c42SBarry Smith .   fun - the function that checks h
11755b7f0c42SBarry Smith -   ctx - any context needed by the function
11765b7f0c42SBarry Smith 
11775b7f0c42SBarry Smith     Options Database Keys:
11785b7f0c42SBarry Smith .   -snes_mf_check_positivity
11795b7f0c42SBarry Smith 
11805b7f0c42SBarry Smith     Level: advanced
11815b7f0c42SBarry Smith 
11825b7f0c42SBarry Smith     Notes: For example, MatSNESMFSetCheckPositivity() insures that all entries
11835b7f0c42SBarry Smith        of U + h*a are non-negative
11845b7f0c42SBarry Smith 
11855b7f0c42SBarry Smith .seealso:  MatSNESMFSetCheckPositivity()
11865b7f0c42SBarry Smith @*/
118763dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFSetCheckh(Mat J,PetscErrorCode (*fun)(Vec,Vec,PetscScalar*,void*),void* ctx)
11885b7f0c42SBarry Smith {
11896849ba73SBarry Smith   PetscErrorCode ierr,(*f)(Mat,PetscErrorCode (*)(Vec,Vec,PetscScalar*,void*),void*);
11905b7f0c42SBarry Smith 
11915b7f0c42SBarry Smith   PetscFunctionBegin;
11924482741eSBarry Smith   PetscValidHeaderSpecific(J,MAT_COOKIE,1);
11935b7f0c42SBarry Smith   ierr = PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetCheckh_C",(void (**)(void))&f);CHKERRQ(ierr);
11945b7f0c42SBarry Smith   if (f) {
11955b7f0c42SBarry Smith     ierr = (*f)(J,fun,ctx);CHKERRQ(ierr);
11965b7f0c42SBarry Smith   }
11975b7f0c42SBarry Smith   PetscFunctionReturn(0);
11985b7f0c42SBarry Smith }
11995b7f0c42SBarry Smith 
12005b7f0c42SBarry Smith #undef __FUNCT__
12015b7f0c42SBarry Smith #define __FUNCT__ "MatSNESMFSetCheckPositivity"
12025b7f0c42SBarry Smith /*@
12035b7f0c42SBarry Smith     MatSNESMFCheckPositivity - Checks that all entries in U + h*a are positive or
12045b7f0c42SBarry Smith         zero, decreases h until this is satisfied.
12055b7f0c42SBarry Smith 
12065b7f0c42SBarry Smith     Collective on Vec
12075b7f0c42SBarry Smith 
12085b7f0c42SBarry Smith     Input Parameters:
12095b7f0c42SBarry Smith +   U - base vector that is added to
12105b7f0c42SBarry Smith .   a - vector that is added
12115b7f0c42SBarry Smith .   h - scaling factor on a
12125b7f0c42SBarry Smith -   dummy - context variable (unused)
12135b7f0c42SBarry Smith 
12145b7f0c42SBarry Smith     Options Database Keys:
12155b7f0c42SBarry Smith .   -snes_mf_check_positivity
12165b7f0c42SBarry Smith 
12175b7f0c42SBarry Smith     Level: advanced
12185b7f0c42SBarry Smith 
12195b7f0c42SBarry Smith     Notes: This is rarely used directly, rather it is passed as an argument to
12205b7f0c42SBarry Smith            MatSNESMFSetCheckh()
12215b7f0c42SBarry Smith 
12225b7f0c42SBarry Smith .seealso:  MatSNESMFSetCheckh()
12235b7f0c42SBarry Smith @*/
122463dd3a1aSKris Buschelman PetscErrorCode PETSCSNES_DLLEXPORT MatSNESMFCheckPositivity(Vec U,Vec a,PetscScalar *h,void *dummy)
12255b7f0c42SBarry Smith {
12265b7f0c42SBarry Smith   PetscReal      val, minval;
12275b7f0c42SBarry Smith   PetscScalar    *u_vec, *a_vec;
1228dfbe8321SBarry Smith   PetscErrorCode ierr;
1229a7cc72afSBarry Smith   PetscInt       i,n;
12305b7f0c42SBarry Smith   MPI_Comm       comm;
12315b7f0c42SBarry Smith 
12325b7f0c42SBarry Smith   PetscFunctionBegin;
12335b7f0c42SBarry Smith   ierr = PetscObjectGetComm((PetscObject)U,&comm);CHKERRQ(ierr);
12345b7f0c42SBarry Smith   ierr = VecGetArray(U,&u_vec);CHKERRQ(ierr);
12355b7f0c42SBarry Smith   ierr = VecGetArray(a,&a_vec);CHKERRQ(ierr);
1236a7cc72afSBarry Smith   ierr = VecGetLocalSize(U,&n);CHKERRQ(ierr);
123761860be5SBarry Smith   minval = PetscAbsScalar(*h*1.01);
1238a7cc72afSBarry Smith   for(i=0;i<n;i++) {
123961860be5SBarry Smith     if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) {
124061860be5SBarry Smith       val = PetscAbsScalar(u_vec[i]/a_vec[i]);
12415b7f0c42SBarry Smith       if (val < minval) minval = val;
12425b7f0c42SBarry Smith     }
12435b7f0c42SBarry Smith   }
12445b7f0c42SBarry Smith   ierr = VecRestoreArray(U,&u_vec);CHKERRQ(ierr);
12455b7f0c42SBarry Smith   ierr = VecRestoreArray(a,&a_vec);CHKERRQ(ierr);
12465b7f0c42SBarry Smith   ierr = PetscGlobalMin(&minval,&val,comm);CHKERRQ(ierr);
124761860be5SBarry Smith   if (val <= PetscAbsScalar(*h)) {
1248ae15b995SBarry Smith     ierr = PetscInfo2(U,"Scaling back h from %G to %G\n",PetscRealPart(*h),.99*val);CHKERRQ(ierr);
124961860be5SBarry Smith     if (PetscRealPart(*h) > 0.0) *h =  0.99*val;
12505b7f0c42SBarry Smith     else                         *h = -0.99*val;
12515b7f0c42SBarry Smith   }
12525b7f0c42SBarry Smith   PetscFunctionReturn(0);
12535b7f0c42SBarry Smith }
1254cf57b110SBarry Smith 
1255cf57b110SBarry Smith 
1256cf57b110SBarry Smith 
1257cf57b110SBarry Smith 
1258cf57b110SBarry Smith 
1259cf57b110SBarry Smith 
1260cf57b110SBarry Smith 
1261