181e6777dSBarry Smith 281e6777dSBarry Smith #ifndef lint 3*fae171e0SBarry Smith static char vcid[] = "$Id: snesmfj.c,v 1.27 1996/03/20 06:05:43 curfman 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 15*fae171e0SBarry Smith int SNESMatrixFreeDestroy_Private(PetscObject obj) 16b9fa9cd0SBarry Smith { 17b9fa9cd0SBarry Smith int ierr; 18*fae171e0SBarry Smith Mat mat = (Mat) obj; 19*fae171e0SBarry Smith MFCtx_Private *ctx; 20*fae171e0SBarry Smith 21*fae171e0SBarry 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);} 24*fae171e0SBarry 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 */ 31*fae171e0SBarry Smith int SNESMatrixFreeMult_Private(Mat mat,Vec dx,Vec y) 3239e2f89bSBarry Smith { 33*fae171e0SBarry Smith MFCtx_Private *ctx; 34*fae171e0SBarry Smith SNES snes; 355334005bSBarry Smith double norm, sum, epsilon = 1.e-8; /* assumes double precision */ 365334005bSBarry Smith Scalar h, dot, mone = -1.0; 37*fae171e0SBarry Smith Vec w,U,F; 3883e56afdSLois Curfman McInnes int ierr, (*eval_fct)(SNES,Vec,Vec); 3939e2f89bSBarry Smith 40*fae171e0SBarry Smith MatShellGetContext(mat,(void **)&ctx); 41*fae171e0SBarry Smith snes = ctx->snes; 42*fae171e0SBarry Smith w = ctx->w; 43*fae171e0SBarry 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*fae171e0SBarry Smith ierr = MatShellSetOperation(*J,MAT_MULT,SNESMatrixFreeMult_Private); CHKERRQ(ierr); 125*fae171e0SBarry Smith ierr = MatShellSetOperation(*J,MAT_DESTROY,SNESMatrixFreeDestroy_Private);CHKERRQ(ierr); 126b9fa9cd0SBarry Smith PLogObjectParent(*J,mfctx->w); 127d370d78aSBarry Smith PLogObjectParent(snes,*J); 12881e6777dSBarry Smith return 0; 12981e6777dSBarry Smith } 13081e6777dSBarry Smith 131b4fd4287SBarry Smith /*@ 132b4fd4287SBarry Smith SNESDefaultMatrixFreeMatAddNullSpace - Provide a null space that 133b4fd4287SBarry Smith an operator is suppose to have. Since round off will create a 134b4fd4287SBarry Smith small component in the null space, if you know the null space 135b4fd4287SBarry Smith you may have it automatically removed. 136b4fd4287SBarry Smith 137b4fd4287SBarry Smith Input Parameters: 138b4fd4287SBarry Smith . J - the matrix free matrix 139b4fd4287SBarry Smith . has_cnst - PETSC_TRUE or PETSC_FALSE indicating if null space has constants 140b4fd4287SBarry Smith . n - number of vectors (excluding constant vector) in null space 141b4fd4287SBarry Smith . vecs - the vectors that span the null space (excluding the constant vector) 142b4fd4287SBarry Smith . these vectors must be orthonormal 143b4fd4287SBarry Smith 144b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space 145b4fd4287SBarry Smith @*/ 146b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs) 147b4fd4287SBarry Smith { 148b4fd4287SBarry Smith int ierr; 149b4fd4287SBarry Smith MFCtx_Private *ctx; 150b4fd4287SBarry Smith MPI_Comm comm; 151b4fd4287SBarry Smith 152b4fd4287SBarry Smith PetscObjectGetComm((PetscObject)J,&comm); 153b4fd4287SBarry Smith 154b4fd4287SBarry Smith ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr); 155b4fd4287SBarry Smith /* no context indicates that it is not the "matrix free" matrix type */ 156b4fd4287SBarry Smith if (!ctx) return 0; 157b4fd4287SBarry Smith ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr); 158b4fd4287SBarry Smith return 0; 159b4fd4287SBarry Smith } 160b4fd4287SBarry Smith 1615334005bSBarry Smith 1625334005bSBarry Smith 1635334005bSBarry Smith 164