15e76c431SBarry Smith #ifndef lint 2*912ebf9aSLois Curfman McInnes static char vcid[] = "$Id: ls.c,v 1.86 1997/02/22 02:28:49 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 */ 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 */ 29094a424c1SBarry Smith PLogInfo(snes, 2914b828684SBarry Smith "SNESCubicLineSearch:Unable to find good step length! %d \n",count); 29294a424c1SBarry Smith PLogInfo(snes, 293ea4d3ed3SLois Curfman McInnes "SNESCubicLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 294ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 295393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 296761aaf1bSLois Curfman McInnes *flag = -1; break; 2975e76c431SBarry Smith } 2985e76c431SBarry Smith t1 = *gnorm - fnorm - lambda*initslope; 2995e76c431SBarry Smith t2 = gnormprev - fnorm - lambdaprev*initslope; 300ddd12767SBarry Smith a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 3015e76c431SBarry Smith b = (-lambdaprev*t1/(lambda*lambda) + 3025e76c431SBarry Smith lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 3035e76c431SBarry Smith d = b*b - 3*a*initslope; 3045e76c431SBarry Smith if (d < 0.0) d = 0.0; 3055e76c431SBarry Smith if (a == 0.0) { 3065e76c431SBarry Smith lambdatemp = -initslope/(2.0*b); 3075e76c431SBarry Smith } else { 3085e76c431SBarry Smith lambdatemp = (-b + sqrt(d))/(3.0*a); 3095e76c431SBarry Smith } 3105e76c431SBarry Smith if (lambdatemp > .5*lambda) { 3115e76c431SBarry Smith lambdatemp = .5*lambda; 3125e76c431SBarry Smith } 3135e76c431SBarry Smith lambdaprev = lambda; 3145e76c431SBarry Smith gnormprev = *gnorm; 3155e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 3165e76c431SBarry Smith lambda = .1*lambda; 3175e76c431SBarry Smith } 3185e76c431SBarry Smith else lambda = lambdatemp; 319393d2d9aSLois Curfman McInnes ierr = VecCopy( x, w ); CHKERRQ(ierr); 320ea4d3ed3SLois Curfman McInnes lambdaneg = -lambda; 3215e42470aSBarry Smith #if defined(PETSC_COMPLEX) 322ea4d3ed3SLois Curfman McInnes clambda = lambdaneg; 323393d2d9aSLois Curfman McInnes ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 3245e42470aSBarry Smith #else 325ea4d3ed3SLois Curfman McInnes ierr = VecAXPY(&lambdaneg,y,w); CHKERRQ(ierr); 3265e42470aSBarry Smith #endif 32778b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 328cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 3295e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* is reduction enough */ 330393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 331ea4d3ed3SLois Curfman McInnes PLogInfo(snes,"SNESCubicLineSearch: Cubically determined step, lambda=%g\n",lambda); 332761aaf1bSLois Curfman McInnes *flag = -1; break; 3335e76c431SBarry Smith } 3345e76c431SBarry Smith count++; 3355e76c431SBarry Smith } 336ad922ac9SBarry Smith theend1: 3377857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 3385e42470aSBarry Smith return 0; 3395e76c431SBarry Smith } 34052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 3415615d1e5SSatish Balay #undef __FUNC__ 3425615d1e5SSatish Balay #define __FUNC__ "SNESQuadraticLineSearch" 3434b828684SBarry Smith /*@C 344f525115eSLois Curfman McInnes SNESQuadraticLineSearch - Performs a quadratic line search. 3455e76c431SBarry Smith 3465e42470aSBarry Smith Input Parameters: 347f59ffdedSLois Curfman McInnes . snes - the SNES context 3485e42470aSBarry Smith . x - current iterate 3495e42470aSBarry Smith . f - residual evaluated at x 3505e42470aSBarry Smith . y - search direction (contains new iterate on output) 3515e42470aSBarry Smith . w - work vector 3525e42470aSBarry Smith . fnorm - 2-norm of f 3535e42470aSBarry Smith 354c4a48953SLois Curfman McInnes Output Parameters: 3555e42470aSBarry Smith . g - residual evaluated at new iterate y 3565e42470aSBarry Smith . y - new iterate (contains search direction on input) 3575e42470aSBarry Smith . gnorm - 2-norm of g 3585e42470aSBarry Smith . ynorm - 2-norm of search length 359761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 3605e42470aSBarry Smith 361c4a48953SLois Curfman McInnes Options Database Key: 36209d61ba7SLois Curfman McInnes $ -snes_eq_ls quadratic 363c4a48953SLois Curfman McInnes 3645e42470aSBarry Smith Notes: 36577c4ece6SBarry Smith Use SNESSetLineSearch() 366f63b844aSLois Curfman McInnes to set this routine within the SNES_EQ_LS method. 3675e42470aSBarry Smith 368f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search 369f59ffdedSLois Curfman McInnes 37077c4ece6SBarry Smith .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearch() 3715e42470aSBarry Smith @*/ 3725e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 373761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag) 3745e76c431SBarry Smith { 375ddd12767SBarry Smith double steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp; 3766b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 3775e42470aSBarry Smith Scalar cinitslope,clambda; 3786b5873e3SBarry Smith #endif 3795e42470aSBarry Smith int ierr,count; 3805e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 3815334005bSBarry Smith Scalar mone = -1.0,scale; 3825e76c431SBarry Smith 3837857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 384761aaf1bSLois Curfman McInnes *flag = 0; 3855e42470aSBarry Smith alpha = neP->alpha; 3865e42470aSBarry Smith maxstep = neP->maxstep; 3875e42470aSBarry Smith steptol = neP->steptol; 3885e76c431SBarry Smith 389cddf8d76SBarry Smith VecNorm(y, NORM_2,ynorm ); 39094a9d846SBarry Smith if (*ynorm == 0.0) { 39194a9d846SBarry Smith PLogInfo(snes,"SNESQuadraticLineSearch: Search direction and size is 0\n"); 392ad922ac9SBarry Smith goto theend2; 39394a9d846SBarry Smith } 3945e42470aSBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 3955e42470aSBarry Smith scale = maxstep/(*ynorm); 396393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 3975e42470aSBarry Smith *ynorm = maxstep; 3985e76c431SBarry Smith } 3995e42470aSBarry Smith minlambda = steptol/(*ynorm); 400a703fe33SLois Curfman McInnes ierr = MatMult(snes->jacobian,y,w); CHKERRQ(ierr); 4015e42470aSBarry Smith #if defined(PETSC_COMPLEX) 402a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&cinitslope); CHKERRQ(ierr); 4035e42470aSBarry Smith initslope = real(cinitslope); 4045e42470aSBarry Smith #else 405a703fe33SLois Curfman McInnes ierr = VecDot(f,w,&initslope); CHKERRQ(ierr); 4065e42470aSBarry Smith #endif 4075e42470aSBarry Smith if (initslope > 0.0) initslope = -initslope; 4085e42470aSBarry Smith if (initslope == 0.0) initslope = -1.0; 4095e42470aSBarry Smith 410393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 4115334005bSBarry Smith ierr = VecAYPX(&mone,x,w); CHKERRQ(ierr); 41278b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 413cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 4145e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 415393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 41694a424c1SBarry Smith PLogInfo(snes,"SNESQuadraticLineSearch: Using full step\n"); 417ad922ac9SBarry Smith goto theend2; 4185e42470aSBarry Smith } 4195e42470aSBarry Smith 4205e42470aSBarry Smith /* Fit points with quadratic */ 4215e42470aSBarry Smith lambda = 1.0; count = 0; 4225e42470aSBarry Smith count = 1; 4235e42470aSBarry Smith while (1) { 4245e42470aSBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 42594a424c1SBarry Smith PLogInfo(snes, 4264b828684SBarry Smith "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 42794a424c1SBarry Smith PLogInfo(snes, 428ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:fnorm=%g, gnorm=%g, ynorm=%g, lambda=%g, initial slope=%g\n", 429ea4d3ed3SLois Curfman McInnes fnorm,*gnorm,*ynorm,lambda,initslope); 430393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 431761aaf1bSLois Curfman McInnes *flag = -1; break; 4325e42470aSBarry Smith } 433a703fe33SLois Curfman McInnes lambdatemp = -initslope/((*gnorm)*(*gnorm) - fnorm*fnorm - 2.0*initslope); 4345e42470aSBarry Smith lambdaprev = lambda; 4355e42470aSBarry Smith gnormprev = *gnorm; 4365e42470aSBarry Smith if (lambdatemp <= .1*lambda) { 4375e42470aSBarry Smith lambda = .1*lambda; 4385e42470aSBarry Smith } else lambda = lambdatemp; 439393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 4405334005bSBarry Smith lambda = -lambda; 4415e42470aSBarry Smith #if defined(PETSC_COMPLEX) 442393d2d9aSLois Curfman McInnes clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 4435e42470aSBarry Smith #else 444393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 4455e42470aSBarry Smith #endif 44678b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 447cddf8d76SBarry Smith ierr = VecNorm(g,NORM_2,gnorm); CHKERRQ(ierr); 4485e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 449393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 45094a424c1SBarry Smith PLogInfo(snes, 451ea4d3ed3SLois Curfman McInnes "SNESQuadraticLineSearch:Quadratically determined step, lambda=%g\n",lambda); 45206259719SBarry Smith break; 4535e42470aSBarry Smith } 4545e42470aSBarry Smith count++; 4555e42470aSBarry Smith } 456ad922ac9SBarry Smith theend2: 4577857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 4585e42470aSBarry Smith return 0; 4595e76c431SBarry Smith } 4605e76c431SBarry Smith /* ------------------------------------------------------------ */ 4615615d1e5SSatish Balay #undef __FUNC__ 4625eea60f9SBarry Smith #define __FUNC__ "SNESSetLineSearch" /* ADIC Ignore */ 463c9e6a524SLois Curfman McInnes /*@C 46477c4ece6SBarry Smith SNESSetLineSearch - Sets the line search routine to be used 465f63b844aSLois Curfman McInnes by the method SNES_EQ_LS. 4665e76c431SBarry Smith 4675e76c431SBarry Smith Input Parameters: 468eafb4bcbSBarry Smith . snes - nonlinear context obtained from SNESCreate() 4695e76c431SBarry Smith . func - pointer to int function 4705e76c431SBarry Smith 471c4a48953SLois Curfman McInnes Available Routines: 472f59ffdedSLois Curfman McInnes . SNESCubicLineSearch() - default line search 473f59ffdedSLois Curfman McInnes . SNESQuadraticLineSearch() - quadratic line search 474f59ffdedSLois Curfman McInnes . SNESNoLineSearch() - the full Newton step (actually not a line search) 4755e76c431SBarry Smith 476c4a48953SLois Curfman McInnes Options Database Keys: 47709d61ba7SLois Curfman McInnes $ -snes_eq_ls [basic,quadratic,cubic] 478*912ebf9aSLois Curfman McInnes $ -snes_eq_ls_alpha <alpha> 479*912ebf9aSLois Curfman McInnes $ -snes_eq_ls_maxstep <max> 480*912ebf9aSLois Curfman McInnes $ -snes_eq_ls_steptol <steptol> 481c4a48953SLois Curfman McInnes 4825e76c431SBarry Smith Calling sequence of func: 483f59ffdedSLois Curfman McInnes func (SNES snes, Vec x, Vec f, Vec g, Vec y, 484761aaf1bSLois Curfman McInnes Vec w, double fnorm, double *ynorm, 485761aaf1bSLois Curfman McInnes double *gnorm, *flag) 4865e76c431SBarry Smith 4875e76c431SBarry Smith Input parameters for func: 4885e42470aSBarry Smith . snes - nonlinear context 4895e76c431SBarry Smith . x - current iterate 4905e76c431SBarry Smith . f - residual evaluated at x 4915e76c431SBarry Smith . y - search direction (contains new iterate on output) 4925e76c431SBarry Smith . w - work vector 4935e76c431SBarry Smith . fnorm - 2-norm of f 4945e76c431SBarry Smith 4955e76c431SBarry Smith Output parameters for func: 4965e76c431SBarry Smith . g - residual evaluated at new iterate y 4975e76c431SBarry Smith . y - new iterate (contains search direction on input) 4985e76c431SBarry Smith . gnorm - 2-norm of g 4995e76c431SBarry Smith . ynorm - 2-norm of search length 500761aaf1bSLois Curfman McInnes . flag - set to 0 if the line search succeeds; a nonzero integer 501761aaf1bSLois Curfman McInnes on failure. 502f59ffdedSLois Curfman McInnes 503f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine 504f59ffdedSLois Curfman McInnes 505f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch() 5065e76c431SBarry Smith @*/ 50777c4ece6SBarry Smith int SNESSetLineSearch(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 508761aaf1bSLois Curfman McInnes double,double*,double*,int*)) 5095e76c431SBarry Smith { 510f63b844aSLois Curfman McInnes if ((snes)->type == SNES_EQ_LS) ((SNES_LS *)(snes->data))->LineSearch = func; 5115e42470aSBarry Smith return 0; 5125e76c431SBarry Smith } 51352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5145615d1e5SSatish Balay #undef __FUNC__ 5155eea60f9SBarry Smith #define __FUNC__ "SNESPrintHelp_EQ_LS" /* ADIC Ignore */ 516f63b844aSLois Curfman McInnes static int SNESPrintHelp_EQ_LS(SNES snes,char *p) 5175e42470aSBarry Smith { 5185e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5196daaf66cSBarry Smith 520f63b844aSLois Curfman McInnes PetscPrintf(snes->comm," method SNES_EQ_LS (ls) for systems of nonlinear equations:\n"); 52109d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls [basic,quadratic,cubic]\n",p); 52209d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_alpha <alpha> (default %g)\n",p,ls->alpha); 52309d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_maxstep <max> (default %g)\n",p,ls->maxstep); 52409d61ba7SLois Curfman McInnes PetscPrintf(snes->comm," %ssnes_eq_ls_steptol <tol> (default %g)\n",p,ls->steptol); 5256b5873e3SBarry Smith return 0; 5265e42470aSBarry Smith } 52752392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5285615d1e5SSatish Balay #undef __FUNC__ 5295eea60f9SBarry Smith #define __FUNC__ "SNESView_EQ_LS" /* ADIC Ignore */ 530f63b844aSLois Curfman McInnes static int SNESView_EQ_LS(PetscObject obj,Viewer viewer) 531a935fc98SLois Curfman McInnes { 532a935fc98SLois Curfman McInnes SNES snes = (SNES)obj; 533a935fc98SLois Curfman McInnes SNES_LS *ls = (SNES_LS *)snes->data; 534d636dbe3SBarry Smith FILE *fd; 53519bcc07fSBarry Smith char *cstr; 53651695f54SLois Curfman McInnes int ierr; 53719bcc07fSBarry Smith ViewerType vtype; 538a935fc98SLois Curfman McInnes 53919bcc07fSBarry Smith ierr = ViewerGetType(viewer,&vtype); CHKERRQ(ierr); 54019bcc07fSBarry Smith if (vtype == ASCII_FILE_VIEWER || vtype == ASCII_FILES_VIEWER) { 54190ace30eSBarry Smith ierr = ViewerASCIIGetPointer(viewer,&fd); CHKERRQ(ierr); 54219bcc07fSBarry Smith if (ls->LineSearch == SNESNoLineSearch) cstr = "SNESNoLineSearch"; 54319bcc07fSBarry Smith else if (ls->LineSearch == SNESQuadraticLineSearch) cstr = "SNESQuadraticLineSearch"; 54419bcc07fSBarry Smith else if (ls->LineSearch == SNESCubicLineSearch) cstr = "SNESCubicLineSearch"; 54519bcc07fSBarry Smith else cstr = "unknown"; 54677c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," line search variant: %s\n",cstr); 54777c4ece6SBarry Smith PetscFPrintf(snes->comm,fd," alpha=%g, maxstep=%g, steptol=%g\n", 548a935fc98SLois Curfman McInnes ls->alpha,ls->maxstep,ls->steptol); 54919bcc07fSBarry Smith } 550a935fc98SLois Curfman McInnes return 0; 551a935fc98SLois Curfman McInnes } 55252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5535615d1e5SSatish Balay #undef __FUNC__ 5545615d1e5SSatish Balay #define __FUNC__ "SNESSetFromOptions_EQ_LS" 555f63b844aSLois Curfman McInnes static int SNESSetFromOptions_EQ_LS(SNES snes) 5565e42470aSBarry Smith { 5575e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5585e42470aSBarry Smith char ver[16]; 5595e42470aSBarry Smith double tmp; 56025cdf11fSBarry Smith int ierr,flg; 5615e42470aSBarry Smith 56209d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_alpha",&tmp, &flg);CHKERRQ(ierr); 56325cdf11fSBarry Smith if (flg) { 5645e42470aSBarry Smith ls->alpha = tmp; 5655e42470aSBarry Smith } 56609d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_maxstep",&tmp, &flg);CHKERRQ(ierr); 56725cdf11fSBarry Smith if (flg) { 5685e42470aSBarry Smith ls->maxstep = tmp; 5695e42470aSBarry Smith } 57009d61ba7SLois Curfman McInnes ierr = OptionsGetDouble(snes->prefix,"-snes_eq_ls_steptol",&tmp, &flg);CHKERRQ(ierr); 57125cdf11fSBarry Smith if (flg) { 5725e42470aSBarry Smith ls->steptol = tmp; 5735e42470aSBarry Smith } 57409d61ba7SLois Curfman McInnes ierr = OptionsGetString(snes->prefix,"-snes_eq_ls",ver,16, &flg); CHKERRQ(ierr); 57525cdf11fSBarry Smith if (flg) { 57648d91487SBarry Smith if (!PetscStrcmp(ver,"basic")) { 57777c4ece6SBarry Smith SNESSetLineSearch(snes,SNESNoLineSearch); 5785e42470aSBarry Smith } 57948d91487SBarry Smith else if (!PetscStrcmp(ver,"quadratic")) { 58077c4ece6SBarry Smith SNESSetLineSearch(snes,SNESQuadraticLineSearch); 5815e42470aSBarry Smith } 58248d91487SBarry Smith else if (!PetscStrcmp(ver,"cubic")) { 58377c4ece6SBarry Smith SNESSetLineSearch(snes,SNESCubicLineSearch); 5845e42470aSBarry Smith } 585e3372554SBarry Smith else {SETERRQ(1,0,"Unknown line search");} 5865e42470aSBarry Smith } 5875e42470aSBarry Smith return 0; 5885e42470aSBarry Smith } 5895e42470aSBarry Smith /* ------------------------------------------------------------ */ 5905615d1e5SSatish Balay #undef __FUNC__ 5915615d1e5SSatish Balay #define __FUNC__ "SNESCreate_EQ_LS" 592f63b844aSLois Curfman McInnes int SNESCreate_EQ_LS(SNES snes ) 5935e42470aSBarry Smith { 5945e42470aSBarry Smith SNES_LS *neP; 5955e42470aSBarry Smith 596ddd12767SBarry Smith if (snes->method_class != SNES_NONLINEAR_EQUATIONS) 597e3372554SBarry Smith SETERRQ(1,0,"For SNES_NONLINEAR_EQUATIONS only"); 598f63b844aSLois Curfman McInnes snes->type = SNES_EQ_LS; 599f63b844aSLois Curfman McInnes snes->setup = SNESSetUp_EQ_LS; 600f63b844aSLois Curfman McInnes snes->solve = SNESSolve_EQ_LS; 601f63b844aSLois Curfman McInnes snes->destroy = SNESDestroy_EQ_LS; 602f63b844aSLois Curfman McInnes snes->converged = SNESConverged_EQ_LS; 603f63b844aSLois Curfman McInnes snes->printhelp = SNESPrintHelp_EQ_LS; 604f63b844aSLois Curfman McInnes snes->setfromoptions = SNESSetFromOptions_EQ_LS; 605f63b844aSLois Curfman McInnes snes->view = SNESView_EQ_LS; 6065baf8537SBarry Smith snes->nwork = 0; 6075e42470aSBarry Smith 6080452661fSBarry Smith neP = PetscNew(SNES_LS); CHKPTRQ(neP); 609ff782a9fSLois Curfman McInnes PLogObjectMemory(snes,sizeof(SNES_LS)); 6105e42470aSBarry Smith snes->data = (void *) neP; 6115e42470aSBarry Smith neP->alpha = 1.e-4; 6125e42470aSBarry Smith neP->maxstep = 1.e8; 6135e42470aSBarry Smith neP->steptol = 1.e-12; 6145e42470aSBarry Smith neP->LineSearch = SNESCubicLineSearch; 6155e42470aSBarry Smith return 0; 6165e42470aSBarry Smith } 6175e42470aSBarry Smith 618