xref: /petsc/src/snes/mf/snesmfj.c (revision b4fd42875b350b60e141cbdf895ae7195e067e9f)
181e6777dSBarry Smith 
281e6777dSBarry Smith #ifndef lint
3*b4fd4287SBarry Smith static char vcid[] = "$Id: snesmfj.c,v 1.22 1995/11/01 23:20:55 bsmith Exp bsmith $";
481e6777dSBarry Smith #endif
581e6777dSBarry Smith 
6b1f0a012SBarry Smith #include "draw.h"   /*I  "draw.h"   I*/
7b1f0a012SBarry Smith #include "snes.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;
12*b4fd4287SBarry 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);
20*b4fd4287SBarry 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 /*
2639e2f89bSBarry Smith   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;
3239e2f89bSBarry Smith   double        norm,epsilon = 1.e-8; /* assumes double precision */
3319a167f6SBarry Smith   Scalar        h,dot;
3419a167f6SBarry Smith   double        sum;
3539e2f89bSBarry Smith   Scalar        mone = -1.0;
3639e2f89bSBarry Smith   Vec           w = ctx->w,U,F;
3739e2f89bSBarry Smith   int           ierr;
3839e2f89bSBarry Smith 
3978b31e54SBarry Smith   ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr);
4078b31e54SBarry Smith   ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr);
4150361f65SLois Curfman McInnes 
4250361f65SLois Curfman McInnes   /* Determine a "good" step size */
4350361f65SLois Curfman McInnes   ierr = VecDot(U,dx,&dot); CHKERRQ(ierr);
44cddf8d76SBarry Smith   ierr = VecNorm(dx,NORM_1,&sum); CHKERRQ(ierr);
45cddf8d76SBarry Smith   ierr = VecNorm(dx,NORM_2,&norm); CHKERRQ(ierr);
46edd2f0e1SBarry Smith   if (sum == 0.0) {dot = 1.0; norm = 1.0;}
4719a167f6SBarry Smith #if defined(PETSC_COMPLEX)
4819a167f6SBarry Smith   else if (abs(dot) < 1.e-16*sum && real(dot) >= 0.0) dot = 1.e-16*sum;
4919a167f6SBarry Smith   else if (abs(dot) < 0.0 && real(dot) > 1.e-16*sum) dot = -1.e-16*sum;
5019a167f6SBarry Smith #else
51edd2f0e1SBarry Smith   else if (dot < 1.e-16*sum && dot >= 0.0) dot = 1.e-16*sum;
5239e2f89bSBarry Smith   else if (dot < 0.0 && dot > 1.e-16*sum) dot = -1.e-16*sum;
5319a167f6SBarry Smith #endif
5439e2f89bSBarry Smith   h = epsilon*dot/(norm*norm);
5539e2f89bSBarry Smith 
5650361f65SLois Curfman McInnes   /* Evaluate function at F(x + dx) */
57195ee392SLois Curfman McInnes   ierr = VecWAXPY(&h,dx,U,w); CHKERRQ(ierr);
5878b31e54SBarry Smith   ierr = SNESComputeFunction(snes,w,y); CHKERRQ(ierr);
59195ee392SLois Curfman McInnes   ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr);
6039e2f89bSBarry Smith   h = -1.0/h;
61195ee392SLois Curfman McInnes   ierr = VecScale(&h,y); CHKERRQ(ierr);
62*b4fd4287SBarry Smith   if (ctx->sp) { ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);}
6339e2f89bSBarry Smith   return 0;
6439e2f89bSBarry Smith }
654b828684SBarry Smith /*@C
665392566eSBarry Smith    SNESDefaultMatrixFreeMatCreate - Creates a matrix-free matrix
6750361f65SLois Curfman McInnes    context for use with a SNES solver.  This matrix can be used as
6850361f65SLois Curfman McInnes    the Jacobian argument for the routine SNESSetJacobian().
695392566eSBarry Smith 
705392566eSBarry Smith    Input Parameters:
715392566eSBarry Smith .  x - vector where SNES solution is to be stored.
725392566eSBarry Smith 
735392566eSBarry Smith    Output Parameters:
745392566eSBarry Smith .  J - the matrix-free matrix
755392566eSBarry Smith 
7665afa06eSLois Curfman McInnes    Notes:
7765afa06eSLois Curfman McInnes    The matrix-free matrix context merely contains the function pointers
7865afa06eSLois Curfman McInnes    and work space for performing finite difference approximations of
7965afa06eSLois Curfman McInnes    matrix operations such as matrix-vector products.
8065afa06eSLois Curfman McInnes 
8165afa06eSLois Curfman McInnes    The user should call MatDestroy() when finished with the matrix-free
8265afa06eSLois Curfman McInnes    matrix context.
8365afa06eSLois Curfman McInnes 
8465afa06eSLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix
8565afa06eSLois Curfman McInnes 
8665afa06eSLois Curfman McInnes .seealso: MatDestroy()
875392566eSBarry Smith @*/
885392566eSBarry Smith int SNESDefaultMatrixFreeMatCreate(SNES snes,Vec x, Mat *J)
895392566eSBarry Smith {
905392566eSBarry Smith   MPI_Comm      comm;
915392566eSBarry Smith   MFCtx_Private *mfctx;
925392566eSBarry Smith   int           n,ierr;
935392566eSBarry Smith 
940452661fSBarry Smith   mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx);
95464493b3SBarry Smith   PLogObjectMemory(snes,sizeof(MFCtx_Private));
96*b4fd4287SBarry Smith   mfctx->sp   = 0;
975392566eSBarry Smith   mfctx->snes = snes;
985392566eSBarry Smith   ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr);
99195ee392SLois Curfman McInnes   ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr);
100195ee392SLois Curfman McInnes   ierr = VecGetSize(x,&n); CHKERRQ(ierr);
1015392566eSBarry Smith   ierr = MatShellCreate(comm,n,n,(void*)mfctx,J); CHKERRQ(ierr);
102195ee392SLois Curfman McInnes   ierr = MatShellSetMult(*J,SNESMatrixFreeMult_Private); CHKERRQ(ierr);
103195ee392SLois Curfman McInnes   ierr = MatShellSetDestroy(*J,SNESMatrixFreeDestroy_Private); CHKERRQ(ierr);
104b9fa9cd0SBarry Smith   PLogObjectParent(*J,mfctx->w);
105d370d78aSBarry Smith   PLogObjectParent(snes,*J);
10681e6777dSBarry Smith   return 0;
10781e6777dSBarry Smith }
10881e6777dSBarry Smith 
109*b4fd4287SBarry Smith /*@
110*b4fd4287SBarry Smith     SNESDefaultMatrixFreeMatAddNullSpace - Provide a null space that
111*b4fd4287SBarry Smith         an operator is suppose to have. Since round off will create a
112*b4fd4287SBarry Smith         small component in the null space, if you know the null space
113*b4fd4287SBarry Smith         you may have it automatically removed.
114*b4fd4287SBarry Smith 
115*b4fd4287SBarry Smith   Input Parameters:
116*b4fd4287SBarry Smith .  J - the matrix free matrix
117*b4fd4287SBarry Smith .  has_cnst - PETSC_TRUE or PETSC_FALSE indicating if null space has constants
118*b4fd4287SBarry Smith .  n - number of vectors (excluding constant vector) in null space
119*b4fd4287SBarry Smith .  vecs - the vectors that span the null space (excluding the constant vector)
120*b4fd4287SBarry Smith .         these vectors must be orthonormal
121*b4fd4287SBarry Smith 
122*b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space
123*b4fd4287SBarry Smith @*/
124*b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs)
125*b4fd4287SBarry Smith {
126*b4fd4287SBarry Smith   int           ierr;
127*b4fd4287SBarry Smith   MFCtx_Private *ctx;
128*b4fd4287SBarry Smith   MPI_Comm      comm;
129*b4fd4287SBarry Smith 
130*b4fd4287SBarry Smith   PetscObjectGetComm((PetscObject)J,&comm);
131*b4fd4287SBarry Smith 
132*b4fd4287SBarry Smith   ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr);
133*b4fd4287SBarry Smith   /* no context indicates that it is not the "matrix free" matrix type */
134*b4fd4287SBarry Smith   if (!ctx) return 0;
135*b4fd4287SBarry Smith   ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr);
136*b4fd4287SBarry Smith   return 0;
137*b4fd4287SBarry Smith }
138*b4fd4287SBarry Smith 
139