Actual source code: posindep.c

petsc-3.7.7 2017-09-25
Report Typos and Errors
  1: /*
  2:        Code for Timestepping with implicit backwards Euler.
  3: */
  4: #include <petsc/private/tsimpl.h>                /*I   "petscts.h"   I*/

  6: typedef struct {
  7:   Vec update;       /* work vector where new solution is formed */
  8:   Vec func;         /* work vector where F(t[i],u[i]) is stored */
  9:   Vec xdot;         /* work vector for time derivative of state */

 11:   /* information used for Pseudo-timestepping */

 13:   PetscErrorCode (*dt)(TS,PetscReal*,void*);              /* compute next timestep, and related context */
 14:   void *dtctx;
 15:   PetscErrorCode (*verify)(TS,Vec,void*,PetscReal*,PetscBool*);  /* verify previous timestep and related context */
 16:   void *verifyctx;

 18:   PetscReal fnorm_initial,fnorm;                   /* original and current norm of F(u) */
 19:   PetscReal fnorm_previous;

 21:   PetscReal dt_initial;                     /* initial time-step */
 22:   PetscReal dt_increment;                   /* scaling that dt is incremented each time-step */
 23:   PetscReal dt_max;                         /* maximum time step */
 24:   PetscBool increment_dt_from_initial_dt;
 25:   PetscReal fatol,frtol;
 26: } TS_Pseudo;

 28: /* ------------------------------------------------------------------------------*/

 32: /*@C
 33:     TSPseudoComputeTimeStep - Computes the next timestep for a currently running
 34:     pseudo-timestepping process.

 36:     Collective on TS

 38:     Input Parameter:
 39: .   ts - timestep context

 41:     Output Parameter:
 42: .   dt - newly computed timestep

 44:     Level: developer

 46:     Notes:
 47:     The routine to be called here to compute the timestep should be
 48:     set by calling TSPseudoSetTimeStep().

 50: .keywords: timestep, pseudo, compute

 52: .seealso: TSPseudoTimeStepDefault(), TSPseudoSetTimeStep()
 53: @*/
 54: PetscErrorCode  TSPseudoComputeTimeStep(TS ts,PetscReal *dt)
 55: {
 56:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;

 60:   PetscLogEventBegin(TS_PseudoComputeTimeStep,ts,0,0,0);
 61:   (*pseudo->dt)(ts,dt,pseudo->dtctx);
 62:   PetscLogEventEnd(TS_PseudoComputeTimeStep,ts,0,0,0);
 63:   return(0);
 64: }


 67: /* ------------------------------------------------------------------------------*/
 70: /*@C
 71:    TSPseudoVerifyTimeStepDefault - Default code to verify the quality of the last timestep.

 73:    Collective on TS

 75:    Input Parameters:
 76: +  ts - the timestep context
 77: .  dtctx - unused timestep context
 78: -  update - latest solution vector

 80:    Output Parameters:
 81: +  newdt - the timestep to use for the next step
 82: -  flag - flag indicating whether the last time step was acceptable

 84:    Level: advanced

 86:    Note:
 87:    This routine always returns a flag of 1, indicating an acceptable
 88:    timestep.

 90: .keywords: timestep, pseudo, default, verify

 92: .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoVerifyTimeStep()
 93: @*/
 94: PetscErrorCode  TSPseudoVerifyTimeStepDefault(TS ts,Vec update,void *dtctx,PetscReal *newdt,PetscBool  *flag)
 95: {
 97:   *flag = PETSC_TRUE;
 98:   return(0);
 99: }


104: /*@
105:     TSPseudoVerifyTimeStep - Verifies whether the last timestep was acceptable.

107:     Collective on TS

109:     Input Parameters:
110: +   ts - timestep context
111: -   update - latest solution vector

113:     Output Parameters:
114: +   dt - newly computed timestep (if it had to shrink)
115: -   flag - indicates if current timestep was ok

117:     Level: advanced

119:     Notes:
120:     The routine to be called here to compute the timestep should be
121:     set by calling TSPseudoSetVerifyTimeStep().

123: .keywords: timestep, pseudo, verify

125: .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoVerifyTimeStepDefault()
126: @*/
127: PetscErrorCode  TSPseudoVerifyTimeStep(TS ts,Vec update,PetscReal *dt,PetscBool *flag)
128: {
129:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;

133:   *flag = PETSC_TRUE;
134:   if(pseudo->verify) {
135:     (*pseudo->verify)(ts,update,pseudo->verifyctx,dt,flag);
136:   }
137:   return(0);
138: }

140: /* --------------------------------------------------------------------------------*/

144: static PetscErrorCode TSStep_Pseudo(TS ts)
145: {
146:   TS_Pseudo           *pseudo = (TS_Pseudo*)ts->data;
147:   PetscInt            nits,lits,reject;
148:   PetscBool           stepok;
149:   PetscReal           next_time_step = ts->time_step;
150:   PetscErrorCode      ierr;

153:   if (ts->steps == 0) pseudo->dt_initial = ts->time_step;
154:   VecCopy(ts->vec_sol,pseudo->update);
155:   TSPseudoComputeTimeStep(ts,&next_time_step);
156:   for (reject=0; reject<ts->max_reject; reject++,ts->reject++) {
157:     ts->time_step = next_time_step;
158:     TSPreStage(ts,ts->ptime+ts->time_step);
159:     SNESSolve(ts->snes,NULL,pseudo->update);
160:     SNESGetIterationNumber(ts->snes,&nits);
161:     SNESGetLinearSolveIterations(ts->snes,&lits);
162:     ts->snes_its += nits; ts->ksp_its += lits;
163:     TSPostStage(ts,ts->ptime+ts->time_step,0,&(pseudo->update));
164:     TSAdaptCheckStage(ts->adapt,ts,ts->ptime+ts->time_step,pseudo->update,&stepok);
165:     if (!stepok) {next_time_step = ts->time_step; continue;}
166:     pseudo->fnorm = -1; /* The current norm is no longer valid, monitor must recompute it. */
167:     TSPseudoVerifyTimeStep(ts,pseudo->update,&next_time_step,&stepok);
168:     if (stepok) break;
169:   }
170:   if (reject >= ts->max_reject) {
171:     ts->reason = TS_DIVERGED_STEP_REJECTED;
172:     PetscInfo2(ts,"Step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,reject);
173:     return(0);
174:   }

176:   VecCopy(pseudo->update,ts->vec_sol);
177:   ts->ptime += ts->time_step;
178:   ts->time_step = next_time_step;

180:   if (pseudo->fnorm < 0) {
181:     VecZeroEntries(pseudo->xdot);
182:     TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);
183:     VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);
184:   }
185:   if (pseudo->fnorm < pseudo->fatol) {
186:     ts->reason = TS_CONVERGED_PSEUDO_FATOL;
187:     PetscInfo3(ts,"Step=%D, converged since fnorm %g < fatol %g\n",ts->steps,pseudo->fnorm,pseudo->frtol);
188:     return(0);
189:   }
190:   if (pseudo->fnorm/pseudo->fnorm_initial < pseudo->frtol) {
191:     ts->reason = TS_CONVERGED_PSEUDO_FRTOL;
192:     PetscInfo4(ts,"Step=%D, converged since fnorm %g / fnorm_initial %g < frtol %g\n",ts->steps,pseudo->fnorm,pseudo->fnorm_initial,pseudo->fatol);
193:     return(0);
194:   }
195:   return(0);
196: }

198: /*------------------------------------------------------------*/
201: static PetscErrorCode TSReset_Pseudo(TS ts)
202: {
203:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;

207:   VecDestroy(&pseudo->update);
208:   VecDestroy(&pseudo->func);
209:   VecDestroy(&pseudo->xdot);
210:   return(0);
211: }

215: static PetscErrorCode TSDestroy_Pseudo(TS ts)
216: {

220:   TSReset_Pseudo(ts);
221:   PetscFree(ts->data);
222:   PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",NULL);
223:   PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",NULL);
224:   PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetMaxTimeStep_C",NULL);
225:   PetscObjectComposeFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",NULL);
226:   PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStep_C",NULL);
227:   return(0);
228: }

230: /*------------------------------------------------------------*/

234: /*
235:     Compute Xdot = (X^{n+1}-X^n)/dt) = 0
236: */
237: static PetscErrorCode TSPseudoGetXdot(TS ts,Vec X,Vec *Xdot)
238: {
239:   TS_Pseudo         *pseudo = (TS_Pseudo*)ts->data;
240:   const PetscScalar mdt     = 1.0/ts->time_step,*xnp1,*xn;
241:   PetscScalar       *xdot;
242:   PetscErrorCode    ierr;
243:   PetscInt          i,n;

246:   VecGetArrayRead(ts->vec_sol,&xn);
247:   VecGetArrayRead(X,&xnp1);
248:   VecGetArray(pseudo->xdot,&xdot);
249:   VecGetLocalSize(X,&n);
250:   for (i=0; i<n; i++) xdot[i] = mdt*(xnp1[i] - xn[i]);
251:   VecRestoreArrayRead(ts->vec_sol,&xn);
252:   VecRestoreArrayRead(X,&xnp1);
253:   VecRestoreArray(pseudo->xdot,&xdot);
254:   *Xdot = pseudo->xdot;
255:   return(0);
256: }

260: /*
261:     The transient residual is

263:         F(U^{n+1},(U^{n+1}-U^n)/dt) = 0

265:     or for ODE,

267:         (U^{n+1} - U^{n})/dt - F(U^{n+1}) = 0

269:     This is the function that must be evaluated for transient simulation and for
270:     finite difference Jacobians.  On the first Newton step, this algorithm uses
271:     a guess of U^{n+1} = U^n in which case the transient term vanishes and the
272:     residual is actually the steady state residual.  Pseudotransient
273:     continuation as described in the literature is a linearly implicit
274:     algorithm, it only takes this one Newton step with the steady state
275:     residual, and then advances to the next time step.
276: */
277: static PetscErrorCode SNESTSFormFunction_Pseudo(SNES snes,Vec X,Vec Y,TS ts)
278: {
279:   Vec            Xdot;

283:   TSPseudoGetXdot(ts,X,&Xdot);
284:   TSComputeIFunction(ts,ts->ptime+ts->time_step,X,Xdot,Y,PETSC_FALSE);
285:   return(0);
286: }

290: /*
291:    This constructs the Jacobian needed for SNES.  For DAE, this is

293:        dF(X,Xdot)/dX + shift*dF(X,Xdot)/dXdot

295:     and for ODE:

297:        J = I/dt - J_{Frhs}   where J_{Frhs} is the given Jacobian of Frhs.
298: */
299: static PetscErrorCode SNESTSFormJacobian_Pseudo(SNES snes,Vec X,Mat AA,Mat BB,TS ts)
300: {
301:   Vec            Xdot;

305:   TSPseudoGetXdot(ts,X,&Xdot);
306:   TSComputeIJacobian(ts,ts->ptime+ts->time_step,X,Xdot,1./ts->time_step,AA,BB,PETSC_FALSE);
307:   return(0);
308: }


313: static PetscErrorCode TSSetUp_Pseudo(TS ts)
314: {
315:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;

319:   VecDuplicate(ts->vec_sol,&pseudo->update);
320:   VecDuplicate(ts->vec_sol,&pseudo->func);
321:   VecDuplicate(ts->vec_sol,&pseudo->xdot);
322:   return(0);
323: }
324: /*------------------------------------------------------------*/

328: static PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *dummy)
329: {
330:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
332:   PetscViewer    viewer = (PetscViewer) dummy;

335:   if (pseudo->fnorm < 0) { /* The last computed norm is stale, recompute */
336:     VecZeroEntries(pseudo->xdot);
337:     TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);
338:     VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);
339:   }
340:   PetscViewerASCIIAddTab(viewer,((PetscObject)ts)->tablevel);
341:   PetscViewerASCIIPrintf(viewer,"TS %D dt %g time %g fnorm %g\n",step,(double)ts->time_step,(double)ptime,(double)pseudo->fnorm);
342:   PetscViewerASCIISubtractTab(viewer,((PetscObject)ts)->tablevel);
343:   return(0);
344: }

348: static PetscErrorCode TSSetFromOptions_Pseudo(PetscOptionItems *PetscOptionsObject,TS ts)
349: {
350:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
352:   PetscBool      flg = PETSC_FALSE;
353:   PetscViewer    viewer;

356:   PetscOptionsHead(PetscOptionsObject,"Pseudo-timestepping options");
357:   PetscOptionsBool("-ts_monitor_pseudo","Monitor convergence","",flg,&flg,NULL);
358:   if (flg) {
359:     PetscViewerASCIIOpen(PetscObjectComm((PetscObject)ts),"stdout",&viewer);
360:     TSMonitorSet(ts,TSPseudoMonitorDefault,viewer,(PetscErrorCode (*)(void**))PetscViewerDestroy);
361:   }
362:   flg  = pseudo->increment_dt_from_initial_dt;
363:   PetscOptionsBool("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",flg,&flg,NULL);
364:   pseudo->increment_dt_from_initial_dt = flg;
365:   PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,NULL);
366:   PetscOptionsReal("-ts_pseudo_max_dt","Maximum value for dt","TSPseudoSetMaxTimeStep",pseudo->dt_max,&pseudo->dt_max,NULL);
367:   PetscOptionsReal("-ts_pseudo_fatol","Tolerance for norm of function","",pseudo->fatol,&pseudo->fatol,NULL);
368:   PetscOptionsReal("-ts_pseudo_frtol","Relative tolerance for norm of function","",pseudo->frtol,&pseudo->frtol,NULL);
369:   PetscOptionsTail();
370:   return(0);
371: }

375: static PetscErrorCode TSView_Pseudo(TS ts,PetscViewer viewer)
376: {
378:   PetscBool      isascii;

381:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
382:   if (isascii) {
383:     TS_Pseudo *pseudo = (TS_Pseudo*) ts->data;
384:     PetscViewerASCIIPrintf(viewer,"Parameters for pseudo timestepping\n");
385:     PetscViewerASCIIPrintf(viewer,"  frtol - relative tolerance in function value %g\n",(double)pseudo->frtol);
386:     PetscViewerASCIIPrintf(viewer,"  fatol - absolute tolerance in function value %g\n",(double)pseudo->fatol);
387:     PetscViewerASCIIPrintf(viewer,"  dt_initial - initial timestep %g\n",(double)pseudo->dt_initial);
388:     PetscViewerASCIIPrintf(viewer,"  dt_increment - increase in timestep on successful step %g\n",(double)pseudo->dt_increment);
389:     PetscViewerASCIIPrintf(viewer,"  dt_max - maximum time %g\n",(double)pseudo->dt_max);
390:   }
391:   if (ts->snes) {SNESView(ts->snes,viewer);}
392:   return(0);
393: }

395: /* ----------------------------------------------------------------------------- */
398: /*@C
399:    TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the
400:    last timestep.

402:    Logically Collective on TS

404:    Input Parameters:
405: +  ts - timestep context
406: .  dt - user-defined function to verify timestep
407: -  ctx - [optional] user-defined context for private data
408:          for the timestep verification routine (may be NULL)

410:    Level: advanced

412:    Calling sequence of func:
413: .  func (TS ts,Vec update,void *ctx,PetscReal *newdt,PetscBool  *flag);

415: .  update - latest solution vector
416: .  ctx - [optional] timestep context
417: .  newdt - the timestep to use for the next step
418: .  flag - flag indicating whether the last time step was acceptable

420:    Notes:
421:    The routine set here will be called by TSPseudoVerifyTimeStep()
422:    during the timestepping process.

424: .keywords: timestep, pseudo, set, verify

426: .seealso: TSPseudoVerifyTimeStepDefault(), TSPseudoVerifyTimeStep()
427: @*/
428: PetscErrorCode  TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (*dt)(TS,Vec,void*,PetscReal*,PetscBool*),void *ctx)
429: {

434:   PetscTryMethod(ts,"TSPseudoSetVerifyTimeStep_C",(TS,PetscErrorCode (*)(TS,Vec,void*,PetscReal*,PetscBool*),void*),(ts,dt,ctx));
435:   return(0);
436: }

440: /*@
441:     TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to
442:     dt when using the TSPseudoTimeStepDefault() routine.

444:    Logically Collective on TS

446:     Input Parameters:
447: +   ts - the timestep context
448: -   inc - the scaling factor >= 1.0

450:     Options Database Key:
451: .    -ts_pseudo_increment <increment>

453:     Level: advanced

455: .keywords: timestep, pseudo, set, increment

457: .seealso: TSPseudoSetTimeStep(), TSPseudoTimeStepDefault()
458: @*/
459: PetscErrorCode  TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc)
460: {

466:   PetscTryMethod(ts,"TSPseudoSetTimeStepIncrement_C",(TS,PetscReal),(ts,inc));
467:   return(0);
468: }

472: /*@
473:     TSPseudoSetMaxTimeStep - Sets the maximum time step
474:     when using the TSPseudoTimeStepDefault() routine.

476:    Logically Collective on TS

478:     Input Parameters:
479: +   ts - the timestep context
480: -   maxdt - the maximum time step, use a non-positive value to deactivate

482:     Options Database Key:
483: .    -ts_pseudo_max_dt <increment>

485:     Level: advanced

487: .keywords: timestep, pseudo, set

489: .seealso: TSPseudoSetTimeStep(), TSPseudoTimeStepDefault()
490: @*/
491: PetscErrorCode  TSPseudoSetMaxTimeStep(TS ts,PetscReal maxdt)
492: {

498:   PetscTryMethod(ts,"TSPseudoSetMaxTimeStep_C",(TS,PetscReal),(ts,maxdt));
499:   return(0);
500: }

504: /*@
505:     TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep
506:     is computed via the formula
507: $         dt = initial_dt*initial_fnorm/current_fnorm
508:       rather than the default update,
509: $         dt = current_dt*previous_fnorm/current_fnorm.

511:    Logically Collective on TS

513:     Input Parameter:
514: .   ts - the timestep context

516:     Options Database Key:
517: .    -ts_pseudo_increment_dt_from_initial_dt

519:     Level: advanced

521: .keywords: timestep, pseudo, set, increment

523: .seealso: TSPseudoSetTimeStep(), TSPseudoTimeStepDefault()
524: @*/
525: PetscErrorCode  TSPseudoIncrementDtFromInitialDt(TS ts)
526: {

531:   PetscTryMethod(ts,"TSPseudoIncrementDtFromInitialDt_C",(TS),(ts));
532:   return(0);
533: }


538: /*@C
539:    TSPseudoSetTimeStep - Sets the user-defined routine to be
540:    called at each pseudo-timestep to update the timestep.

542:    Logically Collective on TS

544:    Input Parameters:
545: +  ts - timestep context
546: .  dt - function to compute timestep
547: -  ctx - [optional] user-defined context for private data
548:          required by the function (may be NULL)

550:    Level: intermediate

552:    Calling sequence of func:
553: .  func (TS ts,PetscReal *newdt,void *ctx);

555: .  newdt - the newly computed timestep
556: .  ctx - [optional] timestep context

558:    Notes:
559:    The routine set here will be called by TSPseudoComputeTimeStep()
560:    during the timestepping process.
561:    If not set then TSPseudoTimeStepDefault() is automatically used

563: .keywords: timestep, pseudo, set

565: .seealso: TSPseudoTimeStepDefault(), TSPseudoComputeTimeStep()
566: @*/
567: PetscErrorCode  TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void *ctx)
568: {

573:   PetscTryMethod(ts,"TSPseudoSetTimeStep_C",(TS,PetscErrorCode (*)(TS,PetscReal*,void*),void*),(ts,dt,ctx));
574:   return(0);
575: }

577: /* ----------------------------------------------------------------------------- */

579: typedef PetscErrorCode (*FCN1)(TS,Vec,void*,PetscReal*,PetscBool*);  /* force argument to next function to not be extern C*/
582: static PetscErrorCode  TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void *ctx)
583: {
584:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

587:   pseudo->verify    = dt;
588:   pseudo->verifyctx = ctx;
589:   return(0);
590: }

594: static PetscErrorCode  TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc)
595: {
596:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

599:   pseudo->dt_increment = inc;
600:   return(0);
601: }

605: static PetscErrorCode  TSPseudoSetMaxTimeStep_Pseudo(TS ts,PetscReal maxdt)
606: {
607:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

610:   pseudo->dt_max = maxdt;
611:   return(0);
612: }

616: static PetscErrorCode  TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
617: {
618:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

621:   pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
622:   return(0);
623: }

625: typedef PetscErrorCode (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/
628: static PetscErrorCode  TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void *ctx)
629: {
630:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

633:   pseudo->dt    = dt;
634:   pseudo->dtctx = ctx;
635:   return(0);
636: }

638: /* ----------------------------------------------------------------------------- */
639: /*MC
640:       TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping

642:   This method solves equations of the form

644: $    F(X,Xdot) = 0

646:   for steady state using the iteration

648: $    [G'] S = -F(X,0)
649: $    X += S

651:   where

653: $    G(Y) = F(Y,(Y-X)/dt)

655:   This is linearly-implicit Euler with the residual always evaluated "at steady
656:   state".  See note below.

658:   Options database keys:
659: +  -ts_pseudo_increment <real> - ratio of increase dt
660: .  -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt
661: .  -ts_pseudo_fatol <atol> - stop iterating when the function norm is less than atol
662: -  -ts_pseudo_frtol <rtol> - stop iterating when the function norm divided by the initial function norm is less than rtol

664:   Level: beginner

666:   References:
667: +  1. - Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential Algebraic Equations, 2003.
668: -  2. - C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998.

670:   Notes:
671:   The residual computed by this method includes the transient term (Xdot is computed instead of
672:   always being zero), but since the prediction from the last step is always the solution from the
673:   last step, on the first Newton iteration we have

675: $  Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0

677:   Therefore, the linear system solved by the first Newton iteration is equivalent to the one
678:   described above and in the papers.  If the user chooses to perform multiple Newton iterations, the
679:   algorithm is no longer the one described in the referenced papers.

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

683: M*/
686: PETSC_EXTERN PetscErrorCode TSCreate_Pseudo(TS ts)
687: {
688:   TS_Pseudo      *pseudo;
690:   SNES           snes;
691:   SNESType       stype;

694:   ts->ops->reset          = TSReset_Pseudo;
695:   ts->ops->destroy        = TSDestroy_Pseudo;
696:   ts->ops->view           = TSView_Pseudo;
697:   ts->ops->setup          = TSSetUp_Pseudo;
698:   ts->ops->step           = TSStep_Pseudo;
699:   ts->ops->setfromoptions = TSSetFromOptions_Pseudo;
700:   ts->ops->snesfunction   = SNESTSFormFunction_Pseudo;
701:   ts->ops->snesjacobian   = SNESTSFormJacobian_Pseudo;

703:   TSGetSNES(ts,&snes);
704:   SNESGetType(snes,&stype);
705:   if (!stype) {SNESSetType(snes,SNESKSPONLY);}

707:   PetscNewLog(ts,&pseudo);
708:   ts->data = (void*)pseudo;

710:   pseudo->dt                           = TSPseudoTimeStepDefault;
711:   pseudo->dtctx                        = NULL;
712:   pseudo->dt_increment                 = 1.1;
713:   pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
714:   pseudo->fnorm                        = -1;
715:   pseudo->fnorm_initial                = -1;
716:   pseudo->fnorm_previous               = -1;
717:  #if defined(PETSC_USE_REAL_SINGLE)
718:   pseudo->fatol                        = 1.e-25;
719:   pseudo->frtol                        = 1.e-5;
720: #else
721:   pseudo->fatol                        = 1.e-50;
722:   pseudo->frtol                        = 1.e-12;
723: #endif
724:   PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",TSPseudoSetVerifyTimeStep_Pseudo);
725:   PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",TSPseudoSetTimeStepIncrement_Pseudo);
726:   PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetMaxTimeStep_C",TSPseudoSetMaxTimeStep_Pseudo);
727:   PetscObjectComposeFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",TSPseudoIncrementDtFromInitialDt_Pseudo);
728:   PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStep_C",TSPseudoSetTimeStep_Pseudo);
729:   return(0);
730: }

734: /*@C
735:    TSPseudoTimeStepDefault - Default code to compute pseudo-timestepping.
736:    Use with TSPseudoSetTimeStep().

738:    Collective on TS

740:    Input Parameters:
741: .  ts - the timestep context
742: .  dtctx - unused timestep context

744:    Output Parameter:
745: .  newdt - the timestep to use for the next step

747:    Level: advanced

749: .keywords: timestep, pseudo, default

751: .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep()
752: @*/
753: PetscErrorCode  TSPseudoTimeStepDefault(TS ts,PetscReal *newdt,void *dtctx)
754: {
755:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
756:   PetscReal      inc = pseudo->dt_increment;

760:   VecZeroEntries(pseudo->xdot);
761:   TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);
762:   VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);
763:   if (pseudo->fnorm_initial < 0) {
764:     /* first time through so compute initial function norm */
765:     pseudo->fnorm_initial  = pseudo->fnorm;
766:     pseudo->fnorm_previous = pseudo->fnorm;
767:   }
768:   if (pseudo->fnorm == 0.0)                      *newdt = 1.e12*inc*ts->time_step;
769:   else if (pseudo->increment_dt_from_initial_dt) *newdt = inc*pseudo->dt_initial*pseudo->fnorm_initial/pseudo->fnorm;
770:   else                                           *newdt = inc*ts->time_step*pseudo->fnorm_previous/pseudo->fnorm;
771:   if (pseudo->dt_max > 0) *newdt = PetscMin(*newdt,pseudo->dt_max);
772:   pseudo->fnorm_previous = pseudo->fnorm;
773:   return(0);
774: }