xref: /petsc/src/ts/impls/pseudo/posindep.c (revision 1718446fabcbabc662c8c2ef82676d369dff910f)
1 #define PETSCTS_DLL
2 
3 /*
4        Code for Timestepping with implicit backwards Euler.
5 */
6 #include "private/tsimpl.h"                /*I   "petscts.h"   I*/
7 
8 typedef struct {
9   Vec  update;      /* work vector where new solution is formed */
10   Vec  func;        /* work vector where F(t[i],u[i]) is stored */
11   Vec  xdot;        /* work vector for time derivative of state */
12 
13   /* information used for Pseudo-timestepping */
14 
15   PetscErrorCode (*dt)(TS,PetscReal*,void*);              /* compute next timestep, and related context */
16   void           *dtctx;
17   PetscErrorCode (*verify)(TS,Vec,void*,PetscReal*,PetscTruth*); /* verify previous timestep and related context */
18   void           *verifyctx;
19 
20   PetscReal  initial_fnorm,fnorm;                  /* original and current norm of F(u) */
21   PetscReal  fnorm_previous;
22 
23   PetscReal  dt_increment;                  /* scaling that dt is incremented each time-step */
24   PetscTruth increment_dt_from_initial_dt;
25 } TS_Pseudo;
26 
27 /* ------------------------------------------------------------------------------*/
28 
29 #undef __FUNCT__
30 #define __FUNCT__ "TSPseudoComputeTimeStep"
31 /*@
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: advanced
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: TSPseudoDefaultTimeStep(), TSPseudoSetTimeStep()
52 @*/
53 PetscErrorCode PETSCTS_DLLEXPORT 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__ "TSPseudoDefaultVerifyTimeStep"
69 /*@C
70    TSPseudoDefaultVerifyTimeStep - 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 PETSCTS_DLLEXPORT TSPseudoDefaultVerifyTimeStep(TS ts,Vec update,void *dtctx,PetscReal *newdt,PetscTruth *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(), TSPseudoDefaultVerifyTimeStep()
125 @*/
126 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoVerifyTimeStep(TS ts,Vec update,PetscReal *dt,PetscTruth *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 
136   PetscFunctionReturn(0);
137 }
138 
139 /* --------------------------------------------------------------------------------*/
140 
141 #undef __FUNCT__
142 #define __FUNCT__ "TSStep_Pseudo"
143 static PetscErrorCode TSStep_Pseudo(TS ts,PetscInt *steps,PetscReal *ptime)
144 {
145   Vec            sol = ts->vec_sol;
146   PetscErrorCode ierr;
147   PetscInt       i,max_steps = ts->max_steps,its,lits;
148   PetscTruth     ok;
149   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
150   PetscReal      current_time_step;
151 
152   PetscFunctionBegin;
153   *steps = -ts->steps;
154 
155   ierr = VecCopy(sol,pseudo->update);CHKERRQ(ierr);
156   for (i=0; i<max_steps && ts->ptime < ts->max_time; i++) {
157     ierr = TSPseudoComputeTimeStep(ts,&ts->time_step);CHKERRQ(ierr);
158     ierr = TSMonitor(ts,ts->steps,ts->ptime,sol);CHKERRQ(ierr);
159     current_time_step = ts->time_step;
160     ierr = TSPreStep(ts);CHKERRQ(ierr);
161     while (PETSC_TRUE) {
162       ts->ptime  += current_time_step;
163       ierr = SNESSolve(ts->snes,PETSC_NULL,pseudo->update);CHKERRQ(ierr);
164       ierr = SNESGetLinearSolveIterations(ts->snes,&lits);CHKERRQ(ierr);
165       ierr = SNESGetIterationNumber(ts->snes,&its);CHKERRQ(ierr);
166       ts->nonlinear_its += its; ts->linear_its += lits;
167       ierr = TSPseudoVerifyTimeStep(ts,pseudo->update,&ts->time_step,&ok);CHKERRQ(ierr);
168       if (ok) break;
169       ts->ptime        -= current_time_step;
170       current_time_step = ts->time_step;
171     }
172     ierr = VecCopy(pseudo->update,sol);CHKERRQ(ierr);
173     ts->steps++;
174     ierr = TSPostStep(ts);CHKERRQ(ierr);
175   }
176   ierr = TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);CHKERRQ(ierr);
177   ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr);
178   ierr = TSMonitor(ts,ts->steps,ts->ptime,sol);CHKERRQ(ierr);
179 
180   *steps += ts->steps;
181   *ptime  = ts->ptime;
182   PetscFunctionReturn(0);
183 }
184 
185 /*------------------------------------------------------------*/
186 #undef __FUNCT__
187 #define __FUNCT__ "TSDestroy_Pseudo"
188 static PetscErrorCode TSDestroy_Pseudo(TS ts)
189 {
190   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
191   PetscErrorCode ierr;
192 
193   PetscFunctionBegin;
194   if (pseudo->update) {ierr = VecDestroy(pseudo->update);CHKERRQ(ierr);}
195   if (pseudo->func) {ierr = VecDestroy(pseudo->func);CHKERRQ(ierr);}
196   if (pseudo->xdot) {ierr = VecDestroy(pseudo->xdot);CHKERRQ(ierr);}
197   ierr = PetscFree(pseudo);CHKERRQ(ierr);
198   PetscFunctionReturn(0);
199 }
200 
201 
202 /*------------------------------------------------------------*/
203 
204 #undef __FUNCT__
205 #define __FUNCT__ "TSPseudoGetXdot"
206 /*
207     Compute Xdot = (X^{n+1}-X^n)/dt) = 0
208 */
209 static PetscErrorCode TSPseudoGetXdot(TS ts,Vec X,Vec *Xdot)
210 {
211   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
212   PetscScalar    mdt = 1.0/ts->time_step,*xnp1,*xn,*xdot;
213   PetscErrorCode ierr;
214   PetscInt       i,n;
215 
216   PetscFunctionBegin;
217   ierr = VecGetArray(ts->vec_sol,&xn);CHKERRQ(ierr);
218   ierr = VecGetArray(X,&xnp1);CHKERRQ(ierr);
219   ierr = VecGetArray(pseudo->xdot,&xdot);CHKERRQ(ierr);
220   ierr = VecGetLocalSize(X,&n);CHKERRQ(ierr);
221   for (i=0; i<n; i++) {
222     xdot[i] = mdt*(xnp1[i] - xn[i]);
223   }
224   ierr = VecRestoreArray(ts->vec_sol,&xn);CHKERRQ(ierr);
225   ierr = VecRestoreArray(X,&xnp1);CHKERRQ(ierr);
226   ierr = VecRestoreArray(pseudo->xdot,&xdot);CHKERRQ(ierr);
227   *Xdot = pseudo->xdot;
228   PetscFunctionReturn(0);
229 }
230 
231 #undef __FUNCT__
232 #define __FUNCT__ "SNESTSFormFunction_Pseudo"
233 /*
234     The transient residual is
235 
236         F(U^{n+1},(U^{n+1}-U^n)/dt) = 0
237 
238     or for ODE,
239 
240         (U^{n+1} - U^{n})/dt - F(U^{n+1}) = 0
241 
242     This is the function that must be evaluated for transient simulation and for
243     finite difference Jacobians.  On the first Newton step, this algorithm uses
244     a guess of U^{n+1} = U^n in which case the transient term vanishes and the
245     residual is actually the steady state residual.  Pseudotransient
246     continuation as described in the literature is a linearly implicit
247     algorithm, it only takes this one Newton step with the steady state
248     residual, and then advances to the next time step.
249 */
250 static PetscErrorCode SNESTSFormFunction_Pseudo(SNES snes,Vec X,Vec Y,TS ts)
251 {
252   Vec            Xdot;
253   PetscErrorCode ierr;
254 
255   PetscFunctionBegin;
256   ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr);
257   ierr = TSComputeIFunction(ts,ts->ptime,X,Xdot,Y);CHKERRQ(ierr);
258   PetscFunctionReturn(0);
259 }
260 
261 #undef __FUNCT__
262 #define __FUNCT__ "SNESTSFormJacobian_Pseudo"
263 /*
264    This constructs the Jacobian needed for SNES.  For DAE, this is
265 
266        dF(X,Xdot)/dX + shift*dF(X,Xdot)/dXdot
267 
268     and for ODE:
269 
270        J = I/dt - J_{Frhs}   where J_{Frhs} is the given Jacobian of Frhs.
271 */
272 static PetscErrorCode SNESTSFormJacobian_Pseudo(SNES snes,Vec X,Mat *AA,Mat *BB,MatStructure *str,TS ts)
273 {
274   Vec            Xdot;
275   PetscErrorCode ierr;
276 
277   PetscFunctionBegin;
278   ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr);
279   ierr = TSComputeIJacobian(ts,ts->ptime,X,Xdot,1./ts->time_step,AA,BB,str);CHKERRQ(ierr);
280   PetscFunctionReturn(0);
281 }
282 
283 
284 #undef __FUNCT__
285 #define __FUNCT__ "TSSetUp_Pseudo"
286 static PetscErrorCode TSSetUp_Pseudo(TS ts)
287 {
288   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
289   PetscErrorCode ierr;
290 
291   PetscFunctionBegin;
292   ierr = VecDuplicate(ts->vec_sol,&pseudo->update);CHKERRQ(ierr);
293   ierr = VecDuplicate(ts->vec_sol,&pseudo->func);CHKERRQ(ierr);
294   ierr = VecDuplicate(ts->vec_sol,&pseudo->xdot);CHKERRQ(ierr);
295   ierr = SNESSetFunction(ts->snes,pseudo->func,SNESTSFormFunction,ts);CHKERRQ(ierr);
296   ierr = SNESSetJacobian(ts->snes,ts->Arhs,ts->B,SNESTSFormJacobian,ts);CHKERRQ(ierr);
297   PetscFunctionReturn(0);
298 }
299 /*------------------------------------------------------------*/
300 
301 #undef __FUNCT__
302 #define __FUNCT__ "TSPseudoMonitorDefault"
303 PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *ctx)
304 {
305   TS_Pseudo               *pseudo = (TS_Pseudo*)ts->data;
306   PetscErrorCode          ierr;
307   PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor)ctx;
308 
309   PetscFunctionBegin;
310   if (!ctx) {
311     ierr = PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);CHKERRQ(ierr);
312   }
313   ierr = PetscViewerASCIIMonitorPrintf(viewer,"TS %D dt %G time %G fnorm %G\n",step,ts->time_step,ptime,pseudo->fnorm);CHKERRQ(ierr);
314   if (!ctx) {
315     ierr = PetscViewerASCIIMonitorDestroy(viewer);CHKERRQ(ierr);
316   }
317   PetscFunctionReturn(0);
318 }
319 
320 #undef __FUNCT__
321 #define __FUNCT__ "TSSetFromOptions_Pseudo"
322 static PetscErrorCode TSSetFromOptions_Pseudo(TS ts)
323 {
324   TS_Pseudo               *pseudo = (TS_Pseudo*)ts->data;
325   PetscErrorCode          ierr;
326   PetscTruth              flg = PETSC_FALSE;
327   PetscViewerASCIIMonitor viewer;
328 
329   PetscFunctionBegin;
330   ierr = PetscOptionsHead("Pseudo-timestepping options");CHKERRQ(ierr);
331     ierr = PetscOptionsTruth("-ts_monitor","Monitor convergence","TSPseudoMonitorDefault",flg,&flg,PETSC_NULL);CHKERRQ(ierr);
332     if (flg) {
333       ierr = PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);CHKERRQ(ierr);
334       ierr = TSMonitorSet(ts,TSPseudoMonitorDefault,viewer,(PetscErrorCode (*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr);
335     }
336     flg  = PETSC_FALSE;
337     ierr = PetscOptionsTruth("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",flg,&flg,PETSC_NULL);CHKERRQ(ierr);
338     if (flg) {
339       ierr = TSPseudoIncrementDtFromInitialDt(ts);CHKERRQ(ierr);
340     }
341     ierr = PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,0);CHKERRQ(ierr);
342   ierr = PetscOptionsTail();CHKERRQ(ierr);
343   PetscFunctionReturn(0);
344 }
345 
346 #undef __FUNCT__
347 #define __FUNCT__ "TSView_Pseudo"
348 static PetscErrorCode TSView_Pseudo(TS ts,PetscViewer viewer)
349 {
350   PetscFunctionBegin;
351   PetscFunctionReturn(0);
352 }
353 
354 /* ----------------------------------------------------------------------------- */
355 #undef __FUNCT__
356 #define __FUNCT__ "TSPseudoSetVerifyTimeStep"
357 /*@C
358    TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the
359    last timestep.
360 
361    Collective on TS
362 
363    Input Parameters:
364 +  ts - timestep context
365 .  dt - user-defined function to verify timestep
366 -  ctx - [optional] user-defined context for private data
367          for the timestep verification routine (may be PETSC_NULL)
368 
369    Level: advanced
370 
371    Calling sequence of func:
372 .  func (TS ts,Vec update,void *ctx,PetscReal *newdt,PetscTruth *flag);
373 
374 .  update - latest solution vector
375 .  ctx - [optional] timestep context
376 .  newdt - the timestep to use for the next step
377 .  flag - flag indicating whether the last time step was acceptable
378 
379    Notes:
380    The routine set here will be called by TSPseudoVerifyTimeStep()
381    during the timestepping process.
382 
383 .keywords: timestep, pseudo, set, verify
384 
385 .seealso: TSPseudoDefaultVerifyTimeStep(), TSPseudoVerifyTimeStep()
386 @*/
387 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (*dt)(TS,Vec,void*,PetscReal*,PetscTruth*),void* ctx)
388 {
389   PetscErrorCode ierr,(*f)(TS,PetscErrorCode (*)(TS,Vec,void*,PetscReal *,PetscTruth *),void *);
390 
391   PetscFunctionBegin;
392   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
393 
394   ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",(void (**)(void))&f);CHKERRQ(ierr);
395   if (f) {
396     ierr = (*f)(ts,dt,ctx);CHKERRQ(ierr);
397   }
398   PetscFunctionReturn(0);
399 }
400 
401 #undef __FUNCT__
402 #define __FUNCT__ "TSPseudoSetTimeStepIncrement"
403 /*@
404     TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to
405     dt when using the TSPseudoDefaultTimeStep() routine.
406 
407    Collective on TS
408 
409     Input Parameters:
410 +   ts - the timestep context
411 -   inc - the scaling factor >= 1.0
412 
413     Options Database Key:
414 $    -ts_pseudo_increment <increment>
415 
416     Level: advanced
417 
418 .keywords: timestep, pseudo, set, increment
419 
420 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
421 @*/
422 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc)
423 {
424   PetscErrorCode ierr,(*f)(TS,PetscReal);
425 
426   PetscFunctionBegin;
427   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
428 
429   ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",(void (**)(void))&f);CHKERRQ(ierr);
430   if (f) {
431     ierr = (*f)(ts,inc);CHKERRQ(ierr);
432   }
433   PetscFunctionReturn(0);
434 }
435 
436 #undef __FUNCT__
437 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt"
438 /*@
439     TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep
440     is computed via the formula
441 $         dt = initial_dt*initial_fnorm/current_fnorm
442       rather than the default update,
443 $         dt = current_dt*previous_fnorm/current_fnorm.
444 
445    Collective on TS
446 
447     Input Parameter:
448 .   ts - the timestep context
449 
450     Options Database Key:
451 $    -ts_pseudo_increment_dt_from_initial_dt
452 
453     Level: advanced
454 
455 .keywords: timestep, pseudo, set, increment
456 
457 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
458 @*/
459 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoIncrementDtFromInitialDt(TS ts)
460 {
461   PetscErrorCode ierr,(*f)(TS);
462 
463   PetscFunctionBegin;
464   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
465 
466   ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",(void (**)(void))&f);CHKERRQ(ierr);
467   if (f) {
468     ierr = (*f)(ts);CHKERRQ(ierr);
469   }
470   PetscFunctionReturn(0);
471 }
472 
473 
474 #undef __FUNCT__
475 #define __FUNCT__ "TSPseudoSetTimeStep"
476 /*@C
477    TSPseudoSetTimeStep - Sets the user-defined routine to be
478    called at each pseudo-timestep to update the timestep.
479 
480    Collective on TS
481 
482    Input Parameters:
483 +  ts - timestep context
484 .  dt - function to compute timestep
485 -  ctx - [optional] user-defined context for private data
486          required by the function (may be PETSC_NULL)
487 
488    Level: intermediate
489 
490    Calling sequence of func:
491 .  func (TS ts,PetscReal *newdt,void *ctx);
492 
493 .  newdt - the newly computed timestep
494 .  ctx - [optional] timestep context
495 
496    Notes:
497    The routine set here will be called by TSPseudoComputeTimeStep()
498    during the timestepping process.
499 
500 .keywords: timestep, pseudo, set
501 
502 .seealso: TSPseudoDefaultTimeStep(), TSPseudoComputeTimeStep()
503 @*/
504 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void* ctx)
505 {
506   PetscErrorCode ierr,(*f)(TS,PetscErrorCode (*)(TS,PetscReal *,void *),void *);
507 
508   PetscFunctionBegin;
509   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
510 
511   ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStep_C",(void (**)(void))&f);CHKERRQ(ierr);
512   if (f) {
513     ierr = (*f)(ts,dt,ctx);CHKERRQ(ierr);
514   }
515   PetscFunctionReturn(0);
516 }
517 
518 /* ----------------------------------------------------------------------------- */
519 
520 typedef PetscErrorCode (*FCN1)(TS,Vec,void*,PetscReal*,PetscTruth*); /* force argument to next function to not be extern C*/
521 EXTERN_C_BEGIN
522 #undef __FUNCT__
523 #define __FUNCT__ "TSPseudoSetVerifyTimeStep_Pseudo"
524 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void* ctx)
525 {
526   TS_Pseudo *pseudo;
527 
528   PetscFunctionBegin;
529   pseudo              = (TS_Pseudo*)ts->data;
530   pseudo->verify      = dt;
531   pseudo->verifyctx   = ctx;
532   PetscFunctionReturn(0);
533 }
534 EXTERN_C_END
535 
536 EXTERN_C_BEGIN
537 #undef __FUNCT__
538 #define __FUNCT__ "TSPseudoSetTimeStepIncrement_Pseudo"
539 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc)
540 {
541   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
542 
543   PetscFunctionBegin;
544   pseudo->dt_increment = inc;
545   PetscFunctionReturn(0);
546 }
547 EXTERN_C_END
548 
549 EXTERN_C_BEGIN
550 #undef __FUNCT__
551 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt_Pseudo"
552 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
553 {
554   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
555 
556   PetscFunctionBegin;
557   pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
558   PetscFunctionReturn(0);
559 }
560 EXTERN_C_END
561 
562 typedef PetscErrorCode (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/
563 EXTERN_C_BEGIN
564 #undef __FUNCT__
565 #define __FUNCT__ "TSPseudoSetTimeStep_Pseudo"
566 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void* ctx)
567 {
568   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
569 
570   PetscFunctionBegin;
571   pseudo->dt      = dt;
572   pseudo->dtctx   = ctx;
573   PetscFunctionReturn(0);
574 }
575 EXTERN_C_END
576 
577 /* ----------------------------------------------------------------------------- */
578 /*MC
579       TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping
580 
581   This method solves equations of the form
582 
583 $    F(X,Xdot) = 0
584 
585   for steady state using the iteration
586 
587 $    [G'] S = -F(X,0)
588 $    X += S
589 
590   where
591 
592 $    G(Y) = F(Y,(Y-X)/dt)
593 
594   This is linearly-implicit Euler with the residual always evaluated "at steady
595   state".  See note below.
596 
597   Options database keys:
598 +  -ts_pseudo_increment <real> - ratio of increase dt
599 -  -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt
600 
601   Level: beginner
602 
603   References:
604   Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003.
605   C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998.
606 
607   Notes:
608   The residual computed by this method includes the transient term (Xdot is computed instead of
609   always being zero), but since the prediction from the last step is always the solution from the
610   last step, on the first Newton iteration we have
611 
612 $  Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0
613 
614   Therefore, the linear system solved by the first Newton iteration is equivalent to the one
615   described above and in the papers.  If the user chooses to perform multiple Newton iterations, the
616   algorithm is no longer the one described in the referenced papers.
617 
618 .seealso:  TSCreate(), TS, TSSetType()
619 
620 M*/
621 EXTERN_C_BEGIN
622 #undef __FUNCT__
623 #define __FUNCT__ "TSCreate_Pseudo"
624 PetscErrorCode PETSCTS_DLLEXPORT TSCreate_Pseudo(TS ts)
625 {
626   TS_Pseudo      *pseudo;
627   PetscErrorCode ierr;
628 
629   PetscFunctionBegin;
630   ts->ops->destroy         = TSDestroy_Pseudo;
631   ts->ops->view            = TSView_Pseudo;
632 
633   if (ts->problem_type == TS_LINEAR) {
634     SETERRQ(PETSC_ERR_ARG_WRONG,"Only for nonlinear problems");
635   }
636   if (!ts->Arhs) {
637     SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set Jacobian");
638   }
639 
640   ts->ops->setup           = TSSetUp_Pseudo;
641   ts->ops->step            = TSStep_Pseudo;
642   ts->ops->setfromoptions  = TSSetFromOptions_Pseudo;
643   ts->ops->snesfunction    = SNESTSFormFunction_Pseudo;
644   ts->ops->snesjacobian    = SNESTSFormJacobian_Pseudo;
645 
646   /* create the required nonlinear solver context */
647   ierr = SNESCreate(((PetscObject)ts)->comm,&ts->snes);CHKERRQ(ierr);
648   ierr = PetscObjectIncrementTabLevel((PetscObject)ts->snes,(PetscObject)ts,1);CHKERRQ(ierr);
649 
650   ierr = PetscNewLog(ts,TS_Pseudo,&pseudo);CHKERRQ(ierr);
651   ts->data = (void*)pseudo;
652 
653   pseudo->dt_increment                 = 1.1;
654   pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
655   pseudo->dt                           = TSPseudoDefaultTimeStep;
656 
657   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",
658                     "TSPseudoSetVerifyTimeStep_Pseudo",
659                      TSPseudoSetVerifyTimeStep_Pseudo);CHKERRQ(ierr);
660   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",
661                     "TSPseudoSetTimeStepIncrement_Pseudo",
662                      TSPseudoSetTimeStepIncrement_Pseudo);CHKERRQ(ierr);
663   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",
664                     "TSPseudoIncrementDtFromInitialDt_Pseudo",
665                      TSPseudoIncrementDtFromInitialDt_Pseudo);CHKERRQ(ierr);
666   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C",
667                     "TSPseudoSetTimeStep_Pseudo",
668                      TSPseudoSetTimeStep_Pseudo);CHKERRQ(ierr);
669   PetscFunctionReturn(0);
670 }
671 EXTERN_C_END
672 
673 #undef __FUNCT__
674 #define __FUNCT__ "TSPseudoDefaultTimeStep"
675 /*@C
676    TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping.
677    Use with TSPseudoSetTimeStep().
678 
679    Collective on TS
680 
681    Input Parameters:
682 .  ts - the timestep context
683 .  dtctx - unused timestep context
684 
685    Output Parameter:
686 .  newdt - the timestep to use for the next step
687 
688    Level: advanced
689 
690 .keywords: timestep, pseudo, default
691 
692 .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep()
693 @*/
694 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoDefaultTimeStep(TS ts,PetscReal* newdt,void* dtctx)
695 {
696   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
697   PetscReal      inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous;
698   PetscErrorCode ierr;
699 
700   PetscFunctionBegin;
701   ierr = TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);CHKERRQ(ierr);
702   ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr);
703   if (pseudo->initial_fnorm == 0.0) {
704     /* first time through so compute initial function norm */
705     pseudo->initial_fnorm = pseudo->fnorm;
706     fnorm_previous        = pseudo->fnorm;
707   }
708   if (pseudo->fnorm == 0.0) {
709     *newdt = 1.e12*inc*ts->time_step;
710   } else if (pseudo->increment_dt_from_initial_dt) {
711     *newdt = inc*ts->initial_time_step*pseudo->initial_fnorm/pseudo->fnorm;
712   } else {
713     *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm;
714   }
715   pseudo->fnorm_previous = pseudo->fnorm;
716   PetscFunctionReturn(0);
717 }
718