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