15e76c431SBarry Smith #ifndef lint 2*ea4d3ed3SLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.72 1996/09/17 20:04:51 curfman Exp $"; 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 27f63b844aSLois Curfman McInnes int SNESSolve_EQ_LS(SNES snes,int *outits) 285e76c431SBarry Smith { 295e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 30761aaf1bSLois Curfman McInnes int maxits, i, history_len, ierr, lits, lsfail; 31112a2221SBarry Smith MatStructure flg = DIFFERENT_NONZERO_PATTERN; 326b5873e3SBarry Smith double fnorm, gnorm, xnorm, ynorm, *history; 335e42470aSBarry Smith Vec Y, X, F, G, W, TMP; 345e76c431SBarry Smith 355e42470aSBarry Smith history = snes->conv_hist; /* convergence history */ 365e42470aSBarry Smith history_len = snes->conv_hist_len; /* convergence history length */ 375e42470aSBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 385e42470aSBarry Smith X = snes->vec_sol; /* solution vector */ 3939e2f89bSBarry Smith F = snes->vec_func; /* residual vector */ 405e42470aSBarry Smith Y = snes->work[0]; /* work vectors */ 415e42470aSBarry Smith G = snes->work[1]; 425e42470aSBarry Smith W = snes->work[2]; 435e76c431SBarry Smith 44cddf8d76SBarry Smith ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 4525ed9cd1SBarry Smith snes->iter = 0; 465334005bSBarry Smith ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* F(X) */ 47cddf8d76SBarry Smith ierr = VecNorm(F,NORM_2,&fnorm); CHKERRQ(ierr); /* fnorm <- ||F|| */ 485e42470aSBarry Smith snes->norm = fnorm; 495e76c431SBarry Smith if (history && history_len > 0) history[0] = fnorm; 5094a424c1SBarry Smith SNESMonitor(snes,0,fnorm); 515e76c431SBarry Smith 52d034289bSBarry Smith /* set parameter for default relative tolerance convergence test */ 53d034289bSBarry Smith snes->ttol = fnorm*snes->rtol; 54d034289bSBarry Smith 555e76c431SBarry Smith for ( i=0; i<maxits; i++ ) { 565e42470aSBarry Smith snes->iter = i+1; 575e76c431SBarry Smith 58*ea4d3ed3SLois Curfman McInnes /* Solve J Y = F, where J is Jacobian matrix */ 595334005bSBarry Smith ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg); CHKERRQ(ierr); 605334005bSBarry Smith ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr); 6178b31e54SBarry Smith ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr); 62*ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNES: iter=%d, linear solve iterations=%d\n",snes->iter,lits); 63*ea4d3ed3SLois Curfman McInnes 64*ea4d3ed3SLois Curfman McInnes /* Compute a (scaled) negative update in the line search routine: 65*ea4d3ed3SLois Curfman McInnes Y <- X - lambda*Y 66*ea4d3ed3SLois Curfman McInnes and evaluate G(Y) = function(Y)) 67*ea4d3ed3SLois Curfman McInnes */ 6881b6cf68SLois Curfman McInnes ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr); 69ddd12767SBarry Smith ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); CHKERRQ(ierr); 70*ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNES: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail); 71761aaf1bSLois Curfman McInnes if (lsfail) snes->nfailures++; 725e76c431SBarry Smith 7339e2f89bSBarry Smith TMP = F; F = G; snes->vec_func_always = F; G = TMP; 7439e2f89bSBarry Smith TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 755e76c431SBarry Smith fnorm = gnorm; 765e76c431SBarry Smith 775e42470aSBarry Smith snes->norm = fnorm; 785e76c431SBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 79cddf8d76SBarry Smith ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 8094a424c1SBarry Smith SNESMonitor(snes,i+1,fnorm); 815e76c431SBarry Smith 825e76c431SBarry Smith /* Test for convergence */ 83bbb6d6a8SBarry Smith if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) { 8439e2f89bSBarry Smith if (X != snes->vec_sol) { 85393d2d9aSLois Curfman McInnes ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr); 8639e2f89bSBarry Smith snes->vec_sol_always = snes->vec_sol; 8739e2f89bSBarry Smith snes->vec_func_always = snes->vec_func; 8839e2f89bSBarry Smith } 895e76c431SBarry Smith break; 905e76c431SBarry Smith } 915e76c431SBarry Smith } 9252392280SLois Curfman McInnes if (i == maxits) { 9394a424c1SBarry Smith PLogInfo(snes, 94f63b844aSLois Curfman McInnes "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits); 9552392280SLois Curfman McInnes i--; 9652392280SLois Curfman McInnes } 975e42470aSBarry Smith *outits = i+1; 985e42470aSBarry Smith return 0; 995e76c431SBarry Smith } 1005e76c431SBarry Smith /* ------------------------------------------------------------ */ 101f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes ) 1025e76c431SBarry Smith { 1035e42470aSBarry Smith int ierr; 10481b6cf68SLois Curfman McInnes snes->nwork = 4; 105d7e8b826SBarry Smith ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr); 1065e42470aSBarry Smith PLogObjectParents(snes,snes->nwork,snes->work); 10781b6cf68SLois Curfman McInnes snes->vec_sol_update_always = snes->work[3]; 1085e42470aSBarry Smith return 0; 1095e76c431SBarry Smith } 1105e76c431SBarry Smith /* ------------------------------------------------------------ */ 111f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj) 1125e76c431SBarry Smith { 1135e42470aSBarry Smith SNES snes = (SNES) obj; 114393d2d9aSLois Curfman McInnes int ierr; 1155baf8537SBarry Smith if (snes->nwork) { 1164b0e389bSBarry Smith ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr); 11721c89e3eSBarry Smith } 1180452661fSBarry Smith PetscFree(snes->data); 1195e42470aSBarry Smith return 0; 1205e76c431SBarry Smith } 1215e76c431SBarry Smith /* ------------------------------------------------------------ */ 1225e76c431SBarry Smith /*ARGSUSED*/ 1234b828684SBarry Smith /*@C 1245e42470aSBarry Smith SNESNoLineSearch - This routine is not a line search at all; 1255e76c431SBarry Smith it simply uses the full Newton step. Thus, this routine is intended 1265e76c431SBarry Smith to serve as a template and is not recommended for general use. 1275e76c431SBarry Smith 1285e76c431SBarry Smith Input Parameters: 1295e42470aSBarry Smith . snes - nonlinear context 1305e76c431SBarry Smith . x - current iterate 1315e76c431SBarry Smith . f - residual evaluated at x 1325e76c431SBarry Smith . y - search direction (contains new iterate on output) 1335e76c431SBarry Smith . w - work vector 1345e76c431SBarry Smith . fnorm - 2-norm of f 1355e76c431SBarry Smith 136c4a48953SLois Curfman McInnes Output Parameters: 1375e76c431SBarry Smith . g - residual evaluated at new iterate y 1385e76c431SBarry Smith . y - new iterate (contains search direction on input) 1395e76c431SBarry Smith . gnorm - 2-norm of g 1405e76c431SBarry Smith . ynorm - 2-norm of search length 141761aaf1bSLois Curfman McInnes . flag - set to 0, indicating a successful line search 1425e76c431SBarry Smith 143c4a48953SLois Curfman McInnes Options Database Key: 144c4a48953SLois Curfman McInnes $ -snes_line_search basic 145c4a48953SLois Curfman McInnes 14628ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 14728ae5a21SLois Curfman McInnes 148f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 14977c4ece6SBarry Smith SNESSetLineSearch() 1505e76c431SBarry Smith @*/ 1515e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 152761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag ) 1535e76c431SBarry Smith { 1545e42470aSBarry Smith int ierr; 1555334005bSBarry Smith Scalar mone = -1.0; 1565334005bSBarry Smith 157761aaf1bSLois Curfman McInnes *flag = 0; 1587857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 159cddf8d76SBarry Smith ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr); /* ynorm = || y || */ 160*ea4d3ed3SLois Curfman McInnes ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr); /* y <- y - x */ 161*ea4d3ed3SLois Curfman McInnes ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y) */ 162cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); /* gnorm = || g || */ 1637857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 164761aaf1bSLois Curfman McInnes return 0; 1655e76c431SBarry Smith } 1665e76c431SBarry Smith /* ------------------------------------------------------------------ */ 1674b828684SBarry Smith /*@C 168f59ffdedSLois Curfman McInnes SNESCubicLineSearch - This routine performs a cubic line search and 169f59ffdedSLois Curfman McInnes is the default line search method. 1705e76c431SBarry Smith 1715e76c431SBarry Smith Input Parameters: 1725e42470aSBarry Smith . snes - nonlinear context 1735e76c431SBarry Smith . x - current iterate 1745e76c431SBarry Smith . f - residual evaluated at x 1755e76c431SBarry Smith . y - search direction (contains new iterate on output) 1765e76c431SBarry Smith . w - work vector 1775e76c431SBarry Smith . fnorm - 2-norm of f 1785e76c431SBarry Smith 179393d2d9aSLois Curfman McInnes Output Parameters: 1805e76c431SBarry Smith . g - residual evaluated at new iterate y 1815e76c431SBarry Smith . y - new iterate (contains search direction on input) 1825e76c431SBarry Smith . gnorm - 2-norm of g 1835e76c431SBarry Smith . ynorm - 2-norm of search length 184761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 1855e76c431SBarry Smith 186c4a48953SLois Curfman McInnes Options Database Key: 187c4a48953SLois Curfman McInnes $ -snes_line_search cubic 188c4a48953SLois Curfman McInnes 1895e76c431SBarry Smith Notes: 1905e76c431SBarry Smith This line search is taken from "Numerical Methods for Unconstrained 1915e76c431SBarry Smith Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 1925e76c431SBarry Smith 19328ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 19428ae5a21SLois Curfman McInnes 19577c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 1965e76c431SBarry Smith @*/ 1975e42470aSBarry Smith int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w, 198761aaf1bSLois Curfman McInnes double fnorm,double *ynorm,double *gnorm,int *flag) 1995e76c431SBarry Smith { 200ddd12767SBarry Smith double steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2; 201*ea4d3ed3SLois Curfman McInnes double maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg; 2026b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 2035e42470aSBarry Smith Scalar cinitslope, clambda; 2046b5873e3SBarry Smith #endif 2055e42470aSBarry Smith int ierr, count; 2065e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 2075334005bSBarry Smith Scalar mone = -1.0,scale; 2085e76c431SBarry Smith 2097857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 210761aaf1bSLois Curfman McInnes *flag = 0; 2115e76c431SBarry Smith alpha = neP->alpha; 2125e76c431SBarry Smith maxstep = neP->maxstep; 2135e76c431SBarry Smith steptol = neP->steptol; 2145e76c431SBarry Smith 215cddf8d76SBarry Smith ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr); 2165e76c431SBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 2175e42470aSBarry Smith scale = maxstep/(*ynorm); 2186b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 21994a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale)); 2206b5873e3SBarry Smith #else 22194a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale); 2226b5873e3SBarry Smith #endif 223393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 2245e76c431SBarry Smith *ynorm = maxstep; 2255e76c431SBarry Smith } 2265e76c431SBarry Smith minlambda = steptol/(*ynorm); 227a703fe33SLois Curfman McInnes ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 2285e42470aSBarry Smith #if defined(PETSC_COMPLEX) 229a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 2305e42470aSBarry Smith initslope = real(cinitslope); 2315e42470aSBarry Smith #else 232a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 2335e42470aSBarry Smith #endif 2345e76c431SBarry Smith if (initslope > 0.0) initslope = -initslope; 2355e76c431SBarry Smith if (initslope == 0.0) initslope = -1.0; 2365e76c431SBarry Smith 237393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 2385334005bSBarry Smith ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 23978b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 240cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); 2415e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 242393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 24394a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Using full step\n"); 244d93a2b8dSBarry Smith goto theend; 2455e76c431SBarry Smith } 2465e76c431SBarry Smith 2475e76c431SBarry Smith /* Fit points with quadratic */ 2485e76c431SBarry Smith lambda = 1.0; count = 0; 249a703fe33SLois Curfman McInnes lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 2505e76c431SBarry Smith lambdaprev = lambda; 2515e76c431SBarry Smith gnormprev = *gnorm; 252ddd12767SBarry Smith if (lambdatemp <= .1*lambda) lambda = .1*lambda; 253ddd12767SBarry Smith else lambda = lambdatemp; 254393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 255*ea4d3ed3SLois Curfman McInnes lambdaneg = -lambda; 2565e42470aSBarry Smith #if defined(PETSC_COMPLEX) 257*ea4d3ed3SLois Curfman McInnes clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 2585e42470aSBarry Smith #else 259*ea4d3ed3SLois Curfman McInnes ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 2605e42470aSBarry Smith #endif 26178b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 262cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 2635e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 264393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 265*ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda); 266d93a2b8dSBarry Smith goto theend; 2675e76c431SBarry Smith } 2685e76c431SBarry Smith 2695e76c431SBarry Smith /* Fit points with cubic */ 2705e76c431SBarry Smith count = 1; 2715e76c431SBarry Smith while (1) { 2725e76c431SBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 27394a424c1SBarry Smith PLogInfo(snes, 2744b828684SBarry Smith "SNESCubicLineSearch:Unable to find good step length! %d \n",count); 27594a424c1SBarry Smith PLogInfo(snes, 276*ea4d3ed3SLois Curfman McInnes "SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 277*ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 278393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 279761aaf1bSLois Curfman McInnes *flag = -1; break; 2805e76c431SBarry Smith } 2815e76c431SBarry Smith t1 = *gnorm - fnorm - lambda*initslope; 2825e76c431SBarry Smith t2 = gnormprev - fnorm - lambdaprev*initslope; 283ddd12767SBarry Smith a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2845e76c431SBarry Smith b = (-lambdaprev*t1/(lambda*lambda) + 2855e76c431SBarry Smith lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2865e76c431SBarry Smith d = b*b - 3*a*initslope; 2875e76c431SBarry Smith if (d < 0.0) d = 0.0; 2885e76c431SBarry Smith if (a == 0.0) { 2895e76c431SBarry Smith lambdatemp = -initslope/(2.0*b); 2905e76c431SBarry Smith } else { 2915e76c431SBarry Smith lambdatemp = (-b + sqrt(d))/(3.0*a); 2925e76c431SBarry Smith } 2935e76c431SBarry Smith if (lambdatemp > .5*lambda) { 2945e76c431SBarry Smith lambdatemp = .5*lambda; 2955e76c431SBarry Smith } 2965e76c431SBarry Smith lambdaprev = lambda; 2975e76c431SBarry Smith gnormprev = *gnorm; 2985e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 2995e76c431SBarry Smith lambda = .1*lambda; 3005e76c431SBarry Smith } 3015e76c431SBarry Smith else lambda = lambdatemp; 302393d2d9aSLois Curfman McInnes ierr = VecCopy( x, w ); CHKERRQ(ierr); 303*ea4d3ed3SLois Curfman McInnes lambdaneg = -lambda; 3045e42470aSBarry Smith #if defined(PETSC_COMPLEX) 305*ea4d3ed3SLois Curfman McInnes clambda = lambdaneg; 306393d2d9aSLois Curfman McInnes ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 3075e42470aSBarry Smith #else 308*ea4d3ed3SLois Curfman McInnes ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 3095e42470aSBarry Smith #endif 31078b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 311cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 3125e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* is reduction enough */ 313393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 314*ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda); 315761aaf1bSLois Curfman McInnes *flag = -1; break; 3165e76c431SBarry Smith } 3175e76c431SBarry Smith count++; 3185e76c431SBarry Smith } 319d93a2b8dSBarry Smith theend: 3207857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 3215e42470aSBarry Smith return 0; 3225e76c431SBarry Smith } 32352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 3244b828684SBarry Smith /*@C 3255e42470aSBarry Smith SNESQuadraticLineSearch - This routine performs a cubic line search. 3265e76c431SBarry Smith 3275e42470aSBarry Smith Input Parameters: 328f59ffdedSLois Curfman McInnes . snes - the SNES context 3295e42470aSBarry Smith . x - current iterate 3305e42470aSBarry Smith . f - residual evaluated at x 3315e42470aSBarry Smith . y - search direction (contains new iterate on output) 3325e42470aSBarry Smith . w - work vector 3335e42470aSBarry Smith . fnorm - 2-norm of f 3345e42470aSBarry Smith 335c4a48953SLois Curfman McInnes Output Parameters: 3365e42470aSBarry Smith . g - residual evaluated at new iterate y 3375e42470aSBarry Smith . y - new iterate (contains search direction on input) 3385e42470aSBarry Smith . gnorm - 2-norm of g 3395e42470aSBarry Smith . ynorm - 2-norm of search length 340761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 3415e42470aSBarry Smith 342c4a48953SLois Curfman McInnes Options Database Key: 343c4a48953SLois Curfman McInnes $ -snes_line_search quadratic 344c4a48953SLois Curfman McInnes 3455e42470aSBarry Smith Notes: 34677c4ece6SBarry Smith Use SNESSetLineSearch() 347f63b844aSLois Curfman McInnes to set this routine within the SNES_EQ_LS method. 3485e42470aSBarry Smith 349f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search 350f59ffdedSLois Curfman McInnes 35177c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 3525e42470aSBarry Smith @*/ 3535e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 354761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag) 3555e76c431SBarry Smith { 356ddd12767SBarry Smith double steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp; 3576b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 3585e42470aSBarry Smith Scalar cinitslope,clambda; 3596b5873e3SBarry Smith #endif 3605e42470aSBarry Smith int ierr,count; 3615e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 3625334005bSBarry Smith Scalar mone = -1.0,scale; 3635e76c431SBarry Smith 3647857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 365761aaf1bSLois Curfman McInnes *flag = 0; 3665e42470aSBarry Smith alpha = neP->alpha; 3675e42470aSBarry Smith maxstep = neP->maxstep; 3685e42470aSBarry Smith steptol = neP->steptol; 3695e76c431SBarry Smith 370cddf8d76SBarry Smith VecNorm(y, NORM_2,ynorm ); 3715e42470aSBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 3725e42470aSBarry Smith scale = maxstep/(*ynorm); 373393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 3745e42470aSBarry Smith *ynorm = maxstep; 3755e76c431SBarry Smith } 3765e42470aSBarry Smith minlambda = steptol/(*ynorm); 377a703fe33SLois Curfman McInnes ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 3785e42470aSBarry Smith #if defined(PETSC_COMPLEX) 379a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 3805e42470aSBarry Smith initslope = real(cinitslope); 3815e42470aSBarry Smith #else 382a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 3835e42470aSBarry Smith #endif 3845e42470aSBarry Smith if (initslope > 0.0) initslope = -initslope; 3855e42470aSBarry Smith if (initslope == 0.0) initslope = -1.0; 3865e42470aSBarry Smith 387393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 3885334005bSBarry Smith ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 38978b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 390cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 3915e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 392393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 39394a424c1SBarry Smith PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n"); 394d93a2b8dSBarry Smith goto theend; 3955e42470aSBarry Smith } 3965e42470aSBarry Smith 3975e42470aSBarry Smith /* Fit points with quadratic */ 3985e42470aSBarry Smith lambda = 1.0; count = 0; 3995e42470aSBarry Smith count = 1; 4005e42470aSBarry Smith while (1) { 4015e42470aSBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 40294a424c1SBarry Smith PLogInfo(snes, 4034b828684SBarry Smith "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 40494a424c1SBarry Smith PLogInfo(snes, 405*ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 406*ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 407393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 408761aaf1bSLois Curfman McInnes *flag = -1; break; 4095e42470aSBarry Smith } 410a703fe33SLois Curfman McInnes lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 4115e42470aSBarry Smith lambdaprev = lambda; 4125e42470aSBarry Smith gnormprev = *gnorm; 4135e42470aSBarry Smith if (lambdatemp <= .1*lambda) { 4145e42470aSBarry Smith lambda = .1*lambda; 4155e42470aSBarry Smith } else lambda = lambdatemp; 416393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 4175334005bSBarry Smith lambda = -lambda; 4185e42470aSBarry Smith #if defined(PETSC_COMPLEX) 419393d2d9aSLois Curfman McInnes clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 4205e42470aSBarry Smith #else 421393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 4225e42470aSBarry Smith #endif 42378b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 424cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 4255e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 426393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 42794a424c1SBarry Smith PLogInfo(snes, 428*ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda); 42906259719SBarry Smith break; 4305e42470aSBarry Smith } 4315e42470aSBarry Smith count++; 4325e42470aSBarry Smith } 433d93a2b8dSBarry Smith theend: 4347857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 4355e42470aSBarry Smith return 0; 4365e76c431SBarry Smith } 4375e76c431SBarry Smith /* ------------------------------------------------------------ */ 438c9e6a524SLois Curfman McInnes /*@C 43977c4ece6SBarry Smith SNESSetLineSearch - Sets the line search routine to be used 440f63b844aSLois Curfman McInnes by the method SNES_EQ_LS. 4415e76c431SBarry Smith 4425e76c431SBarry Smith Input Parameters: 443eafb4bcbSBarry Smith . snes - nonlinear context obtained from SNESCreate() 4445e76c431SBarry Smith . func - pointer to int function 4455e76c431SBarry Smith 446c4a48953SLois Curfman McInnes Available Routines: 447f59ffdedSLois Curfman McInnes . SNESCubicLineSearch() - default line search 448f59ffdedSLois Curfman McInnes . SNESQuadraticLineSearch() - quadratic line search 449f59ffdedSLois Curfman McInnes . SNESNoLineSearch() - the full Newton step (actually not a line search) 4505e76c431SBarry Smith 451c4a48953SLois Curfman McInnes Options Database Keys: 452c4a48953SLois Curfman McInnes $ -snes_line_search [basic,quadratic,cubic] 453c4a48953SLois Curfman McInnes 4545e76c431SBarry Smith Calling sequence of func: 455f59ffdedSLois Curfman McInnes func (SNES snes, Vec x, Vec f, Vec g, Vec y, 456761aaf1bSLois Curfman McInnes Vec w, double fnorm, double *ynorm, 457761aaf1bSLois Curfman McInnes double *gnorm, *flag) 4585e76c431SBarry Smith 4595e76c431SBarry Smith Input parameters for func: 4605e42470aSBarry Smith . snes - nonlinear context 4615e76c431SBarry Smith . x - current iterate 4625e76c431SBarry Smith . f - residual evaluated at x 4635e76c431SBarry Smith . y - search direction (contains new iterate on output) 4645e76c431SBarry Smith . w - work vector 4655e76c431SBarry Smith . fnorm - 2-norm of f 4665e76c431SBarry Smith 4675e76c431SBarry Smith Output parameters for func: 4685e76c431SBarry Smith . g - residual evaluated at new iterate y 4695e76c431SBarry Smith . y - new iterate (contains search direction on input) 4705e76c431SBarry Smith . gnorm - 2-norm of g 4715e76c431SBarry Smith . ynorm - 2-norm of search length 472761aaf1bSLois Curfman McInnes . flag - set to 0 if the line search succeeds; a nonzero integer 473761aaf1bSLois Curfman McInnes on failure. 474f59ffdedSLois Curfman McInnes 475f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine 476f59ffdedSLois Curfman McInnes 477f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch() 4785e76c431SBarry Smith @*/ 47977c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 480761aaf1bSLois Curfman McInnes double,double*,double*,int*)) 4815e76c431SBarry Smith { 482f63b844aSLois Curfman McInnes if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func; 4835e42470aSBarry Smith return 0; 4845e76c431SBarry Smith } 48552392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 486f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p) 4875e42470aSBarry Smith { 4885e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 4896daaf66cSBarry Smith 490f63b844aSLois Curfman McInnes PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n"); 49177c4ece6SBarry Smith PetscPrintf(snes->comm," %ssnes_line_search [basic,quadratic,cubic]\n",p); 4929aca352dSLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_line_search_alpha <alpha> (default %g)\n",p,ls->alpha); 4939aca352dSLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_line_search_maxstep <max> (default %g)\n",p,ls->maxstep); 4949aca352dSLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_line_search_steptol <tol> (default %g)\n",p,ls->steptol); 4956b5873e3SBarry Smith return 0; 4965e42470aSBarry Smith } 49752392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 498f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer) 499a935fc98SLois Curfman McInnes { 500a935fc98SLois Curfman McInnes SNES snes = (SNES)obj; 501a935fc98SLois Curfman McInnes SNES_LS *ls = (SNES_LS *)snes->data; 502d636dbe3SBarry Smith FILE *fd; 50319bcc07fSBarry Smith char *cstr; 50451695f54SLois Curfman McInnes int ierr; 50519bcc07fSBarry Smith ViewerType vtype; 506a935fc98SLois Curfman McInnes 50719bcc07fSBarry Smith ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 50819bcc07fSBarry Smith if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 50990ace30eSBarry Smith ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 51019bcc07fSBarry Smith if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch"; 51119bcc07fSBarry Smith else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch"; 51219bcc07fSBarry Smith else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch"; 51319bcc07fSBarry Smith else cstr = "unknown"; 51477c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," line search variant: %s\n",cstr); 51577c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," alpha=%g, maxstep=%g, steptol=%g\n", 516a935fc98SLois Curfman McInnes ls->alpha,ls->maxstep,ls->steptol); 51719bcc07fSBarry Smith } 518a935fc98SLois Curfman McInnes return 0; 519a935fc98SLois Curfman McInnes } 52052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 521f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes) 5225e42470aSBarry Smith { 5235e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5245e42470aSBarry Smith char ver[16]; 5255e42470aSBarry Smith double tmp; 52625cdf11fSBarry Smith int ierr,flg; 5275e42470aSBarry Smith 528fb262c43SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_alpha",&tmp, &flg);CHKERRQ(ierr); 52925cdf11fSBarry Smith if (flg) { 5305e42470aSBarry Smith ls->alpha = tmp; 5315e42470aSBarry Smith } 532ee8b94d1SSatish Balay ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp, &flg);CHKERRQ(ierr); 53325cdf11fSBarry Smith if (flg) { 5345e42470aSBarry Smith ls->maxstep = tmp; 5355e42470aSBarry Smith } 536ee8b94d1SSatish Balay ierr = OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp, &flg);CHKERRQ(ierr); 53725cdf11fSBarry Smith if (flg) { 5385e42470aSBarry Smith ls->steptol = tmp; 5395e42470aSBarry Smith } 540ee8b94d1SSatish Balay ierr = OptionsGetString(snes->prefix,"-snes_line_search",ver,16, &flg); CHKERRQ(ierr); 54125cdf11fSBarry Smith if (flg) { 54248d91487SBarry Smith if (!PetscStrcmp(ver,"basic")) { 54377c4ece6SBarry Smith SNESSetLineSearch(snes,SNESNoLineSearch); 5445e42470aSBarry Smith } 54548d91487SBarry Smith else if (!PetscStrcmp(ver,"quadratic")) { 54677c4ece6SBarry Smith SNESSetLineSearch(snes,SNESQuadraticLineSearch); 5475e42470aSBarry Smith } 54848d91487SBarry Smith else if (!PetscStrcmp(ver,"cubic")) { 54977c4ece6SBarry Smith SNESSetLineSearch(snes,SNESCubicLineSearch); 5505e42470aSBarry Smith } 551f63b844aSLois Curfman McInnes else {SETERRQ(1,"SNESSetFromOptions_EQ_LS:Unknown line search");} 5525e42470aSBarry Smith } 5535e42470aSBarry Smith return 0; 5545e42470aSBarry Smith } 5555e42470aSBarry Smith /* ------------------------------------------------------------ */ 556f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES snes ) 5575e42470aSBarry Smith { 5585e42470aSBarry Smith SNES_LS *neP; 5595e42470aSBarry Smith 560ddd12767SBarry Smith if (snes->method_class != SNES_NONLINEAR_EQUATIONS) 561f63b844aSLois Curfman McInnes SETERRQ(1,"SNESCreate_EQ_LS:For SNES_NONLINEAR_EQUATIONS only"); 562f63b844aSLois Curfman McInnes snes->type = SNES_EQ_LS; 563f63b844aSLois Curfman McInnes snes->setup = SNESSetUp_EQ_LS; 564f63b844aSLois Curfman McInnes snes->solve = SNESSolve_EQ_LS; 565f63b844aSLois Curfman McInnes snes->destroy = SNESDestroy_EQ_LS; 566f63b844aSLois Curfman McInnes snes->converged = SNESConverged_EQ_LS; 567f63b844aSLois Curfman McInnes snes->printhelp = SNESPrintHelp_EQ_LS; 568f63b844aSLois Curfman McInnes snes->setfromoptions = SNESSetFromOptions_EQ_LS; 569f63b844aSLois Curfman McInnes snes->view = SNESView_EQ_LS; 5705baf8537SBarry Smith snes->nwork = 0; 5715e42470aSBarry Smith 5720452661fSBarry Smith neP = PetscNew(SNES_LS); CHKPTRQ(neP); 573ff782a9fSLois Curfman McInnes PLogObjectMemory(snes,sizeof(SNES_LS)); 5745e42470aSBarry Smith snes->data = (void *) neP; 5755e42470aSBarry Smith neP->alpha = 1.e-4; 5765e42470aSBarry Smith neP->maxstep = 1.e8; 5775e42470aSBarry Smith neP->steptol = 1.e-12; 5785e42470aSBarry Smith neP->LineSearch = SNESCubicLineSearch; 5795e42470aSBarry Smith return 0; 5805e42470aSBarry Smith } 5815e42470aSBarry Smith 5825e42470aSBarry Smith 5835e42470aSBarry Smith 5845e42470aSBarry Smith 585