xref: /petsc/src/ts/impls/pseudo/posindep.c (revision 84df9cb40eca90ea9b18a456fab7a4ecc7f6c1a4)
1 /*
2        Code for Timestepping with implicit backwards Euler.
3 */
4 #include <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 /*@
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  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  TSPseudoDefaultVerifyTimeStep(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(), TSPseudoDefaultVerifyTimeStep()
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 
136   PetscFunctionReturn(0);
137 }
138 
139 /* --------------------------------------------------------------------------------*/
140 
141 #undef __FUNCT__
142 #define __FUNCT__ "TSStep_Pseudo"
143 static PetscErrorCode TSStep_Pseudo(TS ts)
144 {
145   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
146   PetscInt       its,lits,reject;
147   PetscBool      stepok;
148   PetscReal      next_time_step;
149   SNESConvergedReason snesreason = SNES_CONVERGED_ITERATING;
150   PetscErrorCode ierr;
151 
152   PetscFunctionBegin;
153   if (ts->steps == 0) {
154     pseudo->dt_initial = ts->time_step;
155   }
156   ierr = VecCopy(ts->vec_sol,pseudo->update);CHKERRQ(ierr);
157   next_time_step = ts->time_step;
158   ierr = TSPseudoComputeTimeStep(ts,&next_time_step);CHKERRQ(ierr);
159   for (reject=0; reject<ts->max_reject; reject++,ts->reject++) {
160     ts->time_step = next_time_step;
161     ierr = SNESSolve(ts->snes,PETSC_NULL,pseudo->update);CHKERRQ(ierr);
162     ierr = SNESGetConvergedReason(ts->snes,&snesreason);CHKERRQ(ierr);
163     ierr = SNESGetLinearSolveIterations(ts->snes,&lits);CHKERRQ(ierr);
164     ierr = SNESGetIterationNumber(ts->snes,&its);CHKERRQ(ierr);
165     ts->nonlinear_its += its; ts->linear_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 = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C","",PETSC_NULL);CHKERRQ(ierr);
213   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C","",PETSC_NULL);CHKERRQ(ierr);
214   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetMaxTimeStep_C","",PETSC_NULL);CHKERRQ(ierr);
215   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C","",PETSC_NULL);CHKERRQ(ierr);
216   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C","",PETSC_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++) {
241     xdot[i] = mdt*(xnp1[i] - xn[i]);
242   }
243   ierr = VecRestoreArrayRead(ts->vec_sol,&xn);CHKERRQ(ierr);
244   ierr = VecRestoreArrayRead(X,&xnp1);CHKERRQ(ierr);
245   ierr = VecRestoreArray(pseudo->xdot,&xdot);CHKERRQ(ierr);
246   *Xdot = pseudo->xdot;
247   PetscFunctionReturn(0);
248 }
249 
250 #undef __FUNCT__
251 #define __FUNCT__ "SNESTSFormFunction_Pseudo"
252 /*
253     The transient residual is
254 
255         F(U^{n+1},(U^{n+1}-U^n)/dt) = 0
256 
257     or for ODE,
258 
259         (U^{n+1} - U^{n})/dt - F(U^{n+1}) = 0
260 
261     This is the function that must be evaluated for transient simulation and for
262     finite difference Jacobians.  On the first Newton step, this algorithm uses
263     a guess of U^{n+1} = U^n in which case the transient term vanishes and the
264     residual is actually the steady state residual.  Pseudotransient
265     continuation as described in the literature is a linearly implicit
266     algorithm, it only takes this one Newton step with the steady state
267     residual, and then advances to the next time step.
268 */
269 static PetscErrorCode SNESTSFormFunction_Pseudo(SNES snes,Vec X,Vec Y,TS ts)
270 {
271   Vec            Xdot;
272   PetscErrorCode ierr;
273 
274   PetscFunctionBegin;
275   ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr);
276   ierr = TSComputeIFunction(ts,ts->ptime+ts->time_step,X,Xdot,Y,PETSC_FALSE);CHKERRQ(ierr);
277   PetscFunctionReturn(0);
278 }
279 
280 #undef __FUNCT__
281 #define __FUNCT__ "SNESTSFormJacobian_Pseudo"
282 /*
283    This constructs the Jacobian needed for SNES.  For DAE, this is
284 
285        dF(X,Xdot)/dX + shift*dF(X,Xdot)/dXdot
286 
287     and for ODE:
288 
289        J = I/dt - J_{Frhs}   where J_{Frhs} is the given Jacobian of Frhs.
290 */
291 static PetscErrorCode SNESTSFormJacobian_Pseudo(SNES snes,Vec X,Mat *AA,Mat *BB,MatStructure *str,TS ts)
292 {
293   Vec            Xdot;
294   PetscErrorCode ierr;
295 
296   PetscFunctionBegin;
297   ierr = TSPseudoGetXdot(ts,X,&Xdot);CHKERRQ(ierr);
298   ierr = TSComputeIJacobian(ts,ts->ptime+ts->time_step,X,Xdot,1./ts->time_step,AA,BB,str,PETSC_FALSE);CHKERRQ(ierr);
299   PetscFunctionReturn(0);
300 }
301 
302 
303 #undef __FUNCT__
304 #define __FUNCT__ "TSSetUp_Pseudo"
305 static PetscErrorCode TSSetUp_Pseudo(TS ts)
306 {
307   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
308   PetscErrorCode ierr;
309 
310   PetscFunctionBegin;
311   ierr = VecDuplicate(ts->vec_sol,&pseudo->update);CHKERRQ(ierr);
312   ierr = VecDuplicate(ts->vec_sol,&pseudo->func);CHKERRQ(ierr);
313   ierr = VecDuplicate(ts->vec_sol,&pseudo->xdot);CHKERRQ(ierr);
314   PetscFunctionReturn(0);
315 }
316 /*------------------------------------------------------------*/
317 
318 #undef __FUNCT__
319 #define __FUNCT__ "TSPseudoMonitorDefault"
320 PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *dummy)
321 {
322   TS_Pseudo        *pseudo = (TS_Pseudo*)ts->data;
323   PetscErrorCode   ierr;
324   PetscViewer      viewer = dummy ? (PetscViewer) dummy : PETSC_VIEWER_STDOUT_(((PetscObject)ts)->comm);
325 
326   PetscFunctionBegin;
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,PETSC_NULL);CHKERRQ(ierr);
350     if (flg) {
351       ierr = PetscViewerASCIIOpen(((PetscObject)ts)->comm,"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,PETSC_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 PETSC_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: TSPseudoDefaultVerifyTimeStep(), 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 TSPseudoDefaultTimeStep() 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(), TSPseudoDefaultTimeStep()
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 TSPseudoDefaultTimeStep() 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(), TSPseudoDefaultTimeStep()
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(), TSPseudoDefaultTimeStep()
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 PETSC_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 
545 .keywords: timestep, pseudo, set
546 
547 .seealso: TSPseudoDefaultTimeStep(), TSPseudoComputeTimeStep()
548 @*/
549 PetscErrorCode  TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void* ctx)
550 {
551   PetscErrorCode ierr;
552 
553   PetscFunctionBegin;
554   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
555   ierr = PetscTryMethod(ts,"TSPseudoSetTimeStep_C",(TS,PetscErrorCode (*)(TS,PetscReal *,void *),void *),(ts,dt,ctx));CHKERRQ(ierr);
556   PetscFunctionReturn(0);
557 }
558 
559 /* ----------------------------------------------------------------------------- */
560 
561 typedef PetscErrorCode (*FCN1)(TS,Vec,void*,PetscReal*,PetscBool *); /* force argument to next function to not be extern C*/
562 EXTERN_C_BEGIN
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 EXTERN_C_END
576 
577 EXTERN_C_BEGIN
578 #undef __FUNCT__
579 #define __FUNCT__ "TSPseudoSetTimeStepIncrement_Pseudo"
580 PetscErrorCode  TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc)
581 {
582   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
583 
584   PetscFunctionBegin;
585   pseudo->dt_increment = inc;
586   PetscFunctionReturn(0);
587 }
588 EXTERN_C_END
589 
590 EXTERN_C_BEGIN
591 #undef __FUNCT__
592 #define __FUNCT__ "TSPseudoSetMaxTimeStep_Pseudo"
593 PetscErrorCode  TSPseudoSetMaxTimeStep_Pseudo(TS ts,PetscReal maxdt)
594 {
595   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
596 
597   PetscFunctionBegin;
598   pseudo->dt_max = maxdt;
599   PetscFunctionReturn(0);
600 }
601 EXTERN_C_END
602 
603 EXTERN_C_BEGIN
604 #undef __FUNCT__
605 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt_Pseudo"
606 PetscErrorCode  TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
607 {
608   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
609 
610   PetscFunctionBegin;
611   pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
612   PetscFunctionReturn(0);
613 }
614 EXTERN_C_END
615 
616 typedef PetscErrorCode (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/
617 EXTERN_C_BEGIN
618 #undef __FUNCT__
619 #define __FUNCT__ "TSPseudoSetTimeStep_Pseudo"
620 PetscErrorCode  TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void* ctx)
621 {
622   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
623 
624   PetscFunctionBegin;
625   pseudo->dt      = dt;
626   pseudo->dtctx   = ctx;
627   PetscFunctionReturn(0);
628 }
629 EXTERN_C_END
630 
631 /* ----------------------------------------------------------------------------- */
632 /*MC
633       TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping
634 
635   This method solves equations of the form
636 
637 $    F(X,Xdot) = 0
638 
639   for steady state using the iteration
640 
641 $    [G'] S = -F(X,0)
642 $    X += S
643 
644   where
645 
646 $    G(Y) = F(Y,(Y-X)/dt)
647 
648   This is linearly-implicit Euler with the residual always evaluated "at steady
649   state".  See note below.
650 
651   Options database keys:
652 +  -ts_pseudo_increment <real> - ratio of increase dt
653 -  -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt
654 
655   Level: beginner
656 
657   References:
658   Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003.
659   C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998.
660 
661   Notes:
662   The residual computed by this method includes the transient term (Xdot is computed instead of
663   always being zero), but since the prediction from the last step is always the solution from the
664   last step, on the first Newton iteration we have
665 
666 $  Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0
667 
668   Therefore, the linear system solved by the first Newton iteration is equivalent to the one
669   described above and in the papers.  If the user chooses to perform multiple Newton iterations, the
670   algorithm is no longer the one described in the referenced papers.
671 
672 .seealso:  TSCreate(), TS, TSSetType()
673 
674 M*/
675 EXTERN_C_BEGIN
676 #undef __FUNCT__
677 #define __FUNCT__ "TSCreate_Pseudo"
678 PetscErrorCode  TSCreate_Pseudo(TS ts)
679 {
680   TS_Pseudo      *pseudo;
681   PetscErrorCode ierr;
682   SNES           snes;
683   const SNESType stype;
684 
685   PetscFunctionBegin;
686   ts->ops->reset           = TSReset_Pseudo;
687   ts->ops->destroy         = TSDestroy_Pseudo;
688   ts->ops->view            = TSView_Pseudo;
689 
690   ts->ops->setup           = TSSetUp_Pseudo;
691   ts->ops->step            = TSStep_Pseudo;
692   ts->ops->setfromoptions  = TSSetFromOptions_Pseudo;
693   ts->ops->snesfunction    = SNESTSFormFunction_Pseudo;
694   ts->ops->snesjacobian    = SNESTSFormJacobian_Pseudo;
695 
696   ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr);
697   ierr = SNESGetType(snes,&stype);CHKERRQ(ierr);
698   if (!stype) {ierr = SNESSetType(snes,SNESKSPONLY);CHKERRQ(ierr);}
699 
700   ierr = PetscNewLog(ts,TS_Pseudo,&pseudo);CHKERRQ(ierr);
701   ts->data = (void*)pseudo;
702 
703   pseudo->dt_increment                 = 1.1;
704   pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
705   pseudo->dt                           = TSPseudoDefaultTimeStep;
706   pseudo->fnorm                        = -1;
707 
708   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",
709                     "TSPseudoSetVerifyTimeStep_Pseudo",
710                      TSPseudoSetVerifyTimeStep_Pseudo);CHKERRQ(ierr);
711   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",
712                     "TSPseudoSetTimeStepIncrement_Pseudo",
713                      TSPseudoSetTimeStepIncrement_Pseudo);CHKERRQ(ierr);
714   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetMaxTimeStep_C",
715                     "TSPseudoSetMaxTimeStep_Pseudo",
716                      TSPseudoSetMaxTimeStep_Pseudo);CHKERRQ(ierr);
717   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",
718                     "TSPseudoIncrementDtFromInitialDt_Pseudo",
719                      TSPseudoIncrementDtFromInitialDt_Pseudo);CHKERRQ(ierr);
720   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C",
721                     "TSPseudoSetTimeStep_Pseudo",
722                      TSPseudoSetTimeStep_Pseudo);CHKERRQ(ierr);
723   PetscFunctionReturn(0);
724 }
725 EXTERN_C_END
726 
727 #undef __FUNCT__
728 #define __FUNCT__ "TSPseudoDefaultTimeStep"
729 /*@C
730    TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping.
731    Use with TSPseudoSetTimeStep().
732 
733    Collective on TS
734 
735    Input Parameters:
736 .  ts - the timestep context
737 .  dtctx - unused timestep context
738 
739    Output Parameter:
740 .  newdt - the timestep to use for the next step
741 
742    Level: advanced
743 
744 .keywords: timestep, pseudo, default
745 
746 .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep()
747 @*/
748 PetscErrorCode  TSPseudoDefaultTimeStep(TS ts,PetscReal* newdt,void* dtctx)
749 {
750   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
751   PetscReal      inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous;
752   PetscErrorCode ierr;
753 
754   PetscFunctionBegin;
755   ierr = VecZeroEntries(pseudo->xdot);CHKERRQ(ierr);
756   ierr = TSComputeIFunction(ts,ts->ptime,ts->vec_sol,pseudo->xdot,pseudo->func,PETSC_FALSE);CHKERRQ(ierr);
757   ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr);
758   if (pseudo->fnorm_initial == 0.0) {
759     /* first time through so compute initial function norm */
760     pseudo->fnorm_initial = pseudo->fnorm;
761     fnorm_previous        = pseudo->fnorm;
762   }
763   if (pseudo->fnorm == 0.0) {
764     *newdt = 1.e12*inc*ts->time_step;
765   } else if (pseudo->increment_dt_from_initial_dt) {
766     *newdt = inc*pseudo->dt_initial*pseudo->fnorm_initial/pseudo->fnorm;
767   } else {
768     *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm;
769   }
770   if (pseudo->dt_max > 0) *newdt = PetscMin(*newdt,pseudo->dt_max);
771   pseudo->fnorm_previous = pseudo->fnorm;
772   PetscFunctionReturn(0);
773 }
774