Actual source code: posindep.c

  1: /*
  2:        Code for Timestepping with implicit backwards Euler.
  3: */
  4: #include <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:   PetscBool  increment_dt_from_initial_dt;
 24: } TS_Pseudo;

 26: /* ------------------------------------------------------------------------------*/

 30: /*@
 31:     TSPseudoComputeTimeStep - Computes the next timestep for a currently running
 32:     pseudo-timestepping process.

 34:     Collective on TS

 36:     Input Parameter:
 37: .   ts - timestep context

 39:     Output Parameter:
 40: .   dt - newly computed timestep

 42:     Level: advanced

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

 48: .keywords: timestep, pseudo, compute

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

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


 65: /* ------------------------------------------------------------------------------*/
 68: /*@C
 69:    TSPseudoDefaultVerifyTimeStep - Default code to verify the quality of the last timestep.

 71:    Collective on TS

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

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

 82:    Level: advanced

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

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

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


102: /*@
103:     TSPseudoVerifyTimeStep - Verifies whether the last timestep was acceptable.

105:     Collective on TS

107:     Input Parameters:
108: +   ts - timestep context
109: -   update - latest solution vector

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

115:     Level: advanced

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

121: .keywords: timestep, pseudo, verify

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

131:   if (!pseudo->verify) {*flag = PETSC_TRUE; return(0);}

133:   (*pseudo->verify)(ts,update,pseudo->verifyctx,dt,flag);

135:   return(0);
136: }

138: /* --------------------------------------------------------------------------------*/

142: static PetscErrorCode TSStep_Pseudo(TS ts)
143: {
144:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
145:   PetscInt       its,lits,reject;
146:   PetscBool      stepok;
147:   PetscReal      next_time_step;
148:   SNESConvergedReason snesreason = SNES_CONVERGED_ITERATING;

152:   if (ts->steps == 0) {
153:     pseudo->dt_initial = ts->time_step;
154:   }
155:   VecCopy(ts->vec_sol,pseudo->update);
156:   next_time_step = ts->time_step;
157:   TSPseudoComputeTimeStep(ts,&next_time_step);
158:   for (reject=0; reject<ts->max_reject; reject++,ts->reject++) {
159:     ts->time_step = next_time_step;
160:     SNESSolve(ts->snes,PETSC_NULL,pseudo->update);
161:     SNESGetConvergedReason(ts->snes,&snesreason);
162:     SNESGetLinearSolveIterations(ts->snes,&lits);
163:     SNESGetIterationNumber(ts->snes,&its);
164:     ts->nonlinear_its += its; ts->linear_its += lits;
165:     PetscInfo3(ts,"step=%D, nonlinear solve iterations=%D, linear solve iterations=%D\n",ts->steps,its,lits);
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 (snesreason < 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
171:     ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
172:     PetscInfo2(ts,"step=%D, nonlinear solve solve failures %D greater than current TS allowed, stopping solve\n",ts->steps,ts->num_snes_failures);
173:     return(0);
174:   }
175:   if (reject >= ts->max_reject) {
176:     ts->reason = TS_DIVERGED_STEP_REJECTED;
177:     PetscInfo2(ts,"step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,reject);
178:     return(0);
179:   }
180:   VecCopy(pseudo->update,ts->vec_sol);
181:   ts->ptime += ts->time_step;
182:   ts->time_step = next_time_step;
183:   ts->steps++;
184:   return(0);
185: }

187: /*------------------------------------------------------------*/
190: static PetscErrorCode TSReset_Pseudo(TS ts)
191: {
192:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;

196:   VecDestroy(&pseudo->update);
197:   VecDestroy(&pseudo->func);
198:   VecDestroy(&pseudo->xdot);
199:   return(0);
200: }

204: static PetscErrorCode TSDestroy_Pseudo(TS ts)
205: {

209:   TSReset_Pseudo(ts);
210:   PetscFree(ts->data);
211:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C","",PETSC_NULL);
212:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C","",PETSC_NULL);
213:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C","",PETSC_NULL);
214:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C","",PETSC_NULL);
215:   return(0);
216: }

218: /*------------------------------------------------------------*/

222: /*
223:     Compute Xdot = (X^{n+1}-X^n)/dt) = 0
224: */
225: static PetscErrorCode TSPseudoGetXdot(TS ts,Vec X,Vec *Xdot)
226: {
227:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
228:   const PetscScalar mdt = 1.0/ts->time_step,*xnp1,*xn;
229:   PetscScalar    *xdot;
231:   PetscInt       i,n;

234:   VecGetArrayRead(ts->vec_sol,&xn);
235:   VecGetArrayRead(X,&xnp1);
236:   VecGetArray(pseudo->xdot,&xdot);
237:   VecGetLocalSize(X,&n);
238:   for (i=0; i<n; i++) {
239:     xdot[i] = mdt*(xnp1[i] - xn[i]);
240:   }
241:   VecRestoreArrayRead(ts->vec_sol,&xn);
242:   VecRestoreArrayRead(X,&xnp1);
243:   VecRestoreArray(pseudo->xdot,&xdot);
244:   *Xdot = pseudo->xdot;
245:   return(0);
246: }

250: /*
251:     The transient residual is

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

255:     or for ODE,

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

259:     This is the function that must be evaluated for transient simulation and for
260:     finite difference Jacobians.  On the first Newton step, this algorithm uses
261:     a guess of U^{n+1} = U^n in which case the transient term vanishes and the
262:     residual is actually the steady state residual.  Pseudotransient
263:     continuation as described in the literature is a linearly implicit
264:     algorithm, it only takes this one Newton step with the steady state
265:     residual, and then advances to the next time step.
266: */
267: static PetscErrorCode SNESTSFormFunction_Pseudo(SNES snes,Vec X,Vec Y,TS ts)
268: {
269:   Vec            Xdot;

273:   TSPseudoGetXdot(ts,X,&Xdot);
274:   TSComputeIFunction(ts,ts->ptime+ts->time_step,X,Xdot,Y,PETSC_FALSE);
275:   return(0);
276: }

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

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

285:     and for ODE:

287:        J = I/dt - J_{Frhs}   where J_{Frhs} is the given Jacobian of Frhs.
288: */
289: static PetscErrorCode SNESTSFormJacobian_Pseudo(SNES snes,Vec X,Mat *AA,Mat *BB,MatStructure *str,TS ts)
290: {
291:   Vec            Xdot;

295:   TSPseudoGetXdot(ts,X,&Xdot);
296:   TSComputeIJacobian(ts,ts->ptime+ts->time_step,X,Xdot,1./ts->time_step,AA,BB,str,PETSC_FALSE);
297:   return(0);
298: }


303: static PetscErrorCode TSSetUp_Pseudo(TS ts)
304: {
305:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;

309:   VecDuplicate(ts->vec_sol,&pseudo->update);
310:   VecDuplicate(ts->vec_sol,&pseudo->func);
311:   VecDuplicate(ts->vec_sol,&pseudo->xdot);
312:   return(0);
313: }
314: /*------------------------------------------------------------*/

318: PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *dummy)
319: {
320:   TS_Pseudo        *pseudo = (TS_Pseudo*)ts->data;
321:   PetscErrorCode   ierr;
322:   PetscViewer      viewer = dummy ? (PetscViewer) dummy : PETSC_VIEWER_STDOUT_(((PetscObject)ts)->comm);

325:   if (pseudo->fnorm < 0) {      /* The last computed norm is stale, recompute */
326:     VecZeroEntries(pseudo->xdot);
327:     TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);
328:     VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);
329:   }
330:   PetscViewerASCIIAddTab(viewer,((PetscObject)ts)->tablevel);
331:   PetscViewerASCIIPrintf(viewer,"TS %D dt %G time %G fnorm %G\n",step,ts->time_step,ptime,pseudo->fnorm);
332:   PetscViewerASCIISubtractTab(viewer,((PetscObject)ts)->tablevel);
333:   return(0);
334: }

338: static PetscErrorCode TSSetFromOptions_Pseudo(TS ts)
339: {
340:   TS_Pseudo       *pseudo = (TS_Pseudo*)ts->data;
341:   PetscErrorCode  ierr;
342:   PetscBool       flg = PETSC_FALSE;
343:   PetscViewer     viewer;

346:   PetscOptionsHead("Pseudo-timestepping options");
347:     PetscOptionsBool("-ts_monitor_pseudo","Monitor convergence","TSPseudoMonitorDefault",flg,&flg,PETSC_NULL);
348:     if (flg) {
349:       PetscViewerASCIIOpen(((PetscObject)ts)->comm,"stdout",&viewer);
350:       TSMonitorSet(ts,TSPseudoMonitorDefault,viewer,(PetscErrorCode (*)(void**))PetscViewerDestroy);
351:     }
352:     flg  = PETSC_FALSE;
353:     PetscOptionsBool("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",flg,&flg,PETSC_NULL);
354:     if (flg) {
355:       TSPseudoIncrementDtFromInitialDt(ts);
356:     }
357:     PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,0);

359:     SNESSetFromOptions(ts->snes);
360:   PetscOptionsTail();
361:   return(0);
362: }

366: static PetscErrorCode TSView_Pseudo(TS ts,PetscViewer viewer)
367: {

371:   SNESView(ts->snes,viewer);
372:   return(0);
373: }

375: /* ----------------------------------------------------------------------------- */
378: /*@C
379:    TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the
380:    last timestep.

382:    Logically Collective on TS

384:    Input Parameters:
385: +  ts - timestep context
386: .  dt - user-defined function to verify timestep
387: -  ctx - [optional] user-defined context for private data
388:          for the timestep verification routine (may be PETSC_NULL)

390:    Level: advanced

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

395: .  update - latest solution vector
396: .  ctx - [optional] timestep context
397: .  newdt - the timestep to use for the next step
398: .  flag - flag indicating whether the last time step was acceptable

400:    Notes:
401:    The routine set here will be called by TSPseudoVerifyTimeStep()
402:    during the timestepping process.

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

406: .seealso: TSPseudoDefaultVerifyTimeStep(), TSPseudoVerifyTimeStep()
407: @*/
408: PetscErrorCode  TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (*dt)(TS,Vec,void*,PetscReal*,PetscBool *),void* ctx)
409: {

414:   PetscTryMethod(ts,"TSPseudoSetVerifyTimeStep_C",(TS,PetscErrorCode (*)(TS,Vec,void*,PetscReal *,PetscBool  *),void *),(ts,dt,ctx));
415:   return(0);
416: }

420: /*@
421:     TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to
422:     dt when using the TSPseudoDefaultTimeStep() routine.

424:    Logically Collective on TS

426:     Input Parameters:
427: +   ts - the timestep context
428: -   inc - the scaling factor >= 1.0

430:     Options Database Key:
431: $    -ts_pseudo_increment <increment>

433:     Level: advanced

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

437: .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
438: @*/
439: PetscErrorCode  TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc)
440: {

446:   PetscTryMethod(ts,"TSPseudoSetTimeStepIncrement_C",(TS,PetscReal),(ts,inc));
447:   return(0);
448: }

452: /*@
453:     TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep
454:     is computed via the formula
455: $         dt = initial_dt*initial_fnorm/current_fnorm
456:       rather than the default update,
457: $         dt = current_dt*previous_fnorm/current_fnorm.

459:    Logically Collective on TS

461:     Input Parameter:
462: .   ts - the timestep context

464:     Options Database Key:
465: $    -ts_pseudo_increment_dt_from_initial_dt

467:     Level: advanced

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

471: .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
472: @*/
473: PetscErrorCode  TSPseudoIncrementDtFromInitialDt(TS ts)
474: {

479:   PetscTryMethod(ts,"TSPseudoIncrementDtFromInitialDt_C",(TS),(ts));
480:   return(0);
481: }


486: /*@C
487:    TSPseudoSetTimeStep - Sets the user-defined routine to be
488:    called at each pseudo-timestep to update the timestep.

490:    Logically Collective on TS

492:    Input Parameters:
493: +  ts - timestep context
494: .  dt - function to compute timestep
495: -  ctx - [optional] user-defined context for private data
496:          required by the function (may be PETSC_NULL)

498:    Level: intermediate

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

503: .  newdt - the newly computed timestep
504: .  ctx - [optional] timestep context

506:    Notes:
507:    The routine set here will be called by TSPseudoComputeTimeStep()
508:    during the timestepping process.

510: .keywords: timestep, pseudo, set

512: .seealso: TSPseudoDefaultTimeStep(), TSPseudoComputeTimeStep()
513: @*/
514: PetscErrorCode  TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void* ctx)
515: {

520:   PetscTryMethod(ts,"TSPseudoSetTimeStep_C",(TS,PetscErrorCode (*)(TS,PetscReal *,void *),void *),(ts,dt,ctx));
521:   return(0);
522: }

524: /* ----------------------------------------------------------------------------- */

530: PetscErrorCode  TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void* ctx)
531: {
532:   TS_Pseudo *pseudo;

535:   pseudo              = (TS_Pseudo*)ts->data;
536:   pseudo->verify      = dt;
537:   pseudo->verifyctx   = ctx;
538:   return(0);
539: }

545: PetscErrorCode  TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc)
546: {
547:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

550:   pseudo->dt_increment = inc;
551:   return(0);
552: }

558: PetscErrorCode  TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
559: {
560:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

563:   pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
564:   return(0);
565: }

572: PetscErrorCode  TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void* ctx)
573: {
574:   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;

577:   pseudo->dt      = dt;
578:   pseudo->dtctx   = ctx;
579:   return(0);
580: }

583: /* ----------------------------------------------------------------------------- */
584: /*MC
585:       TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping

587:   This method solves equations of the form

589: $    F(X,Xdot) = 0

591:   for steady state using the iteration

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

596:   where

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

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

603:   Options database keys:
604: +  -ts_pseudo_increment <real> - ratio of increase dt
605: -  -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt

607:   Level: beginner

609:   References:
610:   Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003.
611:   C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998.

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

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

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

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

626: M*/
630: PetscErrorCode  TSCreate_Pseudo(TS ts)
631: {
632:   TS_Pseudo      *pseudo;
634:   SNES           snes;
635:   const SNESType stype;

638:   ts->ops->reset           = TSReset_Pseudo;
639:   ts->ops->destroy         = TSDestroy_Pseudo;
640:   ts->ops->view            = TSView_Pseudo;

642:   ts->ops->setup           = TSSetUp_Pseudo;
643:   ts->ops->step            = TSStep_Pseudo;
644:   ts->ops->setfromoptions  = TSSetFromOptions_Pseudo;
645:   ts->ops->snesfunction    = SNESTSFormFunction_Pseudo;
646:   ts->ops->snesjacobian    = SNESTSFormJacobian_Pseudo;

648:   TSGetSNES(ts,&snes);
649:   SNESGetType(snes,&stype);
650:   if (!stype) {SNESSetType(snes,SNESKSPONLY);}

652:   PetscNewLog(ts,TS_Pseudo,&pseudo);
653:   ts->data = (void*)pseudo;

655:   pseudo->dt_increment                 = 1.1;
656:   pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
657:   pseudo->dt                           = TSPseudoDefaultTimeStep;
658:   pseudo->fnorm                        = -1;

660:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",
661:                     "TSPseudoSetVerifyTimeStep_Pseudo",
662:                      TSPseudoSetVerifyTimeStep_Pseudo);
663:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",
664:                     "TSPseudoSetTimeStepIncrement_Pseudo",
665:                      TSPseudoSetTimeStepIncrement_Pseudo);
666:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",
667:                     "TSPseudoIncrementDtFromInitialDt_Pseudo",
668:                      TSPseudoIncrementDtFromInitialDt_Pseudo);
669:   PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C",
670:                     "TSPseudoSetTimeStep_Pseudo",
671:                      TSPseudoSetTimeStep_Pseudo);
672:   return(0);
673: }

678: /*@C
679:    TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping.
680:    Use with TSPseudoSetTimeStep().

682:    Collective on TS

684:    Input Parameters:
685: .  ts - the timestep context
686: .  dtctx - unused timestep context

688:    Output Parameter:
689: .  newdt - the timestep to use for the next step

691:    Level: advanced

693: .keywords: timestep, pseudo, default

695: .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep()
696: @*/
697: PetscErrorCode  TSPseudoDefaultTimeStep(TS ts,PetscReal* newdt,void* dtctx)
698: {
699:   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
700:   PetscReal      inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous;

704:   VecZeroEntries(pseudo->xdot);
705:   TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);
706:   VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);
707:   if (pseudo->fnorm_initial == 0.0) {
708:     /* first time through so compute initial function norm */
709:     pseudo->fnorm_initial = pseudo->fnorm;
710:     fnorm_previous        = pseudo->fnorm;
711:   }
712:   if (pseudo->fnorm == 0.0) {
713:     *newdt = 1.e12*inc*ts->time_step;
714:   } else if (pseudo->increment_dt_from_initial_dt) {
715:     *newdt = inc*pseudo->dt_initial*pseudo->fnorm_initial/pseudo->fnorm;
716:   } else {
717:     *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm;
718:   }
719:   pseudo->fnorm_previous = pseudo->fnorm;
720:   return(0);
721: }