xref: /petsc/src/snes/impls/tr/tr.c (revision 369a4401ebeca8baccc22dd3d5896cf35eb2576f)
14800dd8cSBarry Smith #ifndef lint
2*369a4401SLois Curfman McInnes static char vcid[] = "$Id: tr.c,v 1.17 1995/07/20 15:35:04 curfman Exp curfman $";
34800dd8cSBarry Smith #endif
44800dd8cSBarry Smith 
54800dd8cSBarry Smith #include <math.h>
6fbe28522SBarry Smith #include "tr.h"
7a935fc98SLois Curfman McInnes #include "pviewer.h"
84800dd8cSBarry Smith 
9fbe28522SBarry Smith /*
10df60cc22SBarry Smith       This convergence test determines if the two norm of the
11df60cc22SBarry Smith    solution lies outside the trust region, if so it halts.
12df60cc22SBarry Smith */
13df60cc22SBarry Smith int TRConverged_Private(KSP ksp,int n, double rnorm, void *ctx)
14df60cc22SBarry Smith {
15df60cc22SBarry Smith   SNES    snes = (SNES) ctx;
16df60cc22SBarry Smith   SNES_TR *neP = (SNES_TR*)snes->data;
17df60cc22SBarry Smith   double  rtol,atol,dtol,norm;
18df60cc22SBarry Smith   Vec     x;
1925c7317fSLois Curfman McInnes   int     ierr, mkit;
20df60cc22SBarry Smith 
2125c7317fSLois Curfman McInnes   KSPGetTolerances(ksp,&rtol,&atol,&dtol,&mkit);
22df60cc22SBarry Smith 
23df60cc22SBarry Smith   if ( n == 0 ) {
24df60cc22SBarry Smith     neP->ttol   = MAX(rtol*rnorm,atol);
25df60cc22SBarry Smith     neP->rnorm0 = rnorm;
26df60cc22SBarry Smith   }
27df60cc22SBarry Smith   if ( rnorm <= neP->ttol )      return 1;
28df60cc22SBarry Smith   if ( rnorm >= dtol*neP->rnorm0 || rnorm != rnorm) return -1;
29df60cc22SBarry Smith 
30a935fc98SLois Curfman McInnes   /* Determine norm of solution */
3178b31e54SBarry Smith   ierr = KSPBuildSolution(ksp,0,&x); CHKERRQ(ierr);
3278b31e54SBarry Smith   ierr = VecNorm(x,&norm); CHKERRQ(ierr);
33df60cc22SBarry Smith   if (norm >= neP->delta) {
34a935fc98SLois Curfman McInnes     PLogInfo((PetscObject)snes,
35a935fc98SLois Curfman McInnes       "Ending linear iteration early, delta %g length %g\n",neP->delta,norm);
36df60cc22SBarry Smith     return 1;
37df60cc22SBarry Smith   }
38df60cc22SBarry Smith   return(0);
39df60cc22SBarry Smith }
40df60cc22SBarry Smith /*
41ddbbdb52SLois Curfman McInnes    SNESSolve_TR - Implements Newton's Method with a very simple trust
42ddbbdb52SLois Curfman McInnes    region approach for solving systems of nonlinear equations.
434800dd8cSBarry Smith 
444800dd8cSBarry Smith    The basic algorithm is taken from "The Minpack Project", by More',
454800dd8cSBarry Smith    Sorensen, Garbow, Hillstrom, pages 88-111 of "Sources and Development
46ddbbdb52SLois Curfman McInnes    of Mathematical Software", Wayne Cowell, editor.
47ddbbdb52SLois Curfman McInnes 
484800dd8cSBarry Smith    This is intended as a model implementation, since it does not
494800dd8cSBarry Smith    necessarily have many of the bells and whistles of other
504800dd8cSBarry Smith    implementations.
514800dd8cSBarry Smith */
52fbe28522SBarry Smith static int SNESSolve_TR(SNES snes,int *its)
534800dd8cSBarry Smith {
54fbe28522SBarry Smith   SNES_TR      *neP = (SNES_TR *) snes->data;
556b5873e3SBarry Smith   Vec          X, F, Y, G, TMP, Ytmp;
56ddbbdb52SLois Curfman McInnes   int          maxits, i, history_len, ierr, lits;
57df60cc22SBarry Smith   MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN;
58fbe28522SBarry Smith   double       rho, fnorm, gnorm, gpnorm, xnorm, delta,norm;
594800dd8cSBarry Smith   double       *history, ynorm;
60eafb4bcbSBarry Smith   Scalar       one = 1.0,cnorm;
616b5873e3SBarry Smith   double       epsmch = 1.0e-14;   /* This must be fixed */
62df60cc22SBarry Smith   KSP          ksp;
63df60cc22SBarry Smith   SLES         sles;
644800dd8cSBarry Smith 
65fbe28522SBarry Smith   history	= snes->conv_hist;	/* convergence history */
66fbe28522SBarry Smith   history_len	= snes->conv_hist_len;	/* convergence history length */
67fbe28522SBarry Smith   maxits	= snes->max_its;	/* maximum number of iterations */
68fbe28522SBarry Smith   X		= snes->vec_sol;	/* solution vector */
6939e2f89bSBarry Smith   F		= snes->vec_func;	/* residual vector */
70fbe28522SBarry Smith   Y		= snes->work[0];	/* work vectors */
71fbe28522SBarry Smith   G		= snes->work[1];
726b5873e3SBarry Smith   Ytmp          = snes->work[2];
734800dd8cSBarry Smith 
7478b31e54SBarry Smith   ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr);  /* X <- X_0 */
75fbe28522SBarry Smith   VecNorm(X, &xnorm ); 		/* xnorm = || X || */
764800dd8cSBarry Smith 
7778b31e54SBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* (+/-) F(X) */
78fbe28522SBarry Smith   VecNorm(F, &fnorm );		/* fnorm <- || F || */
79fbe28522SBarry Smith   snes->norm = fnorm;
804800dd8cSBarry Smith   if (history && history_len > 0) history[0] = fnorm;
814800dd8cSBarry Smith   delta = neP->delta0*fnorm;
824800dd8cSBarry Smith   neP->delta = delta;
83bbb6d6a8SBarry Smith   if (snes->monitor)
84bbb6d6a8SBarry Smith     {ierr = (*snes->monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);}
854800dd8cSBarry Smith 
86a935fc98SLois Curfman McInnes   /* Set the stopping criteria to use the More' trick. */
8778b31e54SBarry Smith   ierr = SNESGetSLES(snes,&sles); CHKERRQ(ierr);
8878b31e54SBarry Smith   ierr = SLESGetKSP(sles,&ksp); CHKERRQ(ierr);
89df60cc22SBarry Smith   ierr = KSPSetConvergenceTest(ksp,TRConverged_Private,(void *) snes);
9078b31e54SBarry Smith   CHKERRQ(ierr);
91df60cc22SBarry Smith 
924800dd8cSBarry Smith   for ( i=0; i<maxits; i++ ) {
93fbe28522SBarry Smith      snes->iter = i+1;
944800dd8cSBarry Smith 
95df60cc22SBarry Smith      ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,
96bbb6d6a8SBarry Smith                                              &flg); CHKERRQ(ierr);
97a935fc98SLois Curfman McInnes      ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,
98a935fc98SLois Curfman McInnes                             flg); CHKERRQ(ierr);
9978b31e54SBarry Smith      ierr = SLESSolve(snes->sles,F,Ytmp,&lits); CHKERRQ(ierr);
1006b5873e3SBarry Smith      VecNorm( Ytmp, &norm );
1016b5873e3SBarry Smith      while(1) {
1026b5873e3SBarry Smith        VecCopy(Ytmp,Y);
103fbe28522SBarry Smith        /* Scale Y if need be and predict new value of F norm */
1046b5873e3SBarry Smith 
105eafb4bcbSBarry Smith        if (norm >= delta) {
106fbe28522SBarry Smith          norm = delta/norm;
107fbe28522SBarry Smith          gpnorm = (1.0 - norm)*fnorm;
108eafb4bcbSBarry Smith          cnorm = norm;
109df60cc22SBarry Smith          PLogInfo((PetscObject)snes, "Scaling direction by %g \n",norm );
110eafb4bcbSBarry Smith          VecScale( &cnorm, Y );
111eafb4bcbSBarry Smith          norm = gpnorm;
112fbe28522SBarry Smith          ynorm = delta;
113fbe28522SBarry Smith        } else {
114fbe28522SBarry Smith          gpnorm = 0.0;
115fbe28522SBarry Smith          PLogInfo((PetscObject)snes,"Direction is in Trust Region \n" );
116fbe28522SBarry Smith          ynorm = norm;
117fbe28522SBarry Smith        }
118fbe28522SBarry Smith        VecAXPY(&one, X, Y );	/* Y <- X + Y */
11981b6cf68SLois Curfman McInnes        ierr = VecCopy(X,snes->vec_sol_update_always); CHKERRQ(ierr);
12078b31e54SBarry Smith        ierr = SNESComputeFunction(snes,Y,G); CHKERRQ(ierr); /* (+/-) F(X) */
121fbe28522SBarry Smith        VecNorm( G, &gnorm );	/* gnorm <- || g || */
1224800dd8cSBarry Smith        if (fnorm == gpnorm) rho = 0.0;
123fbe28522SBarry Smith        else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm);
1244800dd8cSBarry Smith 
1254800dd8cSBarry Smith        /* Update size of trust region */
1264800dd8cSBarry Smith        if      (rho < neP->mu)  delta *= neP->delta1;
1274800dd8cSBarry Smith        else if (rho < neP->eta) delta *= neP->delta2;
1284800dd8cSBarry Smith        else                     delta *= neP->delta3;
1294800dd8cSBarry Smith 
130fbe28522SBarry Smith        PLogInfo((PetscObject)snes,"%d:  f_norm=%g, g_norm=%g, ynorm=%g\n",
1314800dd8cSBarry Smith                                              i, fnorm, gnorm, ynorm );
132fbe28522SBarry Smith        PLogInfo((PetscObject)snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n",
133fbe28522SBarry Smith                                                gpnorm, rho, delta, lits);
1344800dd8cSBarry Smith 
1354800dd8cSBarry Smith        neP->delta = delta;
1364800dd8cSBarry Smith        if (rho > neP->sigma) break;
137eafb4bcbSBarry Smith        PLogInfo((PetscObject)snes,"Trying again in smaller region\n");
1386b5873e3SBarry Smith        /* check to see if progress is hopeless */
1396b5873e3SBarry Smith        if (neP->delta < xnorm * epsmch)	return -1;
1404800dd8cSBarry Smith      }
1414800dd8cSBarry Smith      fnorm = gnorm;
142fbe28522SBarry Smith      snes->norm = fnorm;
1434800dd8cSBarry Smith      if (history && history_len > i+1) history[i+1] = fnorm;
14439e2f89bSBarry Smith      TMP = F; F = G; snes->vec_func_always = F; G = TMP;
14539e2f89bSBarry Smith      TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
146fbe28522SBarry Smith      VecNorm(X, &xnorm );		/* xnorm = || X || */
147bbb6d6a8SBarry Smith      if (snes->monitor)
148bbb6d6a8SBarry Smith        {(*snes->monitor)(snes,i+1,fnorm,snes->monP); CHKERRQ(ierr);}
1494800dd8cSBarry Smith 
1504800dd8cSBarry Smith      /* Test for convergence */
151bbb6d6a8SBarry Smith      if ((*snes->converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) {
1524800dd8cSBarry Smith        /* Verify solution is in corect location */
15339e2f89bSBarry Smith        if (X != snes->vec_sol) {
15439e2f89bSBarry Smith          VecCopy(X, snes->vec_sol );
15539e2f89bSBarry Smith          snes->vec_sol_always = snes->vec_sol;
15639e2f89bSBarry Smith          snes->vec_func_always = snes->vec_func;
15739e2f89bSBarry Smith        }
1584800dd8cSBarry Smith        break;
1594800dd8cSBarry Smith      }
1604800dd8cSBarry Smith    }
161614e12f8SBarry Smith    if (i == maxits) *its = i-1; else *its = i + 1;
162fbe28522SBarry Smith    return 0;
1634800dd8cSBarry Smith }
1644800dd8cSBarry Smith /*------------------------------------------------------------*/
165fbe28522SBarry Smith static int SNESSetUp_TR( SNES snes )
1664800dd8cSBarry Smith {
167fbe28522SBarry Smith   int ierr;
16881b6cf68SLois Curfman McInnes   snes->nwork = 4;
16978b31e54SBarry Smith   ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERRQ(ierr);
17081b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
171fbe28522SBarry Smith   return 0;
1724800dd8cSBarry Smith }
1734800dd8cSBarry Smith /*------------------------------------------------------------*/
174fbe28522SBarry Smith static int SNESDestroy_TR(PetscObject obj )
1754800dd8cSBarry Smith {
176fbe28522SBarry Smith   SNES snes = (SNES) obj;
177fbe28522SBarry Smith   VecFreeVecs(snes->work, snes->nwork );
17878b31e54SBarry Smith   PETSCFREE(snes->data);
179fbe28522SBarry Smith   return 0;
1804800dd8cSBarry Smith }
1814800dd8cSBarry Smith /*------------------------------------------------------------*/
1824800dd8cSBarry Smith 
183fbe28522SBarry Smith static int SNESSetFromOptions_TR(SNES snes)
1844800dd8cSBarry Smith {
185fbe28522SBarry Smith   SNES_TR *ctx = (SNES_TR *)snes->data;
186fbe28522SBarry Smith   double  tmp;
1874800dd8cSBarry Smith 
188df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;}
189df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;}
190df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;}
191df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;}
192df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;}
193df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;}
194df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;}
195fbe28522SBarry Smith   return 0;
1964800dd8cSBarry Smith }
1974800dd8cSBarry Smith 
198fbe28522SBarry Smith static int SNESPrintHelp_TR(SNES snes)
1994800dd8cSBarry Smith {
200fbe28522SBarry Smith   SNES_TR *ctx = (SNES_TR *)snes->data;
201fbe28522SBarry Smith   char    *prefix = "-";
202fbe28522SBarry Smith   if (snes->prefix) prefix = snes->prefix;
20325c7317fSLois Curfman McInnes   MPIU_fprintf(snes->comm,stdout," method tr:\n");
20425c7317fSLois Curfman McInnes   MPIU_fprintf(snes->comm,stdout,"   %smu mu (default %g)\n",prefix,ctx->mu);
20525c7317fSLois Curfman McInnes   MPIU_fprintf(snes->comm,stdout,"   %seta eta (default %g)\n",prefix,ctx->eta);
20625c7317fSLois Curfman McInnes   MPIU_fprintf(snes->comm,stdout,"   %ssigma sigma (default %g)\n",prefix,ctx->sigma);
20725c7317fSLois Curfman McInnes   MPIU_fprintf(snes->comm,stdout,"   %sdelta0 delta0 (default %g)\n",prefix,ctx->delta0);
20825c7317fSLois Curfman McInnes   MPIU_fprintf(snes->comm,stdout,"   %sdelta1 delta1 (default %g)\n",prefix,ctx->delta1);
20925c7317fSLois Curfman McInnes   MPIU_fprintf(snes->comm,stdout,"   %sdelta2 delta2 (default %g)\n",prefix,ctx->delta2);
21025c7317fSLois Curfman McInnes   MPIU_fprintf(snes->comm,stdout,"   %sdelta3 delta3 (default %g)\n",prefix,ctx->delta3);
211fbe28522SBarry Smith   return 0;
2124800dd8cSBarry Smith }
2134800dd8cSBarry Smith 
214a935fc98SLois Curfman McInnes static int SNESView_TR(PetscObject obj,Viewer viewer)
215a935fc98SLois Curfman McInnes {
216a935fc98SLois Curfman McInnes   SNES    snes = (SNES)obj;
217a935fc98SLois Curfman McInnes   SNES_TR *tr = (SNES_TR *)snes->data;
218a935fc98SLois Curfman McInnes   FILE    *fd = ViewerFileGetPointer_Private(viewer);
219a935fc98SLois Curfman McInnes 
220a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    mu=%g, eta=%g, sigma=%g\n",
221a935fc98SLois Curfman McInnes     tr->mu,tr->eta,tr->sigma);
222a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,
223a935fc98SLois Curfman McInnes     "    delta0=%g, delta1=%g, delta2=%g, delta3=%g\n",
224a935fc98SLois Curfman McInnes     tr->delta0,tr->delta1,tr->delta2,tr->delta3);
225a935fc98SLois Curfman McInnes   return 0;
226a935fc98SLois Curfman McInnes }
227a935fc98SLois Curfman McInnes 
228fbe28522SBarry Smith int SNESCreate_TR(SNES snes )
2294800dd8cSBarry Smith {
230fbe28522SBarry Smith   SNES_TR *neP;
2314800dd8cSBarry Smith 
232*369a4401SLois Curfman McInnes   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) SETERRQ(1,
233*369a4401SLois Curfman McInnes     "SNESCreate_TR: Valid for SNES_NONLINEAR_EQUATIONS problems only");
23425c7317fSLois Curfman McInnes   snes->type 		= SNES_EQ_NTR;
23506be10caSBarry Smith   snes->setup		= SNESSetUp_TR;
23606be10caSBarry Smith   snes->solve		= SNESSolve_TR;
237fbe28522SBarry Smith   snes->destroy		= SNESDestroy_TR;
238bbb6d6a8SBarry Smith   snes->converged	= SNESDefaultConverged;
23906be10caSBarry Smith   snes->printhelp       = SNESPrintHelp_TR;
24006be10caSBarry Smith   snes->setfromoptions  = SNESSetFromOptions_TR;
241a935fc98SLois Curfman McInnes   snes->view            = SNESView_TR;
242fbe28522SBarry Smith 
24378b31e54SBarry Smith   neP			= PETSCNEW(SNES_TR); CHKPTRQ(neP);
244fbe28522SBarry Smith   snes->data	        = (void *) neP;
245fbe28522SBarry Smith   neP->mu		= 0.25;
246fbe28522SBarry Smith   neP->eta		= 0.75;
247fbe28522SBarry Smith   neP->delta		= 0.0;
248fbe28522SBarry Smith   neP->delta0		= 0.2;
249fbe28522SBarry Smith   neP->delta1		= 0.3;
250fbe28522SBarry Smith   neP->delta2		= 0.75;
251fbe28522SBarry Smith   neP->delta3		= 2.0;
252fbe28522SBarry Smith   neP->sigma		= 0.0001;
253fbe28522SBarry Smith   neP->itflag		= 0;
2546b5873e3SBarry Smith   return 0;
2554800dd8cSBarry Smith }
256