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