xref: /petsc/src/snes/mf/snesmfj.c (revision 639f9d9dbbc54d6ac4e42e98283c540b41bb2cee)
181e6777dSBarry Smith 
281e6777dSBarry Smith #ifndef lint
3*639f9d9dSBarry Smith static char vcid[] = "$Id: snesmfj.c,v 1.37 1996/09/28 23:11:46 curfman Exp bsmith $";
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 */
15*639f9d9dSBarry Smith   double      umin;      /* minimum allowable u'a value relative to |u|_1 */
1639e2f89bSBarry Smith } MFCtx_Private;
1739e2f89bSBarry Smith 
18fae171e0SBarry Smith int SNESMatrixFreeDestroy_Private(PetscObject obj)
19b9fa9cd0SBarry Smith {
20b9fa9cd0SBarry Smith   int           ierr;
21fae171e0SBarry Smith   Mat           mat = (Mat) obj;
22fae171e0SBarry Smith   MFCtx_Private *ctx;
23fae171e0SBarry Smith 
24fae171e0SBarry Smith   ierr = MatShellGetContext(mat,(void **)&ctx);
25b9fa9cd0SBarry Smith   ierr = VecDestroy(ctx->w); CHKERRQ(ierr);
26b4fd4287SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp); CHKERRQ(ierr);}
27fae171e0SBarry Smith   PetscFree(ctx);
28b9fa9cd0SBarry Smith   return 0;
29b9fa9cd0SBarry Smith }
3050361f65SLois Curfman McInnes 
3139e2f89bSBarry Smith /*
321d1bbde2SLois Curfman McInnes    SNESMatrixFreeView_Private - Views matrix-free parameters.
3339e2f89bSBarry Smith  */
34eb9086c3SLois Curfman McInnes int SNESMatrixFreeView_Private(Mat J,Viewer viewer)
35eb9086c3SLois Curfman McInnes {
36eb9086c3SLois Curfman McInnes   int           ierr;
37eb9086c3SLois Curfman McInnes   MFCtx_Private *ctx;
38eb9086c3SLois Curfman McInnes   MPI_Comm      comm;
39eb9086c3SLois Curfman McInnes   FILE          *fd;
40eb9086c3SLois Curfman McInnes   ViewerType    vtype;
41eb9086c3SLois Curfman McInnes 
42eb9086c3SLois Curfman McInnes   PetscObjectGetComm((PetscObject)J,&comm);
43eb9086c3SLois Curfman McInnes   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
44eb9086c3SLois Curfman McInnes   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
45eb9086c3SLois Curfman McInnes   ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
46eb9086c3SLois Curfman McInnes   if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
47eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"  SNES matrix-free approximation:\n");
48eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"    err=%g (relative error in function evaluation)\n",ctx->error_rel);
49eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"    umin=%g (minimum iterate parameter)\n",ctx->umin);
50eb9086c3SLois Curfman McInnes   }
51eb9086c3SLois Curfman McInnes   return 0;
52eb9086c3SLois Curfman McInnes }
53eb9086c3SLois Curfman McInnes 
54eb9086c3SLois Curfman McInnes /*
55eb9086c3SLois Curfman McInnes   SNESMatrixFreeMult_Private - Default matrix-free form for Jacobian-vector
56eb9086c3SLois Curfman McInnes   product, y = F'(u)*a:
57eb9086c3SLois Curfman McInnes         y = ( F(u + ha) - F(u) ) /h,
58eb9086c3SLois Curfman McInnes   where F = nonlinear function, as set by SNESSetFunction()
59eb9086c3SLois Curfman McInnes         u = current iterate
60eb9086c3SLois Curfman McInnes         h = difference interval
61eb9086c3SLois Curfman McInnes */
62eb9086c3SLois Curfman McInnes int SNESMatrixFreeMult_Private(Mat mat,Vec a,Vec y)
6339e2f89bSBarry Smith {
64fae171e0SBarry Smith   MFCtx_Private *ctx;
65fae171e0SBarry Smith   SNES          snes;
66eb9086c3SLois Curfman McInnes   double        norm, sum, umin;
675334005bSBarry Smith   Scalar        h, dot, mone = -1.0;
68fae171e0SBarry Smith   Vec           w,U,F;
6983e56afdSLois Curfman McInnes   int           ierr, (*eval_fct)(SNES,Vec,Vec);
7039e2f89bSBarry Smith 
71fae171e0SBarry Smith   MatShellGetContext(mat,(void **)&ctx);
72fae171e0SBarry Smith   snes = ctx->snes;
73fae171e0SBarry Smith   w    = ctx->w;
74eb9086c3SLois Curfman McInnes   umin = ctx->umin;
75fae171e0SBarry Smith 
7657c37382SLois Curfman McInnes   /* We log matrix-free matrix-vector products separately, so that we can
7757c37382SLois Curfman McInnes      separate the performance monitoring from the cases that use conventional
7857c37382SLois Curfman McInnes      storage.  We may eventually modify event logging to associate events
7957c37382SLois Curfman McInnes      with particular objects, hence alleviating the more general problem. */
80eb9086c3SLois Curfman McInnes   PLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);
8157c37382SLois Curfman McInnes 
8278b31e54SBarry Smith   ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr);
8383e56afdSLois Curfman McInnes   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
8483e56afdSLois Curfman McInnes     eval_fct = SNESComputeFunction;
8578b31e54SBarry Smith     ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr);
8683e56afdSLois Curfman McInnes   }
8783e56afdSLois Curfman McInnes   else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
8883e56afdSLois Curfman McInnes     eval_fct = SNESComputeGradient;
8983e56afdSLois Curfman McInnes     ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr);
9083e56afdSLois Curfman McInnes   }
9183e56afdSLois Curfman McInnes   else SETERRQ(1,"SNESMatrixFreeMult_Private: Invalid method class");
9250361f65SLois Curfman McInnes 
93eb9086c3SLois Curfman McInnes   /* Determine a "good" step size, h */
94eb9086c3SLois Curfman McInnes   ierr = VecDot(U,a,&dot); CHKERRQ(ierr);
95eb9086c3SLois Curfman McInnes   ierr = VecNorm(a,NORM_1,&sum); CHKERRQ(ierr);
96eb9086c3SLois Curfman McInnes   ierr = VecNorm(a,NORM_2,&norm); CHKERRQ(ierr);
97eb9086c3SLois Curfman McInnes 
98eb9086c3SLois Curfman McInnes   /* Safeguard for step sizes too small */
99edd2f0e1SBarry Smith   if (sum == 0.0) {dot = 1.0; norm = 1.0;}
10019a167f6SBarry Smith #if defined(PETSC_COMPLEX)
101eb9086c3SLois Curfman McInnes   else if (abs(dot) < umin*sum && real(dot) >= 0.0) dot = umin*sum;
102eb9086c3SLois Curfman McInnes   else if (abs(dot) < 0.0 && real(dot) > -umin*sum) dot = -umin*sum;
10319a167f6SBarry Smith #else
104eb9086c3SLois Curfman McInnes   else if (dot < umin*sum && dot >= 0.0) dot = umin*sum;
105eb9086c3SLois Curfman McInnes   else if (dot < 0.0 && dot > -umin*sum) dot = -umin*sum;
10619a167f6SBarry Smith #endif
107eb9086c3SLois Curfman McInnes   h = ctx->error_rel*dot/(norm*norm);
10839e2f89bSBarry Smith 
109eb9086c3SLois Curfman McInnes   /* Evaluate function at F(u + ha) */
110eb9086c3SLois Curfman McInnes   ierr = VecWAXPY(&h,a,U,w); CHKERRQ(ierr);
11183e56afdSLois Curfman McInnes   ierr = eval_fct(snes,w,y); CHKERRQ(ierr);
112195ee392SLois Curfman McInnes   ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr);
1135334005bSBarry Smith   h = 1.0/h;
114195ee392SLois Curfman McInnes   ierr = VecScale(&h,y); CHKERRQ(ierr);
115b4fd4287SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);}
11657c37382SLois Curfman McInnes 
117eb9086c3SLois Curfman McInnes   PLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);
11839e2f89bSBarry Smith   return 0;
11939e2f89bSBarry Smith }
12083e56afdSLois Curfman McInnes 
1214b828684SBarry Smith /*@C
1225392566eSBarry Smith    SNESDefaultMatrixFreeMatCreate - Creates a matrix-free matrix
12350361f65SLois Curfman McInnes    context for use with a SNES solver.  This matrix can be used as
12450361f65SLois Curfman McInnes    the Jacobian argument for the routine SNESSetJacobian().
1255392566eSBarry Smith 
1265392566eSBarry Smith    Input Parameters:
127eb9086c3SLois Curfman McInnes .  snes - the SNES context
1285392566eSBarry Smith .  x - vector where SNES solution is to be stored.
1295392566eSBarry Smith 
130eb9086c3SLois Curfman McInnes    Output Parameter:
1315392566eSBarry Smith .  J - the matrix-free matrix
1325392566eSBarry Smith 
13365afa06eSLois Curfman McInnes    Notes:
13465afa06eSLois Curfman McInnes    The matrix-free matrix context merely contains the function pointers
13565afa06eSLois Curfman McInnes    and work space for performing finite difference approximations of
13665afa06eSLois Curfman McInnes    matrix operations such as matrix-vector products.
13765afa06eSLois Curfman McInnes 
13865afa06eSLois Curfman McInnes    The user should call MatDestroy() when finished with the matrix-free
13965afa06eSLois Curfman McInnes    matrix context.
14065afa06eSLois Curfman McInnes 
14165afa06eSLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix
14265afa06eSLois Curfman McInnes 
14365afa06eSLois Curfman McInnes .seealso: MatDestroy()
1445392566eSBarry Smith @*/
1455392566eSBarry Smith int SNESDefaultMatrixFreeMatCreate(SNES snes,Vec x, Mat *J)
1465392566eSBarry Smith {
1475392566eSBarry Smith   MPI_Comm      comm;
1485392566eSBarry Smith   MFCtx_Private *mfctx;
149eb9086c3SLois Curfman McInnes   int           n, nloc, ierr, flg;
1505392566eSBarry Smith 
1510452661fSBarry Smith   mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx);
152464493b3SBarry Smith   PLogObjectMemory(snes,sizeof(MFCtx_Private));
153b4fd4287SBarry Smith   mfctx->sp   = 0;
1545392566eSBarry Smith   mfctx->snes = snes;
155eb9086c3SLois Curfman McInnes   mfctx->error_rel = 1.e-8; /* assumes double precision */
156*639f9d9dSBarry Smith   mfctx->umin      = 1.e-6;
157eb9086c3SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg); CHKERRQ(ierr);
158eb9086c3SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_umin",&mfctx->umin,&flg); CHKERRQ(ierr);
159*639f9d9dSBarry Smith   ierr = OptionsHasName(PETSC_NULL,"-help",&flg); CHKERRQ(ierr);
160*639f9d9dSBarry Smith   if (flg) {
161*639f9d9dSBarry Smith     PetscPrintf(snes->comm,"-snes_mf_err <err> set sqrt rel tol in function. Default 1.e-8\n");
162*639f9d9dSBarry Smith     PetscPrintf(snes->comm,"-snes_mf_umin <umin> see users manual. Default 1.e-8\n");
163*639f9d9dSBarry Smith   }
1645392566eSBarry Smith   ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr);
165195ee392SLois Curfman McInnes   ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr);
166195ee392SLois Curfman McInnes   ierr = VecGetSize(x,&n); CHKERRQ(ierr);
1677ddc982cSLois Curfman McInnes   ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr);
1687ddc982cSLois Curfman McInnes   ierr = MatCreateShell(comm,nloc,n,n,n,(void*)mfctx,J); CHKERRQ(ierr);
1691c1c02c0SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)SNESMatrixFreeMult_Private); CHKERRQ(ierr);
1701c1c02c0SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)SNESMatrixFreeDestroy_Private); CHKERRQ(ierr);
1711c1c02c0SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)SNESMatrixFreeView_Private); CHKERRQ(ierr);
172b9fa9cd0SBarry Smith   PLogObjectParent(*J,mfctx->w);
173d370d78aSBarry Smith   PLogObjectParent(snes,*J);
17481e6777dSBarry Smith   return 0;
17581e6777dSBarry Smith }
17681e6777dSBarry Smith 
177b4fd4287SBarry Smith /*@
178eb9086c3SLois Curfman McInnes    SNESSetMatrixFreeParameters - Sets the parameters for the approximation of
179eb9086c3SLois Curfman McInnes    matrix-vector products using finite differences.
180eb9086c3SLois Curfman McInnes 
181*639f9d9dSBarry Smith $       J(u)*a = [J(u+h*a) - J(u)]/h where
182*639f9d9dSBarry Smith $        h = error_rel*u'a/||a||^2                        if  |u'a| > umin*||a||_{1}
183*639f9d9dSBarry Smith $          = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2   else
184*639f9d9dSBarry Smith $
185eb9086c3SLois Curfman McInnes    Input Parameters:
186eb9086c3SLois Curfman McInnes .  snes - the SNES context
187eb9086c3SLois Curfman McInnes .  error_rel - relative error
188eb9086c3SLois Curfman McInnes .  umin - minimum allowable u-value
189eb9086c3SLois Curfman McInnes 
190eb9086c3SLois Curfman McInnes .keywords: SNES, matrix-free, parameters
191eb9086c3SLois Curfman McInnes @*/
192eb9086c3SLois Curfman McInnes int SNESSetMatrixFreeParameters(SNES snes,double error,double umin)
193eb9086c3SLois Curfman McInnes {
194eb9086c3SLois Curfman McInnes   MFCtx_Private *ctx;
195eb9086c3SLois Curfman McInnes   int           ierr;
196eb9086c3SLois Curfman McInnes   Mat           mat;
197eb9086c3SLois Curfman McInnes 
198eb9086c3SLois Curfman McInnes   ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
199eb9086c3SLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
200eb9086c3SLois Curfman McInnes   if (ctx) {
201eb9086c3SLois Curfman McInnes     if (error != PETSC_DEFAULT) ctx->error_rel = error;
202eb9086c3SLois Curfman McInnes     if (umin != PETSC_DEFAULT)  ctx->umin = umin;
203eb9086c3SLois Curfman McInnes   }
204eb9086c3SLois Curfman McInnes   return 0;
205eb9086c3SLois Curfman McInnes }
206eb9086c3SLois Curfman McInnes 
207eb9086c3SLois Curfman McInnes /*@
20821a45821SLois Curfman McInnes    SNESDefaultMatrixFreeMatAddNullSpace - Provides a null space that
209f525115eSLois Curfman McInnes    an operator is supposed to have.  Since roundoff will create a
210b4fd4287SBarry Smith    small component in the null space, if you know the null space
211b4fd4287SBarry Smith    you may have it automatically removed.
212b4fd4287SBarry Smith 
213b4fd4287SBarry Smith    Input Parameters:
21421a45821SLois Curfman McInnes .  J - the matrix-free matrix context
21521a45821SLois Curfman McInnes .  has_cnst - PETSC_TRUE or PETSC_FALSE, indicating if null space has constants
216b4fd4287SBarry Smith .  n - number of vectors (excluding constant vector) in null space
21721a45821SLois Curfman McInnes .  vecs - the vectors that span the null space (excluding the constant vector);
218b4fd4287SBarry Smith .         these vectors must be orthonormal
219b4fd4287SBarry Smith 
220b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space
221b4fd4287SBarry Smith @*/
222b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs)
223b4fd4287SBarry Smith {
224b4fd4287SBarry Smith   int           ierr;
225b4fd4287SBarry Smith   MFCtx_Private *ctx;
226b4fd4287SBarry Smith   MPI_Comm      comm;
227b4fd4287SBarry Smith 
228b4fd4287SBarry Smith   PetscObjectGetComm((PetscObject)J,&comm);
229b4fd4287SBarry Smith 
230b4fd4287SBarry Smith   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
231b4fd4287SBarry Smith   /* no context indicates that it is not the "matrix free" matrix type */
232b4fd4287SBarry Smith   if (!ctx) return 0;
233b4fd4287SBarry Smith   ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr);
234b4fd4287SBarry Smith   return 0;
235b4fd4287SBarry Smith }
236b4fd4287SBarry Smith 
2375334005bSBarry Smith 
2385334005bSBarry Smith 
2395334005bSBarry Smith 
240