15e76c431SBarry Smith #ifndef lint 2*6b5873e3SBarry Smith static char vcid[] = "$Id: ls.c,v 1.3 1995/04/13 14:42:37 bsmith Exp bsmith $"; 35e76c431SBarry Smith #endif 45e76c431SBarry Smith 55e76c431SBarry Smith #include <math.h> 6fbe28522SBarry Smith #include "ls.h" 75e42470aSBarry Smith 85e42470aSBarry Smith /* 95e42470aSBarry Smith Implements a line search variant of Newton's Method 105e76c431SBarry Smith for solving systems of nonlinear equations. 115e76c431SBarry Smith 125e76c431SBarry Smith Input parameters: 135e42470aSBarry Smith . snes - nonlinear context obtained from SNESCreate() 145e76c431SBarry Smith 155e42470aSBarry Smith Output Parameters: 165e42470aSBarry Smith . its - Number of global iterations until termination. 175e76c431SBarry Smith 185e76c431SBarry Smith Notes: 195e42470aSBarry Smith See SNESCreate() and SNESSetUp() for information on the definition and 205e76c431SBarry Smith initialization of the nonlinear solver context. 215e76c431SBarry Smith 225e76c431SBarry Smith This implements essentially a truncated Newton method with a 235e76c431SBarry Smith line search. By default a cubic backtracking line search 245e76c431SBarry Smith is employed, as described in the text "Numerical Methods for 255e76c431SBarry Smith Unconstrained Optimization and Nonlinear Equations" by Dennis 265e42470aSBarry Smith and Schnabel. See the examples in src/snes/examples. 275e76c431SBarry Smith */ 285e76c431SBarry Smith 295e42470aSBarry Smith int SNESSolve_LS( SNES snes, int *outits ) 305e76c431SBarry Smith { 315e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 32*6b5873e3SBarry Smith int maxits, i, history_len,ierr,lits; 33*6b5873e3SBarry Smith double fnorm, gnorm, xnorm, ynorm, *history; 345e42470aSBarry Smith Vec Y, X, F, G, W, TMP; 355e76c431SBarry Smith 365e42470aSBarry Smith history = snes->conv_hist; /* convergence history */ 375e42470aSBarry Smith history_len = snes->conv_hist_len; /* convergence history length */ 385e42470aSBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 395e42470aSBarry Smith X = snes->vec_sol; /* solution vector */ 405e42470aSBarry Smith F = snes->vec_res; /* residual vector */ 415e42470aSBarry Smith Y = snes->work[0]; /* work vectors */ 425e42470aSBarry Smith G = snes->work[1]; 435e42470aSBarry Smith W = snes->work[2]; 445e76c431SBarry Smith 455e42470aSBarry Smith ierr = SNESComputeInitialGuess(snes,X); CHKERR(ierr); /* X <- X_0 */ 465e42470aSBarry Smith VecNorm( X, &xnorm ); /* xnorm = || X || */ 475e42470aSBarry Smith ierr = SNESComputeResidual(snes,X,F); CHKERR(ierr); /* (+/-) F(X) */ 485e42470aSBarry Smith VecNorm(F, &fnorm ); /* fnorm <- || F || */ 495e42470aSBarry Smith snes->norm = fnorm; 505e76c431SBarry Smith if (history && history_len > 0) history[0] = fnorm; 51fbe28522SBarry Smith if (snes->Monitor) (*snes->Monitor)(snes,0,X,F,fnorm,snes->monP); 525e76c431SBarry Smith 535e76c431SBarry Smith for ( i=0; i<maxits; i++ ) { 545e42470aSBarry Smith snes->iter = i+1; 555e76c431SBarry Smith 565e76c431SBarry Smith /* Solve J Y = -F, where J is Jacobian matrix */ 575e42470aSBarry Smith (*snes->ComputeJacobian)(X,&snes->jacobian,snes->jacP); 585e42470aSBarry Smith ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian,0); 595e42470aSBarry Smith ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERR(ierr); 605e42470aSBarry Smith ierr = (*neP->LineSearch)(snes, X, F, G, Y, W, fnorm, &ynorm, &gnorm ); 615e76c431SBarry Smith 625e76c431SBarry Smith TMP = F; F = G; G = TMP; 635e76c431SBarry Smith TMP = X; X = Y; Y = TMP; 645e76c431SBarry Smith fnorm = gnorm; 655e76c431SBarry Smith 665e42470aSBarry Smith snes->norm = fnorm; 675e76c431SBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 685e42470aSBarry Smith VecNorm( X, &xnorm ); /* xnorm = || X || */ 69fbe28522SBarry Smith if (snes->Monitor) (*snes->Monitor)(snes,i+1,X,F,fnorm,snes->monP); 705e76c431SBarry Smith 715e76c431SBarry Smith /* Test for convergence */ 725e42470aSBarry Smith if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) { 735e42470aSBarry Smith if (X != snes->vec_sol) VecCopy( X, snes->vec_sol ); 745e76c431SBarry Smith break; 755e76c431SBarry Smith } 765e76c431SBarry Smith } 775e76c431SBarry Smith if (i == maxits) i--; 785e42470aSBarry Smith *outits = i+1; 795e42470aSBarry Smith return 0; 805e76c431SBarry Smith } 815e76c431SBarry Smith /* ------------------------------------------------------------ */ 825e76c431SBarry Smith /*ARGSUSED*/ 835e42470aSBarry Smith int SNESSetUp_LS(SNES snes ) 845e76c431SBarry Smith { 855e42470aSBarry Smith int ierr; 865e42470aSBarry Smith snes->nwork = 3; 875e42470aSBarry Smith ierr = VecGetVecs( snes->vec_sol, snes->nwork,&snes->work ); CHKERR(ierr); 885e42470aSBarry Smith PLogObjectParents(snes,snes->nwork,snes->work ); 895e42470aSBarry Smith return 0; 905e76c431SBarry Smith } 915e76c431SBarry Smith /* ------------------------------------------------------------ */ 925e76c431SBarry Smith /*ARGSUSED*/ 935e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj) 945e76c431SBarry Smith { 955e42470aSBarry Smith SNES snes = (SNES) obj; 965e42470aSBarry Smith SLESDestroy(snes->sles); 975e42470aSBarry Smith VecFreeVecs(snes->work, snes->nwork ); 985e42470aSBarry Smith PLogObjectDestroy(obj); 995e42470aSBarry Smith PETSCHEADERDESTROY(obj); 1005e42470aSBarry Smith return 0; 1015e76c431SBarry Smith } 1025e42470aSBarry Smith /*@ 1035e42470aSBarry Smith SNESDefaultMonitor - Default monitor for NLE solvers. Prints the 1045e42470aSBarry Smith residual norm at each iteration. 1055e42470aSBarry Smith 1065e42470aSBarry Smith Input Parameters: 1075e42470aSBarry Smith . nlP - nonlinear context 1085e42470aSBarry Smith . x - current iterate 1095e42470aSBarry Smith . f - current residual (+/-) 1105e42470aSBarry Smith . fnorm - 2-norm residual value (may be estimated). 1115e42470aSBarry Smith 1125e42470aSBarry Smith Notes: 1135e42470aSBarry Smith f is either the residual or its negative, depending on the user's 1145e42470aSBarry Smith preference, as set with NLSetResidualRoutine(). 1155e42470aSBarry Smith 1165e42470aSBarry Smith 1175e42470aSBarry Smith @*/ 1185e42470aSBarry Smith int SNESDefaultMonitor(SNES snes,int its, Vec x,Vec f,double fnorm,void *dummy) 1195e42470aSBarry Smith { 1205e42470aSBarry Smith fprintf( stdout, "iter = %d, residual norm %g \n",its,fnorm); 1215e42470aSBarry Smith return 0; 1225e42470aSBarry Smith } 1235e42470aSBarry Smith 1245e42470aSBarry Smith /*@ 1255e42470aSBarry Smith SNESDefaultConverged - Default test for monitoring the convergence 1265e42470aSBarry Smith of the NLE solvers. 1275e42470aSBarry Smith 1285e42470aSBarry Smith Input Parameters: 1295e42470aSBarry Smith . nlP - nonlinear context 1305e42470aSBarry Smith . xnorm - 2-norm of current iterate 1315e42470aSBarry Smith . pnorm - 2-norm of current step 1325e42470aSBarry Smith . fnorm - 2-norm of residual 1335e42470aSBarry Smith 1345e42470aSBarry Smith Returns: 1355e42470aSBarry Smith $ 2 if ( fnorm < atol ), 1365e42470aSBarry Smith $ 3 if ( pnorm < xtol*xnorm ), 1375e42470aSBarry Smith $ -2 if ( nres > max_res ), 1385e42470aSBarry Smith $ 0 otherwise, 1395e42470aSBarry Smith 1405e42470aSBarry Smith where 1415e42470aSBarry Smith $ atol - absolute residual norm tolerance, 1425e42470aSBarry Smith $ set with NLSetAbsConvergenceTol() 1435e42470aSBarry Smith $ max_res - maximum number of residual evaluations, 1445e42470aSBarry Smith $ set with NLSetMaxResidualEvaluations() 1455e42470aSBarry Smith $ nres - number of residual evaluations 1465e42470aSBarry Smith $ xtol - relative residual norm tolerance, 1475e42470aSBarry Smith 1485e42470aSBarry Smith $ set with NLSetMaxResidualEvaluations() 1495e42470aSBarry Smith $ nres - number of residual evaluations 1505e42470aSBarry Smith $ xtol - relative residual norm tolerance, 1515e42470aSBarry Smith $ set with NLSetRelConvergenceTol() 1525e42470aSBarry Smith 1535e42470aSBarry Smith @*/ 1545e42470aSBarry Smith int SNESDefaultConverged(SNES snes,double xnorm,double pnorm,double fnorm, 1555e42470aSBarry Smith void *dummy) 1565e42470aSBarry Smith { 1575e42470aSBarry Smith if (fnorm < snes->atol) { 1585e42470aSBarry Smith PLogInfo((PetscObject)snes,"Converged due to absolute residual norm %g < %g\n", 1595e42470aSBarry Smith fnorm,snes->atol); 1605e42470aSBarry Smith return 2; 1615e42470aSBarry Smith } 1625e42470aSBarry Smith if (pnorm < snes->xtol*(xnorm)) { 1635e42470aSBarry Smith PLogInfo((PetscObject)snes,"Converged due to small update length %g < %g*%g\n", 1645e42470aSBarry Smith pnorm,snes->xtol,xnorm); 1655e42470aSBarry Smith return 3; 1665e42470aSBarry Smith } 1675e42470aSBarry Smith return 0; 1685e42470aSBarry Smith } 1695e42470aSBarry Smith 1705e76c431SBarry Smith /* ------------------------------------------------------------ */ 1715e76c431SBarry Smith /*ARGSUSED*/ 1725e76c431SBarry Smith /*@ 1735e42470aSBarry Smith SNESNoLineSearch - This routine is not a line search at all; 1745e76c431SBarry Smith it simply uses the full Newton step. Thus, this routine is intended 1755e76c431SBarry Smith to serve as a template and is not recommended for general use. 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 1855e76c431SBarry Smith 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 1905e76c431SBarry Smith 1915e76c431SBarry Smith Returns: 1925e76c431SBarry Smith 1, indicating success of the step. 1935e76c431SBarry Smith 1945e76c431SBarry Smith @*/ 1955e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 1965e42470aSBarry Smith double fnorm, double *ynorm, double *gnorm ) 1975e76c431SBarry Smith { 1985e42470aSBarry Smith int ierr; 1995e42470aSBarry Smith Scalar one = 1.0; 2005e42470aSBarry Smith VecNorm(y, ynorm ); /* ynorm = || y || */ 2015e42470aSBarry Smith VecAXPY(&one, x, y ); /* y <- x + y */ 2025e42470aSBarry Smith ierr = SNESComputeResidual(snes,y,g); CHKERR(ierr); 2035e42470aSBarry Smith VecNorm( g, gnorm ); /* gnorm = || g || */ 2045e76c431SBarry Smith return 1; 2055e76c431SBarry Smith } 2065e76c431SBarry Smith /* ------------------------------------------------------------------ */ 2075e76c431SBarry Smith /*@ 2085e42470aSBarry Smith SNESCubicLineSearch - This routine performs a cubic line search. 2095e76c431SBarry Smith 2105e76c431SBarry Smith Input Parameters: 2115e42470aSBarry Smith . snes - nonlinear context 2125e76c431SBarry Smith . x - current iterate 2135e76c431SBarry Smith . f - residual evaluated at x 2145e76c431SBarry Smith . y - search direction (contains new iterate on output) 2155e76c431SBarry Smith . w - work vector 2165e76c431SBarry Smith . fnorm - 2-norm of f 2175e76c431SBarry Smith 2185e76c431SBarry Smith Output parameters: 2195e76c431SBarry Smith . g - residual evaluated at new iterate y 2205e76c431SBarry Smith . y - new iterate (contains search direction on input) 2215e76c431SBarry Smith . gnorm - 2-norm of g 2225e76c431SBarry Smith . ynorm - 2-norm of search length 2235e76c431SBarry Smith 2245e76c431SBarry Smith Returns: 2255e76c431SBarry Smith 1 if the line search succeeds; 0 if the line search fails. 2265e76c431SBarry Smith 2275e76c431SBarry Smith Notes: 2285e76c431SBarry Smith Use either NLSetStepLineSearchRoutines() or NLSetLineSearchRoutine() 2295e42470aSBarry Smith to set this routine within the SNES_NLS1 method. 2305e76c431SBarry Smith 2315e76c431SBarry Smith This line search is taken from "Numerical Methods for Unconstrained 2325e76c431SBarry Smith Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 2335e76c431SBarry Smith 2345e76c431SBarry Smith @*/ 2355e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 2365e42470aSBarry Smith double fnorm, double *ynorm, double *gnorm ) 2375e76c431SBarry Smith { 2385e42470aSBarry Smith double steptol, initslope; 2395e42470aSBarry Smith double lambdaprev, gnormprev; 2405e76c431SBarry Smith double a, b, d, t1, t2; 241*6b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 2425e42470aSBarry Smith Scalar cinitslope,clambda; 243*6b5873e3SBarry Smith #endif 2445e42470aSBarry Smith int ierr,count; 2455e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 2465e42470aSBarry Smith Scalar one = 1.0,scale; 2475e42470aSBarry Smith double maxstep,minlambda,alpha,lambda,lambdatemp; 2485e76c431SBarry Smith 2495e76c431SBarry Smith alpha = neP->alpha; 2505e76c431SBarry Smith maxstep = neP->maxstep; 2515e76c431SBarry Smith steptol = neP->steptol; 2525e76c431SBarry Smith 2535e42470aSBarry Smith VecNorm(y, ynorm ); 2545e76c431SBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 2555e42470aSBarry Smith scale = maxstep/(*ynorm); 256*6b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 257*6b5873e3SBarry Smith PLogInfo((PetscObject)snes,"Scaling step by %g\n",real(scale)); 258*6b5873e3SBarry Smith #else 2595e42470aSBarry Smith PLogInfo((PetscObject)snes,"Scaling step by %g\n",scale); 260*6b5873e3SBarry Smith #endif 2615e42470aSBarry Smith VecScale(&scale, y ); 2625e76c431SBarry Smith *ynorm = maxstep; 2635e76c431SBarry Smith } 2645e76c431SBarry Smith minlambda = steptol/(*ynorm); 2655e42470aSBarry Smith #if defined(PETSC_COMPLEX) 2665e42470aSBarry Smith VecDot(f, y, &cinitslope ); 2675e42470aSBarry Smith initslope = real(cinitslope); 2685e42470aSBarry Smith #else 2695e42470aSBarry Smith VecDot(f, y, &initslope ); 2705e42470aSBarry Smith #endif 2715e76c431SBarry Smith if (initslope > 0.0) initslope = -initslope; 2725e76c431SBarry Smith if (initslope == 0.0) initslope = -1.0; 2735e76c431SBarry Smith 2745e42470aSBarry Smith VecCopy(y, w ); 2755e42470aSBarry Smith VecAXPY(&one, x, w ); 2765e42470aSBarry Smith ierr = SNESComputeResidual(snes,w,g); CHKERR(ierr); 2775e42470aSBarry Smith VecNorm(g, gnorm ); 2785e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 2795e42470aSBarry Smith VecCopy(w, y ); 2805e42470aSBarry Smith PLogInfo((PetscObject)snes,"Using full step\n"); 2815e42470aSBarry Smith return 0; 2825e76c431SBarry Smith } 2835e76c431SBarry Smith 2845e76c431SBarry Smith /* Fit points with quadratic */ 2855e76c431SBarry Smith lambda = 1.0; count = 0; 2865e76c431SBarry Smith lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope)); 2875e76c431SBarry Smith lambdaprev = lambda; 2885e76c431SBarry Smith gnormprev = *gnorm; 2895e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 2905e76c431SBarry Smith lambda = .1*lambda; 2915e76c431SBarry Smith } else lambda = lambdatemp; 2925e42470aSBarry Smith VecCopy(x, w ); 2935e42470aSBarry Smith #if defined(PETSC_COMPLEX) 2945e42470aSBarry Smith clambda = lambda; VecAXPY(&clambda, y, w ); 2955e42470aSBarry Smith #else 2965e42470aSBarry Smith VecAXPY(&lambda, y, w ); 2975e42470aSBarry Smith #endif 2985e42470aSBarry Smith ierr = SNESComputeResidual(snes,w,g); CHKERR(ierr); 2995e42470aSBarry Smith VecNorm(g, gnorm ); 3005e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 3015e42470aSBarry Smith VecCopy(w, y ); 3025e42470aSBarry Smith PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda); 3035e42470aSBarry Smith return 0; 3045e76c431SBarry Smith } 3055e76c431SBarry Smith 3065e76c431SBarry Smith /* Fit points with cubic */ 3075e76c431SBarry Smith count = 1; 3085e76c431SBarry Smith while (1) { 3095e76c431SBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 3105e42470aSBarry Smith PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count); 3115e42470aSBarry Smith PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n", 3125e76c431SBarry Smith fnorm,*gnorm, *ynorm,lambda); 3135e42470aSBarry Smith VecCopy(w, y ); 3145e76c431SBarry Smith return 0; 3155e76c431SBarry Smith } 3165e76c431SBarry Smith t1 = *gnorm - fnorm - lambda*initslope; 3175e76c431SBarry Smith t2 = gnormprev - fnorm - lambdaprev*initslope; 3185e76c431SBarry Smith a = (t1/(lambda*lambda) - 3195e76c431SBarry Smith t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 3205e76c431SBarry Smith b = (-lambdaprev*t1/(lambda*lambda) + 3215e76c431SBarry Smith lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 3225e76c431SBarry Smith d = b*b - 3*a*initslope; 3235e76c431SBarry Smith if (d < 0.0) d = 0.0; 3245e76c431SBarry Smith if (a == 0.0) { 3255e76c431SBarry Smith lambdatemp = -initslope/(2.0*b); 3265e76c431SBarry Smith } else { 3275e76c431SBarry Smith lambdatemp = (-b + sqrt(d))/(3.0*a); 3285e76c431SBarry Smith } 3295e76c431SBarry Smith if (lambdatemp > .5*lambda) { 3305e76c431SBarry Smith lambdatemp = .5*lambda; 3315e76c431SBarry Smith } 3325e76c431SBarry Smith lambdaprev = lambda; 3335e76c431SBarry Smith gnormprev = *gnorm; 3345e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 3355e76c431SBarry Smith lambda = .1*lambda; 3365e76c431SBarry Smith } 3375e76c431SBarry Smith else lambda = lambdatemp; 3385e42470aSBarry Smith VecCopy( x, w ); 3395e42470aSBarry Smith #if defined(PETSC_COMPLEX) 3405e42470aSBarry Smith VecAXPY(&clambda, y, w ); 3415e42470aSBarry Smith #else 3425e42470aSBarry Smith VecAXPY(&lambda, y, w ); 3435e42470aSBarry Smith #endif 3445e42470aSBarry Smith ierr = SNESComputeResidual(snes,w,g); CHKERR(ierr); 3455e42470aSBarry Smith VecNorm(g, gnorm ); 3465e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* is reduction enough */ 3475e42470aSBarry Smith VecCopy(w, y ); 3485e42470aSBarry Smith PLogInfo((PetscObject)snes,"Cubically determined step, lambda %g\n",lambda); 3495e42470aSBarry Smith return 0; 3505e76c431SBarry Smith } 3515e76c431SBarry Smith count++; 3525e76c431SBarry Smith } 3535e42470aSBarry Smith return 0; 3545e76c431SBarry Smith } 3555e42470aSBarry Smith /*@ 3565e42470aSBarry Smith SNESQuadraticLineSearch - This routine performs a cubic line search. 3575e76c431SBarry Smith 3585e42470aSBarry Smith Input Parameters: 3595e42470aSBarry Smith . snes - nonlinear context 3605e42470aSBarry Smith . x - current iterate 3615e42470aSBarry Smith . f - residual evaluated at x 3625e42470aSBarry Smith . y - search direction (contains new iterate on output) 3635e42470aSBarry Smith . w - work vector 3645e42470aSBarry Smith . fnorm - 2-norm of f 3655e42470aSBarry Smith 3665e42470aSBarry Smith Output parameters: 3675e42470aSBarry Smith . g - residual evaluated at new iterate y 3685e42470aSBarry Smith . y - new iterate (contains search direction on input) 3695e42470aSBarry Smith . gnorm - 2-norm of g 3705e42470aSBarry Smith . ynorm - 2-norm of search length 3715e42470aSBarry Smith 3725e42470aSBarry Smith Returns: 3735e42470aSBarry Smith 1 if the line search succeeds; 0 if the line search fails. 3745e42470aSBarry Smith 3755e42470aSBarry Smith Notes: 3765e42470aSBarry Smith Use SNESSetLineSearchRoutines() 3775e42470aSBarry Smith to set this routine within the SNES_NLS1 method. 3785e42470aSBarry Smith 3795e42470aSBarry Smith @*/ 3805e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 3815e42470aSBarry Smith double fnorm, double *ynorm, double *gnorm ) 3825e76c431SBarry Smith { 3835e42470aSBarry Smith double steptol, initslope; 3845e42470aSBarry Smith double lambdaprev, gnormprev; 385*6b5873e3SBarry Smith #if defined(PETSC_COMPLEX) 3865e42470aSBarry Smith Scalar cinitslope,clambda; 387*6b5873e3SBarry Smith #endif 3885e42470aSBarry Smith int ierr,count; 3895e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 3905e42470aSBarry Smith Scalar one = 1.0,scale; 3915e42470aSBarry Smith double maxstep,minlambda,alpha,lambda,lambdatemp; 3925e76c431SBarry Smith 3935e42470aSBarry Smith alpha = neP->alpha; 3945e42470aSBarry Smith maxstep = neP->maxstep; 3955e42470aSBarry Smith steptol = neP->steptol; 3965e76c431SBarry Smith 3975e42470aSBarry Smith VecNorm(y, ynorm ); 3985e42470aSBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 3995e42470aSBarry Smith scale = maxstep/(*ynorm); 4005e42470aSBarry Smith VecScale(&scale, y ); 4015e42470aSBarry Smith *ynorm = maxstep; 4025e76c431SBarry Smith } 4035e42470aSBarry Smith minlambda = steptol/(*ynorm); 4045e42470aSBarry Smith #if defined(PETSC_COMPLEX) 4055e42470aSBarry Smith VecDot(f, y, &cinitslope ); 4065e42470aSBarry Smith initslope = real(cinitslope); 4075e42470aSBarry Smith #else 4085e42470aSBarry Smith VecDot(f, y, &initslope ); 4095e42470aSBarry Smith #endif 4105e42470aSBarry Smith if (initslope > 0.0) initslope = -initslope; 4115e42470aSBarry Smith if (initslope == 0.0) initslope = -1.0; 4125e42470aSBarry Smith 4135e42470aSBarry Smith VecCopy(y, w ); 4145e42470aSBarry Smith VecAXPY(&one, x, w ); 4155e42470aSBarry Smith ierr = SNESComputeResidual(snes,w,g); CHKERR(ierr); 4165e42470aSBarry Smith VecNorm(g, gnorm ); 4175e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 4185e42470aSBarry Smith VecCopy(w, y ); 4195e42470aSBarry Smith PLogInfo((PetscObject)snes,"Using full step\n"); 4205e42470aSBarry Smith return 0; 4215e42470aSBarry Smith } 4225e42470aSBarry Smith 4235e42470aSBarry Smith /* Fit points with quadratic */ 4245e42470aSBarry Smith lambda = 1.0; count = 0; 4255e42470aSBarry Smith count = 1; 4265e42470aSBarry Smith while (1) { 4275e42470aSBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 4285e42470aSBarry Smith PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count); 4295e42470aSBarry Smith PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n", 4305e42470aSBarry Smith fnorm,*gnorm, *ynorm,lambda); 4315e42470aSBarry Smith VecCopy(w, y ); 4325e42470aSBarry Smith return 0; 4335e42470aSBarry Smith } 4345e42470aSBarry Smith lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope)); 4355e42470aSBarry Smith lambdaprev = lambda; 4365e42470aSBarry Smith gnormprev = *gnorm; 4375e42470aSBarry Smith if (lambdatemp <= .1*lambda) { 4385e42470aSBarry Smith lambda = .1*lambda; 4395e42470aSBarry Smith } else lambda = lambdatemp; 4405e42470aSBarry Smith VecCopy(x, w ); 4415e42470aSBarry Smith #if defined(PETSC_COMPLEX) 4425e42470aSBarry Smith clambda = lambda; VecAXPY(&clambda, y, w ); 4435e42470aSBarry Smith #else 4445e42470aSBarry Smith VecAXPY(&lambda, y, w ); 4455e42470aSBarry Smith #endif 4465e42470aSBarry Smith ierr = SNESComputeResidual(snes,w,g); CHKERR(ierr); 4475e42470aSBarry Smith VecNorm(g, gnorm ); 4485e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 4495e42470aSBarry Smith VecCopy(w, y ); 4505e42470aSBarry Smith PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda); 4515e42470aSBarry Smith return 0; 4525e42470aSBarry Smith } 4535e42470aSBarry Smith count++; 4545e42470aSBarry Smith } 4555e42470aSBarry Smith 4565e42470aSBarry Smith return 0; 4575e76c431SBarry Smith } 4585e76c431SBarry Smith /* ------------------------------------------------------------ */ 4595e76c431SBarry Smith /*@C 4605e42470aSBarry Smith SNESSetLineSearchRoutine - Sets the line search routine to be used 461fbe28522SBarry Smith by the method SNES_LS. 4625e76c431SBarry Smith 4635e76c431SBarry Smith Input Parameters: 4645e42470aSBarry Smith . snes - nonlinear context obtained from NLCreate() 4655e76c431SBarry Smith . func - pointer to int function 4665e76c431SBarry Smith 4675e76c431SBarry Smith Possible routines: 4685e42470aSBarry Smith SNESCubicLineSearch() - default line search 4695e42470aSBarry Smith SNESNoLineSearch() - the full Newton step (actually not a line search) 4705e76c431SBarry Smith 4715e76c431SBarry Smith Calling sequence of func: 4725e42470aSBarry Smith . func (SNES snes, Vec x, Vec f, Vec g, Vec y, 4735e42470aSBarry Smith Vec w, double fnorm, double *ynorm, double *gnorm ) 4745e76c431SBarry Smith 4755e76c431SBarry Smith Input parameters for func: 4765e42470aSBarry Smith . snes - nonlinear context 4775e76c431SBarry Smith . x - current iterate 4785e76c431SBarry Smith . f - residual evaluated at x 4795e76c431SBarry Smith . y - search direction (contains new iterate on output) 4805e76c431SBarry Smith . w - work vector 4815e76c431SBarry Smith . fnorm - 2-norm of f 4825e76c431SBarry Smith 4835e76c431SBarry Smith Output parameters for func: 4845e76c431SBarry Smith . g - residual evaluated at new iterate y 4855e76c431SBarry Smith . y - new iterate (contains search direction on input) 4865e76c431SBarry Smith . gnorm - 2-norm of g 4875e76c431SBarry Smith . ynorm - 2-norm of search length 4885e76c431SBarry Smith 4895e76c431SBarry Smith Returned by func: 4905e76c431SBarry Smith 1 if the line search succeeds; 0 if the line search fails. 4915e76c431SBarry Smith @*/ 4925e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 4935e42470aSBarry Smith double,double *,double*) ) 4945e76c431SBarry Smith { 495fbe28522SBarry Smith if ((snes)->type == SNES_NLS) 4965e42470aSBarry Smith ((SNES_LS *)(snes->data))->LineSearch = func; 4975e42470aSBarry Smith return 0; 4985e76c431SBarry Smith } 4995e42470aSBarry Smith 5005e42470aSBarry Smith static int SNESPrintHelp_LS(SNES snes) 5015e42470aSBarry Smith { 5025e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5035e42470aSBarry Smith fprintf(stderr,"-snes_line_search [basic,quadratic,cubic]\n"); 5045e42470aSBarry Smith fprintf(stderr,"-snes_line_search_alpha alpha (default %g)\n",ls->alpha); 5055e42470aSBarry Smith fprintf(stderr,"-snes_line_search_maxstep max (default %g)\n",ls->maxstep); 5065e42470aSBarry Smith fprintf(stderr,"-snes_line_search_steptol tol (default %g)\n",ls->steptol); 507*6b5873e3SBarry Smith return 0; 5085e42470aSBarry Smith } 5095e42470aSBarry Smith 510*6b5873e3SBarry Smith #include "options.h" 5115e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes) 5125e42470aSBarry Smith { 5135e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 5145e42470aSBarry Smith char ver[16]; 5155e42470aSBarry Smith double tmp; 5165e42470aSBarry Smith 5175e42470aSBarry Smith if (OptionsGetDouble(0,snes->prefix,"-snes_line_search_alpa",&tmp)) { 5185e42470aSBarry Smith ls->alpha = tmp; 5195e42470aSBarry Smith } 5205e42470aSBarry Smith if (OptionsGetDouble(0,snes->prefix,"-snes_line_search_maxstep",&tmp)) { 5215e42470aSBarry Smith ls->maxstep = tmp; 5225e42470aSBarry Smith } 5235e42470aSBarry Smith if (OptionsGetDouble(0,snes->prefix,"-snes_line_search_steptol",&tmp)) { 5245e42470aSBarry Smith ls->steptol = tmp; 5255e42470aSBarry Smith } 5265e42470aSBarry Smith if (OptionsGetString(0,snes->prefix,"-snes_line_search",ver,16)) { 5275e42470aSBarry Smith if (!strcmp(ver,"basic")) { 5285e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESNoLineSearch); 5295e42470aSBarry Smith } 5305e42470aSBarry Smith else if (!strcmp(ver,"quadratic")) { 5315e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch); 5325e42470aSBarry Smith } 5335e42470aSBarry Smith else if (!strcmp(ver,"cubic")) { 5345e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESCubicLineSearch); 5355e42470aSBarry Smith } 5365e42470aSBarry Smith else {SETERR(1,"Unknown line search?");} 5375e42470aSBarry Smith } 5385e42470aSBarry Smith return 0; 5395e42470aSBarry Smith } 5405e42470aSBarry Smith 5415e42470aSBarry Smith /* ------------------------------------------------------------ */ 5425e42470aSBarry Smith int SNESCreate_LS(SNES snes ) 5435e42470aSBarry Smith { 5445e42470aSBarry Smith SNES_LS *neP; 5455e42470aSBarry Smith 546fbe28522SBarry Smith snes->type = SNES_NLS; 5475e42470aSBarry Smith snes->Setup = SNESSetUp_LS; 5485e42470aSBarry Smith snes->Solver = SNESSolve_LS; 5495e42470aSBarry Smith snes->destroy = SNESDestroy_LS; 550fbe28522SBarry Smith snes->Monitor = 0; 5515e42470aSBarry Smith snes->Converged = SNESDefaultConverged; 5525e42470aSBarry Smith snes->PrintHelp = SNESPrintHelp_LS; 5535e42470aSBarry Smith snes->SetFromOptions = SNESSetFromOptions_LS; 5545e42470aSBarry Smith 5555e42470aSBarry Smith neP = NEW(SNES_LS); CHKPTR(neP); 5565e42470aSBarry Smith snes->data = (void *) neP; 5575e42470aSBarry Smith neP->alpha = 1.e-4; 5585e42470aSBarry Smith neP->maxstep = 1.e8; 5595e42470aSBarry Smith neP->steptol = 1.e-12; 5605e42470aSBarry Smith neP->LineSearch = SNESCubicLineSearch; 5615e42470aSBarry Smith return 0; 5625e42470aSBarry Smith } 5635e42470aSBarry Smith 5645e42470aSBarry Smith 5655e42470aSBarry Smith 5665e42470aSBarry Smith 567