xref: /petsc/src/snes/mf/snesmfj.c (revision 029af93f72d387caa45cf6909ac9aed2d04296ca)
181e6777dSBarry Smith 
281e6777dSBarry Smith #ifndef lint
3*029af93fSBarry Smith static char vcid[] = "$Id: snesmfj.c,v 1.48 1997/04/07 20:11:46 bsmith Exp bsmith $";
481e6777dSBarry Smith #endif
581e6777dSBarry Smith 
670f55243SBarry Smith #include "src/snes/snesimpl.h"   /*I  "snes.h"   I*/
7eb9086c3SLois Curfman McInnes #include "pinclude/pviewer.h"
881e6777dSBarry Smith 
950361f65SLois Curfman McInnes typedef struct {  /* default context for matrix-free SNES */
10eb9086c3SLois Curfman McInnes   SNES        snes;      /* SNES context */
11eb9086c3SLois Curfman McInnes   Vec         w;         /* work vector */
12eb9086c3SLois Curfman McInnes   PCNullSpace sp;        /* null space context */
13eb9086c3SLois Curfman McInnes   double      error_rel; /* square root of relative error in computing function */
14639f9d9dSBarry Smith   double      umin;      /* minimum allowable u'a value relative to |u|_1 */
1539e2f89bSBarry Smith } MFCtx_Private;
1639e2f89bSBarry Smith 
175615d1e5SSatish Balay #undef __FUNC__
185eea60f9SBarry Smith #define __FUNC__ "SNESMatrixFreeDestroy_Private" /* ADIC Ignore */
19fae171e0SBarry Smith int SNESMatrixFreeDestroy_Private(PetscObject obj)
20b9fa9cd0SBarry Smith {
21b9fa9cd0SBarry Smith   int           ierr;
22fae171e0SBarry Smith   Mat           mat = (Mat) obj;
23fae171e0SBarry Smith   MFCtx_Private *ctx;
24fae171e0SBarry Smith 
25fae171e0SBarry Smith   ierr = MatShellGetContext(mat,(void **)&ctx);
26b9fa9cd0SBarry Smith   ierr = VecDestroy(ctx->w); CHKERRQ(ierr);
27b4fd4287SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp); CHKERRQ(ierr);}
28fae171e0SBarry Smith   PetscFree(ctx);
29b9fa9cd0SBarry Smith   return 0;
30b9fa9cd0SBarry Smith }
3150361f65SLois Curfman McInnes 
325615d1e5SSatish Balay #undef __FUNC__
335eea60f9SBarry Smith #define __FUNC__ "SNESMatrixFreeView_Private" /* ADIC Ignore */
3439e2f89bSBarry Smith /*
351d1bbde2SLois Curfman McInnes    SNESMatrixFreeView_Private - Views matrix-free parameters.
3639e2f89bSBarry Smith  */
37eb9086c3SLois Curfman McInnes int SNESMatrixFreeView_Private(Mat J,Viewer viewer)
38eb9086c3SLois Curfman McInnes {
39eb9086c3SLois Curfman McInnes   int           ierr;
40eb9086c3SLois Curfman McInnes   MFCtx_Private *ctx;
41eb9086c3SLois Curfman McInnes   MPI_Comm      comm;
42eb9086c3SLois Curfman McInnes   FILE          *fd;
43eb9086c3SLois Curfman McInnes   ViewerType    vtype;
44eb9086c3SLois Curfman McInnes 
45eb9086c3SLois Curfman McInnes   PetscObjectGetComm((PetscObject)J,&comm);
46eb9086c3SLois Curfman McInnes   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
47eb9086c3SLois Curfman McInnes   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
48eb9086c3SLois Curfman McInnes   ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
49eb9086c3SLois Curfman McInnes   if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
50eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"  SNES matrix-free approximation:\n");
51eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"    err=%g (relative error in function evaluation)\n",ctx->error_rel);
52eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"    umin=%g (minimum iterate parameter)\n",ctx->umin);
53eb9086c3SLois Curfman McInnes   }
54eb9086c3SLois Curfman McInnes   return 0;
55eb9086c3SLois Curfman McInnes }
56eb9086c3SLois Curfman McInnes 
575615d1e5SSatish Balay #undef __FUNC__
585615d1e5SSatish Balay #define __FUNC__ "SNESMatrixFreeMult_Private"
59eb9086c3SLois Curfman McInnes /*
60eb9086c3SLois Curfman McInnes   SNESMatrixFreeMult_Private - Default matrix-free form for Jacobian-vector
61eb9086c3SLois Curfman McInnes   product, y = F'(u)*a:
62eb9086c3SLois Curfman McInnes         y = ( F(u + ha) - F(u) ) /h,
63eb9086c3SLois Curfman McInnes   where F = nonlinear function, as set by SNESSetFunction()
64eb9086c3SLois Curfman McInnes         u = current iterate
65eb9086c3SLois Curfman McInnes         h = difference interval
66eb9086c3SLois Curfman McInnes */
67eb9086c3SLois Curfman McInnes int SNESMatrixFreeMult_Private(Mat mat,Vec a,Vec y)
6839e2f89bSBarry Smith {
69fae171e0SBarry Smith   MFCtx_Private *ctx;
70fae171e0SBarry Smith   SNES          snes;
71eb9086c3SLois Curfman McInnes   double        norm, sum, umin;
725334005bSBarry Smith   Scalar        h, dot, mone = -1.0;
73fae171e0SBarry Smith   Vec           w,U,F;
7483e56afdSLois Curfman McInnes   int           ierr, (*eval_fct)(SNES,Vec,Vec);
7539e2f89bSBarry Smith 
766e38a044SBarry Smith   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
77fae171e0SBarry Smith   snes = ctx->snes;
78fae171e0SBarry Smith   w    = ctx->w;
79eb9086c3SLois Curfman McInnes   umin = ctx->umin;
80fae171e0SBarry Smith 
8157c37382SLois Curfman McInnes   /* We log matrix-free matrix-vector products separately, so that we can
8257c37382SLois Curfman McInnes      separate the performance monitoring from the cases that use conventional
8357c37382SLois Curfman McInnes      storage.  We may eventually modify event logging to associate events
8457c37382SLois Curfman McInnes      with particular objects, hence alleviating the more general problem. */
85eb9086c3SLois Curfman McInnes   PLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);
8657c37382SLois Curfman McInnes 
8778b31e54SBarry Smith   ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr);
8883e56afdSLois Curfman McInnes   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
8983e56afdSLois Curfman McInnes     eval_fct = SNESComputeFunction;
9078b31e54SBarry Smith     ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr);
9183e56afdSLois Curfman McInnes   }
9283e56afdSLois Curfman McInnes   else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
9383e56afdSLois Curfman McInnes     eval_fct = SNESComputeGradient;
9483e56afdSLois Curfman McInnes     ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr);
9583e56afdSLois Curfman McInnes   }
96e3372554SBarry Smith   else SETERRQ(1,0,"Invalid method class");
9750361f65SLois Curfman McInnes 
98eb9086c3SLois Curfman McInnes   /* Determine a "good" step size, h */
99eb9086c3SLois Curfman McInnes   ierr = VecDot(U,a,&dot); CHKERRQ(ierr);
100eb9086c3SLois Curfman McInnes   ierr = VecNorm(a,NORM_1,&sum); CHKERRQ(ierr);
101eb9086c3SLois Curfman McInnes   ierr = VecNorm(a,NORM_2,&norm); CHKERRQ(ierr);
102eb9086c3SLois Curfman McInnes 
103eb9086c3SLois Curfman McInnes   /* Safeguard for step sizes too small */
104edd2f0e1SBarry Smith   if (sum == 0.0) {dot = 1.0; norm = 1.0;}
10519a167f6SBarry Smith #if defined(PETSC_COMPLEX)
106eb9086c3SLois Curfman McInnes   else if (abs(dot) < umin*sum && real(dot) >= 0.0) dot = umin*sum;
107eb9086c3SLois Curfman McInnes   else if (abs(dot) < 0.0 && real(dot) > -umin*sum) dot = -umin*sum;
10819a167f6SBarry Smith #else
109eb9086c3SLois Curfman McInnes   else if (dot < umin*sum && dot >= 0.0) dot = umin*sum;
110eb9086c3SLois Curfman McInnes   else if (dot < 0.0 && dot > -umin*sum) dot = -umin*sum;
11119a167f6SBarry Smith #endif
112eb9086c3SLois Curfman McInnes   h = ctx->error_rel*dot/(norm*norm);
11339e2f89bSBarry Smith 
114eb9086c3SLois Curfman McInnes   /* Evaluate function at F(u + ha) */
115eb9086c3SLois Curfman McInnes   ierr = VecWAXPY(&h,a,U,w); CHKERRQ(ierr);
11683e56afdSLois Curfman McInnes   ierr = eval_fct(snes,w,y); CHKERRQ(ierr);
117195ee392SLois Curfman McInnes   ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr);
1185334005bSBarry Smith   h = 1.0/h;
119195ee392SLois Curfman McInnes   ierr = VecScale(&h,y); CHKERRQ(ierr);
120b4fd4287SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);}
12157c37382SLois Curfman McInnes 
122eb9086c3SLois Curfman McInnes   PLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);
12339e2f89bSBarry Smith   return 0;
12439e2f89bSBarry Smith }
12583e56afdSLois Curfman McInnes 
1265615d1e5SSatish Balay #undef __FUNC__
1275615d1e5SSatish Balay #define __FUNC__ "SNESDefaultMatrixFreeMatCreate"
1284b828684SBarry Smith /*@C
1295392566eSBarry Smith    SNESDefaultMatrixFreeMatCreate - Creates a matrix-free matrix
13050361f65SLois Curfman McInnes    context for use with a SNES solver.  This matrix can be used as
13150361f65SLois Curfman McInnes    the Jacobian argument for the routine SNESSetJacobian().
1325392566eSBarry Smith 
1335392566eSBarry Smith    Input Parameters:
134eb9086c3SLois Curfman McInnes .  snes - the SNES context
1355392566eSBarry Smith .  x - vector where SNES solution is to be stored.
1365392566eSBarry Smith 
137eb9086c3SLois Curfman McInnes    Output Parameter:
1385392566eSBarry Smith .  J - the matrix-free matrix
1395392566eSBarry Smith 
14065afa06eSLois Curfman McInnes    Notes:
14165afa06eSLois Curfman McInnes    The matrix-free matrix context merely contains the function pointers
14265afa06eSLois Curfman McInnes    and work space for performing finite difference approximations of
1433d5db8e1SLois Curfman McInnes    Jacobian-vector products, J(u)*a, via
1443d5db8e1SLois Curfman McInnes 
1453d5db8e1SLois Curfman McInnes $       J(u)*a = [J(u+h*a) - J(u)]/h where
1463d5db8e1SLois Curfman McInnes $        h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
1473d5db8e1SLois Curfman McInnes $          = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   otherwise
1483d5db8e1SLois Curfman McInnes $   where
1493d5db8e1SLois Curfman McInnes $        error_rel = square root of relative error in
1503d5db8e1SLois Curfman McInnes $                    function evaluation
1513d5db8e1SLois Curfman McInnes $        umin = minimum iterate parameter
1523d5db8e1SLois Curfman McInnes 
1533d5db8e1SLois Curfman McInnes    The user can set these parameters via SNESSetMatrixFreeParameters().
1543d5db8e1SLois Curfman McInnes    See the nonlinear solvers chapter of the users manual for details.
15565afa06eSLois Curfman McInnes 
15665afa06eSLois Curfman McInnes    The user should call MatDestroy() when finished with the matrix-free
15765afa06eSLois Curfman McInnes    matrix context.
15865afa06eSLois Curfman McInnes 
1593d5db8e1SLois Curfman McInnes    Options Database Keys:
1603d5db8e1SLois Curfman McInnes $  -snes_mf_err <error_rel>
1613d5db8e1SLois Curfman McInnes $  -snes_mf_unim <umin>
1623d5db8e1SLois Curfman McInnes 
16365afa06eSLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix
16465afa06eSLois Curfman McInnes 
1653d5db8e1SLois Curfman McInnes .seealso: MatDestroy(), SNESSetMatrixFreeParameters()
1665392566eSBarry Smith @*/
1675392566eSBarry Smith int SNESDefaultMatrixFreeMatCreate(SNES snes,Vec x, Mat *J)
1685392566eSBarry Smith {
1695392566eSBarry Smith   MPI_Comm      comm;
1705392566eSBarry Smith   MFCtx_Private *mfctx;
171eb9086c3SLois Curfman McInnes   int           n, nloc, ierr, flg;
1723e966953SLois Curfman McInnes   char          p[64];
1735392566eSBarry Smith 
1740452661fSBarry Smith   mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx);
175464493b3SBarry Smith   PLogObjectMemory(snes,sizeof(MFCtx_Private));
176b4fd4287SBarry Smith   mfctx->sp   = 0;
1775392566eSBarry Smith   mfctx->snes = snes;
178eb9086c3SLois Curfman McInnes   mfctx->error_rel = 1.e-8; /* assumes double precision */
179639f9d9dSBarry Smith   mfctx->umin      = 1.e-6;
180eb9086c3SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg); CHKERRQ(ierr);
181eb9086c3SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_umin",&mfctx->umin,&flg); CHKERRQ(ierr);
182639f9d9dSBarry Smith   ierr = OptionsHasName(PETSC_NULL,"-help",&flg); CHKERRQ(ierr);
1833e966953SLois Curfman McInnes   PetscStrcpy(p,"-");
1843e966953SLois Curfman McInnes   if (snes->prefix) PetscStrcat(p,snes->prefix);
185639f9d9dSBarry Smith   if (flg) {
1863e966953SLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_err <err>: set sqrt rel error in function (default %g)\n",p,mfctx->error_rel);
1873e966953SLois Curfman McInnes     PetscPrintf(snes->comm,"   %ssnes_mf_umin <umin> see users manual (default %g)\n",p,mfctx->umin);
188639f9d9dSBarry Smith   }
1895392566eSBarry Smith   ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr);
190195ee392SLois Curfman McInnes   ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr);
191195ee392SLois Curfman McInnes   ierr = VecGetSize(x,&n); CHKERRQ(ierr);
1927ddc982cSLois Curfman McInnes   ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr);
193*029af93fSBarry Smith   ierr = MatCreateShell(comm,nloc,n,n,n,mfctx,J); CHKERRQ(ierr);
1941c1c02c0SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)SNESMatrixFreeMult_Private);CHKERRQ(ierr);
1951c1c02c0SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)SNESMatrixFreeDestroy_Private);CHKERRQ(ierr);
1961c1c02c0SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)SNESMatrixFreeView_Private); CHKERRQ(ierr);
197b9fa9cd0SBarry Smith   PLogObjectParent(*J,mfctx->w);
198d370d78aSBarry Smith   PLogObjectParent(snes,*J);
19981e6777dSBarry Smith   return 0;
20081e6777dSBarry Smith }
20181e6777dSBarry Smith 
2025615d1e5SSatish Balay #undef __FUNC__
2035615d1e5SSatish Balay #define __FUNC__ "SNESSetMatrixFreeParameters"
204b4fd4287SBarry Smith /*@
205eb9086c3SLois Curfman McInnes    SNESSetMatrixFreeParameters - Sets the parameters for the approximation of
206eb9086c3SLois Curfman McInnes    matrix-vector products using finite differences.
207eb9086c3SLois Curfman McInnes 
208639f9d9dSBarry Smith $       J(u)*a = [J(u+h*a) - J(u)]/h where
209639f9d9dSBarry Smith $        h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
210639f9d9dSBarry Smith $          = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
211639f9d9dSBarry Smith $
212eb9086c3SLois Curfman McInnes    Input Parameters:
213eb9086c3SLois Curfman McInnes .  snes - the SNES context
214ccb6204bSLois Curfman McInnes .  error_rel - relative error (should be set to the square root of
215ccb6204bSLois Curfman McInnes      the relative error in the function evaluations)
216eb9086c3SLois Curfman McInnes .  umin - minimum allowable u-value
217eb9086c3SLois Curfman McInnes 
218eb9086c3SLois Curfman McInnes .keywords: SNES, matrix-free, parameters
2193d5db8e1SLois Curfman McInnes 
2203d5db8e1SLois Curfman McInnes .seealso: SNESDefaultMatrixFreeMatCreate()
221eb9086c3SLois Curfman McInnes @*/
222eb9086c3SLois Curfman McInnes int SNESSetMatrixFreeParameters(SNES snes,double error,double umin)
223eb9086c3SLois Curfman McInnes {
224eb9086c3SLois Curfman McInnes   MFCtx_Private *ctx;
225eb9086c3SLois Curfman McInnes   int           ierr;
226eb9086c3SLois Curfman McInnes   Mat           mat;
227eb9086c3SLois Curfman McInnes 
228eb9086c3SLois Curfman McInnes   ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
229eb9086c3SLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
230eb9086c3SLois Curfman McInnes   if (ctx) {
231eb9086c3SLois Curfman McInnes     if (error != PETSC_DEFAULT) ctx->error_rel = error;
232eb9086c3SLois Curfman McInnes     if (umin != PETSC_DEFAULT)  ctx->umin = umin;
233eb9086c3SLois Curfman McInnes   }
234eb9086c3SLois Curfman McInnes   return 0;
235eb9086c3SLois Curfman McInnes }
236eb9086c3SLois Curfman McInnes 
2375615d1e5SSatish Balay #undef __FUNC__
2385615d1e5SSatish Balay #define __FUNC__ "SNESDefaultMatrixFreeMatAddNullSpace"
239eb9086c3SLois Curfman McInnes /*@
24021a45821SLois Curfman McInnes    SNESDefaultMatrixFreeMatAddNullSpace - Provides a null space that
241f525115eSLois Curfman McInnes    an operator is supposed to have.  Since roundoff will create a
242b4fd4287SBarry Smith    small component in the null space, if you know the null space
243b4fd4287SBarry Smith    you may have it automatically removed.
244b4fd4287SBarry Smith 
245b4fd4287SBarry Smith    Input Parameters:
24621a45821SLois Curfman McInnes .  J - the matrix-free matrix context
24721a45821SLois Curfman McInnes .  has_cnst - PETSC_TRUE or PETSC_FALSE, indicating if null space has constants
248b4fd4287SBarry Smith .  n - number of vectors (excluding constant vector) in null space
24921a45821SLois Curfman McInnes .  vecs - the vectors that span the null space (excluding the constant vector);
250b4fd4287SBarry Smith .         these vectors must be orthonormal
251b4fd4287SBarry Smith 
252b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space
253b4fd4287SBarry Smith @*/
254b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs)
255b4fd4287SBarry Smith {
256b4fd4287SBarry Smith   int           ierr;
257b4fd4287SBarry Smith   MFCtx_Private *ctx;
258b4fd4287SBarry Smith   MPI_Comm      comm;
259b4fd4287SBarry Smith 
260b4fd4287SBarry Smith   PetscObjectGetComm((PetscObject)J,&comm);
261b4fd4287SBarry Smith 
262b4fd4287SBarry Smith   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
263b4fd4287SBarry Smith   /* no context indicates that it is not the "matrix free" matrix type */
264b4fd4287SBarry Smith   if (!ctx) return 0;
265b4fd4287SBarry Smith   ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr);
266b4fd4287SBarry Smith   return 0;
267b4fd4287SBarry Smith }
268b4fd4287SBarry Smith 
2695334005bSBarry Smith 
2705334005bSBarry Smith 
2715334005bSBarry Smith 
272