xref: /petsc/src/snes/mf/snesmfj.c (revision 3a3eedf2169b507b1efbdb3dd065481a2d2f2a88)
181e6777dSBarry Smith 
281e6777dSBarry Smith #ifndef lint
3*3a3eedf2SBarry Smith static char vcid[] = "$Id: snesmfj.c,v 1.28 1996/03/26 04:47:51 bsmith Exp bsmith $";
481e6777dSBarry Smith #endif
581e6777dSBarry Smith 
6b1f0a012SBarry Smith #include "draw.h"       /*I  "draw.h"   I*/
783e56afdSLois Curfman McInnes #include "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;
1145392566eSBarry Smith   int           n,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);
123052efed2SBarry Smith   ierr = MatCreateShell(comm,n,n,(void*)mfctx,J); CHKERRQ(ierr);
124*3a3eedf2SBarry Smith   ierr = MatShellSetOperation(*J,MAT_MULT,(void*)SNESMatrixFreeMult_Private);
125*3a3eedf2SBarry Smith          CHKERRQ(ierr);
126*3a3eedf2SBarry Smith   ierr = MatShellSetOperation(*J,MAT_DESTROY,(void *)SNESMatrixFreeDestroy_Private);
127*3a3eedf2SBarry Smith          CHKERRQ(ierr);
128b9fa9cd0SBarry Smith   PLogObjectParent(*J,mfctx->w);
129d370d78aSBarry Smith   PLogObjectParent(snes,*J);
13081e6777dSBarry Smith   return 0;
13181e6777dSBarry Smith }
13281e6777dSBarry Smith 
133b4fd4287SBarry Smith /*@
134b4fd4287SBarry Smith     SNESDefaultMatrixFreeMatAddNullSpace - Provide a null space that
135b4fd4287SBarry Smith         an operator is suppose to have. Since round off will create a
136b4fd4287SBarry Smith         small component in the null space, if you know the null space
137b4fd4287SBarry Smith         you may have it automatically removed.
138b4fd4287SBarry Smith 
139b4fd4287SBarry Smith   Input Parameters:
140b4fd4287SBarry Smith .  J - the matrix free matrix
141b4fd4287SBarry Smith .  has_cnst - PETSC_TRUE or PETSC_FALSE indicating if null space has constants
142b4fd4287SBarry Smith .  n - number of vectors (excluding constant vector) in null space
143b4fd4287SBarry Smith .  vecs - the vectors that span the null space (excluding the constant vector)
144b4fd4287SBarry Smith .         these vectors must be orthonormal
145b4fd4287SBarry Smith 
146b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space
147b4fd4287SBarry Smith @*/
148b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs)
149b4fd4287SBarry Smith {
150b4fd4287SBarry Smith   int           ierr;
151b4fd4287SBarry Smith   MFCtx_Private *ctx;
152b4fd4287SBarry Smith   MPI_Comm      comm;
153b4fd4287SBarry Smith 
154b4fd4287SBarry Smith   PetscObjectGetComm((PetscObject)J,&comm);
155b4fd4287SBarry Smith 
156b4fd4287SBarry Smith   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
157b4fd4287SBarry Smith   /* no context indicates that it is not the "matrix free" matrix type */
158b4fd4287SBarry Smith   if (!ctx) return 0;
159b4fd4287SBarry Smith   ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr);
160b4fd4287SBarry Smith   return 0;
161b4fd4287SBarry Smith }
162b4fd4287SBarry Smith 
1635334005bSBarry Smith 
1645334005bSBarry Smith 
1655334005bSBarry Smith 
166