xref: /petsc/src/ts/impls/pseudo/posindep.c (revision bebe2cf65d55febe21a5af8db2bd2e168caaa2e7)
1 /*
2        Code for Timestepping with implicit backwards Euler.
3 */
4 #include <petsc/private/tsimpl.h>                /*I   "petscts.h"   I*/
5 
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 */
10 
11   /* information used for Pseudo-timestepping */
12 
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;
17 
18   PetscReal fnorm_initial,fnorm;                   /* original and current norm of F(u) */
19   PetscReal fnorm_previous;
20 
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 } TS_Pseudo;
26 
27 /* ------------------------------------------------------------------------------*/
28 
29 #undef __FUNCT__
30 #define __FUNCT__ "TSPseudoComputeTimeStep"
31 /*@C
32     TSPseudoComputeTimeStep - Computes the next timestep for a currently running
33     pseudo-timestepping process.
34 
35     Collective on TS
36 
37     Input Parameter:
38 .   ts - timestep context
39 
40     Output Parameter:
41 .   dt - newly computed timestep
42 
43     Level: developer
44 
45     Notes:
46     The routine to be called here to compute the timestep should be
47     set by calling TSPseudoSetTimeStep().
48 
49 .keywords: timestep, pseudo, compute
50 
51 .seealso: TSPseudoTimeStepDefault(), TSPseudoSetTimeStep()
52 @*/
53 PetscErrorCode  TSPseudoComputeTimeStep(TS ts,PetscReal *dt)
54 {
55   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
56   PetscErrorCode ierr;
57 
58   PetscFunctionBegin;
59   ierr = PetscLogEventBegin(TS_PseudoComputeTimeStep,ts,0,0,0);CHKERRQ(ierr);
60   ierr = (*pseudo->dt)(ts,dt,pseudo->dtctx);CHKERRQ(ierr);
61   ierr = PetscLogEventEnd(TS_PseudoComputeTimeStep,ts,0,0,0);CHKERRQ(ierr);
62   PetscFunctionReturn(0);
63 }
64 
65 
66 /* ------------------------------------------------------------------------------*/
67 #undef __FUNCT__
68 #define __FUNCT__ "TSPseudoVerifyTimeStepDefault"
69 /*@C
70    TSPseudoVerifyTimeStepDefault - Default code to verify the quality of the last timestep.
71 
72    Collective on TS
73 
74    Input Parameters:
75 +  ts - the timestep context
76 .  dtctx - unused timestep context
77 -  update - latest solution vector
78 
79    Output Parameters:
80 +  newdt - the timestep to use for the next step
81 -  flag - flag indicating whether the last time step was acceptable
82 
83    Level: advanced
84 
85    Note:
86    This routine always returns a flag of 1, indicating an acceptable
87    timestep.
88 
89 .keywords: timestep, pseudo, default, verify
90 
91 .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoVerifyTimeStep()
92 @*/
93 PetscErrorCode  TSPseudoVerifyTimeStepDefault(TS ts,Vec update,void *dtctx,PetscReal *newdt,PetscBool  *flag)
94 {
95   PetscFunctionBegin;
96   *flag = PETSC_TRUE;
97   PetscFunctionReturn(0);
98 }
99 
100 
101 #undef __FUNCT__
102 #define __FUNCT__ "TSPseudoVerifyTimeStep"
103 /*@
104     TSPseudoVerifyTimeStep - Verifies whether the last timestep was acceptable.
105 
106     Collective on TS
107 
108     Input Parameters:
109 +   ts - timestep context
110 -   update - latest solution vector
111 
112     Output Parameters:
113 +   dt - newly computed timestep (if it had to shrink)
114 -   flag - indicates if current timestep was ok
115 
116     Level: advanced
117 
118     Notes:
119     The routine to be called here to compute the timestep should be
120     set by calling TSPseudoSetVerifyTimeStep().
121 
122 .keywords: timestep, pseudo, verify
123 
124 .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoVerifyTimeStepDefault()
125 @*/
126 PetscErrorCode  TSPseudoVerifyTimeStep(TS ts,Vec update,PetscReal *dt,PetscBool  *flag)
127 {
128   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
129   PetscErrorCode ierr;
130 
131   PetscFunctionBegin;
132   if (!pseudo->verify) {*flag = PETSC_TRUE; PetscFunctionReturn(0);}
133 
134   ierr = (*pseudo->verify)(ts,update,pseudo->verifyctx,dt,flag);CHKERRQ(ierr);
135   PetscFunctionReturn(0);
136 }
137 
138 /* --------------------------------------------------------------------------------*/
139 
140 #undef __FUNCT__
141 #define __FUNCT__ "TSStep_Pseudo"
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;
149   PetscErrorCode      ierr;
150 
151   PetscFunctionBegin;
152   if (ts->steps == 0) pseudo->dt_initial = ts->time_step;
153   ierr = VecCopy(ts->vec_sol,pseudo->update);CHKERRQ(ierr);
154   next_time_step = ts->time_step;
155   ierr = TSPseudoComputeTimeStep(ts,&next_time_step);CHKERRQ(ierr);
156   for (reject=0; reject<ts->max_reject; reject++,ts->reject++) {
157     ts->time_step = next_time_step;
158     ierr = TSPreStep(ts);CHKERRQ(ierr);
159     ierr = TSPreStage(ts,ts->ptime+ts->time_step);CHKERRQ(ierr);
160     ierr = SNESSolve(ts->snes,NULL,pseudo->update);CHKERRQ(ierr);
161     ierr = SNESGetConvergedReason(ts->snes,&snesreason);CHKERRQ(ierr);
162     ierr = SNESGetLinearSolveIterations(ts->snes,&lits);CHKERRQ(ierr);
163     ierr = SNESGetIterationNumber(ts->snes,&its);CHKERRQ(ierr);
164     ierr = TSPostStage(ts,ts->ptime+ts->time_step,0,&(pseudo->update));CHKERRQ(ierr);
165     ts->snes_its += its; ts->ksp_its += lits;
166     ierr = PetscInfo3(ts,"step=%D, nonlinear solve iterations=%D, linear solve iterations=%D\n",ts->steps,its,lits);CHKERRQ(ierr);
167     pseudo->fnorm = -1;         /* The current norm is no longer valid, monitor must recompute it. */
168     ierr = TSPseudoVerifyTimeStep(ts,pseudo->update,&next_time_step,&stepok);CHKERRQ(ierr);
169     if (stepok) break;
170   }
171   if (snesreason < 0 && ts->max_snes_failures > 0 && ++ts->num_snes_failures >= ts->max_snes_failures) {
172     ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
173     ierr = PetscInfo2(ts,"step=%D, nonlinear solve solve failures %D greater than current TS allowed, stopping solve\n",ts->steps,ts->num_snes_failures);CHKERRQ(ierr);
174     PetscFunctionReturn(0);
175   }
176   if (reject >= ts->max_reject) {
177     ts->reason = TS_DIVERGED_STEP_REJECTED;
178     ierr = PetscInfo2(ts,"step=%D, step rejections %D greater than current TS allowed, stopping solve\n",ts->steps,reject);CHKERRQ(ierr);
179     PetscFunctionReturn(0);
180   }
181   ierr = VecCopy(pseudo->update,ts->vec_sol);CHKERRQ(ierr);
182   ts->ptime += ts->time_step;
183   ts->time_step = next_time_step;
184   ts->steps++;
185   PetscFunctionReturn(0);
186 }
187 
188 /*------------------------------------------------------------*/
189 #undef __FUNCT__
190 #define __FUNCT__ "TSReset_Pseudo"
191 static PetscErrorCode TSReset_Pseudo(TS ts)
192 {
193   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
194   PetscErrorCode ierr;
195 
196   PetscFunctionBegin;
197   ierr = VecDestroy(&pseudo->update);CHKERRQ(ierr);
198   ierr = VecDestroy(&pseudo->func);CHKERRQ(ierr);
199   ierr = VecDestroy(&pseudo->xdot);CHKERRQ(ierr);
200   PetscFunctionReturn(0);
201 }
202 
203 #undef __FUNCT__
204 #define __FUNCT__ "TSDestroy_Pseudo"
205 static PetscErrorCode TSDestroy_Pseudo(TS ts)
206 {
207   PetscErrorCode ierr;
208 
209   PetscFunctionBegin;
210   ierr = TSReset_Pseudo(ts);CHKERRQ(ierr);
211   ierr = PetscFree(ts->data);CHKERRQ(ierr);
212   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",NULL);CHKERRQ(ierr);
213   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",NULL);CHKERRQ(ierr);
214   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetMaxTimeStep_C",NULL);CHKERRQ(ierr);
215   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",NULL);CHKERRQ(ierr);
216   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStep_C",NULL);CHKERRQ(ierr);
217   PetscFunctionReturn(0);
218 }
219 
220 /*------------------------------------------------------------*/
221 
222 #undef __FUNCT__
223 #define __FUNCT__ "TSPseudoGetXdot"
224 /*
225     Compute Xdot = (X^{n+1}-X^n)/dt) = 0
226 */
227 static PetscErrorCode TSPseudoGetXdot(TS ts,Vec X,Vec *Xdot)
228 {
229   TS_Pseudo         *pseudo = (TS_Pseudo*)ts->data;
230   const PetscScalar mdt     = 1.0/ts->time_step,*xnp1,*xn;
231   PetscScalar       *xdot;
232   PetscErrorCode    ierr;
233   PetscInt          i,n;
234 
235   PetscFunctionBegin;
236   ierr = VecGetArrayRead(ts->vec_sol,&xn);CHKERRQ(ierr);
237   ierr = VecGetArrayRead(X,&xnp1);CHKERRQ(ierr);
238   ierr = VecGetArray(pseudo->xdot,&xdot);CHKERRQ(ierr);
239   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
240   for (i=0; i<n; i++) xdot[i] = mdt*(xnp1[i] - xn[i]);
241   ierr = VecRestoreArrayRead(ts->vec_sol,&xn);CHKERRQ(ierr);
242   ierr = VecRestoreArrayRead(X,&xnp1);CHKERRQ(ierr);
243   ierr = VecRestoreArray(pseudo->xdot,&xdot);CHKERRQ(ierr);
244   *Xdot = pseudo->xdot;
245   PetscFunctionReturn(0);
246 }
247 
248 #undef __FUNCT__
249 #define __FUNCT__ "SNESTSFormFunction_Pseudo"
250 /*
251     The transient residual is
252 
253         F(U^{n+1},(U^{n+1}-U^n)/dt) = 0
254 
255     or for ODE,
256 
257         (U^{n+1} - U^{n})/dt - F(U^{n+1}) = 0
258 
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;
270   PetscErrorCode ierr;
271 
272   PetscFunctionBegin;
273   ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr);
274   ierr = TSComputeIFunction(ts,ts->ptime+ts->time_step,X,Xdot,Y,PETSC_FALSE);CHKERRQ(ierr);
275   PetscFunctionReturn(0);
276 }
277 
278 #undef __FUNCT__
279 #define __FUNCT__ "SNESTSFormJacobian_Pseudo"
280 /*
281    This constructs the Jacobian needed for SNES.  For DAE, this is
282 
283        dF(X,Xdot)/dX + shift*dF(X,Xdot)/dXdot
284 
285     and for ODE:
286 
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,TS ts)
290 {
291   Vec            Xdot;
292   PetscErrorCode ierr;
293 
294   PetscFunctionBegin;
295   ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr);
296   ierr = TSComputeIJacobian(ts,ts->ptime+ts->time_step,X,Xdot,1./ts->time_step,AA,BB,PETSC_FALSE);CHKERRQ(ierr);
297   PetscFunctionReturn(0);
298 }
299 
300 
301 #undef __FUNCT__
302 #define __FUNCT__ "TSSetUp_Pseudo"
303 static PetscErrorCode TSSetUp_Pseudo(TS ts)
304 {
305   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
306   PetscErrorCode ierr;
307 
308   PetscFunctionBegin;
309   ierr = VecDuplicate(ts->vec_sol,&pseudo->update);CHKERRQ(ierr);
310   ierr = VecDuplicate(ts->vec_sol,&pseudo->func);CHKERRQ(ierr);
311   ierr = VecDuplicate(ts->vec_sol,&pseudo->xdot);CHKERRQ(ierr);
312   PetscFunctionReturn(0);
313 }
314 /*------------------------------------------------------------*/
315 
316 #undef __FUNCT__
317 #define __FUNCT__ "TSPseudoMonitorDefault"
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 = (PetscViewer) dummy;
323 
324   PetscFunctionBegin;
325   if (!viewer) {
326     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)ts),&viewer);CHKERRQ(ierr);
327   }
328   if (pseudo->fnorm < 0) {      /* The last computed norm is stale, recompute */
329     ierr = VecZeroEntries(pseudo->xdot);CHKERRQ(ierr);
330     ierr = TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);CHKERRQ(ierr);
331     ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr);
332   }
333   ierr = PetscViewerASCIIAddTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr);
334   ierr = PetscViewerASCIIPrintf(viewer,"TS %D dt %g time %g fnorm %g\n",step,(double)ts->time_step,(double)ptime,(double)pseudo->fnorm);CHKERRQ(ierr);
335   ierr = PetscViewerASCIISubtractTab(viewer,((PetscObject)ts)->tablevel);CHKERRQ(ierr);
336   PetscFunctionReturn(0);
337 }
338 
339 #undef __FUNCT__
340 #define __FUNCT__ "TSSetFromOptions_Pseudo"
341 static PetscErrorCode TSSetFromOptions_Pseudo(PetscOptions *PetscOptionsObject,TS ts)
342 {
343   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
344   PetscErrorCode ierr;
345   PetscBool      flg = PETSC_FALSE;
346   PetscViewer    viewer;
347 
348   PetscFunctionBegin;
349   ierr = PetscOptionsHead(PetscOptionsObject,"Pseudo-timestepping options");CHKERRQ(ierr);
350   ierr = PetscOptionsBool("-ts_monitor_pseudo","Monitor convergence","TSPseudoMonitorDefault",flg,&flg,NULL);CHKERRQ(ierr);
351   if (flg) {
352     ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)ts),"stdout",&viewer);CHKERRQ(ierr);
353     ierr = TSMonitorSet(ts,TSPseudoMonitorDefault,viewer,(PetscErrorCode (*)(void**))PetscViewerDestroy);CHKERRQ(ierr);
354   }
355   flg  = PETSC_FALSE;
356   ierr = PetscOptionsBool("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",flg,&flg,NULL);CHKERRQ(ierr);
357   if (flg) {
358     ierr = TSPseudoIncrementDtFromInitialDt(ts);CHKERRQ(ierr);
359   }
360   ierr = PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,NULL);CHKERRQ(ierr);
361   ierr = PetscOptionsReal("-ts_pseudo_max_dt","Maximum value for dt","TSPseudoSetMaxTimeStep",pseudo->dt_max,&pseudo->dt_max,NULL);CHKERRQ(ierr);
362 
363   ierr = SNESSetFromOptions(ts->snes);CHKERRQ(ierr);
364   ierr = PetscOptionsTail();CHKERRQ(ierr);
365   PetscFunctionReturn(0);
366 }
367 
368 #undef __FUNCT__
369 #define __FUNCT__ "TSView_Pseudo"
370 static PetscErrorCode TSView_Pseudo(TS ts,PetscViewer viewer)
371 {
372   PetscErrorCode ierr;
373 
374   PetscFunctionBegin;
375   ierr = SNESView(ts->snes,viewer);CHKERRQ(ierr);
376   PetscFunctionReturn(0);
377 }
378 
379 /* ----------------------------------------------------------------------------- */
380 #undef __FUNCT__
381 #define __FUNCT__ "TSPseudoSetVerifyTimeStep"
382 /*@C
383    TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the
384    last timestep.
385 
386    Logically Collective on TS
387 
388    Input Parameters:
389 +  ts - timestep context
390 .  dt - user-defined function to verify timestep
391 -  ctx - [optional] user-defined context for private data
392          for the timestep verification routine (may be NULL)
393 
394    Level: advanced
395 
396    Calling sequence of func:
397 .  func (TS ts,Vec update,void *ctx,PetscReal *newdt,PetscBool  *flag);
398 
399 .  update - latest solution vector
400 .  ctx - [optional] timestep context
401 .  newdt - the timestep to use for the next step
402 .  flag - flag indicating whether the last time step was acceptable
403 
404    Notes:
405    The routine set here will be called by TSPseudoVerifyTimeStep()
406    during the timestepping process.
407 
408 .keywords: timestep, pseudo, set, verify
409 
410 .seealso: TSPseudoVerifyTimeStepDefault(), TSPseudoVerifyTimeStep()
411 @*/
412 PetscErrorCode  TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (*dt)(TS,Vec,void*,PetscReal*,PetscBool*),void *ctx)
413 {
414   PetscErrorCode ierr;
415 
416   PetscFunctionBegin;
417   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
418   ierr = PetscTryMethod(ts,"TSPseudoSetVerifyTimeStep_C",(TS,PetscErrorCode (*)(TS,Vec,void*,PetscReal*,PetscBool*),void*),(ts,dt,ctx));CHKERRQ(ierr);
419   PetscFunctionReturn(0);
420 }
421 
422 #undef __FUNCT__
423 #define __FUNCT__ "TSPseudoSetTimeStepIncrement"
424 /*@
425     TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to
426     dt when using the TSPseudoTimeStepDefault() routine.
427 
428    Logically Collective on TS
429 
430     Input Parameters:
431 +   ts - the timestep context
432 -   inc - the scaling factor >= 1.0
433 
434     Options Database Key:
435 .    -ts_pseudo_increment <increment>
436 
437     Level: advanced
438 
439 .keywords: timestep, pseudo, set, increment
440 
441 .seealso: TSPseudoSetTimeStep(), TSPseudoTimeStepDefault()
442 @*/
443 PetscErrorCode  TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc)
444 {
445   PetscErrorCode ierr;
446 
447   PetscFunctionBegin;
448   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
449   PetscValidLogicalCollectiveReal(ts,inc,2);
450   ierr = PetscTryMethod(ts,"TSPseudoSetTimeStepIncrement_C",(TS,PetscReal),(ts,inc));CHKERRQ(ierr);
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "TSPseudoSetMaxTimeStep"
456 /*@
457     TSPseudoSetMaxTimeStep - Sets the maximum time step
458     when using the TSPseudoTimeStepDefault() routine.
459 
460    Logically Collective on TS
461 
462     Input Parameters:
463 +   ts - the timestep context
464 -   maxdt - the maximum time step, use a non-positive value to deactivate
465 
466     Options Database Key:
467 .    -ts_pseudo_max_dt <increment>
468 
469     Level: advanced
470 
471 .keywords: timestep, pseudo, set
472 
473 .seealso: TSPseudoSetTimeStep(), TSPseudoTimeStepDefault()
474 @*/
475 PetscErrorCode  TSPseudoSetMaxTimeStep(TS ts,PetscReal maxdt)
476 {
477   PetscErrorCode ierr;
478 
479   PetscFunctionBegin;
480   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
481   PetscValidLogicalCollectiveReal(ts,maxdt,2);
482   ierr = PetscTryMethod(ts,"TSPseudoSetMaxTimeStep_C",(TS,PetscReal),(ts,maxdt));CHKERRQ(ierr);
483   PetscFunctionReturn(0);
484 }
485 
486 #undef __FUNCT__
487 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt"
488 /*@
489     TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep
490     is computed via the formula
491 $         dt = initial_dt*initial_fnorm/current_fnorm
492       rather than the default update,
493 $         dt = current_dt*previous_fnorm/current_fnorm.
494 
495    Logically Collective on TS
496 
497     Input Parameter:
498 .   ts - the timestep context
499 
500     Options Database Key:
501 .    -ts_pseudo_increment_dt_from_initial_dt
502 
503     Level: advanced
504 
505 .keywords: timestep, pseudo, set, increment
506 
507 .seealso: TSPseudoSetTimeStep(), TSPseudoTimeStepDefault()
508 @*/
509 PetscErrorCode  TSPseudoIncrementDtFromInitialDt(TS ts)
510 {
511   PetscErrorCode ierr;
512 
513   PetscFunctionBegin;
514   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
515   ierr = PetscTryMethod(ts,"TSPseudoIncrementDtFromInitialDt_C",(TS),(ts));CHKERRQ(ierr);
516   PetscFunctionReturn(0);
517 }
518 
519 
520 #undef __FUNCT__
521 #define __FUNCT__ "TSPseudoSetTimeStep"
522 /*@C
523    TSPseudoSetTimeStep - Sets the user-defined routine to be
524    called at each pseudo-timestep to update the timestep.
525 
526    Logically Collective on TS
527 
528    Input Parameters:
529 +  ts - timestep context
530 .  dt - function to compute timestep
531 -  ctx - [optional] user-defined context for private data
532          required by the function (may be NULL)
533 
534    Level: intermediate
535 
536    Calling sequence of func:
537 .  func (TS ts,PetscReal *newdt,void *ctx);
538 
539 .  newdt - the newly computed timestep
540 .  ctx - [optional] timestep context
541 
542    Notes:
543    The routine set here will be called by TSPseudoComputeTimeStep()
544    during the timestepping process.
545    If not set then TSPseudoTimeStepDefault() is automatically used
546 
547 .keywords: timestep, pseudo, set
548 
549 .seealso: TSPseudoTimeStepDefault(), TSPseudoComputeTimeStep()
550 @*/
551 PetscErrorCode  TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void *ctx)
552 {
553   PetscErrorCode ierr;
554 
555   PetscFunctionBegin;
556   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
557   ierr = PetscTryMethod(ts,"TSPseudoSetTimeStep_C",(TS,PetscErrorCode (*)(TS,PetscReal*,void*),void*),(ts,dt,ctx));CHKERRQ(ierr);
558   PetscFunctionReturn(0);
559 }
560 
561 /* ----------------------------------------------------------------------------- */
562 
563 typedef PetscErrorCode (*FCN1)(TS,Vec,void*,PetscReal*,PetscBool*);  /* force argument to next function to not be extern C*/
564 #undef __FUNCT__
565 #define __FUNCT__ "TSPseudoSetVerifyTimeStep_Pseudo"
566 PetscErrorCode  TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void *ctx)
567 {
568   TS_Pseudo *pseudo;
569 
570   PetscFunctionBegin;
571   pseudo            = (TS_Pseudo*)ts->data;
572   pseudo->verify    = dt;
573   pseudo->verifyctx = ctx;
574   PetscFunctionReturn(0);
575 }
576 
577 #undef __FUNCT__
578 #define __FUNCT__ "TSPseudoSetTimeStepIncrement_Pseudo"
579 PetscErrorCode  TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc)
580 {
581   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
582 
583   PetscFunctionBegin;
584   pseudo->dt_increment = inc;
585   PetscFunctionReturn(0);
586 }
587 
588 #undef __FUNCT__
589 #define __FUNCT__ "TSPseudoSetMaxTimeStep_Pseudo"
590 PetscErrorCode  TSPseudoSetMaxTimeStep_Pseudo(TS ts,PetscReal maxdt)
591 {
592   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
593 
594   PetscFunctionBegin;
595   pseudo->dt_max = maxdt;
596   PetscFunctionReturn(0);
597 }
598 
599 #undef __FUNCT__
600 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt_Pseudo"
601 PetscErrorCode  TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
602 {
603   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
604 
605   PetscFunctionBegin;
606   pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
607   PetscFunctionReturn(0);
608 }
609 
610 typedef PetscErrorCode (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/
611 #undef __FUNCT__
612 #define __FUNCT__ "TSPseudoSetTimeStep_Pseudo"
613 PetscErrorCode  TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void *ctx)
614 {
615   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
616 
617   PetscFunctionBegin;
618   pseudo->dt    = dt;
619   pseudo->dtctx = ctx;
620   PetscFunctionReturn(0);
621 }
622 
623 /* ----------------------------------------------------------------------------- */
624 /*MC
625       TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping
626 
627   This method solves equations of the form
628 
629 $    F(X,Xdot) = 0
630 
631   for steady state using the iteration
632 
633 $    [G'] S = -F(X,0)
634 $    X += S
635 
636   where
637 
638 $    G(Y) = F(Y,(Y-X)/dt)
639 
640   This is linearly-implicit Euler with the residual always evaluated "at steady
641   state".  See note below.
642 
643   Options database keys:
644 +  -ts_pseudo_increment <real> - ratio of increase dt
645 -  -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt
646 
647   Level: beginner
648 
649   References:
650   Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003.
651   C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998.
652 
653   Notes:
654   The residual computed by this method includes the transient term (Xdot is computed instead of
655   always being zero), but since the prediction from the last step is always the solution from the
656   last step, on the first Newton iteration we have
657 
658 $  Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0
659 
660   Therefore, the linear system solved by the first Newton iteration is equivalent to the one
661   described above and in the papers.  If the user chooses to perform multiple Newton iterations, the
662   algorithm is no longer the one described in the referenced papers.
663 
664 .seealso:  TSCreate(), TS, TSSetType()
665 
666 M*/
667 #undef __FUNCT__
668 #define __FUNCT__ "TSCreate_Pseudo"
669 PETSC_EXTERN PetscErrorCode TSCreate_Pseudo(TS ts)
670 {
671   TS_Pseudo      *pseudo;
672   PetscErrorCode ierr;
673   SNES           snes;
674   SNESType       stype;
675 
676   PetscFunctionBegin;
677   ts->ops->reset   = TSReset_Pseudo;
678   ts->ops->destroy = TSDestroy_Pseudo;
679   ts->ops->view    = TSView_Pseudo;
680 
681   ts->ops->setup          = TSSetUp_Pseudo;
682   ts->ops->step           = TSStep_Pseudo;
683   ts->ops->setfromoptions = TSSetFromOptions_Pseudo;
684   ts->ops->snesfunction   = SNESTSFormFunction_Pseudo;
685   ts->ops->snesjacobian   = SNESTSFormJacobian_Pseudo;
686 
687   ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr);
688   ierr = SNESGetType(snes,&stype);CHKERRQ(ierr);
689   if (!stype) {ierr = SNESSetType(snes,SNESKSPONLY);CHKERRQ(ierr);}
690 
691   ierr = PetscNewLog(ts,&pseudo);CHKERRQ(ierr);
692   ts->data = (void*)pseudo;
693 
694   pseudo->dt_increment                 = 1.1;
695   pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
696   pseudo->dt                           = TSPseudoTimeStepDefault;
697   pseudo->fnorm                        = -1;
698 
699   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",TSPseudoSetVerifyTimeStep_Pseudo);CHKERRQ(ierr);
700   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",TSPseudoSetTimeStepIncrement_Pseudo);CHKERRQ(ierr);
701   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetMaxTimeStep_C",TSPseudoSetMaxTimeStep_Pseudo);CHKERRQ(ierr);
702   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",TSPseudoIncrementDtFromInitialDt_Pseudo);CHKERRQ(ierr);
703   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSPseudoSetTimeStep_C",TSPseudoSetTimeStep_Pseudo);CHKERRQ(ierr);
704   PetscFunctionReturn(0);
705 }
706 
707 #undef __FUNCT__
708 #define __FUNCT__ "TSPseudoTimeStepDefault"
709 /*@C
710    TSPseudoTimeStepDefault - Default code to compute pseudo-timestepping.
711    Use with TSPseudoSetTimeStep().
712 
713    Collective on TS
714 
715    Input Parameters:
716 .  ts - the timestep context
717 .  dtctx - unused timestep context
718 
719    Output Parameter:
720 .  newdt - the timestep to use for the next step
721 
722    Level: advanced
723 
724 .keywords: timestep, pseudo, default
725 
726 .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep()
727 @*/
728 PetscErrorCode  TSPseudoTimeStepDefault(TS ts,PetscReal *newdt,void *dtctx)
729 {
730   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
731   PetscReal      inc     = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous;
732   PetscErrorCode ierr;
733 
734   PetscFunctionBegin;
735   ierr = VecZeroEntries(pseudo->xdot);CHKERRQ(ierr);
736   ierr = TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);CHKERRQ(ierr);
737   ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr);
738   if (pseudo->fnorm_initial == 0.0) {
739     /* first time through so compute initial function norm */
740     pseudo->fnorm_initial = pseudo->fnorm;
741     fnorm_previous        = pseudo->fnorm;
742   }
743   if (pseudo->fnorm == 0.0)                      *newdt = 1.e12*inc*ts->time_step;
744   else if (pseudo->increment_dt_from_initial_dt) *newdt = inc*pseudo->dt_initial*pseudo->fnorm_initial/pseudo->fnorm;
745   else                                           *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm;
746   if (pseudo->dt_max > 0) *newdt = PetscMin(*newdt,pseudo->dt_max);
747   pseudo->fnorm_previous = pseudo->fnorm;
748   PetscFunctionReturn(0);
749 }
750