15e76c431SBarry Smith #ifndef lint 2*ddd12767SBarry Smith static char vcid[] = "$Id: ls.c,v 1.45 1995/10/01 21:53:32 bsmith Exp bsmith $"; 35e76c431SBarry Smith #endif 45e76c431SBarry Smith 55e76c431SBarry Smith #include <math.h> 6fbe28522SBarry Smith #include "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 275e42470aSBarry Smith int SNESSolve_LS(SNES snes,int *outits) 285e76c431SBarry Smith { 295e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 30761aaf1bSLois Curfman McInnes int maxits, i, history_len, ierr, lits, lsfail; 31df60cc22SBarry Smith MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN; 326b5873e3SBarry Smith double fnorm, gnorm, xnorm, ynorm, *history; 335e42470aSBarry Smith Vec Y, X, F, G, W, TMP; 34336446d4SLois Curfman McInnes SLES sles; 35336446d4SLois Curfman McInnes KSP ksp; 365e76c431SBarry Smith 375e42470aSBarry Smith history = snes->conv_hist; /* convergence history */ 385e42470aSBarry Smith history_len = snes->conv_hist_len; /* 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 4678b31e54SBarry Smith ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr); /* X <- X_0 */ 47393d2d9aSLois Curfman McInnes ierr = VecNorm(X,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 4878b31e54SBarry Smith ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* (+/-) F(X) */ 49393d2d9aSLois Curfman McInnes ierr = VecNorm(F,&fnorm); CHKERRQ(ierr); /* fnorm <- ||F|| */ 505e42470aSBarry Smith snes->norm = fnorm; 515e76c431SBarry Smith if (history && history_len > 0) history[0] = fnorm; 52*ddd12767SBarry Smith if (snes->monitor) {ierr = (*snes->monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);} 535e76c431SBarry Smith 54393d2d9aSLois Curfman McInnes /* Set the KSP stopping criterion to use the Eisenstat-Walker method */ 55336446d4SLois Curfman McInnes if (snes->ksp_ewconv) { 56336446d4SLois Curfman McInnes ierr = SNESGetSLES(snes,&sles); CHKERRQ(ierr); 57336446d4SLois Curfman McInnes ierr = SLESGetKSP(sles,&ksp); CHKERRQ(ierr); 58*ddd12767SBarry Smith ierr = KSPSetConvergenceTest(ksp,SNES_KSP_EW_Converged_Private,(void *)snes); 59*ddd12767SBarry Smith CHKERRQ(ierr); 60336446d4SLois Curfman McInnes } 61336446d4SLois Curfman McInnes 625e76c431SBarry Smith for ( i=0; i<maxits; i++ ) { 635e42470aSBarry Smith snes->iter = i+1; 645e76c431SBarry Smith 655e76c431SBarry Smith /* Solve J Y = -F, where J is Jacobian matrix */ 66*ddd12767SBarry Smith ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg); 67*ddd12767SBarry Smith CHKERRQ(ierr); 68*ddd12767SBarry Smith ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,flg); 69*ddd12767SBarry Smith CHKERRQ(ierr); 7078b31e54SBarry Smith ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr); 7181b6cf68SLois Curfman McInnes ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr); 72*ddd12767SBarry Smith ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail);CHKERRQ(ierr); 73761aaf1bSLois Curfman McInnes if (lsfail) snes->nfailures++; 745e76c431SBarry Smith 7539e2f89bSBarry Smith TMP = F; F = G; snes->vec_func_always = F; G = TMP; 7639e2f89bSBarry Smith TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 775e76c431SBarry Smith fnorm = gnorm; 785e76c431SBarry Smith 795e42470aSBarry Smith snes->norm = fnorm; 805e76c431SBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 81393d2d9aSLois Curfman McInnes ierr = VecNorm(X,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 82*ddd12767SBarry Smith if (snes->monitor) {ierr = (*snes->monitor)(snes,i+1,fnorm,snes->monP);CHKERRQ(ierr);} 835e76c431SBarry Smith 845e76c431SBarry Smith /* Test for convergence */ 85bbb6d6a8SBarry Smith if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) { 8639e2f89bSBarry Smith if (X != snes->vec_sol) { 87393d2d9aSLois Curfman McInnes ierr = VecCopy(X,snes->vec_sol); CHKERRQ(ierr); 8839e2f89bSBarry Smith snes->vec_sol_always = snes->vec_sol; 8939e2f89bSBarry Smith snes->vec_func_always = snes->vec_func; 9039e2f89bSBarry Smith } 915e76c431SBarry Smith break; 925e76c431SBarry Smith } 935e76c431SBarry Smith } 9452392280SLois Curfman McInnes if (i == maxits) { 9552392280SLois Curfman McInnes PLogInfo((PetscObject)snes, 96*ddd12767SBarry Smith "SNESSolve_LS: Maximum number of iterations has been reached: %d\n",maxits); 9752392280SLois Curfman McInnes i--; 9852392280SLois Curfman McInnes } 995e42470aSBarry Smith *outits = i+1; 1005e42470aSBarry Smith return 0; 1015e76c431SBarry Smith } 1025e76c431SBarry Smith /* ------------------------------------------------------------ */ 1035e42470aSBarry Smith int SNESSetUp_LS(SNES snes ) 1045e76c431SBarry Smith { 1055e42470aSBarry Smith int ierr; 10681b6cf68SLois Curfman McInnes snes->nwork = 4; 10778b31e54SBarry Smith ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work); CHKERRQ(ierr); 1085e42470aSBarry Smith PLogObjectParents(snes,snes->nwork,snes->work); 10981b6cf68SLois Curfman McInnes snes->vec_sol_update_always = snes->work[3]; 1105e42470aSBarry Smith return 0; 1115e76c431SBarry Smith } 1125e76c431SBarry Smith /* ------------------------------------------------------------ */ 1135e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj) 1145e76c431SBarry Smith { 1155e42470aSBarry Smith SNES snes = (SNES) obj; 116393d2d9aSLois Curfman McInnes int ierr; 117393d2d9aSLois Curfman McInnes ierr = VecFreeVecs(snes->work,snes->nwork); CHKERRQ(ierr); 11878b31e54SBarry Smith PETSCFREE(snes->data); 1195e42470aSBarry Smith return 0; 1205e76c431SBarry Smith } 1215e76c431SBarry Smith /* ------------------------------------------------------------ */ 1225e76c431SBarry Smith /*ARGSUSED*/ 1234b828684SBarry Smith /*@C 1245e42470aSBarry Smith SNESNoLineSearch - This routine is not a line search at all; 1255e76c431SBarry Smith it simply uses the full Newton step. Thus, this routine is intended 1265e76c431SBarry Smith to serve as a template and is not recommended for general use. 1275e76c431SBarry Smith 1285e76c431SBarry Smith Input Parameters: 1295e42470aSBarry Smith . snes - nonlinear context 1305e76c431SBarry Smith . x - current iterate 1315e76c431SBarry Smith . f - residual evaluated at x 1325e76c431SBarry Smith . y - search direction (contains new iterate on output) 1335e76c431SBarry Smith . w - work vector 1345e76c431SBarry Smith . fnorm - 2-norm of f 1355e76c431SBarry Smith 136c4a48953SLois Curfman McInnes Output Parameters: 1375e76c431SBarry Smith . g - residual evaluated at new iterate y 1385e76c431SBarry Smith . y - new iterate (contains search direction on input) 1395e76c431SBarry Smith . gnorm - 2-norm of g 1405e76c431SBarry Smith . ynorm - 2-norm of search length 141761aaf1bSLois Curfman McInnes . flag - set to 0, indicating a successful line search 1425e76c431SBarry Smith 143c4a48953SLois Curfman McInnes Options Database Key: 144c4a48953SLois Curfman McInnes $ -snes_line_search basic 145c4a48953SLois Curfman McInnes 14628ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 14728ae5a21SLois Curfman McInnes 148f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 149a935fc98SLois Curfman McInnes SNESSetLineSearchRoutine() 1505e76c431SBarry Smith @*/ 1515e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 152761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag ) 1535e76c431SBarry Smith { 1545e42470aSBarry Smith int ierr; 1555e42470aSBarry Smith Scalar one = 1.0; 156761aaf1bSLois Curfman McInnes *flag = 0; 1577857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 158393d2d9aSLois Curfman McInnes ierr = VecNorm(y,ynorm); CHKERRQ(ierr); /* ynorm = || y || */ 159393d2d9aSLois Curfman McInnes ierr = VecAXPY(&one,x,y); CHKERRQ(ierr); /* y <- x + y */ 160393d2d9aSLois Curfman McInnes ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* (+/-) F(y) */ 161393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); CHKERRQ(ierr); /* gnorm = || g || */ 1627857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 163761aaf1bSLois Curfman McInnes return 0; 1645e76c431SBarry Smith } 1655e76c431SBarry Smith /* ------------------------------------------------------------------ */ 1664b828684SBarry Smith /*@C 167f59ffdedSLois Curfman McInnes SNESCubicLineSearch - This routine performs a cubic line search and 168f59ffdedSLois Curfman McInnes is the default line search method. 1695e76c431SBarry Smith 1705e76c431SBarry Smith Input Parameters: 1715e42470aSBarry Smith . snes - nonlinear context 1725e76c431SBarry Smith . x - current iterate 1735e76c431SBarry Smith . f - residual evaluated at x 1745e76c431SBarry Smith . y - search direction (contains new iterate on output) 1755e76c431SBarry Smith . w - work vector 1765e76c431SBarry Smith . fnorm - 2-norm of f 1775e76c431SBarry Smith 178393d2d9aSLois Curfman McInnes Output Parameters: 1795e76c431SBarry Smith . g - residual evaluated at new iterate y 1805e76c431SBarry Smith . y - new iterate (contains search direction on input) 1815e76c431SBarry Smith . gnorm - 2-norm of g 1825e76c431SBarry Smith . ynorm - 2-norm of search length 183761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 1845e76c431SBarry Smith 185c4a48953SLois Curfman McInnes Options Database Key: 186c4a48953SLois Curfman McInnes $ -snes_line_search cubic 187c4a48953SLois Curfman McInnes 1885e76c431SBarry Smith Notes: 1895e76c431SBarry Smith This line search is taken from "Numerical Methods for Unconstrained 1905e76c431SBarry Smith Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 1915e76c431SBarry Smith 19228ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 19328ae5a21SLois Curfman McInnes 194f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine() 1955e76c431SBarry Smith @*/ 1965e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 197761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag) 1985e76c431SBarry Smith { 199*ddd12767SBarry Smith double steptol, initslope,lambdaprev, gnormprev,a, b, d, t1, t2; 200*ddd12767SBarry Smith double maxstep,minlambda,alpha,lambda,lambdatemp; 2016b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 2025e42470aSBarry Smith Scalar cinitslope,clambda; 2036b5873e3SBarry Smith #endif 2045e42470aSBarry Smith int ierr, count; 2055e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 2065e42470aSBarry Smith Scalar one = 1.0,scale; 2075e76c431SBarry Smith 2087857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 209761aaf1bSLois Curfman McInnes *flag = 0; 2105e76c431SBarry Smith alpha = neP->alpha; 2115e76c431SBarry Smith maxstep = neP->maxstep; 2125e76c431SBarry Smith steptol = neP->steptol; 2135e76c431SBarry Smith 214393d2d9aSLois Curfman McInnes ierr = VecNorm(y,ynorm); CHKERRQ(ierr); 2155e76c431SBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 2165e42470aSBarry Smith scale = maxstep/(*ynorm); 2176b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 218*ddd12767SBarry Smith PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Scaling step by %g\n",real(scale)); 2196b5873e3SBarry Smith #else 220*ddd12767SBarry Smith PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Scaling step by %g\n",scale); 2216b5873e3SBarry Smith #endif 222393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 2235e76c431SBarry Smith *ynorm = maxstep; 2245e76c431SBarry Smith } 2255e76c431SBarry Smith minlambda = steptol/(*ynorm); 2265e42470aSBarry Smith #if defined(PETSC_COMPLEX) 227393d2d9aSLois Curfman McInnes ierr = VecDot(f,y,&cinitslope); CHKERRQ(ierr); 2285e42470aSBarry Smith initslope = real(cinitslope); 2295e42470aSBarry Smith #else 230393d2d9aSLois Curfman McInnes VecDot(f,y,&initslope); CHKERRQ(ierr); 2315e42470aSBarry Smith #endif 2325e76c431SBarry Smith if (initslope > 0.0) initslope = -initslope; 2335e76c431SBarry Smith if (initslope == 0.0) initslope = -1.0; 2345e76c431SBarry Smith 235393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 236393d2d9aSLois Curfman McInnes ierr = VecAXPY(&one,x,w); CHKERRQ(ierr); 23778b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 238393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); 2395e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 240393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 2414b828684SBarry Smith PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Using full step\n"); 242d93a2b8dSBarry Smith goto theend; 2435e76c431SBarry Smith } 2445e76c431SBarry Smith 2455e76c431SBarry Smith /* Fit points with quadratic */ 2465e76c431SBarry Smith lambda = 1.0; count = 0; 2475e76c431SBarry Smith lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope)); 2485e76c431SBarry Smith lambdaprev = lambda; 2495e76c431SBarry Smith gnormprev = *gnorm; 250*ddd12767SBarry Smith if (lambdatemp <= .1*lambda) lambda = .1*lambda; 251*ddd12767SBarry Smith else lambda = lambdatemp; 252393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 2535e42470aSBarry Smith #if defined(PETSC_COMPLEX) 254393d2d9aSLois Curfman McInnes clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 2555e42470aSBarry Smith #else 256393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 2575e42470aSBarry Smith #endif 25878b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 259393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 2605e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 261393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 2624b828684SBarry Smith PLogInfo((PetscObject)snes, 2634b828684SBarry Smith "SNESCubicLineSearch: Quadratically determined step, lambda %g\n",lambda); 264d93a2b8dSBarry Smith goto theend; 2655e76c431SBarry Smith } 2665e76c431SBarry Smith 2675e76c431SBarry Smith /* Fit points with cubic */ 2685e76c431SBarry Smith count = 1; 2695e76c431SBarry Smith while (1) { 2705e76c431SBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 2714b828684SBarry Smith PLogInfo((PetscObject)snes, 2724b828684SBarry Smith "SNESCubicLineSearch:Unable to find good step length! %d \n",count); 2734b828684SBarry Smith PLogInfo((PetscObject)snes, 274*ddd12767SBarry Smith "SNESCubicLineSearch:f %g fnew %g ynorm %g lambda %g\n",fnorm,*gnorm,*ynorm,lambda); 275393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 276761aaf1bSLois Curfman McInnes *flag = -1; break; 2775e76c431SBarry Smith } 2785e76c431SBarry Smith t1 = *gnorm - fnorm - lambda*initslope; 2795e76c431SBarry Smith t2 = gnormprev - fnorm - lambdaprev*initslope; 280*ddd12767SBarry Smith a = (t1/(lambda*lambda) - t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2815e76c431SBarry Smith b = (-lambdaprev*t1/(lambda*lambda) + 2825e76c431SBarry Smith lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2835e76c431SBarry Smith d = b*b - 3*a*initslope; 2845e76c431SBarry Smith if (d < 0.0) d = 0.0; 2855e76c431SBarry Smith if (a == 0.0) { 2865e76c431SBarry Smith lambdatemp = -initslope/(2.0*b); 2875e76c431SBarry Smith } else { 2885e76c431SBarry Smith lambdatemp = (-b + sqrt(d))/(3.0*a); 2895e76c431SBarry Smith } 2905e76c431SBarry Smith if (lambdatemp > .5*lambda) { 2915e76c431SBarry Smith lambdatemp = .5*lambda; 2925e76c431SBarry Smith } 2935e76c431SBarry Smith lambdaprev = lambda; 2945e76c431SBarry Smith gnormprev = *gnorm; 2955e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 2965e76c431SBarry Smith lambda = .1*lambda; 2975e76c431SBarry Smith } 2985e76c431SBarry Smith else lambda = lambdatemp; 299393d2d9aSLois Curfman McInnes ierr = VecCopy( x, w ); CHKERRQ(ierr); 3005e42470aSBarry Smith #if defined(PETSC_COMPLEX) 301393d2d9aSLois Curfman McInnes ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 3025e42470aSBarry Smith #else 303393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 3045e42470aSBarry Smith #endif 30578b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 306393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 3075e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* is reduction enough */ 308393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 3094b828684SBarry Smith PLogInfo((PetscObject)snes, 3104b828684SBarry Smith "SNESCubicLineSearch: Cubically determined step, lambda %g\n",lambda); 311761aaf1bSLois Curfman McInnes *flag = -1; break; 3125e76c431SBarry Smith } 3135e76c431SBarry Smith count++; 3145e76c431SBarry Smith } 315d93a2b8dSBarry Smith theend: 3167857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 3175e42470aSBarry Smith return 0; 3185e76c431SBarry Smith } 31952392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 3204b828684SBarry Smith /*@C 3215e42470aSBarry Smith SNESQuadraticLineSearch - This routine performs a cubic line search. 3225e76c431SBarry Smith 3235e42470aSBarry Smith Input Parameters: 324f59ffdedSLois Curfman McInnes . snes - the SNES context 3255e42470aSBarry Smith . x - current iterate 3265e42470aSBarry Smith . f - residual evaluated at x 3275e42470aSBarry Smith . y - search direction (contains new iterate on output) 3285e42470aSBarry Smith . w - work vector 3295e42470aSBarry Smith . fnorm - 2-norm of f 3305e42470aSBarry Smith 331c4a48953SLois Curfman McInnes Output Parameters: 3325e42470aSBarry Smith . g - residual evaluated at new iterate y 3335e42470aSBarry Smith . y - new iterate (contains search direction on input) 3345e42470aSBarry Smith . gnorm - 2-norm of g 3355e42470aSBarry Smith . ynorm - 2-norm of search length 336761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 3375e42470aSBarry Smith 338c4a48953SLois Curfman McInnes Options Database Key: 339c4a48953SLois Curfman McInnes $ -snes_line_search quadratic 340c4a48953SLois Curfman McInnes 3415e42470aSBarry Smith Notes: 342f59ffdedSLois Curfman McInnes Use SNESSetLineSearchRoutine() 343*ddd12767SBarry Smith to set this routine within the SNES_EQ_NLS method. 3445e42470aSBarry Smith 345f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search 346f59ffdedSLois Curfman McInnes 347f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine() 3485e42470aSBarry Smith @*/ 3495e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 350761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag) 3515e76c431SBarry Smith { 352*ddd12767SBarry Smith double steptol,initslope,lambdaprev,gnormprev,maxstep,minlambda,alpha,lambda,lambdatemp; 3536b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 3545e42470aSBarry Smith Scalar cinitslope,clambda; 3556b5873e3SBarry Smith #endif 3565e42470aSBarry Smith int ierr,count; 3575e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 3585e42470aSBarry Smith Scalar one = 1.0,scale; 3595e76c431SBarry Smith 3607857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 361761aaf1bSLois Curfman McInnes *flag = 0; 3625e42470aSBarry Smith alpha = neP->alpha; 3635e42470aSBarry Smith maxstep = neP->maxstep; 3645e42470aSBarry Smith steptol = neP->steptol; 3655e76c431SBarry Smith 3665e42470aSBarry Smith VecNorm(y, ynorm ); 3675e42470aSBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 3685e42470aSBarry Smith scale = maxstep/(*ynorm); 369393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 3705e42470aSBarry Smith *ynorm = maxstep; 3715e76c431SBarry Smith } 3725e42470aSBarry Smith minlambda = steptol/(*ynorm); 3735e42470aSBarry Smith #if defined(PETSC_COMPLEX) 374393d2d9aSLois Curfman McInnes ierr = VecDot(f,y,&cinitslope); CHKERRQ(ierr); 3755e42470aSBarry Smith initslope = real(cinitslope); 3765e42470aSBarry Smith #else 377393d2d9aSLois Curfman McInnes ierr = VecDot(f,y,&initslope); CHKERRQ(ierr); 3785e42470aSBarry Smith #endif 3795e42470aSBarry Smith if (initslope > 0.0) initslope = -initslope; 3805e42470aSBarry Smith if (initslope == 0.0) initslope = -1.0; 3815e42470aSBarry Smith 382393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 383393d2d9aSLois Curfman McInnes ierr = VecAXPY(&one,x,w); CHKERRQ(ierr); 38478b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 385393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 3865e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 387393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 3884b828684SBarry Smith PLogInfo((PetscObject)snes,"SNESQuadraticLineSearch: Using full step\n"); 389d93a2b8dSBarry Smith goto theend; 3905e42470aSBarry Smith } 3915e42470aSBarry Smith 3925e42470aSBarry Smith /* Fit points with quadratic */ 3935e42470aSBarry Smith lambda = 1.0; count = 0; 3945e42470aSBarry Smith count = 1; 3955e42470aSBarry Smith while (1) { 3965e42470aSBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 3974b828684SBarry Smith PLogInfo((PetscObject)snes, 3984b828684SBarry Smith "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 3994b828684SBarry Smith PLogInfo((PetscObject)snes, 400*ddd12767SBarry Smith "SNESQuadraticLineSearch:f %g fnew %g ynorm %g lambda %g\n",fnorm,*gnorm,*ynorm,lambda); 401393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 402761aaf1bSLois Curfman McInnes *flag = -1; break; 4035e42470aSBarry Smith } 4045e42470aSBarry Smith lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope)); 4055e42470aSBarry Smith lambdaprev = lambda; 4065e42470aSBarry Smith gnormprev = *gnorm; 4075e42470aSBarry Smith if (lambdatemp <= .1*lambda) { 4085e42470aSBarry Smith lambda = .1*lambda; 4095e42470aSBarry Smith } else lambda = lambdatemp; 410393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 4115e42470aSBarry Smith #if defined(PETSC_COMPLEX) 412393d2d9aSLois Curfman McInnes clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 4135e42470aSBarry Smith #else 414393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 4155e42470aSBarry Smith #endif 41678b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 417393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 4185e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 419393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 4204b828684SBarry Smith PLogInfo((PetscObject)snes, 421*ddd12767SBarry Smith "SNESQuadraticLineSearch:Quadratically determined step, lambda %g\n",lambda); 42206259719SBarry Smith break; 4235e42470aSBarry Smith } 4245e42470aSBarry Smith count++; 4255e42470aSBarry Smith } 426d93a2b8dSBarry Smith theend: 4277857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 4285e42470aSBarry Smith return 0; 4295e76c431SBarry Smith } 4305e76c431SBarry Smith /* ------------------------------------------------------------ */ 431b1f0a012SBarry Smith /*@ 4325e42470aSBarry Smith SNESSetLineSearchRoutine - Sets the line search routine to be used 433fbe28522SBarry Smith by the method SNES_LS. 4345e76c431SBarry Smith 4355e76c431SBarry Smith Input Parameters: 436eafb4bcbSBarry Smith . snes - nonlinear context obtained from SNESCreate() 4375e76c431SBarry Smith . func - pointer to int function 4385e76c431SBarry Smith 439c4a48953SLois Curfman McInnes Available Routines: 440f59ffdedSLois Curfman McInnes . SNESCubicLineSearch() - default line search 441f59ffdedSLois Curfman McInnes . SNESQuadraticLineSearch() - quadratic line search 442f59ffdedSLois Curfman McInnes . SNESNoLineSearch() - the full Newton step (actually not a line search) 4435e76c431SBarry Smith 444c4a48953SLois Curfman McInnes Options Database Keys: 445c4a48953SLois Curfman McInnes $ -snes_line_search [basic,quadratic,cubic] 446c4a48953SLois Curfman McInnes 4475e76c431SBarry Smith Calling sequence of func: 448f59ffdedSLois Curfman McInnes func (SNES snes, Vec x, Vec f, Vec g, Vec y, 449761aaf1bSLois Curfman McInnes Vec w, double fnorm, double *ynorm, 450761aaf1bSLois Curfman McInnes double *gnorm, *flag) 4515e76c431SBarry Smith 4525e76c431SBarry Smith Input parameters for func: 4535e42470aSBarry Smith . snes - nonlinear context 4545e76c431SBarry Smith . x - current iterate 4555e76c431SBarry Smith . f - residual evaluated at x 4565e76c431SBarry Smith . y - search direction (contains new iterate on output) 4575e76c431SBarry Smith . w - work vector 4585e76c431SBarry Smith . fnorm - 2-norm of f 4595e76c431SBarry Smith 4605e76c431SBarry Smith Output parameters for func: 4615e76c431SBarry Smith . g - residual evaluated at new iterate y 4625e76c431SBarry Smith . y - new iterate (contains search direction on input) 4635e76c431SBarry Smith . gnorm - 2-norm of g 4645e76c431SBarry Smith . ynorm - 2-norm of search length 465761aaf1bSLois Curfman McInnes . flag - set to 0 if the line search succeeds; a nonzero integer 466761aaf1bSLois Curfman McInnes on failure. 467f59ffdedSLois Curfman McInnes 468f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine 469f59ffdedSLois Curfman McInnes 470f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch() 4715e76c431SBarry Smith @*/ 4725e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 473761aaf1bSLois Curfman McInnes double,double *,double*,int*) ) 4745e76c431SBarry Smith { 475*ddd12767SBarry Smith if ((snes)->type == SNES_EQ_NLS) 4765e42470aSBarry Smith ((SNES_LS *)(snes->data))->LineSearch = func; 4775e42470aSBarry Smith return 0; 4785e76c431SBarry Smith } 47952392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 4805e42470aSBarry Smith static int SNESPrintHelp_LS(SNES snes) 4815e42470aSBarry Smith { 4825e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 48352392280SLois Curfman McInnes char *p; 48452392280SLois Curfman McInnes if (snes->prefix) p = snes->prefix; else p = "-"; 48552392280SLois Curfman McInnes MPIU_printf(snes->comm," method ls (system of nonlinear equations):\n"); 48652392280SLois Curfman McInnes MPIU_printf(snes->comm," %ssnes_line_search [basic,quadratic,cubic]\n",p); 48752392280SLois Curfman McInnes MPIU_printf(snes->comm," %ssnes_line_search_alpha alpha (default %g)\n",p,ls->alpha); 48852392280SLois Curfman McInnes MPIU_printf(snes->comm," %ssnes_line_search_maxstep max (default %g)\n",p,ls->maxstep); 48952392280SLois Curfman McInnes MPIU_printf(snes->comm," %ssnes_line_search_steptol tol (default %g)\n",p,ls->steptol); 4906b5873e3SBarry Smith return 0; 4915e42470aSBarry Smith } 49252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 493a935fc98SLois Curfman McInnes static int SNESView_LS(PetscObject obj,Viewer viewer) 494a935fc98SLois Curfman McInnes { 495a935fc98SLois Curfman McInnes SNES snes = (SNES)obj; 496a935fc98SLois Curfman McInnes SNES_LS *ls = (SNES_LS *)snes->data; 497d636dbe3SBarry Smith FILE *fd; 498a935fc98SLois Curfman McInnes char *cstring; 49951695f54SLois Curfman McInnes int ierr; 500a935fc98SLois Curfman McInnes 501a447f0b5SLois Curfman McInnes ierr = ViewerFileGetPointer_Private(viewer,&fd); CHKERRQ(ierr); 502*ddd12767SBarry Smith if (ls->LineSearch == SNESNoLineSearch) cstring = "SNESNoLineSearch"; 503*ddd12767SBarry Smith else if (ls->LineSearch == SNESQuadraticLineSearch) cstring = "SNESQuadraticLineSearch"; 504*ddd12767SBarry Smith else if (ls->LineSearch == SNESCubicLineSearch) cstring = "SNESCubicLineSearch"; 505*ddd12767SBarry Smith else cstring = "unknown"; 506a935fc98SLois Curfman McInnes MPIU_fprintf(snes->comm,fd," line search variant: %s\n",cstring); 507a935fc98SLois Curfman McInnes MPIU_fprintf(snes->comm,fd," alpha=%g, maxstep=%g, steptol=%g\n", 508a935fc98SLois Curfman McInnes ls->alpha,ls->maxstep,ls->steptol); 509a935fc98SLois Curfman McInnes return 0; 510a935fc98SLois Curfman McInnes } 51152392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5125e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes) 5135e42470aSBarry Smith { 5145e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5155e42470aSBarry Smith char ver[16]; 5165e42470aSBarry Smith double tmp; 5175e42470aSBarry Smith 518df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp)) { 5195e42470aSBarry Smith ls->alpha = tmp; 5205e42470aSBarry Smith } 521df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp)) { 5225e42470aSBarry Smith ls->maxstep = tmp; 5235e42470aSBarry Smith } 524df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp)) { 5255e42470aSBarry Smith ls->steptol = tmp; 5265e42470aSBarry Smith } 527df60cc22SBarry Smith if (OptionsGetString(snes->prefix,"-snes_line_search",ver,16)) { 52848d91487SBarry Smith if (!PetscStrcmp(ver,"basic")) { 5295e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESNoLineSearch); 5305e42470aSBarry Smith } 53148d91487SBarry Smith else if (!PetscStrcmp(ver,"quadratic")) { 5325e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch); 5335e42470aSBarry Smith } 53448d91487SBarry Smith else if (!PetscStrcmp(ver,"cubic")) { 5355e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESCubicLineSearch); 5365e42470aSBarry Smith } 5378c48e012SBarry Smith else {SETERRQ(1,"SNESSetFromOptions_LS:Unknown line search");} 5385e42470aSBarry Smith } 5395e42470aSBarry Smith return 0; 5405e42470aSBarry Smith } 5415e42470aSBarry Smith /* ------------------------------------------------------------ */ 5425e42470aSBarry Smith int SNESCreate_LS(SNES snes ) 5435e42470aSBarry Smith { 5445e42470aSBarry Smith SNES_LS *neP; 5455e42470aSBarry Smith 546*ddd12767SBarry Smith if (snes->method_class != SNES_NONLINEAR_EQUATIONS) 547*ddd12767SBarry Smith SETERRQ(1,"SNESCreate_LS:For SNES_NONLINEAR_EQUATIONS only"); 54825c7317fSLois Curfman McInnes snes->type = SNES_EQ_NLS; 54949e3953dSBarry Smith snes->setup = SNESSetUp_LS; 55049e3953dSBarry Smith snes->solve = SNESSolve_LS; 5515e42470aSBarry Smith snes->destroy = SNESDestroy_LS; 552bbb6d6a8SBarry Smith snes->converged = SNESDefaultConverged; 55349e3953dSBarry Smith snes->printhelp = SNESPrintHelp_LS; 55449e3953dSBarry Smith snes->setfromoptions = SNESSetFromOptions_LS; 555a935fc98SLois Curfman McInnes snes->view = SNESView_LS; 5565e42470aSBarry Smith 55778b31e54SBarry Smith neP = PETSCNEW(SNES_LS); CHKPTRQ(neP); 558ff782a9fSLois Curfman McInnes PLogObjectMemory(snes,sizeof(SNES_LS)); 5595e42470aSBarry Smith snes->data = (void *) neP; 5605e42470aSBarry Smith neP->alpha = 1.e-4; 5615e42470aSBarry Smith neP->maxstep = 1.e8; 5625e42470aSBarry Smith neP->steptol = 1.e-12; 5635e42470aSBarry Smith neP->LineSearch = SNESCubicLineSearch; 5645e42470aSBarry Smith return 0; 5655e42470aSBarry Smith } 5665e42470aSBarry Smith 5675e42470aSBarry Smith 5685e42470aSBarry Smith 5695e42470aSBarry Smith 570