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