15e76c431SBarry Smith #ifndef lint 2*16c95cacSBarry Smith static char vcid[] = "$Id: ls.c,v 1.81 1997/01/14 22:58:01 curfman Exp bsmith $"; 35e76c431SBarry Smith #endif 45e76c431SBarry Smith 55e76c431SBarry Smith #include <math.h> 670f55243SBarry Smith #include "src/snes/impls/ls/ls.h" 7b16a3bb1SBarry Smith #include "pinclude/pviewer.h" 85e42470aSBarry Smith 95e42470aSBarry Smith /* 105e42470aSBarry Smith Implements a line search variant of Newton's Method 115e76c431SBarry Smith for solving systems of nonlinear equations. 125e76c431SBarry Smith 135e76c431SBarry Smith Input parameters: 145e42470aSBarry Smith . snes - nonlinear context obtained from SNESCreate() 155e76c431SBarry Smith 165e42470aSBarry Smith Output Parameters: 17a935fc98SLois Curfman McInnes . outits - Number of global iterations until termination. 185e76c431SBarry Smith 195e76c431SBarry Smith Notes: 205e76c431SBarry Smith This implements essentially a truncated Newton method with a 215e76c431SBarry Smith line search. By default a cubic backtracking line search 225e76c431SBarry Smith is employed, as described in the text "Numerical Methods for 235e76c431SBarry Smith Unconstrained Optimization and Nonlinear Equations" by Dennis 24393d2d9aSLois Curfman McInnes and Schnabel. 255e76c431SBarry Smith */ 265e76c431SBarry Smith 275615d1e5SSatish Balay #undef __FUNC__ 285615d1e5SSatish Balay #define __FUNC__ "SNESSolve_EQ_LS" 29f63b844aSLois Curfman McInnes int SNESSolve_EQ_LS(SNES snes,int *outits) 305e76c431SBarry Smith { 315e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 32761aaf1bSLois Curfman McInnes int maxits, i, history_len, ierr, lits, lsfail; 33112a2221SBarry Smith MatStructure flg = DIFFERENT_NONZERO_PATTERN; 346b5873e3SBarry Smith double fnorm, gnorm, xnorm, ynorm, *history; 355e42470aSBarry Smith Vec Y, X, F, G, W, TMP; 365e76c431SBarry Smith 375e42470aSBarry Smith history = snes->conv_hist; /* convergence history */ 385e42470aSBarry Smith history_len = snes->conv_hist_len; /* convergence history length */ 395e42470aSBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 405e42470aSBarry Smith X = snes->vec_sol; /* solution vector */ 4139e2f89bSBarry Smith F = snes->vec_func; /* residual vector */ 425e42470aSBarry Smith Y = snes->work[0]; /* work vectors */ 435e42470aSBarry Smith G = snes->work[1]; 445e42470aSBarry Smith W = snes->work[2]; 455e76c431SBarry Smith 46cddf8d76SBarry Smith ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 4725ed9cd1SBarry Smith snes->iter = 0; 485334005bSBarry Smith ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* F(X) */ 49cddf8d76SBarry Smith ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr); /* fnorm <- ||F|| */ 505e42470aSBarry Smith snes->norm = fnorm; 515e76c431SBarry Smith if (history && history_len > 0) history[0] = fnorm; 5294a424c1SBarry Smith SNESMonitor(snes,0,fnorm); 535e76c431SBarry Smith 54d034289bSBarry Smith /* set parameter for default relative tolerance convergence test */ 55d034289bSBarry Smith snes->ttol = fnorm*snes->rtol; 56d034289bSBarry Smith 575e76c431SBarry Smith for ( i=0; i<maxits; i++ ) { 585e42470aSBarry Smith snes->iter = i+1; 595e76c431SBarry Smith 60ea4d3ed3SLois Curfman McInnes /* Solve J Y = F, where J is Jacobian matrix */ 615334005bSBarry Smith ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg); CHKERRQ(ierr); 625334005bSBarry Smith ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr); 6378b31e54SBarry Smith ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr); 647a00f4a9SLois Curfman McInnes snes->linear_its += PetscAbsInt(lits); 65af1ccdebSLois Curfman McInnes PLogInfo(snes,"SNESSolve_EQ_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits); 66ea4d3ed3SLois Curfman McInnes 67ea4d3ed3SLois Curfman McInnes /* Compute a (scaled) negative update in the line search routine: 68ea4d3ed3SLois Curfman McInnes Y <- X - lambda*Y 69ea4d3ed3SLois Curfman McInnes and evaluate G(Y) = function(Y)) 70ea4d3ed3SLois Curfman McInnes */ 7181b6cf68SLois Curfman McInnes ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr); 72ddd12767SBarry Smith ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); CHKERRQ(ierr); 73af1ccdebSLois Curfman McInnes PLogInfo(snes,"SNESSolve_EQ_LS: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail); 74761aaf1bSLois Curfman McInnes if (lsfail) snes->nfailures++; 755e76c431SBarry Smith 7639e2f89bSBarry Smith TMP = F; F = G; snes->vec_func_always = F; G = TMP; 7739e2f89bSBarry Smith TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 785e76c431SBarry Smith fnorm = gnorm; 795e76c431SBarry Smith 805e42470aSBarry Smith snes->norm = fnorm; 815e76c431SBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 82cddf8d76SBarry Smith ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 8394a424c1SBarry Smith SNESMonitor(snes,i+1,fnorm); 845e76c431SBarry Smith 855e76c431SBarry Smith /* Test for convergence */ 86bbb6d6a8SBarry Smith if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) { 87*16c95cacSBarry Smith break; 88*16c95cacSBarry Smith } 89*16c95cacSBarry Smith } 9039e2f89bSBarry Smith if (X != snes->vec_sol) { 91393d2d9aSLois Curfman McInnes ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr); 9239e2f89bSBarry Smith snes->vec_sol_always = snes->vec_sol; 9339e2f89bSBarry Smith snes->vec_func_always = snes->vec_func; 9439e2f89bSBarry Smith } 9552392280SLois Curfman McInnes if (i == maxits) { 9694a424c1SBarry Smith PLogInfo(snes, 97f63b844aSLois Curfman McInnes "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits); 9852392280SLois Curfman McInnes i--; 9952392280SLois Curfman McInnes } 1005e42470aSBarry Smith *outits = i+1; 1015e42470aSBarry Smith return 0; 1025e76c431SBarry Smith } 1035e76c431SBarry Smith /* ------------------------------------------------------------ */ 1045615d1e5SSatish Balay #undef __FUNC__ 1055615d1e5SSatish Balay #define __FUNC__ "SNESSetUp_EQ_LS" 106f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes ) 1075e76c431SBarry Smith { 1085e42470aSBarry Smith int ierr; 10981b6cf68SLois Curfman McInnes snes->nwork = 4; 110d7e8b826SBarry Smith ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr); 1115e42470aSBarry Smith PLogObjectParents(snes,snes->nwork,snes->work); 11281b6cf68SLois Curfman McInnes snes->vec_sol_update_always = snes->work[3]; 1135e42470aSBarry Smith return 0; 1145e76c431SBarry Smith } 1155e76c431SBarry Smith /* ------------------------------------------------------------ */ 1165615d1e5SSatish Balay #undef __FUNC__ 1175615d1e5SSatish Balay #define __FUNC__ "SNESDestroy_EQ_LS" 118f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj) 1195e76c431SBarry Smith { 1205e42470aSBarry Smith SNES snes = (SNES) obj; 121393d2d9aSLois Curfman McInnes int ierr; 1225baf8537SBarry Smith if (snes->nwork) { 1234b0e389bSBarry Smith ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr); 12421c89e3eSBarry Smith } 1250452661fSBarry Smith PetscFree(snes->data); 1265e42470aSBarry Smith return 0; 1275e76c431SBarry Smith } 1285e76c431SBarry Smith /* ------------------------------------------------------------ */ 1295615d1e5SSatish Balay #undef __FUNC__ 1305615d1e5SSatish Balay #define __FUNC__ "SNESNoLineSearch" 1315e76c431SBarry Smith /*ARGSUSED*/ 1324b828684SBarry Smith /*@C 1335e42470aSBarry Smith SNESNoLineSearch - This routine is not a line search at all; 1345e76c431SBarry Smith it simply uses the full Newton step. Thus, this routine is intended 1355e76c431SBarry Smith to serve as a template and is not recommended for general use. 1365e76c431SBarry Smith 1375e76c431SBarry Smith Input Parameters: 1385e42470aSBarry Smith . snes - nonlinear context 1395e76c431SBarry Smith . x - current iterate 1405e76c431SBarry Smith . f - residual evaluated at x 1415e76c431SBarry Smith . y - search direction (contains new iterate on output) 1425e76c431SBarry Smith . w - work vector 1435e76c431SBarry Smith . fnorm - 2-norm of f 1445e76c431SBarry Smith 145c4a48953SLois Curfman McInnes Output Parameters: 1465e76c431SBarry Smith . g - residual evaluated at new iterate y 1475e76c431SBarry Smith . y - new iterate (contains search direction on input) 1485e76c431SBarry Smith . gnorm - 2-norm of g 1495e76c431SBarry Smith . ynorm - 2-norm of search length 150761aaf1bSLois Curfman McInnes . flag - set to 0, indicating a successful line search 1515e76c431SBarry Smith 152c4a48953SLois Curfman McInnes Options Database Key: 15309d61ba7SLois Curfman McInnes $ -snes_eq_ls basic 154c4a48953SLois Curfman McInnes 15528ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 15628ae5a21SLois Curfman McInnes 157f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 15877c4ece6SBarry Smith SNESSetLineSearch() 1595e76c431SBarry Smith @*/ 1605e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 161761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag ) 1625e76c431SBarry Smith { 1635e42470aSBarry Smith int ierr; 1645334005bSBarry Smith Scalar mone = -1.0; 1655334005bSBarry Smith 166761aaf1bSLois Curfman McInnes *flag = 0; 1677857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 168cddf8d76SBarry Smith ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr); /* ynorm = || y || */ 169ea4d3ed3SLois Curfman McInnes ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr); /* y <- y - x */ 170ea4d3ed3SLois Curfman McInnes ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y) */ 171cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); /* gnorm = || g || */ 1727857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 173761aaf1bSLois Curfman McInnes return 0; 1745e76c431SBarry Smith } 1755e76c431SBarry Smith /* ------------------------------------------------------------------ */ 1765615d1e5SSatish Balay #undef __FUNC__ 1775615d1e5SSatish Balay #define __FUNC__ "SNESCubicLineSearch" 1784b828684SBarry Smith /*@C 179f525115eSLois Curfman McInnes SNESCubicLineSearch - Performs a cubic line search (default line search method). 1805e76c431SBarry Smith 1815e76c431SBarry Smith Input Parameters: 1825e42470aSBarry Smith . snes - nonlinear context 1835e76c431SBarry Smith . x - current iterate 1845e76c431SBarry Smith . f - residual evaluated at x 1855e76c431SBarry Smith . y - search direction (contains new iterate on output) 1865e76c431SBarry Smith . w - work vector 1875e76c431SBarry Smith . fnorm - 2-norm of f 1885e76c431SBarry Smith 189393d2d9aSLois Curfman McInnes Output Parameters: 1905e76c431SBarry Smith . g - residual evaluated at new iterate y 1915e76c431SBarry Smith . y - new iterate (contains search direction on input) 1925e76c431SBarry Smith . gnorm - 2-norm of g 1935e76c431SBarry Smith . ynorm - 2-norm of search length 194761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 1955e76c431SBarry Smith 196c4a48953SLois Curfman McInnes Options Database Key: 19709d61ba7SLois Curfman McInnes $ -snes_eq_ls cubic 198c4a48953SLois Curfman McInnes 1995e76c431SBarry Smith Notes: 2005e76c431SBarry Smith This line search is taken from "Numerical Methods for Unconstrained 2015e76c431SBarry Smith Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 2025e76c431SBarry Smith 20328ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 20428ae5a21SLois Curfman McInnes 20577c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 2065e76c431SBarry Smith @*/ 2075e42470aSBarry Smith int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w, 208761aaf1bSLois Curfman McInnes double fnorm,double *ynorm,double *gnorm,int *flag) 2095e76c431SBarry Smith { 210ddd12767SBarry Smith double steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2; 211ea4d3ed3SLois Curfman McInnes double maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg; 2126b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 2135e42470aSBarry Smith Scalar cinitslope, clambda; 2146b5873e3SBarry Smith #endif 2155e42470aSBarry Smith int ierr, count; 2165e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 2175334005bSBarry Smith Scalar mone = -1.0,scale; 2185e76c431SBarry Smith 2197857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 220761aaf1bSLois Curfman McInnes *flag = 0; 2215e76c431SBarry Smith alpha = neP->alpha; 2225e76c431SBarry Smith maxstep = neP->maxstep; 2235e76c431SBarry Smith steptol = neP->steptol; 2245e76c431SBarry Smith 225cddf8d76SBarry Smith ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr); 2265e76c431SBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 2275e42470aSBarry Smith scale = maxstep/(*ynorm); 2286b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 22994a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale)); 2306b5873e3SBarry Smith #else 23194a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale); 2326b5873e3SBarry Smith #endif 233393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 2345e76c431SBarry Smith *ynorm = maxstep; 2355e76c431SBarry Smith } 2365e76c431SBarry Smith minlambda = steptol/(*ynorm); 237a703fe33SLois Curfman McInnes ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 2385e42470aSBarry Smith #if defined(PETSC_COMPLEX) 239a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 2405e42470aSBarry Smith initslope = real(cinitslope); 2415e42470aSBarry Smith #else 242a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 2435e42470aSBarry Smith #endif 2445e76c431SBarry Smith if (initslope > 0.0) initslope = -initslope; 2455e76c431SBarry Smith if (initslope == 0.0) initslope = -1.0; 2465e76c431SBarry Smith 247393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 2485334005bSBarry Smith ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 24978b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 250cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); 2515e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 252393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 25394a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Using full step\n"); 254d93a2b8dSBarry Smith goto theend; 2555e76c431SBarry Smith } 2565e76c431SBarry Smith 2575e76c431SBarry Smith /* Fit points with quadratic */ 2585e76c431SBarry Smith lambda = 1.0; count = 0; 259a703fe33SLois Curfman McInnes lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 2605e76c431SBarry Smith lambdaprev = lambda; 2615e76c431SBarry Smith gnormprev = *gnorm; 262ddd12767SBarry Smith if (lambdatemp <= .1*lambda) lambda = .1*lambda; 263ddd12767SBarry Smith else lambda = lambdatemp; 264393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 265ea4d3ed3SLois Curfman McInnes lambdaneg = -lambda; 2665e42470aSBarry Smith #if defined(PETSC_COMPLEX) 267ea4d3ed3SLois Curfman McInnes clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 2685e42470aSBarry Smith #else 269ea4d3ed3SLois Curfman McInnes ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 2705e42470aSBarry Smith #endif 27178b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 272cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 2735e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 274393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 275ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda); 276d93a2b8dSBarry Smith goto theend; 2775e76c431SBarry Smith } 2785e76c431SBarry Smith 2795e76c431SBarry Smith /* Fit points with cubic */ 2805e76c431SBarry Smith count = 1; 2815e76c431SBarry Smith while (1) { 2825e76c431SBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 28394a424c1SBarry Smith PLogInfo(snes, 2844b828684SBarry Smith "SNESCubicLineSearch:Unable to find good step length! %d \n",count); 28594a424c1SBarry Smith PLogInfo(snes, 286ea4d3ed3SLois Curfman McInnes "SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 287ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 288393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 289761aaf1bSLois Curfman McInnes *flag = -1; break; 2905e76c431SBarry Smith } 2915e76c431SBarry Smith t1 = *gnorm - fnorm - lambda*initslope; 2925e76c431SBarry Smith t2 = gnormprev - fnorm - lambdaprev*initslope; 293ddd12767SBarry Smith a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2945e76c431SBarry Smith b = (-lambdaprev*t1/(lambda*lambda) + 2955e76c431SBarry Smith lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2965e76c431SBarry Smith d = b*b - 3*a*initslope; 2975e76c431SBarry Smith if (d < 0.0) d = 0.0; 2985e76c431SBarry Smith if (a == 0.0) { 2995e76c431SBarry Smith lambdatemp = -initslope/(2.0*b); 3005e76c431SBarry Smith } else { 3015e76c431SBarry Smith lambdatemp = (-b + sqrt(d))/(3.0*a); 3025e76c431SBarry Smith } 3035e76c431SBarry Smith if (lambdatemp > .5*lambda) { 3045e76c431SBarry Smith lambdatemp = .5*lambda; 3055e76c431SBarry Smith } 3065e76c431SBarry Smith lambdaprev = lambda; 3075e76c431SBarry Smith gnormprev = *gnorm; 3085e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 3095e76c431SBarry Smith lambda = .1*lambda; 3105e76c431SBarry Smith } 3115e76c431SBarry Smith else lambda = lambdatemp; 312393d2d9aSLois Curfman McInnes ierr = VecCopy( x, w ); CHKERRQ(ierr); 313ea4d3ed3SLois Curfman McInnes lambdaneg = -lambda; 3145e42470aSBarry Smith #if defined(PETSC_COMPLEX) 315ea4d3ed3SLois Curfman McInnes clambda = lambdaneg; 316393d2d9aSLois Curfman McInnes ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 3175e42470aSBarry Smith #else 318ea4d3ed3SLois Curfman McInnes ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 3195e42470aSBarry Smith #endif 32078b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 321cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 3225e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* is reduction enough */ 323393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 324ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda); 325761aaf1bSLois Curfman McInnes *flag = -1; break; 3265e76c431SBarry Smith } 3275e76c431SBarry Smith count++; 3285e76c431SBarry Smith } 329d93a2b8dSBarry Smith theend: 3307857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 3315e42470aSBarry Smith return 0; 3325e76c431SBarry Smith } 33352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 3345615d1e5SSatish Balay #undef __FUNC__ 3355615d1e5SSatish Balay #define __FUNC__ "SNESQuadraticLineSearch" 3364b828684SBarry Smith /*@C 337f525115eSLois Curfman McInnes SNESQuadraticLineSearch - Performs a quadratic line search. 3385e76c431SBarry Smith 3395e42470aSBarry Smith Input Parameters: 340f59ffdedSLois Curfman McInnes . snes - the SNES context 3415e42470aSBarry Smith . x - current iterate 3425e42470aSBarry Smith . f - residual evaluated at x 3435e42470aSBarry Smith . y - search direction (contains new iterate on output) 3445e42470aSBarry Smith . w - work vector 3455e42470aSBarry Smith . fnorm - 2-norm of f 3465e42470aSBarry Smith 347c4a48953SLois Curfman McInnes Output Parameters: 3485e42470aSBarry Smith . g - residual evaluated at new iterate y 3495e42470aSBarry Smith . y - new iterate (contains search direction on input) 3505e42470aSBarry Smith . gnorm - 2-norm of g 3515e42470aSBarry Smith . ynorm - 2-norm of search length 352761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 3535e42470aSBarry Smith 354c4a48953SLois Curfman McInnes Options Database Key: 35509d61ba7SLois Curfman McInnes $ -snes_eq_ls quadratic 356c4a48953SLois Curfman McInnes 3575e42470aSBarry Smith Notes: 35877c4ece6SBarry Smith Use SNESSetLineSearch() 359f63b844aSLois Curfman McInnes to set this routine within the SNES_EQ_LS method. 3605e42470aSBarry Smith 361f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search 362f59ffdedSLois Curfman McInnes 36377c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 3645e42470aSBarry Smith @*/ 3655e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 366761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag) 3675e76c431SBarry Smith { 368ddd12767SBarry Smith double steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp; 3696b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 3705e42470aSBarry Smith Scalar cinitslope,clambda; 3716b5873e3SBarry Smith #endif 3725e42470aSBarry Smith int ierr,count; 3735e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 3745334005bSBarry Smith Scalar mone = -1.0,scale; 3755e76c431SBarry Smith 3767857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 377761aaf1bSLois Curfman McInnes *flag = 0; 3785e42470aSBarry Smith alpha = neP->alpha; 3795e42470aSBarry Smith maxstep = neP->maxstep; 3805e42470aSBarry Smith steptol = neP->steptol; 3815e76c431SBarry Smith 382cddf8d76SBarry Smith VecNorm(y, NORM_2,ynorm ); 3835e42470aSBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 3845e42470aSBarry Smith scale = maxstep/(*ynorm); 385393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 3865e42470aSBarry Smith *ynorm = maxstep; 3875e76c431SBarry Smith } 3885e42470aSBarry Smith minlambda = steptol/(*ynorm); 389a703fe33SLois Curfman McInnes ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 3905e42470aSBarry Smith #if defined(PETSC_COMPLEX) 391a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 3925e42470aSBarry Smith initslope = real(cinitslope); 3935e42470aSBarry Smith #else 394a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 3955e42470aSBarry Smith #endif 3965e42470aSBarry Smith if (initslope > 0.0) initslope = -initslope; 3975e42470aSBarry Smith if (initslope == 0.0) initslope = -1.0; 3985e42470aSBarry Smith 399393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 4005334005bSBarry Smith ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 40178b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 402cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 4035e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 404393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 40594a424c1SBarry Smith PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n"); 406d93a2b8dSBarry Smith goto theend; 4075e42470aSBarry Smith } 4085e42470aSBarry Smith 4095e42470aSBarry Smith /* Fit points with quadratic */ 4105e42470aSBarry Smith lambda = 1.0; count = 0; 4115e42470aSBarry Smith count = 1; 4125e42470aSBarry Smith while (1) { 4135e42470aSBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 41494a424c1SBarry Smith PLogInfo(snes, 4154b828684SBarry Smith "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 41694a424c1SBarry Smith PLogInfo(snes, 417ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 418ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 419393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 420761aaf1bSLois Curfman McInnes *flag = -1; break; 4215e42470aSBarry Smith } 422a703fe33SLois Curfman McInnes lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 4235e42470aSBarry Smith lambdaprev = lambda; 4245e42470aSBarry Smith gnormprev = *gnorm; 4255e42470aSBarry Smith if (lambdatemp <= .1*lambda) { 4265e42470aSBarry Smith lambda = .1*lambda; 4275e42470aSBarry Smith } else lambda = lambdatemp; 428393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 4295334005bSBarry Smith lambda = -lambda; 4305e42470aSBarry Smith #if defined(PETSC_COMPLEX) 431393d2d9aSLois Curfman McInnes clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 4325e42470aSBarry Smith #else 433393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 4345e42470aSBarry Smith #endif 43578b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 436cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 4375e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 438393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 43994a424c1SBarry Smith PLogInfo(snes, 440ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda); 44106259719SBarry Smith break; 4425e42470aSBarry Smith } 4435e42470aSBarry Smith count++; 4445e42470aSBarry Smith } 445d93a2b8dSBarry Smith theend: 4467857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 4475e42470aSBarry Smith return 0; 4485e76c431SBarry Smith } 4495e76c431SBarry Smith /* ------------------------------------------------------------ */ 4505615d1e5SSatish Balay #undef __FUNC__ 4515615d1e5SSatish Balay #define __FUNC__ "SNESSetLineSearch" 452c9e6a524SLois Curfman McInnes /*@C 45377c4ece6SBarry Smith SNESSetLineSearch - Sets the line search routine to be used 454f63b844aSLois Curfman McInnes by the method SNES_EQ_LS. 4555e76c431SBarry Smith 4565e76c431SBarry Smith Input Parameters: 457eafb4bcbSBarry Smith . snes - nonlinear context obtained from SNESCreate() 4585e76c431SBarry Smith . func - pointer to int function 4595e76c431SBarry Smith 460c4a48953SLois Curfman McInnes Available Routines: 461f59ffdedSLois Curfman McInnes . SNESCubicLineSearch() - default line search 462f59ffdedSLois Curfman McInnes . SNESQuadraticLineSearch() - quadratic line search 463f59ffdedSLois Curfman McInnes . SNESNoLineSearch() - the full Newton step (actually not a line search) 4645e76c431SBarry Smith 465c4a48953SLois Curfman McInnes Options Database Keys: 46609d61ba7SLois Curfman McInnes $ -snes_eq_ls [basic,quadratic,cubic] 467c4a48953SLois Curfman McInnes 4685e76c431SBarry Smith Calling sequence of func: 469f59ffdedSLois Curfman McInnes func (SNES snes, Vec x, Vec f, Vec g, Vec y, 470761aaf1bSLois Curfman McInnes Vec w, double fnorm, double *ynorm, 471761aaf1bSLois Curfman McInnes double *gnorm, *flag) 4725e76c431SBarry Smith 4735e76c431SBarry Smith Input parameters for func: 4745e42470aSBarry Smith . snes - nonlinear context 4755e76c431SBarry Smith . x - current iterate 4765e76c431SBarry Smith . f - residual evaluated at x 4775e76c431SBarry Smith . y - search direction (contains new iterate on output) 4785e76c431SBarry Smith . w - work vector 4795e76c431SBarry Smith . fnorm - 2-norm of f 4805e76c431SBarry Smith 4815e76c431SBarry Smith Output parameters for func: 4825e76c431SBarry Smith . g - residual evaluated at new iterate y 4835e76c431SBarry Smith . y - new iterate (contains search direction on input) 4845e76c431SBarry Smith . gnorm - 2-norm of g 4855e76c431SBarry Smith . ynorm - 2-norm of search length 486761aaf1bSLois Curfman McInnes . flag - set to 0 if the line search succeeds; a nonzero integer 487761aaf1bSLois Curfman McInnes on failure. 488f59ffdedSLois Curfman McInnes 489f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine 490f59ffdedSLois Curfman McInnes 491f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch() 4925e76c431SBarry Smith @*/ 49377c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 494761aaf1bSLois Curfman McInnes double,double*,double*,int*)) 4955e76c431SBarry Smith { 496f63b844aSLois Curfman McInnes if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func; 4975e42470aSBarry Smith return 0; 4985e76c431SBarry Smith } 49952392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5005615d1e5SSatish Balay #undef __FUNC__ 5015615d1e5SSatish Balay #define __FUNC__ "SNESPrintHelp_EQ_LS" 502f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p) 5035e42470aSBarry Smith { 5045e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5056daaf66cSBarry Smith 506f63b844aSLois Curfman McInnes PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n"); 50709d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls [basic,quadratic,cubic]\n",p); 50809d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha); 50909d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep); 51009d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol); 5116b5873e3SBarry Smith return 0; 5125e42470aSBarry Smith } 51352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5145615d1e5SSatish Balay #undef __FUNC__ 5155615d1e5SSatish Balay #define __FUNC__ "SNESView_EQ_LS" 516f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer) 517a935fc98SLois Curfman McInnes { 518a935fc98SLois Curfman McInnes SNES snes = (SNES)obj; 519a935fc98SLois Curfman McInnes SNES_LS *ls = (SNES_LS *)snes->data; 520d636dbe3SBarry Smith FILE *fd; 52119bcc07fSBarry Smith char *cstr; 52251695f54SLois Curfman McInnes int ierr; 52319bcc07fSBarry Smith ViewerType vtype; 524a935fc98SLois Curfman McInnes 52519bcc07fSBarry Smith ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 52619bcc07fSBarry Smith if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 52790ace30eSBarry Smith ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 52819bcc07fSBarry Smith if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch"; 52919bcc07fSBarry Smith else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch"; 53019bcc07fSBarry Smith else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch"; 53119bcc07fSBarry Smith else cstr = "unknown"; 53277c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," line search variant: %s\n",cstr); 53377c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," alpha=%g, maxstep=%g, steptol=%g\n", 534a935fc98SLois Curfman McInnes ls->alpha,ls->maxstep,ls->steptol); 53519bcc07fSBarry Smith } 536a935fc98SLois Curfman McInnes return 0; 537a935fc98SLois Curfman McInnes } 53852392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5395615d1e5SSatish Balay #undef __FUNC__ 5405615d1e5SSatish Balay #define __FUNC__ "SNESSetFromOptions_EQ_LS" 541f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes) 5425e42470aSBarry Smith { 5435e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5445e42470aSBarry Smith char ver[16]; 5455e42470aSBarry Smith double tmp; 54625cdf11fSBarry Smith int ierr,flg; 5475e42470aSBarry Smith 54809d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr); 54925cdf11fSBarry Smith if (flg) { 5505e42470aSBarry Smith ls->alpha = tmp; 5515e42470aSBarry Smith } 55209d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr); 55325cdf11fSBarry Smith if (flg) { 5545e42470aSBarry Smith ls->maxstep = tmp; 5555e42470aSBarry Smith } 55609d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr); 55725cdf11fSBarry Smith if (flg) { 5585e42470aSBarry Smith ls->steptol = tmp; 5595e42470aSBarry Smith } 56009d61ba7SLois Curfman McInnes ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr); 56125cdf11fSBarry Smith if (flg) { 56248d91487SBarry Smith if (!PetscStrcmp(ver,"basic")) { 56377c4ece6SBarry Smith SNESSetLineSearch(snes,SNESNoLineSearch); 5645e42470aSBarry Smith } 56548d91487SBarry Smith else if (!PetscStrcmp(ver,"quadratic")) { 56677c4ece6SBarry Smith SNESSetLineSearch(snes,SNESQuadraticLineSearch); 5675e42470aSBarry Smith } 56848d91487SBarry Smith else if (!PetscStrcmp(ver,"cubic")) { 56977c4ece6SBarry Smith SNESSetLineSearch(snes,SNESCubicLineSearch); 5705e42470aSBarry Smith } 571e3372554SBarry Smith else {SETERRQ(1,0,"Unknown line search");} 5725e42470aSBarry Smith } 5735e42470aSBarry Smith return 0; 5745e42470aSBarry Smith } 5755e42470aSBarry Smith /* ------------------------------------------------------------ */ 5765615d1e5SSatish Balay #undef __FUNC__ 5775615d1e5SSatish Balay #define __FUNC__ "SNESCreate_EQ_LS" 578f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES snes ) 5795e42470aSBarry Smith { 5805e42470aSBarry Smith SNES_LS *neP; 5815e42470aSBarry Smith 582ddd12767SBarry Smith if (snes->method_class != SNES_NONLINEAR_EQUATIONS) 583e3372554SBarry Smith SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only"); 584f63b844aSLois Curfman McInnes snes->type = SNES_EQ_LS; 585f63b844aSLois Curfman McInnes snes->setup = SNESSetUp_EQ_LS; 586f63b844aSLois Curfman McInnes snes->solve = SNESSolve_EQ_LS; 587f63b844aSLois Curfman McInnes snes->destroy = SNESDestroy_EQ_LS; 588f63b844aSLois Curfman McInnes snes->converged = SNESConverged_EQ_LS; 589f63b844aSLois Curfman McInnes snes->printhelp = SNESPrintHelp_EQ_LS; 590f63b844aSLois Curfman McInnes snes->setfromoptions = SNESSetFromOptions_EQ_LS; 591f63b844aSLois Curfman McInnes snes->view = SNESView_EQ_LS; 5925baf8537SBarry Smith snes->nwork = 0; 5935e42470aSBarry Smith 5940452661fSBarry Smith neP = PetscNew(SNES_LS); CHKPTRQ(neP); 595ff782a9fSLois Curfman McInnes PLogObjectMemory(snes,sizeof(SNES_LS)); 5965e42470aSBarry Smith snes->data = (void *) neP; 5975e42470aSBarry Smith neP->alpha = 1.e-4; 5985e42470aSBarry Smith neP->maxstep = 1.e8; 5995e42470aSBarry Smith neP->steptol = 1.e-12; 6005e42470aSBarry Smith neP->LineSearch = SNESCubicLineSearch; 6015e42470aSBarry Smith return 0; 6025e42470aSBarry Smith } 6035e42470aSBarry Smith 604