Actual source code: snesut.c

  1: #define PETSCSNES_DLL

 3:  #include include/private/snesimpl.h

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

 11:    Collective on SNES

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

 19:    Level: intermediate

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

 23: .seealso: SNESMonitorSet(), SNESMonitorDefault(), VecView()
 24: @*/
 25: PetscErrorCode  SNESMonitorSolution(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
 26: {
 28:   Vec            x;
 29:   PetscViewer    viewer = (PetscViewer) dummy;

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

 40:   return(0);
 41: }

 45: /*@C
 46:    SNESMonitorResidual - Monitors progress of the SNES solvers by calling 
 47:    VecView() for the residual at each iteration.

 49:    Collective on SNES

 51:    Input Parameters:
 52: +  snes - the SNES context
 53: .  its - iteration number
 54: .  fgnorm - 2-norm of residual
 55: -  dummy - either a viewer or PETSC_NULL

 57:    Level: intermediate

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

 61: .seealso: SNESMonitorSet(), SNESMonitorDefault(), VecView()
 62: @*/
 63: PetscErrorCode  SNESMonitorResidual(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
 64: {
 66:   Vec            x;
 67:   PetscViewer    viewer = (PetscViewer) dummy;

 70:   SNESGetFunction(snes,&x,0,0);
 71:   if (!viewer) {
 72:     MPI_Comm comm;
 73:     PetscObjectGetComm((PetscObject)snes,&comm);
 74:     viewer = PETSC_VIEWER_DRAW_(comm);
 75:   }
 76:   VecView(x,viewer);

 78:   return(0);
 79: }

 83: /*@C
 84:    SNESMonitorSolutionUpdate - Monitors progress of the SNES solvers by calling 
 85:    VecView() for the UPDATE to the solution at each iteration.

 87:    Collective on SNES

 89:    Input Parameters:
 90: +  snes - the SNES context
 91: .  its - iteration number
 92: .  fgnorm - 2-norm of residual
 93: -  dummy - either a viewer or PETSC_NULL

 95:    Level: intermediate

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

 99: .seealso: SNESMonitorSet(), SNESMonitorDefault(), VecView()
100: @*/
101: PetscErrorCode  SNESMonitorSolutionUpdate(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
102: {
104:   Vec            x;
105:   PetscViewer    viewer = (PetscViewer) dummy;

108:   SNESGetSolutionUpdate(snes,&x);
109:   if (!viewer) {
110:     MPI_Comm comm;
111:     PetscObjectGetComm((PetscObject)snes,&comm);
112:     viewer = PETSC_VIEWER_DRAW_(comm);
113:   }
114:   VecView(x,viewer);

116:   return(0);
117: }

121: /*@C
122:    SNESMonitorDefault - Monitors progress of the SNES solvers (default).

124:    Collective on SNES

126:    Input Parameters:
127: +  snes - the SNES context
128: .  its - iteration number
129: .  fgnorm - 2-norm of residual
130: -  dummy - unused context

132:    Notes:
133:    This routine prints the residual norm at each iteration.

135:    Level: intermediate

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

139: .seealso: SNESMonitorSet(), SNESMonitorSolution()
140: @*/
141: PetscErrorCode  SNESMonitorDefault(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
142: {
143:   PetscErrorCode          ierr;
144:   PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor) dummy;

147:   if (!dummy) {
148:     PetscViewerASCIIMonitorCreate(snes->comm,"stdout",0,&viewer);
149:   }
150:   PetscViewerASCIIMonitorPrintf(viewer,"%3D SNES Function norm %14.12e \n",its,fgnorm);
151:   if (!dummy) {
152:     PetscViewerASCIIMonitorDestroy(viewer);
153:   }
154:   return(0);
155: }

157: typedef struct {
158:   PetscViewerASCIIMonitor viewer;
159:   PetscReal               *history;
160: } SNESMonitorRatioContext;

164: /*@C
165:    SNESMonitorRatio - Monitors progress of the SNES solvers by printing the ratio
166:    of residual norm at each iteration to the previous.

168:    Collective on SNES

170:    Input Parameters:
171: +  snes - the SNES context
172: .  its - iteration number
173: .  fgnorm - 2-norm of residual (or gradient)
174: -  dummy -  context of monitor

176:    Level: intermediate

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

180: .seealso: SNESMonitorSet(), SNESMonitorSolution()
181: @*/
182: PetscErrorCode  SNESMonitorRatio(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
183: {
184:   PetscErrorCode          ierr;
185:   PetscInt                len;
186:   PetscReal               *history;
187:   SNESMonitorRatioContext *ctx = (SNESMonitorRatioContext*)dummy;

190:   SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);
191:   if (!its || !history || its > len) {
192:     PetscViewerASCIIMonitorPrintf(ctx->viewer,"%3D SNES Function norm %14.12e \n",its,fgnorm);
193:   } else {
194:     PetscReal ratio = fgnorm/history[its-1];
195:     PetscViewerASCIIMonitorPrintf(ctx->viewer,"%3D SNES Function norm %14.12e %G \n",its,fgnorm,ratio);
196:   }
197:   return(0);
198: }

200: /*
201:    If the we set the history monitor space then we must destroy it
202: */
205: PetscErrorCode SNESMonitorRatioDestroy(void *ct)
206: {
207:   PetscErrorCode          ierr;
208:   SNESMonitorRatioContext *ctx = (SNESMonitorRatioContext*)ct;

211:   PetscFree(ctx->history);
212:   PetscViewerASCIIMonitorDestroy(ctx->viewer);
213:   PetscFree(ctx);
214:   return(0);
215: }

219: /*@C
220:    SNESMonitorSetRatio - Sets SNES to use a monitor that prints the 
221:    ratio of the function norm at each iteration.

223:    Collective on SNES

225:    Input Parameters:
226: +   snes - the SNES context
227: -   viewer - ASCII viewer to print output

229:    Level: intermediate

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

233: .seealso: SNESMonitorSet(), SNESMonitorSolution(), SNESMonitorDefault()
234: @*/
235: PetscErrorCode  SNESMonitorSetRatio(SNES snes,PetscViewerASCIIMonitor viewer)
236: {
237:   PetscErrorCode          ierr;
238:   SNESMonitorRatioContext *ctx;
239:   PetscReal               *history;

242:   if (!viewer) {
243:     PetscViewerASCIIMonitorCreate(snes->comm,"stdout",0,&viewer);
244:     PetscObjectReference((PetscObject)viewer);
245:   }
246:   PetscNew(SNESMonitorRatioContext,&ctx);
247:   SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);
248:   if (!history) {
249:     PetscMalloc(100*sizeof(PetscReal),&ctx->history);
250:     SNESSetConvergenceHistory(snes,ctx->history,0,100,PETSC_TRUE);
251:   }
252:   ctx->viewer = viewer;
253:   SNESMonitorSet(snes,SNESMonitorRatio,ctx,SNESMonitorRatioDestroy);
254:   return(0);
255: }

257: /* ---------------------------------------------------------------- */
260: /*
261:      Default (short) SNES Monitor, same as SNESMonitorDefault() except
262:   it prints fewer digits of the residual as the residual gets smaller.
263:   This is because the later digits are meaningless and are often 
264:   different on different machines; by using this routine different 
265:   machines will usually generate the same output.
266: */
267: PetscErrorCode  SNESMonitorDefaultShort(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
268: {
269:   PetscErrorCode          ierr;
270:   PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor) dummy;

273:   if (!dummy) {
274:     PetscViewerASCIIMonitorCreate(snes->comm,"stdout",0,&viewer);
275:   }
276:   if (fgnorm > 1.e-9) {
277:     PetscViewerASCIIMonitorPrintf(viewer,"%3D SNES Function norm %G \n",its,fgnorm);
278:   } else if (fgnorm > 1.e-11){
279:     PetscViewerASCIIMonitorPrintf(viewer,"%3D SNES Function norm %5.3e \n",its,fgnorm);
280:   } else {
281:     PetscViewerASCIIMonitorPrintf(viewer,"%3D SNES Function norm < 1.e-11\n",its);
282:   }
283:   if (!dummy) {
284:     PetscViewerASCIIMonitorDestroy(viewer);
285:   }
286:   return(0);
287: }
288: /* ---------------------------------------------------------------- */
291: /*@C 
292:    SNESConverged_LS - Monitors the convergence of the solvers for
293:    systems of nonlinear equations (default).

295:    Collective on SNES

297:    Input Parameters:
298: +  snes - the SNES context
299: .  it - the iteration (0 indicates before any Newton steps)
300: .  xnorm - 2-norm of current iterate
301: .  pnorm - 2-norm of current step 
302: .  fnorm - 2-norm of function at current iterate
303: -  dummy - unused context

305:    Output Parameter:
306: .   reason  - one of
307: $  SNES_CONVERGED_FNORM_ABS       - (fnorm < abstol),
308: $  SNES_CONVERGED_PNORM_RELATIVE  - (pnorm < xtol*xnorm),
309: $  SNES_CONVERGED_FNORM_RELATIVE  - (fnorm < rtol*fnorm0),
310: $  SNES_DIVERGED_FUNCTION_COUNT   - (nfct > maxf),
311: $  SNES_DIVERGED_FNORM_NAN        - (fnorm == NaN),
312: $  SNES_CONVERGED_ITERATING       - (otherwise),

314:    where
315: +    maxf - maximum number of function evaluations,
316:             set with SNESSetTolerances()
317: .    nfct - number of function evaluations,
318: .    abstol - absolute function norm tolerance,
319:             set with SNESSetTolerances()
320: -    rtol - relative function norm tolerance, set with SNESSetTolerances()

322:    Level: intermediate

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

326: .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
327: @*/
328: PetscErrorCode  SNESConverged_LS(SNES snes,PetscInt it,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
329: {

333:   *reason = SNES_CONVERGED_ITERATING;

335:   if (!it) {
336:     /* set parameter for default relative tolerance convergence test */
337:     snes->ttol = fnorm*snes->rtol;
338:   }
339:   if (fnorm != fnorm) {
340:     PetscInfo(snes,"Failed to converged, function norm is NaN\n");
341:     *reason = SNES_DIVERGED_FNORM_NAN;
342:   } else if (fnorm < snes->abstol) {
343:     PetscInfo2(snes,"Converged due to function norm %G < %G\n",fnorm,snes->abstol);
344:     *reason = SNES_CONVERGED_FNORM_ABS;
345:   } else if (snes->nfuncs >= snes->max_funcs) {
346:     PetscInfo2(snes,"Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs);
347:     *reason = SNES_DIVERGED_FUNCTION_COUNT;
348:   }

350:   if (it && !*reason) {
351:     if (fnorm <= snes->ttol) {
352:       PetscInfo2(snes,"Converged due to function norm %G < %G (relative tolerance)\n",fnorm,snes->ttol);
353:       *reason = SNES_CONVERGED_FNORM_RELATIVE;
354:     } else if (pnorm < snes->xtol*xnorm) {
355:       PetscInfo3(snes,"Converged due to small update length: %G < %G * %G\n",pnorm,snes->xtol,xnorm);
356:       *reason = SNES_CONVERGED_PNORM_RELATIVE;
357:     }
358:   }
359:   return(0);
360: }
361: /* ------------------------------------------------------------ */
364: /*@
365:    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
366:    for the linear solvers within an inexact Newton method.  

368:    Collective on SNES

370:    Input Parameter:
371: .  snes - SNES context

373:    Notes:
374:    Currently, the default is to use a constant relative tolerance for 
375:    the inner linear solvers.  Alternatively, one can use the 
376:    Eisenstat-Walker method, where the relative convergence tolerance 
377:    is reset at each Newton iteration according progress of the nonlinear 
378:    solver. 

380:    Level: advanced

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

386: .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
387: @*/
388: PetscErrorCode  SNES_KSP_SetConvergenceTestEW(SNES snes)
389: {
391:   snes->ksp_ewconv = PETSC_TRUE;
392:   return(0);
393: }

397: /*@
398:    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
399:    convergence criteria for the linear solvers within an inexact
400:    Newton method.

402:    Collective on SNES
403:  
404:    Input Parameters:
405: +    snes - SNES context
406: .    version - version 1, 2 (default is 2) or 3
407: .    rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
408: .    rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
409: .    alpha - power for version 2 rtol computation (1 < alpha <= 2)
410: .    alpha2 - power for safeguard
411: .    gamma2 - multiplicative factor for version 2 rtol computation
412:               (0 <= gamma2 <= 1)
413: -    threshold - threshold for imposing safeguard (0 < threshold < 1)

415:    Note:
416:    Version 3 was contributed by Luis Chacon, June 2006.

418:    Use PETSC_DEFAULT to retain the default for any of the parameters.

420:    Level: advanced

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

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

429: .seealso: SNES_KSP_SetConvergenceTestEW()
430: @*/
431: PetscErrorCode  SNES_KSP_SetParametersEW(SNES snes,PetscInt version,PetscReal rtol_0,PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
432:                                         PetscReal alpha2,PetscReal threshold)
433: {
434:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;

437:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing");
438:   if (version != PETSC_DEFAULT)   kctx->version   = version;
439:   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0    = rtol_0;
440:   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max  = rtol_max;
441:   if (gamma2 != PETSC_DEFAULT)    kctx->gamma     = gamma2;
442:   if (alpha != PETSC_DEFAULT)     kctx->alpha     = alpha;
443:   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2    = alpha2;
444:   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
445:   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
446:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %G",kctx->rtol_0);
447:   }
448:   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
449:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max (%G) < 1.0\n",kctx->rtol_max);
450:   }
451:   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
452:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold (%G) < 1.0\n",kctx->threshold);
453:   }
454:   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
455:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%G) <= 1.0\n",kctx->gamma);
456:   }
457:   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
458:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%G) <= 2.0\n",kctx->alpha);
459:   }
460:   if (kctx->version < 1 || kctx->version > 3) {
461:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1, 2 and 3 are supported: %D",kctx->version);
462:   }
463:   return(0);
464: }

468: PetscErrorCode SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
469: {
470:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
471:   PetscReal           rtol = 0.0,stol;
472:   PetscErrorCode      ierr;

475:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists");
476:   if (!snes->iter) { /* first time in, so use the original user rtol */
477:     rtol = kctx->rtol_0;
478:   } else {
479:     if (kctx->version == 1) {
480:       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
481:       if (rtol < 0.0) rtol = -rtol;
482:       stol = pow(kctx->rtol_last,kctx->alpha2);
483:       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
484:     } else if (kctx->version == 2) {
485:       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
486:       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
487:       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
488:     } else if (kctx->version == 3) {
489:       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
490:       /* safeguard: avoid sharp decrease of rtol */
491:       rtol = PetscMin(kctx->rtol_0,PetscMax(rtol,kctx->gamma*pow(kctx->rtol_last,kctx->alpha)));
492:       /* safeguard: avoid oversolving */
493:       rtol = PetscMin(kctx->rtol_0,PetscMax(rtol,kctx->gamma*(snes->ttol)/snes->norm));

495:     } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1, 2 or 3 are supported: %D",kctx->version);
496:   }
497:   rtol = PetscMin(rtol,kctx->rtol_max);
498:   kctx->rtol_last = rtol;
499:   PetscInfo3(snes,"iter %D, Eisenstat-Walker (version %D) KSP rtol = %G\n",snes->iter,kctx->version,rtol);
500:   KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
501:   kctx->norm_last = snes->norm;
502:   return(0);
503: }

507: PetscErrorCode SNES_KSP_EW_Converged_Private(KSP ksp,PetscInt n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
508: {
509:   SNES                snes = (SNES)ctx;
510:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
511:   PetscErrorCode      ierr;

514:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
515:   if (!n) {SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);}
516:   KSPDefaultConverged(ksp,n,rnorm,reason,ctx);
517:   kctx->lresid_last = rnorm;
518:   if (*reason) {
519:     PetscInfo2(snes,"KSP iterations=%D, rnorm=%G\n",n,rnorm);
520:   }
521:   return(0);
522: }