xref: /petsc/src/snes/mf/snesmfj.c (revision eb9086c326e4cc6bfdd7293d19465081a34d1265)
181e6777dSBarry Smith 
281e6777dSBarry Smith #ifndef lint
3*eb9086c3SLois Curfman McInnes static char vcid[] = "$Id: snesmfj.c,v 1.32 1996/08/09 01:20:14 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*/
8*eb9086c3SLois Curfman McInnes #include "pinclude/pviewer.h"
981e6777dSBarry Smith 
1050361f65SLois Curfman McInnes typedef struct {  /* default context for matrix-free SNES */
11*eb9086c3SLois Curfman McInnes   SNES        snes;      /* SNES context */
12*eb9086c3SLois Curfman McInnes   Vec         w;         /* work vector */
13*eb9086c3SLois Curfman McInnes   PCNullSpace sp;        /* null space context */
14*eb9086c3SLois Curfman McInnes   double      error_rel; /* square root of relative error in computing function */
15*eb9086c3SLois Curfman McInnes   double      umin;      /* minimum allowable u value */
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 /*
32*eb9086c3SLois Curfman McInnes    SNESMatrixFreeView_Private -
3339e2f89bSBarry Smith  */
34*eb9086c3SLois Curfman McInnes int SNESMatrixFreeView_Private(Mat J,Viewer viewer)
35*eb9086c3SLois Curfman McInnes {
36*eb9086c3SLois Curfman McInnes   int           ierr;
37*eb9086c3SLois Curfman McInnes   MFCtx_Private *ctx;
38*eb9086c3SLois Curfman McInnes   MPI_Comm      comm;
39*eb9086c3SLois Curfman McInnes   FILE          *fd;
40*eb9086c3SLois Curfman McInnes   ViewerType    vtype;
41*eb9086c3SLois Curfman McInnes 
42*eb9086c3SLois Curfman McInnes   PetscObjectGetComm((PetscObject)J,&comm);
43*eb9086c3SLois Curfman McInnes   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
44*eb9086c3SLois Curfman McInnes   ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr);
45*eb9086c3SLois Curfman McInnes   ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr);
46*eb9086c3SLois Curfman McInnes   if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) {
47*eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"  SNES matrix-free approximation:\n");
48*eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"    err=%g (relative error in function evaluation)\n",ctx->error_rel);
49*eb9086c3SLois Curfman McInnes      PetscFPrintf(comm,fd,"    umin=%g (minimum iterate parameter)\n",ctx->umin);
50*eb9086c3SLois Curfman McInnes   }
51*eb9086c3SLois Curfman McInnes   return 0;
52*eb9086c3SLois Curfman McInnes }
53*eb9086c3SLois Curfman McInnes 
54*eb9086c3SLois Curfman McInnes /*
55*eb9086c3SLois Curfman McInnes   SNESMatrixFreeMult_Private - Default matrix-free form for Jacobian-vector
56*eb9086c3SLois Curfman McInnes   product, y = F'(u)*a:
57*eb9086c3SLois Curfman McInnes        y = ( F(u + ha) - F(u) ) /h,
58*eb9086c3SLois Curfman McInnes  where F = nonlinear function, as set by SNESSetFunction()
59*eb9086c3SLois Curfman McInnes        u = current iterate
60*eb9086c3SLois Curfman McInnes        h = difference interval
61*eb9086c3SLois Curfman McInnes */
62*eb9086c3SLois Curfman McInnes int SNESMatrixFreeMult_Private(Mat mat,Vec a,Vec y)
6339e2f89bSBarry Smith {
64fae171e0SBarry Smith   MFCtx_Private *ctx;
65fae171e0SBarry Smith   SNES          snes;
66*eb9086c3SLois 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;
74*eb9086c3SLois 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. */
80*eb9086c3SLois 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 
93*eb9086c3SLois Curfman McInnes   /* Determine a "good" step size, h */
94*eb9086c3SLois Curfman McInnes   ierr = VecDot(U,a,&dot); CHKERRQ(ierr);
95*eb9086c3SLois Curfman McInnes   ierr = VecNorm(a,NORM_1,&sum); CHKERRQ(ierr);
96*eb9086c3SLois Curfman McInnes   ierr = VecNorm(a,NORM_2,&norm); CHKERRQ(ierr);
97*eb9086c3SLois Curfman McInnes 
98*eb9086c3SLois 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)
101*eb9086c3SLois Curfman McInnes   else if (abs(dot) < umin*sum && real(dot) >= 0.0) dot = umin*sum;
102*eb9086c3SLois Curfman McInnes   else if (abs(dot) < 0.0 && real(dot) > -umin*sum) dot = -umin*sum;
10319a167f6SBarry Smith #else
104*eb9086c3SLois Curfman McInnes   else if (dot < umin*sum && dot >= 0.0) dot = umin*sum;
105*eb9086c3SLois Curfman McInnes   else if (dot < 0.0 && dot > -umin*sum) dot = -umin*sum;
10619a167f6SBarry Smith #endif
107*eb9086c3SLois Curfman McInnes   h = ctx->error_rel*dot/(norm*norm);
10839e2f89bSBarry Smith 
109*eb9086c3SLois Curfman McInnes   /* Evaluate function at F(u + ha) */
110*eb9086c3SLois 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 
117*eb9086c3SLois 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:
127*eb9086c3SLois Curfman McInnes .  snes - the SNES context
1285392566eSBarry Smith .  x - vector where SNES solution is to be stored.
1295392566eSBarry Smith 
130*eb9086c3SLois 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;
149*eb9086c3SLois 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;
155*eb9086c3SLois Curfman McInnes   mfctx->error_rel = 1.e-8; /* assumes double precision */
156*eb9086c3SLois Curfman McInnes   mfctx->umin      = 1.e-8;
157*eb9086c3SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg); CHKERRQ(ierr);
158*eb9086c3SLois Curfman McInnes   ierr = OptionsGetDouble(snes->prefix,"-snes_mf_umin",&mfctx->umin,&flg); CHKERRQ(ierr);
1595392566eSBarry Smith   ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr);
160195ee392SLois Curfman McInnes   ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr);
161195ee392SLois Curfman McInnes   ierr = VecGetSize(x,&n); CHKERRQ(ierr);
1627ddc982cSLois Curfman McInnes   ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr);
1637ddc982cSLois Curfman McInnes   ierr = MatCreateShell(comm,nloc,n,n,n,(void*)mfctx,J); CHKERRQ(ierr);
164*eb9086c3SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MAT_MULT,(void*)SNESMatrixFreeMult_Private); CHKERRQ(ierr);
165*eb9086c3SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MAT_DESTROY,(void *)SNESMatrixFreeDestroy_Private); CHKERRQ(ierr);
166*eb9086c3SLois Curfman McInnes   ierr = MatShellSetOperation(*J,MAT_VIEW,(void *)SNESMatrixFreeView_Private); CHKERRQ(ierr);
167b9fa9cd0SBarry Smith   PLogObjectParent(*J,mfctx->w);
168d370d78aSBarry Smith   PLogObjectParent(snes,*J);
16981e6777dSBarry Smith   return 0;
17081e6777dSBarry Smith }
17181e6777dSBarry Smith 
172b4fd4287SBarry Smith /*@
173*eb9086c3SLois Curfman McInnes    SNESSetMatrixFreeParameters - Sets the parameters for the approximation of
174*eb9086c3SLois Curfman McInnes    matrix-vector products using finite differences.
175*eb9086c3SLois Curfman McInnes 
176*eb9086c3SLois Curfman McInnes    Input Parameters:
177*eb9086c3SLois Curfman McInnes .  snes - the SNES context
178*eb9086c3SLois Curfman McInnes .  error_rel - relative error
179*eb9086c3SLois Curfman McInnes .  umin - minimum allowable u-value
180*eb9086c3SLois Curfman McInnes 
181*eb9086c3SLois Curfman McInnes .keywords: SNES, matrix-free, parameters
182*eb9086c3SLois Curfman McInnes @*/
183*eb9086c3SLois Curfman McInnes int SNESSetMatrixFreeParameters(SNES snes,double error,double umin)
184*eb9086c3SLois Curfman McInnes {
185*eb9086c3SLois Curfman McInnes   MFCtx_Private *ctx;
186*eb9086c3SLois Curfman McInnes   int           ierr;
187*eb9086c3SLois Curfman McInnes   Mat           mat;
188*eb9086c3SLois Curfman McInnes 
189*eb9086c3SLois Curfman McInnes   ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr);
190*eb9086c3SLois Curfman McInnes   ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr);
191*eb9086c3SLois Curfman McInnes   if (ctx) {
192*eb9086c3SLois Curfman McInnes     if (error != PETSC_DEFAULT) ctx->error_rel = error;
193*eb9086c3SLois Curfman McInnes     if (umin != PETSC_DEFAULT)  ctx->umin = umin;
194*eb9086c3SLois Curfman McInnes   }
195*eb9086c3SLois Curfman McInnes   return 0;
196*eb9086c3SLois Curfman McInnes }
197*eb9086c3SLois Curfman McInnes 
198*eb9086c3SLois Curfman McInnes /*@
19921a45821SLois Curfman McInnes    SNESDefaultMatrixFreeMatAddNullSpace - Provides a null space that
200b4fd4287SBarry Smith    an operator is suppose to have.  Since roundoff will create a
201b4fd4287SBarry Smith    small component in the null space, if you know the null space
202b4fd4287SBarry Smith    you may have it automatically removed.
203b4fd4287SBarry Smith 
204b4fd4287SBarry Smith    Input Parameters:
20521a45821SLois Curfman McInnes .  J - the matrix-free matrix context
20621a45821SLois Curfman McInnes .  has_cnst - PETSC_TRUE or PETSC_FALSE, indicating if null space has constants
207b4fd4287SBarry Smith .  n - number of vectors (excluding constant vector) in null space
20821a45821SLois Curfman McInnes .  vecs - the vectors that span the null space (excluding the constant vector);
209b4fd4287SBarry Smith .         these vectors must be orthonormal
210b4fd4287SBarry Smith 
211b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space
212b4fd4287SBarry Smith @*/
213b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs)
214b4fd4287SBarry Smith {
215b4fd4287SBarry Smith   int           ierr;
216b4fd4287SBarry Smith   MFCtx_Private *ctx;
217b4fd4287SBarry Smith   MPI_Comm      comm;
218b4fd4287SBarry Smith 
219b4fd4287SBarry Smith   PetscObjectGetComm((PetscObject)J,&comm);
220b4fd4287SBarry Smith 
221b4fd4287SBarry Smith   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
222b4fd4287SBarry Smith   /* no context indicates that it is not the "matrix free" matrix type */
223b4fd4287SBarry Smith   if (!ctx) return 0;
224b4fd4287SBarry Smith   ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr);
225b4fd4287SBarry Smith   return 0;
226b4fd4287SBarry Smith }
227b4fd4287SBarry Smith 
2285334005bSBarry Smith 
2295334005bSBarry Smith 
2305334005bSBarry Smith 
231