181e6777dSBarry Smith 281e6777dSBarry Smith #ifndef lint 3*3e966953SLois Curfman McInnes static char vcid[] = "$Id: snesmfj.c,v 1.43 1997/01/21 20:12:37 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*/ 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__ 195615d1e5SSatish Balay #define __FUNC__ "SNESMatrixFreeDestroy_Private" 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__ 345615d1e5SSatish Balay #define __FUNC__ "SNESMatrixFreeView_Private" 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 14465afa06eSLois Curfman McInnes matrix operations such as matrix-vector products. 14565afa06eSLois Curfman McInnes 14665afa06eSLois Curfman McInnes The user should call MatDestroy() when finished with the matrix-free 14765afa06eSLois Curfman McInnes matrix context. 14865afa06eSLois Curfman McInnes 14965afa06eSLois Curfman McInnes .keywords: SNES, default, matrix-free, create, matrix 15065afa06eSLois Curfman McInnes 15165afa06eSLois Curfman McInnes .seealso: MatDestroy() 1525392566eSBarry Smith @*/ 1535392566eSBarry Smith int SNESDefaultMatrixFreeMatCreate(SNES snes,Vec x, Mat *J) 1545392566eSBarry Smith { 1555392566eSBarry Smith MPI_Comm comm; 1565392566eSBarry Smith MFCtx_Private *mfctx; 157eb9086c3SLois Curfman McInnes int n, nloc, ierr, flg; 158*3e966953SLois Curfman McInnes char p[64]; 1595392566eSBarry Smith 1600452661fSBarry Smith mfctx = (MFCtx_Private *) PetscMalloc(sizeof(MFCtx_Private)); CHKPTRQ(mfctx); 161464493b3SBarry Smith PLogObjectMemory(snes,sizeof(MFCtx_Private)); 162b4fd4287SBarry Smith mfctx->sp = 0; 1635392566eSBarry Smith mfctx->snes = snes; 164eb9086c3SLois Curfman McInnes mfctx->error_rel = 1.e-8; /* assumes double precision */ 165639f9d9dSBarry Smith mfctx->umin = 1.e-6; 166eb9086c3SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_mf_err",&mfctx->error_rel,&flg); CHKERRQ(ierr); 167eb9086c3SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_mf_umin",&mfctx->umin,&flg); CHKERRQ(ierr); 168639f9d9dSBarry Smith ierr = OptionsHasName(PETSC_NULL,"-help",&flg); CHKERRQ(ierr); 169*3e966953SLois Curfman McInnes PetscStrcpy(p,"-"); 170*3e966953SLois Curfman McInnes if (snes->prefix) PetscStrcat(p,snes->prefix); 171639f9d9dSBarry Smith if (flg) { 172*3e966953SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_mf_err <err>: set sqrt rel error in function (default %g)\n",p,mfctx->error_rel); 173*3e966953SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_mf_umin <umin> see users manual (default %g)\n",p,mfctx->umin); 174639f9d9dSBarry Smith } 1755392566eSBarry Smith ierr = VecDuplicate(x,&mfctx->w); CHKERRQ(ierr); 176195ee392SLois Curfman McInnes ierr = PetscObjectGetComm((PetscObject)x,&comm); CHKERRQ(ierr); 177195ee392SLois Curfman McInnes ierr = VecGetSize(x,&n); CHKERRQ(ierr); 1787ddc982cSLois Curfman McInnes ierr = VecGetLocalSize(x,&nloc); CHKERRQ(ierr); 1797ddc982cSLois Curfman McInnes ierr = MatCreateShell(comm,nloc,n,n,n,(void*)mfctx,J); CHKERRQ(ierr); 1801c1c02c0SLois Curfman McInnes ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)SNESMatrixFreeMult_Private); CHKERRQ(ierr); 1811c1c02c0SLois Curfman McInnes ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)SNESMatrixFreeDestroy_Private); CHKERRQ(ierr); 1821c1c02c0SLois Curfman McInnes ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)SNESMatrixFreeView_Private); CHKERRQ(ierr); 183b9fa9cd0SBarry Smith PLogObjectParent(*J,mfctx->w); 184d370d78aSBarry Smith PLogObjectParent(snes,*J); 18581e6777dSBarry Smith return 0; 18681e6777dSBarry Smith } 18781e6777dSBarry Smith 1885615d1e5SSatish Balay #undef __FUNC__ 1895615d1e5SSatish Balay #define __FUNC__ "SNESSetMatrixFreeParameters" 190b4fd4287SBarry Smith /*@ 191eb9086c3SLois Curfman McInnes SNESSetMatrixFreeParameters - Sets the parameters for the approximation of 192eb9086c3SLois Curfman McInnes matrix-vector products using finite differences. 193eb9086c3SLois Curfman McInnes 194639f9d9dSBarry Smith $ J(u)*a = [J(u+h*a) - J(u)]/h where 195639f9d9dSBarry Smith $ h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 196639f9d9dSBarry Smith $ = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else 197639f9d9dSBarry Smith $ 198eb9086c3SLois Curfman McInnes Input Parameters: 199eb9086c3SLois Curfman McInnes . snes - the SNES context 200ccb6204bSLois Curfman McInnes . error_rel - relative error (should be set to the square root of 201ccb6204bSLois Curfman McInnes the relative error in the function evaluations) 202eb9086c3SLois Curfman McInnes . umin - minimum allowable u-value 203eb9086c3SLois Curfman McInnes 204eb9086c3SLois Curfman McInnes .keywords: SNES, matrix-free, parameters 205eb9086c3SLois Curfman McInnes @*/ 206eb9086c3SLois Curfman McInnes int SNESSetMatrixFreeParameters(SNES snes,double error,double umin) 207eb9086c3SLois Curfman McInnes { 208eb9086c3SLois Curfman McInnes MFCtx_Private *ctx; 209eb9086c3SLois Curfman McInnes int ierr; 210eb9086c3SLois Curfman McInnes Mat mat; 211eb9086c3SLois Curfman McInnes 212eb9086c3SLois Curfman McInnes ierr = SNESGetJacobian(snes,&mat,PETSC_NULL,PETSC_NULL); CHKERRQ(ierr); 213eb9086c3SLois Curfman McInnes ierr = MatShellGetContext(mat,(void **)&ctx); CHKERRQ(ierr); 214eb9086c3SLois Curfman McInnes if (ctx) { 215eb9086c3SLois Curfman McInnes if (error != PETSC_DEFAULT) ctx->error_rel = error; 216eb9086c3SLois Curfman McInnes if (umin != PETSC_DEFAULT) ctx->umin = umin; 217eb9086c3SLois Curfman McInnes } 218eb9086c3SLois Curfman McInnes return 0; 219eb9086c3SLois Curfman McInnes } 220eb9086c3SLois Curfman McInnes 2215615d1e5SSatish Balay #undef __FUNC__ 2225615d1e5SSatish Balay #define __FUNC__ "SNESDefaultMatrixFreeMatAddNullSpace" 223eb9086c3SLois Curfman McInnes /*@ 22421a45821SLois Curfman McInnes SNESDefaultMatrixFreeMatAddNullSpace - Provides a null space that 225f525115eSLois Curfman McInnes an operator is supposed to have. Since roundoff will create a 226b4fd4287SBarry Smith small component in the null space, if you know the null space 227b4fd4287SBarry Smith you may have it automatically removed. 228b4fd4287SBarry Smith 229b4fd4287SBarry Smith Input Parameters: 23021a45821SLois Curfman McInnes . J - the matrix-free matrix context 23121a45821SLois Curfman McInnes . has_cnst - PETSC_TRUE or PETSC_FALSE, indicating if null space has constants 232b4fd4287SBarry Smith . n - number of vectors (excluding constant vector) in null space 23321a45821SLois Curfman McInnes . vecs - the vectors that span the null space (excluding the constant vector); 234b4fd4287SBarry Smith . these vectors must be orthonormal 235b4fd4287SBarry Smith 236b4fd4287SBarry Smith .keywords: SNES, matrix-free, null space 237b4fd4287SBarry Smith @*/ 238b4fd4287SBarry Smith int SNESDefaultMatrixFreeMatAddNullSpace(Mat J,int has_cnst,int n,Vec *vecs) 239b4fd4287SBarry Smith { 240b4fd4287SBarry Smith int ierr; 241b4fd4287SBarry Smith MFCtx_Private *ctx; 242b4fd4287SBarry Smith MPI_Comm comm; 243b4fd4287SBarry Smith 244b4fd4287SBarry Smith PetscObjectGetComm((PetscObject)J,&comm); 245b4fd4287SBarry Smith 246b4fd4287SBarry Smith ierr = MatShellGetContext(J,(void **)&ctx); CHKERRQ(ierr); 247b4fd4287SBarry Smith /* no context indicates that it is not the "matrix free" matrix type */ 248b4fd4287SBarry Smith if (!ctx) return 0; 249b4fd4287SBarry Smith ierr = PCNullSpaceCreate(comm,has_cnst,n,vecs,&ctx->sp); CHKERRQ(ierr); 250b4fd4287SBarry Smith return 0; 251b4fd4287SBarry Smith } 252b4fd4287SBarry Smith 2535334005bSBarry Smith 2545334005bSBarry Smith 2555334005bSBarry Smith 256