181e6777dSBarry Smith 281e6777dSBarry Smith #ifndef lint 3*5eea60f9SBarry Smith static char vcid[] = "$Id: snesmfj.c,v 1.45 1997/01/28 03:01:04 curfman Exp bsmith $"; 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*/ 8eb9086c3SLois Curfman McInnes #include "pinclude/pviewer.h" 981e6777dSBarry Smith 1050361f65SLois Curfman McInnes typedef struct { /* default context for matrix-free SNES */ 11eb9086c3SLois Curfman McInnes SNES snes; /* SNES context */ 12eb9086c3SLois Curfman McInnes Vec w; /* work vector */ 13eb9086c3SLois Curfman McInnes PCNullSpace sp; /* null space context */ 14eb9086c3SLois Curfman McInnes double error_rel; /* square root of relative error in computing function */ 15639f9d9dSBarry Smith double umin; /* minimum allowable u'a value relative to |u|_1 */ 1639e2f89bSBarry Smith } MFCtx_Private; 1739e2f89bSBarry Smith 185615d1e5SSatish Balay #undef __FUNC__ 19*5eea60f9SBarry Smith #define __FUNC__ "SNESMatrixFreeDestroy_Private" /* ADIC Ignore */ 20fae171e0SBarry Smith int SNESMatrixFreeDestroy_Private(PetscObject obj) 21b9fa9cd0SBarry Smith { 22b9fa9cd0SBarry Smith int ierr; 23fae171e0SBarry Smith Mat mat = (Mat) obj; 24fae171e0SBarry Smith MFCtx_Private *ctx; 25fae171e0SBarry Smith 26fae171e0SBarry Smith ierr = MatShellGetContext(mat,(void **)&ctx); 27b9fa9cd0SBarry Smith ierr = VecDestroy(ctx->w); CHKERRQ(ierr); 28b4fd4287SBarry Smith if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp); CHKERRQ(ierr);} 29fae171e0SBarry Smith PetscFree(ctx); 30b9fa9cd0SBarry Smith return 0; 31b9fa9cd0SBarry Smith } 3250361f65SLois Curfman McInnes 335615d1e5SSatish Balay #undef __FUNC__ 34*5eea60f9SBarry Smith #define __FUNC__ "SNESMatrixFreeView_Private" /* ADIC Ignore */ 3539e2f89bSBarry Smith /* 361d1bbde2SLois Curfman McInnes SNESMatrixFreeView_Private - Views matrix-free parameters. 3739e2f89bSBarry Smith */ 38eb9086c3SLois Curfman McInnes int SNESMatrixFreeView_Private(Mat J,Viewer viewer) 39eb9086c3SLois Curfman McInnes { 40eb9086c3SLois Curfman McInnes int ierr; 41eb9086c3SLois Curfman McInnes MFCtx_Private *ctx; 42eb9086c3SLois Curfman McInnes MPI_Comm comm; 43eb9086c3SLois Curfman McInnes FILE *fd; 44eb9086c3SLois Curfman McInnes ViewerType vtype; 45eb9086c3SLois Curfman McInnes 46eb9086c3SLois Curfman McInnes PetscObjectGetComm((PetscObject)J,&comm); 47eb9086c3SLois Curfman McInnes ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr); 48eb9086c3SLois Curfman McInnes ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 49eb9086c3SLois Curfman McInnes ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 50eb9086c3SLois Curfman McInnes if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 51eb9086c3SLois Curfman McInnes PetscFPrintf(comm,fd," SNES matrix-free approximation:\n"); 52eb9086c3SLois Curfman McInnes PetscFPrintf(comm,fd," err=%g (relative error in function evaluation)\n",ctx->error_rel); 53eb9086c3SLois Curfman McInnes PetscFPrintf(comm,fd," umin=%g (minimum iterate parameter)\n",ctx->umin); 54eb9086c3SLois Curfman McInnes } 55eb9086c3SLois Curfman McInnes return 0; 56eb9086c3SLois Curfman McInnes } 57eb9086c3SLois Curfman McInnes 585615d1e5SSatish Balay #undef __FUNC__ 595615d1e5SSatish Balay #define __FUNC__ "SNESMatrixFreeMult_Private" 60eb9086c3SLois Curfman McInnes /* 61eb9086c3SLois Curfman McInnes SNESMatrixFreeMult_Private - Default matrix-free form for Jacobian-vector 62eb9086c3SLois Curfman McInnes product, y = F'(u)*a: 63eb9086c3SLois Curfman McInnes y = ( F(u + ha) - F(u) ) /h, 64eb9086c3SLois Curfman McInnes where F = nonlinear function, as set by SNESSetFunction() 65eb9086c3SLois Curfman McInnes u = current iterate 66eb9086c3SLois Curfman McInnes h = difference interval 67eb9086c3SLois Curfman McInnes */ 68eb9086c3SLois Curfman McInnes int SNESMatrixFreeMult_Private(Mat mat,Vec a,Vec y) 6939e2f89bSBarry Smith { 70fae171e0SBarry Smith MFCtx_Private *ctx; 71fae171e0SBarry Smith SNES snes; 72eb9086c3SLois Curfman McInnes double norm, sum, umin; 735334005bSBarry Smith Scalar h, dot, mone = -1.0; 74fae171e0SBarry Smith Vec w,U,F; 7583e56afdSLois Curfman McInnes int ierr, (*eval_fct)(SNES,Vec,Vec); 7639e2f89bSBarry Smith 77fae171e0SBarry Smith MatShellGetContext(mat,(void **)&ctx); 78fae171e0SBarry Smith snes = ctx->snes; 79fae171e0SBarry Smith w = ctx->w; 80eb9086c3SLois Curfman McInnes umin = ctx->umin; 81fae171e0SBarry Smith 8257c37382SLois Curfman McInnes /* We log matrix-free matrix-vector products separately, so that we can 8357c37382SLois Curfman McInnes separate the performance monitoring from the cases that use conventional 8457c37382SLois Curfman McInnes storage. We may eventually modify event logging to associate events 8557c37382SLois Curfman McInnes with particular objects, hence alleviating the more general problem. */ 86eb9086c3SLois Curfman McInnes PLogEventBegin(MAT_MatrixFreeMult,a,y,0,0); 8757c37382SLois Curfman McInnes 8878b31e54SBarry Smith ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr); 8983e56afdSLois Curfman McInnes if (snes->method_class == SNES_NONLINEAR_EQUATIONS) { 9083e56afdSLois Curfman McInnes eval_fct = SNESComputeFunction; 9178b31e54SBarry Smith ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr); 9283e56afdSLois Curfman McInnes } 9383e56afdSLois Curfman McInnes else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 9483e56afdSLois Curfman McInnes eval_fct = SNESComputeGradient; 9583e56afdSLois Curfman McInnes ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr); 9683e56afdSLois Curfman McInnes } 97e3372554SBarry Smith else SETERRQ(1,0,"Invalid method class"); 9850361f65SLois Curfman McInnes 99eb9086c3SLois Curfman McInnes /* Determine a "good" step size, h */ 100eb9086c3SLois Curfman McInnes ierr = VecDot(U,a,&dot); CHKERRQ(ierr); 101eb9086c3SLois Curfman McInnes ierr = VecNorm(a,NORM_1,&sum); CHKERRQ(ierr); 102eb9086c3SLois Curfman McInnes ierr = VecNorm(a,NORM_2,&norm); CHKERRQ(ierr); 103eb9086c3SLois Curfman McInnes 104eb9086c3SLois Curfman McInnes /* Safeguard for step sizes too small */ 105edd2f0e1SBarry Smith if (sum == 0.0) {dot = 1.0; norm = 1.0;} 10619a167f6SBarry Smith #if defined(PETSC_COMPLEX) 107eb9086c3SLois Curfman McInnes else if (abs(dot) < umin*sum && real(dot) >= 0.0) dot = umin*sum; 108eb9086c3SLois Curfman McInnes else if (abs(dot) < 0.0 && real(dot) > -umin*sum) dot = -umin*sum; 10919a167f6SBarry Smith #else 110eb9086c3SLois Curfman McInnes else if (dot < umin*sum && dot >= 0.0) dot = umin*sum; 111eb9086c3SLois Curfman McInnes else if (dot < 0.0 && dot > -umin*sum) dot = -umin*sum; 11219a167f6SBarry Smith #endif 113eb9086c3SLois Curfman McInnes h = ctx->error_rel*dot/(norm*norm); 11439e2f89bSBarry Smith 115eb9086c3SLois Curfman McInnes /* Evaluate function at F(u + ha) */ 116eb9086c3SLois Curfman McInnes ierr = VecWAXPY(&h,a,U,w); CHKERRQ(ierr); 11783e56afdSLois Curfman McInnes ierr = eval_fct(snes,w,y); CHKERRQ(ierr); 118195ee392SLois Curfman McInnes ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr); 1195334005bSBarry Smith h = 1.0/h; 120195ee392SLois Curfman McInnes ierr = VecScale(&h,y); CHKERRQ(ierr); 121b4fd4287SBarry Smith if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);} 12257c37382SLois Curfman McInnes 123eb9086c3SLois Curfman McInnes PLogEventEnd(MAT_MatrixFreeMult,a,y,0,0); 12439e2f89bSBarry Smith return 0; 12539e2f89bSBarry Smith } 12683e56afdSLois Curfman McInnes 1275615d1e5SSatish Balay #undef __FUNC__ 1285615d1e5SSatish Balay #define __FUNC__ "SNESDefaultMatrixFreeMatCreate" 1294b828684SBarry Smith /*@C 1305392566eSBarry Smith SNESDefaultMatrixFreeMatCreate - Creates a matrix-free matrix 13150361f65SLois Curfman McInnes context for use with a SNES solver. This matrix can be used as 13250361f65SLois Curfman McInnes the Jacobian argument for the routine SNESSetJacobian(). 1335392566eSBarry Smith 1345392566eSBarry Smith Input Parameters: 135eb9086c3SLois Curfman McInnes . snes - the SNES context 1365392566eSBarry Smith . x - vector where SNES solution is to be stored. 1375392566eSBarry Smith 138eb9086c3SLois Curfman McInnes Output Parameter: 1395392566eSBarry Smith . J - the matrix-free matrix 1405392566eSBarry Smith 14165afa06eSLois Curfman McInnes Notes: 14265afa06eSLois Curfman McInnes The matrix-free matrix context merely contains the function pointers 14365afa06eSLois Curfman McInnes and work space for performing finite difference approximations of 1443d5db8e1SLois Curfman McInnes Jacobian-vector products, J(u)*a, via 1453d5db8e1SLois Curfman McInnes 1463d5db8e1SLois Curfman McInnes $ J(u)*a = [J(u+h*a) - J(u)]/h where 1473d5db8e1SLois Curfman McInnes $ h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 1483d5db8e1SLois Curfman McInnes $ = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 1493d5db8e1SLois Curfman McInnes $ where 1503d5db8e1SLois Curfman McInnes $ error_rel = square root of relative error in 1513d5db8e1SLois Curfman McInnes $ function evaluation 1523d5db8e1SLois Curfman McInnes $ umin = minimum iterate parameter 1533d5db8e1SLois Curfman McInnes 1543d5db8e1SLois Curfman McInnes The user can set these parameters via SNESSetMatrixFreeParameters(). 1553d5db8e1SLois Curfman McInnes See the nonlinear solvers chapter of the users manual for details. 15665afa06eSLois Curfman McInnes 15765afa06eSLois Curfman McInnes The user should call MatDestroy() when finished with the matrix-free 15865afa06eSLois Curfman McInnes matrix context. 15965afa06eSLois Curfman McInnes 1603d5db8e1SLois Curfman McInnes Options Database Keys: 1613d5db8e1SLois Curfman McInnes $ -snes_mf_err <error_rel> 1623d5db8e1SLois Curfman McInnes $ -snes_mf_unim <umin> 1633d5db8e1SLois Curfman McInnes 16465afa06eSLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix 16565afa06eSLois Curfman McInnes 1663d5db8e1SLois Curfman McInnes .seealso: MatDestroy(), SNESSetMatrixFreeParameters() 1675392566eSBarry Smith @*/ 1685392566eSBarry Smith int SNESDefaultMatrixFreeMatCreate(SNES snes,Vec x, Mat *J) 1695392566eSBarry Smith { 1705392566eSBarry Smith MPI_Comm comm; 1715392566eSBarry Smith MFCtx_Private *mfctx; 172eb9086c3SLois Curfman McInnes int n, nloc, ierr, flg; 1733e966953SLois Curfman McInnes char p[64]; 1745392566eSBarry Smith 1750452661fSBarry Smith mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx); 176464493b3SBarry Smith PLogObjectMemory(snes,sizeof(MFCtx_Private)); 177b4fd4287SBarry Smith mfctx->sp = 0; 1785392566eSBarry Smith mfctx->snes = snes; 179eb9086c3SLois Curfman McInnes mfctx->error_rel = 1.e-8; /* assumes double precision */ 180639f9d9dSBarry Smith mfctx->umin = 1.e-6; 181eb9086c3SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg); CHKERRQ(ierr); 182eb9086c3SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_mf_umin",&mfctx->umin,&flg); CHKERRQ(ierr); 183639f9d9dSBarry Smith ierr = OptionsHasName(PETSC_NULL,"-help",&flg); CHKERRQ(ierr); 1843e966953SLois Curfman McInnes PetscStrcpy(p,"-"); 1853e966953SLois Curfman McInnes if (snes->prefix) PetscStrcat(p,snes->prefix); 186639f9d9dSBarry Smith if (flg) { 1873e966953SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_mf_err <err>: set sqrt rel error in function (default %g)\n",p,mfctx->error_rel); 1883e966953SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_mf_umin <umin> see users manual (default %g)\n",p,mfctx->umin); 189639f9d9dSBarry Smith } 1905392566eSBarry Smith ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr); 191195ee392SLois Curfman McInnes ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr); 192195ee392SLois Curfman McInnes ierr = VecGetSize(x,&n); CHKERRQ(ierr); 1937ddc982cSLois Curfman McInnes ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr); 1947ddc982cSLois Curfman McInnes ierr = MatCreateShell(comm,nloc,n,n,n,(void*)mfctx,J); CHKERRQ(ierr); 1951c1c02c0SLois Curfman McInnes ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)SNESMatrixFreeMult_Private); CHKERRQ(ierr); 1961c1c02c0SLois Curfman McInnes ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)SNESMatrixFreeDestroy_Private); CHKERRQ(ierr); 1971c1c02c0SLois Curfman McInnes ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)SNESMatrixFreeView_Private); CHKERRQ(ierr); 198b9fa9cd0SBarry Smith PLogObjectParent(*J,mfctx->w); 199d370d78aSBarry Smith PLogObjectParent(snes,*J); 20081e6777dSBarry Smith return 0; 20181e6777dSBarry Smith } 20281e6777dSBarry Smith 2035615d1e5SSatish Balay #undef __FUNC__ 2045615d1e5SSatish Balay #define __FUNC__ "SNESSetMatrixFreeParameters" 205b4fd4287SBarry Smith /*@ 206eb9086c3SLois Curfman McInnes SNESSetMatrixFreeParameters - Sets the parameters for the approximation of 207eb9086c3SLois Curfman McInnes matrix-vector products using finite differences. 208eb9086c3SLois Curfman McInnes 209639f9d9dSBarry Smith $ J(u)*a = [J(u+h*a) - J(u)]/h where 210639f9d9dSBarry Smith $ h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 211639f9d9dSBarry Smith $ = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else 212639f9d9dSBarry Smith $ 213eb9086c3SLois Curfman McInnes Input Parameters: 214eb9086c3SLois Curfman McInnes . snes - the SNES context 215ccb6204bSLois Curfman McInnes . error_rel - relative error (should be set to the square root of 216ccb6204bSLois Curfman McInnes the relative error in the function evaluations) 217eb9086c3SLois Curfman McInnes . umin - minimum allowable u-value 218eb9086c3SLois Curfman McInnes 219eb9086c3SLois Curfman McInnes .keywords: SNES, matrix-free, parameters 2203d5db8e1SLois Curfman McInnes 2213d5db8e1SLois Curfman McInnes .seealso: SNESDefaultMatrixFreeMatCreate() 222eb9086c3SLois Curfman McInnes @*/ 223eb9086c3SLois Curfman McInnes int SNESSetMatrixFreeParameters(SNES snes,double error,double umin) 224eb9086c3SLois Curfman McInnes { 225eb9086c3SLois Curfman McInnes MFCtx_Private *ctx; 226eb9086c3SLois Curfman McInnes int ierr; 227eb9086c3SLois Curfman McInnes Mat mat; 228eb9086c3SLois Curfman McInnes 229eb9086c3SLois Curfman McInnes ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr); 230eb9086c3SLois Curfman McInnes ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr); 231eb9086c3SLois Curfman McInnes if (ctx) { 232eb9086c3SLois Curfman McInnes if (error != PETSC_DEFAULT) ctx->error_rel = error; 233eb9086c3SLois Curfman McInnes if (umin != PETSC_DEFAULT) ctx->umin = umin; 234eb9086c3SLois Curfman McInnes } 235eb9086c3SLois Curfman McInnes return 0; 236eb9086c3SLois Curfman McInnes } 237eb9086c3SLois Curfman McInnes 2385615d1e5SSatish Balay #undef __FUNC__ 2395615d1e5SSatish Balay #define __FUNC__ "SNESDefaultMatrixFreeMatAddNullSpace" 240eb9086c3SLois Curfman McInnes /*@ 24121a45821SLois Curfman McInnes SNESDefaultMatrixFreeMatAddNullSpace - Provides a null space that 242f525115eSLois Curfman McInnes an operator is supposed to have. Since roundoff will create a 243b4fd4287SBarry Smith small component in the null space, if you know the null space 244b4fd4287SBarry Smith you may have it automatically removed. 245b4fd4287SBarry Smith 246b4fd4287SBarry Smith Input Parameters: 24721a45821SLois Curfman McInnes . J - the matrix-free matrix context 24821a45821SLois Curfman McInnes . has_cnst - PETSC_TRUE or PETSC_FALSE, indicating if null space has constants 249b4fd4287SBarry Smith . n - number of vectors (excluding constant vector) in null space 25021a45821SLois Curfman McInnes . vecs - the vectors that span the null space (excluding the constant vector); 251b4fd4287SBarry Smith . these vectors must be orthonormal 252b4fd4287SBarry Smith 253b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space 254b4fd4287SBarry Smith @*/ 255b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs) 256b4fd4287SBarry Smith { 257b4fd4287SBarry Smith int ierr; 258b4fd4287SBarry Smith MFCtx_Private *ctx; 259b4fd4287SBarry Smith MPI_Comm comm; 260b4fd4287SBarry Smith 261b4fd4287SBarry Smith PetscObjectGetComm((PetscObject)J,&comm); 262b4fd4287SBarry Smith 263b4fd4287SBarry Smith ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr); 264b4fd4287SBarry Smith /* no context indicates that it is not the "matrix free" matrix type */ 265b4fd4287SBarry Smith if (!ctx) return 0; 266b4fd4287SBarry Smith ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr); 267b4fd4287SBarry Smith return 0; 268b4fd4287SBarry Smith } 269b4fd4287SBarry Smith 2705334005bSBarry Smith 2715334005bSBarry Smith 2725334005bSBarry Smith 273