xref: /petsc/src/ts/impls/pseudo/posindep.c (revision f3fe499b4cc4d64bf04aa4f5e4963dcc4eb56541)
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   /* This is nasty.  SNESSetFromOptions() is usually called in TSSetFromOptions().  With -snes_mf_operator, it will
297   replace A and we don't want to mess with that.  With -snes_mf, A and B will be replaced as well as the function and
298   context.  Note that SNESSetFunction() normally has not been called before SNESSetFromOptions(), so when -snes_mf sets
299   the Jacobian user context to snes->funP, it will actually be NULL.  This is not a problem because both snes->funP and
300   snes->jacP should be the TS. */
301   {
302     Mat A,B;
303     PetscErrorCode (*func)(SNES,Vec,Mat*,Mat*,MatStructure*,void*);
304     void *ctx;
305     ierr = SNESGetJacobian(ts->snes,&A,&B,&func,&ctx);CHKERRQ(ierr);
306     ierr = SNESSetJacobian(ts->snes,A?A:ts->A,B?B:ts->B,func?func:SNESTSFormJacobian,ctx?ctx:ts);CHKERRQ(ierr);
307   }
308   PetscFunctionReturn(0);
309 }
310 /*------------------------------------------------------------*/
311 
312 #undef __FUNCT__
313 #define __FUNCT__ "TSPseudoMonitorDefault"
314 PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *ctx)
315 {
316   TS_Pseudo               *pseudo = (TS_Pseudo*)ts->data;
317   PetscErrorCode          ierr;
318   PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor)ctx;
319 
320   PetscFunctionBegin;
321   if (!ctx) {
322     ierr = PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);CHKERRQ(ierr);
323   }
324   ierr = PetscViewerASCIIMonitorPrintf(viewer,"TS %D dt %G time %G fnorm %G\n",step,ts->time_step,ptime,pseudo->fnorm);CHKERRQ(ierr);
325   if (!ctx) {
326     ierr = PetscViewerASCIIMonitorDestroy(viewer);CHKERRQ(ierr);
327   }
328   PetscFunctionReturn(0);
329 }
330 
331 #undef __FUNCT__
332 #define __FUNCT__ "TSSetFromOptions_Pseudo"
333 static PetscErrorCode TSSetFromOptions_Pseudo(TS ts)
334 {
335   TS_Pseudo               *pseudo = (TS_Pseudo*)ts->data;
336   PetscErrorCode          ierr;
337   PetscTruth              flg = PETSC_FALSE;
338   PetscViewerASCIIMonitor viewer;
339 
340   PetscFunctionBegin;
341   ierr = PetscOptionsHead("Pseudo-timestepping options");CHKERRQ(ierr);
342     ierr = PetscOptionsTruth("-ts_monitor","Monitor convergence","TSPseudoMonitorDefault",flg,&flg,PETSC_NULL);CHKERRQ(ierr);
343     if (flg) {
344       ierr = PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);CHKERRQ(ierr);
345       ierr = TSMonitorSet(ts,TSPseudoMonitorDefault,viewer,(PetscErrorCode (*)(void*))PetscViewerASCIIMonitorDestroy);CHKERRQ(ierr);
346     }
347     flg  = PETSC_FALSE;
348     ierr = PetscOptionsTruth("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",flg,&flg,PETSC_NULL);CHKERRQ(ierr);
349     if (flg) {
350       ierr = TSPseudoIncrementDtFromInitialDt(ts);CHKERRQ(ierr);
351     }
352     ierr = PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,0);CHKERRQ(ierr);
353   ierr = PetscOptionsTail();CHKERRQ(ierr);
354   PetscFunctionReturn(0);
355 }
356 
357 #undef __FUNCT__
358 #define __FUNCT__ "TSView_Pseudo"
359 static PetscErrorCode TSView_Pseudo(TS ts,PetscViewer viewer)
360 {
361   PetscFunctionBegin;
362   PetscFunctionReturn(0);
363 }
364 
365 /* ----------------------------------------------------------------------------- */
366 #undef __FUNCT__
367 #define __FUNCT__ "TSPseudoSetVerifyTimeStep"
368 /*@C
369    TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the
370    last timestep.
371 
372    Logically Collective on TS
373 
374    Input Parameters:
375 +  ts - timestep context
376 .  dt - user-defined function to verify timestep
377 -  ctx - [optional] user-defined context for private data
378          for the timestep verification routine (may be PETSC_NULL)
379 
380    Level: advanced
381 
382    Calling sequence of func:
383 .  func (TS ts,Vec update,void *ctx,PetscReal *newdt,PetscTruth *flag);
384 
385 .  update - latest solution vector
386 .  ctx - [optional] timestep context
387 .  newdt - the timestep to use for the next step
388 .  flag - flag indicating whether the last time step was acceptable
389 
390    Notes:
391    The routine set here will be called by TSPseudoVerifyTimeStep()
392    during the timestepping process.
393 
394 .keywords: timestep, pseudo, set, verify
395 
396 .seealso: TSPseudoDefaultVerifyTimeStep(), TSPseudoVerifyTimeStep()
397 @*/
398 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (*dt)(TS,Vec,void*,PetscReal*,PetscTruth*),void* ctx)
399 {
400   PetscErrorCode ierr,(*f)(TS,PetscErrorCode (*)(TS,Vec,void*,PetscReal *,PetscTruth *),void *);
401 
402   PetscFunctionBegin;
403   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
404 
405   ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",(void (**)(void))&f);CHKERRQ(ierr);
406   if (f) {
407     ierr = (*f)(ts,dt,ctx);CHKERRQ(ierr);
408   }
409   PetscFunctionReturn(0);
410 }
411 
412 #undef __FUNCT__
413 #define __FUNCT__ "TSPseudoSetTimeStepIncrement"
414 /*@
415     TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to
416     dt when using the TSPseudoDefaultTimeStep() routine.
417 
418    Logically Collective on TS
419 
420     Input Parameters:
421 +   ts - the timestep context
422 -   inc - the scaling factor >= 1.0
423 
424     Options Database Key:
425 $    -ts_pseudo_increment <increment>
426 
427     Level: advanced
428 
429 .keywords: timestep, pseudo, set, increment
430 
431 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
432 @*/
433 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc)
434 {
435   PetscErrorCode ierr,(*f)(TS,PetscReal);
436 
437   PetscFunctionBegin;
438   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
439   PetscValidLogicalCollectiveReal(ts,inc,2);
440 
441   ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",(void (**)(void))&f);CHKERRQ(ierr);
442   if (f) {
443     ierr = (*f)(ts,inc);CHKERRQ(ierr);
444   }
445   PetscFunctionReturn(0);
446 }
447 
448 #undef __FUNCT__
449 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt"
450 /*@
451     TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep
452     is computed via the formula
453 $         dt = initial_dt*initial_fnorm/current_fnorm
454       rather than the default update,
455 $         dt = current_dt*previous_fnorm/current_fnorm.
456 
457    Logically Collective on TS
458 
459     Input Parameter:
460 .   ts - the timestep context
461 
462     Options Database Key:
463 $    -ts_pseudo_increment_dt_from_initial_dt
464 
465     Level: advanced
466 
467 .keywords: timestep, pseudo, set, increment
468 
469 .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
470 @*/
471 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoIncrementDtFromInitialDt(TS ts)
472 {
473   PetscErrorCode ierr,(*f)(TS);
474 
475   PetscFunctionBegin;
476   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
477 
478   ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",(void (**)(void))&f);CHKERRQ(ierr);
479   if (f) {
480     ierr = (*f)(ts);CHKERRQ(ierr);
481   }
482   PetscFunctionReturn(0);
483 }
484 
485 
486 #undef __FUNCT__
487 #define __FUNCT__ "TSPseudoSetTimeStep"
488 /*@C
489    TSPseudoSetTimeStep - Sets the user-defined routine to be
490    called at each pseudo-timestep to update the timestep.
491 
492    Logically Collective on TS
493 
494    Input Parameters:
495 +  ts - timestep context
496 .  dt - function to compute timestep
497 -  ctx - [optional] user-defined context for private data
498          required by the function (may be PETSC_NULL)
499 
500    Level: intermediate
501 
502    Calling sequence of func:
503 .  func (TS ts,PetscReal *newdt,void *ctx);
504 
505 .  newdt - the newly computed timestep
506 .  ctx - [optional] timestep context
507 
508    Notes:
509    The routine set here will be called by TSPseudoComputeTimeStep()
510    during the timestepping process.
511 
512 .keywords: timestep, pseudo, set
513 
514 .seealso: TSPseudoDefaultTimeStep(), TSPseudoComputeTimeStep()
515 @*/
516 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void* ctx)
517 {
518   PetscErrorCode ierr,(*f)(TS,PetscErrorCode (*)(TS,PetscReal *,void *),void *);
519 
520   PetscFunctionBegin;
521   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
522 
523   ierr = PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStep_C",(void (**)(void))&f);CHKERRQ(ierr);
524   if (f) {
525     ierr = (*f)(ts,dt,ctx);CHKERRQ(ierr);
526   }
527   PetscFunctionReturn(0);
528 }
529 
530 /* ----------------------------------------------------------------------------- */
531 
532 typedef PetscErrorCode (*FCN1)(TS,Vec,void*,PetscReal*,PetscTruth*); /* force argument to next function to not be extern C*/
533 EXTERN_C_BEGIN
534 #undef __FUNCT__
535 #define __FUNCT__ "TSPseudoSetVerifyTimeStep_Pseudo"
536 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void* ctx)
537 {
538   TS_Pseudo *pseudo;
539 
540   PetscFunctionBegin;
541   pseudo              = (TS_Pseudo*)ts->data;
542   pseudo->verify      = dt;
543   pseudo->verifyctx   = ctx;
544   PetscFunctionReturn(0);
545 }
546 EXTERN_C_END
547 
548 EXTERN_C_BEGIN
549 #undef __FUNCT__
550 #define __FUNCT__ "TSPseudoSetTimeStepIncrement_Pseudo"
551 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc)
552 {
553   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
554 
555   PetscFunctionBegin;
556   pseudo->dt_increment = inc;
557   PetscFunctionReturn(0);
558 }
559 EXTERN_C_END
560 
561 EXTERN_C_BEGIN
562 #undef __FUNCT__
563 #define __FUNCT__ "TSPseudoIncrementDtFromInitialDt_Pseudo"
564 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
565 {
566   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
567 
568   PetscFunctionBegin;
569   pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
570   PetscFunctionReturn(0);
571 }
572 EXTERN_C_END
573 
574 typedef PetscErrorCode (*FCN2)(TS,PetscReal*,void*); /* force argument to next function to not be extern C*/
575 EXTERN_C_BEGIN
576 #undef __FUNCT__
577 #define __FUNCT__ "TSPseudoSetTimeStep_Pseudo"
578 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void* ctx)
579 {
580   TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
581 
582   PetscFunctionBegin;
583   pseudo->dt      = dt;
584   pseudo->dtctx   = ctx;
585   PetscFunctionReturn(0);
586 }
587 EXTERN_C_END
588 
589 /* ----------------------------------------------------------------------------- */
590 /*MC
591       TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping
592 
593   This method solves equations of the form
594 
595 $    F(X,Xdot) = 0
596 
597   for steady state using the iteration
598 
599 $    [G'] S = -F(X,0)
600 $    X += S
601 
602   where
603 
604 $    G(Y) = F(Y,(Y-X)/dt)
605 
606   This is linearly-implicit Euler with the residual always evaluated "at steady
607   state".  See note below.
608 
609   Options database keys:
610 +  -ts_pseudo_increment <real> - ratio of increase dt
611 -  -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt
612 
613   Level: beginner
614 
615   References:
616   Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003.
617   C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998.
618 
619   Notes:
620   The residual computed by this method includes the transient term (Xdot is computed instead of
621   always being zero), but since the prediction from the last step is always the solution from the
622   last step, on the first Newton iteration we have
623 
624 $  Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0
625 
626   Therefore, the linear system solved by the first Newton iteration is equivalent to the one
627   described above and in the papers.  If the user chooses to perform multiple Newton iterations, the
628   algorithm is no longer the one described in the referenced papers.
629 
630 .seealso:  TSCreate(), TS, TSSetType()
631 
632 M*/
633 EXTERN_C_BEGIN
634 #undef __FUNCT__
635 #define __FUNCT__ "TSCreate_Pseudo"
636 PetscErrorCode PETSCTS_DLLEXPORT TSCreate_Pseudo(TS ts)
637 {
638   TS_Pseudo      *pseudo;
639   PetscErrorCode ierr;
640 
641   PetscFunctionBegin;
642   ts->ops->destroy         = TSDestroy_Pseudo;
643   ts->ops->view            = TSView_Pseudo;
644 
645   if (ts->problem_type == TS_LINEAR) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Only for nonlinear problems");
646   ts->ops->setup           = TSSetUp_Pseudo;
647   ts->ops->step            = TSStep_Pseudo;
648   ts->ops->setfromoptions  = TSSetFromOptions_Pseudo;
649   ts->ops->snesfunction    = SNESTSFormFunction_Pseudo;
650   ts->ops->snesjacobian    = SNESTSFormJacobian_Pseudo;
651 
652   /* create the required nonlinear solver context */
653   ierr = SNESCreate(((PetscObject)ts)->comm,&ts->snes);CHKERRQ(ierr);
654   ierr = PetscObjectIncrementTabLevel((PetscObject)ts->snes,(PetscObject)ts,1);CHKERRQ(ierr);
655 
656   ierr = PetscNewLog(ts,TS_Pseudo,&pseudo);CHKERRQ(ierr);
657   ts->data = (void*)pseudo;
658 
659   pseudo->dt_increment                 = 1.1;
660   pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
661   pseudo->dt                           = TSPseudoDefaultTimeStep;
662 
663   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",
664                     "TSPseudoSetVerifyTimeStep_Pseudo",
665                      TSPseudoSetVerifyTimeStep_Pseudo);CHKERRQ(ierr);
666   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",
667                     "TSPseudoSetTimeStepIncrement_Pseudo",
668                      TSPseudoSetTimeStepIncrement_Pseudo);CHKERRQ(ierr);
669   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",
670                     "TSPseudoIncrementDtFromInitialDt_Pseudo",
671                      TSPseudoIncrementDtFromInitialDt_Pseudo);CHKERRQ(ierr);
672   ierr = PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C",
673                     "TSPseudoSetTimeStep_Pseudo",
674                      TSPseudoSetTimeStep_Pseudo);CHKERRQ(ierr);
675   PetscFunctionReturn(0);
676 }
677 EXTERN_C_END
678 
679 #undef __FUNCT__
680 #define __FUNCT__ "TSPseudoDefaultTimeStep"
681 /*@C
682    TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping.
683    Use with TSPseudoSetTimeStep().
684 
685    Collective on TS
686 
687    Input Parameters:
688 .  ts - the timestep context
689 .  dtctx - unused timestep context
690 
691    Output Parameter:
692 .  newdt - the timestep to use for the next step
693 
694    Level: advanced
695 
696 .keywords: timestep, pseudo, default
697 
698 .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep()
699 @*/
700 PetscErrorCode PETSCTS_DLLEXPORT TSPseudoDefaultTimeStep(TS ts,PetscReal* newdt,void* dtctx)
701 {
702   TS_Pseudo      *pseudo = (TS_Pseudo*)ts->data;
703   PetscReal      inc = pseudo->dt_increment,fnorm_previous = pseudo->fnorm_previous;
704   PetscErrorCode ierr;
705 
706   PetscFunctionBegin;
707   ierr = TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);CHKERRQ(ierr);
708   ierr = VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);CHKERRQ(ierr);
709   if (pseudo->initial_fnorm == 0.0) {
710     /* first time through so compute initial function norm */
711     pseudo->initial_fnorm = pseudo->fnorm;
712     fnorm_previous        = pseudo->fnorm;
713   }
714   if (pseudo->fnorm == 0.0) {
715     *newdt = 1.e12*inc*ts->time_step;
716   } else if (pseudo->increment_dt_from_initial_dt) {
717     *newdt = inc*ts->initial_time_step*pseudo->initial_fnorm/pseudo->fnorm;
718   } else {
719     *newdt = inc*ts->time_step*fnorm_previous/pseudo->fnorm;
720   }
721   pseudo->fnorm_previous = pseudo->fnorm;
722   PetscFunctionReturn(0);
723 }
724