Actual source code: tr.c

  1: #define PETSCSNES_DLL
  2: 
 3:  #include ../src/snes/impls/tr/tr.h

  5: typedef struct {
  6:   void *ctx;
  7:   SNES snes;
  8: } SNES_TR_KSPConverged_Ctx;

 10: /*
 11:    This convergence test determines if the two norm of the 
 12:    solution lies outside the trust region, if so it halts.
 13: */
 16: PetscErrorCode SNES_TR_KSPConverged_Private(KSP ksp,PetscInt n,PetscReal rnorm,KSPConvergedReason *reason,void *cctx)
 17: {
 18:   SNES_TR_KSPConverged_Ctx *ctx = (SNES_TR_KSPConverged_Ctx *)cctx;
 19:   SNES                     snes = ctx->snes;
 20:   SNES_TR                  *neP = (SNES_TR*)snes->data;
 21:   Vec                      x;
 22:   PetscReal                nrm;
 23:   PetscErrorCode           ierr;

 26:   KSPDefaultConverged(ksp,n,rnorm,reason,ctx->ctx);
 27:   if (*reason) {
 28:     PetscInfo2(snes,"default convergence test KSP iterations=%D, rnorm=%G\n",n,rnorm);
 29:   }
 30:   /* Determine norm of solution */
 31:   KSPBuildSolution(ksp,0,&x);
 32:   VecNorm(x,NORM_2,&nrm);
 33:   if (nrm >= neP->delta) {
 34:     PetscInfo2(snes,"Ending linear iteration early, delta=%G, length=%G\n",neP->delta,nrm);
 35:     *reason = KSP_CONVERGED_STEP_LENGTH;
 36:   }
 37:   return(0);
 38: }

 42: PetscErrorCode SNES_TR_KSPConverged_Destroy(void *cctx)
 43: {
 44:   SNES_TR_KSPConverged_Ctx *ctx = (SNES_TR_KSPConverged_Ctx *)cctx;
 45:   PetscErrorCode           ierr;

 48:   KSPDefaultConvergedDestroy(ctx->ctx);
 49:   PetscFree(ctx);
 50:   return(0);
 51: }

 53: /* ---------------------------------------------------------------- */
 56: /*
 57:    SNES_TR_Converged_Private -test convergence JUST for 
 58:    the trust region tolerance.

 60: */
 61: static PetscErrorCode SNES_TR_Converged_Private(SNES snes,PetscInt it,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
 62: {
 63:   SNES_TR        *neP = (SNES_TR *)snes->data;

 67:   *reason = SNES_CONVERGED_ITERATING;
 68:   if (neP->delta < xnorm * snes->deltatol) {
 69:     PetscInfo3(snes,"Converged due to trust region param %G<%G*%G\n",neP->delta,xnorm,snes->deltatol);
 70:     *reason = SNES_CONVERGED_TR_DELTA;
 71:   } else if (snes->nfuncs >= snes->max_funcs) {
 72:     PetscInfo1(snes,"Exceeded maximum number of function evaluations: %D\n",snes->max_funcs);
 73:     *reason = SNES_DIVERGED_FUNCTION_COUNT;
 74:   }
 75:   return(0);
 76: }


 79: /*
 80:    SNESSolve_TR - Implements Newton's Method with a very simple trust 
 81:    region approach for solving systems of nonlinear equations. 

 83:  
 84: */
 87: static PetscErrorCode SNESSolve_TR(SNES snes)
 88: {
 89:   SNES_TR             *neP = (SNES_TR*)snes->data;
 90:   Vec                 X,F,Y,G,Ytmp;
 91:   PetscErrorCode      ierr;
 92:   PetscInt            maxits,i,lits;
 93:   MatStructure        flg = DIFFERENT_NONZERO_PATTERN;
 94:   PetscReal           rho,fnorm,gnorm,gpnorm,xnorm=0,delta,nrm,ynorm,norm1;
 95:   PetscScalar         cnorm;
 96:   KSP                 ksp;
 97:   SNESConvergedReason reason = SNES_CONVERGED_ITERATING;
 98:   PetscTruth          conv = PETSC_FALSE,breakout = PETSC_FALSE;

101:   maxits        = snes->max_its;        /* maximum number of iterations */
102:   X                = snes->vec_sol;        /* solution vector */
103:   F                = snes->vec_func;        /* residual vector */
104:   Y                = snes->work[0];        /* work vectors */
105:   G                = snes->work[1];
106:   Ytmp          = snes->work[2];

108:   PetscObjectTakeAccess(snes);
109:   snes->iter = 0;
110:   PetscObjectGrantAccess(snes);

112:   SNESComputeFunction(snes,X,F);          /* F(X) */
113:   VecNorm(F,NORM_2,&fnorm);             /* fnorm <- || F || */
114:   PetscObjectTakeAccess(snes);
115:   snes->norm = fnorm;
116:   PetscObjectGrantAccess(snes);
117:   delta = neP->delta0*fnorm;
118:   neP->delta = delta;
119:   SNESLogConvHistory(snes,fnorm,0);
120:   SNESMonitor(snes,0,fnorm);

122:   /* set parameter for default relative tolerance convergence test */
123:   snes->ttol = fnorm*snes->rtol;
124:   /* test convergence */
125:   (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
126:   if (snes->reason) return(0);

128:   /* Set the stopping criteria to use the More' trick. */
129:   PetscOptionsGetTruth(PETSC_NULL,"-snes_tr_ksp_regular_convergence_test",&conv,PETSC_NULL);
130:   if (!conv) {
131:     SNES_TR_KSPConverged_Ctx *ctx;
132:     SNESGetKSP(snes,&ksp);
133:     PetscNew(SNES_TR_KSPConverged_Ctx,&ctx);
134:     ctx->snes = snes;
135:     KSPDefaultConvergedCreate(&ctx->ctx);
136:     KSPSetConvergenceTest(ksp,SNES_TR_KSPConverged_Private,ctx,SNES_TR_KSPConverged_Destroy);
137:     PetscInfo(snes,"Using Krylov convergence test SNES_TR_KSPConverged_Private\n");
138:   }
139: 
140:   for (i=0; i<maxits; i++) {

142:     /* Call general purpose update function */
143:     if (snes->ops->update) {
144:       (*snes->ops->update)(snes, snes->iter);
145:     }

147:     /* Solve J Y = F, where J is Jacobian matrix */
148:     SNESComputeJacobian(snes,X,&snes->jacobian,&snes->jacobian_pre,&flg);
149:     KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre,flg);
150:     SNES_KSPSolve(snes,snes->ksp,F,Ytmp);
151:     KSPGetIterationNumber(snes->ksp,&lits);
152:     snes->linear_its += lits;
153:     PetscInfo2(snes,"iter=%D, linear solve iterations=%D\n",snes->iter,lits);
154:     VecNorm(Ytmp,NORM_2,&nrm);
155:     norm1 = nrm;
156:     while(1) {
157:       VecCopy(Ytmp,Y);
158:       nrm = norm1;

160:       /* Scale Y if need be and predict new value of F norm */
161:       if (nrm >= delta) {
162:         nrm = delta/nrm;
163:         gpnorm = (1.0 - nrm)*fnorm;
164:         cnorm = nrm;
165:         PetscInfo1(snes,"Scaling direction by %G\n",nrm);
166:         VecScale(Y,cnorm);
167:         nrm = gpnorm;
168:         ynorm = delta;
169:       } else {
170:         gpnorm = 0.0;
171:         PetscInfo(snes,"Direction is in Trust Region\n");
172:         ynorm = nrm;
173:       }
174:       VecAYPX(Y,-1.0,X);            /* Y <- X - Y */
175:       VecCopy(X,snes->vec_sol_update);
176:       SNESComputeFunction(snes,Y,G); /*  F(X) */
177:       VecNorm(G,NORM_2,&gnorm);      /* gnorm <- || g || */
178:       if (fnorm == gpnorm) rho = 0.0;
179:       else rho = (fnorm*fnorm - gnorm*gnorm)/(fnorm*fnorm - gpnorm*gpnorm);

181:       /* Update size of trust region */
182:       if      (rho < neP->mu)  delta *= neP->delta1;
183:       else if (rho < neP->eta) delta *= neP->delta2;
184:       else                     delta *= neP->delta3;
185:       PetscInfo3(snes,"fnorm=%G, gnorm=%G, ynorm=%G\n",fnorm,gnorm,ynorm);
186:       PetscInfo3(snes,"gpred=%G, rho=%G, delta=%G\n",gpnorm,rho,delta);
187:       neP->delta = delta;
188:       if (rho > neP->sigma) break;
189:       PetscInfo(snes,"Trying again in smaller region\n");
190:       /* check to see if progress is hopeless */
191:       neP->itflag = PETSC_FALSE;
192:       SNES_TR_Converged_Private(snes,snes->iter,xnorm,ynorm,fnorm,&reason,snes->cnvP);
193:       if (!reason) { (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&reason,snes->cnvP); }
194:       if (reason) {
195:         /* We're not progressing, so return with the current iterate */
196:         SNESMonitor(snes,i+1,fnorm);
197:         breakout = PETSC_TRUE;
198:         break;
199:       }
200:       snes->numFailures++;
201:     }
202:     if (!breakout) {
203:       /* Update function and solution vectors */
204:       fnorm = gnorm;
205:       VecCopy(G,F);
206:       VecCopy(Y,X);
207:       /* Monitor convergence */
208:       PetscObjectTakeAccess(snes);
209:       snes->iter = i+1;
210:       snes->norm = fnorm;
211:       PetscObjectGrantAccess(snes);
212:       SNESLogConvHistory(snes,snes->norm,lits);
213:       SNESMonitor(snes,snes->iter,snes->norm);
214:       /* Test for convergence, xnorm = || X || */
215:       neP->itflag = PETSC_TRUE;
216:       if (snes->ops->converged != SNESSkipConverged) { VecNorm(X,NORM_2,&xnorm); }
217:       (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&reason,snes->cnvP);
218:       if (reason) break;
219:     } else {
220:       break;
221:     }
222:   }
223:   if (i == maxits) {
224:     PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",maxits);
225:     if (!reason) reason = SNES_DIVERGED_MAX_IT;
226:   }
227:   PetscObjectTakeAccess(snes);
228:   snes->reason = reason;
229:   PetscObjectGrantAccess(snes);
230:   return(0);
231: }
232: /*------------------------------------------------------------*/
235: static PetscErrorCode SNESSetUp_TR(SNES snes)
236: {

240:   if (!snes->vec_sol_update) {
241:     VecDuplicate(snes->vec_sol,&snes->vec_sol_update);
242:     PetscLogObjectParent(snes,snes->vec_sol_update);
243:   }
244:   if (!snes->work) {
245:     snes->nwork = 3;
246:     VecDuplicateVecs(snes->vec_sol,snes->nwork,&snes->work);
247:     PetscLogObjectParents(snes,snes->nwork,snes->work);
248:   }
249:   return(0);
250: }
251: /*------------------------------------------------------------*/
254: static PetscErrorCode SNESDestroy_TR(SNES snes)
255: {

259:   if (snes->vec_sol_update) {
260:     VecDestroy(snes->vec_sol_update);
261:     snes->vec_sol_update = PETSC_NULL;
262:   }
263:   if (snes->nwork) {
264:     VecDestroyVecs(snes->work,snes->nwork);
265:     snes->nwork = 0;
266:     snes->work  = PETSC_NULL;
267:   }
268:   PetscFree(snes->data);
269:   return(0);
270: }
271: /*------------------------------------------------------------*/

275: static PetscErrorCode SNESSetFromOptions_TR(SNES snes)
276: {
277:   SNES_TR *ctx = (SNES_TR *)snes->data;

281:   PetscOptionsHead("SNES trust region options for nonlinear equations");
282:     PetscOptionsReal("-snes_trtol","Trust region tolerance","SNESSetTrustRegionTolerance",snes->deltatol,&snes->deltatol,0);
283:     PetscOptionsReal("-snes_tr_mu","mu","None",ctx->mu,&ctx->mu,0);
284:     PetscOptionsReal("-snes_tr_eta","eta","None",ctx->eta,&ctx->eta,0);
285:     PetscOptionsReal("-snes_tr_sigma","sigma","None",ctx->sigma,&ctx->sigma,0);
286:     PetscOptionsReal("-snes_tr_delta0","delta0","None",ctx->delta0,&ctx->delta0,0);
287:     PetscOptionsReal("-snes_tr_delta1","delta1","None",ctx->delta1,&ctx->delta1,0);
288:     PetscOptionsReal("-snes_tr_delta2","delta2","None",ctx->delta2,&ctx->delta2,0);
289:     PetscOptionsReal("-snes_tr_delta3","delta3","None",ctx->delta3,&ctx->delta3,0);
290:   PetscOptionsTail();
291:   return(0);
292: }

296: static PetscErrorCode SNESView_TR(SNES snes,PetscViewer viewer)
297: {
298:   SNES_TR *tr = (SNES_TR *)snes->data;
300:   PetscTruth iascii;

303:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
304:   if (iascii) {
305:     PetscViewerASCIIPrintf(viewer,"  mu=%G, eta=%G, sigma=%G\n",tr->mu,tr->eta,tr->sigma);
306:     PetscViewerASCIIPrintf(viewer,"  delta0=%G, delta1=%G, delta2=%G, delta3=%G\n",tr->delta0,tr->delta1,tr->delta2,tr->delta3);
307:   } else {
308:     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for SNES EQ TR",((PetscObject)viewer)->type_name);
309:   }
310:   return(0);
311: }
312: /* ------------------------------------------------------------ */
313: /*MC
314:       SNESTR - Newton based nonlinear solver that uses a trust region

316:    Options Database:
317: +    -snes_trtol <tol> Trust region tolerance
318: .    -snes_tr_mu <mu>
319: .    -snes_tr_eta <eta>
320: .    -snes_tr_sigma <sigma>
321: .    -snes_tr_delta0 <delta0>
322: .    -snes_tr_delta1 <delta1>
323: .    -snes_tr_delta2 <delta2>
324: -    -snes_tr_delta3 <delta3>

326:    The basic algorithm is taken from "The Minpack Project", by More', 
327:    Sorensen, Garbow, Hillstrom, pages 88-111 of "Sources and Development 
328:    of Mathematical Software", Wayne Cowell, editor.

330:    This is intended as a model implementation, since it does not 
331:    necessarily have many of the bells and whistles of other 
332:    implementations.  

334:    Level: intermediate

336: .seealso:  SNESCreate(), SNES, SNESSetType(), SNESLS, SNESSetTrustRegionTolerance()

338: M*/
342: PetscErrorCode  SNESCreate_TR(SNES snes)
343: {
344:   SNES_TR        *neP;

348:   snes->ops->setup             = SNESSetUp_TR;
349:   snes->ops->solve             = SNESSolve_TR;
350:   snes->ops->destroy             = SNESDestroy_TR;
351:   snes->ops->setfromoptions  = SNESSetFromOptions_TR;
352:   snes->ops->view            = SNESView_TR;
353: 
354:   ierr                        = PetscNewLog(snes,SNES_TR,&neP);
355:   snes->data                = (void*)neP;
356:   neP->mu                = 0.25;
357:   neP->eta                = 0.75;
358:   neP->delta                = 0.0;
359:   neP->delta0                = 0.2;
360:   neP->delta1                = 0.3;
361:   neP->delta2                = 0.75;
362:   neP->delta3                = 2.0;
363:   neP->sigma                = 0.0001;
364:   neP->itflag                = PETSC_FALSE;
365:   neP->rnorm0                = 0.0;
366:   neP->ttol                = 0.0;
367:   return(0);
368: }