181e6777dSBarry Smith 281e6777dSBarry Smith #ifndef lint 3*eb9086c3SLois Curfman McInnes static char vcid[] = "$Id: snesmfj.c,v 1.32 1996/08/09 01:20:14 curfman Exp curfman $"; 481e6777dSBarry Smith #endif 581e6777dSBarry Smith 6b1f0a012SBarry Smith #include "draw.h" /*I "draw.h" I*/ 770f55243SBarry Smith #include "src/snes/snesimpl.h" /*I "snes.h" I*/ 8*eb9086c3SLois Curfman McInnes #include "pinclude/pviewer.h" 981e6777dSBarry Smith 1050361f65SLois Curfman McInnes typedef struct { /* default context for matrix-free SNES */ 11*eb9086c3SLois Curfman McInnes SNES snes; /* SNES context */ 12*eb9086c3SLois Curfman McInnes Vec w; /* work vector */ 13*eb9086c3SLois Curfman McInnes PCNullSpace sp; /* null space context */ 14*eb9086c3SLois Curfman McInnes double error_rel; /* square root of relative error in computing function */ 15*eb9086c3SLois Curfman McInnes double umin; /* minimum allowable u value */ 1639e2f89bSBarry Smith } MFCtx_Private; 1739e2f89bSBarry Smith 18fae171e0SBarry Smith int SNESMatrixFreeDestroy_Private(PetscObject obj) 19b9fa9cd0SBarry Smith { 20b9fa9cd0SBarry Smith int ierr; 21fae171e0SBarry Smith Mat mat = (Mat) obj; 22fae171e0SBarry Smith MFCtx_Private *ctx; 23fae171e0SBarry Smith 24fae171e0SBarry Smith ierr = MatShellGetContext(mat,(void **)&ctx); 25b9fa9cd0SBarry Smith ierr = VecDestroy(ctx->w); CHKERRQ(ierr); 26b4fd4287SBarry Smith if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp); CHKERRQ(ierr);} 27fae171e0SBarry Smith PetscFree(ctx); 28b9fa9cd0SBarry Smith return 0; 29b9fa9cd0SBarry Smith } 3050361f65SLois Curfman McInnes 3139e2f89bSBarry Smith /* 32*eb9086c3SLois Curfman McInnes SNESMatrixFreeView_Private - 3339e2f89bSBarry Smith */ 34*eb9086c3SLois Curfman McInnes int SNESMatrixFreeView_Private(Mat J,Viewer viewer) 35*eb9086c3SLois Curfman McInnes { 36*eb9086c3SLois Curfman McInnes int ierr; 37*eb9086c3SLois Curfman McInnes MFCtx_Private *ctx; 38*eb9086c3SLois Curfman McInnes MPI_Comm comm; 39*eb9086c3SLois Curfman McInnes FILE *fd; 40*eb9086c3SLois Curfman McInnes ViewerType vtype; 41*eb9086c3SLois Curfman McInnes 42*eb9086c3SLois Curfman McInnes PetscObjectGetComm((PetscObject)J,&comm); 43*eb9086c3SLois Curfman McInnes ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr); 44*eb9086c3SLois Curfman McInnes ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 45*eb9086c3SLois Curfman McInnes ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 46*eb9086c3SLois Curfman McInnes if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 47*eb9086c3SLois Curfman McInnes PetscFPrintf(comm,fd," SNES matrix-free approximation:\n"); 48*eb9086c3SLois Curfman McInnes PetscFPrintf(comm,fd," err=%g (relative error in function evaluation)\n",ctx->error_rel); 49*eb9086c3SLois Curfman McInnes PetscFPrintf(comm,fd," umin=%g (minimum iterate parameter)\n",ctx->umin); 50*eb9086c3SLois Curfman McInnes } 51*eb9086c3SLois Curfman McInnes return 0; 52*eb9086c3SLois Curfman McInnes } 53*eb9086c3SLois Curfman McInnes 54*eb9086c3SLois Curfman McInnes /* 55*eb9086c3SLois Curfman McInnes SNESMatrixFreeMult_Private - Default matrix-free form for Jacobian-vector 56*eb9086c3SLois Curfman McInnes product, y = F'(u)*a: 57*eb9086c3SLois Curfman McInnes y = ( F(u + ha) - F(u) ) /h, 58*eb9086c3SLois Curfman McInnes where F = nonlinear function, as set by SNESSetFunction() 59*eb9086c3SLois Curfman McInnes u = current iterate 60*eb9086c3SLois Curfman McInnes h = difference interval 61*eb9086c3SLois Curfman McInnes */ 62*eb9086c3SLois Curfman McInnes int SNESMatrixFreeMult_Private(Mat mat,Vec a,Vec y) 6339e2f89bSBarry Smith { 64fae171e0SBarry Smith MFCtx_Private *ctx; 65fae171e0SBarry Smith SNES snes; 66*eb9086c3SLois Curfman McInnes double norm, sum, umin; 675334005bSBarry Smith Scalar h, dot, mone = -1.0; 68fae171e0SBarry Smith Vec w,U,F; 6983e56afdSLois Curfman McInnes int ierr, (*eval_fct)(SNES,Vec,Vec); 7039e2f89bSBarry Smith 71fae171e0SBarry Smith MatShellGetContext(mat,(void **)&ctx); 72fae171e0SBarry Smith snes = ctx->snes; 73fae171e0SBarry Smith w = ctx->w; 74*eb9086c3SLois Curfman McInnes umin = ctx->umin; 75fae171e0SBarry Smith 7657c37382SLois Curfman McInnes /* We log matrix-free matrix-vector products separately, so that we can 7757c37382SLois Curfman McInnes separate the performance monitoring from the cases that use conventional 7857c37382SLois Curfman McInnes storage. We may eventually modify event logging to associate events 7957c37382SLois Curfman McInnes with particular objects, hence alleviating the more general problem. */ 80*eb9086c3SLois Curfman McInnes PLogEventBegin(MAT_MatrixFreeMult,a,y,0,0); 8157c37382SLois Curfman McInnes 8278b31e54SBarry Smith ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr); 8383e56afdSLois Curfman McInnes if (snes->method_class == SNES_NONLINEAR_EQUATIONS) { 8483e56afdSLois Curfman McInnes eval_fct = SNESComputeFunction; 8578b31e54SBarry Smith ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr); 8683e56afdSLois Curfman McInnes } 8783e56afdSLois Curfman McInnes else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 8883e56afdSLois Curfman McInnes eval_fct = SNESComputeGradient; 8983e56afdSLois Curfman McInnes ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr); 9083e56afdSLois Curfman McInnes } 9183e56afdSLois Curfman McInnes else SETERRQ(1,"SNESMatrixFreeMult_Private: Invalid method class"); 9250361f65SLois Curfman McInnes 93*eb9086c3SLois Curfman McInnes /* Determine a "good" step size, h */ 94*eb9086c3SLois Curfman McInnes ierr = VecDot(U,a,&dot); CHKERRQ(ierr); 95*eb9086c3SLois Curfman McInnes ierr = VecNorm(a,NORM_1,&sum); CHKERRQ(ierr); 96*eb9086c3SLois Curfman McInnes ierr = VecNorm(a,NORM_2,&norm); CHKERRQ(ierr); 97*eb9086c3SLois Curfman McInnes 98*eb9086c3SLois Curfman McInnes /* Safeguard for step sizes too small */ 99edd2f0e1SBarry Smith if (sum == 0.0) {dot = 1.0; norm = 1.0;} 10019a167f6SBarry Smith #if defined(PETSC_COMPLEX) 101*eb9086c3SLois Curfman McInnes else if (abs(dot) < umin*sum && real(dot) >= 0.0) dot = umin*sum; 102*eb9086c3SLois Curfman McInnes else if (abs(dot) < 0.0 && real(dot) > -umin*sum) dot = -umin*sum; 10319a167f6SBarry Smith #else 104*eb9086c3SLois Curfman McInnes else if (dot < umin*sum && dot >= 0.0) dot = umin*sum; 105*eb9086c3SLois Curfman McInnes else if (dot < 0.0 && dot > -umin*sum) dot = -umin*sum; 10619a167f6SBarry Smith #endif 107*eb9086c3SLois Curfman McInnes h = ctx->error_rel*dot/(norm*norm); 10839e2f89bSBarry Smith 109*eb9086c3SLois Curfman McInnes /* Evaluate function at F(u + ha) */ 110*eb9086c3SLois Curfman McInnes ierr = VecWAXPY(&h,a,U,w); CHKERRQ(ierr); 11183e56afdSLois Curfman McInnes ierr = eval_fct(snes,w,y); CHKERRQ(ierr); 112195ee392SLois Curfman McInnes ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr); 1135334005bSBarry Smith h = 1.0/h; 114195ee392SLois Curfman McInnes ierr = VecScale(&h,y); CHKERRQ(ierr); 115b4fd4287SBarry Smith if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);} 11657c37382SLois Curfman McInnes 117*eb9086c3SLois Curfman McInnes PLogEventEnd(MAT_MatrixFreeMult,a,y,0,0); 11839e2f89bSBarry Smith return 0; 11939e2f89bSBarry Smith } 12083e56afdSLois Curfman McInnes 1214b828684SBarry Smith /*@C 1225392566eSBarry Smith SNESDefaultMatrixFreeMatCreate - Creates a matrix-free matrix 12350361f65SLois Curfman McInnes context for use with a SNES solver. This matrix can be used as 12450361f65SLois Curfman McInnes the Jacobian argument for the routine SNESSetJacobian(). 1255392566eSBarry Smith 1265392566eSBarry Smith Input Parameters: 127*eb9086c3SLois Curfman McInnes . snes - the SNES context 1285392566eSBarry Smith . x - vector where SNES solution is to be stored. 1295392566eSBarry Smith 130*eb9086c3SLois Curfman McInnes Output Parameter: 1315392566eSBarry Smith . J - the matrix-free matrix 1325392566eSBarry Smith 13365afa06eSLois Curfman McInnes Notes: 13465afa06eSLois Curfman McInnes The matrix-free matrix context merely contains the function pointers 13565afa06eSLois Curfman McInnes and work space for performing finite difference approximations of 13665afa06eSLois Curfman McInnes matrix operations such as matrix-vector products. 13765afa06eSLois Curfman McInnes 13865afa06eSLois Curfman McInnes The user should call MatDestroy() when finished with the matrix-free 13965afa06eSLois Curfman McInnes matrix context. 14065afa06eSLois Curfman McInnes 14165afa06eSLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix 14265afa06eSLois Curfman McInnes 14365afa06eSLois Curfman McInnes .seealso: MatDestroy() 1445392566eSBarry Smith @*/ 1455392566eSBarry Smith int SNESDefaultMatrixFreeMatCreate(SNES snes,Vec x, Mat *J) 1465392566eSBarry Smith { 1475392566eSBarry Smith MPI_Comm comm; 1485392566eSBarry Smith MFCtx_Private *mfctx; 149*eb9086c3SLois Curfman McInnes int n, nloc, ierr, flg; 1505392566eSBarry Smith 1510452661fSBarry Smith mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx); 152464493b3SBarry Smith PLogObjectMemory(snes,sizeof(MFCtx_Private)); 153b4fd4287SBarry Smith mfctx->sp = 0; 1545392566eSBarry Smith mfctx->snes = snes; 155*eb9086c3SLois Curfman McInnes mfctx->error_rel = 1.e-8; /* assumes double precision */ 156*eb9086c3SLois Curfman McInnes mfctx->umin = 1.e-8; 157*eb9086c3SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg); CHKERRQ(ierr); 158*eb9086c3SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_mf_umin",&mfctx->umin,&flg); CHKERRQ(ierr); 1595392566eSBarry Smith ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr); 160195ee392SLois Curfman McInnes ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr); 161195ee392SLois Curfman McInnes ierr = VecGetSize(x,&n); CHKERRQ(ierr); 1627ddc982cSLois Curfman McInnes ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr); 1637ddc982cSLois Curfman McInnes ierr = MatCreateShell(comm,nloc,n,n,n,(void*)mfctx,J); CHKERRQ(ierr); 164*eb9086c3SLois Curfman McInnes ierr = MatShellSetOperation(*J,MAT_MULT,(void*)SNESMatrixFreeMult_Private); CHKERRQ(ierr); 165*eb9086c3SLois Curfman McInnes ierr = MatShellSetOperation(*J,MAT_DESTROY,(void *)SNESMatrixFreeDestroy_Private); CHKERRQ(ierr); 166*eb9086c3SLois Curfman McInnes ierr = MatShellSetOperation(*J,MAT_VIEW,(void *)SNESMatrixFreeView_Private); CHKERRQ(ierr); 167b9fa9cd0SBarry Smith PLogObjectParent(*J,mfctx->w); 168d370d78aSBarry Smith PLogObjectParent(snes,*J); 16981e6777dSBarry Smith return 0; 17081e6777dSBarry Smith } 17181e6777dSBarry Smith 172b4fd4287SBarry Smith /*@ 173*eb9086c3SLois Curfman McInnes SNESSetMatrixFreeParameters - Sets the parameters for the approximation of 174*eb9086c3SLois Curfman McInnes matrix-vector products using finite differences. 175*eb9086c3SLois Curfman McInnes 176*eb9086c3SLois Curfman McInnes Input Parameters: 177*eb9086c3SLois Curfman McInnes . snes - the SNES context 178*eb9086c3SLois Curfman McInnes . error_rel - relative error 179*eb9086c3SLois Curfman McInnes . umin - minimum allowable u-value 180*eb9086c3SLois Curfman McInnes 181*eb9086c3SLois Curfman McInnes .keywords: SNES, matrix-free, parameters 182*eb9086c3SLois Curfman McInnes @*/ 183*eb9086c3SLois Curfman McInnes int SNESSetMatrixFreeParameters(SNES snes,double error,double umin) 184*eb9086c3SLois Curfman McInnes { 185*eb9086c3SLois Curfman McInnes MFCtx_Private *ctx; 186*eb9086c3SLois Curfman McInnes int ierr; 187*eb9086c3SLois Curfman McInnes Mat mat; 188*eb9086c3SLois Curfman McInnes 189*eb9086c3SLois Curfman McInnes ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr); 190*eb9086c3SLois Curfman McInnes ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr); 191*eb9086c3SLois Curfman McInnes if (ctx) { 192*eb9086c3SLois Curfman McInnes if (error != PETSC_DEFAULT) ctx->error_rel = error; 193*eb9086c3SLois Curfman McInnes if (umin != PETSC_DEFAULT) ctx->umin = umin; 194*eb9086c3SLois Curfman McInnes } 195*eb9086c3SLois Curfman McInnes return 0; 196*eb9086c3SLois Curfman McInnes } 197*eb9086c3SLois Curfman McInnes 198*eb9086c3SLois Curfman McInnes /*@ 19921a45821SLois Curfman McInnes SNESDefaultMatrixFreeMatAddNullSpace - Provides a null space that 200b4fd4287SBarry Smith an operator is suppose to have. Since roundoff will create a 201b4fd4287SBarry Smith small component in the null space, if you know the null space 202b4fd4287SBarry Smith you may have it automatically removed. 203b4fd4287SBarry Smith 204b4fd4287SBarry Smith Input Parameters: 20521a45821SLois Curfman McInnes . J - the matrix-free matrix context 20621a45821SLois Curfman McInnes . has_cnst - PETSC_TRUE or PETSC_FALSE, indicating if null space has constants 207b4fd4287SBarry Smith . n - number of vectors (excluding constant vector) in null space 20821a45821SLois Curfman McInnes . vecs - the vectors that span the null space (excluding the constant vector); 209b4fd4287SBarry Smith . these vectors must be orthonormal 210b4fd4287SBarry Smith 211b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space 212b4fd4287SBarry Smith @*/ 213b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs) 214b4fd4287SBarry Smith { 215b4fd4287SBarry Smith int ierr; 216b4fd4287SBarry Smith MFCtx_Private *ctx; 217b4fd4287SBarry Smith MPI_Comm comm; 218b4fd4287SBarry Smith 219b4fd4287SBarry Smith PetscObjectGetComm((PetscObject)J,&comm); 220b4fd4287SBarry Smith 221b4fd4287SBarry Smith ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr); 222b4fd4287SBarry Smith /* no context indicates that it is not the "matrix free" matrix type */ 223b4fd4287SBarry Smith if (!ctx) return 0; 224b4fd4287SBarry Smith ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr); 225b4fd4287SBarry Smith return 0; 226b4fd4287SBarry Smith } 227b4fd4287SBarry Smith 2285334005bSBarry Smith 2295334005bSBarry Smith 2305334005bSBarry Smith 231