Actual source code: snesut.c

  1: /*$Id: snesut.c,v 1.66 2001/08/06 21:17:07 bsmith Exp $*/

 3:  #include src/snes/snesimpl.h

  5: /*@C
  6:    SNESVecViewMonitor - Monitors progress of the SNES solvers by calling 
  7:    VecView() for the approximate solution at each iteration.

  9:    Collective on SNES

 11:    Input Parameters:
 12: +  snes - the SNES context
 13: .  its - iteration number
 14: .  fgnorm - 2-norm of residual
 15: -  dummy - either a viewer or PETSC_NULL

 17:    Level: intermediate

 19: .keywords: SNES, nonlinear, vector, monitor, view

 21: .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
 22: @*/
 23: int SNESVecViewMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
 24: {
 25:   int         ierr;
 26:   Vec         x;
 27:   PetscViewer viewer = (PetscViewer) dummy;

 30:   SNESGetSolution(snes,&x);
 31:   if (!viewer) {
 32:     MPI_Comm comm;
 33:     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);
 34:     viewer = PETSC_VIEWER_DRAW_(comm);
 35:   }
 36:   VecView(x,viewer);

 38:   return(0);
 39: }

 41: /*@C
 42:    SNESVecViewResidualMonitor - Monitors progress of the SNES solvers by calling 
 43:    VecView() for the residual at each iteration.

 45:    Collective on SNES

 47:    Input Parameters:
 48: +  snes - the SNES context
 49: .  its - iteration number
 50: .  fgnorm - 2-norm of residual
 51: -  dummy - either a viewer or PETSC_NULL

 53:    Level: intermediate

 55: .keywords: SNES, nonlinear, vector, monitor, view

 57: .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
 58: @*/
 59: int SNESVecViewResidualMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
 60: {
 61:   int         ierr;
 62:   Vec         x;
 63:   PetscViewer viewer = (PetscViewer) dummy;

 66:   SNESGetFunction(snes,&x,0,0);
 67:   if (!viewer) {
 68:     MPI_Comm comm;
 69:     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);
 70:     viewer = PETSC_VIEWER_DRAW_(comm);
 71:   }
 72:   VecView(x,viewer);

 74:   return(0);
 75: }

 77: /*@C
 78:    SNESVecViewUpdateMonitor - Monitors progress of the SNES solvers by calling 
 79:    VecView() for the UPDATE to the solution at each iteration.

 81:    Collective on SNES

 83:    Input Parameters:
 84: +  snes - the SNES context
 85: .  its - iteration number
 86: .  fgnorm - 2-norm of residual
 87: -  dummy - either a viewer or PETSC_NULL

 89:    Level: intermediate

 91: .keywords: SNES, nonlinear, vector, monitor, view

 93: .seealso: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
 94: @*/
 95: int SNESVecViewUpdateMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
 96: {
 97:   int         ierr;
 98:   Vec         x;
 99:   PetscViewer viewer = (PetscViewer) dummy;

102:   SNESGetSolutionUpdate(snes,&x);
103:   if (!viewer) {
104:     MPI_Comm comm;
105:     ierr   = PetscObjectGetComm((PetscObject)snes,&comm);
106:     viewer = PETSC_VIEWER_DRAW_(comm);
107:   }
108:   VecView(x,viewer);

110:   return(0);
111: }

113: /*@C
114:    SNESDefaultMonitor - Monitors progress of the SNES solvers (default).

116:    Collective on SNES

118:    Input Parameters:
119: +  snes - the SNES context
120: .  its - iteration number
121: .  fgnorm - 2-norm of residual
122: -  dummy - unused context

124:    Notes:
125:    This routine prints the residual norm at each iteration.

127:    Level: intermediate

129: .keywords: SNES, nonlinear, default, monitor, norm

131: .seealso: SNESSetMonitor(), SNESVecViewMonitor()
132: @*/
133: int SNESDefaultMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
134: {
135:   int         ierr;
136:   PetscViewer viewer = (PetscViewer) dummy;

139:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm);
140:   PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e n",its,fgnorm);
141:   return(0);
142: }

144: /*@C
145:    SNESRatioMonitor - Monitors progress of the SNES solvers by printing the ratio
146:    of residual norm at each iteration to the previous.

148:    Collective on SNES

150:    Input Parameters:
151: +  snes - the SNES context
152: .  its - iteration number
153: .  fgnorm - 2-norm of residual (or gradient)
154: -  dummy - unused context

156:    Level: intermediate

158: .keywords: SNES, nonlinear, monitor, norm

160: .seealso: SNESSetMonitor(), SNESVecViewMonitor()
161: @*/
162: int SNESRatioMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
163: {
164:   int         ierr,len;
165:   PetscReal   *history;
166:   PetscViewer viewer;

169:   viewer = PETSC_VIEWER_STDOUT_(snes->comm);

171:   SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);
172:   if (its == 0 || !history || its > len) {
173:     PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e n",its,fgnorm);
174:   } else {
175:     PetscReal ratio = fgnorm/history[its-1];
176:     PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e %g n",its,fgnorm,ratio);
177:   }
178:   return(0);
179: }

181: /*
182:    If the we set the history monitor space then we must destroy it
183: */
184: int SNESRatioMonitorDestroy(void *history)
185: {
186:   int         ierr;

189:   PetscFree(history);
190:   return(0);
191: }

193: /*@C
194:    SNESSetRatioMonitor - Sets SNES to use a monitor that prints the 
195:    ratio of the function norm at each iteration.

197:    Collective on SNES

199:    Input Parameters:
200: .   snes - the SNES context

202:    Level: intermediate

204: .keywords: SNES, nonlinear, monitor, norm

206: .seealso: SNESSetMonitor(), SNESVecViewMonitor(), SNESDefaultMonitor()
207: @*/
208: int SNESSetRatioMonitor(SNES snes)
209: {
210:   int       ierr;
211:   PetscReal *history;


215:   SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);
216:   if (!history) {
217:     PetscMalloc(100*sizeof(double),&history);
218:     SNESSetConvergenceHistory(snes,history,0,100,PETSC_TRUE);
219:     SNESSetMonitor(snes,SNESRatioMonitor,history,SNESRatioMonitorDestroy);
220:   } else {
221:     SNESSetMonitor(snes,SNESRatioMonitor,0,0);
222:   }
223:   return(0);
224: }

226: /* ---------------------------------------------------------------- */
227: /*
228:      Default (short) SNES Monitor, same as SNESDefaultMonitor() except
229:   it prints fewer digits of the residual as the residual gets smaller.
230:   This is because the later digits are meaningless and are often 
231:   different on different machines; by using this routine different 
232:   machines will usually generate the same output.
233: */
234: int SNESDefaultSMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
235: {

239:   if (fgnorm > 1.e-9) {
240:     PetscPrintf(snes->comm,"%3d SNES Function norm %g n",its,fgnorm);
241:   } else if (fgnorm > 1.e-11){
242:     PetscPrintf(snes->comm,"%3d SNES Function norm %5.3e n",its,fgnorm);
243:   } else {
244:     PetscPrintf(snes->comm,"%3d SNES Function norm < 1.e-11n",its);
245:   }
246:   return(0);
247: }
248: /* ---------------------------------------------------------------- */
249: /*@C 
250:    SNESConverged_LS - Monitors the convergence of the solvers for
251:    systems of nonlinear equations (default).

253:    Collective on SNES

255:    Input Parameters:
256: +  snes - the SNES context
257: .  xnorm - 2-norm of current iterate
258: .  pnorm - 2-norm of current step 
259: .  fnorm - 2-norm of function
260: -  dummy - unused context

262:    Output Parameter:
263: .   reason  - one of
264: $  SNES_CONVERGED_FNORM_ABS       - (fnorm < atol),
265: $  SNES_CONVERGED_PNORM_RELATIVE  - (pnorm < xtol*xnorm),
266: $  SNES_CONVERGED_FNORM_RELATIVE  - (fnorm < rtol*fnorm0),
267: $  SNES_DIVERGED_FUNCTION_COUNT   - (nfct > maxf),
268: $  SNES_DIVERGED_FNORM_NAN        - (fnorm == NaN),
269: $  SNES_CONVERGED_ITERATING       - (otherwise),

271:    where
272: +    maxf - maximum number of function evaluations,
273:             set with SNESSetTolerances()
274: .    nfct - number of function evaluations,
275: .    atol - absolute function norm tolerance,
276:             set with SNESSetTolerances()
277: -    rtol - relative function norm tolerance, set with SNESSetTolerances()

279:    Level: intermediate

281: .keywords: SNES, nonlinear, default, converged, convergence

283: .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
284: @*/
285: int SNESConverged_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
286: {
288:   if (fnorm != fnorm) {
289:     PetscLogInfo(snes,"SNESConverged_LS:Failed to converged, function norm is NaNn");
290:     *reason = SNES_DIVERGED_FNORM_NAN;
291:   } else if (fnorm <= snes->ttol) {
292:     PetscLogInfo(snes,"SNESConverged_LS:Converged due to function norm %g < %g (relative tolerance)n",fnorm,snes->ttol);
293:     *reason = SNES_CONVERGED_FNORM_RELATIVE;
294:   } else if (fnorm < snes->atol) {
295:     PetscLogInfo(snes,"SNESConverged_LS:Converged due to function norm %g < %gn",fnorm,snes->atol);
296:     *reason = SNES_CONVERGED_FNORM_ABS;
297:   } else if (pnorm < snes->xtol*xnorm) {
298:     PetscLogInfo(snes,"SNESConverged_LS:Converged due to small update length: %g < %g * %gn",pnorm,snes->xtol,xnorm);
299:     *reason = SNES_CONVERGED_PNORM_RELATIVE;
300:   } else if (snes->nfuncs > snes->max_funcs) {
301:     PetscLogInfo(snes,"SNESConverged_LS:Exceeded maximum number of function evaluations: %d > %dn",snes->nfuncs,snes->max_funcs);
302:     *reason = SNES_DIVERGED_FUNCTION_COUNT ;
303:   } else {
304:     *reason = SNES_CONVERGED_ITERATING;
305:   }
306:   return(0);
307: }
308: /* ------------------------------------------------------------ */
309: /*@
310:    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
311:    for the linear solvers within an inexact Newton method.  

313:    Collective on SNES

315:    Input Parameter:
316: .  snes - SNES context

318:    Notes:
319:    Currently, the default is to use a constant relative tolerance for 
320:    the inner linear solvers.  Alternatively, one can use the 
321:    Eisenstat-Walker method, where the relative convergence tolerance 
322:    is reset at each Newton iteration according progress of the nonlinear 
323:    solver. 

325:    Level: advanced

327:    Reference:
328:    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 
329:    inexact Newton method", SISC 17 (1), pp.16-32, 1996.

331: .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
332: @*/
333: int SNES_KSP_SetConvergenceTestEW(SNES snes)
334: {
336:   snes->ksp_ewconv = PETSC_TRUE;
337:   return(0);
338: }

340: /*@
341:    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
342:    convergence criteria for the linear solvers within an inexact
343:    Newton method.

345:    Collective on SNES
346:  
347:    Input Parameters:
348: +    snes - SNES context
349: .    version - version 1 or 2 (default is 2)
350: .    rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
351: .    rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
352: .    alpha - power for version 2 rtol computation (1 < alpha <= 2)
353: .    alpha2 - power for safeguard
354: .    gamma2 - multiplicative factor for version 2 rtol computation
355:               (0 <= gamma2 <= 1)
356: -    threshold - threshold for imposing safeguard (0 < threshold < 1)

358:    Note:
359:    Use PETSC_DEFAULT to retain the default for any of the parameters.

361:    Level: advanced

363:    Reference:
364:    S. C. Eisenstat and H. F. Walker, "Choosing the forcing terms in an 
365:    inexact Newton method", Utah State University Math. Stat. Dept. Res. 
366:    Report 6/94/75, June, 1994, to appear in SIAM J. Sci. Comput. 

368: .keywords: SNES, KSP, Eisenstat, Walker, set, parameters

370: .seealso: SNES_KSP_SetConvergenceTestEW()
371: @*/
372: int SNES_KSP_SetParametersEW(SNES snes,int version,PetscReal rtol_0,
373:                              PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
374:                              PetscReal alpha2,PetscReal threshold)
375: {
376:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;

379:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing");
380:   if (version != PETSC_DEFAULT)   kctx->version   = version;
381:   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0    = rtol_0;
382:   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max  = rtol_max;
383:   if (gamma2 != PETSC_DEFAULT)    kctx->gamma     = gamma2;
384:   if (alpha != PETSC_DEFAULT)     kctx->alpha     = alpha;
385:   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2    = alpha2;
386:   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
387:   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
388:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0);
389:   }
390:   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
391:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max (%g) < 1.0n",kctx->rtol_max);
392:   }
393:   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
394:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold (%g) < 1.0n",kctx->threshold);
395:   }
396:   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
397:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%g) <= 1.0n",kctx->gamma);
398:   }
399:   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
400:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%g) <= 2.0n",kctx->alpha);
401:   }
402:   if (kctx->version != 1 && kctx->version !=2) {
403:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 and 2 are supported: %d",kctx->version);
404:   }
405:   return(0);
406: }

408: int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
409: {
410:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
411:   PetscReal           rtol = 0.0,stol;
412:   int                 ierr;

415:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists");
416:   if (!snes->iter) { /* first time in, so use the original user rtol */
417:     rtol = kctx->rtol_0;
418:   } else {
419:     if (kctx->version == 1) {
420:       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
421:       if (rtol < 0.0) rtol = -rtol;
422:       stol = pow(kctx->rtol_last,kctx->alpha2);
423:       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
424:     } else if (kctx->version == 2) {
425:       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
426:       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
427:       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
428:     } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 or 2 are supported: %d",kctx->version);
429:   }
430:   rtol = PetscMin(rtol,kctx->rtol_max);
431:   kctx->rtol_last = rtol;
432:   PetscLogInfo(snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %d, Eisenstat-Walker (version %d) KSP rtol = %gn",snes->iter,kctx->version,rtol);
433:   KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
434:   kctx->norm_last = snes->norm;
435:   return(0);
436: }

438: int SNES_KSP_EW_Converged_Private(KSP ksp,int n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
439: {
440:   SNES                snes = (SNES)ctx;
441:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
442:   int                 ierr;

445:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
446:   if (n == 0) {SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);}
447:   KSPDefaultConverged(ksp,n,rnorm,reason,ctx);
448:   kctx->lresid_last = rnorm;
449:   if (*reason) {
450:     PetscLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%gn",n,rnorm);
451:   }
452:   return(0);
453: }