15e76c431SBarry Smith #ifndef lint 2*09d61ba7SLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.74 1996/09/28 16:24:44 curfman Exp curfman $"; 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 58ea4d3ed3SLois 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); 62ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNES: iter=%d, linear solve iterations=%d\n",snes->iter,lits); 63ea4d3ed3SLois Curfman McInnes 64ea4d3ed3SLois Curfman McInnes /* Compute a (scaled) negative update in the line search routine: 65ea4d3ed3SLois Curfman McInnes Y <- X - lambda*Y 66ea4d3ed3SLois Curfman McInnes and evaluate G(Y) = function(Y)) 67ea4d3ed3SLois 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); 70ea4d3ed3SLois 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: 144*09d61ba7SLois Curfman McInnes $ -snes_eq_ls 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 || */ 160ea4d3ed3SLois Curfman McInnes ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr); /* y <- y - x */ 161ea4d3ed3SLois 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 168f525115eSLois Curfman McInnes SNESCubicLineSearch - Performs a cubic line search (default line search method). 1695e76c431SBarry Smith 1705e76c431SBarry Smith Input Parameters: 1715e42470aSBarry Smith . snes - nonlinear context 1725e76c431SBarry Smith . x - current iterate 1735e76c431SBarry Smith . f - residual evaluated at x 1745e76c431SBarry Smith . y - search direction (contains new iterate on output) 1755e76c431SBarry Smith . w - work vector 1765e76c431SBarry Smith . fnorm - 2-norm of f 1775e76c431SBarry Smith 178393d2d9aSLois Curfman McInnes Output Parameters: 1795e76c431SBarry Smith . g - residual evaluated at new iterate y 1805e76c431SBarry Smith . y - new iterate (contains search direction on input) 1815e76c431SBarry Smith . gnorm - 2-norm of g 1825e76c431SBarry Smith . ynorm - 2-norm of search length 183761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 1845e76c431SBarry Smith 185c4a48953SLois Curfman McInnes Options Database Key: 186*09d61ba7SLois Curfman McInnes $ -snes_eq_ls cubic 187c4a48953SLois Curfman McInnes 1885e76c431SBarry Smith Notes: 1895e76c431SBarry Smith This line search is taken from "Numerical Methods for Unconstrained 1905e76c431SBarry Smith Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 1915e76c431SBarry Smith 19228ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 19328ae5a21SLois Curfman McInnes 19477c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 1955e76c431SBarry Smith @*/ 1965e42470aSBarry Smith int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w, 197761aaf1bSLois Curfman McInnes double fnorm,double *ynorm,double *gnorm,int *flag) 1985e76c431SBarry Smith { 199ddd12767SBarry Smith double steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2; 200ea4d3ed3SLois Curfman McInnes double maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg; 2016b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 2025e42470aSBarry Smith Scalar cinitslope, clambda; 2036b5873e3SBarry Smith #endif 2045e42470aSBarry Smith int ierr, count; 2055e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 2065334005bSBarry Smith Scalar mone = -1.0,scale; 2075e76c431SBarry Smith 2087857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 209761aaf1bSLois Curfman McInnes *flag = 0; 2105e76c431SBarry Smith alpha = neP->alpha; 2115e76c431SBarry Smith maxstep = neP->maxstep; 2125e76c431SBarry Smith steptol = neP->steptol; 2135e76c431SBarry Smith 214cddf8d76SBarry Smith ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr); 2155e76c431SBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 2165e42470aSBarry Smith scale = maxstep/(*ynorm); 2176b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 21894a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale)); 2196b5873e3SBarry Smith #else 22094a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale); 2216b5873e3SBarry Smith #endif 222393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 2235e76c431SBarry Smith *ynorm = maxstep; 2245e76c431SBarry Smith } 2255e76c431SBarry Smith minlambda = steptol/(*ynorm); 226a703fe33SLois Curfman McInnes ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 2275e42470aSBarry Smith #if defined(PETSC_COMPLEX) 228a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 2295e42470aSBarry Smith initslope = real(cinitslope); 2305e42470aSBarry Smith #else 231a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 2325e42470aSBarry Smith #endif 2335e76c431SBarry Smith if (initslope > 0.0) initslope = -initslope; 2345e76c431SBarry Smith if (initslope == 0.0) initslope = -1.0; 2355e76c431SBarry Smith 236393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 2375334005bSBarry Smith ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 23878b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 239cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); 2405e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 241393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 24294a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Using full step\n"); 243d93a2b8dSBarry Smith goto theend; 2445e76c431SBarry Smith } 2455e76c431SBarry Smith 2465e76c431SBarry Smith /* Fit points with quadratic */ 2475e76c431SBarry Smith lambda = 1.0; count = 0; 248a703fe33SLois Curfman McInnes lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 2495e76c431SBarry Smith lambdaprev = lambda; 2505e76c431SBarry Smith gnormprev = *gnorm; 251ddd12767SBarry Smith if (lambdatemp <= .1*lambda) lambda = .1*lambda; 252ddd12767SBarry Smith else lambda = lambdatemp; 253393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 254ea4d3ed3SLois Curfman McInnes lambdaneg = -lambda; 2555e42470aSBarry Smith #if defined(PETSC_COMPLEX) 256ea4d3ed3SLois Curfman McInnes clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 2575e42470aSBarry Smith #else 258ea4d3ed3SLois Curfman McInnes ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 2595e42470aSBarry Smith #endif 26078b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 261cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 2625e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 263393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 264ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda); 265d93a2b8dSBarry Smith goto theend; 2665e76c431SBarry Smith } 2675e76c431SBarry Smith 2685e76c431SBarry Smith /* Fit points with cubic */ 2695e76c431SBarry Smith count = 1; 2705e76c431SBarry Smith while (1) { 2715e76c431SBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 27294a424c1SBarry Smith PLogInfo(snes, 2734b828684SBarry Smith "SNESCubicLineSearch:Unable to find good step length! %d \n",count); 27494a424c1SBarry Smith PLogInfo(snes, 275ea4d3ed3SLois Curfman McInnes "SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 276ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 277393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 278761aaf1bSLois Curfman McInnes *flag = -1; break; 2795e76c431SBarry Smith } 2805e76c431SBarry Smith t1 = *gnorm - fnorm - lambda*initslope; 2815e76c431SBarry Smith t2 = gnormprev - fnorm - lambdaprev*initslope; 282ddd12767SBarry Smith a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2835e76c431SBarry Smith b = (-lambdaprev*t1/(lambda*lambda) + 2845e76c431SBarry Smith lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2855e76c431SBarry Smith d = b*b - 3*a*initslope; 2865e76c431SBarry Smith if (d < 0.0) d = 0.0; 2875e76c431SBarry Smith if (a == 0.0) { 2885e76c431SBarry Smith lambdatemp = -initslope/(2.0*b); 2895e76c431SBarry Smith } else { 2905e76c431SBarry Smith lambdatemp = (-b + sqrt(d))/(3.0*a); 2915e76c431SBarry Smith } 2925e76c431SBarry Smith if (lambdatemp > .5*lambda) { 2935e76c431SBarry Smith lambdatemp = .5*lambda; 2945e76c431SBarry Smith } 2955e76c431SBarry Smith lambdaprev = lambda; 2965e76c431SBarry Smith gnormprev = *gnorm; 2975e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 2985e76c431SBarry Smith lambda = .1*lambda; 2995e76c431SBarry Smith } 3005e76c431SBarry Smith else lambda = lambdatemp; 301393d2d9aSLois Curfman McInnes ierr = VecCopy( x, w ); CHKERRQ(ierr); 302ea4d3ed3SLois Curfman McInnes lambdaneg = -lambda; 3035e42470aSBarry Smith #if defined(PETSC_COMPLEX) 304ea4d3ed3SLois Curfman McInnes clambda = lambdaneg; 305393d2d9aSLois Curfman McInnes ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 3065e42470aSBarry Smith #else 307ea4d3ed3SLois Curfman McInnes ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 3085e42470aSBarry Smith #endif 30978b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 310cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 3115e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* is reduction enough */ 312393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 313ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda); 314761aaf1bSLois Curfman McInnes *flag = -1; break; 3155e76c431SBarry Smith } 3165e76c431SBarry Smith count++; 3175e76c431SBarry Smith } 318d93a2b8dSBarry Smith theend: 3197857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 3205e42470aSBarry Smith return 0; 3215e76c431SBarry Smith } 32252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 3234b828684SBarry Smith /*@C 324f525115eSLois Curfman McInnes SNESQuadraticLineSearch - Performs a quadratic line search. 3255e76c431SBarry Smith 3265e42470aSBarry Smith Input Parameters: 327f59ffdedSLois Curfman McInnes . snes - the SNES context 3285e42470aSBarry Smith . x - current iterate 3295e42470aSBarry Smith . f - residual evaluated at x 3305e42470aSBarry Smith . y - search direction (contains new iterate on output) 3315e42470aSBarry Smith . w - work vector 3325e42470aSBarry Smith . fnorm - 2-norm of f 3335e42470aSBarry Smith 334c4a48953SLois Curfman McInnes Output Parameters: 3355e42470aSBarry Smith . g - residual evaluated at new iterate y 3365e42470aSBarry Smith . y - new iterate (contains search direction on input) 3375e42470aSBarry Smith . gnorm - 2-norm of g 3385e42470aSBarry Smith . ynorm - 2-norm of search length 339761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 3405e42470aSBarry Smith 341c4a48953SLois Curfman McInnes Options Database Key: 342*09d61ba7SLois Curfman McInnes $ -snes_eq_ls quadratic 343c4a48953SLois Curfman McInnes 3445e42470aSBarry Smith Notes: 34577c4ece6SBarry Smith Use SNESSetLineSearch() 346f63b844aSLois Curfman McInnes to set this routine within the SNES_EQ_LS method. 3475e42470aSBarry Smith 348f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search 349f59ffdedSLois Curfman McInnes 35077c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 3515e42470aSBarry Smith @*/ 3525e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 353761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag) 3545e76c431SBarry Smith { 355ddd12767SBarry Smith double steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp; 3566b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 3575e42470aSBarry Smith Scalar cinitslope,clambda; 3586b5873e3SBarry Smith #endif 3595e42470aSBarry Smith int ierr,count; 3605e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 3615334005bSBarry Smith Scalar mone = -1.0,scale; 3625e76c431SBarry Smith 3637857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 364761aaf1bSLois Curfman McInnes *flag = 0; 3655e42470aSBarry Smith alpha = neP->alpha; 3665e42470aSBarry Smith maxstep = neP->maxstep; 3675e42470aSBarry Smith steptol = neP->steptol; 3685e76c431SBarry Smith 369cddf8d76SBarry Smith VecNorm(y, NORM_2,ynorm ); 3705e42470aSBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 3715e42470aSBarry Smith scale = maxstep/(*ynorm); 372393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 3735e42470aSBarry Smith *ynorm = maxstep; 3745e76c431SBarry Smith } 3755e42470aSBarry Smith minlambda = steptol/(*ynorm); 376a703fe33SLois Curfman McInnes ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 3775e42470aSBarry Smith #if defined(PETSC_COMPLEX) 378a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 3795e42470aSBarry Smith initslope = real(cinitslope); 3805e42470aSBarry Smith #else 381a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 3825e42470aSBarry Smith #endif 3835e42470aSBarry Smith if (initslope > 0.0) initslope = -initslope; 3845e42470aSBarry Smith if (initslope == 0.0) initslope = -1.0; 3855e42470aSBarry Smith 386393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 3875334005bSBarry Smith ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 38878b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 389cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 3905e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 391393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 39294a424c1SBarry Smith PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n"); 393d93a2b8dSBarry Smith goto theend; 3945e42470aSBarry Smith } 3955e42470aSBarry Smith 3965e42470aSBarry Smith /* Fit points with quadratic */ 3975e42470aSBarry Smith lambda = 1.0; count = 0; 3985e42470aSBarry Smith count = 1; 3995e42470aSBarry Smith while (1) { 4005e42470aSBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 40194a424c1SBarry Smith PLogInfo(snes, 4024b828684SBarry Smith "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 40394a424c1SBarry Smith PLogInfo(snes, 404ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 405ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 406393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 407761aaf1bSLois Curfman McInnes *flag = -1; break; 4085e42470aSBarry Smith } 409a703fe33SLois Curfman McInnes lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 4105e42470aSBarry Smith lambdaprev = lambda; 4115e42470aSBarry Smith gnormprev = *gnorm; 4125e42470aSBarry Smith if (lambdatemp <= .1*lambda) { 4135e42470aSBarry Smith lambda = .1*lambda; 4145e42470aSBarry Smith } else lambda = lambdatemp; 415393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 4165334005bSBarry Smith lambda = -lambda; 4175e42470aSBarry Smith #if defined(PETSC_COMPLEX) 418393d2d9aSLois Curfman McInnes clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 4195e42470aSBarry Smith #else 420393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 4215e42470aSBarry Smith #endif 42278b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 423cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 4245e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 425393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 42694a424c1SBarry Smith PLogInfo(snes, 427ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda); 42806259719SBarry Smith break; 4295e42470aSBarry Smith } 4305e42470aSBarry Smith count++; 4315e42470aSBarry Smith } 432d93a2b8dSBarry Smith theend: 4337857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 4345e42470aSBarry Smith return 0; 4355e76c431SBarry Smith } 4365e76c431SBarry Smith /* ------------------------------------------------------------ */ 437c9e6a524SLois Curfman McInnes /*@C 43877c4ece6SBarry Smith SNESSetLineSearch - Sets the line search routine to be used 439f63b844aSLois Curfman McInnes by the method SNES_EQ_LS. 4405e76c431SBarry Smith 4415e76c431SBarry Smith Input Parameters: 442eafb4bcbSBarry Smith . snes - nonlinear context obtained from SNESCreate() 4435e76c431SBarry Smith . func - pointer to int function 4445e76c431SBarry Smith 445c4a48953SLois Curfman McInnes Available Routines: 446f59ffdedSLois Curfman McInnes . SNESCubicLineSearch() - default line search 447f59ffdedSLois Curfman McInnes . SNESQuadraticLineSearch() - quadratic line search 448f59ffdedSLois Curfman McInnes . SNESNoLineSearch() - the full Newton step (actually not a line search) 4495e76c431SBarry Smith 450c4a48953SLois Curfman McInnes Options Database Keys: 451*09d61ba7SLois Curfman McInnes $ -snes_eq_ls [basic,quadratic,cubic] 452c4a48953SLois Curfman McInnes 4535e76c431SBarry Smith Calling sequence of func: 454f59ffdedSLois Curfman McInnes func (SNES snes, Vec x, Vec f, Vec g, Vec y, 455761aaf1bSLois Curfman McInnes Vec w, double fnorm, double *ynorm, 456761aaf1bSLois Curfman McInnes double *gnorm, *flag) 4575e76c431SBarry Smith 4585e76c431SBarry Smith Input parameters for func: 4595e42470aSBarry Smith . snes - nonlinear context 4605e76c431SBarry Smith . x - current iterate 4615e76c431SBarry Smith . f - residual evaluated at x 4625e76c431SBarry Smith . y - search direction (contains new iterate on output) 4635e76c431SBarry Smith . w - work vector 4645e76c431SBarry Smith . fnorm - 2-norm of f 4655e76c431SBarry Smith 4665e76c431SBarry Smith Output parameters for func: 4675e76c431SBarry Smith . g - residual evaluated at new iterate y 4685e76c431SBarry Smith . y - new iterate (contains search direction on input) 4695e76c431SBarry Smith . gnorm - 2-norm of g 4705e76c431SBarry Smith . ynorm - 2-norm of search length 471761aaf1bSLois Curfman McInnes . flag - set to 0 if the line search succeeds; a nonzero integer 472761aaf1bSLois Curfman McInnes on failure. 473f59ffdedSLois Curfman McInnes 474f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine 475f59ffdedSLois Curfman McInnes 476f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch() 4775e76c431SBarry Smith @*/ 47877c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 479761aaf1bSLois Curfman McInnes double,double*,double*,int*)) 4805e76c431SBarry Smith { 481f63b844aSLois Curfman McInnes if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func; 4825e42470aSBarry Smith return 0; 4835e76c431SBarry Smith } 48452392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 485f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p) 4865e42470aSBarry Smith { 4875e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 4886daaf66cSBarry Smith 489f63b844aSLois Curfman McInnes PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n"); 490*09d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls [basic,quadratic,cubic]\n",p); 491*09d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha); 492*09d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep); 493*09d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol); 4946b5873e3SBarry Smith return 0; 4955e42470aSBarry Smith } 49652392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 497f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer) 498a935fc98SLois Curfman McInnes { 499a935fc98SLois Curfman McInnes SNES snes = (SNES)obj; 500a935fc98SLois Curfman McInnes SNES_LS *ls = (SNES_LS *)snes->data; 501d636dbe3SBarry Smith FILE *fd; 50219bcc07fSBarry Smith char *cstr; 50351695f54SLois Curfman McInnes int ierr; 50419bcc07fSBarry Smith ViewerType vtype; 505a935fc98SLois Curfman McInnes 50619bcc07fSBarry Smith ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 50719bcc07fSBarry Smith if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 50890ace30eSBarry Smith ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 50919bcc07fSBarry Smith if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch"; 51019bcc07fSBarry Smith else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch"; 51119bcc07fSBarry Smith else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch"; 51219bcc07fSBarry Smith else cstr = "unknown"; 51377c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," line search variant: %s\n",cstr); 51477c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," alpha=%g, maxstep=%g, steptol=%g\n", 515a935fc98SLois Curfman McInnes ls->alpha,ls->maxstep,ls->steptol); 51619bcc07fSBarry Smith } 517a935fc98SLois Curfman McInnes return 0; 518a935fc98SLois Curfman McInnes } 51952392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 520f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes) 5215e42470aSBarry Smith { 5225e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5235e42470aSBarry Smith char ver[16]; 5245e42470aSBarry Smith double tmp; 52525cdf11fSBarry Smith int ierr,flg; 5265e42470aSBarry Smith 527*09d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr); 52825cdf11fSBarry Smith if (flg) { 5295e42470aSBarry Smith ls->alpha = tmp; 5305e42470aSBarry Smith } 531*09d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr); 53225cdf11fSBarry Smith if (flg) { 5335e42470aSBarry Smith ls->maxstep = tmp; 5345e42470aSBarry Smith } 535*09d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr); 53625cdf11fSBarry Smith if (flg) { 5375e42470aSBarry Smith ls->steptol = tmp; 5385e42470aSBarry Smith } 539*09d61ba7SLois Curfman McInnes ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr); 54025cdf11fSBarry Smith if (flg) { 54148d91487SBarry Smith if (!PetscStrcmp(ver,"basic")) { 54277c4ece6SBarry Smith SNESSetLineSearch(snes,SNESNoLineSearch); 5435e42470aSBarry Smith } 54448d91487SBarry Smith else if (!PetscStrcmp(ver,"quadratic")) { 54577c4ece6SBarry Smith SNESSetLineSearch(snes,SNESQuadraticLineSearch); 5465e42470aSBarry Smith } 54748d91487SBarry Smith else if (!PetscStrcmp(ver,"cubic")) { 54877c4ece6SBarry Smith SNESSetLineSearch(snes,SNESCubicLineSearch); 5495e42470aSBarry Smith } 550f63b844aSLois Curfman McInnes else {SETERRQ(1,"SNESSetFromOptions_EQ_LS:Unknown line search");} 5515e42470aSBarry Smith } 5525e42470aSBarry Smith return 0; 5535e42470aSBarry Smith } 5545e42470aSBarry Smith /* ------------------------------------------------------------ */ 555f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES snes ) 5565e42470aSBarry Smith { 5575e42470aSBarry Smith SNES_LS *neP; 5585e42470aSBarry Smith 559ddd12767SBarry Smith if (snes->method_class != SNES_NONLINEAR_EQUATIONS) 560f63b844aSLois Curfman McInnes SETERRQ(1,"SNESCreate_EQ_LS:For SNES_NONLINEAR_EQUATIONS only"); 561f63b844aSLois Curfman McInnes snes->type = SNES_EQ_LS; 562f63b844aSLois Curfman McInnes snes->setup = SNESSetUp_EQ_LS; 563f63b844aSLois Curfman McInnes snes->solve = SNESSolve_EQ_LS; 564f63b844aSLois Curfman McInnes snes->destroy = SNESDestroy_EQ_LS; 565f63b844aSLois Curfman McInnes snes->converged = SNESConverged_EQ_LS; 566f63b844aSLois Curfman McInnes snes->printhelp = SNESPrintHelp_EQ_LS; 567f63b844aSLois Curfman McInnes snes->setfromoptions = SNESSetFromOptions_EQ_LS; 568f63b844aSLois Curfman McInnes snes->view = SNESView_EQ_LS; 5695baf8537SBarry Smith snes->nwork = 0; 5705e42470aSBarry Smith 5710452661fSBarry Smith neP = PetscNew(SNES_LS); CHKPTRQ(neP); 572ff782a9fSLois Curfman McInnes PLogObjectMemory(snes,sizeof(SNES_LS)); 5735e42470aSBarry Smith snes->data = (void *) neP; 5745e42470aSBarry Smith neP->alpha = 1.e-4; 5755e42470aSBarry Smith neP->maxstep = 1.e8; 5765e42470aSBarry Smith neP->steptol = 1.e-12; 5775e42470aSBarry Smith neP->LineSearch = SNESCubicLineSearch; 5785e42470aSBarry Smith return 0; 5795e42470aSBarry Smith } 5805e42470aSBarry Smith 5815e42470aSBarry Smith 5825e42470aSBarry Smith 5835e42470aSBarry Smith 584