xref: /petsc/src/snes/impls/tr/tr.c (revision a935fc98aa0ada3a65f6943302157d2323c0d5aa)
14800dd8cSBarry Smith #ifndef lint
2*a935fc98SLois Curfman McInnes static char vcid[] = "$Id: tr.c,v 1.13 1995/06/13 02:24:21 curfman Exp curfman $";
34800dd8cSBarry Smith #endif
44800dd8cSBarry Smith 
54800dd8cSBarry Smith #include <math.h>
6fbe28522SBarry Smith #include "tr.h"
7*a935fc98SLois 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;
19df60cc22SBarry Smith   int     ierr;
20df60cc22SBarry Smith 
21df60cc22SBarry Smith   KSPGetTolerances(ksp,&rtol,&atol,&dtol);
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 
30*a935fc98SLois 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) {
34*a935fc98SLois Curfman McInnes     PLogInfo((PetscObject)snes,
35*a935fc98SLois 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 /*
4139e2f89bSBarry Smith       Implements Newton's Method with a very simple trust region
424800dd8cSBarry Smith     approach for solving systems of nonlinear equations.
434800dd8cSBarry Smith 
444800dd8cSBarry Smith     Input parameters:
456b5873e3SBarry Smith .   nlP - nonlinear context obtained from SNESCreate()
464800dd8cSBarry Smith 
474800dd8cSBarry Smith     The basic algorithm is taken from "The Minpack Project", by More',
484800dd8cSBarry Smith     Sorensen, Garbow, Hillstrom, pages 88-111 of "Sources and Development
494800dd8cSBarry Smith     of Mathematical Software", Wayne Cowell, editor.  See the examples
504800dd8cSBarry Smith     in nonlin/examples.
51fbe28522SBarry Smith */
524800dd8cSBarry Smith /*
534800dd8cSBarry Smith    This is intended as a model implementation, since it does not
544800dd8cSBarry Smith    necessarily have many of the bells and whistles of other
554800dd8cSBarry Smith    implementations.
564800dd8cSBarry Smith 
574800dd8cSBarry Smith */
58fbe28522SBarry Smith static int SNESSolve_TR(SNES snes, int *its )
594800dd8cSBarry Smith {
60fbe28522SBarry Smith   SNES_TR      *neP = (SNES_TR *) snes->data;
616b5873e3SBarry Smith   Vec          X, F, Y, G, TMP, Ytmp;
62edd2f0e1SBarry Smith   int          maxits, i, history_len, nlconv,ierr,lits;
63df60cc22SBarry Smith   MatStructure flg = ALLMAT_DIFFERENT_NONZERO_PATTERN;
64fbe28522SBarry Smith   double       rho, fnorm, gnorm, gpnorm, xnorm, delta,norm;
654800dd8cSBarry Smith   double       *history, ynorm;
66eafb4bcbSBarry Smith   Scalar       one = 1.0,cnorm;
676b5873e3SBarry Smith   double       epsmch = 1.0e-14;   /* This must be fixed */
68df60cc22SBarry Smith   KSP          ksp;
69df60cc22SBarry Smith   SLES         sles;
704800dd8cSBarry Smith 
714800dd8cSBarry Smith   nlconv	= 0;			/* convergence monitor */
72fbe28522SBarry Smith   history	= snes->conv_hist;	/* convergence history */
73fbe28522SBarry Smith   history_len	= snes->conv_hist_len;	/* convergence history length */
74fbe28522SBarry Smith   maxits	= snes->max_its;	/* maximum number of iterations */
75fbe28522SBarry Smith   X		= snes->vec_sol;		/* solution vector */
7639e2f89bSBarry Smith   F		= snes->vec_func;		/* residual vector */
77fbe28522SBarry Smith   Y		= snes->work[0];		/* work vectors */
78fbe28522SBarry Smith   G		= snes->work[1];
796b5873e3SBarry Smith   Ytmp          = snes->work[2];
804800dd8cSBarry Smith 
8178b31e54SBarry Smith   ierr = SNESComputeInitialGuess(snes,X); CHKERRQ(ierr);  /* X <- X_0 */
82fbe28522SBarry Smith   VecNorm(X, &xnorm ); 		/* xnorm = || X || */
834800dd8cSBarry Smith 
8478b31e54SBarry Smith   ierr = SNESComputeFunction(snes,X,F); CHKERRQ(ierr); /* (+/-) F(X) */
85fbe28522SBarry Smith   VecNorm(F, &fnorm );		/* fnorm <- || F || */
86fbe28522SBarry Smith   snes->norm = fnorm;
874800dd8cSBarry Smith   if (history && history_len > 0) history[0] = fnorm;
884800dd8cSBarry Smith   delta = neP->delta0*fnorm;
894800dd8cSBarry Smith   neP->delta = delta;
90*a935fc98SLois Curfman McInnes   if (snes->Monitor)
91*a935fc98SLois Curfman McInnes     {ierr = (*snes->Monitor)(snes,0,fnorm,snes->monP); CHKERRQ(ierr);}
924800dd8cSBarry Smith 
93*a935fc98SLois Curfman McInnes   /* Set the stopping criteria to use the More' trick. */
9478b31e54SBarry Smith   ierr = SNESGetSLES(snes,&sles); CHKERRQ(ierr);
9578b31e54SBarry Smith   ierr = SLESGetKSP(sles,&ksp); CHKERRQ(ierr);
96df60cc22SBarry Smith   ierr = KSPSetConvergenceTest(ksp,TRConverged_Private,(void *) snes);
9778b31e54SBarry Smith   CHKERRQ(ierr);
98df60cc22SBarry Smith 
994800dd8cSBarry Smith   for ( i=0; i<maxits; i++ ) {
100fbe28522SBarry Smith      snes->iter = i+1;
1014800dd8cSBarry Smith 
102df60cc22SBarry Smith      ierr = SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,
10378b31e54SBarry Smith                                              &flg,snes->jacP); CHKERRQ(ierr);
104*a935fc98SLois Curfman McInnes      ierr = SLESSetOperators(snes->sles,snes->jacobian,snes->jacobian_pre,
105*a935fc98SLois Curfman McInnes                             flg); CHKERRQ(ierr);
10678b31e54SBarry Smith      ierr = SLESSolve(snes->sles,F,Ytmp,&lits); CHKERRQ(ierr);
1076b5873e3SBarry Smith      VecNorm( Ytmp, &norm );
1086b5873e3SBarry Smith      while(1) {
1096b5873e3SBarry Smith        VecCopy(Ytmp,Y);
110fbe28522SBarry Smith        /* Scale Y if need be and predict new value of F norm */
1116b5873e3SBarry Smith 
112eafb4bcbSBarry Smith        if (norm >= delta) {
113fbe28522SBarry Smith          norm = delta/norm;
114fbe28522SBarry Smith          gpnorm = (1.0 - norm)*fnorm;
115eafb4bcbSBarry Smith          cnorm = norm;
116df60cc22SBarry Smith          PLogInfo((PetscObject)snes, "Scaling direction by %g \n",norm );
117eafb4bcbSBarry Smith          VecScale( &cnorm, Y );
118eafb4bcbSBarry Smith          norm = gpnorm;
119fbe28522SBarry Smith          ynorm = delta;
120fbe28522SBarry Smith        } else {
121fbe28522SBarry Smith          gpnorm = 0.0;
122fbe28522SBarry Smith          PLogInfo((PetscObject)snes,"Direction is in Trust Region \n" );
123fbe28522SBarry Smith          ynorm = norm;
124fbe28522SBarry Smith        }
125fbe28522SBarry Smith        VecAXPY(&one, X, Y );	/* Y <- X + Y */
12681b6cf68SLois Curfman McInnes        ierr = VecCopy(X,snes->vec_sol_update_always); CHKERRQ(ierr);
12778b31e54SBarry Smith        ierr = SNESComputeFunction(snes,Y,G); CHKERRQ(ierr); /* (+/-) F(X) */
128fbe28522SBarry Smith        VecNorm( G, &gnorm );	/* gnorm <- || g || */
1294800dd8cSBarry Smith        if (fnorm == gpnorm) rho = 0.0;
130fbe28522SBarry Smith        else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm);
1314800dd8cSBarry Smith 
1324800dd8cSBarry Smith        /* Update size of trust region */
1334800dd8cSBarry Smith        if      (rho < neP->mu)  delta *= neP->delta1;
1344800dd8cSBarry Smith        else if (rho < neP->eta) delta *= neP->delta2;
1354800dd8cSBarry Smith        else                     delta *= neP->delta3;
1364800dd8cSBarry Smith 
137fbe28522SBarry Smith        PLogInfo((PetscObject)snes,"%d:  f_norm=%g, g_norm=%g, ynorm=%g\n",
1384800dd8cSBarry Smith                                              i, fnorm, gnorm, ynorm );
139fbe28522SBarry Smith        PLogInfo((PetscObject)snes,"gpred=%g, rho=%g, delta=%g,iters=%d\n",
140fbe28522SBarry Smith                                                gpnorm, rho, delta, lits);
1414800dd8cSBarry Smith 
1424800dd8cSBarry Smith        neP->delta = delta;
1434800dd8cSBarry Smith        if (rho > neP->sigma) break;
144eafb4bcbSBarry Smith        PLogInfo((PetscObject)snes,"Trying again in smaller region\n");
1456b5873e3SBarry Smith        /* check to see if progress is hopeless */
1466b5873e3SBarry Smith        if (neP->delta < xnorm * epsmch)	return -1;
1474800dd8cSBarry Smith      }
1484800dd8cSBarry Smith      fnorm = gnorm;
149fbe28522SBarry Smith      snes->norm = fnorm;
1504800dd8cSBarry Smith      if (history && history_len > i+1) history[i+1] = fnorm;
15139e2f89bSBarry Smith      TMP = F; F = G; snes->vec_func_always = F; G = TMP;
15239e2f89bSBarry Smith      TMP = X; X = Y; snes->vec_sol_always = X; Y = TMP;
153fbe28522SBarry Smith      VecNorm(X, &xnorm );		/* xnorm = || X || */
154*a935fc98SLois Curfman McInnes      if (snes->Monitor)
155*a935fc98SLois Curfman McInnes        {(*snes->Monitor)(snes,i+1,fnorm,snes->monP); CHKERRQ(ierr);}
1564800dd8cSBarry Smith 
1574800dd8cSBarry Smith      /* Test for convergence */
158fbe28522SBarry Smith      if ((*snes->Converged)( snes, xnorm, ynorm, fnorm,snes->cnvP )) {
1594800dd8cSBarry Smith        /* Verify solution is in corect location */
16039e2f89bSBarry Smith        if (X != snes->vec_sol) {
16139e2f89bSBarry Smith          VecCopy(X, snes->vec_sol );
16239e2f89bSBarry Smith          snes->vec_sol_always = snes->vec_sol;
16339e2f89bSBarry Smith          snes->vec_func_always = snes->vec_func;
16439e2f89bSBarry Smith        }
1654800dd8cSBarry Smith        break;
1664800dd8cSBarry Smith      }
1674800dd8cSBarry Smith    }
168614e12f8SBarry Smith    if (i == maxits) *its = i-1; else *its = i + 1;
169fbe28522SBarry Smith    return 0;
1704800dd8cSBarry Smith }
1714800dd8cSBarry Smith /*------------------------------------------------------------*/
172fbe28522SBarry Smith static int SNESSetUp_TR( SNES snes )
1734800dd8cSBarry Smith {
174fbe28522SBarry Smith   int ierr;
17581b6cf68SLois Curfman McInnes   snes->nwork = 4;
17678b31e54SBarry Smith   ierr = VecGetVecs(snes->vec_sol,snes->nwork,&snes->work ); CHKERRQ(ierr);
17781b6cf68SLois Curfman McInnes   snes->vec_sol_update_always = snes->work[3];
178fbe28522SBarry Smith   return 0;
1794800dd8cSBarry Smith }
1804800dd8cSBarry Smith /*------------------------------------------------------------*/
181fbe28522SBarry Smith static int SNESDestroy_TR(PetscObject obj )
1824800dd8cSBarry Smith {
183fbe28522SBarry Smith   SNES snes = (SNES) obj;
184fbe28522SBarry Smith   VecFreeVecs(snes->work, snes->nwork );
18578b31e54SBarry Smith   PETSCFREE(snes->data);
186fbe28522SBarry Smith   return 0;
1874800dd8cSBarry Smith }
1884800dd8cSBarry Smith /*------------------------------------------------------------*/
1894800dd8cSBarry Smith 
190fbe28522SBarry Smith static int SNESSetFromOptions_TR(SNES snes)
1914800dd8cSBarry Smith {
192fbe28522SBarry Smith   SNES_TR *ctx = (SNES_TR *)snes->data;
193fbe28522SBarry Smith   double  tmp;
1944800dd8cSBarry Smith 
195df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-mu",&tmp)) {ctx->mu = tmp;}
196df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-eta",&tmp)) {ctx->eta = tmp;}
197df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-sigma",&tmp)) {ctx->sigma = tmp;}
198df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-delta0",&tmp)) {ctx->delta0 = tmp;}
199df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-delta1",&tmp)) {ctx->delta1 = tmp;}
200df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-delta2",&tmp)) {ctx->delta2 = tmp;}
201df60cc22SBarry Smith   if (OptionsGetDouble(snes->prefix,"-delta3",&tmp)) {ctx->delta3 = tmp;}
202fbe28522SBarry Smith   return 0;
2034800dd8cSBarry Smith }
2044800dd8cSBarry Smith 
205fbe28522SBarry Smith static int SNESPrintHelp_TR(SNES snes)
2064800dd8cSBarry Smith {
207fbe28522SBarry Smith   SNES_TR *ctx = (SNES_TR *)snes->data;
208fbe28522SBarry Smith   char    *prefix = "-";
209fbe28522SBarry Smith   if (snes->prefix) prefix = snes->prefix;
210fbe28522SBarry Smith   fprintf(stderr,"%smu mu (default %g)\n",prefix,ctx->mu);
211fbe28522SBarry Smith   fprintf(stderr,"%seta eta (default %g)\n",prefix,ctx->eta);
212fbe28522SBarry Smith   fprintf(stderr,"%ssigma sigma (default %g)\n",prefix,ctx->sigma);
213fbe28522SBarry Smith   fprintf(stderr,"%sdelta0 delta0 (default %g)\n",prefix,ctx->delta0);
214fbe28522SBarry Smith   fprintf(stderr,"%sdelta1 delta1 (default %g)\n",prefix,ctx->delta1);
215fbe28522SBarry Smith   fprintf(stderr,"%sdelta2 delta2 (default %g)\n",prefix,ctx->delta2);
216fbe28522SBarry Smith   fprintf(stderr,"%sdelta3 delta3 (default %g)\n",prefix,ctx->delta3);
217fbe28522SBarry Smith   return 0;
2184800dd8cSBarry Smith }
2194800dd8cSBarry Smith 
220*a935fc98SLois Curfman McInnes static int SNESView_TR(PetscObject obj,Viewer viewer)
221*a935fc98SLois Curfman McInnes {
222*a935fc98SLois Curfman McInnes   SNES    snes = (SNES)obj;
223*a935fc98SLois Curfman McInnes   SNES_TR *tr = (SNES_TR *)snes->data;
224*a935fc98SLois Curfman McInnes   FILE    *fd = ViewerFileGetPointer_Private(viewer);
225*a935fc98SLois Curfman McInnes 
226*a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,"    mu=%g, eta=%g, sigma=%g\n",
227*a935fc98SLois Curfman McInnes     tr->mu,tr->eta,tr->sigma);
228*a935fc98SLois Curfman McInnes   MPIU_fprintf(snes->comm,fd,
229*a935fc98SLois Curfman McInnes     "    delta0=%g, delta1=%g, delta2=%g, delta3=%g\n",
230*a935fc98SLois Curfman McInnes     tr->delta0,tr->delta1,tr->delta2,tr->delta3);
231*a935fc98SLois Curfman McInnes   return 0;
232*a935fc98SLois Curfman McInnes }
233*a935fc98SLois Curfman McInnes 
234fbe28522SBarry Smith int SNESCreate_TR(SNES snes )
2354800dd8cSBarry Smith {
236fbe28522SBarry Smith   SNES_TR *neP;
2374800dd8cSBarry Smith 
238fbe28522SBarry Smith   snes->type 		= SNES_NTR;
239*a935fc98SLois Curfman McInnes   snes->method_class	= SNES_T;
24006be10caSBarry Smith   snes->setup		= SNESSetUp_TR;
24106be10caSBarry Smith   snes->solve		= SNESSolve_TR;
242fbe28522SBarry Smith   snes->destroy		= SNESDestroy_TR;
2436b5873e3SBarry Smith   snes->Converged	= SNESDefaultConverged;
24406be10caSBarry Smith   snes->printhelp       = SNESPrintHelp_TR;
24506be10caSBarry Smith   snes->setfromoptions  = SNESSetFromOptions_TR;
246*a935fc98SLois Curfman McInnes   snes->view            = SNESView_TR;
247fbe28522SBarry Smith 
24878b31e54SBarry Smith   neP			= PETSCNEW(SNES_TR); CHKPTRQ(neP);
249fbe28522SBarry Smith   snes->data	        = (void *) neP;
250fbe28522SBarry Smith   neP->mu		= 0.25;
251fbe28522SBarry Smith   neP->eta		= 0.75;
252fbe28522SBarry Smith   neP->delta		= 0.0;
253fbe28522SBarry Smith   neP->delta0		= 0.2;
254fbe28522SBarry Smith   neP->delta1		= 0.3;
255fbe28522SBarry Smith   neP->delta2		= 0.75;
256fbe28522SBarry Smith   neP->delta3		= 2.0;
257fbe28522SBarry Smith   neP->sigma		= 0.0001;
258fbe28522SBarry Smith   neP->itflag		= 0;
2596b5873e3SBarry Smith   return 0;
2604800dd8cSBarry Smith }
261