xref: /petsc/src/snes/impls/tr/tr.c (revision fbe28522c53d349534977c8c6cbaf0d5bf3f7b02)
14800dd8cSBarry Smith #ifndef lint
2*fbe28522SBarry Smith static char vcid[] = "$Id: tr.c,v 1.1 1995/04/12 20:36:40 bsmith Exp bsmith $";
34800dd8cSBarry Smith #endif
44800dd8cSBarry Smith 
54800dd8cSBarry Smith #include <math.h>
6*fbe28522SBarry Smith #include "tr.h"
74800dd8cSBarry Smith 
8*fbe28522SBarry Smith /*
94800dd8cSBarry Smith     NLE_NTR1 - Implements Newton's Method with a trust region
104800dd8cSBarry Smith     approach for solving systems of nonlinear equations.
114800dd8cSBarry Smith 
124800dd8cSBarry Smith     Input parameters:
134800dd8cSBarry Smith .   nlP - nonlinear context obtained from NLCreate()
144800dd8cSBarry Smith 
154800dd8cSBarry Smith     Returns:
164800dd8cSBarry Smith     Number of global iterations until termination.  The precise type of
174800dd8cSBarry Smith     termination can be examined by calling NLGetTerminationType() after
184800dd8cSBarry Smith     NLSolve().
194800dd8cSBarry Smith 
204800dd8cSBarry Smith     Calling sequence:
214800dd8cSBarry Smith $   nlP = NLCreate(NLE_NTR1,0)
224800dd8cSBarry Smith $   NLCreateDVectors()
234800dd8cSBarry Smith $   NLSet***()
244800dd8cSBarry Smith $   NLSetUp()
254800dd8cSBarry Smith $   NLSolve()
264800dd8cSBarry Smith $   NLDestroy()
274800dd8cSBarry Smith 
284800dd8cSBarry Smith     Notes:
294800dd8cSBarry Smith     See NLCreate() and NLSetUp() for information on the definition and
304800dd8cSBarry Smith     initialization of the nonlinear solver context.
314800dd8cSBarry Smith 
324800dd8cSBarry Smith     The basic algorithm is taken from "The Minpack Project", by More',
334800dd8cSBarry Smith     Sorensen, Garbow, Hillstrom, pages 88-111 of "Sources and Development
344800dd8cSBarry Smith     of Mathematical Software", Wayne Cowell, editor.  See the examples
354800dd8cSBarry Smith     in nonlin/examples.
36*fbe28522SBarry Smith */
374800dd8cSBarry Smith /*
384800dd8cSBarry Smith    This is intended as a model implementation, since it does not
394800dd8cSBarry Smith    necessarily have many of the bells and whistles of other
404800dd8cSBarry Smith    implementations.
414800dd8cSBarry Smith 
424800dd8cSBarry Smith    The code is DATA-STRUCTURE NEUTRAL and can be called RECURSIVELY.
434800dd8cSBarry Smith    The following context variable is used:
444800dd8cSBarry Smith      NLCtx *nlP - The nonlinear solver context, which is created by
454800dd8cSBarry Smith                   calling NLCreate(NLE_NTR1).
464800dd8cSBarry Smith 
474800dd8cSBarry Smith    The step_compute routine must return two values:
484800dd8cSBarry Smith      1) ynorm - the norm of the step
494800dd8cSBarry Smith      2) gpnorm - the predicted value for the residual norm at the new
504800dd8cSBarry Smith         point, assuming a local linearization.  The value is 0 if the
514800dd8cSBarry Smith         step lies within the trust region and is > 0 otherwise.
524800dd8cSBarry Smith */
53*fbe28522SBarry Smith static int SNESSolve_TR(SNES snes, int *its )
544800dd8cSBarry Smith {
55*fbe28522SBarry Smith   SNES_TR  *neP = (SNES_TR *) snes->data;
56*fbe28522SBarry Smith   Vec      X, F, Y, G, TMP;
57*fbe28522SBarry Smith   int      maxits, i, iters, history_len, nlconv,ierr,lits;
58*fbe28522SBarry Smith   double   rho, fnorm, gnorm, gpnorm, xnorm, delta,norm;
594800dd8cSBarry Smith   double   *history, ynorm;
60*fbe28522SBarry Smith   Scalar   one = 1.0;
614800dd8cSBarry Smith 
624800dd8cSBarry Smith   nlconv	= 0;			/* convergence monitor */
63*fbe28522SBarry Smith   history	= snes->conv_hist;	/* convergence history */
64*fbe28522SBarry Smith   history_len	= snes->conv_hist_len;	/* convergence history length */
65*fbe28522SBarry Smith   maxits	= snes->max_its;	/* maximum number of iterations */
66*fbe28522SBarry Smith   X		= snes->vec_sol;		/* solution vector */
67*fbe28522SBarry Smith   F		= snes->vec_res;		/* residual vector */
68*fbe28522SBarry Smith   Y		= snes->work[0];		/* work vectors */
69*fbe28522SBarry Smith   G		= snes->work[1];
704800dd8cSBarry Smith 
71*fbe28522SBarry Smith   ierr = SNESComputeInitialGuess(snes,X); CHKERR(ierr);  /* X <- X_0 */
72*fbe28522SBarry Smith   VecNorm(X, &xnorm ); 		/* xnorm = || X || */
734800dd8cSBarry Smith 
74*fbe28522SBarry Smith   ierr = SNESComputeResidual(snes,X,F); CHKERR(ierr); /* (+/-) F(X) */
75*fbe28522SBarry Smith   VecNorm(F, &fnorm );		/* fnorm <- || F || */
76*fbe28522SBarry Smith   snes->norm = fnorm;
774800dd8cSBarry Smith   if (history && history_len > 0) history[0] = fnorm;
784800dd8cSBarry Smith   delta = neP->delta0*fnorm;
794800dd8cSBarry Smith   neP->delta = delta;
80*fbe28522SBarry Smith   if (snes->Monitor)(*snes->Monitor)(snes,0,X,F,fnorm,snes->monP);
814800dd8cSBarry Smith 
824800dd8cSBarry Smith    for ( i=0; i<maxits; i++ ) {
83*fbe28522SBarry Smith      snes->iter = i+1;
844800dd8cSBarry Smith 
85*fbe28522SBarry Smith      (*snes->ComputeJacobian)(X,&snes->jacobian,snes->jacP);
864800dd8cSBarry Smith      while(1) {
87*fbe28522SBarry Smith        ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian,0);
88*fbe28522SBarry Smith        ierr = SLESSolve(snes->sles,F,Y,&lits); CHKERR(ierr);
89*fbe28522SBarry Smith        /* Scale Y if need be and predict new value of F norm */
90*fbe28522SBarry Smith        VecNorm( Y, &norm );
91*fbe28522SBarry Smith        if (norm > delta) {
92*fbe28522SBarry Smith          norm = delta/norm;
93*fbe28522SBarry Smith          gpnorm = (1.0 - norm)*fnorm;
94*fbe28522SBarry Smith          VecScale( &norm, Y );
95*fbe28522SBarry Smith          PLogInfo((PetscObject)snes, "Scaling direction by %g \n",norm );
96*fbe28522SBarry Smith          ynorm = delta;
97*fbe28522SBarry Smith        } else {
98*fbe28522SBarry Smith          gpnorm = 0.0;
99*fbe28522SBarry Smith          PLogInfo((PetscObject)snes,"Direction is in Trust Region \n" );
100*fbe28522SBarry Smith          ynorm = norm;
101*fbe28522SBarry Smith        }
102*fbe28522SBarry Smith        VecAXPY(&one, X, Y );	/* Y <- X + Y */
103*fbe28522SBarry Smith        ierr = SNESComputeResidual(snes,Y,G); CHKERR(ierr); /* (+/-) F(X) */
104*fbe28522SBarry Smith        VecNorm( G, &gnorm );	/* gnorm <- || g || */
1054800dd8cSBarry Smith        if (fnorm == gpnorm) rho = 0.0;
106*fbe28522SBarry Smith        else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm);
1074800dd8cSBarry Smith 
1084800dd8cSBarry Smith        /* Update size of trust region */
1094800dd8cSBarry Smith        if      (rho < neP->mu)  delta *= neP->delta1;
1104800dd8cSBarry Smith        else if (rho < neP->eta) delta *= neP->delta2;
1114800dd8cSBarry Smith        else                     delta *= neP->delta3;
1124800dd8cSBarry Smith 
113*fbe28522SBarry Smith        PLogInfo((PetscObject)snes,"%d:  f_norm=%g, g_norm=%g, ynorm=%g\n",
1144800dd8cSBarry Smith                                              i, fnorm, gnorm, ynorm );
115*fbe28522SBarry Smith        PLogInfo((PetscObject)snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n",
116*fbe28522SBarry Smith                                                gpnorm, rho, delta, lits);
1174800dd8cSBarry Smith 
1184800dd8cSBarry Smith        neP->delta = delta;
1194800dd8cSBarry Smith        if (rho > neP->sigma) break;
1204800dd8cSBarry Smith        neP->itflag = 0;
121*fbe28522SBarry Smith        if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP)) {
1224800dd8cSBarry Smith          /* We're not progressing, so return with the current iterate */
123*fbe28522SBarry Smith          if (X != snes->vec_sol) VecCopy( X, snes->vec_sol );
1244800dd8cSBarry Smith          return i;
1254800dd8cSBarry Smith        }
1264800dd8cSBarry Smith      }
1274800dd8cSBarry Smith      fnorm = gnorm;
128*fbe28522SBarry Smith      snes->norm = fnorm;
1294800dd8cSBarry Smith      if (history && history_len > i+1) history[i+1] = fnorm;
1304800dd8cSBarry Smith      TMP = F; F = G; G = TMP;
1314800dd8cSBarry Smith      TMP = X; X = Y; Y = TMP;
132*fbe28522SBarry Smith      VecNorm(X, &xnorm );		/* xnorm = || X || */
133*fbe28522SBarry Smith      if (snes->Monitor) (*snes->Monitor)(snes,0,X,F,fnorm,snes->monP);
1344800dd8cSBarry Smith 
1354800dd8cSBarry Smith      /* Test for convergence */
1364800dd8cSBarry Smith      neP->itflag = 1;
137*fbe28522SBarry Smith      if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) {
1384800dd8cSBarry Smith        /* Verify solution is in corect location */
139*fbe28522SBarry Smith        if (X != snes->vec_sol) VecCopy(X, snes->vec_sol );
1404800dd8cSBarry Smith        break;
1414800dd8cSBarry Smith      }
1424800dd8cSBarry Smith    }
143*fbe28522SBarry Smith    if (i == maxits) *its = i-1; else *its = i;
144*fbe28522SBarry Smith    return 0;
1454800dd8cSBarry Smith }
1464800dd8cSBarry Smith /* -------------------------------------------------------------*/
1474800dd8cSBarry Smith 
1484800dd8cSBarry Smith /*------------------------------------------------------------*/
149*fbe28522SBarry Smith static int SNESSetUp_TR( SNES snes )
1504800dd8cSBarry Smith {
151*fbe28522SBarry Smith   int ierr;
152*fbe28522SBarry Smith   snes->nwork = 2;
153*fbe28522SBarry Smith   ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERR(ierr);
154*fbe28522SBarry Smith   return 0;
1554800dd8cSBarry Smith }
1564800dd8cSBarry Smith /*------------------------------------------------------------*/
157*fbe28522SBarry Smith static int SNESDestroy_TR(PetscObject obj )
1584800dd8cSBarry Smith {
159*fbe28522SBarry Smith   SNES snes = (SNES) obj;
160*fbe28522SBarry Smith   VecFreeVecs(snes->work, snes->nwork );
161*fbe28522SBarry Smith   return 0;
1624800dd8cSBarry Smith }
1634800dd8cSBarry Smith /*------------------------------------------------------------*/
1644800dd8cSBarry Smith /*@
165*fbe28522SBarry Smith    SNESTRDefaultConverged - Default test for monitoring the
1664800dd8cSBarry Smith    convergence of the method NLENewtonTR1Solve.
1674800dd8cSBarry Smith 
1684800dd8cSBarry Smith    Input Parameters:
169*fbe28522SBarry Smith .  snes - nonlinear context obtained from NLCreate()
1704800dd8cSBarry Smith .  xnorm - 2-norm of current iterate
1714800dd8cSBarry Smith .  pnorm - 2-norm of current step
1724800dd8cSBarry Smith .  fnorm - 2-norm of residual
1734800dd8cSBarry Smith 
1744800dd8cSBarry Smith    Returns:
1754800dd8cSBarry Smith $  1  if  ( delta < xnorm*deltatol ),
1764800dd8cSBarry Smith $  2  if  ( fnorm < atol ),
1774800dd8cSBarry Smith $  3  if  ( pnorm < xtol*xnorm ),
1784800dd8cSBarry Smith $ -2  if  ( nres > max_res ),
1794800dd8cSBarry Smith $ -1  if  ( delta < xnorm*epsmch ),
1804800dd8cSBarry Smith $  0  otherwise,
1814800dd8cSBarry Smith 
1824800dd8cSBarry Smith    where
1834800dd8cSBarry Smith $    atol     - absolute residual norm tolerance,
1844800dd8cSBarry Smith $               set with NLSetAbsConvergenceTol()
1854800dd8cSBarry Smith $    delta    - trust region paramenter
1864800dd8cSBarry Smith $    deltatol - trust region size tolerance,
1874800dd8cSBarry Smith $               set with NLSetTrustRegionTol()
1884800dd8cSBarry Smith $    epsmch   - machine epsilon
1894800dd8cSBarry Smith $    max_res  - maximum number of residual evaluations,
1904800dd8cSBarry Smith $               set with NLSetMaxResidualEvaluations()
1914800dd8cSBarry Smith $    nres     - number of residual evaluations
1924800dd8cSBarry Smith $    xtol     - relative residual norm tolerance,
1934800dd8cSBarry Smith $               set with NLSetRelConvergenceTol()
1944800dd8cSBarry Smith 
1954800dd8cSBarry Smith    Note:
1964800dd8cSBarry Smith    Call NLGetConvergenceType() after calling NLSolve() to obtain
1974800dd8cSBarry Smith    information about the type of termination which occurred for the
1984800dd8cSBarry Smith    nonlinear solver.
1994800dd8cSBarry Smith @*/
200*fbe28522SBarry Smith int SNESTRDefaultConverged(SNES snes, double xnorm, double pnorm,
201*fbe28522SBarry Smith                            double fnorm, void *ctx )
2024800dd8cSBarry Smith {
203*fbe28522SBarry Smith   SNES_TR *neP = (SNES_TR *)snes->data;
2044800dd8cSBarry Smith   double  epsmch = 1.0e-14;   /* This must be fixed */
2054800dd8cSBarry Smith 
206*fbe28522SBarry Smith   if (neP->delta < xnorm * neP->deltatol) 	return  1;
207*fbe28522SBarry Smith   if (neP->itflag) {
208*fbe28522SBarry Smith           return SNESDefaultConverged( snes, xnorm, pnorm, fnorm,ctx );
209*fbe28522SBarry Smith       }
210*fbe28522SBarry Smith   if (neP->delta < xnorm * epsmch)		return -1;
2114800dd8cSBarry Smith   return 0;
2124800dd8cSBarry Smith }
2134800dd8cSBarry Smith 
214*fbe28522SBarry Smith static int SNESSetFromOptions_TR(SNES snes)
2154800dd8cSBarry Smith {
216*fbe28522SBarry Smith   SNES_TR *ctx = (SNES_TR *)snes->data;
217*fbe28522SBarry Smith   double  tmp;
2184800dd8cSBarry Smith 
219*fbe28522SBarry Smith   if (OptionsGetDouble(0,snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;}
220*fbe28522SBarry Smith   if (OptionsGetDouble(0,snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;}
221*fbe28522SBarry Smith   if (OptionsGetDouble(0,snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;}
222*fbe28522SBarry Smith   if (OptionsGetDouble(0,snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;}
223*fbe28522SBarry Smith   if (OptionsGetDouble(0,snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;}
224*fbe28522SBarry Smith   if (OptionsGetDouble(0,snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;}
225*fbe28522SBarry Smith   if (OptionsGetDouble(0,snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;}
226*fbe28522SBarry Smith   return 0;
2274800dd8cSBarry Smith }
2284800dd8cSBarry Smith 
229*fbe28522SBarry Smith static int SNESPrintHelp_TR(SNES snes)
2304800dd8cSBarry Smith {
231*fbe28522SBarry Smith   SNES_TR *ctx = (SNES_TR *)snes->data;
232*fbe28522SBarry Smith   char    *prefix = "-";
233*fbe28522SBarry Smith   if (snes->prefix) prefix = snes->prefix;
234*fbe28522SBarry Smith   fprintf(stderr,"%smu mu (default %g)\n",prefix,ctx->mu);
235*fbe28522SBarry Smith   fprintf(stderr,"%seta eta (default %g)\n",prefix,ctx->eta);
236*fbe28522SBarry Smith   fprintf(stderr,"%ssigma sigma (default %g)\n",prefix,ctx->sigma);
237*fbe28522SBarry Smith   fprintf(stderr,"%sdelta0 delta0 (default %g)\n",prefix,ctx->delta0);
238*fbe28522SBarry Smith   fprintf(stderr,"%sdelta1 delta1 (default %g)\n",prefix,ctx->delta1);
239*fbe28522SBarry Smith   fprintf(stderr,"%sdelta2 delta2 (default %g)\n",prefix,ctx->delta2);
240*fbe28522SBarry Smith   fprintf(stderr,"%sdelta3 delta3 (default %g)\n",prefix,ctx->delta3);
241*fbe28522SBarry Smith   return 0;
2424800dd8cSBarry Smith }
2434800dd8cSBarry Smith 
244*fbe28522SBarry Smith int SNESCreate_TR(SNES snes )
2454800dd8cSBarry Smith {
246*fbe28522SBarry Smith   SNES_TR *neP;
2474800dd8cSBarry Smith 
248*fbe28522SBarry Smith   snes->type 		= SNES_NTR;
249*fbe28522SBarry Smith   snes->Setup		= SNESSetUp_TR;
250*fbe28522SBarry Smith   snes->Solver		= SNESSolve_TR;
251*fbe28522SBarry Smith   snes->destroy		= SNESDestroy_TR;
252*fbe28522SBarry Smith   snes->Monitor  	= 0;
253*fbe28522SBarry Smith   snes->Converged	= SNESTRDefaultConverged;
254*fbe28522SBarry Smith   snes->PrintHelp       = SNESPrintHelp_TR;
255*fbe28522SBarry Smith   snes->SetFromOptions  = SNESSetFromOptions_TR;
256*fbe28522SBarry Smith 
257*fbe28522SBarry Smith   neP			= NEW(SNES_TR); CHKPTR(neP);
258*fbe28522SBarry Smith   snes->data	        = (void *) neP;
259*fbe28522SBarry Smith   neP->mu		= 0.25;
260*fbe28522SBarry Smith   neP->eta		= 0.75;
261*fbe28522SBarry Smith   neP->delta		= 0.0;
262*fbe28522SBarry Smith   neP->delta0		= 0.2;
263*fbe28522SBarry Smith   neP->delta1		= 0.3;
264*fbe28522SBarry Smith   neP->delta2		= 0.75;
265*fbe28522SBarry Smith   neP->delta3		= 2.0;
266*fbe28522SBarry Smith   neP->sigma		= 0.0001;
267*fbe28522SBarry Smith   neP->itflag		= 0;
2684800dd8cSBarry Smith }
269