Actual source code: snesut.c

      1: #define PETSCSNES_DLL

     3:  #include src/snes/snesimpl.h

      7: /*@C
      8:    SNESVecViewMonitor - 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: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
     24: @*/
     25: PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewMonitor(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:    SNESVecViewResidualMonitor - 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: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
     62: @*/
     63: PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewResidualMonitor(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:    SNESVecViewUpdateMonitor - 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: SNESSetMonitor(), SNESDefaultMonitor(), VecView()
    100: @*/
    101: PetscErrorCode PETSCSNES_DLLEXPORT SNESVecViewUpdateMonitor(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:    SNESDefaultMonitor - 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: SNESSetMonitor(), SNESVecViewMonitor()
    140: @*/
    141: PetscErrorCode PETSCSNES_DLLEXPORT SNESDefaultMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
    142: {
    144:   PetscViewer    viewer = (PetscViewer) dummy;

    147:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(snes->comm);
    148:   PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %14.12e \n",its,fgnorm);
    149:   return(0);
    150: }

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

    158:    Collective on SNES

    160:    Input Parameters:
    161: +  snes - the SNES context
    162: .  its - iteration number
    163: .  fgnorm - 2-norm of residual (or gradient)
    164: -  dummy - unused context

    166:    Level: intermediate

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

    170: .seealso: SNESSetMonitor(), SNESVecViewMonitor()
    171: @*/
    172: PetscErrorCode PETSCSNES_DLLEXPORT SNESRatioMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
    173: {
    175:   PetscInt       len;
    176:   PetscReal      *history;
    177:   PetscViewer    viewer;

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

    182:   SNESGetConvergenceHistory(snes,&history,PETSC_NULL,&len);
    183:   if (!its || !history || its > len) {
    184:     PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %14.12e \n",its,fgnorm);
    185:   } else {
    186:     PetscReal ratio = fgnorm/history[its-1];
    187:     PetscViewerASCIIPrintf(viewer,"%3D SNES Function norm %14.12e %g \n",its,fgnorm,ratio);
    188:   }
    189:   return(0);
    190: }

    192: /*
    193:    If the we set the history monitor space then we must destroy it
    194: */
    197: PetscErrorCode SNESRatioMonitorDestroy(void *history)
    198: {

    202:   PetscFree(history);
    203:   return(0);
    204: }

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

    212:    Collective on SNES

    214:    Input Parameters:
    215: .   snes - the SNES context

    217:    Level: intermediate

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

    221: .seealso: SNESSetMonitor(), SNESVecViewMonitor(), SNESDefaultMonitor()
    222: @*/
    223: PetscErrorCode PETSCSNES_DLLEXPORT SNESSetRatioMonitor(SNES snes)
    224: {
    226:   PetscReal      *history;

    230:   SNESGetConvergenceHistory(snes,&history,PETSC_NULL,PETSC_NULL);
    231:   if (!history) {
    232:     PetscMalloc(100*sizeof(double),&history);
    233:     SNESSetConvergenceHistory(snes,history,0,100,PETSC_TRUE);
    234:     SNESSetMonitor(snes,SNESRatioMonitor,history,SNESRatioMonitorDestroy);
    235:   } else {
    236:     SNESSetMonitor(snes,SNESRatioMonitor,0,0);
    237:   }
    238:   return(0);
    239: }

    241: /* ---------------------------------------------------------------- */
    244: /*
    245:      Default (short) SNES Monitor, same as SNESDefaultMonitor() except
    246:   it prints fewer digits of the residual as the residual gets smaller.
    247:   This is because the later digits are meaningless and are often
    248:   different on different machines; by using this routine different
    249:   machines will usually generate the same output.
    250: */
    251: PetscErrorCode PETSCSNES_DLLEXPORT SNESDefaultSMonitor(SNES snes,PetscInt its,PetscReal fgnorm,void *dummy)
    252: {

    256:   if (fgnorm > 1.e-9) {
    257:     PetscPrintf(snes->comm,"%3D SNES Function norm %g \n",its,fgnorm);
    258:   } else if (fgnorm > 1.e-11){
    259:     PetscPrintf(snes->comm,"%3D SNES Function norm %5.3e \n",its,fgnorm);
    260:   } else {
    261:     PetscPrintf(snes->comm,"%3D SNES Function norm < 1.e-11\n",its);
    262:   }
    263:   return(0);
    264: }
    265: /* ---------------------------------------------------------------- */
    268: /*@C
    269:    SNESConverged_LS - Monitors the convergence of the solvers for
    270:    systems of nonlinear equations (default).

    272:    Collective on SNES

    274:    Input Parameters:
    275: +  snes - the SNES context
    276: .  xnorm - 2-norm of current iterate
    277: .  pnorm - 2-norm of current step
    278: .  fnorm - 2-norm of function
    279: -  dummy - unused context

    281:    Output Parameter:
    282: .   reason  - one of
    283: $  SNES_CONVERGED_FNORM_ABS       - (fnorm < abstol),
    284: $  SNES_CONVERGED_PNORM_RELATIVE  - (pnorm < xtol*xnorm),
    285: $  SNES_CONVERGED_FNORM_RELATIVE  - (fnorm < rtol*fnorm0),
    286: $  SNES_DIVERGED_FUNCTION_COUNT   - (nfct > maxf),
    287: $  SNES_DIVERGED_FNORM_NAN        - (fnorm == NaN),
    288: $  SNES_CONVERGED_ITERATING       - (otherwise),

    290:    where
    291: +    maxf - maximum number of function evaluations,
    292:             set with SNESSetTolerances()
    293: .    nfct - number of function evaluations,
    294: .    abstol - absolute function norm tolerance,
    295:             set with SNESSetTolerances()
    296: -    rtol - relative function norm tolerance, set with SNESSetTolerances()

    298:    Level: intermediate

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

    302: .seealso: SNESSetConvergenceTest(), SNESEisenstatWalkerConverged()
    303: @*/
    304: PetscErrorCode PETSCSNES_DLLEXPORT SNESConverged_LS(SNES snes,PetscReal xnorm,PetscReal pnorm,PetscReal fnorm,SNESConvergedReason *reason,void *dummy)
    305: {

    309:   if (fnorm != fnorm) {
    310:     PetscLogInfo((snes,"SNESConverged_LS:Failed to converged, function norm is NaN\n"));
    311:     *reason = SNES_DIVERGED_FNORM_NAN;
    312:   } else if (fnorm <= snes->ttol) {
    313:     PetscLogInfo((snes,"SNESConverged_LS:Converged due to function norm %g < %g (relative tolerance)\n",fnorm,snes->ttol));
    314:     *reason = SNES_CONVERGED_FNORM_RELATIVE;
    315:   } else if (fnorm < snes->abstol) {
    316:     PetscLogInfo((snes,"SNESConverged_LS:Converged due to function norm %g < %g\n",fnorm,snes->abstol));
    317:     *reason = SNES_CONVERGED_FNORM_ABS;
    318:   } else if (pnorm < snes->xtol*xnorm) {
    319:     PetscLogInfo((snes,"SNESConverged_LS:Converged due to small update length: %g < %g * %g\n",pnorm,snes->xtol,xnorm));
    320:     *reason = SNES_CONVERGED_PNORM_RELATIVE;
    321:   } else if (snes->nfuncs >= snes->max_funcs) {
    322:     PetscLogInfo((snes,"SNESConverged_LS:Exceeded maximum number of function evaluations: %D > %D\n",snes->nfuncs,snes->max_funcs));
    323:     *reason = SNES_DIVERGED_FUNCTION_COUNT ;
    324:   } else {
    325:     *reason = SNES_CONVERGED_ITERATING;
    326:   }
    327:   return(0);
    328: }
    329: /* ------------------------------------------------------------ */
    332: /*@
    333:    SNES_KSP_SetConvergenceTestEW - Sets alternative convergence test
    334:    for the linear solvers within an inexact Newton method.

    336:    Collective on SNES

    338:    Input Parameter:
    339: .  snes - SNES context

    341:    Notes:
    342:    Currently, the default is to use a constant relative tolerance for
    343:    the inner linear solvers.  Alternatively, one can use the
    344:    Eisenstat-Walker method, where the relative convergence tolerance
    345:    is reset at each Newton iteration according progress of the nonlinear
    346:    solver.

    348:    Level: advanced

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

    354: .keywords: SNES, KSP, Eisenstat, Walker, convergence, test, inexact, Newton
    355: @*/
    356: PetscErrorCode PETSCSNES_DLLEXPORT SNES_KSP_SetConvergenceTestEW(SNES snes)
    357: {
    359:   snes->ksp_ewconv = PETSC_TRUE;
    360:   return(0);
    361: }

    365: /*@
    366:    SNES_KSP_SetParametersEW - Sets parameters for Eisenstat-Walker
    367:    convergence criteria for the linear solvers within an inexact
    368:    Newton method.

    370:    Collective on SNES
    371:
    372:    Input Parameters:
    373: +    snes - SNES context
    374: .    version - version 1 or 2 (default is 2)
    375: .    rtol_0 - initial relative tolerance (0 <= rtol_0 < 1)
    376: .    rtol_max - maximum relative tolerance (0 <= rtol_max < 1)
    377: .    alpha - power for version 2 rtol computation (1 < alpha <= 2)
    378: .    alpha2 - power for safeguard
    379: .    gamma2 - multiplicative factor for version 2 rtol computation
    380:               (0 <= gamma2 <= 1)
    381: -    threshold - threshold for imposing safeguard (0 < threshold < 1)

    383:    Note:
    384:    Use PETSC_DEFAULT to retain the default for any of the parameters.

    386:    Level: advanced

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

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

    395: .seealso: SNES_KSP_SetConvergenceTestEW()
    396: @*/
    397: PetscErrorCode PETSCSNES_DLLEXPORT SNES_KSP_SetParametersEW(SNES snes,PetscInt version,PetscReal rtol_0,PetscReal rtol_max,PetscReal gamma2,PetscReal alpha,
    398:                                         PetscReal alpha2,PetscReal threshold)
    399: {
    400:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;

    403:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context existing");
    404:   if (version != PETSC_DEFAULT)   kctx->version   = version;
    405:   if (rtol_0 != PETSC_DEFAULT)    kctx->rtol_0    = rtol_0;
    406:   if (rtol_max != PETSC_DEFAULT)  kctx->rtol_max  = rtol_max;
    407:   if (gamma2 != PETSC_DEFAULT)    kctx->gamma     = gamma2;
    408:   if (alpha != PETSC_DEFAULT)     kctx->alpha     = alpha;
    409:   if (alpha2 != PETSC_DEFAULT)    kctx->alpha2    = alpha2;
    410:   if (threshold != PETSC_DEFAULT) kctx->threshold = threshold;
    411:   if (kctx->rtol_0 < 0.0 || kctx->rtol_0 >= 1.0) {
    412:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_0 < 1.0: %g",kctx->rtol_0);
    413:   }
    414:   if (kctx->rtol_max < 0.0 || kctx->rtol_max >= 1.0) {
    415:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= rtol_max (%g) < 1.0\n",kctx->rtol_max);
    416:   }
    417:   if (kctx->threshold <= 0.0 || kctx->threshold >= 1.0) {
    418:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 < threshold (%g) < 1.0\n",kctx->threshold);
    419:   }
    420:   if (kctx->gamma < 0.0 || kctx->gamma > 1.0) {
    421:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"0.0 <= gamma (%g) <= 1.0\n",kctx->gamma);
    422:   }
    423:   if (kctx->alpha <= 1.0 || kctx->alpha > 2.0) {
    424:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"1.0 < alpha (%g) <= 2.0\n",kctx->alpha);
    425:   }
    426:   if (kctx->version != 1 && kctx->version !=2) {
    427:     SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 and 2 are supported: %D",kctx->version);
    428:   }
    429:   return(0);
    430: }

    434: PetscErrorCode SNES_KSP_EW_ComputeRelativeTolerance_Private(SNES snes,KSP ksp)
    435: {
    436:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
    437:   PetscReal           rtol = 0.0,stol;
    438:   PetscErrorCode      ierr;

    441:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context exists");
    442:   if (!snes->iter) { /* first time in, so use the original user rtol */
    443:     rtol = kctx->rtol_0;
    444:   } else {
    445:     if (kctx->version == 1) {
    446:       rtol = (snes->norm - kctx->lresid_last)/kctx->norm_last;
    447:       if (rtol < 0.0) rtol = -rtol;
    448:       stol = pow(kctx->rtol_last,kctx->alpha2);
    449:       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
    450:     } else if (kctx->version == 2) {
    451:       rtol = kctx->gamma * pow(snes->norm/kctx->norm_last,kctx->alpha);
    452:       stol = kctx->gamma * pow(kctx->rtol_last,kctx->alpha);
    453:       if (stol > kctx->threshold) rtol = PetscMax(rtol,stol);
    454:     } else SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Only versions 1 or 2 are supported: %D",kctx->version);
    455:   }
    456:   rtol = PetscMin(rtol,kctx->rtol_max);
    457:   kctx->rtol_last = rtol;
    458:   PetscLogInfo((snes,"SNES_KSP_EW_ComputeRelativeTolerance_Private: iter %D, Eisenstat-Walker (version %D) KSP rtol = %g\n",snes->iter,kctx->version,rtol));
    459:   KSPSetTolerances(ksp,rtol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
    460:   kctx->norm_last = snes->norm;
    461:   return(0);
    462: }

    466: PetscErrorCode SNES_KSP_EW_Converged_Private(KSP ksp,PetscInt n,PetscReal rnorm,KSPConvergedReason *reason,void *ctx)
    467: {
    468:   SNES                snes = (SNES)ctx;
    469:   SNES_KSP_EW_ConvCtx *kctx = (SNES_KSP_EW_ConvCtx*)snes->kspconvctx;
    470:   PetscErrorCode      ierr;

    473:   if (!kctx) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No Eisenstat-Walker context set");
    474:   if (!n) {SNES_KSP_EW_ComputeRelativeTolerance_Private(snes,ksp);}
    475:   KSPDefaultConverged(ksp,n,rnorm,reason,ctx);
    476:   kctx->lresid_last = rnorm;
    477:   if (*reason) {
    478:     PetscLogInfo((snes,"SNES_KSP_EW_Converged_Private: KSP iterations=%D, rnorm=%g\n",n,rnorm));
    479:   }
    480:   return(0);
    481: }