15e76c431SBarry Smith #ifndef lint 2*5e42470aSBarry Smith static char vcid[] = "$Id: newls1.c,v 1.1 1995/03/20 22:59:54 bsmith Exp bsmith $"; 35e76c431SBarry Smith #endif 45e76c431SBarry Smith 55e76c431SBarry Smith #include <math.h> 6*5e42470aSBarry Smith #include "newls1.h" 75e76c431SBarry Smith 8*5e42470aSBarry Smith int SNESNewtonDefaultMonitor(SNES,int,Vec,Vec, double ,void*); 9*5e42470aSBarry Smith int SNESNewtonDefaultConverged(SNES, double ,double ,double,void * ); 10*5e42470aSBarry Smith 11*5e42470aSBarry Smith /* 12*5e42470aSBarry Smith Implements a line search variant of Newton's Method 135e76c431SBarry Smith for solving systems of nonlinear equations. 145e76c431SBarry Smith 155e76c431SBarry Smith Input parameters: 16*5e42470aSBarry Smith . snes - nonlinear context obtained from SNESCreate() 175e76c431SBarry Smith 18*5e42470aSBarry Smith Output Parameters: 19*5e42470aSBarry Smith . its - Number of global iterations until termination. 205e76c431SBarry Smith 215e76c431SBarry Smith Notes: 22*5e42470aSBarry Smith See SNESCreate() and SNESSetUp() for information on the definition and 235e76c431SBarry Smith initialization of the nonlinear solver context. 245e76c431SBarry Smith 255e76c431SBarry Smith This implements essentially a truncated Newton method with a 265e76c431SBarry Smith line search. By default a cubic backtracking line search 275e76c431SBarry Smith is employed, as described in the text "Numerical Methods for 285e76c431SBarry Smith Unconstrained Optimization and Nonlinear Equations" by Dennis 29*5e42470aSBarry Smith and Schnabel. See the examples in src/snes/examples. 305e76c431SBarry Smith */ 315e76c431SBarry Smith 32*5e42470aSBarry Smith int SNESSolve_LS( SNES snes, int *outits ) 335e76c431SBarry Smith { 34*5e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 35*5e42470aSBarry Smith int maxits, i, iters, line, nlconv, history_len,ierr,lits; 365e76c431SBarry Smith double fnorm, gnorm, gpnorm, xnorm, ynorm, *history; 37*5e42470aSBarry Smith Vec Y, X, F, G, W, TMP; 385e76c431SBarry Smith 39*5e42470aSBarry Smith history = snes->conv_hist; /* convergence history */ 40*5e42470aSBarry Smith history_len = snes->conv_hist_len; /* convergence history length */ 41*5e42470aSBarry Smith maxits = snes->max_its; /* maximum number of iterations */ 42*5e42470aSBarry Smith X = snes->vec_sol; /* solution vector */ 43*5e42470aSBarry Smith F = snes->vec_res; /* residual vector */ 44*5e42470aSBarry Smith Y = snes->work[0]; /* work vectors */ 45*5e42470aSBarry Smith G = snes->work[1]; 46*5e42470aSBarry Smith W = snes->work[2]; 475e76c431SBarry Smith 48*5e42470aSBarry Smith ierr = SNESComputeInitialGuess(snes,X); CHKERR(ierr); /* X <- X_0 */ 49*5e42470aSBarry Smith VecNorm( X, &xnorm ); /* xnorm = || X || */ 50*5e42470aSBarry Smith ierr = SNESComputeResidual(snes,X,F); CHKERR(ierr); /* (+/-) F(X) */ 51*5e42470aSBarry Smith VecNorm(F, &fnorm ); /* fnorm <- || F || */ 52*5e42470aSBarry Smith snes->norm = fnorm; 535e76c431SBarry Smith if (history && history_len > 0) history[0] = fnorm; 54*5e42470aSBarry Smith (*snes->Monitor)(snes,0,X,F,fnorm,snes->monP); /* Monitor progress */ 555e76c431SBarry Smith 565e76c431SBarry Smith for ( i=0; i<maxits; i++ ) { 57*5e42470aSBarry Smith snes->iter = i+1; 585e76c431SBarry Smith 595e76c431SBarry Smith /* Solve J Y = -F, where J is Jacobian matrix */ 60*5e42470aSBarry Smith (*snes->ComputeJacobian)(X,&snes->jacobian,snes->jacP); 61*5e42470aSBarry Smith ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian,0); 62*5e42470aSBarry Smith ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERR(ierr); 63*5e42470aSBarry Smith ierr = (*neP->LineSearch)(snes, X, F, G, Y, W, fnorm, &ynorm, &gnorm ); 645e76c431SBarry Smith 655e76c431SBarry Smith TMP = F; F = G; G = TMP; 665e76c431SBarry Smith TMP = X; X = Y; Y = TMP; 675e76c431SBarry Smith fnorm = gnorm; 685e76c431SBarry Smith 69*5e42470aSBarry Smith snes->norm = fnorm; 705e76c431SBarry Smith if (history && history_len > i+1) history[i+1] = fnorm; 71*5e42470aSBarry Smith VecNorm( X, &xnorm ); /* xnorm = || X || */ 72*5e42470aSBarry Smith (*snes->Monitor)(snes,i+1,X,F,fnorm,snes->monP); /* Monitor progress */ 735e76c431SBarry Smith 745e76c431SBarry Smith /* Test for convergence */ 75*5e42470aSBarry Smith if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) { 76*5e42470aSBarry Smith if (X != snes->vec_sol) VecCopy( X, snes->vec_sol ); 775e76c431SBarry Smith break; 785e76c431SBarry Smith } 795e76c431SBarry Smith } 805e76c431SBarry Smith if (i == maxits) i--; 81*5e42470aSBarry Smith *outits = i+1; 82*5e42470aSBarry Smith return 0; 835e76c431SBarry Smith } 845e76c431SBarry Smith /* ------------------------------------------------------------ */ 855e76c431SBarry Smith /*ARGSUSED*/ 86*5e42470aSBarry Smith int SNESSetUp_LS(SNES snes ) 875e76c431SBarry Smith { 88*5e42470aSBarry Smith SNES_LS *ctx = (SNES_LS *)snes->data; 89*5e42470aSBarry Smith int ierr; 90*5e42470aSBarry Smith snes->nwork = 3; 91*5e42470aSBarry Smith ierr = VecGetVecs( snes->vec_sol, snes->nwork,&snes->work ); CHKERR(ierr); 92*5e42470aSBarry Smith PLogObjectParents(snes,snes->nwork,snes->work ); 93*5e42470aSBarry Smith return 0; 945e76c431SBarry Smith } 955e76c431SBarry Smith /* ------------------------------------------------------------ */ 965e76c431SBarry Smith /*ARGSUSED*/ 97*5e42470aSBarry Smith int SNESDestroy_LS(PetscObject obj) 985e76c431SBarry Smith { 99*5e42470aSBarry Smith SNES snes = (SNES) obj; 100*5e42470aSBarry Smith SLESDestroy(snes->sles); 101*5e42470aSBarry Smith VecFreeVecs(snes->work, snes->nwork ); 102*5e42470aSBarry Smith PLogObjectDestroy(obj); 103*5e42470aSBarry Smith PETSCHEADERDESTROY(obj); 104*5e42470aSBarry Smith return 0; 1055e76c431SBarry Smith } 106*5e42470aSBarry Smith /*@ 107*5e42470aSBarry Smith SNESDefaultMonitor - Default monitor for NLE solvers. Prints the 108*5e42470aSBarry Smith residual norm at each iteration. 109*5e42470aSBarry Smith 110*5e42470aSBarry Smith Input Parameters: 111*5e42470aSBarry Smith . nlP - nonlinear context 112*5e42470aSBarry Smith . x - current iterate 113*5e42470aSBarry Smith . f - current residual (+/-) 114*5e42470aSBarry Smith . fnorm - 2-norm residual value (may be estimated). 115*5e42470aSBarry Smith 116*5e42470aSBarry Smith Notes: 117*5e42470aSBarry Smith f is either the residual or its negative, depending on the user's 118*5e42470aSBarry Smith preference, as set with NLSetResidualRoutine(). 119*5e42470aSBarry Smith 120*5e42470aSBarry Smith 121*5e42470aSBarry Smith @*/ 122*5e42470aSBarry Smith int SNESDefaultMonitor(SNES snes,int its, Vec x,Vec f,double fnorm,void *dummy) 123*5e42470aSBarry Smith { 124*5e42470aSBarry Smith fprintf( stdout, "iter = %d, residual norm %g \n",its,fnorm); 125*5e42470aSBarry Smith return 0; 126*5e42470aSBarry Smith } 127*5e42470aSBarry Smith 128*5e42470aSBarry Smith /*@ 129*5e42470aSBarry Smith SNESDefaultConverged - Default test for monitoring the convergence 130*5e42470aSBarry Smith of the NLE solvers. 131*5e42470aSBarry Smith 132*5e42470aSBarry Smith Input Parameters: 133*5e42470aSBarry Smith . nlP - nonlinear context 134*5e42470aSBarry Smith . xnorm - 2-norm of current iterate 135*5e42470aSBarry Smith . pnorm - 2-norm of current step 136*5e42470aSBarry Smith . fnorm - 2-norm of residual 137*5e42470aSBarry Smith 138*5e42470aSBarry Smith Returns: 139*5e42470aSBarry Smith $ 2 if ( fnorm < atol ), 140*5e42470aSBarry Smith $ 3 if ( pnorm < xtol*xnorm ), 141*5e42470aSBarry Smith $ -2 if ( nres > max_res ), 142*5e42470aSBarry Smith $ 0 otherwise, 143*5e42470aSBarry Smith 144*5e42470aSBarry Smith where 145*5e42470aSBarry Smith $ atol - absolute residual norm tolerance, 146*5e42470aSBarry Smith $ set with NLSetAbsConvergenceTol() 147*5e42470aSBarry Smith $ max_res - maximum number of residual evaluations, 148*5e42470aSBarry Smith $ set with NLSetMaxResidualEvaluations() 149*5e42470aSBarry Smith $ nres - number of residual evaluations 150*5e42470aSBarry Smith $ xtol - relative residual norm tolerance, 151*5e42470aSBarry Smith 152*5e42470aSBarry Smith $ set with NLSetMaxResidualEvaluations() 153*5e42470aSBarry Smith $ nres - number of residual evaluations 154*5e42470aSBarry Smith $ xtol - relative residual norm tolerance, 155*5e42470aSBarry Smith $ set with NLSetRelConvergenceTol() 156*5e42470aSBarry Smith 157*5e42470aSBarry Smith @*/ 158*5e42470aSBarry Smith int SNESDefaultConverged(SNES snes,double xnorm,double pnorm,double fnorm, 159*5e42470aSBarry Smith void *dummy) 160*5e42470aSBarry Smith { 161*5e42470aSBarry Smith if (fnorm < snes->atol) { 162*5e42470aSBarry Smith PLogInfo((PetscObject)snes,"Converged due to absolute residual norm %g < %g\n", 163*5e42470aSBarry Smith fnorm,snes->atol); 164*5e42470aSBarry Smith return 2; 165*5e42470aSBarry Smith } 166*5e42470aSBarry Smith if (pnorm < snes->xtol*(xnorm)) { 167*5e42470aSBarry Smith PLogInfo((PetscObject)snes,"Converged due to small update length %g < %g*%g\n", 168*5e42470aSBarry Smith pnorm,snes->xtol,xnorm); 169*5e42470aSBarry Smith return 3; 170*5e42470aSBarry Smith } 171*5e42470aSBarry Smith return 0; 172*5e42470aSBarry Smith } 173*5e42470aSBarry Smith 1745e76c431SBarry Smith /* ------------------------------------------------------------ */ 1755e76c431SBarry Smith /*ARGSUSED*/ 1765e76c431SBarry Smith /*@ 177*5e42470aSBarry Smith SNESNoLineSearch - This routine is not a line search at all; 1785e76c431SBarry Smith it simply uses the full Newton step. Thus, this routine is intended 1795e76c431SBarry Smith to serve as a template and is not recommended for general use. 1805e76c431SBarry Smith 1815e76c431SBarry Smith Input Parameters: 182*5e42470aSBarry Smith . snes - nonlinear context 1835e76c431SBarry Smith . x - current iterate 1845e76c431SBarry Smith . f - residual evaluated at x 1855e76c431SBarry Smith . y - search direction (contains new iterate on output) 1865e76c431SBarry Smith . w - work vector 1875e76c431SBarry Smith . fnorm - 2-norm of f 1885e76c431SBarry Smith 1895e76c431SBarry Smith Output parameters: 1905e76c431SBarry Smith . g - residual evaluated at new iterate y 1915e76c431SBarry Smith . y - new iterate (contains search direction on input) 1925e76c431SBarry Smith . gnorm - 2-norm of g 1935e76c431SBarry Smith . ynorm - 2-norm of search length 1945e76c431SBarry Smith 1955e76c431SBarry Smith Returns: 1965e76c431SBarry Smith 1, indicating success of the step. 1975e76c431SBarry Smith 1985e76c431SBarry Smith @*/ 199*5e42470aSBarry Smith int SNESNoLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 200*5e42470aSBarry Smith double fnorm, double *ynorm, double *gnorm ) 2015e76c431SBarry Smith { 202*5e42470aSBarry Smith int ierr; 203*5e42470aSBarry Smith Scalar one = 1.0; 204*5e42470aSBarry Smith VecNorm(y, ynorm ); /* ynorm = || y || */ 205*5e42470aSBarry Smith VecAXPY(&one, x, y ); /* y <- x + y */ 206*5e42470aSBarry Smith ierr = SNESComputeResidual(snes,y,g); CHKERR(ierr); 207*5e42470aSBarry Smith VecNorm( g, gnorm ); /* gnorm = || g || */ 2085e76c431SBarry Smith return 1; 2095e76c431SBarry Smith } 2105e76c431SBarry Smith /* ------------------------------------------------------------------ */ 2115e76c431SBarry Smith /*@ 212*5e42470aSBarry Smith SNESCubicLineSearch - This routine performs a cubic line search. 2135e76c431SBarry Smith 2145e76c431SBarry Smith Input Parameters: 215*5e42470aSBarry Smith . snes - nonlinear context 2165e76c431SBarry Smith . x - current iterate 2175e76c431SBarry Smith . f - residual evaluated at x 2185e76c431SBarry Smith . y - search direction (contains new iterate on output) 2195e76c431SBarry Smith . w - work vector 2205e76c431SBarry Smith . fnorm - 2-norm of f 2215e76c431SBarry Smith 2225e76c431SBarry Smith Output parameters: 2235e76c431SBarry Smith . g - residual evaluated at new iterate y 2245e76c431SBarry Smith . y - new iterate (contains search direction on input) 2255e76c431SBarry Smith . gnorm - 2-norm of g 2265e76c431SBarry Smith . ynorm - 2-norm of search length 2275e76c431SBarry Smith 2285e76c431SBarry Smith Returns: 2295e76c431SBarry Smith 1 if the line search succeeds; 0 if the line search fails. 2305e76c431SBarry Smith 2315e76c431SBarry Smith Notes: 2325e76c431SBarry Smith Use either NLSetStepLineSearchRoutines() or NLSetLineSearchRoutine() 233*5e42470aSBarry Smith to set this routine within the SNES_NLS1 method. 2345e76c431SBarry Smith 2355e76c431SBarry Smith This line search is taken from "Numerical Methods for Unconstrained 2365e76c431SBarry Smith Optimization and Nonlinear Equations" by Dennis and Schnabel, page 325. 2375e76c431SBarry Smith 2385e76c431SBarry Smith @*/ 239*5e42470aSBarry Smith int SNESCubicLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 240*5e42470aSBarry Smith double fnorm, double *ynorm, double *gnorm ) 2415e76c431SBarry Smith { 242*5e42470aSBarry Smith double steptol, initslope; 243*5e42470aSBarry Smith double lambdaprev, gnormprev; 2445e76c431SBarry Smith double a, b, d, t1, t2; 245*5e42470aSBarry Smith Scalar cinitslope,clambda; 246*5e42470aSBarry Smith int ierr,count; 247*5e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 248*5e42470aSBarry Smith Scalar one = 1.0,scale; 249*5e42470aSBarry Smith double maxstep,minlambda,alpha,lambda,lambdatemp; 2505e76c431SBarry Smith 2515e76c431SBarry Smith alpha = neP->alpha; 2525e76c431SBarry Smith maxstep = neP->maxstep; 2535e76c431SBarry Smith steptol = neP->steptol; 2545e76c431SBarry Smith 255*5e42470aSBarry Smith VecNorm(y, ynorm ); 2565e76c431SBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 257*5e42470aSBarry Smith scale = maxstep/(*ynorm); 258*5e42470aSBarry Smith PLogInfo((PetscObject)snes,"Scaling step by %g\n",scale); 259*5e42470aSBarry Smith VecScale(&scale, y ); 2605e76c431SBarry Smith *ynorm = maxstep; 2615e76c431SBarry Smith } 2625e76c431SBarry Smith minlambda = steptol/(*ynorm); 263*5e42470aSBarry Smith #if defined(PETSC_COMPLEX) 264*5e42470aSBarry Smith VecDot(f, y, &cinitslope ); 265*5e42470aSBarry Smith initslope = real(cinitslope); 266*5e42470aSBarry Smith #else 267*5e42470aSBarry Smith VecDot(f, y, &initslope ); 268*5e42470aSBarry Smith #endif 2695e76c431SBarry Smith if (initslope > 0.0) initslope = -initslope; 2705e76c431SBarry Smith if (initslope == 0.0) initslope = -1.0; 2715e76c431SBarry Smith 272*5e42470aSBarry Smith VecCopy(y, w ); 273*5e42470aSBarry Smith VecAXPY(&one, x, w ); 274*5e42470aSBarry Smith ierr = SNESComputeResidual(snes,w,g); CHKERR(ierr); 275*5e42470aSBarry Smith VecNorm(g, gnorm ); 2765e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 277*5e42470aSBarry Smith VecCopy(w, y ); 278*5e42470aSBarry Smith PLogInfo((PetscObject)snes,"Using full step\n"); 279*5e42470aSBarry Smith return 0; 2805e76c431SBarry Smith } 2815e76c431SBarry Smith 2825e76c431SBarry Smith /* Fit points with quadratic */ 2835e76c431SBarry Smith lambda = 1.0; count = 0; 2845e76c431SBarry Smith lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope)); 2855e76c431SBarry Smith lambdaprev = lambda; 2865e76c431SBarry Smith gnormprev = *gnorm; 2875e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 2885e76c431SBarry Smith lambda = .1*lambda; 2895e76c431SBarry Smith } else lambda = lambdatemp; 290*5e42470aSBarry Smith VecCopy(x, w ); 291*5e42470aSBarry Smith #if defined(PETSC_COMPLEX) 292*5e42470aSBarry Smith clambda = lambda; VecAXPY(&clambda, y, w ); 293*5e42470aSBarry Smith #else 294*5e42470aSBarry Smith VecAXPY(&lambda, y, w ); 295*5e42470aSBarry Smith #endif 296*5e42470aSBarry Smith ierr = SNESComputeResidual(snes,w,g); CHKERR(ierr); 297*5e42470aSBarry Smith VecNorm(g, gnorm ); 2985e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 299*5e42470aSBarry Smith VecCopy(w, y ); 300*5e42470aSBarry Smith PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda); 301*5e42470aSBarry Smith return 0; 3025e76c431SBarry Smith } 3035e76c431SBarry Smith 3045e76c431SBarry Smith /* Fit points with cubic */ 3055e76c431SBarry Smith count = 1; 3065e76c431SBarry Smith while (1) { 3075e76c431SBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 308*5e42470aSBarry Smith PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count); 309*5e42470aSBarry Smith PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n", 3105e76c431SBarry Smith fnorm,*gnorm, *ynorm,lambda); 311*5e42470aSBarry Smith VecCopy(w, y ); 3125e76c431SBarry Smith return 0; 3135e76c431SBarry Smith } 3145e76c431SBarry Smith t1 = *gnorm - fnorm - lambda*initslope; 3155e76c431SBarry Smith t2 = gnormprev - fnorm - lambdaprev*initslope; 3165e76c431SBarry Smith a = (t1/(lambda*lambda) - 3175e76c431SBarry Smith t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 3185e76c431SBarry Smith b = (-lambdaprev*t1/(lambda*lambda) + 3195e76c431SBarry Smith lambda*t2/(lambdaprev*lambdaprev))/(lambda-lambdaprev); 3205e76c431SBarry Smith d = b*b - 3*a*initslope; 3215e76c431SBarry Smith if (d < 0.0) d = 0.0; 3225e76c431SBarry Smith if (a == 0.0) { 3235e76c431SBarry Smith lambdatemp = -initslope/(2.0*b); 3245e76c431SBarry Smith } else { 3255e76c431SBarry Smith lambdatemp = (-b + sqrt(d))/(3.0*a); 3265e76c431SBarry Smith } 3275e76c431SBarry Smith if (lambdatemp > .5*lambda) { 3285e76c431SBarry Smith lambdatemp = .5*lambda; 3295e76c431SBarry Smith } 3305e76c431SBarry Smith lambdaprev = lambda; 3315e76c431SBarry Smith gnormprev = *gnorm; 3325e76c431SBarry Smith if (lambdatemp <= .1*lambda) { 3335e76c431SBarry Smith lambda = .1*lambda; 3345e76c431SBarry Smith } 3355e76c431SBarry Smith else lambda = lambdatemp; 336*5e42470aSBarry Smith VecCopy( x, w ); 337*5e42470aSBarry Smith #if defined(PETSC_COMPLEX) 338*5e42470aSBarry Smith VecAXPY(&clambda, y, w ); 339*5e42470aSBarry Smith #else 340*5e42470aSBarry Smith VecAXPY(&lambda, y, w ); 341*5e42470aSBarry Smith #endif 342*5e42470aSBarry Smith ierr = SNESComputeResidual(snes,w,g); CHKERR(ierr); 343*5e42470aSBarry Smith VecNorm(g, gnorm ); 3445e76c431SBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* is reduction enough */ 345*5e42470aSBarry Smith VecCopy(w, y ); 346*5e42470aSBarry Smith PLogInfo((PetscObject)snes,"Cubically determined step, lambda %g\n",lambda); 347*5e42470aSBarry Smith return 0; 3485e76c431SBarry Smith } 3495e76c431SBarry Smith count++; 3505e76c431SBarry Smith } 351*5e42470aSBarry Smith return 0; 3525e76c431SBarry Smith } 353*5e42470aSBarry Smith /*@ 354*5e42470aSBarry Smith SNESQuadraticLineSearch - This routine performs a cubic line search. 3555e76c431SBarry Smith 356*5e42470aSBarry Smith Input Parameters: 357*5e42470aSBarry Smith . snes - nonlinear context 358*5e42470aSBarry Smith . x - current iterate 359*5e42470aSBarry Smith . f - residual evaluated at x 360*5e42470aSBarry Smith . y - search direction (contains new iterate on output) 361*5e42470aSBarry Smith . w - work vector 362*5e42470aSBarry Smith . fnorm - 2-norm of f 363*5e42470aSBarry Smith 364*5e42470aSBarry Smith Output parameters: 365*5e42470aSBarry Smith . g - residual evaluated at new iterate y 366*5e42470aSBarry Smith . y - new iterate (contains search direction on input) 367*5e42470aSBarry Smith . gnorm - 2-norm of g 368*5e42470aSBarry Smith . ynorm - 2-norm of search length 369*5e42470aSBarry Smith 370*5e42470aSBarry Smith Returns: 371*5e42470aSBarry Smith 1 if the line search succeeds; 0 if the line search fails. 372*5e42470aSBarry Smith 373*5e42470aSBarry Smith Notes: 374*5e42470aSBarry Smith Use SNESSetLineSearchRoutines() 375*5e42470aSBarry Smith to set this routine within the SNES_NLS1 method. 376*5e42470aSBarry Smith 377*5e42470aSBarry Smith @*/ 378*5e42470aSBarry Smith int SNESQuadraticLineSearch(SNES snes, Vec x, Vec f, Vec g, Vec y, Vec w, 379*5e42470aSBarry Smith double fnorm, double *ynorm, double *gnorm ) 3805e76c431SBarry Smith { 381*5e42470aSBarry Smith double steptol, initslope; 382*5e42470aSBarry Smith double lambdaprev, gnormprev; 383*5e42470aSBarry Smith double a, b, d, t1, t2; 384*5e42470aSBarry Smith Scalar cinitslope,clambda; 385*5e42470aSBarry Smith int ierr,count; 386*5e42470aSBarry Smith SNES_LS *neP = (SNES_LS *) snes->data; 387*5e42470aSBarry Smith Scalar one = 1.0,scale; 388*5e42470aSBarry Smith double maxstep,minlambda,alpha,lambda,lambdatemp; 3895e76c431SBarry Smith 390*5e42470aSBarry Smith alpha = neP->alpha; 391*5e42470aSBarry Smith maxstep = neP->maxstep; 392*5e42470aSBarry Smith steptol = neP->steptol; 3935e76c431SBarry Smith 394*5e42470aSBarry Smith VecNorm(y, ynorm ); 395*5e42470aSBarry Smith if (*ynorm > maxstep) { /* Step too big, so scale back */ 396*5e42470aSBarry Smith scale = maxstep/(*ynorm); 397*5e42470aSBarry Smith VecScale(&scale, y ); 398*5e42470aSBarry Smith *ynorm = maxstep; 3995e76c431SBarry Smith } 400*5e42470aSBarry Smith minlambda = steptol/(*ynorm); 401*5e42470aSBarry Smith #if defined(PETSC_COMPLEX) 402*5e42470aSBarry Smith VecDot(f, y, &cinitslope ); 403*5e42470aSBarry Smith initslope = real(cinitslope); 404*5e42470aSBarry Smith #else 405*5e42470aSBarry Smith VecDot(f, y, &initslope ); 406*5e42470aSBarry Smith #endif 407*5e42470aSBarry Smith if (initslope > 0.0) initslope = -initslope; 408*5e42470aSBarry Smith if (initslope == 0.0) initslope = -1.0; 409*5e42470aSBarry Smith 410*5e42470aSBarry Smith VecCopy(y, w ); 411*5e42470aSBarry Smith VecAXPY(&one, x, w ); 412*5e42470aSBarry Smith ierr = SNESComputeResidual(snes,w,g); CHKERR(ierr); 413*5e42470aSBarry Smith VecNorm(g, gnorm ); 414*5e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* Sufficient reduction */ 415*5e42470aSBarry Smith VecCopy(w, y ); 416*5e42470aSBarry Smith PLogInfo((PetscObject)snes,"Using full step\n"); 417*5e42470aSBarry Smith return 0; 418*5e42470aSBarry Smith } 419*5e42470aSBarry Smith 420*5e42470aSBarry Smith /* Fit points with quadratic */ 421*5e42470aSBarry Smith lambda = 1.0; count = 0; 422*5e42470aSBarry Smith count = 1; 423*5e42470aSBarry Smith while (1) { 424*5e42470aSBarry Smith if (lambda <= minlambda) { /* bad luck; use full step */ 425*5e42470aSBarry Smith PLogInfo((PetscObject)snes,"Unable to find good step length! %d \n",count); 426*5e42470aSBarry Smith PLogInfo((PetscObject)snes, "f %g fnew %g ynorm %g lambda %g \n", 427*5e42470aSBarry Smith fnorm,*gnorm, *ynorm,lambda); 428*5e42470aSBarry Smith VecCopy(w, y ); 429*5e42470aSBarry Smith return 0; 430*5e42470aSBarry Smith } 431*5e42470aSBarry Smith lambdatemp = -initslope/(2.0*(*gnorm - fnorm - initslope)); 432*5e42470aSBarry Smith lambdaprev = lambda; 433*5e42470aSBarry Smith gnormprev = *gnorm; 434*5e42470aSBarry Smith if (lambdatemp <= .1*lambda) { 435*5e42470aSBarry Smith lambda = .1*lambda; 436*5e42470aSBarry Smith } else lambda = lambdatemp; 437*5e42470aSBarry Smith VecCopy(x, w ); 438*5e42470aSBarry Smith #if defined(PETSC_COMPLEX) 439*5e42470aSBarry Smith clambda = lambda; VecAXPY(&clambda, y, w ); 440*5e42470aSBarry Smith #else 441*5e42470aSBarry Smith VecAXPY(&lambda, y, w ); 442*5e42470aSBarry Smith #endif 443*5e42470aSBarry Smith ierr = SNESComputeResidual(snes,w,g); CHKERR(ierr); 444*5e42470aSBarry Smith VecNorm(g, gnorm ); 445*5e42470aSBarry Smith if (*gnorm <= fnorm + alpha*initslope) { /* sufficient reduction */ 446*5e42470aSBarry Smith VecCopy(w, y ); 447*5e42470aSBarry Smith PLogInfo((PetscObject)snes,"Quadratically determined step, lambda %g\n",lambda); 448*5e42470aSBarry Smith return 0; 449*5e42470aSBarry Smith } 450*5e42470aSBarry Smith count++; 451*5e42470aSBarry Smith } 452*5e42470aSBarry Smith 453*5e42470aSBarry Smith return 0; 4545e76c431SBarry Smith } 4555e76c431SBarry Smith /* ------------------------------------------------------------ */ 4565e76c431SBarry Smith /*@C 457*5e42470aSBarry Smith SNESSetLineSearchRoutine - Sets the line search routine to be used 458*5e42470aSBarry Smith by the method SNES_NLS1. 4595e76c431SBarry Smith 4605e76c431SBarry Smith Input Parameters: 461*5e42470aSBarry Smith . snes - nonlinear context obtained from NLCreate() 4625e76c431SBarry Smith . func - pointer to int function 4635e76c431SBarry Smith 4645e76c431SBarry Smith Possible routines: 465*5e42470aSBarry Smith SNESCubicLineSearch() - default line search 466*5e42470aSBarry Smith SNESNoLineSearch() - the full Newton step (actually not a line search) 4675e76c431SBarry Smith 4685e76c431SBarry Smith Calling sequence of func: 469*5e42470aSBarry Smith . func (SNES snes, Vec x, Vec f, Vec g, Vec y, 470*5e42470aSBarry Smith Vec w, double fnorm, double *ynorm, double *gnorm ) 4715e76c431SBarry Smith 4725e76c431SBarry Smith Input parameters for func: 473*5e42470aSBarry Smith . snes - nonlinear context 4745e76c431SBarry Smith . x - current iterate 4755e76c431SBarry Smith . f - residual evaluated at x 4765e76c431SBarry Smith . y - search direction (contains new iterate on output) 4775e76c431SBarry Smith . w - work vector 4785e76c431SBarry Smith . fnorm - 2-norm of f 4795e76c431SBarry Smith 4805e76c431SBarry Smith Output parameters for func: 4815e76c431SBarry Smith . g - residual evaluated at new iterate y 4825e76c431SBarry Smith . y - new iterate (contains search direction on input) 4835e76c431SBarry Smith . gnorm - 2-norm of g 4845e76c431SBarry Smith . ynorm - 2-norm of search length 4855e76c431SBarry Smith 4865e76c431SBarry Smith Returned by func: 4875e76c431SBarry Smith 1 if the line search succeeds; 0 if the line search fails. 4885e76c431SBarry Smith @*/ 489*5e42470aSBarry Smith int SNESSetLineSearchRoutine(SNES snes,int (*func)(SNES,Vec,Vec,Vec,Vec,Vec, 490*5e42470aSBarry Smith double,double *,double*) ) 4915e76c431SBarry Smith { 492*5e42470aSBarry Smith if ((snes)->type == SNES_NLS1) 493*5e42470aSBarry Smith ((SNES_LS *)(snes->data))->LineSearch = func; 494*5e42470aSBarry Smith return 0; 4955e76c431SBarry Smith } 496*5e42470aSBarry Smith 497*5e42470aSBarry Smith static int SNESPrintHelp_LS(SNES snes) 498*5e42470aSBarry Smith { 499*5e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 500*5e42470aSBarry Smith fprintf(stderr,"-snes_line_search [basic,quadratic,cubic]\n"); 501*5e42470aSBarry Smith fprintf(stderr,"-snes_line_search_alpha alpha (default %g)\n",ls->alpha); 502*5e42470aSBarry Smith fprintf(stderr,"-snes_line_search_maxstep max (default %g)\n",ls->maxstep); 503*5e42470aSBarry Smith fprintf(stderr,"-snes_line_search_steptol tol (default %g)\n",ls->steptol); 504*5e42470aSBarry Smith } 505*5e42470aSBarry Smith 506*5e42470aSBarry Smith static int SNESSetFromOptions_LS(SNES snes) 507*5e42470aSBarry Smith { 508*5e42470aSBarry Smith SNES_LS *ls = (SNES_LS *)snes->data; 509*5e42470aSBarry Smith char ver[16]; 510*5e42470aSBarry Smith double tmp; 511*5e42470aSBarry Smith 512*5e42470aSBarry Smith if (OptionsGetDouble(0,snes->prefix,"-snes_line_search_alpa",&tmp)) { 513*5e42470aSBarry Smith ls->alpha = tmp; 514*5e42470aSBarry Smith } 515*5e42470aSBarry Smith if (OptionsGetDouble(0,snes->prefix,"-snes_line_search_maxstep",&tmp)) { 516*5e42470aSBarry Smith ls->maxstep = tmp; 517*5e42470aSBarry Smith } 518*5e42470aSBarry Smith if (OptionsGetDouble(0,snes->prefix,"-snes_line_search_steptol",&tmp)) { 519*5e42470aSBarry Smith ls->steptol = tmp; 520*5e42470aSBarry Smith } 521*5e42470aSBarry Smith if (OptionsGetString(0,snes->prefix,"-snes_line_search",ver,16)) { 522*5e42470aSBarry Smith if (!strcmp(ver,"basic")) { 523*5e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESNoLineSearch); 524*5e42470aSBarry Smith } 525*5e42470aSBarry Smith else if (!strcmp(ver,"quadratic")) { 526*5e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESQuadraticLineSearch); 527*5e42470aSBarry Smith } 528*5e42470aSBarry Smith else if (!strcmp(ver,"cubic")) { 529*5e42470aSBarry Smith SNESSetLineSearchRoutine(snes,SNESCubicLineSearch); 530*5e42470aSBarry Smith } 531*5e42470aSBarry Smith else {SETERR(1,"Unknown line search?");} 532*5e42470aSBarry Smith } 533*5e42470aSBarry Smith return 0; 534*5e42470aSBarry Smith } 535*5e42470aSBarry Smith 536*5e42470aSBarry Smith /* ------------------------------------------------------------ */ 537*5e42470aSBarry Smith int SNESCreate_LS(SNES snes ) 538*5e42470aSBarry Smith { 539*5e42470aSBarry Smith SNES_LS *neP; 540*5e42470aSBarry Smith 541*5e42470aSBarry Smith snes->type = SNES_NLS1; 542*5e42470aSBarry Smith snes->Setup = SNESSetUp_LS; 543*5e42470aSBarry Smith snes->Solver = SNESSolve_LS; 544*5e42470aSBarry Smith snes->destroy = SNESDestroy_LS; 545*5e42470aSBarry Smith snes->Monitor = SNESDefaultMonitor; 546*5e42470aSBarry Smith snes->Converged = SNESDefaultConverged; 547*5e42470aSBarry Smith snes->PrintHelp = SNESPrintHelp_LS; 548*5e42470aSBarry Smith snes->SetFromOptions = SNESSetFromOptions_LS; 549*5e42470aSBarry Smith 550*5e42470aSBarry Smith neP = NEW(SNES_LS); CHKPTR(neP); 551*5e42470aSBarry Smith snes->data = (void *) neP; 552*5e42470aSBarry Smith neP->alpha = 1.e-4; 553*5e42470aSBarry Smith neP->maxstep = 1.e8; 554*5e42470aSBarry Smith neP->steptol = 1.e-12; 555*5e42470aSBarry Smith neP->LineSearch = SNESCubicLineSearch; 556*5e42470aSBarry Smith return 0; 557*5e42470aSBarry Smith } 558*5e42470aSBarry Smith 559*5e42470aSBarry Smith 560*5e42470aSBarry Smith 561*5e42470aSBarry Smith 562