Date: 2013-07-02T14:51:07+00:00

Actual source code: alpha.c
petsc-3.4.2 2013-07-02

      1: /*
      2:   Code for timestepping with implicit generalized-\alpha method
      3:   for first order systems.
      4: */
      5: #include <petsc-private/tsimpl.h>                /*I   "petscts.h"   I*/

      7: typedef PetscErrorCode (*TSAlphaAdaptFunction)(TS,PetscReal,Vec,Vec,PetscReal*,PetscBool*,void*);

      9: typedef struct {
     10:   Vec       X0,Xa,X1;
     11:   Vec       V0,Va,V1;
     12:   Vec       R,E;
     13:   PetscReal Alpha_m;
     14:   PetscReal Alpha_f;
     15:   PetscReal Gamma;
     16:   PetscReal stage_time;
     17:   PetscReal shift;

     19:   TSAlphaAdaptFunction adapt;
     20:   void                 *adaptctx;
     21:   PetscReal            rtol;
     22:   PetscReal            atol;
     23:   PetscReal            rho;
     24:   PetscReal            scale_min;
     25:   PetscReal            scale_max;
     26:   PetscReal            dt_min;
     27:   PetscReal            dt_max;
     28: } TS_Alpha;

     32: static PetscErrorCode TSStep_Alpha(TS ts)
     33: {
     34:   TS_Alpha            *th = (TS_Alpha*)ts->data;
     35:   PetscInt            its,lits,reject;
     36:   PetscReal           next_time_step;
     37:   SNESConvergedReason snesreason = SNES_CONVERGED_ITERATING;
     38:   PetscErrorCode      ierr;

     41:   if (ts->steps == 0) {
     42:     VecSet(th->V0,0.0);
     43:   } else {
     44:     VecCopy(th->V1,th->V0);
     45:   }
     46:   VecCopy(ts->vec_sol,th->X0);
     47:   next_time_step = ts->time_step;
     48:   for (reject=0; reject<ts->max_reject; reject++,ts->reject++) {
     49:     ts->time_step  = next_time_step;
     50:     th->stage_time = ts->ptime + th->Alpha_f*ts->time_step;
     51:     th->shift      = th->Alpha_m/(th->Alpha_f*th->Gamma*ts->time_step);
     52:     TSPreStep(ts);
     53:     TSPreStage(ts,th->stage_time);
     54:     /* predictor */
     55:     VecCopy(th->X0,th->X1);
     56:     /* solve R(X,V) = 0 */
     57:     SNESSolve(ts->snes,NULL,th->X1);
     58:     /* V1 = (1-1/Gamma)*V0 + 1/(Gamma*dT)*(X1-X0) */
     59:     VecWAXPY(th->V1,-1,th->X0,th->X1);
     60:     VecAXPBY(th->V1,1-1/th->Gamma,1/(th->Gamma*ts->time_step),th->V0);
     61:     /* nonlinear solve convergence */
     62:     SNESGetConvergedReason(ts->snes,&snesreason);
     63:     if (snesreason < 0 && !th->adapt) break;
     64:     SNESGetIterationNumber(ts->snes,&its);
     65:     SNESGetLinearSolveIterations(ts->snes,&lits);
     66:     ts->snes_its += its; ts->ksp_its += lits;
     67:     PetscInfo3(ts,"step=%D, nonlinear solve iterations=%D, linear solve iterations=%D\n",ts->steps,its,lits);
     68:     /* time step adaptativity */
     69:     if (!th->adapt) break;
     70:     else {
     71:       PetscReal t1     = ts->ptime + ts->time_step;
     72:       PetscBool stepok = (reject==0) ? PETSC_TRUE : PETSC_FALSE;
     73:       th->adapt(ts,t1,th->X1,th->V1,&next_time_step,&stepok,th->adaptctx);
     74:       PetscInfo5(ts,"Step %D (t=%G,dt=%G) %s, next dt=%G\n",ts->steps,ts->ptime,ts->time_step,stepok?"accepted":"rejected",next_time_step);
     75:       if (stepok) break;
     76:     }
     77:   }
     78:   if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
     79:     ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
     80:     PetscInfo2(ts,"Step=%D, nonlinear solve solve failures %D greater than current TS allowed, stopping solve\n",ts->steps,ts->num_snes_failures);
     81:     return(0);
     82:   }
     83:   if (reject >= ts->max_reject) {
     84:     ts->reason = TS_DIVERGED_STEP_REJECTED;
     85:     PetscInfo2(ts,"Step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,reject);
     86:     return(0);
     87:   }
     88:   VecCopy(th->X1,ts->vec_sol);
     89:   ts->ptime    += ts->time_step;
     90:   ts->time_step = next_time_step;
     91:   ts->steps++;
     92:   return(0);
     93: }

     97: static PetscErrorCode TSInterpolate_Alpha(TS ts,PetscReal t,Vec X)
     98: {
     99:   TS_Alpha       *th = (TS_Alpha*)ts->data;
    100:   PetscReal      dt  = t - ts->ptime;

    104:   VecCopy(ts->vec_sol,X);
    105:   VecAXPY(X,th->Gamma*dt,th->V1);
    106:   VecAXPY(X,(1-th->Gamma)*dt,th->V0);
    107:   return(0);
    108: }

    110: /*------------------------------------------------------------*/
    113: static PetscErrorCode TSReset_Alpha(TS ts)
    114: {
    115:   TS_Alpha       *th = (TS_Alpha*)ts->data;

    119:   VecDestroy(&th->X0);
    120:   VecDestroy(&th->Xa);
    121:   VecDestroy(&th->X1);
    122:   VecDestroy(&th->V0);
    123:   VecDestroy(&th->Va);
    124:   VecDestroy(&th->V1);
    125:   VecDestroy(&th->E);
    126:   return(0);
    127: }

    131: static PetscErrorCode TSDestroy_Alpha(TS ts)
    132: {

    136:   TSReset_Alpha(ts);
    137:   PetscFree(ts->data);

    139:   PetscObjectComposeFunction((PetscObject)ts,"TSAlphaSetRadius_C",NULL);
    140:   PetscObjectComposeFunction((PetscObject)ts,"TSAlphaSetParams_C",NULL);
    141:   PetscObjectComposeFunction((PetscObject)ts,"TSAlphaGetParams_C",NULL);
    142:   PetscObjectComposeFunction((PetscObject)ts,"TSAlphaSetAdapt_C",NULL);
    143:   return(0);
    144: }

    148: static PetscErrorCode SNESTSFormFunction_Alpha(SNES snes,Vec x,Vec y,TS ts)
    149: {
    150:   TS_Alpha       *th = (TS_Alpha*)ts->data;
    151:   Vec            X0  = th->X0, V0 = th->V0;
    152:   Vec            X1  = x, V1 = th->V1, R = y;

    156:   /* V1 = (1-1/Gamma)*V0 + 1/(Gamma*dT)*(X1-X0) */
    157:   VecWAXPY(V1,-1,X0,X1);
    158:   VecAXPBY(V1,1-1/th->Gamma,1/(th->Gamma*ts->time_step),V0);
    159:   /* Xa = X0 + Alpha_f*(X1-X0) */
    160:   VecWAXPY(th->Xa,-1,X0,X1);
    161:   VecAYPX(th->Xa,th->Alpha_f,X0);
    162:   /* Va = V0 + Alpha_m*(V1-V0) */
    163:   VecWAXPY(th->Va,-1,V0,V1);
    164:   VecAYPX(th->Va,th->Alpha_m,V0);
    165:   /* F = Function(ta,Xa,Va) */
    166:   TSComputeIFunction(ts,th->stage_time,th->Xa,th->Va,R,PETSC_FALSE);
    167:   VecScale(R,1/th->Alpha_f);
    168:   return(0);
    169: }

    173: static PetscErrorCode SNESTSFormJacobian_Alpha(SNES snes,Vec x,Mat *A,Mat *B,MatStructure *str,TS ts)
    174: {
    175:   TS_Alpha       *th = (TS_Alpha*)ts->data;

    179:   /* A,B = Jacobian(ta,Xa,Va) */
    180:   TSComputeIJacobian(ts,th->stage_time,th->Xa,th->Va,th->shift,A,B,str,PETSC_FALSE);
    181:   return(0);
    182: }

    186: static PetscErrorCode TSSetUp_Alpha(TS ts)
    187: {
    188:   TS_Alpha       *th = (TS_Alpha*)ts->data;

    192:   VecDuplicate(ts->vec_sol,&th->X0);
    193:   VecDuplicate(ts->vec_sol,&th->Xa);
    194:   VecDuplicate(ts->vec_sol,&th->X1);
    195:   VecDuplicate(ts->vec_sol,&th->V0);
    196:   VecDuplicate(ts->vec_sol,&th->Va);
    197:   VecDuplicate(ts->vec_sol,&th->V1);
    198:   return(0);
    199: }

    203: static PetscErrorCode TSSetFromOptions_Alpha(TS ts)
    204: {
    205:   TS_Alpha       *th = (TS_Alpha*)ts->data;

    209:   PetscOptionsHead("Alpha ODE solver options");
    210:   {
    211:     PetscBool flag, adapt = PETSC_FALSE;
    212:     PetscReal radius = 1.0;
    213:     PetscOptionsReal("-ts_alpha_radius","spectral radius","TSAlphaSetRadius",radius,&radius,&flag);
    214:     if (flag) { TSAlphaSetRadius(ts,radius); }
    215:     PetscOptionsReal("-ts_alpha_alpha_m","algoritmic parameter alpha_m","TSAlphaSetParams",th->Alpha_m,&th->Alpha_m,NULL);
    216:     PetscOptionsReal("-ts_alpha_alpha_f","algoritmic parameter alpha_f","TSAlphaSetParams",th->Alpha_f,&th->Alpha_f,NULL);
    217:     PetscOptionsReal("-ts_alpha_gamma","algoritmic parameter gamma","TSAlphaSetParams",th->Gamma,&th->Gamma,NULL);
    218:     TSAlphaSetParams(ts,th->Alpha_m,th->Alpha_f,th->Gamma);

    220:     PetscOptionsBool("-ts_alpha_adapt","default time step adaptativity","TSAlphaSetAdapt",adapt,&adapt,&flag);
    221:     if (flag) { TSAlphaSetAdapt(ts,adapt ? TSAlphaAdaptDefault : NULL,NULL); }
    222:     PetscOptionsReal("-ts_alpha_adapt_rtol","relative tolerance for dt adaptativity","",th->rtol,&th->rtol,NULL);
    223:     PetscOptionsReal("-ts_alpha_adapt_atol","absolute tolerance for dt adaptativity","",th->atol,&th->atol,NULL);
    224:     PetscOptionsReal("-ts_alpha_adapt_min","minimum dt scale","",th->scale_min,&th->scale_min,NULL);
    225:     PetscOptionsReal("-ts_alpha_adapt_max","maximum dt scale","",th->scale_max,&th->scale_max,NULL);
    226:     PetscOptionsReal("-ts_alpha_adapt_dt_min","minimum dt","",th->dt_min,&th->dt_min,NULL);
    227:     PetscOptionsReal("-ts_alpha_adapt_dt_max","maximum dt","",th->dt_max,&th->dt_max,NULL);
    228:     SNESSetFromOptions(ts->snes);
    229:   }
    230:   PetscOptionsTail();
    231:   return(0);
    232: }

    236: static PetscErrorCode TSView_Alpha(TS ts,PetscViewer viewer)
    237: {
    238:   TS_Alpha       *th = (TS_Alpha*)ts->data;
    239:   PetscBool      iascii;

    243:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
    244:   if (iascii) {
    245:     PetscViewerASCIIPrintf(viewer,"  Alpha_m=%G, Alpha_f=%G, Gamma=%G\n",th->Alpha_m,th->Alpha_f,th->Gamma);
    246:   }
    247:   SNESView(ts->snes,viewer);
    248:   return(0);
    249: }

    251: /*------------------------------------------------------------*/

    255: PetscErrorCode  TSAlphaSetRadius_Alpha(TS ts,PetscReal radius)
    256: {
    257:   TS_Alpha *th = (TS_Alpha*)ts->data;

    260:   if (radius < 0 || radius > 1) SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Radius %G not in range [0,1]",radius);
    261:   th->Alpha_m = 0.5*(3-radius)/(1+radius);
    262:   th->Alpha_f = 1/(1+radius);
    263:   th->Gamma   = 0.5 + th->Alpha_m - th->Alpha_f;
    264:   return(0);
    265: }

    269: PetscErrorCode  TSAlphaSetParams_Alpha(TS ts,PetscReal alpha_m,PetscReal alpha_f,PetscReal gamma)
    270: {
    271:   TS_Alpha *th = (TS_Alpha*)ts->data;

    274:   th->Alpha_m = alpha_m;
    275:   th->Alpha_f = alpha_f;
    276:   th->Gamma   = gamma;
    277:   return(0);
    278: }

    282: PetscErrorCode  TSAlphaGetParams_Alpha(TS ts,PetscReal *alpha_m,PetscReal *alpha_f,PetscReal *gamma)
    283: {
    284:   TS_Alpha *th = (TS_Alpha*)ts->data;

    287:   if (alpha_m) *alpha_m = th->Alpha_m;
    288:   if (alpha_f) *alpha_f = th->Alpha_f;
    289:   if (gamma)   *gamma   = th->Gamma;
    290:   return(0);
    291: }

    295: PetscErrorCode  TSAlphaSetAdapt_Alpha(TS ts,TSAlphaAdaptFunction adapt,void *ctx)
    296: {
    297:   TS_Alpha *th = (TS_Alpha*)ts->data;

    300:   th->adapt    = adapt;
    301:   th->adaptctx = ctx;
    302:   return(0);
    303: }

    305: /* ------------------------------------------------------------ */
    306: /*MC
    307:       TSALPHA - DAE solver using the implicit Generalized-Alpha method

    309:   Level: beginner

    311:   References:
    312:   K.E. Jansen, C.H. Whiting, G.M. Hulber, "A generalized-alpha
    313:   method for integrating the filtered Navier-Stokes equations with a
    314:   stabilized finite element method", Computer Methods in Applied
    315:   Mechanics and Engineering, 190, 305-319, 2000.
    316:   DOI: 10.1016/S0045-7825(00)00203-6.

    318:   J. Chung, G.M.Hubert. "A Time Integration Algorithm for Structural
    319:   Dynamics with Improved Numerical Dissipation: The Generalized-alpha
    320:   Method" ASME Journal of Applied Mechanics, 60, 371:375, 1993.

    322: .seealso:  TSCreate(), TS, TSSetType()

    324: M*/
    327: PETSC_EXTERN PetscErrorCode TSCreate_Alpha(TS ts)
    328: {
    329:   TS_Alpha       *th;

    333:   ts->ops->reset          = TSReset_Alpha;
    334:   ts->ops->destroy        = TSDestroy_Alpha;
    335:   ts->ops->view           = TSView_Alpha;
    336:   ts->ops->setup          = TSSetUp_Alpha;
    337:   ts->ops->step           = TSStep_Alpha;
    338:   ts->ops->interpolate    = TSInterpolate_Alpha;
    339:   ts->ops->setfromoptions = TSSetFromOptions_Alpha;
    340:   ts->ops->snesfunction   = SNESTSFormFunction_Alpha;
    341:   ts->ops->snesjacobian   = SNESTSFormJacobian_Alpha;

    343:   PetscNewLog(ts,TS_Alpha,&th);
    344:   ts->data = (void*)th;

    346:   th->Alpha_m = 0.5;
    347:   th->Alpha_f = 0.5;
    348:   th->Gamma   = 0.5;

    350:   th->rtol      = 1e-3;
    351:   th->atol      = 1e-3;
    352:   th->rho       = 0.9;
    353:   th->scale_min = 0.1;
    354:   th->scale_max = 5.0;
    355:   th->dt_min    = 0.0;
    356:   th->dt_max    = PETSC_MAX_REAL;

    358:   PetscObjectComposeFunction((PetscObject)ts,"TSAlphaSetAdapt_C",TSAlphaSetAdapt_Alpha);
    359:   PetscObjectComposeFunction((PetscObject)ts,"TSAlphaSetRadius_C",TSAlphaSetRadius_Alpha);
    360:   PetscObjectComposeFunction((PetscObject)ts,"TSAlphaSetParams_C",TSAlphaSetParams_Alpha);
    361:   PetscObjectComposeFunction((PetscObject)ts,"TSAlphaGetParams_C",TSAlphaGetParams_Alpha);
    362:   return(0);
    363: }

    367: /*@C
    368:   TSAlphaSetAdapt - sets the time step adaptativity and acceptance test routine

    370:   This function allows to accept/reject a step and select the
    371:   next time step to use.

    373:   Not Collective

    375:   Input Parameter:
    376: +  ts - timestepping context
    377: .  adapt - user-defined adapt routine
    378: -  ctx  - [optional] user-defined context for private data for the
    379:          adapt routine (may be NULL)

    381:    Calling sequence of adapt:
    382: $    adapt (TS ts,PetscReal t,Vec X,Vec Xdot,
    383: $            PetscReal *next_dt,PetscBool *accepted,void *ctx);

    385:   Level: intermediate

    387: @*/
    388: PetscErrorCode  TSAlphaSetAdapt(TS ts,TSAlphaAdaptFunction adapt,void *ctx)
    389: {

    394:   PetscTryMethod(ts,"TSAlphaSetAdapt_C",(TS,TSAlphaAdaptFunction,void*),(ts,adapt,ctx));
    395:   return(0);
    396: }

    400: PetscErrorCode  TSAlphaAdaptDefault(TS ts,PetscReal t,Vec X,Vec Xdot, PetscReal *nextdt,PetscBool *ok,void *ctx)
    401: {
    402:   TS_Alpha            *th;
    403:   SNESConvergedReason snesreason;
    404:   PetscReal           dt,normX,normE,Emax,scale;
    405:   PetscErrorCode      ierr;

    409: #if PETSC_USE_DEBUG
    410:   {
    411:     PetscBool match;
    412:     PetscObjectTypeCompare((PetscObject)ts,TSALPHA,&match);
    413:     if (!match) SETERRQ(PetscObjectComm((PetscObject)ts),1,"Only for TSALPHA");
    414:   }
    415: #endif
    416:   th = (TS_Alpha*)ts->data;

    418:   SNESGetConvergedReason(ts->snes,&snesreason);
    419:   if (snesreason < 0) {
    420:     *ok      = PETSC_FALSE;
    421:     *nextdt *= th->scale_min;
    422:     goto finally;
    423:   }

    425:   /* first-order aproximation to the local error */
    426:   /* E = (X0 + dt*Xdot) - X */
    427:   TSGetTimeStep(ts,&dt);
    428:   if (!th->E) {VecDuplicate(th->X0,&th->E);}
    429:   VecWAXPY(th->E,dt,Xdot,th->X0);
    430:   VecAXPY(th->E,-1,X);
    431:   VecNorm(th->E,NORM_2,&normE);
    432:   /* compute maximum allowable error */
    433:   VecNorm(X,NORM_2,&normX);
    434:   if (normX == 0) {VecNorm(th->X0,NORM_2,&normX);}
    435:   Emax =  th->rtol * normX + th->atol;
    436:   /* compute next time step */
    437:   if (normE > 0) {
    438:     scale = th->rho * PetscRealPart(PetscSqrtScalar((PetscScalar)(Emax/normE)));
    439:     scale = PetscMax(scale,th->scale_min);
    440:     scale = PetscMin(scale,th->scale_max);
    441:     if (!(*ok)) scale = PetscMin(1.0,scale);
    442:     *nextdt *= scale;
    443:   }
    444:   /* accept or reject step */
    445:   if (normE <= Emax) *ok = PETSC_TRUE;
    446:   else               *ok = PETSC_FALSE;

    448: finally:
    449:   *nextdt = PetscMax(*nextdt,th->dt_min);
    450:   *nextdt = PetscMin(*nextdt,th->dt_max);
    451:   return(0);
    452: }

    456: /*@
    457:   TSAlphaSetRadius - sets the desired spectral radius of the method
    458:                      (i.e. high-frequency numerical damping)

    460:   Logically Collective on TS

    462:   The algorithmic parameters \alpha_m and \alpha_f of the
    463:   generalized-\alpha method can be computed in terms of a specified
    464:   spectral radius \rho in [0,1] for infinite time step in order to
    465:   control high-frequency numerical damping:
    466:     alpha_m = 0.5*(3-\rho)/(1+\rho)
    467:     alpha_f = 1/(1+\rho)

    469:   Input Parameter:
    470: +  ts - timestepping context
    471: -  radius - the desired spectral radius

    473:   Options Database:
    474: .  -ts_alpha_radius <radius>

    476:   Level: intermediate

    478: .seealso: TSAlphaSetParams(), TSAlphaGetParams()
    479: @*/
    480: PetscErrorCode  TSAlphaSetRadius(TS ts,PetscReal radius)
    481: {

    486:   PetscTryMethod(ts,"TSAlphaSetRadius_C",(TS,PetscReal),(ts,radius));
    487:   return(0);
    488: }

    492: /*@
    493:   TSAlphaSetParams - sets the algorithmic parameters for TSALPHA

    495:   Not Collective

    497:   Second-order accuracy can be obtained so long as:
    498:     \gamma = 0.5 + alpha_m - alpha_f

    500:   Unconditional stability requires:
    501:     \alpha_m >= \alpha_f >= 0.5

    503:   Backward Euler method is recovered when:
    504:     \alpha_m = \alpha_f = gamma = 1

    507:   Input Parameter:
    508: +  ts - timestepping context
    509: .  \alpha_m - algorithmic paramenter
    510: .  \alpha_f - algorithmic paramenter
    511: -  \gamma   - algorithmic paramenter

    513:    Options Database:
    514: +  -ts_alpha_alpha_m <alpha_m>
    515: .  -ts_alpha_alpha_f <alpha_f>
    516: -  -ts_alpha_gamma <gamma>

    518:   Note:
    519:   Use of this function is normally only required to hack TSALPHA to
    520:   use a modified integration scheme. Users should call
    521:   TSAlphaSetRadius() to set the desired spectral radius of the methods
    522:   (i.e. high-frequency damping) in order so select optimal values for
    523:   these parameters.

    525:   Level: advanced

    527: .seealso: TSAlphaSetRadius(), TSAlphaGetParams()
    528: @*/
    529: PetscErrorCode  TSAlphaSetParams(TS ts,PetscReal alpha_m,PetscReal alpha_f,PetscReal gamma)
    530: {

    535:   PetscTryMethod(ts,"TSAlphaSetParams_C",(TS,PetscReal,PetscReal,PetscReal),(ts,alpha_m,alpha_f,gamma));
    536:   return(0);
    537: }

    541: /*@
    542:   TSAlphaGetParams - gets the algorithmic parameters for TSALPHA

    544:   Not Collective

    546:   Input Parameter:
    547: +  ts - timestepping context
    548: .  \alpha_m - algorithmic parameter
    549: .  \alpha_f - algorithmic parameter
    550: -  \gamma   - algorithmic parameter

    552:   Note:
    553:   Use of this function is normally only required to hack TSALPHA to
    554:   use a modified integration scheme. Users should call
    555:   TSAlphaSetRadius() to set the high-frequency damping (i.e. spectral
    556:   radius of the method) in order so select optimal values for these
    557:   parameters.

    559:   Level: advanced

    561: .seealso: TSAlphaSetRadius(), TSAlphaSetParams()
    562: @*/
    563: PetscErrorCode  TSAlphaGetParams(TS ts,PetscReal *alpha_m,PetscReal *alpha_f,PetscReal *gamma)
    564: {

    572:   PetscUseMethod(ts,"TSAlphaGetParams_C",(TS,PetscReal*,PetscReal*,PetscReal*),(ts,alpha_m,alpha_f,gamma));
    573:   return(0);
    574: }