15e76c431SBarry Smith #ifndef lint 2*51979daaSLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.82 1997/01/20 22:11:40 bsmith 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 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 */ 38*51979daaSLois Curfman McInnes history_len = snes->conv_hist_size; /* 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; 51*51979daaSLois Curfman McInnes if (history) 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)) { 8716c95cacSBarry Smith break; 8816c95cacSBarry Smith } 8916c95cacSBarry 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 } 100*51979daaSLois Curfman McInnes if (history) snes->conv_act_size = (history_len < i+1) ? history_len : i+1; 1015e42470aSBarry Smith *outits = i+1; 1025e42470aSBarry Smith return 0; 1035e76c431SBarry Smith } 1045e76c431SBarry Smith /* ------------------------------------------------------------ */ 1055615d1e5SSatish Balay #undef __FUNC__ 1065615d1e5SSatish Balay #define __FUNC__ "SNESSetUp_EQ_LS" 107f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes ) 1085e76c431SBarry Smith { 1095e42470aSBarry Smith int ierr; 11081b6cf68SLois Curfman McInnes snes->nwork = 4; 111d7e8b826SBarry Smith ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr); 1125e42470aSBarry Smith PLogObjectParents(snes,snes->nwork,snes->work); 11381b6cf68SLois Curfman McInnes snes->vec_sol_update_always = snes->work[3]; 1145e42470aSBarry Smith return 0; 1155e76c431SBarry Smith } 1165e76c431SBarry Smith /* ------------------------------------------------------------ */ 1175615d1e5SSatish Balay #undef __FUNC__ 1185615d1e5SSatish Balay #define __FUNC__ "SNESDestroy_EQ_LS" 119f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj) 1205e76c431SBarry Smith { 1215e42470aSBarry Smith SNES snes = (SNES) obj; 122393d2d9aSLois Curfman McInnes int ierr; 1235baf8537SBarry Smith if (snes->nwork) { 1244b0e389bSBarry Smith ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr); 12521c89e3eSBarry Smith } 1260452661fSBarry Smith PetscFree(snes->data); 1275e42470aSBarry Smith return 0; 1285e76c431SBarry Smith } 1295e76c431SBarry Smith /* ------------------------------------------------------------ */ 1305615d1e5SSatish Balay #undef __FUNC__ 1315615d1e5SSatish Balay #define __FUNC__ "SNESNoLineSearch" 1325e76c431SBarry Smith /*ARGSUSED*/ 1334b828684SBarry Smith /*@C 1345e42470aSBarry Smith SNESNoLineSearch - This routine is not a line search at all; 1355e76c431SBarry Smith it simply uses the full Newton step. Thus, this routine is intended 1365e76c431SBarry Smith to serve as a template and is not recommended for general use. 1375e76c431SBarry Smith 1385e76c431SBarry Smith Input Parameters: 1395e42470aSBarry Smith . snes - nonlinear context 1405e76c431SBarry Smith . x - current iterate 1415e76c431SBarry Smith . f - residual evaluated at x 1425e76c431SBarry Smith . y - search direction (contains new iterate on output) 1435e76c431SBarry Smith . w - work vector 1445e76c431SBarry Smith . fnorm - 2-norm of f 1455e76c431SBarry Smith 146c4a48953SLois Curfman McInnes Output Parameters: 1475e76c431SBarry Smith . g - residual evaluated at new iterate y 1485e76c431SBarry Smith . y - new iterate (contains search direction on input) 1495e76c431SBarry Smith . gnorm - 2-norm of g 1505e76c431SBarry Smith . ynorm - 2-norm of search length 151761aaf1bSLois Curfman McInnes . flag - set to 0, indicating a successful line search 1525e76c431SBarry Smith 153c4a48953SLois Curfman McInnes Options Database Key: 15409d61ba7SLois Curfman McInnes $ -snes_eq_ls basic 155c4a48953SLois Curfman McInnes 15628ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 15728ae5a21SLois Curfman McInnes 158f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 15977c4ece6SBarry Smith SNESSetLineSearch() 1605e76c431SBarry Smith @*/ 1615e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 162761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag ) 1635e76c431SBarry Smith { 1645e42470aSBarry Smith int ierr; 1655334005bSBarry Smith Scalar mone = -1.0; 1665334005bSBarry Smith 167761aaf1bSLois Curfman McInnes *flag = 0; 1687857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 169cddf8d76SBarry Smith ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr); /* ynorm = || y || */ 170ea4d3ed3SLois Curfman McInnes ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr); /* y <- y - x */ 171ea4d3ed3SLois Curfman McInnes ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y) */ 172cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); /* gnorm = || g || */ 1737857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 174761aaf1bSLois Curfman McInnes return 0; 1755e76c431SBarry Smith } 1765e76c431SBarry Smith /* ------------------------------------------------------------------ */ 1775615d1e5SSatish Balay #undef __FUNC__ 1785615d1e5SSatish Balay #define __FUNC__ "SNESCubicLineSearch" 1794b828684SBarry Smith /*@C 180f525115eSLois Curfman McInnes SNESCubicLineSearch - Performs a cubic line search (default line search method). 1815e76c431SBarry Smith 1825e76c431SBarry Smith Input Parameters: 1835e42470aSBarry Smith . snes - nonlinear context 1845e76c431SBarry Smith . x - current iterate 1855e76c431SBarry Smith . f - residual evaluated at x 1865e76c431SBarry Smith . y - search direction (contains new iterate on output) 1875e76c431SBarry Smith . w - work vector 1885e76c431SBarry Smith . fnorm - 2-norm of f 1895e76c431SBarry Smith 190393d2d9aSLois Curfman McInnes Output Parameters: 1915e76c431SBarry Smith . g - residual evaluated at new iterate y 1925e76c431SBarry Smith . y - new iterate (contains search direction on input) 1935e76c431SBarry Smith . gnorm - 2-norm of g 1945e76c431SBarry Smith . ynorm - 2-norm of search length 195761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 1965e76c431SBarry Smith 197c4a48953SLois Curfman McInnes Options Database Key: 19809d61ba7SLois Curfman McInnes $ -snes_eq_ls cubic 199c4a48953SLois Curfman McInnes 2005e76c431SBarry Smith Notes: 2015e76c431SBarry Smith This line search is taken from "Numerical Methods for Unconstrained 2025e76c431SBarry Smith Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 2035e76c431SBarry Smith 20428ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 20528ae5a21SLois Curfman McInnes 20677c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 2075e76c431SBarry Smith @*/ 2085e42470aSBarry Smith int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w, 209761aaf1bSLois Curfman McInnes double fnorm,double *ynorm,double *gnorm,int *flag) 2105e76c431SBarry Smith { 211ddd12767SBarry Smith double steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2; 212ea4d3ed3SLois Curfman McInnes double maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg; 2136b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 2145e42470aSBarry Smith Scalar cinitslope, clambda; 2156b5873e3SBarry Smith #endif 2165e42470aSBarry Smith int ierr, count; 2175e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 2185334005bSBarry Smith Scalar mone = -1.0,scale; 2195e76c431SBarry Smith 2207857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 221761aaf1bSLois Curfman McInnes *flag = 0; 2225e76c431SBarry Smith alpha = neP->alpha; 2235e76c431SBarry Smith maxstep = neP->maxstep; 2245e76c431SBarry Smith steptol = neP->steptol; 2255e76c431SBarry Smith 226cddf8d76SBarry Smith ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr); 2275e76c431SBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 2285e42470aSBarry Smith scale = maxstep/(*ynorm); 2296b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 23094a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale)); 2316b5873e3SBarry Smith #else 23294a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale); 2336b5873e3SBarry Smith #endif 234393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 2355e76c431SBarry Smith *ynorm = maxstep; 2365e76c431SBarry Smith } 2375e76c431SBarry Smith minlambda = steptol/(*ynorm); 238a703fe33SLois Curfman McInnes ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 2395e42470aSBarry Smith #if defined(PETSC_COMPLEX) 240a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 2415e42470aSBarry Smith initslope = real(cinitslope); 2425e42470aSBarry Smith #else 243a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 2445e42470aSBarry Smith #endif 2455e76c431SBarry Smith if (initslope > 0.0) initslope = -initslope; 2465e76c431SBarry Smith if (initslope == 0.0) initslope = -1.0; 2475e76c431SBarry Smith 248393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 2495334005bSBarry Smith ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 25078b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 251cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); 2525e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 253393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 25494a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Using full step\n"); 255d93a2b8dSBarry Smith goto theend; 2565e76c431SBarry Smith } 2575e76c431SBarry Smith 2585e76c431SBarry Smith /* Fit points with quadratic */ 2595e76c431SBarry Smith lambda = 1.0; count = 0; 260a703fe33SLois Curfman McInnes lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 2615e76c431SBarry Smith lambdaprev = lambda; 2625e76c431SBarry Smith gnormprev = *gnorm; 263ddd12767SBarry Smith if (lambdatemp <= .1*lambda) lambda = .1*lambda; 264ddd12767SBarry Smith else lambda = lambdatemp; 265393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 266ea4d3ed3SLois Curfman McInnes lambdaneg = -lambda; 2675e42470aSBarry Smith #if defined(PETSC_COMPLEX) 268ea4d3ed3SLois Curfman McInnes clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 2695e42470aSBarry Smith #else 270ea4d3ed3SLois Curfman McInnes ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 2715e42470aSBarry Smith #endif 27278b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 273cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 2745e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 275393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 276ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda); 277d93a2b8dSBarry Smith goto theend; 2785e76c431SBarry Smith } 2795e76c431SBarry Smith 2805e76c431SBarry Smith /* Fit points with cubic */ 2815e76c431SBarry Smith count = 1; 2825e76c431SBarry Smith while (1) { 2835e76c431SBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 28494a424c1SBarry Smith PLogInfo(snes, 2854b828684SBarry Smith "SNESCubicLineSearch:Unable to find good step length! %d \n",count); 28694a424c1SBarry Smith PLogInfo(snes, 287ea4d3ed3SLois Curfman McInnes "SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 288ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 289393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 290761aaf1bSLois Curfman McInnes *flag = -1; break; 2915e76c431SBarry Smith } 2925e76c431SBarry Smith t1 = *gnorm - fnorm - lambda*initslope; 2935e76c431SBarry Smith t2 = gnormprev - fnorm - lambdaprev*initslope; 294ddd12767SBarry Smith a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2955e76c431SBarry Smith b = (-lambdaprev*t1/(lambda*lambda) + 2965e76c431SBarry Smith lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2975e76c431SBarry Smith d = b*b - 3*a*initslope; 2985e76c431SBarry Smith if (d < 0.0) d = 0.0; 2995e76c431SBarry Smith if (a == 0.0) { 3005e76c431SBarry Smith lambdatemp = -initslope/(2.0*b); 3015e76c431SBarry Smith } else { 3025e76c431SBarry Smith lambdatemp = (-b + sqrt(d))/(3.0*a); 3035e76c431SBarry Smith } 3045e76c431SBarry Smith if (lambdatemp > .5*lambda) { 3055e76c431SBarry Smith lambdatemp = .5*lambda; 3065e76c431SBarry Smith } 3075e76c431SBarry Smith lambdaprev = lambda; 3085e76c431SBarry Smith gnormprev = *gnorm; 3095e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 3105e76c431SBarry Smith lambda = .1*lambda; 3115e76c431SBarry Smith } 3125e76c431SBarry Smith else lambda = lambdatemp; 313393d2d9aSLois Curfman McInnes ierr = VecCopy( x, w ); CHKERRQ(ierr); 314ea4d3ed3SLois Curfman McInnes lambdaneg = -lambda; 3155e42470aSBarry Smith #if defined(PETSC_COMPLEX) 316ea4d3ed3SLois Curfman McInnes clambda = lambdaneg; 317393d2d9aSLois Curfman McInnes ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 3185e42470aSBarry Smith #else 319ea4d3ed3SLois Curfman McInnes ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 3205e42470aSBarry Smith #endif 32178b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 322cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 3235e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* is reduction enough */ 324393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 325ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda); 326761aaf1bSLois Curfman McInnes *flag = -1; break; 3275e76c431SBarry Smith } 3285e76c431SBarry Smith count++; 3295e76c431SBarry Smith } 330d93a2b8dSBarry Smith theend: 3317857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 3325e42470aSBarry Smith return 0; 3335e76c431SBarry Smith } 33452392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 3355615d1e5SSatish Balay #undef __FUNC__ 3365615d1e5SSatish Balay #define __FUNC__ "SNESQuadraticLineSearch" 3374b828684SBarry Smith /*@C 338f525115eSLois Curfman McInnes SNESQuadraticLineSearch - Performs a quadratic line search. 3395e76c431SBarry Smith 3405e42470aSBarry Smith Input Parameters: 341f59ffdedSLois Curfman McInnes . snes - the SNES context 3425e42470aSBarry Smith . x - current iterate 3435e42470aSBarry Smith . f - residual evaluated at x 3445e42470aSBarry Smith . y - search direction (contains new iterate on output) 3455e42470aSBarry Smith . w - work vector 3465e42470aSBarry Smith . fnorm - 2-norm of f 3475e42470aSBarry Smith 348c4a48953SLois Curfman McInnes Output Parameters: 3495e42470aSBarry Smith . g - residual evaluated at new iterate y 3505e42470aSBarry Smith . y - new iterate (contains search direction on input) 3515e42470aSBarry Smith . gnorm - 2-norm of g 3525e42470aSBarry Smith . ynorm - 2-norm of search length 353761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 3545e42470aSBarry Smith 355c4a48953SLois Curfman McInnes Options Database Key: 35609d61ba7SLois Curfman McInnes $ -snes_eq_ls quadratic 357c4a48953SLois Curfman McInnes 3585e42470aSBarry Smith Notes: 35977c4ece6SBarry Smith Use SNESSetLineSearch() 360f63b844aSLois Curfman McInnes to set this routine within the SNES_EQ_LS method. 3615e42470aSBarry Smith 362f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search 363f59ffdedSLois Curfman McInnes 36477c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 3655e42470aSBarry Smith @*/ 3665e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 367761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag) 3685e76c431SBarry Smith { 369ddd12767SBarry Smith double steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp; 3706b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 3715e42470aSBarry Smith Scalar cinitslope,clambda; 3726b5873e3SBarry Smith #endif 3735e42470aSBarry Smith int ierr,count; 3745e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 3755334005bSBarry Smith Scalar mone = -1.0,scale; 3765e76c431SBarry Smith 3777857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 378761aaf1bSLois Curfman McInnes *flag = 0; 3795e42470aSBarry Smith alpha = neP->alpha; 3805e42470aSBarry Smith maxstep = neP->maxstep; 3815e42470aSBarry Smith steptol = neP->steptol; 3825e76c431SBarry Smith 383cddf8d76SBarry Smith VecNorm(y, NORM_2,ynorm ); 3845e42470aSBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 3855e42470aSBarry Smith scale = maxstep/(*ynorm); 386393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 3875e42470aSBarry Smith *ynorm = maxstep; 3885e76c431SBarry Smith } 3895e42470aSBarry Smith minlambda = steptol/(*ynorm); 390a703fe33SLois Curfman McInnes ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 3915e42470aSBarry Smith #if defined(PETSC_COMPLEX) 392a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 3935e42470aSBarry Smith initslope = real(cinitslope); 3945e42470aSBarry Smith #else 395a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 3965e42470aSBarry Smith #endif 3975e42470aSBarry Smith if (initslope > 0.0) initslope = -initslope; 3985e42470aSBarry Smith if (initslope == 0.0) initslope = -1.0; 3995e42470aSBarry Smith 400393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 4015334005bSBarry Smith ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 40278b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 403cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 4045e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 405393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 40694a424c1SBarry Smith PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n"); 407d93a2b8dSBarry Smith goto theend; 4085e42470aSBarry Smith } 4095e42470aSBarry Smith 4105e42470aSBarry Smith /* Fit points with quadratic */ 4115e42470aSBarry Smith lambda = 1.0; count = 0; 4125e42470aSBarry Smith count = 1; 4135e42470aSBarry Smith while (1) { 4145e42470aSBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 41594a424c1SBarry Smith PLogInfo(snes, 4164b828684SBarry Smith "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 41794a424c1SBarry Smith PLogInfo(snes, 418ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 419ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 420393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 421761aaf1bSLois Curfman McInnes *flag = -1; break; 4225e42470aSBarry Smith } 423a703fe33SLois Curfman McInnes lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 4245e42470aSBarry Smith lambdaprev = lambda; 4255e42470aSBarry Smith gnormprev = *gnorm; 4265e42470aSBarry Smith if (lambdatemp <= .1*lambda) { 4275e42470aSBarry Smith lambda = .1*lambda; 4285e42470aSBarry Smith } else lambda = lambdatemp; 429393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 4305334005bSBarry Smith lambda = -lambda; 4315e42470aSBarry Smith #if defined(PETSC_COMPLEX) 432393d2d9aSLois Curfman McInnes clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 4335e42470aSBarry Smith #else 434393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 4355e42470aSBarry Smith #endif 43678b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 437cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 4385e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 439393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 44094a424c1SBarry Smith PLogInfo(snes, 441ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda); 44206259719SBarry Smith break; 4435e42470aSBarry Smith } 4445e42470aSBarry Smith count++; 4455e42470aSBarry Smith } 446d93a2b8dSBarry Smith theend: 4477857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 4485e42470aSBarry Smith return 0; 4495e76c431SBarry Smith } 4505e76c431SBarry Smith /* ------------------------------------------------------------ */ 4515615d1e5SSatish Balay #undef __FUNC__ 4525615d1e5SSatish Balay #define __FUNC__ "SNESSetLineSearch" 453c9e6a524SLois Curfman McInnes /*@C 45477c4ece6SBarry Smith SNESSetLineSearch - Sets the line search routine to be used 455f63b844aSLois Curfman McInnes by the method SNES_EQ_LS. 4565e76c431SBarry Smith 4575e76c431SBarry Smith Input Parameters: 458eafb4bcbSBarry Smith . snes - nonlinear context obtained from SNESCreate() 4595e76c431SBarry Smith . func - pointer to int function 4605e76c431SBarry Smith 461c4a48953SLois Curfman McInnes Available Routines: 462f59ffdedSLois Curfman McInnes . SNESCubicLineSearch() - default line search 463f59ffdedSLois Curfman McInnes . SNESQuadraticLineSearch() - quadratic line search 464f59ffdedSLois Curfman McInnes . SNESNoLineSearch() - the full Newton step (actually not a line search) 4655e76c431SBarry Smith 466c4a48953SLois Curfman McInnes Options Database Keys: 46709d61ba7SLois Curfman McInnes $ -snes_eq_ls [basic,quadratic,cubic] 468c4a48953SLois Curfman McInnes 4695e76c431SBarry Smith Calling sequence of func: 470f59ffdedSLois Curfman McInnes func (SNES snes, Vec x, Vec f, Vec g, Vec y, 471761aaf1bSLois Curfman McInnes Vec w, double fnorm, double *ynorm, 472761aaf1bSLois Curfman McInnes double *gnorm, *flag) 4735e76c431SBarry Smith 4745e76c431SBarry Smith Input parameters for func: 4755e42470aSBarry Smith . snes - nonlinear context 4765e76c431SBarry Smith . x - current iterate 4775e76c431SBarry Smith . f - residual evaluated at x 4785e76c431SBarry Smith . y - search direction (contains new iterate on output) 4795e76c431SBarry Smith . w - work vector 4805e76c431SBarry Smith . fnorm - 2-norm of f 4815e76c431SBarry Smith 4825e76c431SBarry Smith Output parameters for func: 4835e76c431SBarry Smith . g - residual evaluated at new iterate y 4845e76c431SBarry Smith . y - new iterate (contains search direction on input) 4855e76c431SBarry Smith . gnorm - 2-norm of g 4865e76c431SBarry Smith . ynorm - 2-norm of search length 487761aaf1bSLois Curfman McInnes . flag - set to 0 if the line search succeeds; a nonzero integer 488761aaf1bSLois Curfman McInnes on failure. 489f59ffdedSLois Curfman McInnes 490f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine 491f59ffdedSLois Curfman McInnes 492f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch() 4935e76c431SBarry Smith @*/ 49477c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 495761aaf1bSLois Curfman McInnes double,double*,double*,int*)) 4965e76c431SBarry Smith { 497f63b844aSLois Curfman McInnes if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func; 4985e42470aSBarry Smith return 0; 4995e76c431SBarry Smith } 50052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5015615d1e5SSatish Balay #undef __FUNC__ 5025615d1e5SSatish Balay #define __FUNC__ "SNESPrintHelp_EQ_LS" 503f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p) 5045e42470aSBarry Smith { 5055e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5066daaf66cSBarry Smith 507f63b844aSLois Curfman McInnes PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n"); 50809d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls [basic,quadratic,cubic]\n",p); 50909d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha); 51009d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep); 51109d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol); 5126b5873e3SBarry Smith return 0; 5135e42470aSBarry Smith } 51452392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5155615d1e5SSatish Balay #undef __FUNC__ 5165615d1e5SSatish Balay #define __FUNC__ "SNESView_EQ_LS" 517f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer) 518a935fc98SLois Curfman McInnes { 519a935fc98SLois Curfman McInnes SNES snes = (SNES)obj; 520a935fc98SLois Curfman McInnes SNES_LS *ls = (SNES_LS *)snes->data; 521d636dbe3SBarry Smith FILE *fd; 52219bcc07fSBarry Smith char *cstr; 52351695f54SLois Curfman McInnes int ierr; 52419bcc07fSBarry Smith ViewerType vtype; 525a935fc98SLois Curfman McInnes 52619bcc07fSBarry Smith ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 52719bcc07fSBarry Smith if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 52890ace30eSBarry Smith ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 52919bcc07fSBarry Smith if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch"; 53019bcc07fSBarry Smith else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch"; 53119bcc07fSBarry Smith else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch"; 53219bcc07fSBarry Smith else cstr = "unknown"; 53377c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," line search variant: %s\n",cstr); 53477c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," alpha=%g, maxstep=%g, steptol=%g\n", 535a935fc98SLois Curfman McInnes ls->alpha,ls->maxstep,ls->steptol); 53619bcc07fSBarry Smith } 537a935fc98SLois Curfman McInnes return 0; 538a935fc98SLois Curfman McInnes } 53952392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5405615d1e5SSatish Balay #undef __FUNC__ 5415615d1e5SSatish Balay #define __FUNC__ "SNESSetFromOptions_EQ_LS" 542f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes) 5435e42470aSBarry Smith { 5445e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5455e42470aSBarry Smith char ver[16]; 5465e42470aSBarry Smith double tmp; 54725cdf11fSBarry Smith int ierr,flg; 5485e42470aSBarry Smith 54909d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr); 55025cdf11fSBarry Smith if (flg) { 5515e42470aSBarry Smith ls->alpha = tmp; 5525e42470aSBarry Smith } 55309d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr); 55425cdf11fSBarry Smith if (flg) { 5555e42470aSBarry Smith ls->maxstep = tmp; 5565e42470aSBarry Smith } 55709d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr); 55825cdf11fSBarry Smith if (flg) { 5595e42470aSBarry Smith ls->steptol = tmp; 5605e42470aSBarry Smith } 56109d61ba7SLois Curfman McInnes ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr); 56225cdf11fSBarry Smith if (flg) { 56348d91487SBarry Smith if (!PetscStrcmp(ver,"basic")) { 56477c4ece6SBarry Smith SNESSetLineSearch(snes,SNESNoLineSearch); 5655e42470aSBarry Smith } 56648d91487SBarry Smith else if (!PetscStrcmp(ver,"quadratic")) { 56777c4ece6SBarry Smith SNESSetLineSearch(snes,SNESQuadraticLineSearch); 5685e42470aSBarry Smith } 56948d91487SBarry Smith else if (!PetscStrcmp(ver,"cubic")) { 57077c4ece6SBarry Smith SNESSetLineSearch(snes,SNESCubicLineSearch); 5715e42470aSBarry Smith } 572e3372554SBarry Smith else {SETERRQ(1,0,"Unknown line search");} 5735e42470aSBarry Smith } 5745e42470aSBarry Smith return 0; 5755e42470aSBarry Smith } 5765e42470aSBarry Smith /* ------------------------------------------------------------ */ 5775615d1e5SSatish Balay #undef __FUNC__ 5785615d1e5SSatish Balay #define __FUNC__ "SNESCreate_EQ_LS" 579f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES snes ) 5805e42470aSBarry Smith { 5815e42470aSBarry Smith SNES_LS *neP; 5825e42470aSBarry Smith 583ddd12767SBarry Smith if (snes->method_class != SNES_NONLINEAR_EQUATIONS) 584e3372554SBarry Smith SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only"); 585f63b844aSLois Curfman McInnes snes->type = SNES_EQ_LS; 586f63b844aSLois Curfman McInnes snes->setup = SNESSetUp_EQ_LS; 587f63b844aSLois Curfman McInnes snes->solve = SNESSolve_EQ_LS; 588f63b844aSLois Curfman McInnes snes->destroy = SNESDestroy_EQ_LS; 589f63b844aSLois Curfman McInnes snes->converged = SNESConverged_EQ_LS; 590f63b844aSLois Curfman McInnes snes->printhelp = SNESPrintHelp_EQ_LS; 591f63b844aSLois Curfman McInnes snes->setfromoptions = SNESSetFromOptions_EQ_LS; 592f63b844aSLois Curfman McInnes snes->view = SNESView_EQ_LS; 5935baf8537SBarry Smith snes->nwork = 0; 5945e42470aSBarry Smith 5950452661fSBarry Smith neP = PetscNew(SNES_LS); CHKPTRQ(neP); 596ff782a9fSLois Curfman McInnes PLogObjectMemory(snes,sizeof(SNES_LS)); 5975e42470aSBarry Smith snes->data = (void *) neP; 5985e42470aSBarry Smith neP->alpha = 1.e-4; 5995e42470aSBarry Smith neP->maxstep = 1.e8; 6005e42470aSBarry Smith neP->steptol = 1.e-12; 6015e42470aSBarry Smith neP->LineSearch = SNESCubicLineSearch; 6025e42470aSBarry Smith return 0; 6035e42470aSBarry Smith } 6045e42470aSBarry Smith 605