181e6777dSBarry Smith 281e6777dSBarry Smith #ifndef lint 3*029af93fSBarry Smith static char vcid[] = "$Id: snesmfj.c,v 1.48 1997/04/07 20:11:46 bsmith Exp bsmith $"; 481e6777dSBarry Smith #endif 581e6777dSBarry Smith 670f55243SBarry Smith #include "src/snes/snesimpl.h" /*I "snes.h" I*/ 7eb9086c3SLois Curfman McInnes #include "pinclude/pviewer.h" 881e6777dSBarry Smith 950361f65SLois Curfman McInnes typedef struct { /* default context for matrix-free SNES */ 10eb9086c3SLois Curfman McInnes SNES snes; /* SNES context */ 11eb9086c3SLois Curfman McInnes Vec w; /* work vector */ 12eb9086c3SLois Curfman McInnes PCNullSpace sp; /* null space context */ 13eb9086c3SLois Curfman McInnes double error_rel; /* square root of relative error in computing function */ 14639f9d9dSBarry Smith double umin; /* minimum allowable u'a value relative to |u|_1 */ 1539e2f89bSBarry Smith } MFCtx_Private; 1639e2f89bSBarry Smith 175615d1e5SSatish Balay #undef __FUNC__ 185eea60f9SBarry Smith #define __FUNC__ "SNESMatrixFreeDestroy_Private" /* ADIC Ignore */ 19fae171e0SBarry Smith int SNESMatrixFreeDestroy_Private(PetscObject obj) 20b9fa9cd0SBarry Smith { 21b9fa9cd0SBarry Smith int ierr; 22fae171e0SBarry Smith Mat mat = (Mat) obj; 23fae171e0SBarry Smith MFCtx_Private *ctx; 24fae171e0SBarry Smith 25fae171e0SBarry Smith ierr = MatShellGetContext(mat,(void **)&ctx); 26b9fa9cd0SBarry Smith ierr = VecDestroy(ctx->w); CHKERRQ(ierr); 27b4fd4287SBarry Smith if (ctx->sp) {ierr = PCNullSpaceDestroy(ctx->sp); CHKERRQ(ierr);} 28fae171e0SBarry Smith PetscFree(ctx); 29b9fa9cd0SBarry Smith return 0; 30b9fa9cd0SBarry Smith } 3150361f65SLois Curfman McInnes 325615d1e5SSatish Balay #undef __FUNC__ 335eea60f9SBarry Smith #define __FUNC__ "SNESMatrixFreeView_Private" /* ADIC Ignore */ 3439e2f89bSBarry Smith /* 351d1bbde2SLois Curfman McInnes SNESMatrixFreeView_Private - Views matrix-free parameters. 3639e2f89bSBarry Smith */ 37eb9086c3SLois Curfman McInnes int SNESMatrixFreeView_Private(Mat J,Viewer viewer) 38eb9086c3SLois Curfman McInnes { 39eb9086c3SLois Curfman McInnes int ierr; 40eb9086c3SLois Curfman McInnes MFCtx_Private *ctx; 41eb9086c3SLois Curfman McInnes MPI_Comm comm; 42eb9086c3SLois Curfman McInnes FILE *fd; 43eb9086c3SLois Curfman McInnes ViewerType vtype; 44eb9086c3SLois Curfman McInnes 45eb9086c3SLois Curfman McInnes PetscObjectGetComm((PetscObject)J,&comm); 46eb9086c3SLois Curfman McInnes ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr); 47eb9086c3SLois Curfman McInnes ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 48eb9086c3SLois Curfman McInnes ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 49eb9086c3SLois Curfman McInnes if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 50eb9086c3SLois Curfman McInnes PetscFPrintf(comm,fd," SNES matrix-free approximation:\n"); 51eb9086c3SLois Curfman McInnes PetscFPrintf(comm,fd," err=%g (relative error in function evaluation)\n",ctx->error_rel); 52eb9086c3SLois Curfman McInnes PetscFPrintf(comm,fd," umin=%g (minimum iterate parameter)\n",ctx->umin); 53eb9086c3SLois Curfman McInnes } 54eb9086c3SLois Curfman McInnes return 0; 55eb9086c3SLois Curfman McInnes } 56eb9086c3SLois Curfman McInnes 575615d1e5SSatish Balay #undef __FUNC__ 585615d1e5SSatish Balay #define __FUNC__ "SNESMatrixFreeMult_Private" 59eb9086c3SLois Curfman McInnes /* 60eb9086c3SLois Curfman McInnes SNESMatrixFreeMult_Private - Default matrix-free form for Jacobian-vector 61eb9086c3SLois Curfman McInnes product, y = F'(u)*a: 62eb9086c3SLois Curfman McInnes y = ( F(u + ha) - F(u) ) /h, 63eb9086c3SLois Curfman McInnes where F = nonlinear function, as set by SNESSetFunction() 64eb9086c3SLois Curfman McInnes u = current iterate 65eb9086c3SLois Curfman McInnes h = difference interval 66eb9086c3SLois Curfman McInnes */ 67eb9086c3SLois Curfman McInnes int SNESMatrixFreeMult_Private(Mat mat,Vec a,Vec y) 6839e2f89bSBarry Smith { 69fae171e0SBarry Smith MFCtx_Private *ctx; 70fae171e0SBarry Smith SNES snes; 71eb9086c3SLois Curfman McInnes double norm, sum, umin; 725334005bSBarry Smith Scalar h, dot, mone = -1.0; 73fae171e0SBarry Smith Vec w,U,F; 7483e56afdSLois Curfman McInnes int ierr, (*eval_fct)(SNES,Vec,Vec); 7539e2f89bSBarry Smith 766e38a044SBarry Smith ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr); 77fae171e0SBarry Smith snes = ctx->snes; 78fae171e0SBarry Smith w = ctx->w; 79eb9086c3SLois Curfman McInnes umin = ctx->umin; 80fae171e0SBarry Smith 8157c37382SLois Curfman McInnes /* We log matrix-free matrix-vector products separately, so that we can 8257c37382SLois Curfman McInnes separate the performance monitoring from the cases that use conventional 8357c37382SLois Curfman McInnes storage. We may eventually modify event logging to associate events 8457c37382SLois Curfman McInnes with particular objects, hence alleviating the more general problem. */ 85eb9086c3SLois Curfman McInnes PLogEventBegin(MAT_MatrixFreeMult,a,y,0,0); 8657c37382SLois Curfman McInnes 8778b31e54SBarry Smith ierr = SNESGetSolution(snes,&U); CHKERRQ(ierr); 8883e56afdSLois Curfman McInnes if (snes->method_class == SNES_NONLINEAR_EQUATIONS) { 8983e56afdSLois Curfman McInnes eval_fct = SNESComputeFunction; 9078b31e54SBarry Smith ierr = SNESGetFunction(snes,&F); CHKERRQ(ierr); 9183e56afdSLois Curfman McInnes } 9283e56afdSLois Curfman McInnes else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 9383e56afdSLois Curfman McInnes eval_fct = SNESComputeGradient; 9483e56afdSLois Curfman McInnes ierr = SNESGetGradient(snes,&F); CHKERRQ(ierr); 9583e56afdSLois Curfman McInnes } 96e3372554SBarry Smith else SETERRQ(1,0,"Invalid method class"); 9750361f65SLois Curfman McInnes 98eb9086c3SLois Curfman McInnes /* Determine a "good" step size, h */ 99eb9086c3SLois Curfman McInnes ierr = VecDot(U,a,&dot); CHKERRQ(ierr); 100eb9086c3SLois Curfman McInnes ierr = VecNorm(a,NORM_1,&sum); CHKERRQ(ierr); 101eb9086c3SLois Curfman McInnes ierr = VecNorm(a,NORM_2,&norm); CHKERRQ(ierr); 102eb9086c3SLois Curfman McInnes 103eb9086c3SLois Curfman McInnes /* Safeguard for step sizes too small */ 104edd2f0e1SBarry Smith if (sum == 0.0) {dot = 1.0; norm = 1.0;} 10519a167f6SBarry Smith #if defined(PETSC_COMPLEX) 106eb9086c3SLois Curfman McInnes else if (abs(dot) < umin*sum && real(dot) >= 0.0) dot = umin*sum; 107eb9086c3SLois Curfman McInnes else if (abs(dot) < 0.0 && real(dot) > -umin*sum) dot = -umin*sum; 10819a167f6SBarry Smith #else 109eb9086c3SLois Curfman McInnes else if (dot < umin*sum && dot >= 0.0) dot = umin*sum; 110eb9086c3SLois Curfman McInnes else if (dot < 0.0 && dot > -umin*sum) dot = -umin*sum; 11119a167f6SBarry Smith #endif 112eb9086c3SLois Curfman McInnes h = ctx->error_rel*dot/(norm*norm); 11339e2f89bSBarry Smith 114eb9086c3SLois Curfman McInnes /* Evaluate function at F(u + ha) */ 115eb9086c3SLois Curfman McInnes ierr = VecWAXPY(&h,a,U,w); CHKERRQ(ierr); 11683e56afdSLois Curfman McInnes ierr = eval_fct(snes,w,y); CHKERRQ(ierr); 117195ee392SLois Curfman McInnes ierr = VecAXPY(&mone,F,y); CHKERRQ(ierr); 1185334005bSBarry Smith h = 1.0/h; 119195ee392SLois Curfman McInnes ierr = VecScale(&h,y); CHKERRQ(ierr); 120b4fd4287SBarry Smith if (ctx->sp) {ierr = PCNullSpaceRemove(ctx->sp,y); CHKERRQ(ierr);} 12157c37382SLois Curfman McInnes 122eb9086c3SLois Curfman McInnes PLogEventEnd(MAT_MatrixFreeMult,a,y,0,0); 12339e2f89bSBarry Smith return 0; 12439e2f89bSBarry Smith } 12583e56afdSLois Curfman McInnes 1265615d1e5SSatish Balay #undef __FUNC__ 1275615d1e5SSatish Balay #define __FUNC__ "SNESDefaultMatrixFreeMatCreate" 1284b828684SBarry Smith /*@C 1295392566eSBarry Smith SNESDefaultMatrixFreeMatCreate - Creates a matrix-free matrix 13050361f65SLois Curfman McInnes context for use with a SNES solver. This matrix can be used as 13150361f65SLois Curfman McInnes the Jacobian argument for the routine SNESSetJacobian(). 1325392566eSBarry Smith 1335392566eSBarry Smith Input Parameters: 134eb9086c3SLois Curfman McInnes . snes - the SNES context 1355392566eSBarry Smith . x - vector where SNES solution is to be stored. 1365392566eSBarry Smith 137eb9086c3SLois Curfman McInnes Output Parameter: 1385392566eSBarry Smith . J - the matrix-free matrix 1395392566eSBarry Smith 14065afa06eSLois Curfman McInnes Notes: 14165afa06eSLois Curfman McInnes The matrix-free matrix context merely contains the function pointers 14265afa06eSLois Curfman McInnes and work space for performing finite difference approximations of 1433d5db8e1SLois Curfman McInnes Jacobian-vector products, J(u)*a, via 1443d5db8e1SLois Curfman McInnes 1453d5db8e1SLois Curfman McInnes $ J(u)*a = [J(u+h*a) - J(u)]/h where 1463d5db8e1SLois Curfman McInnes $ h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 1473d5db8e1SLois Curfman McInnes $ = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 1483d5db8e1SLois Curfman McInnes $ where 1493d5db8e1SLois Curfman McInnes $ error_rel = square root of relative error in 1503d5db8e1SLois Curfman McInnes $ function evaluation 1513d5db8e1SLois Curfman McInnes $ umin = minimum iterate parameter 1523d5db8e1SLois Curfman McInnes 1533d5db8e1SLois Curfman McInnes The user can set these parameters via SNESSetMatrixFreeParameters(). 1543d5db8e1SLois Curfman McInnes See the nonlinear solvers chapter of the users manual for details. 15565afa06eSLois Curfman McInnes 15665afa06eSLois Curfman McInnes The user should call MatDestroy() when finished with the matrix-free 15765afa06eSLois Curfman McInnes matrix context. 15865afa06eSLois Curfman McInnes 1593d5db8e1SLois Curfman McInnes Options Database Keys: 1603d5db8e1SLois Curfman McInnes $ -snes_mf_err <error_rel> 1613d5db8e1SLois Curfman McInnes $ -snes_mf_unim <umin> 1623d5db8e1SLois Curfman McInnes 16365afa06eSLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix 16465afa06eSLois Curfman McInnes 1653d5db8e1SLois Curfman McInnes .seealso: MatDestroy(), SNESSetMatrixFreeParameters() 1665392566eSBarry Smith @*/ 1675392566eSBarry Smith int SNESDefaultMatrixFreeMatCreate(SNES snes,Vec x, Mat *J) 1685392566eSBarry Smith { 1695392566eSBarry Smith MPI_Comm comm; 1705392566eSBarry Smith MFCtx_Private *mfctx; 171eb9086c3SLois Curfman McInnes int n, nloc, ierr, flg; 1723e966953SLois Curfman McInnes char p[64]; 1735392566eSBarry Smith 1740452661fSBarry Smith mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx); 175464493b3SBarry Smith PLogObjectMemory(snes,sizeof(MFCtx_Private)); 176b4fd4287SBarry Smith mfctx->sp = 0; 1775392566eSBarry Smith mfctx->snes = snes; 178eb9086c3SLois Curfman McInnes mfctx->error_rel = 1.e-8; /* assumes double precision */ 179639f9d9dSBarry Smith mfctx->umin = 1.e-6; 180eb9086c3SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg); CHKERRQ(ierr); 181eb9086c3SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_mf_umin",&mfctx->umin,&flg); CHKERRQ(ierr); 182639f9d9dSBarry Smith ierr = OptionsHasName(PETSC_NULL,"-help",&flg); CHKERRQ(ierr); 1833e966953SLois Curfman McInnes PetscStrcpy(p,"-"); 1843e966953SLois Curfman McInnes if (snes->prefix) PetscStrcat(p,snes->prefix); 185639f9d9dSBarry Smith if (flg) { 1863e966953SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_mf_err <err>: set sqrt rel error in function (default %g)\n",p,mfctx->error_rel); 1873e966953SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_mf_umin <umin> see users manual (default %g)\n",p,mfctx->umin); 188639f9d9dSBarry Smith } 1895392566eSBarry Smith ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr); 190195ee392SLois Curfman McInnes ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr); 191195ee392SLois Curfman McInnes ierr = VecGetSize(x,&n); CHKERRQ(ierr); 1927ddc982cSLois Curfman McInnes ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr); 193*029af93fSBarry Smith ierr = MatCreateShell(comm,nloc,n,n,n,mfctx,J); CHKERRQ(ierr); 1941c1c02c0SLois Curfman McInnes ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)SNESMatrixFreeMult_Private);CHKERRQ(ierr); 1951c1c02c0SLois Curfman McInnes ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)SNESMatrixFreeDestroy_Private);CHKERRQ(ierr); 1961c1c02c0SLois Curfman McInnes ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)SNESMatrixFreeView_Private); CHKERRQ(ierr); 197b9fa9cd0SBarry Smith PLogObjectParent(*J,mfctx->w); 198d370d78aSBarry Smith PLogObjectParent(snes,*J); 19981e6777dSBarry Smith return 0; 20081e6777dSBarry Smith } 20181e6777dSBarry Smith 2025615d1e5SSatish Balay #undef __FUNC__ 2035615d1e5SSatish Balay #define __FUNC__ "SNESSetMatrixFreeParameters" 204b4fd4287SBarry Smith /*@ 205eb9086c3SLois Curfman McInnes SNESSetMatrixFreeParameters - Sets the parameters for the approximation of 206eb9086c3SLois Curfman McInnes matrix-vector products using finite differences. 207eb9086c3SLois Curfman McInnes 208639f9d9dSBarry Smith $ J(u)*a = [J(u+h*a) - J(u)]/h where 209639f9d9dSBarry Smith $ h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 210639f9d9dSBarry Smith $ = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else 211639f9d9dSBarry Smith $ 212eb9086c3SLois Curfman McInnes Input Parameters: 213eb9086c3SLois Curfman McInnes . snes - the SNES context 214ccb6204bSLois Curfman McInnes . error_rel - relative error (should be set to the square root of 215ccb6204bSLois Curfman McInnes the relative error in the function evaluations) 216eb9086c3SLois Curfman McInnes . umin - minimum allowable u-value 217eb9086c3SLois Curfman McInnes 218eb9086c3SLois Curfman McInnes .keywords: SNES, matrix-free, parameters 2193d5db8e1SLois Curfman McInnes 2203d5db8e1SLois Curfman McInnes .seealso: SNESDefaultMatrixFreeMatCreate() 221eb9086c3SLois Curfman McInnes @*/ 222eb9086c3SLois Curfman McInnes int SNESSetMatrixFreeParameters(SNES snes,double error,double umin) 223eb9086c3SLois Curfman McInnes { 224eb9086c3SLois Curfman McInnes MFCtx_Private *ctx; 225eb9086c3SLois Curfman McInnes int ierr; 226eb9086c3SLois Curfman McInnes Mat mat; 227eb9086c3SLois Curfman McInnes 228eb9086c3SLois Curfman McInnes ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr); 229eb9086c3SLois Curfman McInnes ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr); 230eb9086c3SLois Curfman McInnes if (ctx) { 231eb9086c3SLois Curfman McInnes if (error != PETSC_DEFAULT) ctx->error_rel = error; 232eb9086c3SLois Curfman McInnes if (umin != PETSC_DEFAULT) ctx->umin = umin; 233eb9086c3SLois Curfman McInnes } 234eb9086c3SLois Curfman McInnes return 0; 235eb9086c3SLois Curfman McInnes } 236eb9086c3SLois Curfman McInnes 2375615d1e5SSatish Balay #undef __FUNC__ 2385615d1e5SSatish Balay #define __FUNC__ "SNESDefaultMatrixFreeMatAddNullSpace" 239eb9086c3SLois Curfman McInnes /*@ 24021a45821SLois Curfman McInnes SNESDefaultMatrixFreeMatAddNullSpace - Provides a null space that 241f525115eSLois Curfman McInnes an operator is supposed to have. Since roundoff will create a 242b4fd4287SBarry Smith small component in the null space, if you know the null space 243b4fd4287SBarry Smith you may have it automatically removed. 244b4fd4287SBarry Smith 245b4fd4287SBarry Smith Input Parameters: 24621a45821SLois Curfman McInnes . J - the matrix-free matrix context 24721a45821SLois Curfman McInnes . has_cnst - PETSC_TRUE or PETSC_FALSE, indicating if null space has constants 248b4fd4287SBarry Smith . n - number of vectors (excluding constant vector) in null space 24921a45821SLois Curfman McInnes . vecs - the vectors that span the null space (excluding the constant vector); 250b4fd4287SBarry Smith . these vectors must be orthonormal 251b4fd4287SBarry Smith 252b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space 253b4fd4287SBarry Smith @*/ 254b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs) 255b4fd4287SBarry Smith { 256b4fd4287SBarry Smith int ierr; 257b4fd4287SBarry Smith MFCtx_Private *ctx; 258b4fd4287SBarry Smith MPI_Comm comm; 259b4fd4287SBarry Smith 260b4fd4287SBarry Smith PetscObjectGetComm((PetscObject)J,&comm); 261b4fd4287SBarry Smith 262b4fd4287SBarry Smith ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr); 263b4fd4287SBarry Smith /* no context indicates that it is not the "matrix free" matrix type */ 264b4fd4287SBarry Smith if (!ctx) return 0; 265b4fd4287SBarry Smith ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr); 266b4fd4287SBarry Smith return 0; 267b4fd4287SBarry Smith } 268b4fd4287SBarry Smith 2695334005bSBarry Smith 2705334005bSBarry Smith 2715334005bSBarry Smith 272