15e76c431SBarry Smith #ifndef lint 2*d636dbe3SBarry Smith static char vcid[] = "$Id: ls.c,v 1.40 1995/09/04 17:25:44 bsmith Exp bsmith $"; 35e76c431SBarry Smith #endif 45e76c431SBarry Smith 55e76c431SBarry Smith #include <math.h> 6fbe28522SBarry Smith #include "ls.h" 7b16a3bb1SBarry Smith #include "pinclude/pviewer.h" 8bbb6d6a8SBarry Smith #if defined(HAVE_STRING_H) 9bbb6d6a8SBarry Smith #include <string.h> 10bbb6d6a8SBarry Smith #endif 115e42470aSBarry Smith 125e42470aSBarry Smith /* 135e42470aSBarry Smith Implements a line search variant of Newton's Method 145e76c431SBarry Smith for solving systems of nonlinear equations. 155e76c431SBarry Smith 165e76c431SBarry Smith Input parameters: 175e42470aSBarry Smith . snes - nonlinear context obtained from SNESCreate() 185e76c431SBarry Smith 195e42470aSBarry Smith Output Parameters: 20a935fc98SLois Curfman McInnes . outits - Number of global iterations until termination. 215e76c431SBarry Smith 225e76c431SBarry Smith Notes: 235e76c431SBarry Smith This implements essentially a truncated Newton method with a 245e76c431SBarry Smith line search. By default a cubic backtracking line search 255e76c431SBarry Smith is employed, as described in the text "Numerical Methods for 265e76c431SBarry Smith Unconstrained Optimization and Nonlinear Equations" by Dennis 27393d2d9aSLois Curfman McInnes and Schnabel. 285e76c431SBarry Smith */ 295e76c431SBarry Smith 305e42470aSBarry Smith int SNESSolve_LS(SNES snes,int *outits) 315e76c431SBarry Smith { 325e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 33761aaf1bSLois Curfman McInnes int maxits, i, history_len, ierr, lits, lsfail; 34df60cc22SBarry Smith MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN; 356b5873e3SBarry Smith double fnorm, gnorm, xnorm, ynorm, *history; 365e42470aSBarry Smith Vec Y, X, F, G, W, TMP; 37336446d4SLois Curfman McInnes SLES sles; 38336446d4SLois Curfman McInnes KSP ksp; 395e76c431SBarry Smith 405e42470aSBarry Smith history = snes->conv_hist; /* convergence history */ 415e42470aSBarry Smith history_len = snes->conv_hist_len; /* convergence history length */ 425e42470aSBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 435e42470aSBarry Smith X = snes->vec_sol; /* solution vector */ 4439e2f89bSBarry Smith F = snes->vec_func; /* residual vector */ 455e42470aSBarry Smith Y = snes->work[0]; /* work vectors */ 465e42470aSBarry Smith G = snes->work[1]; 475e42470aSBarry Smith W = snes->work[2]; 485e76c431SBarry Smith 4978b31e54SBarry Smith ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr); /* X <- X_0 */ 50393d2d9aSLois Curfman McInnes ierr = VecNorm(X,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 5178b31e54SBarry Smith ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* (+/-) F(X) */ 52393d2d9aSLois Curfman McInnes ierr = VecNorm(F,&fnorm); CHKERRQ(ierr); /* fnorm <- ||F|| */ 535e42470aSBarry Smith snes->norm = fnorm; 545e76c431SBarry Smith if (history && history_len > 0) history[0] = fnorm; 55bbb6d6a8SBarry Smith if (snes->monitor) 56bbb6d6a8SBarry Smith {ierr = (*snes->monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);} 575e76c431SBarry Smith 58393d2d9aSLois Curfman McInnes /* Set the KSP stopping criterion to use the Eisenstat-Walker method */ 59336446d4SLois Curfman McInnes if (snes->ksp_ewconv) { 60336446d4SLois Curfman McInnes ierr = SNESGetSLES(snes,&sles); CHKERRQ(ierr); 61336446d4SLois Curfman McInnes ierr = SLESGetKSP(sles,&ksp); CHKERRQ(ierr); 62336446d4SLois Curfman McInnes ierr = KSPSetConvergenceTest(ksp,SNES_KSP_EW_Converged_Private, 63336446d4SLois Curfman McInnes (void *)snes); CHKERRQ(ierr); 64336446d4SLois Curfman McInnes } 65336446d4SLois Curfman McInnes 665e76c431SBarry Smith for ( i=0; i<maxits; i++ ) { 675e42470aSBarry Smith snes->iter = i+1; 685e76c431SBarry Smith 695e76c431SBarry Smith /* Solve J Y = -F, where J is Jacobian matrix */ 70df60cc22SBarry Smith ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre, 71bbb6d6a8SBarry Smith &flg); CHKERRQ(ierr); 72a935fc98SLois Curfman McInnes ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre, 73a935fc98SLois Curfman McInnes flg); CHKERRQ(ierr); 7478b31e54SBarry Smith ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERRQ(ierr); 7581b6cf68SLois Curfman McInnes ierr = VecCopy(Y,snes->vec_sol_update_always); CHKERRQ(ierr); 76761aaf1bSLois Curfman McInnes ierr = (*neP->LineSearch)(snes,X,F,G,Y,W,fnorm,&ynorm,&gnorm,&lsfail); 77761aaf1bSLois Curfman McInnes if (lsfail) snes->nfailures++; 7878b31e54SBarry Smith CHKERRQ(ierr); 795e76c431SBarry Smith 8039e2f89bSBarry Smith TMP = F; F = G; snes->vec_func_always = F; G = TMP; 8139e2f89bSBarry Smith TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP; 825e76c431SBarry Smith fnorm = gnorm; 835e76c431SBarry Smith 845e42470aSBarry Smith snes->norm = fnorm; 855e76c431SBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 86393d2d9aSLois Curfman McInnes ierr = VecNorm(X,&xnorm); CHKERRQ(ierr); /* xnorm = || X || */ 87bbb6d6a8SBarry Smith if (snes->monitor) 88393d2d9aSLois Curfman McInnes {ierr = (*snes->monitor)(snes,i+1,fnorm,snes->monP); CHKERRQ(ierr);} 895e76c431SBarry Smith 905e76c431SBarry Smith /* Test for convergence */ 91bbb6d6a8SBarry Smith if ((*snes->converged)(snes,xnorm,ynorm,fnorm,snes->cnvP)) { 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 } 975e76c431SBarry Smith break; 985e76c431SBarry Smith } 995e76c431SBarry Smith } 10052392280SLois Curfman McInnes if (i == maxits) { 10152392280SLois Curfman McInnes PLogInfo((PetscObject)snes, 1024b828684SBarry Smith "SNESSolve_LS: Maximum number of iterations has been reached: %d\n", 1034b828684SBarry Smith maxits); 10452392280SLois Curfman McInnes i--; 10552392280SLois Curfman McInnes } 1065e42470aSBarry Smith *outits = i+1; 1075e42470aSBarry Smith return 0; 1085e76c431SBarry Smith } 1095e76c431SBarry Smith /* ------------------------------------------------------------ */ 1105e42470aSBarry Smith int SNESSetUp_LS(SNES snes ) 1115e76c431SBarry Smith { 1125e42470aSBarry Smith int ierr; 11381b6cf68SLois Curfman McInnes snes->nwork = 4; 11478b31e54SBarry Smith ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work); CHKERRQ(ierr); 1155e42470aSBarry Smith PLogObjectParents(snes,snes->nwork,snes->work); 11681b6cf68SLois Curfman McInnes snes->vec_sol_update_always = snes->work[3]; 1175e42470aSBarry Smith return 0; 1185e76c431SBarry Smith } 1195e76c431SBarry Smith /* ------------------------------------------------------------ */ 1205e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj) 1215e76c431SBarry Smith { 1225e42470aSBarry Smith SNES snes = (SNES) obj; 123393d2d9aSLois Curfman McInnes int ierr; 124393d2d9aSLois Curfman McInnes ierr = VecFreeVecs(snes->work,snes->nwork); CHKERRQ(ierr); 12578b31e54SBarry Smith PETSCFREE(snes->data); 1265e42470aSBarry Smith return 0; 1275e76c431SBarry Smith } 1285e76c431SBarry Smith /* ------------------------------------------------------------ */ 1295e76c431SBarry Smith /*ARGSUSED*/ 1304b828684SBarry Smith /*@C 1315e42470aSBarry Smith SNESNoLineSearch - This routine is not a line search at all; 1325e76c431SBarry Smith it simply uses the full Newton step. Thus, this routine is intended 1335e76c431SBarry Smith to serve as a template and is not recommended for general use. 1345e76c431SBarry Smith 1355e76c431SBarry Smith Input Parameters: 1365e42470aSBarry Smith . snes - nonlinear context 1375e76c431SBarry Smith . x - current iterate 1385e76c431SBarry Smith . f - residual evaluated at x 1395e76c431SBarry Smith . y - search direction (contains new iterate on output) 1405e76c431SBarry Smith . w - work vector 1415e76c431SBarry Smith . fnorm - 2-norm of f 1425e76c431SBarry Smith 143c4a48953SLois Curfman McInnes Output Parameters: 1445e76c431SBarry Smith . g - residual evaluated at new iterate y 1455e76c431SBarry Smith . y - new iterate (contains search direction on input) 1465e76c431SBarry Smith . gnorm - 2-norm of g 1475e76c431SBarry Smith . ynorm - 2-norm of search length 148761aaf1bSLois Curfman McInnes . flag - set to 0, indicating a successful line search 1495e76c431SBarry Smith 150c4a48953SLois Curfman McInnes Options Database Key: 151c4a48953SLois Curfman McInnes $ -snes_line_search basic 152c4a48953SLois Curfman McInnes 15328ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 15428ae5a21SLois Curfman McInnes 155f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESQuadraticLineSearch(), 156a935fc98SLois Curfman McInnes SNESSetLineSearchRoutine() 1575e76c431SBarry Smith @*/ 1585e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 159761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag ) 1605e76c431SBarry Smith { 1615e42470aSBarry Smith int ierr; 1625e42470aSBarry Smith Scalar one = 1.0; 163761aaf1bSLois Curfman McInnes *flag = 0; 1647857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 165393d2d9aSLois Curfman McInnes ierr = VecNorm(y,ynorm); CHKERRQ(ierr); /* ynorm = || y || */ 166393d2d9aSLois Curfman McInnes ierr = VecAXPY(&one,x,y); CHKERRQ(ierr); /* y <- x + y */ 167393d2d9aSLois Curfman McInnes ierr = SNESComputeFunction(snes,y,g); CHKERRQ(ierr); /* (+/-) F(y) */ 168393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); CHKERRQ(ierr); /* gnorm = || g || */ 1697857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 170761aaf1bSLois Curfman McInnes return 0; 1715e76c431SBarry Smith } 1725e76c431SBarry Smith /* ------------------------------------------------------------------ */ 1734b828684SBarry Smith /*@C 174f59ffdedSLois Curfman McInnes SNESCubicLineSearch - This routine performs a cubic line search and 175f59ffdedSLois Curfman McInnes is the default line search method. 1765e76c431SBarry Smith 1775e76c431SBarry Smith Input Parameters: 1785e42470aSBarry Smith . snes - nonlinear context 1795e76c431SBarry Smith . x - current iterate 1805e76c431SBarry Smith . f - residual evaluated at x 1815e76c431SBarry Smith . y - search direction (contains new iterate on output) 1825e76c431SBarry Smith . w - work vector 1835e76c431SBarry Smith . fnorm - 2-norm of f 1845e76c431SBarry Smith 185393d2d9aSLois Curfman McInnes Output Parameters: 1865e76c431SBarry Smith . g - residual evaluated at new iterate y 1875e76c431SBarry Smith . y - new iterate (contains search direction on input) 1885e76c431SBarry Smith . gnorm - 2-norm of g 1895e76c431SBarry Smith . ynorm - 2-norm of search length 190761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 1915e76c431SBarry Smith 192c4a48953SLois Curfman McInnes Options Database Key: 193c4a48953SLois Curfman McInnes $ -snes_line_search cubic 194c4a48953SLois Curfman McInnes 1955e76c431SBarry Smith Notes: 1965e76c431SBarry Smith This line search is taken from "Numerical Methods for Unconstrained 1975e76c431SBarry Smith Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 1985e76c431SBarry Smith 19928ae5a21SLois Curfman McInnes .keywords: SNES, nonlinear, line search, cubic 20028ae5a21SLois Curfman McInnes 201f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine() 2025e76c431SBarry Smith @*/ 2035e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 204761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag) 2055e76c431SBarry Smith { 2065e42470aSBarry Smith double steptol, initslope; 2075e42470aSBarry Smith double lambdaprev, gnormprev; 2085e76c431SBarry Smith double a, b, d, t1, t2; 2096b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 2105e42470aSBarry Smith Scalar cinitslope,clambda; 2116b5873e3SBarry Smith #endif 2125e42470aSBarry Smith int ierr, count; 2135e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 2145e42470aSBarry Smith Scalar one = 1.0,scale; 2155e42470aSBarry Smith double maxstep,minlambda,alpha,lambda,lambdatemp; 2165e76c431SBarry Smith 2177857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 218761aaf1bSLois Curfman McInnes *flag = 0; 2195e76c431SBarry Smith alpha = neP->alpha; 2205e76c431SBarry Smith maxstep = neP->maxstep; 2215e76c431SBarry Smith steptol = neP->steptol; 2225e76c431SBarry Smith 223393d2d9aSLois Curfman McInnes ierr = VecNorm(y,ynorm); CHKERRQ(ierr); 2245e76c431SBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 2255e42470aSBarry Smith scale = maxstep/(*ynorm); 2266b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 2274b828684SBarry Smith PLogInfo((PetscObject)snes, 2284b828684SBarry Smith "SNESCubicLineSearch: Scaling step by %g\n",real(scale)); 2296b5873e3SBarry Smith #else 2304b828684SBarry Smith PLogInfo((PetscObject)snes, 2314b828684SBarry Smith "SNESCubicLineSearch: Scaling step by %g\n",scale); 2326b5873e3SBarry Smith #endif 233393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 2345e76c431SBarry Smith *ynorm = maxstep; 2355e76c431SBarry Smith } 2365e76c431SBarry Smith minlambda = steptol/(*ynorm); 2375e42470aSBarry Smith #if defined(PETSC_COMPLEX) 238393d2d9aSLois Curfman McInnes ierr = VecDot(f,y,&cinitslope); CHKERRQ(ierr); 2395e42470aSBarry Smith initslope = real(cinitslope); 2405e42470aSBarry Smith #else 241393d2d9aSLois Curfman McInnes VecDot(f,y,&initslope); CHKERRQ(ierr); 2425e42470aSBarry Smith #endif 2435e76c431SBarry Smith if (initslope > 0.0) initslope = -initslope; 2445e76c431SBarry Smith if (initslope == 0.0) initslope = -1.0; 2455e76c431SBarry Smith 246393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 247393d2d9aSLois Curfman McInnes ierr = VecAXPY(&one,x,w); CHKERRQ(ierr); 24878b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 249393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); 2505e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 251393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 2524b828684SBarry Smith PLogInfo((PetscObject)snes,"SNESCubicLineSearch: Using full step\n"); 253d93a2b8dSBarry Smith goto theend; 2545e76c431SBarry Smith } 2555e76c431SBarry Smith 2565e76c431SBarry Smith /* Fit points with quadratic */ 2575e76c431SBarry Smith lambda = 1.0; count = 0; 2585e76c431SBarry Smith lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope)); 2595e76c431SBarry Smith lambdaprev = lambda; 2605e76c431SBarry Smith gnormprev = *gnorm; 2615e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 2625e76c431SBarry Smith lambda = .1*lambda; 2635e76c431SBarry Smith } else lambda = lambdatemp; 264393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 2655e42470aSBarry Smith #if defined(PETSC_COMPLEX) 266393d2d9aSLois Curfman McInnes clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 2675e42470aSBarry Smith #else 268393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 2695e42470aSBarry Smith #endif 27078b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 271393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 2725e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 273393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 2744b828684SBarry Smith PLogInfo((PetscObject)snes, 2754b828684SBarry Smith "SNESCubicLineSearch: Quadratically determined step, lambda %g\n",lambda); 276d93a2b8dSBarry Smith goto theend; 2775e76c431SBarry Smith } 2785e76c431SBarry Smith 2795e76c431SBarry Smith /* Fit points with cubic */ 2805e76c431SBarry Smith count = 1; 2815e76c431SBarry Smith while (1) { 2825e76c431SBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 2834b828684SBarry Smith PLogInfo((PetscObject)snes, 2844b828684SBarry Smith "SNESCubicLineSearch:Unable to find good step length! %d \n",count); 2854b828684SBarry Smith PLogInfo((PetscObject)snes, 2864b828684SBarry Smith "SNESCubicLineSearch:f %g fnew %g ynorm %g lambda %g \n", 2875e76c431SBarry Smith fnorm,*gnorm, *ynorm,lambda); 288393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 289761aaf1bSLois Curfman McInnes *flag = -1; break; 2905e76c431SBarry Smith } 2915e76c431SBarry Smith t1 = *gnorm - fnorm - lambda*initslope; 2925e76c431SBarry Smith t2 = gnormprev - fnorm - lambdaprev*initslope; 2935e76c431SBarry Smith a = (t1/(lambda*lambda) - 2945e76c431SBarry Smith t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2955e76c431SBarry Smith b = (-lambdaprev*t1/(lambda*lambda) + 2965e76c431SBarry Smith lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 2975e76c431SBarry Smith d = b*b - 3*a*initslope; 2985e76c431SBarry Smith if (d < 0.0) d = 0.0; 2995e76c431SBarry Smith if (a == 0.0) { 3005e76c431SBarry Smith lambdatemp = -initslope/(2.0*b); 3015e76c431SBarry Smith } else { 3025e76c431SBarry Smith lambdatemp = (-b + sqrt(d))/(3.0*a); 3035e76c431SBarry Smith } 3045e76c431SBarry Smith if (lambdatemp > .5*lambda) { 3055e76c431SBarry Smith lambdatemp = .5*lambda; 3065e76c431SBarry Smith } 3075e76c431SBarry Smith lambdaprev = lambda; 3085e76c431SBarry Smith gnormprev = *gnorm; 3095e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 3105e76c431SBarry Smith lambda = .1*lambda; 3115e76c431SBarry Smith } 3125e76c431SBarry Smith else lambda = lambdatemp; 313393d2d9aSLois Curfman McInnes ierr = VecCopy( x, w ); CHKERRQ(ierr); 3145e42470aSBarry Smith #if defined(PETSC_COMPLEX) 315393d2d9aSLois Curfman McInnes ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 3165e42470aSBarry Smith #else 317393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 3185e42470aSBarry Smith #endif 31978b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 320393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 3215e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* is reduction enough */ 322393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 3234b828684SBarry Smith PLogInfo((PetscObject)snes, 3244b828684SBarry Smith "SNESCubicLineSearch: Cubically determined step, lambda %g\n",lambda); 325761aaf1bSLois Curfman McInnes *flag = -1; break; 3265e76c431SBarry Smith } 3275e76c431SBarry Smith count++; 3285e76c431SBarry Smith } 329d93a2b8dSBarry Smith theend: 3307857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 3315e42470aSBarry Smith return 0; 3325e76c431SBarry Smith } 33352392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 3344b828684SBarry Smith /*@C 3355e42470aSBarry Smith SNESQuadraticLineSearch - This routine performs a cubic line search. 3365e76c431SBarry Smith 3375e42470aSBarry Smith Input Parameters: 338f59ffdedSLois Curfman McInnes . snes - the SNES context 3395e42470aSBarry Smith . x - current iterate 3405e42470aSBarry Smith . f - residual evaluated at x 3415e42470aSBarry Smith . y - search direction (contains new iterate on output) 3425e42470aSBarry Smith . w - work vector 3435e42470aSBarry Smith . fnorm - 2-norm of f 3445e42470aSBarry Smith 345c4a48953SLois Curfman McInnes Output Parameters: 3465e42470aSBarry Smith . g - residual evaluated at new iterate y 3475e42470aSBarry Smith . y - new iterate (contains search direction on input) 3485e42470aSBarry Smith . gnorm - 2-norm of g 3495e42470aSBarry Smith . ynorm - 2-norm of search length 350761aaf1bSLois Curfman McInnes . flag - 0 if line search succeeds; -1 on failure. 3515e42470aSBarry Smith 352c4a48953SLois Curfman McInnes Options Database Key: 353c4a48953SLois Curfman McInnes $ -snes_line_search quadratic 354c4a48953SLois Curfman McInnes 3555e42470aSBarry Smith Notes: 356f59ffdedSLois Curfman McInnes Use SNESSetLineSearchRoutine() 357f59ffdedSLois Curfman McInnes to set this routine within the SNES_NLS method. 3585e42470aSBarry Smith 359f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, quadratic, line search 360f59ffdedSLois Curfman McInnes 361f59ffdedSLois Curfman McInnes .seealso: SNESCubicLineSearch(), SNESNoLineSearch(), SNESSetLineSearchRoutine() 3625e42470aSBarry Smith @*/ 3635e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 364761aaf1bSLois Curfman McInnes double fnorm, double *ynorm, double *gnorm,int *flag) 3655e76c431SBarry Smith { 3665e42470aSBarry Smith double steptol, initslope; 3675e42470aSBarry Smith double lambdaprev, gnormprev; 3686b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 3695e42470aSBarry Smith Scalar cinitslope,clambda; 3706b5873e3SBarry Smith #endif 3715e42470aSBarry Smith int ierr,count; 3725e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 3735e42470aSBarry Smith Scalar one = 1.0,scale; 3745e42470aSBarry Smith double maxstep,minlambda,alpha,lambda,lambdatemp; 3755e76c431SBarry Smith 3767857610eSBarry Smith PLogEventBegin(SNES_LineSearch,snes,x,f,g); 377761aaf1bSLois Curfman McInnes *flag = 0; 3785e42470aSBarry Smith alpha = neP->alpha; 3795e42470aSBarry Smith maxstep = neP->maxstep; 3805e42470aSBarry Smith steptol = neP->steptol; 3815e76c431SBarry Smith 3825e42470aSBarry Smith VecNorm(y, ynorm ); 3835e42470aSBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 3845e42470aSBarry Smith scale = maxstep/(*ynorm); 385393d2d9aSLois Curfman McInnes ierr = VecScale(&scale,y); CHKERRQ(ierr); 3865e42470aSBarry Smith *ynorm = maxstep; 3875e76c431SBarry Smith } 3885e42470aSBarry Smith minlambda = steptol/(*ynorm); 3895e42470aSBarry Smith #if defined(PETSC_COMPLEX) 390393d2d9aSLois Curfman McInnes ierr = VecDot(f,y,&cinitslope); CHKERRQ(ierr); 3915e42470aSBarry Smith initslope = real(cinitslope); 3925e42470aSBarry Smith #else 393393d2d9aSLois Curfman McInnes ierr = VecDot(f,y,&initslope); CHKERRQ(ierr); 3945e42470aSBarry Smith #endif 3955e42470aSBarry Smith if (initslope > 0.0) initslope = -initslope; 3965e42470aSBarry Smith if (initslope == 0.0) initslope = -1.0; 3975e42470aSBarry Smith 398393d2d9aSLois Curfman McInnes ierr = VecCopy(y,w); CHKERRQ(ierr); 399393d2d9aSLois Curfman McInnes ierr = VecAXPY(&one,x,w); CHKERRQ(ierr); 40078b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 401393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 4025e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 403393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 4044b828684SBarry Smith PLogInfo((PetscObject)snes,"SNESQuadraticLineSearch: Using full step\n"); 405d93a2b8dSBarry Smith goto theend; 4065e42470aSBarry Smith } 4075e42470aSBarry Smith 4085e42470aSBarry Smith /* Fit points with quadratic */ 4095e42470aSBarry Smith lambda = 1.0; count = 0; 4105e42470aSBarry Smith count = 1; 4115e42470aSBarry Smith while (1) { 4125e42470aSBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 4134b828684SBarry Smith PLogInfo((PetscObject)snes, 4144b828684SBarry Smith "SNESQuadraticLineSearch:Unable to find good step length! %d \n",count); 4154b828684SBarry Smith PLogInfo((PetscObject)snes, 4164b828684SBarry Smith "SNESQuadraticLineSearch:f %g fnew %g ynorm %g lambda %g \n", 4175e42470aSBarry Smith fnorm,*gnorm, *ynorm,lambda); 418393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 419761aaf1bSLois Curfman McInnes *flag = -1; break; 4205e42470aSBarry Smith } 4215e42470aSBarry Smith lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope)); 4225e42470aSBarry Smith lambdaprev = lambda; 4235e42470aSBarry Smith gnormprev = *gnorm; 4245e42470aSBarry Smith if (lambdatemp <= .1*lambda) { 4255e42470aSBarry Smith lambda = .1*lambda; 4265e42470aSBarry Smith } else lambda = lambdatemp; 427393d2d9aSLois Curfman McInnes ierr = VecCopy(x,w); CHKERRQ(ierr); 4285e42470aSBarry Smith #if defined(PETSC_COMPLEX) 429393d2d9aSLois Curfman McInnes clambda = lambda; ierr = VecAXPY(&clambda,y,w); CHKERRQ(ierr); 4305e42470aSBarry Smith #else 431393d2d9aSLois Curfman McInnes ierr = VecAXPY(&lambda,y,w); CHKERRQ(ierr); 4325e42470aSBarry Smith #endif 43378b31e54SBarry Smith ierr = SNESComputeFunction(snes,w,g); CHKERRQ(ierr); 434393d2d9aSLois Curfman McInnes ierr = VecNorm(g,gnorm); CHKERRQ(ierr); 4355e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 436393d2d9aSLois Curfman McInnes ierr = VecCopy(w,y); CHKERRQ(ierr); 4374b828684SBarry Smith PLogInfo((PetscObject)snes, 4384b828684SBarry Smith "SNESQuadraticLineSearch:Quadratically determined step, lambda %g\n", 4394b828684SBarry Smith lambda); 44006259719SBarry Smith break; 4415e42470aSBarry Smith } 4425e42470aSBarry Smith count++; 4435e42470aSBarry Smith } 444d93a2b8dSBarry Smith theend: 4457857610eSBarry Smith PLogEventEnd(SNES_LineSearch,snes,x,f,g); 4465e42470aSBarry Smith return 0; 4475e76c431SBarry Smith } 4485e76c431SBarry Smith /* ------------------------------------------------------------ */ 449b1f0a012SBarry Smith /*@ 4505e42470aSBarry Smith SNESSetLineSearchRoutine - Sets the line search routine to be used 451fbe28522SBarry Smith by the method SNES_LS. 4525e76c431SBarry Smith 4535e76c431SBarry Smith Input Parameters: 454eafb4bcbSBarry Smith . snes - nonlinear context obtained from SNESCreate() 4555e76c431SBarry Smith . func - pointer to int function 4565e76c431SBarry Smith 457c4a48953SLois Curfman McInnes Available Routines: 458f59ffdedSLois Curfman McInnes . SNESCubicLineSearch() - default line search 459f59ffdedSLois Curfman McInnes . SNESQuadraticLineSearch() - quadratic line search 460f59ffdedSLois Curfman McInnes . SNESNoLineSearch() - the full Newton step (actually not a line search) 4615e76c431SBarry Smith 462c4a48953SLois Curfman McInnes Options Database Keys: 463c4a48953SLois Curfman McInnes $ -snes_line_search [basic,quadratic,cubic] 464c4a48953SLois Curfman McInnes 4655e76c431SBarry Smith Calling sequence of func: 466f59ffdedSLois Curfman McInnes func (SNES snes, Vec x, Vec f, Vec g, Vec y, 467761aaf1bSLois Curfman McInnes Vec w, double fnorm, double *ynorm, 468761aaf1bSLois Curfman McInnes double *gnorm, *flag) 4695e76c431SBarry Smith 4705e76c431SBarry Smith Input parameters for func: 4715e42470aSBarry Smith . snes - nonlinear context 4725e76c431SBarry Smith . x - current iterate 4735e76c431SBarry Smith . f - residual evaluated at x 4745e76c431SBarry Smith . y - search direction (contains new iterate on output) 4755e76c431SBarry Smith . w - work vector 4765e76c431SBarry Smith . fnorm - 2-norm of f 4775e76c431SBarry Smith 4785e76c431SBarry Smith Output parameters for func: 4795e76c431SBarry Smith . g - residual evaluated at new iterate y 4805e76c431SBarry Smith . y - new iterate (contains search direction on input) 4815e76c431SBarry Smith . gnorm - 2-norm of g 4825e76c431SBarry Smith . ynorm - 2-norm of search length 483761aaf1bSLois Curfman McInnes . flag - set to 0 if the line search succeeds; a nonzero integer 484761aaf1bSLois Curfman McInnes on failure. 485f59ffdedSLois Curfman McInnes 486f59ffdedSLois Curfman McInnes .keywords: SNES, nonlinear, set, line search, routine 487f59ffdedSLois Curfman McInnes 488f59ffdedSLois Curfman McInnes .seealso: SNESNoLineSearch(), SNESQuadraticLineSearch(), SNESCubicLineSearch() 4895e76c431SBarry Smith @*/ 4905e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 491761aaf1bSLois Curfman McInnes double,double *,double*,int*) ) 4925e76c431SBarry Smith { 493fbe28522SBarry Smith if ((snes)->type == SNES_NLS) 4945e42470aSBarry Smith ((SNES_LS *)(snes->data))->LineSearch = func; 4955e42470aSBarry Smith return 0; 4965e76c431SBarry Smith } 49752392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 4985e42470aSBarry Smith static int SNESPrintHelp_LS(SNES snes) 4995e42470aSBarry Smith { 5005e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 50152392280SLois Curfman McInnes char *p; 50252392280SLois Curfman McInnes if (snes->prefix) p = snes->prefix; else p = "-"; 50352392280SLois Curfman McInnes MPIU_printf(snes->comm," method ls (system of nonlinear equations):\n"); 50452392280SLois Curfman McInnes MPIU_printf(snes->comm," %ssnes_line_search [basic,quadratic,cubic]\n",p); 50552392280SLois Curfman McInnes MPIU_printf(snes->comm," %ssnes_line_search_alpha alpha (default %g)\n",p,ls->alpha); 50652392280SLois Curfman McInnes MPIU_printf(snes->comm," %ssnes_line_search_maxstep max (default %g)\n",p,ls->maxstep); 50752392280SLois Curfman McInnes MPIU_printf(snes->comm," %ssnes_line_search_steptol tol (default %g)\n",p,ls->steptol); 5086b5873e3SBarry Smith return 0; 5095e42470aSBarry Smith } 51052392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 511a935fc98SLois Curfman McInnes static int SNESView_LS(PetscObject obj,Viewer viewer) 512a935fc98SLois Curfman McInnes { 513a935fc98SLois Curfman McInnes SNES snes = (SNES)obj; 514a935fc98SLois Curfman McInnes SNES_LS *ls = (SNES_LS *)snes->data; 515*d636dbe3SBarry Smith FILE *fd; 516a935fc98SLois Curfman McInnes char *cstring; 517a935fc98SLois Curfman McInnes 518*d636dbe3SBarry Smith ierr = ViewerFileGetPointer_Private(viewer,&fd); CHKERRQ(ierr): 519a935fc98SLois Curfman McInnes if (ls->LineSearch == SNESNoLineSearch) 520a935fc98SLois Curfman McInnes cstring = "SNESNoLineSearch"; 521a935fc98SLois Curfman McInnes else if (ls->LineSearch == SNESQuadraticLineSearch) 522a935fc98SLois Curfman McInnes cstring = "SNESQuadraticLineSearch"; 523a935fc98SLois Curfman McInnes else if (ls->LineSearch == SNESCubicLineSearch) 524a935fc98SLois Curfman McInnes cstring = "SNESCubicLineSearch"; 525a935fc98SLois Curfman McInnes else 526a935fc98SLois Curfman McInnes cstring = "unknown"; 527a935fc98SLois Curfman McInnes MPIU_fprintf(snes->comm,fd," line search variant: %s\n",cstring); 528a935fc98SLois Curfman McInnes MPIU_fprintf(snes->comm,fd," alpha=%g, maxstep=%g, steptol=%g\n", 529a935fc98SLois Curfman McInnes ls->alpha,ls->maxstep,ls->steptol); 530a935fc98SLois Curfman McInnes return 0; 531a935fc98SLois Curfman McInnes } 53252392280SLois Curfman McInnes /* ------------------------------------------------------------------ */ 5335e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes) 5345e42470aSBarry Smith { 5355e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5365e42470aSBarry Smith char ver[16]; 5375e42470aSBarry Smith double tmp; 5385e42470aSBarry Smith 539df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-snes_line_search_alpa",&tmp)) { 5405e42470aSBarry Smith ls->alpha = tmp; 5415e42470aSBarry Smith } 542df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-snes_line_search_maxstep",&tmp)) { 5435e42470aSBarry Smith ls->maxstep = tmp; 5445e42470aSBarry Smith } 545df60cc22SBarry Smith if (OptionsGetDouble(snes->prefix,"-snes_line_search_steptol",&tmp)) { 5465e42470aSBarry Smith ls->steptol = tmp; 5475e42470aSBarry Smith } 548df60cc22SBarry Smith if (OptionsGetString(snes->prefix,"-snes_line_search",ver,16)) { 5495e42470aSBarry Smith if (!strcmp(ver,"basic")) { 5505e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESNoLineSearch); 5515e42470aSBarry Smith } 5525e42470aSBarry Smith else if (!strcmp(ver,"quadratic")) { 5535e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch); 5545e42470aSBarry Smith } 5555e42470aSBarry Smith else if (!strcmp(ver,"cubic")) { 5565e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESCubicLineSearch); 5575e42470aSBarry Smith } 5588c48e012SBarry Smith else {SETERRQ(1,"SNESSetFromOptions_LS: Unknown line search");} 5595e42470aSBarry Smith } 5605e42470aSBarry Smith return 0; 5615e42470aSBarry Smith } 5625e42470aSBarry Smith /* ------------------------------------------------------------ */ 5635e42470aSBarry Smith int SNESCreate_LS(SNES snes ) 5645e42470aSBarry Smith { 5655e42470aSBarry Smith SNES_LS *neP; 5665e42470aSBarry Smith 5671a3481a4SLois Curfman McInnes if (snes->method_class != SNES_NONLINEAR_EQUATIONS) SETERRQ(1, 5681a3481a4SLois Curfman McInnes "SNESCreate_LS: Valid for SNES_NONLINEAR_EQUATIONS problems only"); 56925c7317fSLois Curfman McInnes snes->type = SNES_EQ_NLS; 57049e3953dSBarry Smith snes->setup = SNESSetUp_LS; 57149e3953dSBarry Smith snes->solve = SNESSolve_LS; 5725e42470aSBarry Smith snes->destroy = SNESDestroy_LS; 573bbb6d6a8SBarry Smith snes->converged = SNESDefaultConverged; 57449e3953dSBarry Smith snes->printhelp = SNESPrintHelp_LS; 57549e3953dSBarry Smith snes->setfromoptions = SNESSetFromOptions_LS; 576a935fc98SLois Curfman McInnes snes->view = SNESView_LS; 5775e42470aSBarry Smith 57878b31e54SBarry Smith neP = PETSCNEW(SNES_LS); CHKPTRQ(neP); 579ff782a9fSLois Curfman McInnes PLogObjectMemory(snes,sizeof(SNES_LS)); 5805e42470aSBarry Smith snes->data = (void *) neP; 5815e42470aSBarry Smith neP->alpha = 1.e-4; 5825e42470aSBarry Smith neP->maxstep = 1.e8; 5835e42470aSBarry Smith neP->steptol = 1.e-12; 5845e42470aSBarry Smith neP->LineSearch = SNESCubicLineSearch; 5855e42470aSBarry Smith return 0; 5865e42470aSBarry Smith } 5875e42470aSBarry Smith 5885e42470aSBarry Smith 5895e42470aSBarry Smith 5905e42470aSBarry Smith 591