15e76c431SBarry Smith #ifndef lint 2*2b022350SLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.88 1997/04/02 16:38:35 curfman Exp bsmith $"; 35e76c431SBarry Smith #endif 45e76c431SBarry Smith 55e76c431SBarry Smith #include <math.h> 670f55243SBarry Smith #include "src/snes/impls/ls/ls.h" 7b16a3bb1SBarry Smith #include "pinclude/pviewer.h" 85e42470aSBarry Smith 95e42470aSBarry Smith /* 105e42470aSBarry Smith Implements a line search variant of Newton's Method 115e76c431SBarry Smith for solving systems of nonlinear equations. 125e76c431SBarry Smith 135e76c431SBarry Smith Input parameters: 145e42470aSBarry Smith . snes - nonlinear context obtained from SNESCreate() 155e76c431SBarry Smith 165e42470aSBarry Smith Output Parameters: 17a935fc98SLois Curfman McInnes . outits - Number of global iterations until termination. 185e76c431SBarry Smith 195e76c431SBarry Smith Notes: 205e76c431SBarry Smith This implements essentially a truncated Newton method with a 215e76c431SBarry Smith line search. By default a cubic backtracking line search 225e76c431SBarry Smith is employed, as described in the text "Numerical Methods for 235e76c431SBarry Smith Unconstrained Optimization and Nonlinear Equations" by Dennis 24393d2d9aSLois Curfman McInnes and Schnabel. 255e76c431SBarry Smith */ 265e76c431SBarry Smith 275615d1e5SSatish Balay #undef __FUNC__ 285615d1e5SSatish Balay #define __FUNC__ "SNESSolve_EQ_LS" 29f63b844aSLois Curfman McInnes int SNESSolve_EQ_LS(SNES snes,int *outits) 305e76c431SBarry Smith { 315e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 32761aaf1bSLois Curfman McInnes int maxits, i, history_len, ierr, lits, lsfail; 33112a2221SBarry Smith MatStructure flg = DIFFERENT_NONZERO_PATTERN; 346b5873e3SBarry Smith double fnorm, gnorm, xnorm, ynorm, *history; 355e42470aSBarry Smith Vec Y, X, F, G, W, TMP; 365e76c431SBarry Smith 375e42470aSBarry Smith history = snes->conv_hist; /* convergence history */ 3851979daaSLois 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; 5151979daaSLois Curfman McInnes if (history) history[0] = fnorm; 5294a424c1SBarry Smith SNESMonitor(snes,0,fnorm); 535e76c431SBarry Smith 5494a9d846SBarry Smith if (fnorm == 0.0) {outits = 0; return 0;} 5594a9d846SBarry Smith 56d034289bSBarry Smith /* set parameter for default relative tolerance convergence test */ 57d034289bSBarry Smith snes->ttol = fnorm*snes->rtol; 58d034289bSBarry Smith 595e76c431SBarry Smith for ( i=0; i<maxits; i++ ) { 605e42470aSBarry Smith snes->iter = i+1; 615e76c431SBarry Smith 62ea4d3ed3SLois Curfman McInnes /* Solve J Y = F, where J is Jacobian matrix */ 635334005bSBarry Smith ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg); CHKERRQ(ierr); 645334005bSBarry Smith ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); CHKERRQ(ierr); 6578b31e54SBarry Smith ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr); 667a00f4a9SLois Curfman McInnes snes->linear_its += PetscAbsInt(lits); 67af1ccdebSLois Curfman McInnes PLogInfo(snes,"SNESSolve_EQ_LS: iter=%d, linear solve iterations=%d\n",snes->iter,lits); 68ea4d3ed3SLois Curfman McInnes 69ea4d3ed3SLois Curfman McInnes /* Compute a (scaled) negative update in the line search routine: 70ea4d3ed3SLois Curfman McInnes Y <- X - lambda*Y 71ea4d3ed3SLois Curfman McInnes and evaluate G(Y) = function(Y)) 72ea4d3ed3SLois Curfman McInnes */ 7381b6cf68SLois Curfman McInnes ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr); 74ddd12767SBarry Smith ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); CHKERRQ(ierr); 75af1ccdebSLois Curfman McInnes PLogInfo(snes,"SNESSolve_EQ_LS: fnorm=%g, gnorm=%g, ynorm=%g, lsfail=%d\n",fnorm,gnorm,ynorm,lsfail); 76761aaf1bSLois Curfman McInnes if (lsfail) snes->nfailures++; 775e76c431SBarry Smith 7839e2f89bSBarry Smith TMP = F; F = G; snes->vec_func_always = F; G = TMP; 7939e2f89bSBarry Smith TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 805e76c431SBarry Smith fnorm = gnorm; 815e76c431SBarry Smith 825e42470aSBarry Smith snes->norm = fnorm; 835e76c431SBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 84cddf8d76SBarry Smith ierr = VecNorm(X,NORM_2,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 8594a424c1SBarry Smith SNESMonitor(snes,i+1,fnorm); 865e76c431SBarry Smith 875e76c431SBarry Smith /* Test for convergence */ 88bbb6d6a8SBarry Smith if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) { 8916c95cacSBarry Smith break; 9016c95cacSBarry Smith } 9116c95cacSBarry Smith } 9239e2f89bSBarry Smith if (X != snes->vec_sol) { 93393d2d9aSLois Curfman McInnes ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr); 9439e2f89bSBarry Smith snes->vec_sol_always = snes->vec_sol; 9539e2f89bSBarry Smith snes->vec_func_always = snes->vec_func; 9639e2f89bSBarry Smith } 9752392280SLois Curfman McInnes if (i == maxits) { 9894a424c1SBarry Smith PLogInfo(snes, 99f63b844aSLois Curfman McInnes "SNESSolve_EQ_LS: Maximum number of iterations has been reached: %d\n",maxits); 10052392280SLois Curfman McInnes i--; 10152392280SLois Curfman McInnes } 10251979daaSLois Curfman McInnes if (history) snes->conv_act_size = (history_len < i+1) ? history_len : i+1; 1035e42470aSBarry Smith *outits = i+1; 1045e42470aSBarry Smith return 0; 1055e76c431SBarry Smith } 1065e76c431SBarry Smith /* ------------------------------------------------------------ */ 1075615d1e5SSatish Balay #undef __FUNC__ 1085615d1e5SSatish Balay #define __FUNC__ "SNESSetUp_EQ_LS" 109f63b844aSLois Curfman McInnes int SNESSetUp_EQ_LS(SNES snes ) 1105e76c431SBarry Smith { 1115e42470aSBarry Smith int ierr; 11281b6cf68SLois Curfman McInnes snes->nwork = 4; 113d7e8b826SBarry Smith ierr = VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);CHKERRQ(ierr); 1145e42470aSBarry Smith PLogObjectParents(snes,snes->nwork,snes->work); 11581b6cf68SLois Curfman McInnes snes->vec_sol_update_always = snes->work[3]; 1165e42470aSBarry Smith return 0; 1175e76c431SBarry Smith } 1185e76c431SBarry Smith /* ------------------------------------------------------------ */ 1195615d1e5SSatish Balay #undef __FUNC__ 1205eea60f9SBarry Smith #define __FUNC__ "SNESDestroy_EQ_LS" /* ADIC Ignore */ 121f63b844aSLois Curfman McInnes int SNESDestroy_EQ_LS(PetscObject obj) 1225e76c431SBarry Smith { 1235e42470aSBarry Smith SNES snes = (SNES) obj; 124393d2d9aSLois Curfman McInnes int ierr; 1255baf8537SBarry Smith if (snes->nwork) { 1264b0e389bSBarry Smith ierr = VecDestroyVecs(snes->work,snes->nwork); CHKERRQ(ierr); 12721c89e3eSBarry Smith } 1280452661fSBarry Smith PetscFree(snes->data); 1295e42470aSBarry Smith return 0; 1305e76c431SBarry Smith } 1315e76c431SBarry Smith /* ------------------------------------------------------------ */ 1325615d1e5SSatish Balay #undef __FUNC__ 1335615d1e5SSatish Balay #define __FUNC__ "SNESNoLineSearch" 1345e76c431SBarry Smith /*ARGSUSED*/ 1354b828684SBarry Smith /*@C 1365e42470aSBarry Smith SNESNoLineSearch - This routine is not a line search at all; 1375e76c431SBarry Smith it simply uses the full Newton step. Thus, this routine is intended 1385e76c431SBarry Smith to serve as a template and is not recommended for general use. 1395e76c431SBarry Smith 1405e76c431SBarry Smith Input Parameters: 1415e42470aSBarry Smith . snes - nonlinear context 1425e76c431SBarry Smith . x - current iterate 1435e76c431SBarry Smith . f - residual evaluated at x 1445e76c431SBarry Smith . y - search direction (contains new iterate on output) 1455e76c431SBarry Smith . w - work vector 1465e76c431SBarry Smith . fnorm - 2-norm of f 1475e76c431SBarry Smith 148c4a48953SLois Curfman McInnes Output Parameters: 1495e76c431SBarry Smith . g - residual evaluated at new iterate y 1505e76c431SBarry Smith . y - new iterate (contains search direction on input) 1515e76c431SBarry Smith . gnorm - 2-norm of g 1525e76c431SBarry Smith . ynorm - 2-norm of search length 153761aaf1bSLois Curfman McInnes . flag - set to 0, indicating a successful line search 1545e76c431SBarry Smith 155c4a48953SLois Curfman McInnes Options Database Key: 15609d61ba7SLois Curfman McInnes $ -snes_eq_ls basic 157c4a48953SLois Curfman McInnes 15828ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 15928ae5a21SLois Curfman McInnes 160f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 16177c4ece6SBarry Smith SNESSetLineSearch() 1625e76c431SBarry Smith @*/ 1635e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 164761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag ) 1655e76c431SBarry Smith { 1665e42470aSBarry Smith int ierr; 1675334005bSBarry Smith Scalar mone = -1.0; 1685334005bSBarry Smith 169761aaf1bSLois Curfman McInnes *flag = 0; 1707857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 171cddf8d76SBarry Smith ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr); /* ynorm = || y || */ 172ea4d3ed3SLois Curfman McInnes ierr = VecAYPX(&mone,x,y); CHKERRQ(ierr); /* y <- y - x */ 173ea4d3ed3SLois Curfman McInnes ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* Compute F(y) */ 174cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); /* gnorm = || g || */ 1757857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 176761aaf1bSLois Curfman McInnes return 0; 1775e76c431SBarry Smith } 1785e76c431SBarry Smith /* ------------------------------------------------------------------ */ 1795615d1e5SSatish Balay #undef __FUNC__ 1805615d1e5SSatish Balay #define __FUNC__ "SNESCubicLineSearch" 1814b828684SBarry Smith /*@C 182f525115eSLois Curfman McInnes SNESCubicLineSearch - Performs a cubic line search (default line search method). 1835e76c431SBarry Smith 1845e76c431SBarry Smith Input Parameters: 1855e42470aSBarry Smith . snes - nonlinear context 1865e76c431SBarry Smith . x - current iterate 1875e76c431SBarry Smith . f - residual evaluated at x 1885e76c431SBarry Smith . y - search direction (contains new iterate on output) 1895e76c431SBarry Smith . w - work vector 1905e76c431SBarry Smith . fnorm - 2-norm of f 1915e76c431SBarry Smith 192393d2d9aSLois Curfman McInnes Output Parameters: 1935e76c431SBarry Smith . g - residual evaluated at new iterate y 1945e76c431SBarry Smith . y - new iterate (contains search direction on input) 1955e76c431SBarry Smith . gnorm - 2-norm of g 1965e76c431SBarry Smith . ynorm - 2-norm of search length 197761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 1985e76c431SBarry Smith 199c4a48953SLois Curfman McInnes Options Database Key: 20009d61ba7SLois Curfman McInnes $ -snes_eq_ls cubic 201c4a48953SLois Curfman McInnes 2025e76c431SBarry Smith Notes: 2035e76c431SBarry Smith This line search is taken from "Numerical Methods for Unconstrained 2045e76c431SBarry Smith Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 2055e76c431SBarry Smith 20628ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 20728ae5a21SLois Curfman McInnes 20877c4ece6SBarry Smith .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 2095e76c431SBarry Smith @*/ 2105e42470aSBarry Smith int SNESCubicLineSearch(SNES snes,Vec x,Vec f,Vec g,Vec y,Vec w, 211761aaf1bSLois Curfman McInnes double fnorm,double *ynorm,double *gnorm,int *flag) 2125e76c431SBarry Smith { 213ddd12767SBarry Smith double steptol, initslope, lambdaprev, gnormprev, a, b, d, t1, t2; 214ea4d3ed3SLois Curfman McInnes double maxstep, minlambda, alpha, lambda, lambdatemp, lambdaneg; 2156b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 2165e42470aSBarry Smith Scalar cinitslope, clambda; 2176b5873e3SBarry Smith #endif 2185e42470aSBarry Smith int ierr, count; 2195e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 2205334005bSBarry Smith Scalar mone = -1.0,scale; 2215e76c431SBarry Smith 2227857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 223761aaf1bSLois Curfman McInnes *flag = 0; 2245e76c431SBarry Smith alpha = neP->alpha; 2255e76c431SBarry Smith maxstep = neP->maxstep; 2265e76c431SBarry Smith steptol = neP->steptol; 2275e76c431SBarry Smith 228cddf8d76SBarry Smith ierr = VecNorm(y,NORM_2,ynorm); CHKERRQ(ierr); 22994a9d846SBarry Smith if (*ynorm == 0.0) { 23094a9d846SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Search direction and size is 0\n"); 231ad922ac9SBarry Smith goto theend1; 23294a9d846SBarry Smith } 2335e76c431SBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 2345e42470aSBarry Smith scale = maxstep/(*ynorm); 2356b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 23694a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale)); 2376b5873e3SBarry Smith #else 23894a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Scaling step by %g\n",scale); 2396b5873e3SBarry Smith #endif 240393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 2415e76c431SBarry Smith *ynorm = maxstep; 2425e76c431SBarry Smith } 2435e76c431SBarry Smith minlambda = steptol/(*ynorm); 244a703fe33SLois Curfman McInnes ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 2455e42470aSBarry Smith #if defined(PETSC_COMPLEX) 246a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 2475e42470aSBarry Smith initslope = real(cinitslope); 2485e42470aSBarry Smith #else 249a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 2505e42470aSBarry Smith #endif 2515e76c431SBarry Smith if (initslope > 0.0) initslope = -initslope; 2525e76c431SBarry Smith if (initslope == 0.0) initslope = -1.0; 2535e76c431SBarry Smith 254393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 2555334005bSBarry Smith ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 25678b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 257cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); 2585e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 259393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 26094a424c1SBarry Smith PLogInfo(snes,"SNESCubicLineSearch: Using full step\n"); 261ad922ac9SBarry Smith goto theend1; 2625e76c431SBarry Smith } 2635e76c431SBarry Smith 2645e76c431SBarry Smith /* Fit points with quadratic */ 2655e76c431SBarry Smith lambda = 1.0; count = 0; 266a703fe33SLois Curfman McInnes lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 2675e76c431SBarry Smith lambdaprev = lambda; 2685e76c431SBarry Smith gnormprev = *gnorm; 269ddd12767SBarry Smith if (lambdatemp <= .1*lambda) lambda = .1*lambda; 270ddd12767SBarry Smith else lambda = lambdatemp; 271393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 272ea4d3ed3SLois Curfman McInnes lambdaneg = -lambda; 2735e42470aSBarry Smith #if defined(PETSC_COMPLEX) 274ea4d3ed3SLois Curfman McInnes clambda = lambdaneg; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 2755e42470aSBarry Smith #else 276ea4d3ed3SLois Curfman McInnes ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 2775e42470aSBarry Smith #endif 27878b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 279cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 2805e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 281393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 282ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Quadratically determined step, lambda=%g\n",lambda); 283ad922ac9SBarry Smith goto theend1; 2845e76c431SBarry Smith } 2855e76c431SBarry Smith 2865e76c431SBarry Smith /* Fit points with cubic */ 2875e76c431SBarry Smith count = 1; 2885e76c431SBarry Smith while (1) { 2895e76c431SBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 290*2b022350SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch:Unable to find good step length! %d \n",count); 291*2b022350SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 292ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 293393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 294761aaf1bSLois Curfman McInnes *flag = -1; break; 2955e76c431SBarry Smith } 2965e76c431SBarry Smith t1 = *gnorm - fnorm - lambda*initslope; 2975e76c431SBarry Smith t2 = gnormprev - fnorm - lambdaprev*initslope; 298ddd12767SBarry Smith a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 299*2b022350SLois Curfman McInnes b = (-lambdaprev*t1/(lambda*lambda) + lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 3005e76c431SBarry Smith d = b*b - 3*a*initslope; 3015e76c431SBarry Smith if (d < 0.0) d = 0.0; 3025e76c431SBarry Smith if (a == 0.0) { 3035e76c431SBarry Smith lambdatemp = -initslope/(2.0*b); 3045e76c431SBarry Smith } else { 3055e76c431SBarry Smith lambdatemp = (-b + sqrt(d))/(3.0*a); 3065e76c431SBarry Smith } 3075e76c431SBarry Smith if (lambdatemp > .5*lambda) { 3085e76c431SBarry Smith lambdatemp = .5*lambda; 3095e76c431SBarry Smith } 3105e76c431SBarry Smith lambdaprev = lambda; 3115e76c431SBarry Smith gnormprev = *gnorm; 3125e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 3135e76c431SBarry Smith lambda = .1*lambda; 3145e76c431SBarry Smith } 3155e76c431SBarry Smith else lambda = lambdatemp; 316393d2d9aSLois Curfman McInnes ierr = VecCopy( x, w ); CHKERRQ(ierr); 317ea4d3ed3SLois Curfman McInnes lambdaneg = -lambda; 3185e42470aSBarry Smith #if defined(PETSC_COMPLEX) 319ea4d3ed3SLois Curfman McInnes clambda = lambdaneg; 320393d2d9aSLois Curfman McInnes ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 3215e42470aSBarry Smith #else 322ea4d3ed3SLois Curfman McInnes ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 3235e42470aSBarry Smith #endif 32478b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 325cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 326*2b022350SLois Curfman McInnes if (*gnorm <= fnorm + alpha*initslope) { /* is reduction enough? */ 327393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 328ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda); 3292715565aSLois Curfman McInnes goto theend1; 330*2b022350SLois Curfman McInnes } else { 331*2b022350SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Cubic step no good, shrinking lambda, lambda=%g\n",lambda); 3325e76c431SBarry Smith } 3335e76c431SBarry Smith count++; 3345e76c431SBarry Smith } 335ad922ac9SBarry Smith theend1: 3367857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 3375e42470aSBarry Smith return 0; 3385e76c431SBarry Smith } 33952392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 3405615d1e5SSatish Balay #undef __FUNC__ 3415615d1e5SSatish Balay #define __FUNC__ "SNESQuadraticLineSearch" 3424b828684SBarry Smith /*@C 343f525115eSLois Curfman McInnes SNESQuadraticLineSearch - Performs a quadratic line search. 3445e76c431SBarry Smith 3455e42470aSBarry Smith Input Parameters: 346f59ffdedSLois Curfman McInnes . snes - the SNES context 3475e42470aSBarry Smith . x - current iterate 3485e42470aSBarry Smith . f - residual evaluated at x 3495e42470aSBarry Smith . y - search direction (contains new iterate on output) 3505e42470aSBarry Smith . w - work vector 3515e42470aSBarry Smith . fnorm - 2-norm of f 3525e42470aSBarry Smith 353c4a48953SLois Curfman McInnes Output Parameters: 3545e42470aSBarry Smith . g - residual evaluated at new iterate y 3555e42470aSBarry Smith . y - new iterate (contains search direction on input) 3565e42470aSBarry Smith . gnorm - 2-norm of g 3575e42470aSBarry Smith . ynorm - 2-norm of search length 358761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 3595e42470aSBarry Smith 360c4a48953SLois Curfman McInnes Options Database Key: 36109d61ba7SLois Curfman McInnes $ -snes_eq_ls quadratic 362c4a48953SLois Curfman McInnes 3635e42470aSBarry Smith Notes: 36477c4ece6SBarry Smith Use SNESSetLineSearch() 365f63b844aSLois Curfman McInnes to set this routine within the SNES_EQ_LS method. 3665e42470aSBarry Smith 367f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search 368f59ffdedSLois Curfman McInnes 36977c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 3705e42470aSBarry Smith @*/ 3715e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 372761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag) 3735e76c431SBarry Smith { 374ddd12767SBarry Smith double steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp; 3756b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 3765e42470aSBarry Smith Scalar cinitslope,clambda; 3776b5873e3SBarry Smith #endif 3785e42470aSBarry Smith int ierr,count; 3795e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 3805334005bSBarry Smith Scalar mone = -1.0,scale; 3815e76c431SBarry Smith 3827857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 383761aaf1bSLois Curfman McInnes *flag = 0; 3845e42470aSBarry Smith alpha = neP->alpha; 3855e42470aSBarry Smith maxstep = neP->maxstep; 3865e42470aSBarry Smith steptol = neP->steptol; 3875e76c431SBarry Smith 388cddf8d76SBarry Smith VecNorm(y, NORM_2,ynorm ); 38994a9d846SBarry Smith if (*ynorm == 0.0) { 39094a9d846SBarry Smith PLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n"); 391ad922ac9SBarry Smith goto theend2; 39294a9d846SBarry Smith } 3935e42470aSBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 3945e42470aSBarry Smith scale = maxstep/(*ynorm); 395393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 3965e42470aSBarry Smith *ynorm = maxstep; 3975e76c431SBarry Smith } 3985e42470aSBarry Smith minlambda = steptol/(*ynorm); 399a703fe33SLois Curfman McInnes ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 4005e42470aSBarry Smith #if defined(PETSC_COMPLEX) 401a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 4025e42470aSBarry Smith initslope = real(cinitslope); 4035e42470aSBarry Smith #else 404a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 4055e42470aSBarry Smith #endif 4065e42470aSBarry Smith if (initslope > 0.0) initslope = -initslope; 4075e42470aSBarry Smith if (initslope == 0.0) initslope = -1.0; 4085e42470aSBarry Smith 409393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 4105334005bSBarry Smith ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 41178b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 412cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 4135e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 414393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 41594a424c1SBarry Smith PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n"); 416ad922ac9SBarry Smith goto theend2; 4175e42470aSBarry Smith } 4185e42470aSBarry Smith 4195e42470aSBarry Smith /* Fit points with quadratic */ 4205e42470aSBarry Smith lambda = 1.0; count = 0; 4215e42470aSBarry Smith count = 1; 4225e42470aSBarry Smith while (1) { 4235e42470aSBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 42494a424c1SBarry Smith PLogInfo(snes, 4254b828684SBarry Smith "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 42694a424c1SBarry Smith PLogInfo(snes, 427ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 428ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 429393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 430761aaf1bSLois Curfman McInnes *flag = -1; break; 4315e42470aSBarry Smith } 432a703fe33SLois Curfman McInnes lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 4335e42470aSBarry Smith lambdaprev = lambda; 4345e42470aSBarry Smith gnormprev = *gnorm; 4355e42470aSBarry Smith if (lambdatemp <= .1*lambda) { 4365e42470aSBarry Smith lambda = .1*lambda; 4375e42470aSBarry Smith } else lambda = lambdatemp; 438393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 4395334005bSBarry Smith lambda = -lambda; 4405e42470aSBarry Smith #if defined(PETSC_COMPLEX) 441393d2d9aSLois Curfman McInnes clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 4425e42470aSBarry Smith #else 443393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 4445e42470aSBarry Smith #endif 44578b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 446cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 4475e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 448393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 44994a424c1SBarry Smith PLogInfo(snes, 450ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda); 45106259719SBarry Smith break; 4525e42470aSBarry Smith } 4535e42470aSBarry Smith count++; 4545e42470aSBarry Smith } 455ad922ac9SBarry Smith theend2: 4567857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 4575e42470aSBarry Smith return 0; 4585e76c431SBarry Smith } 4595e76c431SBarry Smith /* ------------------------------------------------------------ */ 4605615d1e5SSatish Balay #undef __FUNC__ 4615eea60f9SBarry Smith #define __FUNC__ "SNESSetLineSearch" /* ADIC Ignore */ 462c9e6a524SLois Curfman McInnes /*@C 46377c4ece6SBarry Smith SNESSetLineSearch - Sets the line search routine to be used 464f63b844aSLois Curfman McInnes by the method SNES_EQ_LS. 4655e76c431SBarry Smith 4665e76c431SBarry Smith Input Parameters: 467eafb4bcbSBarry Smith . snes - nonlinear context obtained from SNESCreate() 4685e76c431SBarry Smith . func - pointer to int function 4695e76c431SBarry Smith 470c4a48953SLois Curfman McInnes Available Routines: 471f59ffdedSLois Curfman McInnes . SNESCubicLineSearch() - default line search 472f59ffdedSLois Curfman McInnes . SNESQuadraticLineSearch() - quadratic line search 473f59ffdedSLois Curfman McInnes . SNESNoLineSearch() - the full Newton step (actually not a line search) 4745e76c431SBarry Smith 475c4a48953SLois Curfman McInnes Options Database Keys: 47609d61ba7SLois Curfman McInnes $ -snes_eq_ls [basic,quadratic,cubic] 477912ebf9aSLois Curfman McInnes $ -snes_eq_ls_alpha <alpha> 478912ebf9aSLois Curfman McInnes $ -snes_eq_ls_maxstep <max> 479912ebf9aSLois Curfman McInnes $ -snes_eq_ls_steptol <steptol> 480c4a48953SLois Curfman McInnes 4815e76c431SBarry Smith Calling sequence of func: 482f59ffdedSLois Curfman McInnes func (SNES snes, Vec x, Vec f, Vec g, Vec y, 483761aaf1bSLois Curfman McInnes Vec w, double fnorm, double *ynorm, 484761aaf1bSLois Curfman McInnes double *gnorm, *flag) 4855e76c431SBarry Smith 4865e76c431SBarry Smith Input parameters for func: 4875e42470aSBarry Smith . snes - nonlinear context 4885e76c431SBarry Smith . x - current iterate 4895e76c431SBarry Smith . f - residual evaluated at x 4905e76c431SBarry Smith . y - search direction (contains new iterate on output) 4915e76c431SBarry Smith . w - work vector 4925e76c431SBarry Smith . fnorm - 2-norm of f 4935e76c431SBarry Smith 4945e76c431SBarry Smith Output parameters for func: 4955e76c431SBarry Smith . g - residual evaluated at new iterate y 4965e76c431SBarry Smith . y - new iterate (contains search direction on input) 4975e76c431SBarry Smith . gnorm - 2-norm of g 4985e76c431SBarry Smith . ynorm - 2-norm of search length 499761aaf1bSLois Curfman McInnes . flag - set to 0 if the line search succeeds; a nonzero integer 500761aaf1bSLois Curfman McInnes on failure. 501f59ffdedSLois Curfman McInnes 502f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine 503f59ffdedSLois Curfman McInnes 504f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch() 5055e76c431SBarry Smith @*/ 50677c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 507761aaf1bSLois Curfman McInnes double,double*,double*,int*)) 5085e76c431SBarry Smith { 509f63b844aSLois Curfman McInnes if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func; 5105e42470aSBarry Smith return 0; 5115e76c431SBarry Smith } 51252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5135615d1e5SSatish Balay #undef __FUNC__ 5145eea60f9SBarry Smith #define __FUNC__ "SNESPrintHelp_EQ_LS" /* ADIC Ignore */ 515f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p) 5165e42470aSBarry Smith { 5175e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5186daaf66cSBarry Smith 519f63b844aSLois Curfman McInnes PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n"); 52009d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls [basic,quadratic,cubic]\n",p); 52109d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha); 52209d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep); 52309d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol); 5246b5873e3SBarry Smith return 0; 5255e42470aSBarry Smith } 52652392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5275615d1e5SSatish Balay #undef __FUNC__ 5285eea60f9SBarry Smith #define __FUNC__ "SNESView_EQ_LS" /* ADIC Ignore */ 529f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer) 530a935fc98SLois Curfman McInnes { 531a935fc98SLois Curfman McInnes SNES snes = (SNES)obj; 532a935fc98SLois Curfman McInnes SNES_LS *ls = (SNES_LS *)snes->data; 533d636dbe3SBarry Smith FILE *fd; 53419bcc07fSBarry Smith char *cstr; 53551695f54SLois Curfman McInnes int ierr; 53619bcc07fSBarry Smith ViewerType vtype; 537a935fc98SLois Curfman McInnes 53819bcc07fSBarry Smith ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 53919bcc07fSBarry Smith if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 54090ace30eSBarry Smith ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 54119bcc07fSBarry Smith if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch"; 54219bcc07fSBarry Smith else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch"; 54319bcc07fSBarry Smith else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch"; 54419bcc07fSBarry Smith else cstr = "unknown"; 54577c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," line search variant: %s\n",cstr); 54677c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," alpha=%g, maxstep=%g, steptol=%g\n", 547a935fc98SLois Curfman McInnes ls->alpha,ls->maxstep,ls->steptol); 54819bcc07fSBarry Smith } 549a935fc98SLois Curfman McInnes return 0; 550a935fc98SLois Curfman McInnes } 55152392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5525615d1e5SSatish Balay #undef __FUNC__ 5535615d1e5SSatish Balay #define __FUNC__ "SNESSetFromOptions_EQ_LS" 554f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes) 5555e42470aSBarry Smith { 5565e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5575e42470aSBarry Smith char ver[16]; 5585e42470aSBarry Smith double tmp; 55925cdf11fSBarry Smith int ierr,flg; 5605e42470aSBarry Smith 56109d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr); 56225cdf11fSBarry Smith if (flg) { 5635e42470aSBarry Smith ls->alpha = tmp; 5645e42470aSBarry Smith } 56509d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr); 56625cdf11fSBarry Smith if (flg) { 5675e42470aSBarry Smith ls->maxstep = tmp; 5685e42470aSBarry Smith } 56909d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr); 57025cdf11fSBarry Smith if (flg) { 5715e42470aSBarry Smith ls->steptol = tmp; 5725e42470aSBarry Smith } 57309d61ba7SLois Curfman McInnes ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr); 57425cdf11fSBarry Smith if (flg) { 57548d91487SBarry Smith if (!PetscStrcmp(ver,"basic")) { 57677c4ece6SBarry Smith SNESSetLineSearch(snes,SNESNoLineSearch); 5775e42470aSBarry Smith } 57848d91487SBarry Smith else if (!PetscStrcmp(ver,"quadratic")) { 57977c4ece6SBarry Smith SNESSetLineSearch(snes,SNESQuadraticLineSearch); 5805e42470aSBarry Smith } 58148d91487SBarry Smith else if (!PetscStrcmp(ver,"cubic")) { 58277c4ece6SBarry Smith SNESSetLineSearch(snes,SNESCubicLineSearch); 5835e42470aSBarry Smith } 584e3372554SBarry Smith else {SETERRQ(1,0,"Unknown line search");} 5855e42470aSBarry Smith } 5865e42470aSBarry Smith return 0; 5875e42470aSBarry Smith } 5885e42470aSBarry Smith /* ------------------------------------------------------------ */ 5895615d1e5SSatish Balay #undef __FUNC__ 5905615d1e5SSatish Balay #define __FUNC__ "SNESCreate_EQ_LS" 591f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES snes ) 5925e42470aSBarry Smith { 5935e42470aSBarry Smith SNES_LS *neP; 5945e42470aSBarry Smith 595ddd12767SBarry Smith if (snes->method_class != SNES_NONLINEAR_EQUATIONS) 596e3372554SBarry Smith SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only"); 597f63b844aSLois Curfman McInnes snes->type = SNES_EQ_LS; 598f63b844aSLois Curfman McInnes snes->setup = SNESSetUp_EQ_LS; 599f63b844aSLois Curfman McInnes snes->solve = SNESSolve_EQ_LS; 600f63b844aSLois Curfman McInnes snes->destroy = SNESDestroy_EQ_LS; 601f63b844aSLois Curfman McInnes snes->converged = SNESConverged_EQ_LS; 602f63b844aSLois Curfman McInnes snes->printhelp = SNESPrintHelp_EQ_LS; 603f63b844aSLois Curfman McInnes snes->setfromoptions = SNESSetFromOptions_EQ_LS; 604f63b844aSLois Curfman McInnes snes->view = SNESView_EQ_LS; 6055baf8537SBarry Smith snes->nwork = 0; 6065e42470aSBarry Smith 6070452661fSBarry Smith neP = PetscNew(SNES_LS); CHKPTRQ(neP); 608ff782a9fSLois Curfman McInnes PLogObjectMemory(snes,sizeof(SNES_LS)); 6095e42470aSBarry Smith snes->data = (void *) neP; 6105e42470aSBarry Smith neP->alpha = 1.e-4; 6115e42470aSBarry Smith neP->maxstep = 1.e8; 6125e42470aSBarry Smith neP->steptol = 1.e-12; 6135e42470aSBarry Smith neP->LineSearch = SNESCubicLineSearch; 6145e42470aSBarry Smith return 0; 6155e42470aSBarry Smith } 6165e42470aSBarry Smith 617