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 (or gradient)
 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:    SNESVecViewUpdateMonitor - Monitors progress of the SNES solvers by calling 
 43:    VecView() for the UPDATE to the solution 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 (or gradient)
 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 SNESVecViewUpdateMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
 60: {
 61:   int         ierr;
 62:   Vec         x;
 63:   PetscViewer viewer = (PetscViewer) dummy;

 66:   SNESGetSolutionUpdate(snes,&x);
 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:    SNESDefaultMonitor - Monitoring progress of the SNES solvers (default).

 80:    Collective on SNES

 82:    Input Parameters:
 83: +  snes - the SNES context
 84: .  its - iteration number
 85: .  fgnorm - 2-norm of residual (or gradient)
 86: -  dummy - unused context

 88:    Notes:
 89:    For SNES_NONLINEAR_EQUATIONS methods the routine prints the 
 90:    residual norm at each iteration.

 92:    For SNES_UNCONSTRAINED_MINIMIZATION methods the routine prints the
 93:    function value and gradient norm at each iteration.

 95:    Level: intermediate

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

 99: .seealso: SNESSetMonitor(), SNESVecViewMonitor()
100: @*/
101: int SNESDefaultMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
102: {
103:   int         ierr;
104:   PetscViewer viewer = (PetscViewer) dummy;

107:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm);

109:   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
110:     PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e n",its,fgnorm);
111:   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
112:     PetscViewerASCIIPrintf(viewer,"%3d SNES Function value %14.12e, Gradient norm %14.12e n",its,snes->fc,fgnorm);
113:   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown method class");
114:   return(0);
115: }

117: /*@C
118:    SNESRatioMonitor - Monitoring progress of the SNES solvers, prints ratio
119:       of residual norm at each iteration to previous

121:    Collective on SNES

123:    Input Parameters:
124: +  snes - the SNES context
125: .  its - iteration number
126: .  fgnorm - 2-norm of residual (or gradient)
127: -  dummy - unused context

129:    Level: intermediate

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

133: .seealso: SNESSetMonitor(), SNESVecViewMonitor()
134: @*/
135: int SNESRatioMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
136: {
137:   int         ierr,len;
138:   PetscReal   *history;
139:   PetscViewer viewer;

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

144:   SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);
145:   if (its == 0 || !history || its > len) {
146:     PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e n",its,fgnorm);
147:   } else {
148:     PetscReal ratio = fgnorm/history[its-1];
149:     PetscViewerASCIIPrintf(viewer,"%3d SNES Function norm %14.12e %g n",its,fgnorm,ratio);
150:   }
151:   return(0);
152: }

154: /*
155:    If the we set the history monitor space then we must destroy it
156: */
157: int SNESRatioMonitorDestroy(void *history)
158: {
159:   int         ierr;

162:   PetscFree(history);
163:   return(0);
164: }

166: /*@C
167:    SNESSetRatioMonitor - Sets SNES to use a monitor that prints the 
168:      ratio of the function norm at each iteration

170:    Collective on SNES

172:    Input Parameters:
173: .   snes - the SNES context

175:    Level: intermediate

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

179: .seealso: SNESSetMonitor(), SNESVecViewMonitor(), SNESDefaultMonitor()
180: @*/
181: int SNESSetRatioMonitor(SNES snes)
182: {
183:   int       ierr;
184:   PetscReal *history;


188:   SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);
189:   if (!history) {
190:     PetscMalloc(100*sizeof(double),&history);
191:     SNESSetConvergenceHistory(snes,history,0,100,PETSC_TRUE);
192:     SNESSetMonitor(snes,SNESRatioMonitor,history,SNESRatioMonitorDestroy);
193:   } else {
194:     SNESSetMonitor(snes,SNESRatioMonitor,0,0);
195:   }
196:   return(0);
197: }

199: /* ---------------------------------------------------------------- */
200: /*
201:      Default (short) SNES Monitor, same as SNESDefaultMonitor() except
202:   it prints fewer digits of the residual as the residual gets smaller.
203:   This is because the later digits are meaningless and are often 
204:   different on different machines; by using this routine different 
205:   machines will usually generate the same output.
206: */
207: int SNESDefaultSMonitor(SNES snes,int its,PetscReal fgnorm,void *dummy)
208: {

212:   if (snes->method_class == SNES_NONLINEAR_EQUATIONS) {
213:     if (fgnorm > 1.e-9) {
214:       PetscPrintf(snes->comm,"%3d SNES Function norm %g n",its,fgnorm);
215:     } else if (fgnorm > 1.e-11){
216:       PetscPrintf(snes->comm,"%3d SNES Function norm %5.3e n",its,fgnorm);
217:     } else {
218:       PetscPrintf(snes->comm,"%3d SNES Function norm < 1.e-11n",its);
219:     }
220:   } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) {
221:     if (fgnorm > 1.e-9) {
222:       PetscPrintf(snes->comm,"%3d SNES Function value %g, Gradient norm %g n",its,snes->fc,fgnorm);
223:     } else if (fgnorm > 1.e-11) {
224:       PetscPrintf(snes->comm,"%3d SNES Function value %g, Gradient norm %5.3e n",its,snes->fc,fgnorm);
225:     } else {
226:       PetscPrintf(snes->comm,"%3d SNES Function value %g, Gradient norm < 1.e-11n",its,snes->fc);
227:     }
228:   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown method class");
229:   return(0);
230: }
231: /* ---------------------------------------------------------------- */
232: /*@C 
233:    SNESConverged_EQ_LS - Monitors the convergence of the solvers for
234:    systems of nonlinear equations (default).

236:    Collective on SNES

238:    Input Parameters:
239: +  snes - the SNES context
240: .  xnorm - 2-norm of current iterate
241: .  pnorm - 2-norm of current step 
242: .  fnorm - 2-norm of function
243: -  dummy - unused context

245:    Output Parameter:
246: .   reason  - one of
247: $  SNES_CONVERGED_FNORM_ABS       - (fnorm < atol),
248: $  SNES_CONVERGED_PNORM_RELATIVE  - (pnorm < xtol*xnorm),
249: $  SNES_CONVERGED_FNORM_RELATIVE  - (fnorm < rtol*fnorm0),
250: $  SNES_DIVERGED_FUNCTION_COUNT   - (nfct > maxf),
251: $  SNES_DIVERGED_FNORM_NAN        - (fnorm == NaN),
252: $  SNES_CONVERGED_ITERATING       - (otherwise),

254:    where
255: +    maxf - maximum number of function evaluations,
256:             set with SNESSetTolerances()
257: .    nfct - number of function evaluations,
258: .    atol - absolute function norm tolerance,
259:             set with SNESSetTolerances()
260: -    rtol - relative function norm tolerance, set with SNESSetTolerances()

262:    Level: intermediate

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

266: .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
267: @*/
268: int SNESConverged_EQ_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
269: {
271:   if (snes->method_class != SNES_NONLINEAR_EQUATIONS) {
272:      SETERRQ(PETSC_ERR_ARG_WRONG,"For SNES_NONLINEAR_EQUATIONS only");
273:   }

275:   if (fnorm != fnorm) {
276:     PetscLogInfo(snes,"SNESConverged_EQ_LS:Failed to converged, function norm is NaNn");
277:     *reason = SNES_DIVERGED_FNORM_NAN;
278:   } else if (fnorm <= snes->ttol) {
279:     PetscLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %g (relative tolerance)n",fnorm,snes->ttol);
280:     *reason = SNES_CONVERGED_FNORM_RELATIVE;
281:   } else if (fnorm < snes->atol) {
282:     PetscLogInfo(snes,"SNESConverged_EQ_LS:Converged due to function norm %g < %gn",fnorm,snes->atol);
283:     *reason = SNES_CONVERGED_FNORM_ABS;
284:   } else if (pnorm < snes->xtol*(xnorm)) {
285:     PetscLogInfo(snes,"SNESConverged_EQ_LS:Converged due to small update length: %g < %g * %gn",pnorm,snes->xtol,xnorm);
286:     *reason = SNES_CONVERGED_PNORM_RELATIVE;
287:   } else if (snes->nfuncs > snes->max_funcs) {
288:     PetscLogInfo(snes,"SNESConverged_EQ_LS:Exceeded maximum number of function evaluations: %d > %dn",snes->nfuncs,snes->max_funcs);
289:     *reason = SNES_DIVERGED_FUNCTION_COUNT ;
290:   } else {
291:     *reason = SNES_CONVERGED_ITERATING;
292:   }
293:   return(0);
294: }
295: /* ------------------------------------------------------------ */
296: /*@
297:    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
298:    for the linear solvers within an inexact Newton method.  

300:    Collective on SNES

302:    Input Parameter:
303: .  snes - SNES context

305:    Notes:
306:    Currently, the default is to use a constant relative tolerance for 
307:    the inner linear solvers.  Alternatively, one can use the 
308:    Eisenstat-Walker method, where the relative convergence tolerance 
309:    is reset at each Newton iteration according progress of the nonlinear 
310:    solver. 

312:    Level: advanced

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

318: .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
319: @*/
320: int SNES_KSP_SetConvergenceTestEW(SNES snes)
321: {
323:   snes->ksp_ewconv = PETSC_TRUE;
324:   return(0);
325: }

327: /*@
328:    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
329:    convergence criteria for the linear solvers within an inexact
330:    Newton method.

332:    Collective on SNES
333:  
334:    Input Parameters:
335: +    snes - SNES context
336: .    version - version 1 or 2 (default is 2)
337: .    rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
338: .    rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
339: .    alpha - power for version 2 rtol computation (1 < alpha <= 2)
340: .    alpha2 - power for safeguard
341: .    gamma2 - multiplicative factor for version 2 rtol computation
342:               (0 <= gamma2 <= 1)
343: -    threshold - threshold for imposing safeguard (0 < threshold < 1)

345:    Note:
346:    Use PETSC_DEFAULT to retain the default for any of the parameters.

348:    Level: advanced

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

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

357: .seealso: SNES_KSP_SetConvergenceTestEW()
358: @*/
359: int SNES_KSP_SetParametersEW(SNES snes,int version,PetscReal rtol_0,
360:                              PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
361:                              PetscReal alpha2,PetscReal threshold)
362: {
363:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;

366:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing");
367:   if (version != PETSC_DEFAULT)   kctx->version   = version;
368:   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0    = rtol_0;
369:   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max  = rtol_max;
370:   if (gamma2 != PETSC_DEFAULT)    kctx->gamma     = gamma2;
371:   if (alpha != PETSC_DEFAULT)     kctx->alpha     = alpha;
372:   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2    = alpha2;
373:   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
374:   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
375:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0);
376:   }
377:   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
378:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max (%g) < 1.0n",kctx->rtol_max);
379:   }
380:   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
381:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold (%g) < 1.0n",kctx->threshold);
382:   }
383:   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
384:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%g) <= 1.0n",kctx->gamma);
385:   }
386:   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
387:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%g) <= 2.0n",kctx->alpha);
388:   }
389:   if (kctx->version != 1 && kctx->version !=2) {
390:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 and 2 are supported: %d",kctx->version);
391:   }
392:   return(0);
393: }

395: int SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
396: {
397:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
398:   PetscReal           rtol = 0.0,stol;
399:   int                 ierr;

402:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists");
403:   if (!snes->iter) { /* first time in, so use the original user rtol */
404:     rtol = kctx->rtol_0;
405:   } else {
406:     if (kctx->version == 1) {
407:       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
408:       if (rtol < 0.0) rtol = -rtol;
409:       stol = pow(kctx->rtol_last,kctx->alpha2);
410:       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
411:     } else if (kctx->version == 2) {
412:       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
413:       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
414:       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
415:     } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 or 2 are supported: %d",kctx->version);
416:   }
417:   rtol = PetscMin(rtol,kctx->rtol_max);
418:   kctx->rtol_last = rtol;
419:   PetscLogInfo(snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %d, Eisenstat-Walker (version %d) KSP rtol = %gn",snes->iter,kctx->version,rtol);
420:   KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
421:   kctx->norm_last = snes->norm;
422:   return(0);
423: }

425: int SNES_KSP_EW_Converged_Private(KSP ksp,int n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
426: {
427:   SNES                snes = (SNES)ctx;
428:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
429:   int                 ierr;

432:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
433:   if (n == 0) {SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);}
434:   KSPDefaultConverged(ksp,n,rnorm,reason,ctx);
435:   kctx->lresid_last = rnorm;
436:   if (*reason) {
437:     PetscLogInfo(snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%d, rnorm=%gn",n,rnorm);
438:   }
439:   return(0);
440: }