xref: /petsc/src/snes/mf/snesmfj.c (revision 83e56afd8bd036e5a9d50596b2b34bdb60c9f056)
181e6777dSBarry Smith 
281e6777dSBarry Smith #ifndef lint
3*83e56afdSLois Curfman McInnes static char vcid[] = "$Id: snesmfj.c,v 1.26 1996/02/08 16:54:00 curfman Exp curfman $";
481e6777dSBarry Smith #endif
581e6777dSBarry Smith 
6b1f0a012SBarry Smith #include "draw.h"       /*I  "draw.h"   I*/
7*83e56afdSLois 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 
15b9fa9cd0SBarry Smith int SNESMatrixFreeDestroy_Private(void *ptr)
16b9fa9cd0SBarry Smith {
17b9fa9cd0SBarry Smith   int           ierr;
18b9fa9cd0SBarry Smith   MFCtx_Private *ctx = (MFCtx_Private* ) ptr;
19b9fa9cd0SBarry Smith   ierr = VecDestroy(ctx->w); CHKERRQ(ierr);
20b4fd4287SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp); CHKERRQ(ierr);}
210452661fSBarry Smith   PetscFree(ptr);
22b9fa9cd0SBarry Smith   return 0;
23b9fa9cd0SBarry Smith }
2450361f65SLois Curfman McInnes 
2539e2f89bSBarry Smith /*
26*83e56afdSLois Curfman McInnes   SNESMatrixFreeMult_Private - Default matrix-free form of A*u.
2739e2f89bSBarry Smith */
2839e2f89bSBarry Smith int SNESMatrixFreeMult_Private(void *ptr,Vec dx,Vec y)
2939e2f89bSBarry Smith {
3039e2f89bSBarry Smith   MFCtx_Private *ctx = (MFCtx_Private* ) ptr;
3139e2f89bSBarry Smith   SNES          snes = ctx->snes;
325334005bSBarry Smith   double        norm, sum, epsilon = 1.e-8; /* assumes double precision */
335334005bSBarry Smith   Scalar        h, dot, mone = -1.0;
3439e2f89bSBarry Smith   Vec           w = ctx->w,U,F;
35*83e56afdSLois Curfman McInnes   int           ierr, (*eval_fct)(SNES,Vec,Vec);
3639e2f89bSBarry Smith 
3757c37382SLois Curfman McInnes   /* We log matrix-free matrix-vector products separately, so that we can
3857c37382SLois Curfman McInnes      separate the performance monitoring from the cases that use conventional
3957c37382SLois Curfman McInnes      storage.  We may eventually modify event logging to associate events
4057c37382SLois Curfman McInnes      with particular objects, hence alleviating the more general problem. */
4157c37382SLois Curfman McInnes   PLogEventBegin(MAT_MatrixFreeMult,dx,y,0,0);
4257c37382SLois Curfman McInnes 
4378b31e54SBarry Smith   ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr);
44*83e56afdSLois Curfman McInnes   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
45*83e56afdSLois Curfman McInnes     eval_fct = SNESComputeFunction;
4678b31e54SBarry Smith     ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr);
47*83e56afdSLois Curfman McInnes   }
48*83e56afdSLois Curfman McInnes   else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
49*83e56afdSLois Curfman McInnes     eval_fct = SNESComputeGradient;
50*83e56afdSLois Curfman McInnes     ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr);
51*83e56afdSLois Curfman McInnes   }
52*83e56afdSLois Curfman McInnes   else SETERRQ(1,"SNESMatrixFreeMult_Private: Invalid method class");
5350361f65SLois Curfman McInnes 
5450361f65SLois Curfman McInnes   /* Determine a "good" step size */
5550361f65SLois Curfman McInnes   ierr = VecDot(U,dx,&dot); CHKERRQ(ierr);
56cddf8d76SBarry Smith   ierr = VecNorm(dx,NORM_1,&sum); CHKERRQ(ierr);
57cddf8d76SBarry Smith   ierr = VecNorm(dx,NORM_2,&norm); CHKERRQ(ierr);
58edd2f0e1SBarry Smith   if (sum == 0.0) {dot = 1.0; norm = 1.0;}
5919a167f6SBarry Smith #if defined(PETSC_COMPLEX)
6019a167f6SBarry Smith   else if (abs(dot) < 1.e-16*sum && real(dot) >= 0.0) dot = 1.e-16*sum;
6119a167f6SBarry Smith   else if (abs(dot) < 0.0 && real(dot) > 1.e-16*sum) dot = -1.e-16*sum;
6219a167f6SBarry Smith #else
63edd2f0e1SBarry Smith   else if (dot < 1.e-16*sum && dot >= 0.0) dot = 1.e-16*sum;
6439e2f89bSBarry Smith   else if (dot < 0.0 && dot > 1.e-16*sum) dot = -1.e-16*sum;
6519a167f6SBarry Smith #endif
6639e2f89bSBarry Smith   h = epsilon*dot/(norm*norm);
6739e2f89bSBarry Smith 
6850361f65SLois Curfman McInnes   /* Evaluate function at F(x + dx) */
69195ee392SLois Curfman McInnes   ierr = VecWAXPY(&h,dx,U,w); CHKERRQ(ierr);
70*83e56afdSLois Curfman McInnes   ierr = eval_fct(snes,w,y); CHKERRQ(ierr);
71195ee392SLois Curfman McInnes   ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr);
725334005bSBarry Smith   h = 1.0/h;
73195ee392SLois Curfman McInnes   ierr = VecScale(&h,y); CHKERRQ(ierr);
74b4fd4287SBarry Smith   if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);}
7557c37382SLois Curfman McInnes 
7657c37382SLois Curfman McInnes   PLogEventEnd(MAT_MatrixFreeMult,dx,y,0,0);
7739e2f89bSBarry Smith   return 0;
7839e2f89bSBarry Smith }
79*83e56afdSLois Curfman McInnes 
804b828684SBarry Smith /*@C
815392566eSBarry Smith    SNESDefaultMatrixFreeMatCreate - Creates a matrix-free matrix
8250361f65SLois Curfman McInnes    context for use with a SNES solver.  This matrix can be used as
8350361f65SLois Curfman McInnes    the Jacobian argument for the routine SNESSetJacobian().
845392566eSBarry Smith 
855392566eSBarry Smith    Input Parameters:
865392566eSBarry Smith .  x - vector where SNES solution is to be stored.
875392566eSBarry Smith 
885392566eSBarry Smith    Output Parameters:
895392566eSBarry Smith .  J - the matrix-free matrix
905392566eSBarry Smith 
9165afa06eSLois Curfman McInnes    Notes:
9265afa06eSLois Curfman McInnes    The matrix-free matrix context merely contains the function pointers
9365afa06eSLois Curfman McInnes    and work space for performing finite difference approximations of
9465afa06eSLois Curfman McInnes    matrix operations such as matrix-vector products.
9565afa06eSLois Curfman McInnes 
9665afa06eSLois Curfman McInnes    The user should call MatDestroy() when finished with the matrix-free
9765afa06eSLois Curfman McInnes    matrix context.
9865afa06eSLois Curfman McInnes 
9965afa06eSLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix
10065afa06eSLois Curfman McInnes 
10165afa06eSLois Curfman McInnes .seealso: MatDestroy()
1025392566eSBarry Smith @*/
1035392566eSBarry Smith int SNESDefaultMatrixFreeMatCreate(SNES snes,Vec x, Mat *J)
1045392566eSBarry Smith {
1055392566eSBarry Smith   MPI_Comm      comm;
1065392566eSBarry Smith   MFCtx_Private *mfctx;
1075392566eSBarry Smith   int           n,ierr;
1085392566eSBarry Smith 
1090452661fSBarry Smith   mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx);
110464493b3SBarry Smith   PLogObjectMemory(snes,sizeof(MFCtx_Private));
111b4fd4287SBarry Smith   mfctx->sp   = 0;
1125392566eSBarry Smith   mfctx->snes = snes;
1135392566eSBarry Smith   ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr);
114195ee392SLois Curfman McInnes   ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr);
115195ee392SLois Curfman McInnes   ierr = VecGetSize(x,&n); CHKERRQ(ierr);
116052efed2SBarry Smith   ierr = MatCreateShell(comm,n,n,(void*)mfctx,J); CHKERRQ(ierr);
117195ee392SLois Curfman McInnes   ierr = MatShellSetMult(*J,SNESMatrixFreeMult_Private); CHKERRQ(ierr);
118195ee392SLois Curfman McInnes   ierr = MatShellSetDestroy(*J,SNESMatrixFreeDestroy_Private); CHKERRQ(ierr);
119b9fa9cd0SBarry Smith   PLogObjectParent(*J,mfctx->w);
120d370d78aSBarry Smith   PLogObjectParent(snes,*J);
12181e6777dSBarry Smith   return 0;
12281e6777dSBarry Smith }
12381e6777dSBarry Smith 
124b4fd4287SBarry Smith /*@
125b4fd4287SBarry Smith     SNESDefaultMatrixFreeMatAddNullSpace - Provide a null space that
126b4fd4287SBarry Smith         an operator is suppose to have. Since round off will create a
127b4fd4287SBarry Smith         small component in the null space, if you know the null space
128b4fd4287SBarry Smith         you may have it automatically removed.
129b4fd4287SBarry Smith 
130b4fd4287SBarry Smith   Input Parameters:
131b4fd4287SBarry Smith .  J - the matrix free matrix
132b4fd4287SBarry Smith .  has_cnst - PETSC_TRUE or PETSC_FALSE indicating if null space has constants
133b4fd4287SBarry Smith .  n - number of vectors (excluding constant vector) in null space
134b4fd4287SBarry Smith .  vecs - the vectors that span the null space (excluding the constant vector)
135b4fd4287SBarry Smith .         these vectors must be orthonormal
136b4fd4287SBarry Smith 
137b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space
138b4fd4287SBarry Smith @*/
139b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs)
140b4fd4287SBarry Smith {
141b4fd4287SBarry Smith   int           ierr;
142b4fd4287SBarry Smith   MFCtx_Private *ctx;
143b4fd4287SBarry Smith   MPI_Comm      comm;
144b4fd4287SBarry Smith 
145b4fd4287SBarry Smith   PetscObjectGetComm((PetscObject)J,&comm);
146b4fd4287SBarry Smith 
147b4fd4287SBarry Smith   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
148b4fd4287SBarry Smith   /* no context indicates that it is not the "matrix free" matrix type */
149b4fd4287SBarry Smith   if (!ctx) return 0;
150b4fd4287SBarry Smith   ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr);
151b4fd4287SBarry Smith   return 0;
152b4fd4287SBarry Smith }
153b4fd4287SBarry Smith 
1545334005bSBarry Smith 
1555334005bSBarry Smith 
1565334005bSBarry Smith 
157