xref: /petsc/src/snes/mf/snesmfj.c (revision 70f55243aafb320636e2a54ff30cab5d1e8d3d7b)
181e6777dSBarry Smith 
281e6777dSBarry Smith #ifndef lint
3*70f55243SBarry Smith static char vcid[] = "$Id: snesmfj.c,v 1.30 1996/04/09 02:24:04 curfman Exp bsmith $";
481e6777dSBarry Smith #endif
581e6777dSBarry Smith 
6b1f0a012SBarry Smith #include "draw.h"       /*I  "draw.h"   I*/
7*70f55243SBarry Smith #include "src/snes/snesimpl.h"   /*I  "snes.h"   I*/
881e6777dSBarry Smith 
950361f65SLois Curfman McInnes typedef struct {  /* default context for matrix-free SNES */
1039e2f89bSBarry Smith   SNES        snes;
1139e2f89bSBarry Smith   Vec         w;
12b4fd4287SBarry Smith   PCNullSpace sp;
1339e2f89bSBarry Smith } MFCtx_Private;
1439e2f89bSBarry Smith 
15fae171e0SBarry Smith int SNESMatrixFreeDestroy_Private(PetscObject obj)
16b9fa9cd0SBarry Smith {
17b9fa9cd0SBarry Smith   int           ierr;
18fae171e0SBarry Smith   Mat           mat = (Mat) obj;
19fae171e0SBarry Smith   MFCtx_Private *ctx;
20fae171e0SBarry Smith 
21fae171e0SBarry Smith   ierr = MatShellGetContext(mat,(void **)&ctx);
22b9fa9cd0SBarry Smith   ierr = VecDestroy(ctx->w); CHKERRQ(ierr);
23b4fd4287SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp); CHKERRQ(ierr);}
24fae171e0SBarry Smith   PetscFree(ctx);
25b9fa9cd0SBarry Smith   return 0;
26b9fa9cd0SBarry Smith }
2750361f65SLois Curfman McInnes 
2839e2f89bSBarry Smith /*
2983e56afdSLois Curfman McInnes   SNESMatrixFreeMult_Private - Default matrix-free form of A*u.
3039e2f89bSBarry Smith */
31fae171e0SBarry Smith int SNESMatrixFreeMult_Private(Mat mat,Vec dx,Vec y)
3239e2f89bSBarry Smith {
33fae171e0SBarry Smith   MFCtx_Private *ctx;
34fae171e0SBarry Smith   SNES          snes;
355334005bSBarry Smith   double        norm, sum, epsilon = 1.e-8; /* assumes double precision */
365334005bSBarry Smith   Scalar        h, dot, mone = -1.0;
37fae171e0SBarry Smith   Vec           w,U,F;
3883e56afdSLois Curfman McInnes   int           ierr, (*eval_fct)(SNES,Vec,Vec);
3939e2f89bSBarry Smith 
40fae171e0SBarry Smith   MatShellGetContext(mat,(void **)&ctx);
41fae171e0SBarry Smith   snes = ctx->snes;
42fae171e0SBarry Smith   w = ctx->w;
43fae171e0SBarry Smith 
4457c37382SLois Curfman McInnes   /* We log matrix-free matrix-vector products separately, so that we can
4557c37382SLois Curfman McInnes      separate the performance monitoring from the cases that use conventional
4657c37382SLois Curfman McInnes      storage.  We may eventually modify event logging to associate events
4757c37382SLois Curfman McInnes      with particular objects, hence alleviating the more general problem. */
4857c37382SLois Curfman McInnes   PLogEventBegin(MAT_MatrixFreeMult,dx,y,0,0);
4957c37382SLois Curfman McInnes 
5078b31e54SBarry Smith   ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr);
5183e56afdSLois Curfman McInnes   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
5283e56afdSLois Curfman McInnes     eval_fct = SNESComputeFunction;
5378b31e54SBarry Smith     ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr);
5483e56afdSLois Curfman McInnes   }
5583e56afdSLois Curfman McInnes   else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
5683e56afdSLois Curfman McInnes     eval_fct = SNESComputeGradient;
5783e56afdSLois Curfman McInnes     ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr);
5883e56afdSLois Curfman McInnes   }
5983e56afdSLois Curfman McInnes   else SETERRQ(1,"SNESMatrixFreeMult_Private: Invalid method class");
6050361f65SLois Curfman McInnes 
6150361f65SLois Curfman McInnes   /* Determine a "good" step size */
6250361f65SLois Curfman McInnes   ierr = VecDot(U,dx,&dot); CHKERRQ(ierr);
63cddf8d76SBarry Smith   ierr = VecNorm(dx,NORM_1,&sum); CHKERRQ(ierr);
64cddf8d76SBarry Smith   ierr = VecNorm(dx,NORM_2,&norm); CHKERRQ(ierr);
65edd2f0e1SBarry Smith   if (sum == 0.0) {dot = 1.0; norm = 1.0;}
6619a167f6SBarry Smith #if defined(PETSC_COMPLEX)
6719a167f6SBarry Smith   else if (abs(dot) < 1.e-16*sum && real(dot) >= 0.0) dot = 1.e-16*sum;
6819a167f6SBarry Smith   else if (abs(dot) < 0.0 && real(dot) > 1.e-16*sum) dot = -1.e-16*sum;
6919a167f6SBarry Smith #else
70edd2f0e1SBarry Smith   else if (dot < 1.e-16*sum && dot >= 0.0) dot = 1.e-16*sum;
7139e2f89bSBarry Smith   else if (dot < 0.0 && dot > 1.e-16*sum) dot = -1.e-16*sum;
7219a167f6SBarry Smith #endif
7339e2f89bSBarry Smith   h = epsilon*dot/(norm*norm);
7439e2f89bSBarry Smith 
7550361f65SLois Curfman McInnes   /* Evaluate function at F(x + dx) */
76195ee392SLois Curfman McInnes   ierr = VecWAXPY(&h,dx,U,w); CHKERRQ(ierr);
7783e56afdSLois Curfman McInnes   ierr = eval_fct(snes,w,y); CHKERRQ(ierr);
78195ee392SLois Curfman McInnes   ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr);
795334005bSBarry Smith   h = 1.0/h;
80195ee392SLois Curfman McInnes   ierr = VecScale(&h,y); CHKERRQ(ierr);
81b4fd4287SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);}
8257c37382SLois Curfman McInnes 
8357c37382SLois Curfman McInnes   PLogEventEnd(MAT_MatrixFreeMult,dx,y,0,0);
8439e2f89bSBarry Smith   return 0;
8539e2f89bSBarry Smith }
8683e56afdSLois Curfman McInnes 
874b828684SBarry Smith /*@C
885392566eSBarry Smith    SNESDefaultMatrixFreeMatCreate - Creates a matrix-free matrix
8950361f65SLois Curfman McInnes    context for use with a SNES solver.  This matrix can be used as
9050361f65SLois Curfman McInnes    the Jacobian argument for the routine SNESSetJacobian().
915392566eSBarry Smith 
925392566eSBarry Smith    Input Parameters:
935392566eSBarry Smith .  x - vector where SNES solution is to be stored.
945392566eSBarry Smith 
955392566eSBarry Smith    Output Parameters:
965392566eSBarry Smith .  J - the matrix-free matrix
975392566eSBarry Smith 
9865afa06eSLois Curfman McInnes    Notes:
9965afa06eSLois Curfman McInnes    The matrix-free matrix context merely contains the function pointers
10065afa06eSLois Curfman McInnes    and work space for performing finite difference approximations of
10165afa06eSLois Curfman McInnes    matrix operations such as matrix-vector products.
10265afa06eSLois Curfman McInnes 
10365afa06eSLois Curfman McInnes    The user should call MatDestroy() when finished with the matrix-free
10465afa06eSLois Curfman McInnes    matrix context.
10565afa06eSLois Curfman McInnes 
10665afa06eSLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix
10765afa06eSLois Curfman McInnes 
10865afa06eSLois Curfman McInnes .seealso: MatDestroy()
1095392566eSBarry Smith @*/
1105392566eSBarry Smith int SNESDefaultMatrixFreeMatCreate(SNES snes,Vec x, Mat *J)
1115392566eSBarry Smith {
1125392566eSBarry Smith   MPI_Comm      comm;
1135392566eSBarry Smith   MFCtx_Private *mfctx;
1147ddc982cSLois Curfman McInnes   int           n, nloc, ierr;
1155392566eSBarry Smith 
1160452661fSBarry Smith   mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx);
117464493b3SBarry Smith   PLogObjectMemory(snes,sizeof(MFCtx_Private));
118b4fd4287SBarry Smith   mfctx->sp   = 0;
1195392566eSBarry Smith   mfctx->snes = snes;
1205392566eSBarry Smith   ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr);
121195ee392SLois Curfman McInnes   ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr);
122195ee392SLois Curfman McInnes   ierr = VecGetSize(x,&n); CHKERRQ(ierr);
1237ddc982cSLois Curfman McInnes   ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr);
1247ddc982cSLois Curfman McInnes   ierr = MatCreateShell(comm,nloc,n,n,n,(void*)mfctx,J); CHKERRQ(ierr);
1253a3eedf2SBarry Smith   ierr = MatShellSetOperation(*J,MAT_MULT,(void*)SNESMatrixFreeMult_Private);
1263a3eedf2SBarry Smith          CHKERRQ(ierr);
1273a3eedf2SBarry Smith   ierr = MatShellSetOperation(*J,MAT_DESTROY,(void *)SNESMatrixFreeDestroy_Private);
1283a3eedf2SBarry Smith          CHKERRQ(ierr);
129b9fa9cd0SBarry Smith   PLogObjectParent(*J,mfctx->w);
130d370d78aSBarry Smith   PLogObjectParent(snes,*J);
13181e6777dSBarry Smith   return 0;
13281e6777dSBarry Smith }
13381e6777dSBarry Smith 
134b4fd4287SBarry Smith /*@
135b4fd4287SBarry Smith     SNESDefaultMatrixFreeMatAddNullSpace - Provide a null space that
136b4fd4287SBarry Smith         an operator is suppose to have. Since round off will create a
137b4fd4287SBarry Smith         small component in the null space, if you know the null space
138b4fd4287SBarry Smith         you may have it automatically removed.
139b4fd4287SBarry Smith 
140b4fd4287SBarry Smith   Input Parameters:
141b4fd4287SBarry Smith .  J - the matrix free matrix
142b4fd4287SBarry Smith .  has_cnst - PETSC_TRUE or PETSC_FALSE indicating if null space has constants
143b4fd4287SBarry Smith .  n - number of vectors (excluding constant vector) in null space
144b4fd4287SBarry Smith .  vecs - the vectors that span the null space (excluding the constant vector)
145b4fd4287SBarry Smith .         these vectors must be orthonormal
146b4fd4287SBarry Smith 
147b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space
148b4fd4287SBarry Smith @*/
149b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs)
150b4fd4287SBarry Smith {
151b4fd4287SBarry Smith   int           ierr;
152b4fd4287SBarry Smith   MFCtx_Private *ctx;
153b4fd4287SBarry Smith   MPI_Comm      comm;
154b4fd4287SBarry Smith 
155b4fd4287SBarry Smith   PetscObjectGetComm((PetscObject)J,&comm);
156b4fd4287SBarry Smith 
157b4fd4287SBarry Smith   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
158b4fd4287SBarry Smith   /* no context indicates that it is not the "matrix free" matrix type */
159b4fd4287SBarry Smith   if (!ctx) return 0;
160b4fd4287SBarry Smith   ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr);
161b4fd4287SBarry Smith   return 0;
162b4fd4287SBarry Smith }
163b4fd4287SBarry Smith 
1645334005bSBarry Smith 
1655334005bSBarry Smith 
1665334005bSBarry Smith 
167