xref: /petsc/src/snes/mf/snesmfj.c (revision 3d5db8e15ff86837921696cbae1739f25a099aff)
181e6777dSBarry Smith 
281e6777dSBarry Smith #ifndef lint
3*3d5db8e1SLois Curfman McInnes static char vcid[] = "$Id: snesmfj.c,v 1.44 1997/01/22 01:42:26 curfman Exp curfman $";
481e6777dSBarry Smith #endif
581e6777dSBarry Smith 
6b1f0a012SBarry Smith #include "draw.h"       /*I  "draw.h"   I*/
770f55243SBarry Smith #include "src/snes/snesimpl.h"   /*I  "snes.h"   I*/
8eb9086c3SLois Curfman McInnes #include "pinclude/pviewer.h"
981e6777dSBarry Smith 
1050361f65SLois Curfman McInnes typedef struct {  /* default context for matrix-free SNES */
11eb9086c3SLois Curfman McInnes   SNES        snes;      /* SNES context */
12eb9086c3SLois Curfman McInnes   Vec         w;         /* work vector */
13eb9086c3SLois Curfman McInnes   PCNullSpace sp;        /* null space context */
14eb9086c3SLois Curfman McInnes   double      error_rel; /* square root of relative error in computing function */
15639f9d9dSBarry Smith   double      umin;      /* minimum allowable u'a value relative to |u|_1 */
1639e2f89bSBarry Smith } MFCtx_Private;
1739e2f89bSBarry Smith 
185615d1e5SSatish Balay #undef __FUNC__
195615d1e5SSatish Balay #define __FUNC__ "SNESMatrixFreeDestroy_Private"
20fae171e0SBarry Smith int SNESMatrixFreeDestroy_Private(PetscObject obj)
21b9fa9cd0SBarry Smith {
22b9fa9cd0SBarry Smith   int           ierr;
23fae171e0SBarry Smith   Mat           mat = (Mat) obj;
24fae171e0SBarry Smith   MFCtx_Private *ctx;
25fae171e0SBarry Smith 
26fae171e0SBarry Smith   ierr = MatShellGetContext(mat,(void **)&ctx);
27b9fa9cd0SBarry Smith   ierr = VecDestroy(ctx->w); CHKERRQ(ierr);
28b4fd4287SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp); CHKERRQ(ierr);}
29fae171e0SBarry Smith   PetscFree(ctx);
30b9fa9cd0SBarry Smith   return 0;
31b9fa9cd0SBarry Smith }
3250361f65SLois Curfman McInnes 
335615d1e5SSatish Balay #undef __FUNC__
345615d1e5SSatish Balay #define __FUNC__ "SNESMatrixFreeView_Private"
3539e2f89bSBarry Smith /*
361d1bbde2SLois Curfman McInnes    SNESMatrixFreeView_Private - Views matrix-free parameters.
3739e2f89bSBarry Smith  */
38eb9086c3SLois Curfman McInnes int SNESMatrixFreeView_Private(Mat J,Viewer viewer)
39eb9086c3SLois Curfman McInnes {
40eb9086c3SLois Curfman McInnes   int           ierr;
41eb9086c3SLois Curfman McInnes   MFCtx_Private *ctx;
42eb9086c3SLois Curfman McInnes   MPI_Comm      comm;
43eb9086c3SLois Curfman McInnes   FILE          *fd;
44eb9086c3SLois Curfman McInnes   ViewerType    vtype;
45eb9086c3SLois Curfman McInnes 
46eb9086c3SLois Curfman McInnes   PetscObjectGetComm((PetscObject)J,&comm);
47eb9086c3SLois Curfman McInnes   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
48eb9086c3SLois Curfman McInnes   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
49eb9086c3SLois Curfman McInnes   ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
50eb9086c3SLois Curfman McInnes   if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
51eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"  SNES matrix-free approximation:\n");
52eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"    err=%g (relative error in function evaluation)\n",ctx->error_rel);
53eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"    umin=%g (minimum iterate parameter)\n",ctx->umin);
54eb9086c3SLois Curfman McInnes   }
55eb9086c3SLois Curfman McInnes   return 0;
56eb9086c3SLois Curfman McInnes }
57eb9086c3SLois Curfman McInnes 
585615d1e5SSatish Balay #undef __FUNC__
595615d1e5SSatish Balay #define __FUNC__ "SNESMatrixFreeMult_Private"
60eb9086c3SLois Curfman McInnes /*
61eb9086c3SLois Curfman McInnes   SNESMatrixFreeMult_Private - Default matrix-free form for Jacobian-vector
62eb9086c3SLois Curfman McInnes   product, y = F'(u)*a:
63eb9086c3SLois Curfman McInnes         y = ( F(u + ha) - F(u) ) /h,
64eb9086c3SLois Curfman McInnes   where F = nonlinear function, as set by SNESSetFunction()
65eb9086c3SLois Curfman McInnes         u = current iterate
66eb9086c3SLois Curfman McInnes         h = difference interval
67eb9086c3SLois Curfman McInnes */
68eb9086c3SLois Curfman McInnes int SNESMatrixFreeMult_Private(Mat mat,Vec a,Vec y)
6939e2f89bSBarry Smith {
70fae171e0SBarry Smith   MFCtx_Private *ctx;
71fae171e0SBarry Smith   SNES          snes;
72eb9086c3SLois Curfman McInnes   double        norm, sum, umin;
735334005bSBarry Smith   Scalar        h, dot, mone = -1.0;
74fae171e0SBarry Smith   Vec           w,U,F;
7583e56afdSLois Curfman McInnes   int           ierr, (*eval_fct)(SNES,Vec,Vec);
7639e2f89bSBarry Smith 
77fae171e0SBarry Smith   MatShellGetContext(mat,(void **)&ctx);
78fae171e0SBarry Smith   snes = ctx->snes;
79fae171e0SBarry Smith   w    = ctx->w;
80eb9086c3SLois Curfman McInnes   umin = ctx->umin;
81fae171e0SBarry Smith 
8257c37382SLois Curfman McInnes   /* We log matrix-free matrix-vector products separately, so that we can
8357c37382SLois Curfman McInnes      separate the performance monitoring from the cases that use conventional
8457c37382SLois Curfman McInnes      storage.  We may eventually modify event logging to associate events
8557c37382SLois Curfman McInnes      with particular objects, hence alleviating the more general problem. */
86eb9086c3SLois Curfman McInnes   PLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);
8757c37382SLois Curfman McInnes 
8878b31e54SBarry Smith   ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr);
8983e56afdSLois Curfman McInnes   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
9083e56afdSLois Curfman McInnes     eval_fct = SNESComputeFunction;
9178b31e54SBarry Smith     ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr);
9283e56afdSLois Curfman McInnes   }
9383e56afdSLois Curfman McInnes   else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
9483e56afdSLois Curfman McInnes     eval_fct = SNESComputeGradient;
9583e56afdSLois Curfman McInnes     ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr);
9683e56afdSLois Curfman McInnes   }
97e3372554SBarry Smith   else SETERRQ(1,0,"Invalid method class");
9850361f65SLois Curfman McInnes 
99eb9086c3SLois Curfman McInnes   /* Determine a "good" step size, h */
100eb9086c3SLois Curfman McInnes   ierr = VecDot(U,a,&dot); CHKERRQ(ierr);
101eb9086c3SLois Curfman McInnes   ierr = VecNorm(a,NORM_1,&sum); CHKERRQ(ierr);
102eb9086c3SLois Curfman McInnes   ierr = VecNorm(a,NORM_2,&norm); CHKERRQ(ierr);
103eb9086c3SLois Curfman McInnes 
104eb9086c3SLois Curfman McInnes   /* Safeguard for step sizes too small */
105edd2f0e1SBarry Smith   if (sum == 0.0) {dot = 1.0; norm = 1.0;}
10619a167f6SBarry Smith #if defined(PETSC_COMPLEX)
107eb9086c3SLois Curfman McInnes   else if (abs(dot) < umin*sum && real(dot) >= 0.0) dot = umin*sum;
108eb9086c3SLois Curfman McInnes   else if (abs(dot) < 0.0 && real(dot) > -umin*sum) dot = -umin*sum;
10919a167f6SBarry Smith #else
110eb9086c3SLois Curfman McInnes   else if (dot < umin*sum && dot >= 0.0) dot = umin*sum;
111eb9086c3SLois Curfman McInnes   else if (dot < 0.0 && dot > -umin*sum) dot = -umin*sum;
11219a167f6SBarry Smith #endif
113eb9086c3SLois Curfman McInnes   h = ctx->error_rel*dot/(norm*norm);
11439e2f89bSBarry Smith 
115eb9086c3SLois Curfman McInnes   /* Evaluate function at F(u + ha) */
116eb9086c3SLois Curfman McInnes   ierr = VecWAXPY(&h,a,U,w); CHKERRQ(ierr);
11783e56afdSLois Curfman McInnes   ierr = eval_fct(snes,w,y); CHKERRQ(ierr);
118195ee392SLois Curfman McInnes   ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr);
1195334005bSBarry Smith   h = 1.0/h;
120195ee392SLois Curfman McInnes   ierr = VecScale(&h,y); CHKERRQ(ierr);
121b4fd4287SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);}
12257c37382SLois Curfman McInnes 
123eb9086c3SLois Curfman McInnes   PLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);
12439e2f89bSBarry Smith   return 0;
12539e2f89bSBarry Smith }
12683e56afdSLois Curfman McInnes 
1275615d1e5SSatish Balay #undef __FUNC__
1285615d1e5SSatish Balay #define __FUNC__ "SNESDefaultMatrixFreeMatCreate"
1294b828684SBarry Smith /*@C
1305392566eSBarry Smith    SNESDefaultMatrixFreeMatCreate - Creates a matrix-free matrix
13150361f65SLois Curfman McInnes    context for use with a SNES solver.  This matrix can be used as
13250361f65SLois Curfman McInnes    the Jacobian argument for the routine SNESSetJacobian().
1335392566eSBarry Smith 
1345392566eSBarry Smith    Input Parameters:
135eb9086c3SLois Curfman McInnes .  snes - the SNES context
1365392566eSBarry Smith .  x - vector where SNES solution is to be stored.
1375392566eSBarry Smith 
138eb9086c3SLois Curfman McInnes    Output Parameter:
1395392566eSBarry Smith .  J - the matrix-free matrix
1405392566eSBarry Smith 
14165afa06eSLois Curfman McInnes    Notes:
14265afa06eSLois Curfman McInnes    The matrix-free matrix context merely contains the function pointers
14365afa06eSLois Curfman McInnes    and work space for performing finite difference approximations of
144*3d5db8e1SLois Curfman McInnes    Jacobian-vector products, J(u)*a, via
145*3d5db8e1SLois Curfman McInnes 
146*3d5db8e1SLois Curfman McInnes $       J(u)*a = [J(u+h*a) - J(u)]/h where
147*3d5db8e1SLois Curfman McInnes $        h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
148*3d5db8e1SLois Curfman McInnes $          = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
149*3d5db8e1SLois Curfman McInnes $   where
150*3d5db8e1SLois Curfman McInnes $        error_rel = square root of relative error in
151*3d5db8e1SLois Curfman McInnes $                    function evaluation
152*3d5db8e1SLois Curfman McInnes $        umin = minimum iterate parameter
153*3d5db8e1SLois Curfman McInnes 
154*3d5db8e1SLois Curfman McInnes    The user can set these parameters via SNESSetMatrixFreeParameters().
155*3d5db8e1SLois Curfman McInnes    See the nonlinear solvers chapter of the users manual for details.
15665afa06eSLois Curfman McInnes 
15765afa06eSLois Curfman McInnes    The user should call MatDestroy() when finished with the matrix-free
15865afa06eSLois Curfman McInnes    matrix context.
15965afa06eSLois Curfman McInnes 
160*3d5db8e1SLois Curfman McInnes    Options Database Keys:
161*3d5db8e1SLois Curfman McInnes $  -snes_mf_err <error_rel>
162*3d5db8e1SLois Curfman McInnes $  -snes_mf_unim <umin>
163*3d5db8e1SLois Curfman McInnes 
16465afa06eSLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix
16565afa06eSLois Curfman McInnes 
166*3d5db8e1SLois Curfman McInnes .seealso: MatDestroy(), SNESSetMatrixFreeParameters()
1675392566eSBarry Smith @*/
1685392566eSBarry Smith int SNESDefaultMatrixFreeMatCreate(SNES snes,Vec x, Mat *J)
1695392566eSBarry Smith {
1705392566eSBarry Smith   MPI_Comm      comm;
1715392566eSBarry Smith   MFCtx_Private *mfctx;
172eb9086c3SLois Curfman McInnes   int           n, nloc, ierr, flg;
1733e966953SLois Curfman McInnes   char          p[64];
1745392566eSBarry Smith 
1750452661fSBarry Smith   mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx);
176464493b3SBarry Smith   PLogObjectMemory(snes,sizeof(MFCtx_Private));
177b4fd4287SBarry Smith   mfctx->sp   = 0;
1785392566eSBarry Smith   mfctx->snes = snes;
179eb9086c3SLois Curfman McInnes   mfctx->error_rel = 1.e-8; /* assumes double precision */
180639f9d9dSBarry Smith   mfctx->umin      = 1.e-6;
181eb9086c3SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg); CHKERRQ(ierr);
182eb9086c3SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_umin",&mfctx->umin,&flg); CHKERRQ(ierr);
183639f9d9dSBarry Smith   ierr = OptionsHasName(PETSC_NULL,"-help",&flg); CHKERRQ(ierr);
1843e966953SLois Curfman McInnes   PetscStrcpy(p,"-");
1853e966953SLois Curfman McInnes   if (snes->prefix) PetscStrcat(p,snes->prefix);
186639f9d9dSBarry Smith   if (flg) {
1873e966953SLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_err <err>: set sqrt rel error in function (default %g)\n",p,mfctx->error_rel);
1883e966953SLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_umin <umin> see users manual (default %g)\n",p,mfctx->umin);
189639f9d9dSBarry Smith   }
1905392566eSBarry Smith   ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr);
191195ee392SLois Curfman McInnes   ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr);
192195ee392SLois Curfman McInnes   ierr = VecGetSize(x,&n); CHKERRQ(ierr);
1937ddc982cSLois Curfman McInnes   ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr);
1947ddc982cSLois Curfman McInnes   ierr = MatCreateShell(comm,nloc,n,n,n,(void*)mfctx,J); CHKERRQ(ierr);
1951c1c02c0SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)SNESMatrixFreeMult_Private); CHKERRQ(ierr);
1961c1c02c0SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)SNESMatrixFreeDestroy_Private); CHKERRQ(ierr);
1971c1c02c0SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)SNESMatrixFreeView_Private); CHKERRQ(ierr);
198b9fa9cd0SBarry Smith   PLogObjectParent(*J,mfctx->w);
199d370d78aSBarry Smith   PLogObjectParent(snes,*J);
20081e6777dSBarry Smith   return 0;
20181e6777dSBarry Smith }
20281e6777dSBarry Smith 
2035615d1e5SSatish Balay #undef __FUNC__
2045615d1e5SSatish Balay #define __FUNC__ "SNESSetMatrixFreeParameters"
205b4fd4287SBarry Smith /*@
206eb9086c3SLois Curfman McInnes    SNESSetMatrixFreeParameters - Sets the parameters for the approximation of
207eb9086c3SLois Curfman McInnes    matrix-vector products using finite differences.
208eb9086c3SLois Curfman McInnes 
209639f9d9dSBarry Smith $       J(u)*a = [J(u+h*a) - J(u)]/h where
210639f9d9dSBarry Smith $        h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
211639f9d9dSBarry Smith $          = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
212639f9d9dSBarry Smith $
213eb9086c3SLois Curfman McInnes    Input Parameters:
214eb9086c3SLois Curfman McInnes .  snes - the SNES context
215ccb6204bSLois Curfman McInnes .  error_rel - relative error (should be set to the square root of
216ccb6204bSLois Curfman McInnes      the relative error in the function evaluations)
217eb9086c3SLois Curfman McInnes .  umin - minimum allowable u-value
218eb9086c3SLois Curfman McInnes 
219eb9086c3SLois Curfman McInnes .keywords: SNES, matrix-free, parameters
220*3d5db8e1SLois Curfman McInnes 
221*3d5db8e1SLois Curfman McInnes .seealso: SNESDefaultMatrixFreeMatCreate()
222eb9086c3SLois Curfman McInnes @*/
223eb9086c3SLois Curfman McInnes int SNESSetMatrixFreeParameters(SNES snes,double error,double umin)
224eb9086c3SLois Curfman McInnes {
225eb9086c3SLois Curfman McInnes   MFCtx_Private *ctx;
226eb9086c3SLois Curfman McInnes   int           ierr;
227eb9086c3SLois Curfman McInnes   Mat           mat;
228eb9086c3SLois Curfman McInnes 
229eb9086c3SLois Curfman McInnes   ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
230eb9086c3SLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
231eb9086c3SLois Curfman McInnes   if (ctx) {
232eb9086c3SLois Curfman McInnes     if (error != PETSC_DEFAULT) ctx->error_rel = error;
233eb9086c3SLois Curfman McInnes     if (umin != PETSC_DEFAULT)  ctx->umin = umin;
234eb9086c3SLois Curfman McInnes   }
235eb9086c3SLois Curfman McInnes   return 0;
236eb9086c3SLois Curfman McInnes }
237eb9086c3SLois Curfman McInnes 
2385615d1e5SSatish Balay #undef __FUNC__
2395615d1e5SSatish Balay #define __FUNC__ "SNESDefaultMatrixFreeMatAddNullSpace"
240eb9086c3SLois Curfman McInnes /*@
24121a45821SLois Curfman McInnes    SNESDefaultMatrixFreeMatAddNullSpace - Provides a null space that
242f525115eSLois Curfman McInnes    an operator is supposed to have.  Since roundoff will create a
243b4fd4287SBarry Smith    small component in the null space, if you know the null space
244b4fd4287SBarry Smith    you may have it automatically removed.
245b4fd4287SBarry Smith 
246b4fd4287SBarry Smith    Input Parameters:
24721a45821SLois Curfman McInnes .  J - the matrix-free matrix context
24821a45821SLois Curfman McInnes .  has_cnst - PETSC_TRUE or PETSC_FALSE, indicating if null space has constants
249b4fd4287SBarry Smith .  n - number of vectors (excluding constant vector) in null space
25021a45821SLois Curfman McInnes .  vecs - the vectors that span the null space (excluding the constant vector);
251b4fd4287SBarry Smith .         these vectors must be orthonormal
252b4fd4287SBarry Smith 
253b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space
254b4fd4287SBarry Smith @*/
255b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs)
256b4fd4287SBarry Smith {
257b4fd4287SBarry Smith   int           ierr;
258b4fd4287SBarry Smith   MFCtx_Private *ctx;
259b4fd4287SBarry Smith   MPI_Comm      comm;
260b4fd4287SBarry Smith 
261b4fd4287SBarry Smith   PetscObjectGetComm((PetscObject)J,&comm);
262b4fd4287SBarry Smith 
263b4fd4287SBarry Smith   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
264b4fd4287SBarry Smith   /* no context indicates that it is not the "matrix free" matrix type */
265b4fd4287SBarry Smith   if (!ctx) return 0;
266b4fd4287SBarry Smith   ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr);
267b4fd4287SBarry Smith   return 0;
268b4fd4287SBarry Smith }
269b4fd4287SBarry Smith 
2705334005bSBarry Smith 
2715334005bSBarry Smith 
2725334005bSBarry Smith 
273